Building the Slideshow Example Program


Because you haven't learned about how to process user input such as key strokes and mouse clicks, it still isn't quite possible to create a game yet. However, the remainder of the hour guides you through the creation of a surprisingly practical example program that happens to serve as a great demonstration of the Bitmap class. I'm referring to the Slideshow program, which uses a series of bitmap images to present a slideshow. The Slideshow program takes advantage of the timing mechanism built into the game engine to provide a delay between moving to each successive image in a slideshow. The Bitmap class proves to be quite useful as a means of loading and drawing bitmaps from both files and resources.

Before looking at the code for the Slideshow program, let's quickly go over what it is supposed to accomplish:

  • Create several bitmaps from files

  • Create several bitmaps from resources

  • Create a blank bitmap in a solid color

  • Draw the bitmaps one at a time as part of a slideshow

  • Time the presentation of the slides in the slideshow appropriately

These requirements for the Slideshow program make it pretty clear what is supposed to happen. The only thing worth mentioning is that you wouldn't normally mix the two approaches of loading bitmaps from files and resources. Generally speaking, it makes sense to commit to one approach or the other. In the case of a slideshow, it probably makes more sense to load bitmaps from files because you might want to change the images without recompiling the program. However, in this case it's important to demonstrate the different uses of the Bitmap class.

Writing the Program Code

The header for the Slideshow program example is the best place to start in terms of getting acquainted with how it works. Check out Listing 5.2 to get a feel for what the header is all about. Don't forget that you can access all of the code for the Slideshow program on the accompanying CD-ROM.

Listing 5.2 The Slideshow.h Header File Imports a Few Header Files and Declares Several Global Variables
 1: #pragma once  2:  3: //-----------------------------------------------------------------  4: // Include Files  5: //-----------------------------------------------------------------  6: #include <windows.h>  7: #include "Resource.h"  8: #include "GameEngine.h"  9: #include "Bitmap.h" 10: 11: //----------------------------------------------------------------- 12: // Global Variables 13: //----------------------------------------------------------------- 14: HINSTANCE   _hInstance; 15: GameEngine* _pGame; 16: const int   _iNUMSLIDES = 7; 17: Bitmap*     _pSlides[_iNUMSLIDES]; 18: int         _iCurSlide; 

Other than declaring a few global variables, there aren't really any surprises here. The _hInstance variable is necessary to store because a program instance handle is necessary in order to load bitmaps as resources (line 14). An instance is simply a program loaded into memory; all the programs you have open and running in Windows are considered instances. An instance handle is a reference to an instance, which allows you to interact with the instance and do things such as load resources that are stored in the executable program file. Because you're going to be loading bitmaps as resources, it's important to store away an instance handle for the Slideshow program.

The _pGame global variable is used to store a pointer to the game engine, which should be familiar to you by now (line 15). The remaining member variables relate specifically to the slideshow functionality. The global constant _iNUMSLIDES is used to set the number of slides in the slideshow, and should be changed if you modify the number of slides in the slideshow (line 16). The _pSlides variable is perhaps the most important because it stores away pointers to the Bitmap objects (line 17); these objects correspond to the slides in the slideshow. Finally, the _iCurSlide variable represents the array index of the current slide, which is the slide currently being displayed (line 18). This variable is important because it keeps track of where the slideshow is in the slide sequence.

The global variables in the Slideshow header file are somewhat revealing , but you obviously have to look at the code for the game functions to really get a feel for what's going on. Listing 5.3 contains the code for the GameInitialize() function, which is the first of the Slideshow game functions.

Listing 5.3 The GameInitialize() Function Creates the Game Engine, Sets the Frame Rate to One Cycle Per Second, and Stores Away the Instance Handle for the Program
 1: BOOL GameInitialize(HINSTANCE hInstance)  2: {  3:   // Create the game engine  4:   _pGame = new GameEngine(hInstance, TEXT("Slideshow"),  5:     TEXT("Slideshow"), IDI_SLIDESHOW, IDI_SLIDESHOW_SM);  6:   if (_pGame == NULL)  7:     return FALSE;  8:  9:   // Set the frame rate 10:   _pGame->SetFrameRate(1); 11: 12:   // Store the instance handle 13:   _hInstance = hInstance; 14: 15:   return TRUE; 16: } 

The GameInitialize() function is pretty basic in terms of doing things you've gotten accustomed to seeing in a program that makes use of the game engine. Notice, however, that the frame rate for the game engine is set to 1 , which means that there is only one game cycle per second (line 10). This is important because it helps to establish the timing of the slideshow. The problem is that one second is still too short a period to flip between slides, so we'll have to trick the game engine into displaying each slide a little longer; you tackle this problem in a moment. The only other task carried out in GameInitialize() is storing away the instance handle, which is very important for loading bitmaps from resources (line 13).

Although GameInitialize() creates and initializes the game engine, it's the GameStart() function that really gets the Slideshow program on track. Its counterpart is GameEnd() , which cleans up the bitmaps created in GameStart() . The code for both functions is shown in Listing 5.4.

Listing 5.4 The GameStart() and GameEnd() Functions Take Care of Initializing and Cleaning Up the Slide Bitmaps
 1: void GameStart(HWND hWindow)  2: {  3:   // Create and load the slide bitmaps  4:   HDC hDC = GetDC(hWindow);  5:   _pSlides[0] = new Bitmap(hDC, TEXT("Image1.bmp"));  6:   _pSlides[1] = new Bitmap(hDC, TEXT("Image2.bmp"));  7:   _pSlides[2] = new Bitmap(hDC, TEXT("Image3.bmp"));  8:   _pSlides[3] = new Bitmap(hDC, IDB_IMAGE4, _hInstance);  9:   _pSlides[4] = new Bitmap(hDC, IDB_IMAGE5, _hInstance); 10:   _pSlides[5] = new Bitmap(hDC, IDB_IMAGE6, _hInstance); 11:   _pSlides[6] = new Bitmap(hDC, 640, 480, RGB(128, 128, 64)); 12: 13:   // Set the first slide 14:   _iCurSlide = 0; 15: } 16: 17: void GameEnd() 18: { 19:   // Cleanup the slide bitmaps 20:   for (int i = 0; i < _iNUMSLIDES; i++) 21:     delete _pSlides[i]; 22: 23:   // Cleanup the game engine 24:   delete _pGame; 25: } 

The GameStart() function takes on the responsibility of creating the slide bitmaps. It first obtains a device context, which is necessary to create any bitmaps (line 4). It then loads several bitmaps from files (lines 5 “7), as well as loading a few bitmaps as resources (lines 8 “10). The final bitmap is a solid color blank bitmap that is created using the third Bitmap() constructor (line 11). After creating the bitmaps, the GameStart() function sets the current slide to the first bitmap (line 14).

The GameEnd() function simply cleans up the slide bitmaps by stepping through the array and deleting them one at a time (lines 20 and 21). This is an important part of the Slideshow program because you definitely want to clean up after yourself.

The current slide is drawn to the game screen in the Slideshow program thanks to the GamePaint() function, which is shown in Listing 5.5.

Listing 5.5 The GamePaint() Function Simply Draws the Current Slide Bitmap
 1: void GamePaint(HDC hDC)  2: {  3:   // Draw the current slide bitmap  4:   _pSlides[_iCurSlide]->Draw(hDC, 0, 0);  5: } 

The GamePaint() function is probably simpler than you might have expected. Here, you're really getting to see how helpful the Bitmap class is because it allows you to draw a bitmap image with a very simple call to the Draw() method (line 4) of the Bitmap object. The _iCurSlide global variable is used to make sure that the appropriate slide is drawn.

The GameCycle() function is responsible for moving to the next slide after imposing a small delay, as shown in Listing 5.6.

Listing 5.6 The GameCycle() Function Steps Through the Slides After Waiting a Few Seconds
 1: void GameCycle()  2: {  3:   static int iDelay = 0;  4:  5:   // Establish a 3-second delay before moving to the next slide  6:   if (++iDelay > 3)  7:   {  8:     // Restore the delay counter  9:     iDelay = 0; 10: 11:     // Move to the next slide 12:     if (++_iCurSlide == _iNUMSLIDES) 13:       _iCurSlide = 0; 14: 15:     // Force a repaint to draw the next slide 16:     InvalidateRect(_pGame->GetWindow(), NULL, FALSE); 17:   } 18: } 

Because the game engine is limited to a minimum frame rate of one second, it's necessary to slow down the slideshow further by imposing a delay in the GameCycle() function. Three seconds is a reasonable delay for viewing each slide, so the GameCycle() function uses a static variable, iDelay , to delay each slide for three seconds before moving to the next (line 3). In order to move to the next slide, the iCurSlide variable is incremented (line 12); if it is incremented past the last slide, the slideshow cycles back to the first slide (line 13).

Just because you increment the current slide variable doesn't mean that the slideshow updates to show the new slide bitmap. Keep in mind that the current slide bitmap is drawn in the GamePaint() function, which is called whenever the client area of the Slideshow window needs to be repainted. The trick is to force a repaint of the window, which is possible using the Win32 InvalidateRect() function. The GameCycle() function calls InvalidateRect() to force a repaint and display the new slide bitmap (line 16). The second argument to InvalidateRect() indicates that the entire client area is to be repainted, whereas the last argument indicates that it isn't necessary to erase the client area before repainting .

Assembling the Resources

You've now seen the vast majority of the code for the Slideshow program example, which hopefully wasn't too overwhelming seeing as how the Bitmap class removed a great deal of the work required to display images. The only remaining code to address involves the bitmap resources used in the program. To demonstrate how to use bitmaps as resources, I decided to go ahead and include all the slide bitmaps as resources, even though the program only loads three of them as resources. Listing 5.7 contains the code for the Resource.h header file, which defines unique resource IDs for the bitmaps.

Listing 5.7 The Resource.h Header File Contains Resource IDs for the Icons and Bitmap Images in the Slideshow Program Example
 1: //-----------------------------------------------------------------  2: // Icons                    Range : 1000 - 1999  3: //-----------------------------------------------------------------  4: #define IDI_SLIDESHOW       1000  5: #define IDI_SLIDESHOW_SM    1001  6:  7: //-----------------------------------------------------------------  8: // Bitmaps                  Range : 2000 - 2999  9: //----------------------------------------------------------------- 10: #define IDB_IMAGE1          2000 11: #define IDB_IMAGE2          2001 12: #define IDB_IMAGE3          2002 13: #define IDB_IMAGE4          2003 14: #define IDB_IMAGE5          2004 15: #define IDB_IMAGE6          2005 

This code reveals how resources are typically organized according to type. It also shows how the numbers used to distinguish between resources are specified as ranges for each resource type. This is primarily an organizational issue, but it does help to keep things straight. The bitmap resource IDs are created in lines 10 “15, and are pretty straightforward. Notice that there is no ID for the seventh bitmap, the solid color bitmap, because it is a blank bitmap that doesn't derive from a resource.

The bitmap resource IDs come into play in the Slideshow.rc resource script, which is shown in Listing 5.8.

Listing 5.8 The Slideshow.rc Resource Script Contains the Resources for the Slideshow Program Example, Including the Bitmap Resources
 1: //-----------------------------------------------------------------  2: // Include Files  3: //-----------------------------------------------------------------  4: #include "Resource.h"  5:  6: //-----------------------------------------------------------------  7: // Icons  8: //-----------------------------------------------------------------  9: IDI_SLIDESHOW      ICON         "Slideshow.ico" 10: IDI_SLIDESHOW_SM   ICON         "Slideshow_sm.ico" 11: 12: //----------------------------------------------------------------- 13: // Bitmaps 14: //----------------------------------------------------------------- 15: IDB_IMAGE1         BITMAP       "Image1.bmp" 16: IDB_IMAGE2         BITMAP       "Image2.bmp" 17: IDB_IMAGE3         BITMAP       "Image3.bmp" 18: IDB_IMAGE4         BITMAP       "Image4.bmp" 19: IDB_IMAGE5         BITMAP       "Image5.bmp" 20: IDB_IMAGE6         BITMAP       "Image6.bmp" 

This resource script reveals how bitmap resources are included using the BITMAP resource type. Including bitmaps in a resource script is similar to including icons, and involves specifying the resource ID, resource type, and image file for each bitmap (lines 15 “20). By including bitmaps in the resource script, you are alleviating the need to include separate bitmap image files with the completed program.

Testing the Finished Product

The Slideshow program example is definitely the most practical program you've seen thus far. You can use the program to display any kind of slideshow of images that you want, provided that you store the images as 8-bit (256 color) bitmaps with no compression. To demonstrate the practicality of the program, I decided to put together a slideshow of photos from a recent trip I took to Arizona. Figure 5.2 shows a photo of a jackrabbit, which happens to be the opening slide in the slideshow.

Figure 5.2. The Slideshow program example demonstrates how to display bitmap images, and also serves as a good way to relive a vacation.

graphics/05fig02.gif

You'll notice that every three seconds the slide will change, eventually leading to the end of the slideshow, after which it wraps around and begins with the first image again. Figure 5.3 shows another slide in the slideshow to demonstrate how the slides are changed.

Figure 5.3. Each successive slide in the Slideshow program is separated by a three second delay.

graphics/05fig03.gif

Whether or not you decide to place your family album of digital photographs into a Slideshow program of your own, you've hopefully gained an appreciation of bitmaps and how to work with them at the programming level. You also now have the Bitmap class, which you will be using heavily throughout the remainder of the book.



Sams Teach Yourself Game Programming in 24 Hours
Sams Teach Yourself Game Programming in 24 Hours
ISBN: 067232461X
EAN: 2147483647
Year: 2002
Pages: 271

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net