Second, the first DirectDraw instance To use DirectDraw, you must first create an instance of the DirectDRAW object to characterize the display adapter card on your computer, and then use the interface method to handle the object. Also need to create an instance of one or more DirectDrawSurface objects to display the game. Ddex1 first creates a DirectDraw object, then create a primary surface and a background buffer (back buffer) and then converts between the surface. DDEXX examples are written in C . If you are using a C compiler, you must make the code appropriately change, at least the pocket to point to the interface method.
1. First, the DirectDraw object DDEX1 program is initialized in the DOINIT function contains the initialization code of DirectDraw: // Creating the primary DirectDraw object DDRVAL = DirectDrawCreate (NULL, & LPDD, NULL); if (DDRVAL == DD_OK) {// Get exclusive mode DDRVAL = LPDD-> SetCooperativeelevel (HWnd, DDSCL_EXCLUSIVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELE (DDRVAL == DD_OK) {ddrval = LPDD-> setDisplayMode (640, 480, 8); if (ddrval == dd_ok) {// Creating a background buffer the main surface region ddsd.dwSize = sizeof (ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; ddsd.dwBackBufferCount = 1; ddrval = lpDD-> CreateSurface (& ddsd, & lpDDSPrimary, NULL); if (DDRVAL == DD_OK) {// Gets the pointer of the background buffer DDSCAPS.DWCAPS = DDSCAPS_BACKBUFFER; DDRVAL = LPDDSPRIMARY-> GetAttachedSurface (& DDSCAPS, & LPDDSBACK); if (DDRVAL == DD_OK) {// Draw some text if (LPDDSPRIMARY-> Getdc (& HDC) == DD_OK) {setBkcolor (HDC, RGB (0, 0, 255)); setTextColor (HDC, RGB (255, 0)); Textout (HDC, 0, 0, SZFRONTMSG, LSTRLEN (SZFRONTMSG)); LPDDSPRIMARY-> ReleaseDC (HDC);} if (LPDDSBACK-> getDC (& HDC) == DD_OK) {setbkcolor (HDC, RGB (0, 0, 255) ); SetTextColor (HDC, RGB (255, 255, 0));
Textout (HDC, 0, 0, SzBackMSG, LSTRLEN (SZBackMSG)); LPDDSBACK-> ReleaseDC (HDC);} // Create a timer IF of the flip page (SetTimer (hwnd, timer_id, timer_rate, null) {Return TRUE; }}}}}} WSPRINTF (BUF, "Direct Draw Init Failed (% 08LX) / N", DDRVAL); ............ The following detailed description of the creation of the DirectDraw object initialization and prepares the surface. Each step. 2. Creating a DirectDraw object Creating an instance of a DirectDraw object, you should use the DirectDrawCreate API function, you can also use the COCREATEINSTANCE function in COM. DirectDrawCreate characterizes the display device with a global unified marker Guid (GlobalLoBally Unique Identifier), in most cases, GUID is NULL (using the system's default display device, "empty device"); pointer points to the address of the DirectDraw object; Three parameters are always NULL (for future expansion). The following code indicates how to create a DirectDraw object and the inspection is successful. DDRVAL = DirectDrawCreate (NULL, & LPDD, NULL); if (DDRVAL == DD_OK) {// LPDD IS is a legal DirectDraw object} else {// DirectDRAW object cannot be created}
3, Set the display mode Setting the display mode of the DirectDRAW application requires two steps: first call the iDirectdraw :: setCoopeRarativeEvelEvelLevel method to set the requirements in this mode, once the requirements are determined, then use the IDirectdraw :: SetDisplayMode method to select the display resolution. Before changing the display resolution, you must also specify the DDSCL_EXCLUSIVE and DDSCL_FULLSCREEN flags via the iDirectDraw :: SetCooperativeEvelEvel method. This allows the game program to fully control the display device, and other applications cannot share the display device at the same time. The DDSCL_FULLSCREEN flag indicates that the program is set to full screen mode. The following code shows how to use IDirectDraw :: SetCooperativeLevel Method: HRESULT ddrval; LPDIRECTDRAW lpDD; // already created by DirectDrawCreate ddrval = lpDD-> SetCooperativeLevel (hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); if (ddrval == DD_OK) {// fullscreen Excise mode Setting success} Else {// call is unsuccessful, but the program can continue to run}
If iDIRECTDRAW :: SETCOOPERATIVELEVEL does not return DD_OK, you can still run the program, but not full screen mode, sometimes some unpredictable errors. So you should display an error message, let the user know what happened, by the user to decide whether to continue the game. When using iDirectdraw :: SetCoopeRATIVELEVEL, you must transfer a handle to the window (HWND), allowing the window to determine when the application is not normally stopped. For example, if a GP error or GDI is flipped (FLIP) to the background buffer, the user cannot access the current screen. In order to avoid this, DirectDraw has a background waiting process that captures all messages sent to the window, use these messages to determine when the application is terminated. If a new window is created, you must make sure that the window is active, otherwise, there will be a series of events that cannot continue to work. 4. Changing the display mode Once the application's operating mode is selected, you can use the idirectdraw :: setDisplayMode method to change the display mode, the following code sets the display mode to 640x480x256: HRESULT DDRVAL; LPDIRECTDRAW LPDD; // already create DDRVAL = LPDD -> setDisplayMode (640, 480, 8); if (DDRVAL == DD_OK) {// Change mode Success} Else {// Display mode can not change // The system may not support this mode} When setting the display mode, it should Make sure that if the user's device does not support higher resolution, the application should return to the standard mode supported by the system. If you display a resolution of the design, IDirectDraw :: setDisplayMode returns a DDERR_INVALIDMODE error value. Therefore, when setting the resolution, you should first use the IDirectDraw :: EnumDisplayMode method to detect the performance of the user's display device.
5. Creating a flippable surface (FLIPPABLE SURFACE) After setting the display mode, you must create the surface where the application is placed. In DDEX1, we use the iDirectDraw :: SetCoopeRarativeEvelEvel method to set the program exclusive full screen mode, and then create a flip surface. If you use iDireCTDraw :: SetCoopeRATIVELEVEL to be DDSCL_NORMAL mode, you can only create a block of writing.
6. Define the first step in which the surface requirement to create a flipped surface is to define the requirements of the surface in the DDSurfaceDesc structure. The following code describes the definition of the structure and creates the flag required to convert the flip surface: // Create a main surface DDSD.dwsize = sizeof (DDSD) with a background buffer; DDSD.DWFLAGS = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; DDSD.DDSCAPS .dwcaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; DDSD.DWBACKBUFFFERCOUNT = 1; Example, member variable DWSIZE is set to the size of the DDSurfaceDesc structure. DWFlags flag Specifies which domains in the DDSurfaceDesc structure can store valid information. In DDEX1, DWFlags pointed out that you need to use a DDSCAPS structure (DDSD_CAPS) and create a background buffer (DDSD_BACKBufferCount). DWCaps indicates the flags of the DDSCAPS structure, which specifies a master surface (DDSCAPS_PRIMARYSURFACE, a flip surface (DDSCAPS_FLIP), and a complex surface (DDSCAPS_COMPLEX). Finally, the program specifies a background buffer. The background buffer is the background image and the person will be written, which can be converted to the main surface. In this example, the number of background buffers is 1, in fact, as long as there is enough display memory, you can create any multiple background buffers, usually every 1m display memory can only be used to create a background buffer. The surface of the surface can be either displayed, or a system memory. DirectDRAW will automatically use system memory when using the displayed memory (for example, 2 background buffers that only 1m display memory) will automatically use. You can specify only system memory or only display memory only by setting DWCaps in the DDSCAPS structure to DDSCAPS_SYSTEMEMORY or DDSCAPS_VIDEMEMORY. If DDSCAPS_VIDEOMEMORY is specified, there is not enough display memory to create a surface, iDirectdraw :: CreateSurface will return a DderR_OutofVideoMory error.
7. Creating the surface fills the DDSurfaceDesc structure, you can use this structure and LPDD, LPDD is a pointer to the DirectDraw object created with the DirectDrawCreate method. The following code shows this process: ddrval = lpdd-> createSurface (& DDSD, & LPDDSPRIMARY) NULL); if (ddrval == dd_ok) {// LPDDSPRIMARY POINTS TO New Surface} else {// Surface WAS NOT CREATED RETURN FALSE;} If the call is successful, the idirectdraw :: createSurface function returns the pointer LPDDSPRIMARY to the main surface. When the main surface of the pointer is available, you can call the method of obtaining IDirectDrawSurface :: GetAttachedSurface back buffer pointer, as follows: ddscaps.dwCaps = DDSCAPS_BACKBUFFER; ddrval = lpDDSPrimary-> GetAttachedSurface (& ddcaps, & lpDDSBack); if (ddrval == DD_OK) {// LPDDSBACK POINTS to the back buffer} Else {Return False;} If the iDirectdrawsurface :: GetAtTachedSurface calls success, the LPDDSBack parameter points to the background buffer by providing the address of the main surface and setting the DDSCAPS_BACKBuffer flag.
8, after the coloration surface creates the main surface and the background buffer, DDEX1 submits some text to the main surface and background buffer using the standard Windows GDI function, the code is as follows: if (LPDDSPRIMARY-> Getdc (& HDC) == DD_OK) { SetBkcolor (HDC, RGB (0, 0, 255); setTextColor (HDC, RGB (255, 255, 0)); Textout (HDC, 0, 0, Szfrontmsg, Lstrlen (SzfrontMSG)); LPDDSPRIMARY-> ReleaseDC (HDC );} IF (LPDDSBACK-> Getdc (& HDC) == DD_OK) {setBkcolor (HDC, RGB (0, 0, 255)); setTextColor (HDC, RGB (255, 255, 0)); Textout (HDC, 0 , 0, SzBackMSG, LSTRLEN (SZBACKMSG)); LPDDSBACK-> ReleaseDC (HDC);} The iDirectdrawSurface :: GETDC method is used to lock the handle and lock the surface. If you don't want to use the Windows function of your handle, you can also lock and unlock the background buffer using the iDirectdrawsurface :: Lock and IdirectDrawSurface :: UNLock method. The memory of the lock surface (whether the entire surface is also part of it) ensures that your application and system will not access this memory at the same time. In addition, the program cannot flush the surface unless the memory is unlocked. In this case, use the Windows GDI function setBkcolor to set the background color after the lock surface, use setTextColor to set the text color, then output the text to the surface using Textout. When the text is written into the buffer, the idirectdrawsurface :: releasedc method is used to unlock the surface and release the handle. Good habits are that after writing data to the background buffer, call IDirectDrawsurface :: releasedc or idirectdrawsurface :: unlock. In general, when writing data to the surface, the surface is the background buffer, and then the buffer is turned out into the main surface. In DDEX1, there is an important delay before the first flip surface. So DDEX1 writes data to a main buffer to avoid too long time intervals when the start is displayed. It will be said later that DDEX1 will write data to the background only during WM_TIMER. Initialization functions or header heads may be written to the main buffer. It should be noted that once the IDIRECTDRAWSURFACE :: UNLock is unlocked to the surface, the pointer to the surface becomes invalid, and the iDirectDrawsurface :: Lock method must be used again to obtain the valid pointer of the surface memory.
9. After the writing surface and the flip surface are completed, DDEX1 starts processing a message loop. During the message cycle, complete the lockup background buffer - write new text-unlock the background buffer-flip surface. WM_TIMER contains most of the code in writing data and flipping surfaces. The first half of the WM_TIMER message is used to write data to the background buffer, and the "Phase" variable is determined whether to write the main buffer message or write the background buffer message. If PHASE is 1, represent the message written in the main buffer, then change the phase to 0; if 0, represent the message written in the background buffer, and then change the phase to 1. Note that the messages in both cases are written to the background buffer. After writing the message, the background buffer is unlocked using the idirectdrawsurface :: releasedc method. The following code implements this: case wm_timer: // Flip Surfaces if (bactage) {if (LPDDSBACK-> Getdc (& HDC) == DD_OK) {setBkcolor (HDC, RGB (0, 0, 255)); setTextColor HDC, RGB (255, 255, 0); if (phase) {textout (HDC, 0, 0, SZFRONTMSG, LSTRLEN (SZFRONTMSG)); Phase = 0;} else {Textout (HDC, 0, 0, SzBackMSG, Lstrlen (szbackmsg); Phase = 1;} lpddsback-> releasedc (hdc);
After the lock, use the idirectdrawsurface :: flip method to turn the background buffer into the main surface, the code is as follows: While (1) {HRESULT DDRVAL; DDRVAL = LPDDSPRIMARY-> FLIP (null, 0); if (DDRVAL == DD_OK) {Break;} f (DDRVAL = DDERR_SURFACELOST) {if (DDRVAL = LPDDSPRIMARY- & G> VAL! = DD_OK) {Break;}} f (DDRVAL! = DDERR_WASSTILLDRAWING) {Break;}} example, LPDDSPRIMARY indicates the main surface And its posterior buffer. After calling the idirectdrawsurface :: FLIP method, the main surface and the rear surface are swapped. After the call is successful, return DD_OK, the program terminates the While loop; if you return Dderr_Surface :: The program terminates the While loop and returns an error value. In addition, as mentioned above, even if the IDirectDrawSurface :: flip is successful, the exchange is not immediately complete, it will wait until the system is completed after this. For example, the previous surface flip has not happened, and idirectdrawsurface :: flip returns DDERR_WASSTILLDRAWING. In this example, idirectdrawsurface :: flip continues to loop until returns DD_OK ..
10. Release the DirectDRAW Object When F12 is pressed, the DDEX1 program processes the WM_DESTROY message before exiting, which calls the Finiobjects function, and the Finiobjects function contains all the iUnknown release calls, the code is as follows: static void finiobjects (void) { IF (LPDDSPRIMARY! = null) {lpddsprimary-> release (); lpddsprimary = null;} lpdd-> release (); lpdd = null;}} / * finiobjects * / program detection DirectDRAW object The pointer (LPDDSPRIMARY) of the pointer (LPDD) and the DirectDrawSurface object is equal to NULL, which is obviously not NULL in this example. Then DDEX1 calls the idirectdrawsurface :: release method minus the reference value of the DirectDrawSurface object, which will make its reference value becomes 0, the DirectDrawSurface object is released, and the DirectDrawSurface's pointer is set to a null value, then undo. The program is called iDirectdraw :: Release reduces the reference value of the DirectDRAW object to 0, and the DirectDRAW object and its pointer are released. The above DDEX1 is the most basic application of DirectDraw. It first creates a DirectDraw object and a DirectDrawSurface object. Create a home surface and its rear buffer, output text to the background buffer, then transform the surface. The second example DDEX2 extends the function of DDEX1, which can transfer a bitmap file into the backbrew. The third example DDEX3 further, in addition to a major surface and the background buffer, two screens are created, transfer the bitmap into each screen, then use the idirectdrawsurface :: bltfast method to put a single screen The content bit block of the surface is transmitted to the background buffer, then flip the surface and transmits the content bit block of the other screen outside to the background buffer. These features will be discussed in detail below.
11. Tune the position of the bitmap, such as Ddex1, the DOINIT function is the initialization function of DDEX2, the same, until the following code: lpddpal = ddloadpalette (LPDD, SZBACKGROUND); if (lpddpal == null) GOTO error; ddrval = lpDDSPrimary-> SetPalette (lpDDPal); if (! ddrval = DD_OK) goto error; // load a bitmap into the back buffer ddrval = DDReLoadBitmap (lpDDSBack, szBackground);. if (! ddrval = DD_OK) goto error The first row of the code returns a value from the function DDLoadPalette, which is in the ddutil.cpp file in C: / DX5SDK / SDK / Samples / MISC, so it is necessary to join DDUTIL.CPP and DDUTIL.H when compiling DDEX2. Most DirectDraw programs require this file. In DDEX2, the DDLoadPalette function creates a DirectDrawPalette object from the Back.BMP file. The DDLoadPalette function first checks the file or resource exists for creating a palette. If there is no existence, create a default palette. In DDEX2, it extracts the palette information from the bitmap file and stores the structure pointed to by the APE, then create a DirectDrawPalette object as follows: PDD-> CreatePalette (DDPCaps_8bit, APE, & DDPAL, NULL); Return DDPAL; when IdirectDraw: : When the CreatePalette method returns, ddpal points to the DirectDrawPalette object. APE is a pointer to a structure that includes 2/4/16/256 linear entities, and the number of entities is determined by the dwflags parameter called by idirectdraw :: CreatePalette. In this example, DWFLAGS is set to DDPCAPS_8bit, which means that there are 256 entities in the structure, each entity has four bytes (red, green, blue, and flag bytes).
12. Set the palette to create a palette after transferring the bitmap into the back buffer, you can transfer the DirectDrawPalette object's pointer DDPAL to the main surface by calling the IDiretTe method, the code is as follows: ddrval = lpddsprimary-> setPalette (LPDDPAL); if (DDRVAL! = DD_OK) // setPalette failed calls the IDirectdrawSurface :: setPalette method, the DirectDrawPalette object is together with the DirectDrawSurface object, and when you need to change the palette, you only need to create a new The palette is set to it. After the object is linked together with DirectDrawPalette DirectDrawSurface objects, DDEX2 Back.bmp using the following code files into the back buffer: // load a bitmap into the back buffer ddrval = DDReLoadBitmap (lpDDSBack, szBackground); if (ddrval = DD_OK.! ) // load failed DDRELOADBITMAP is another function in ddutil.cpp, which transfers bitmaps to the existing DirectDRAW surface from files or resources. In this example, it puts the back.bmp pointing by SZBackground into the background buffer pointing to LPDDSBack. DDRELOADBITMAP calls the DDCopybitmap function to copy the file to the background buffer and extend to the appropriate size. The DDCopyBitmap function removes bitmap into memory, use the getObject function to get the size of the bitmap, then get the size of the background buffer to place bitmap with the following code: // Get size of surface. Ddsd.dwsize = sizeof (ddsd) DDSD.DWFLAGS = DDSD_HEIGHT | DDSD_WIDTH; PDDS-> GetSurfaceDesc (& DDSD); DDSD is a pointer to the DDSurfaceDesc structure that stores the current description of the DirectDRAW surface. The member of the DDSurfaceDesc structure describes the high and width of the surface by DDSD_HEIGHT and DDSD_WIDTH. IdirectdrawSurface :: getSurfaceDesc method Use the appropriate value to the structure, the example is 480, and the width is 640. DDCopyBitmap function locks the surface and copies the bitmap to the background buffer, and then stretch or compress the bitmap with the StretchBLT function. The code is as follows: if ((hr = pdds-> getdc (& hdc)) == dd_ok) {stretchblt HDC, 0, 0, DDSD.dwwidth, ddsd.dwheight, hdcimage, x, y, dx, dy, srcopy); PDDS-> ReleaseDC (HDC);} 13, transmit Ddex2 from the exterior surface block transmission DDEX2 is basically the same . DDEX2 opens a bitmap file and sent it to the background buffer and flip the background buffer and main surface. However, this is not particularly ideal for display bitmaps. DDEX3 extends the function of DDEX2, which adds two screen buffers, and each buffer stores a bitmap.
Here is part of DDEX3 in doInit function, function is to create a buffer zone outside the two screens: // Create an offscreen bitmap ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; ddsd.dwHeight = 480. ; ddsd.dwWidth = 640; ddrval = lpDD-> CreateSurface (& ddsd, & lpDDSOne, NULL); if (ddrval = DD_OK!) {return initFail (hwnd);}. // Create another offscreen bitmap ddrval = lpDD-> CreateSurface ( & DDSD, & LPDDSTWO, NULL); if (DDRVAL! = DD_OK) {Return INITFAIL (HWND);} You can see from the code, dwflags indicates the program using the DDSCAPS structure and sets the high and wide width of the buffer. The DDSCAPS_OFFSCREEN flag in the DDSCAPS structure is specified that the surface is the exterior buffer, which will be high and wide to 480 and 640 in the DDSurfaceDesc structure, and then use the iDirectdraw :: CreateSurface method to create the surface. Because the size of the outer surface of the two screens, create a second buffer only need to run idirectdraw :: CreateSurface (of course, different pointers). You can also set DDSCAPS_SYSTEMMORY or DDSCAPS_VIDEMEMORY in DDSCAPS to specify that the screen outer buffer is placed in the display memory or system memory. Place the bitmap in the display memory can speed up the data transfer speed between the background buffer and the exterior surface, which is very important in bitmap animation. However, if you specify DDSCAPS_VIDEOMEMORY for the exterior buffer and there is not enough display memory to transfer the entire bitmap. When the surface is created, the program returns a DDERR_OUTOFVIDEMEMORY error value. 14. After the bitmap file is built into the exterior surface, DDEX3 uses the INTSURFACES function to load the bitmap from the frntback.bmp file to both surfaces. InitSurfaces function using two bitmaps transferred DDCopyBitmap function, as follows: // Load our bitmap resource hbm = (HBITMAP) LoadImage (GetModuleHandle (NULL), szBitmap, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); if (hbm =. = NULL) RETURN FALSE; DDCopyBitmap (LPDDsone, HBM, 0, 0, 640, 480); DDCopybitmap (LPDDSTWO, HBM, 0, 480, 640, 480); deleteObject (HBM); return true; frntback.bmp file by two Part of the composition, half on, half is below. The DDCopyBitmap function is transferred to the first half of the first screen LPDDSOONE, and the lower half is transferred to the second surface LPDDSTWO.