init project
[pong.git] / 31_scrolling_backgrounds.cpp
1 /*This source code copyrighted by Lazy Foo' Productions (2004-2020)
2 and may not be redistributed without written permission.*/
3
4 //Using SDL, SDL_image, standard IO, vectors, and strings
5 #include <SDL2/SDL.h>
6 #include <SDL2/SDL_image.h>
7 #include <stdio.h>
8 #include <string>
9
10 //Screen dimension constants
11 const int SCREEN_WIDTH = 640;
12 const int SCREEN_HEIGHT = 480;
13
14 //Texture wrapper class
15 class LTexture
16 {
17         public:
18                 //Initializes variables
19                 LTexture();
20
21                 //Deallocates memory
22                 ~LTexture();
23
24                 //Loads image at specified path
25                 bool loadFromFile( std::string path );
26                 
27                 #if defined(_SDL_TTF_H) || defined(SDL_TTF_H)
28                 //Creates image from font string
29                 bool loadFromRenderedText( std::string textureText, SDL_Color textColor );
30                 #endif
31
32                 //Deallocates texture
33                 void free();
34
35                 //Set color modulation
36                 void setColor( Uint8 red, Uint8 green, Uint8 blue );
37
38                 //Set blending
39                 void setBlendMode( SDL_BlendMode blending );
40
41                 //Set alpha modulation
42                 void setAlpha( Uint8 alpha );
43                 
44                 //Renders texture at given point
45                 void render( int x, int y, SDL_Rect* clip = NULL, double angle = 0.0, SDL_Point* center = NULL, SDL_RendererFlip flip = SDL_FLIP_NONE );
46
47                 //Gets image dimensions
48                 int getWidth();
49                 int getHeight();
50
51         private:
52                 //The actual hardware texture
53                 SDL_Texture* mTexture;
54
55                 //Image dimensions
56                 int mWidth;
57                 int mHeight;
58 };
59
60 //The dot that will move around on the screen
61 class Dot
62 {
63     public:
64
65                 //Maximum axis velocity of the dot
66                 static const int DOT_VEL = 10;
67
68                 //Initializes the variables
69                 Dot();
70
71                 //Takes key presses and adjusts the dot's velocity
72                 void handleEvent( SDL_Event& e );
73
74                 //Moves the dot
75                 void move();
76
77                 // Change dimensions
78           void setDimensions(Uint8 w, Uint8 h);
79
80                 //Shows the dot on the screen
81                 void render();
82
83     private:
84                 //The X and Y offsets of the dot
85                 int mPosX, mPosY;
86
87                 //The velocity of the dot
88                 int mVelX, mVelY;
89                 //The dimensions of the dot
90                 
91           int mWidth;
92           int mHeight;
93 };
94
95 //Starts up SDL and creates window
96 bool init();
97
98 //Loads media
99 bool loadMedia();
100
101 //Frees media and shuts down SDL
102 void close();
103
104 //The window we'll be rendering to
105 SDL_Window* gWindow = NULL;
106
107 //The window renderer
108 SDL_Renderer* gRenderer = NULL;
109
110 //Scene textures
111 LTexture gDotTexture;
112 LTexture gBGTexture;
113
114 LTexture::LTexture()
115 {
116         //Initialize
117         mTexture = NULL;
118         mWidth = 0;
119         mHeight = 0;
120 }
121
122 LTexture::~LTexture()
123 {
124         //Deallocate
125         free();
126 }
127
128 bool LTexture::loadFromFile( std::string path )
129 {
130         //Get rid of preexisting texture
131         free();
132
133         //The final texture
134         SDL_Texture* newTexture = NULL;
135
136         //Load image at specified path
137         SDL_Surface* loadedSurface = IMG_Load( path.c_str() );
138         if( loadedSurface == NULL )
139         {
140                 printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
141         }
142         else
143         {
144                 //Color key image
145                 SDL_SetColorKey( loadedSurface, SDL_TRUE, SDL_MapRGB( loadedSurface->format, 0, 0xFF, 0xFF ) );
146
147                 //Create texture from surface pixels
148         newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface );
149                 if( newTexture == NULL )
150                 {
151                         printf( "Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
152                 }
153                 else
154                 {
155                         //Get image dimensions
156                         mWidth = loadedSurface->w;
157                         mHeight = loadedSurface->h;
158                 }
159
160                 //Get rid of old loaded surface
161                 SDL_FreeSurface( loadedSurface );
162         }
163
164         //Return success
165         mTexture = newTexture;
166         return mTexture != NULL;
167 }
168
169 #if defined(_SDL_TTF_H) || defined(SDL_TTF_H)
170 bool LTexture::loadFromRenderedText( std::string textureText, SDL_Color textColor )
171 {
172         //Get rid of preexisting texture
173         free();
174
175         //Render text surface
176         SDL_Surface* textSurface = TTF_RenderText_Solid( gFont, textureText.c_str(), textColor );
177         if( textSurface != NULL )
178         {
179                 //Create texture from surface pixels
180         mTexture = SDL_CreateTextureFromSurface( gRenderer, textSurface );
181                 if( mTexture == NULL )
182                 {
183                         printf( "Unable to create texture from rendered text! SDL Error: %s\n", SDL_GetError() );
184                 }
185                 else
186                 {
187                         //Get image dimensions
188                         mWidth = textSurface->w;
189                         mHeight = textSurface->h;
190                 }
191
192                 //Get rid of old surface
193                 SDL_FreeSurface( textSurface );
194         }
195         else
196         {
197                 printf( "Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
198         }
199
200         
201         //Return success
202         return mTexture != NULL;
203 }
204 #endif
205
206 void LTexture::free()
207 {
208         //Free texture if it exists
209         if( mTexture != NULL )
210         {
211                 SDL_DestroyTexture( mTexture );
212                 mTexture = NULL;
213                 mWidth = 0;
214                 mHeight = 0;
215         }
216 }
217
218 void LTexture::setColor( Uint8 red, Uint8 green, Uint8 blue )
219 {
220         //Modulate texture rgb
221         SDL_SetTextureColorMod( mTexture, red, green, blue );
222 }
223
224 void LTexture::setBlendMode( SDL_BlendMode blending )
225 {
226         //Set blending function
227         SDL_SetTextureBlendMode( mTexture, blending );
228 }
229                 
230 void LTexture::setAlpha( Uint8 alpha )
231 {
232         //Modulate texture alpha
233         SDL_SetTextureAlphaMod( mTexture, alpha );
234 }
235
236 void LTexture::render( int x, int y, SDL_Rect* clip, double angle, SDL_Point* center, SDL_RendererFlip flip )
237 {
238         //Set rendering space and render to screen
239         SDL_Rect renderQuad = { x, y, mWidth, mHeight };
240
241         //Set clip rendering dimensions
242         if( clip != NULL )
243         {
244                 renderQuad.w = clip->w;
245                 renderQuad.h = clip->h;
246         }
247
248         //Render to screen
249         SDL_RenderCopyEx( gRenderer, mTexture, clip, &renderQuad, angle, center, flip );
250 }
251
252 int LTexture::getWidth()
253 {
254         return mWidth;
255 }
256
257 int LTexture::getHeight()
258 {
259         return mHeight;
260 }
261
262 Dot::Dot()
263 {
264     //Initialize the offsets
265     mPosX = 0;
266     mPosY = 0;
267
268     //Initialize the velocity
269     mVelX = 0;
270     mVelY = 0;
271
272     mWidth = 10;
273     mHeight = 10;
274 }
275
276 void Dot::setDimensions(Uint8 w, Uint8 h)
277 {
278   mWidth = w;
279   mHeight = h;
280 }
281
282 void Dot::handleEvent( SDL_Event& e )
283 {
284     //If a key was pressed
285         if( e.type == SDL_KEYDOWN && e.key.repeat == 0 )
286     {
287         //Adjust the velocity
288         switch( e.key.keysym.sym )
289         {
290             case SDLK_UP: mVelY -= DOT_VEL; break;
291             case SDLK_DOWN: mVelY += DOT_VEL; break;
292             // case SDLK_LEFT: mVelX -= DOT_VEL; break;
293             // case SDLK_RIGHT: mVelX += DOT_VEL; break;
294         }
295     }
296     //If a key was released
297     else if( e.type == SDL_KEYUP && e.key.repeat == 0 )
298     {
299         //Adjust the velocity
300         switch( e.key.keysym.sym )
301         {
302             case SDLK_UP: mVelY += DOT_VEL; break;
303             case SDLK_DOWN: mVelY -= DOT_VEL; break;
304             // case SDLK_LEFT: mVelX += DOT_VEL; break;
305             // case SDLK_RIGHT: mVelX -= DOT_VEL; break;
306         }
307     }
308 }
309
310 void Dot::move()
311 {
312     //Move the dot up or down
313     mPosY += mVelY;
314
315     //If the dot went too far up or down
316     if( ( mPosY < 0 ) || ( mPosY + mHeight > SCREEN_HEIGHT ) )
317     {
318         //Move back
319         mPosY -= mVelY;
320     }
321 }
322
323 void Dot::render()
324 {
325     //Show the dot
326         gDotTexture.render( mPosX, mPosY );
327 }
328
329 bool init()
330 {
331         //Initialization flag
332         bool success = true;
333
334         //Initialize SDL
335         if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
336         {
337                 printf( "SDL could not initialize! SDL Error: %s\n", SDL_GetError() );
338                 success = false;
339         }
340         else
341         {
342                 //Set texture filtering to linear
343                 if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) )
344                 {
345                         printf( "Warning: Linear texture filtering not enabled!" );
346                 }
347
348                 //Create window
349                 gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
350                 if( gWindow == NULL )
351                 {
352                         printf( "Window could not be created! SDL Error: %s\n", SDL_GetError() );
353                         success = false;
354                 }
355                 else
356                 {
357                         //Create vsynced renderer for window
358                         gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
359                         if( gRenderer == NULL )
360                         {
361                                 printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );
362                                 success = false;
363                         }
364                         else
365                         {
366                                 //Initialize renderer color
367                                 SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
368                                 //Initialize PNG loading
369                                 int imgFlags = IMG_INIT_PNG;
370                                 if( !( IMG_Init( imgFlags ) & imgFlags ) )
371                                 {
372                                         printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() );
373                                         success = false;
374                                 }
375                         }
376                 }
377         }
378
379         return success;
380 }
381
382 bool loadMedia()
383 {
384         //Loading success flag
385         bool success = true;
386
387         //Load dot texture
388         if( !gDotTexture.loadFromFile( "dot.bmp" ) )
389         {
390                 printf( "Failed to load dot texture!\n" );
391                 success = false;
392         }
393
394         //Load background texture
395         if( !gBGTexture.loadFromFile( "bg.png" ) )
396         {
397                 printf( "Failed to load background texture!\n" );
398                 success = false;
399         }
400
401         return success;
402 }
403
404 void close()
405 {
406         //Free loaded images
407         gDotTexture.free();
408         gBGTexture.free();
409
410         //Destroy window        
411         SDL_DestroyRenderer( gRenderer );
412         SDL_DestroyWindow( gWindow );
413         gWindow = NULL;
414         gRenderer = NULL;
415
416         //Quit SDL subsystems
417         IMG_Quit();
418         SDL_Quit();
419 }
420
421 int main( int argc, char* args[] )
422 {
423         //Start up SDL and create window
424         if( !init() )
425         {
426                 printf( "Failed to initialize!\n" );
427         }
428         else
429         {
430                 //Load media
431                 if( !loadMedia() )
432                 {
433                         printf( "Failed to load media!\n" );
434                 }
435                 else
436                 {       
437                         //Main loop flag
438                         bool quit = false;
439
440                         //Event handler
441                         SDL_Event e;
442
443                         //The dot that will be moving around on the screen
444                         Dot dot;
445
446                         Dot movingDot;
447                         movingDot.setDimensions(3, 3);
448
449                         //The background scrolling offset
450                         int scrollingOffset = 0;
451
452                         //While application is running
453                         while( !quit )
454                         {
455                                 //Handle events on queue
456                                 while( SDL_PollEvent( &e ) != 0 )
457                                 {
458                                         //User requests quit
459                                         if( e.type == SDL_QUIT )
460                                         {
461                                                 quit = true;
462                                         }
463
464                                         //Handle input for the dot
465                                         dot.handleEvent( e );
466                                 }
467
468                                 //Move the dot
469                                 dot.move();
470
471                                 //Scroll background
472                                 --scrollingOffset;
473                                 if( scrollingOffset < -gBGTexture.getWidth() )
474                                 {
475                                         scrollingOffset = 0;
476                                 }
477
478                                 //Clear screen
479                                 SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
480                                 SDL_RenderClear( gRenderer );
481
482                                 //Render background
483                                 gBGTexture.render( scrollingOffset, 0 );
484                                 gBGTexture.render( scrollingOffset + gBGTexture.getWidth(), 0 );
485
486                                 //Render middle line
487                                 //SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
488                                 SDL_RenderDrawLine(gRenderer, SCREEN_WIDTH/2, 0, SCREEN_WIDTH/2, SCREEN_HEIGHT);
489
490                                 //Render objects
491                                 dot.render();
492
493                                 //Update screen
494                                 SDL_RenderPresent( gRenderer );
495                         }
496                 }
497         }
498
499         //Free resources and close SDL
500         close();
501
502         return 0;
503 }