This article is for a few months to learn programming experience: read the C tutorial, see the basic C grammar; a little VC usage experience, know how to form a project; understand some of the basic concepts of Windows programming, such as windows , Message loop, etc .; also, you don't understand the information :).
I have seen a few books about DirectDraw, these books are good, thank you by the author. Insufficient in the United States is that the part of these books is high, although we can still understand some concepts, there will be many confused in organizing these documents. Here I reiterate the concept of books, and let go of their own ideas. Less nonsense, the words retired.
First of all, some things that are unable to say. I think they should not mention because these things may be too foundation, and masters often ignore these things to newcomers. As a newbie, I think the framework of the program and organizational methods are more urgent than more familiar with several APIs. Now Lets Begin:
Write a game program, be familiar with its processes, and exercise the ability of the organizational file. For novices, I recommend that the procedure to write and analyze the procedures you want to write according to the class, don't advocate this time you jump. This is a good habit, of course, it is also beneficial to grasp the ideological methods of programming as soon as possible. Let's take a summary process and the corresponding program framework.
(The frame is displayed ..)
So how do you use the above process to build our general program framework? We already know something in Windows programming, maybe you still know the MFC. We don't advocate MFC here, although it has been packaged in a lot of useful models, but it is cumbersome to our compilation. Ok, let's talk. Since WindowsAPI is used, you can create a file WinMain.cpp to handle some of the problems related to windows in Windows programming. In this way, we should complete the creation window in this document, handle basic messages (such as "ESC" exit, etc.), the control program exits. Is there anything in the window during the game? Of course, the window in the game is not only a Windows window, but the display section relies on DirectDraw to control, then we have to call the relevant modules in WinMain.cpp. This seems that almost the entire process is almost included in WinMain.cpp, which controls the entire framework of the program and provides a platform for your program core. The platform has, then the next step, Gamemain.cpp is born, this mainly used to control each component of the game, coordinate the work, complete the game setting initialization, the game in the game, control the game exit. Your talents have played here. In general, the game program will have several fixed components: display, music, information input. It provides a convenient component DirectDraw, DirectSound, and DirectMusic, DirectInput. Corresponding we creates myDirectdraw.cpp, mydirectaudio.cpp, mydirectinput.cpp to control the respective features of each component. Obviously, this will be served for Gamemain.cpp, and is called by Gamemain.cpp. Then we can see that our procedures should include the relationships:
(The chart shows that the 555) The program file can be organized, and it should be seen by this table. In this way, we found that Winmain.cpp seems to be an investor, providing a development platform, he only pays attention to the overall process, not paying attention to details. GameMain.cpp seems to be a project person in charge, the details of the entire project are planned, to control, interact with WinMain.cpp, to complete the project, coordinate myDirectdraw.cpp, mydirectaudio.cpp, myDirectinput.cpp jobs. These three guys in myDirectdio.cpp, mydirectaudio.cpp, mydirectinput.cpp, are employees, responsible for their work, complete the corresponding functionality to GameMain.cpp. The organizational program should be such ideas, of course, specific questions. Then let's take a look at the DirectDraw section. First, do preparing for work, install DirectX SDK, add DXGUID.LIB and DDRAW.LIB in VC (I didn't want to say this, I saw a tutorial, it added less DXGUID.LIB, depressed, I am a big time, harm people I feel very deeply), this, the DirectDraw program can be compiled. Take it, DXGUID.LIB defines all global handles in DirectX, DDRaw.lib is the library used by DirectDraw. Here we can write code. Here will we mainly look at MYDIRECTDRAW.CPP to this, I chose several source code, doing reference research, they will pack with this article. I am still used to the first bird's eye view: General, at least two parts in myDirectdraw.cpp (notice not to forget the reference header file DDRAW.H): initialization and end. First look at initialization, the so-called initialization is nothing more than a preparation, and the needed definition is created to be posted on hand. Take a look at the initialization function INTMYDIRECTDRAWINIT (VOID) how to write. First define a pointer to the DirectDraw object, create a DirectDraw object, query to get the latest DirectDRAW interface, set the collaboration level, set the display mode. Through these steps, you can create a black screen, that is, the space we need has opened up, of course, the initialization of the DirectDraw program is not as simple as it is. To operate 2D graphics, we must then create a homepage and buffer page and off-screen page, in short, if you need to prepare things, you need to be ready before you can put it here. Then Int MyDirectDrawShut (void) should release our open things, usually release the main page pointer, and the DirectDraw interface, etc.
It is so like this, Go ON, this fine, huh, first definition pointer: lpdirectdraw lpddraw_temp; represents the entire display system Create an object: if (Faled (DirectDrawCreate (Null, & lpdddddddddddddddddddddDraw_temp, null))) {MessageBox (Null, Text) "Direct Draw Create Error!"), Text ("WRONG!"), MB_OK; Return (0);} This uses a failed macro to detect whether it is created, which can help us track errors. Function DirectDrawCreate (NULL, & LPDDRAW_TEMP, NULL) is created, the first parameter is the global unique marker showing the drive, where null represents the current display device; the second parameter is used to accept the created DirectDraw object address, here with & lpddraw_temp Accept; the third parameter? Don't ask, give it null, don't want to provoke. Query DirectDraw Interface: if (FAILED (lpDDraw_temp-> QueryInterface (IID_IDirectDraw7, (LPVOID *) & lpDDraw7))) {MessageBox (NULL, TEXT ( "DirectDraw QueryInterface error!"), TEXT (), MB_OK "Wrong!"); Return (0);} Take the new interface through the queryinterface () method, here is iDirectdraw7 instead of iDirectDraw8, pointing to the IDirectDraw7 pointer in LPDDRAW7, this is a global variable, which can define lpdirectdraw7 lpddraw7 = null; By the way, the general situation You should know the interface you use, this is related to SDK, so this step is not necessary. Set cooperative level: if (FAILED (lpDDraw7-> SetCooperativeLevel (main_window_handle, DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT))) {MessageBox ( "! DirectDraw SetCooperativeLevel error" NULL, TEXT (), TEXT ( "! Wrong"), MB_OK) Return (0);} Determine your programs and Windows relationships, it applies for the resource used by the Windows, such as it is full screen, exclusive, etc.
The first parameter is the main window handle, which is created in your WinMain (). There are several control flags in your WinMain (). Commonly used usage is as follows: DDSCL_FULLSCREEN: full screen mode, must be used with DDSCL_EXCLUSIVE simultaneously using DDSCL_EXCLUSIVE: request exclusive level , Must use DDSCL_FULLSCREEN to use DDSCL_ALLLOWREBOOT: Allow the system to detect CTRL ALT DEL button message (this is useful) I think, these three are enough, the other will set the display mode: IF (Failed (LPDDRAW7 -> SetDisplayMode (800, 600, 16, 0)))) {MessageBox (Null, Text ("DirectDraw SetDisplayMode Error!), Text (" WRONG! "), MB_OK; Return (0);} The display mode to be used may be different from the user's current display mode. To set the setDisplaymode () to force the model it set, it is easy to understand, the first three parameters are easy, the fourth, 0 means using the default Refresh rate, the fifth parameter here is 0, there must be DDSDM_Standvgamode, there must be ddsdm_standvgamode (you can understand, just don't know what this 0 means, I think it should be default. To this, I want to create it. We need it. Space, later, with the improvement of our requirements, gradually improve the initialization function, now look at the end function: Release interface: if (lpddraw7) {lpddraw7-> release (); lpddraw7 = null;} After the home page Side, buffer page, etc., it is necessary to pay attention to the resource you apply, this is a good habit. It should be noted that the first creation must be released, because the original created environment is in the first environment. Work. So, we just do the most basic preparation work, what else can you do? Do you want to do something? Let's take a break, say something you have to say: then let's take a look at the color. Related to color, divided into such a few, 256 colors (8), 16-bit enhancement color, 24-bit true color and 32 real color. 256 color estimates are rarely used, and 16 is still mainstream, so we focus on A 16-bit enhancement color, usually 16-bit enhanced colors have two formats: 5.5.5 and 5.6.5, generally represented by RGB representation. Where: 5.5.5 format, the highest bit is an alpha bit, indicating that it is transparent, the rest 15 represents 5 digits of color, red and green, which can represent 32786 colors.
Through macro #define _RGB16bit555 (R, G, B) ((b% 32) ((g% 32) << 5) ((R% 32) << 10)) to 5.5.5 format pair 5.6 .5 format, obviously, red and blue, green 6, this can represent 65536 colors, the same, macro #define _RGB16Bit565 (R, G, B) ((B% 32) ((g% 64) < <6) ((R% 32) << 11)) Change to the shift in the middle of the 5.6.5 format, I can't figure it out, just can't see it, the more you can see it. So which format should I use? Look at the machine, most of you can use 5.6.5, of course you can detect it, as for how to detect, I don't say it, please check the relevant information. 24-bit? Red green blue 8, 32-bit? Add an Alpha bit, the rest of the same 24 digits. It's better to say this. What do you want to do below? I want to get a color on the screen, see the source code of the attached code, Code1, will you find that we should add it on the basis? Yes, the page should be created in the initialization function, which is the DirectDrawSurface object, what is the difference between it and the DirectDRAW? DirectDraw object, we know that the entire display system is that your graphics card and the screen consisting of the screen. Can you draw some things directly on the monitor screen? No, the screen on the screen is displayed through the memory and memory operation, then corresponds to the screen, there should be a rectangular white paper in the memory, and then you can display it on the screen. That white paper is the DirectDrawSurface object that represents a continuous linear data area in the memory or memory. This data area can be identified and confirmed by representing the DirectDRAW object of the display hardware. Generally, there are 4 pages that can be created. We often use the main page (Primary Surface) and offshoot page (offscreen plain) first say the home page, that is, a picture, the graphic in the main page is displayed in the screen, direct There is a problem on the main page, more data, the image will not be continuous, to use a buffer technology to create a back buffer (a background buffer), whitening, is in memory, then open a zone, The area of the main page corresponds to the main page, you can do not directly operating the main page, first write the data here, and then become visible by switching. The slap is different, it is the same picture as the main page, but it will never be expressed on the screen, usually used to store the bitmap, used to burn the later bitmap image Blit to the main page or the background buffer. So let's take a look at the location and role of these pages in work:
(There is a chart here, which is not shown), which we generally understand the role of the page, then initialize it, you should create it to wait for the operation of the page. So our initialization functions should be added: MemSet (& DDSD, 0, SIZEOF (DDSD)); DDSD.DWSIZE = SIZEOF (DDSD); // Set dwflags, tell DirectDraw which members can use DDSD.DWFLAGS = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; // define ddsCaps.dwCaps, requesting a page buffer with a background surface ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; // set number is defined as the back buffer 1ddsd.dwBackBufferCount = 1; // Create a home page if (FAILED (LPDDRAW7-> CreateSurface (& DDSD, & LPDDPRIMARY, NULL)) {MessageBox (NULL, Text ("DirectDraw Create Primary Surface Error!"), Text ("Wrong!"), MB_OK; Return (0);} // provided ddsCaps.dwCapsddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; // connected to the Home page and back buffer if (FAILED (lpDDprimary-> GetAttachedSurface (& ddsd.ddsCaps, & lpDDback))) {MessageBox (NULL, TEXT ( "DirectDraw Create back surface error! "), Text (" WRONG! "), MB_OK); Return (0);} Here, we have to define several global variables: extern lpdirectsurface7 lpddprimary; extern lpdirectsurface7 lpddback; extern ddsurfaceDesc2 DDSD; this is a pointing master page Pointer, a pointer pointing to the background buffer, and a page description structure. Needless to say, these definitions You can place it in MyDirectDraw.h. By populating a member of the DDSD structure, the type of the page you want to create is declared. Here we didn't create a slap page. With the main page and the background buffer can complete some relatively simple, the data is not a lot of graphic display, the data is too complicated, and the off-screen page should be created. Corresponding, at the end, in addition to the release of the DirectDraw7 interface, release the back buffer pointer and the home page pointer sequentially. Still remind, first release it first, otherwise you will be dead. How to go to Release these things, look at the code in Code1, it is easy to understand.
By the way, let's take a look at how to create an off-screen page, look at the following code: DDSurfaceDesc2 ddsd; lpdirectsurface7 lpddopl; // These two definitions don't have to say MEMSET (& DDSD, 0, SizeOf (DDSD)); // Clear Structure DDSD.dwsize = sizeof (ddsd); // Sets the size ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; // the specified page type ddsd.dwWidth = 600; ddsd.dwHeight = 800; // set offscreen Page size if (Failed (LPDDRAW7-> CreateSurface)) {MessageBox (Null, Text ("DirectDraw Create Offscreen PLAIN Error!"), Text ("Wrong!"), MB_OK; Return (0 );} // Create an off-screen page Okay! Create a remote page, say, because the off-screen page is a separate page, not belonging to any other page, so you must specify its size. We will say this about the creation of the page. If there is anything to have a good thing? Looking up, the sky is bright, I will sleep, wake up, then say, go to call. ... N hours later ... well, since we only owe Dongfeng, we will say Dongfeng. Simple drawing, we can see the operation of the bitmap of the use of the application (on the screen) About the page (the figure is also these two things) I have also organized, I can't help it, I can organize what I understand to the program ( Khan! I haven't really understood it yet, I'm trying to say this.) I am studying, I can understand it, I can organize it, then, then, we can only be dismantled like I have seen. It has been, starting the list of books. I hope that after the copy is complete, I can have a bit of an eyebrow. From the previous page table, it can be seen that the operation here is nothing more than load bitmap, map, page turning display, and scrapbooking screen. Then let's talk about step by step. There are not much about the matter, on the module module, code segment, and previous files. Everyone can't understand, don't marry me, understand the years. First look at the load bitmap, you will access the bitmap load to the remote screen, you want to access through the HDC of Windows, with WindowsAPI to match DirectX to complete.
We look at the code segment: HDC HDC, HDC1; // Declaration HDC object, HDC is used to store bitmaps, HDC1 represents DCHBITMAP Bitmap on the panel page; // Declaration hbitMap object HDC = :: createcompataterialdc (null); // Establishment Current display mode compatible DC (NULL) bitmap = (hbitmap) :: loadImage (null, "bgroud.bmp", image_bitmap, 640, 480, lr_loadfromfile); // Load 640 * 480 bitmap :: SelectObject (HDC, Bitmap; // Use the Windows function to set the content in the HDC to load the bitmap now to the DC. Below the DC's bitmap in the off-screen page LPDIRECTSURFACE7 LPDDDOPL; // This definition is not used. HRESULT RESULT; // Why do you use it? Look down to LPDDOPL-> GetSurfaceDesc (& DDSD); // DDSD is the same as RESULT = LPDDDOPL-> getDC (& HDC1) in front; // with getDC () to acquire DC if (Result! = DD_OK MessageBox ("Take a temporary sector DC failed"); // Whether to succeed, learn about Result :: Bitblt (HDC1, 0, 0, DDSD.dwwidth, ddsd.dwheight, HDC, 0, 0, SRCCOPY) // This is the Windows function lpddopl-> releasedc (hdc1) for the map; // Release the DC of the panel page, must release this, we have put bitmap to the remote page, below should be removed The bitmap in the page DC is filled into the Back Buffer and then displayed by the change page. Let's first understand the two DirectDraw's map functions BLT and BLTFAST. The prototype of these two functions has a detailed instructions in the DirectX development manual translated by Old Kings, you can Down on my homepage, you can check it out. Here I simply say: HRESULT BLT (LPDESTRECT, LPDESTRECT defines its left right down coordinate LPDIRECTDRECTDRAWSURFACE7 LPDDSRCSURECTDRECTDRAWSURFACE7 LPDDSRCSURFACE, // Source page pointer LPRECT LPSRCRECT, // Source page area DWORD DWFLAGS, // Control Sign, detailed, please refer to the information structure of the old king's manual lpddbltfx lpdddbltfx. / Source page pointer LPRECT LPSRCRECT, // Source page area DWORD DWTRANS, / / conversion parameters, see Lao Wang Manual
The difference between the two is that BLT has more graphic deficiency, but BLTFAST efficiency is high, how to choose is very clear. Calling one of these two functions can realize the map from the off-screen page to the Back Buffer, the code is as follows: lpddback-> Bltfast (0, 0, LPDDDOPL, CRECT (0, 0, 640, 480), DDBLTFAST_WAIT); // LPDDBACK is us Previously declared the background buffer, create (...) is an object of a CRECT class. If we have declared a CRECT RECT; here can use & Rect instead of single watching this step, or very easy. It seems that it seems to be just a step away, Right, just turn the page (FLIP), just look forward to the page function: HRESULT FLIP (LPDirectDrawSurface7 LPDDDestsurface, // You want to turn to the target page DWORD dwflags) // Usually set to ddflip_wait Description: When the first parameter is NULL, it means to top the next page of the current page. When the change page object is a visible page, such as the home page changing a chain, the FLIP function of the change page is performed asynchronously. That is to say, on these visible pages, call the FLIP function, it just simply tells the hardware to change the page, do not need to wait for the transfer operation to return after the actual completion in the hardware device. This is because the display hardware (display) can only be changed again after completing a vertical refresh. Therefore, the FLIP function call is successful, and does not mean that the page has been completed. Before the actual change operation is performed, the background cache will not be locked and blirl operation. To make the FLIP function actions synchronized with the system CPU, specify the DDFLIP_WAIT flag when calling: lpddprimary-> flip (null, ddflip_wait); Xiaolong tells that we have set a specified bitmap BGroud. BMP is displayed on the screen, which can be used as a background diagram of your game, such as the big chart of the submarine game. It should be explained that if we want to operate on which page (generally back buffer), it is best to lock first, unlock it, prevent the interference of other GDI programs. For example: LPDDBACK-> LOCK (NULL, & DDSD, DDLOCK-WAIT | DDLOCK_SURFACEMORYPTR, NULL); // Lock Background Current LPDDBACK-> UNLOCK (NULL); // Unlock the background buffer to add this two codes to the corresponding position, respectively I.e.