Chapter 6 First Touch: DirectDraw This chapter, you will first contact the most important components in DirectX: DirectDraw. DirectDraw may be the most powerful technology in DirectX because it runs through 2D graphics, and its frame bundle layer is also the foundation of DirectX3D. Of course, DirectDraw is fully integrated into DirectX3D in DirectX8.0. Also, if you have a deep understanding of DirectDraw, it will have the ability to create any DOS16 / 32 type graphics program. DirectDraw is a key to understanding numerous DirectX itself. So, listen carefully.
Here is the knowledge point you want to solve this chapter: • DirectDraw interface · Create a DirectDraw object · Cooperate with Windows · In-depth research mode · Wonderful color · Build the display surface
DirectDraw's interface DirectDraw consists of a series of interfaces. If you review our discussion of the Component Object Model (COM) in Chapter 5, "DirectX Foundation and Horror, then you will understand that the interface is just a function or (and) method for communication with components. set. Look down Figure 6.1 About DirectDraw across interface. Remember, I don't intend to add version numbers to each interface, because we are abstract so far. For example, iDirectDraw has indeed upgraded to 7.0, so when we use DirectDraw, we refer to IDirectDraw7, but now, I just want to show some of DirectDraw's foundation and relationships. Figure 6.1 Interface interface features of DirectDraw, such as what you see, the interface that makes up the DirectDraw: IUNKNOWN: All COM objects must be derived from this base interface, DirectDraw is of course no exception. IUNKNOWN does not have anything that will contain addRef (), Release (), and QueryInterface () functions that will be overloaded by all other interfaces.
IDirectDraw: This primary interface must be created with DirectDraw. The graphics card and related hardware are implied from the literal meaning of IdirectDraw. It is very interesting that since Win98 / ME / XP / NT2000 supports MMS (multi-display support), so you can install more than one graphics card in your system, so there is more than one DirectDraw object. However, this book assumes that there is only one graphics card in the computer, and even if there are multiple graphics cards in the system, the default graphics card is always selected to represent the DirectDRAW object.
IDirectDrawSurface: It represents the true display surface created, operated, and displayed by DirectDraw. A DirectDRAW surface can be present in the VRAM (memory) of the graphics card itself or in the system memory. There are two basic surface types: main surfaces and side surfaces.
The main surface is used to indicate the real video cache that the graphics card is currently being rasterized and displayed. The side surface is often not displayed. In most cases, you will create a single main surface to represent real video playback, then use one or more sidelines to represent bitmap objects and (or) use backup to reply to draw next frame animation The screen is a diagram area (Offscreen Drawing "). In the next chapter we will discuss details about the surface. But now, look at the detailed illustration of Figure 6.2. Figure 6.2 DirectDRAW Surface iDirectDrawPalette: DirectDraw can be used to handle any color depth, from 1 digit color to 32-bit color. Therefore, DirectDraw supports the IDirectDrawPaletTE interface to support video modes of 256 colors or fewer colors. The 256-color mode is widely used when making a series of DEMOs because 256 colors are the fastest video mode when using software rasterization. In the second volume of the DirectX3D instant mode you will turn to 24-bit color because it is the basic video mode of D3D. Whether it is the case, the IDirectDrawPalette interface is used to create, load, operate palette, and attach the palette to those that you create for the DirectDraw program, such as the main surface or the side surface. Figure 6.3 shows the relationship between the drawing surface and the palette. Figure 6.3 Drawing surface and palette relationship iDirectdrawclipper: This interface is used to help the DirectDraw rasterization and bitmap of the bitmap in the subset of the visual display surface. In most cases, you only need to use the DirectDraw clipper when the window-wide DirectX program is neutralized (or) in the cut bitmap exceeding the display surface (whether the main surface or the side surface) is used. The Cool Form of the IDirectDrawclipper interface will use the hardware acceleration function as much as possible. In addition, in the shear bitmap to accommodate the screen size, there is a process of pixel-by-pixel or a process called the Solt statue, and the iDirectdrawclipper interface is deactified. Now, before you start to create a DirectDraw object, let's re-review the previous chapter learned about how to use COM objects. DirectDraw and all DirectX components continue to develop, so their interfaces are constantly updated. Hey, although this chapter refers to the DirectDraw interface, IdirectDrawPalette, and IdirectDrawClipper refer to this chapter, but most of these interfaces have been updated. For example, it is mentioned earlier, iDirectDraw has been updated to iDirectDraw7 when DirectX7.0.
All this means that if you want to use the latest software and hardware features, you must always use iUnknown :: queryinterface () to check the latest interface revisions. But if you want to determine the latest version of the interface, you have to check the DirectX SDK documentation. Of course, in this book you are using DirectX8.0, so you have known this latest, where you have, but you will have an updated interface when you upgrade to DirectX9.0. However, the two volumes of this book are about writing your own rasterization and 3D software, so I will be a short bit. In most cases, you don't use most of the new version of DirectX.
Comprehensive use of each interface, I will simply use each interface to create a DirectDraw program. 1. Create a primary DirectDraw object and get an IDirectDraw7 interface through queryinterface (). Or use DirectDrawCreateEx () to get an IDirectDraw7 interface. Use the interface to set the collaboration level and video mode. 2. Create at least one main surface for drawing using the iDirectdrawSurface7 interface. A palette may be required for the color depth and video mode for the surface. If the color depth of the video mode is less than 8 bits per pixel, use a palette.
3. Create a palette with the IDirectDrawPalette interface, initialize the palette with the rating of the RGB format and associate the palette with the relevant surface.
4. If the DirectDraw program is a window program, or if your rendering bitmap is likely to exceed the boundary of the visual DirectDraw surface, you should at least create a clipper and adjust it to the size of the visual window. See Figure 6.4. Figure 6.4 DirectDraw clipper 5. Draw on the main surface.
Of course, I sail a lot of technical details, but the above five points are common points common to different interfaces. Remember these five points, let us know some details and truly use these interfaces ...
When you create a DirectDraw object in C objects to create a DirectDraw1.0, you have to do is call DirectDrawCreate (), as follows: HRESULT WINAPI DirectDrawCreate (GUID FAR * lpGUID, // guid of object LPDIRECTDRAW FAR * lplpDD, // Receives Interface IUNKNOWN FAR * PUNKOUTER); // com stufflpguid: This is the display-driven GUID you want to use. In most cases, simply set to NULL to use the default hardware. LPLPDD: If the call is successful This will be a pointer to the pointer of an IDirectdraw interface (the translator: no wrong, is a "pointer pointer"). Note that this function returns an IDirectDraw interface instead of the iDirectDraw7 interface. Punkouter: Advanced features, always set to NULL.
Below you may want to use: Create a default DirectDraw object based on the iDirectDRAW interface. LPDIRECTDRAW LPDD = NULL; // Storage for IDirectDraw // Create The DirectDraw ObjectDirectDrawCreate (NULL, & LPDD, NULL);
If the function call is successful, the LPDD will be an available IDirectDraw 1.0 object interface. However, you may like the latest version of the interface, IDirectDraw7. But let us talk about the wrong handling problem before you learn how to do this.
DirectDraw's error handling DirectX's error handling is very simple. There are many macros that can be used to detect success and failure of various function calls. Microsoft is recommended to use the following two macros when testing the DirectX function error: failed (): The detection call is successful. Succeeded (): Detect call failed.
Know that these, you can make your program more regular by joining the error handling code. IF (DirectDrawCreate (NULL, & LPDD, NULL))) {// error} // endiff
Or similar, you can detect successfully: if (successddddd (Null, & lpdd, null)) {// move ONTO next step} // end ifelse {// error} // Else I often use Failed () Macro, because I don't like to consider problems in both logic directions, but what macro you can use, you can follow you. The only problem with the macro is that the macro tells you that there are too little information, which can only check some regular errors. If you want to know the exact error, you can check the return code of the function. Table 6.1 lists the possible return codes of DirectX6.0 DirectDrawCreate ().
Table 6.1. DirectDrawCreate () return codes Return Code Description DD_OK entirely successful DDERR_DIRECTDRAWALREADYCREATED DirectDraw object is created and passed DDERR_GENERIC unknown unknown device error DDERR_INVALIDDIRECTDRAWGUID GUID DDERR_INVALIDPARAMS illegal parameters DDERR_NODIRECTDRAWHW without any hardware DDERR_OUTOFMEMORY bold speculation of some?
The only problem with these constants is that Microsoft does not guarantee that they do not completely change all of the error code. However, I want to encode the following way is absolutely safe. IF (DirectDrawCreate (...)! = DD_OK) {// error} // end if at any time, all functions of DirectDraw define DD_OK, so you can use it as you can use.
Improve the interface As I said, you can use the LPDD to store the basic iDirectDRAW interface from calling DirectDrawCreate (). Alternatively, you can query a new interface to achieve the purpose of using the latest version of the interface through any DirectDRAW interface, to achieve the purpose of using the latest version of the interface (no matter what this interface is The latest DirectDRAW interface, in DirectX7.0, called IDirectDraw7. So you get this interface pointer in the way.
LPDIRECTDRAW LPDD = NULL; // Standard DirectDraw 1.0lpdirectdraw LPDD7 = NULL; // DirectDraw 7.0 Interface 7
// First Create Base IdirectDraw Interfaceif (Failed (DirectDrawCreate (Null)) {// error} // endiff
// Now query for idirectdraw7if (IID_IDD-> Queryinterface (iid_idirectdraw7, (lpvoid *) & lpdd7)))) {// error} // End if now, some important things need to be aware: • Call queryinterface () the way. • Using IdirectDraw7 interface, IID_IDirectDraw7. Typically, all function calls from an interface have the following form: interface_pointr-> method (PARMS ...); all interfaces are identified as follows: IID_IDirectCD here , C represents components, others such as DRAW represents DirectDraw, Sound represents DirectSound, INPUT represents DirectInput, and so on. D represents a number from 2 to N, indicating the interface you want. You can find all these constants from the DDRAW.H file. Continue this example. You may be confused with both IDirectdraw interfaces that have both iDirectdraw interfaces. Do you have to do it? Since you don't need an older version of the interface, you will be like this to throw it away. It is: lpdd-> Release (); lpdd = null; // set to null for safeTy from now on, all functions from the new interface IDirectDraw7 transfer.
WARNING: Because there is a new feature of IdirectDraw7, the freedom of coding changes and the trivial things you have to do. This can be, in addition to the iDirectDraw7 interface more mature and advanced, but also due to most cases it needs and returns the new data type, not the data type defined for DirectX1.0. The only way to determine this irregular change is to check the DirectX SDK documentation, verify the version of the data type returned by any specific function and (or). But this is just a general warning, I will tell you the correct data type in all examples you have encountered in this book. I am so good. By the way, my birthday is 6.14.
In addition to using QueryInterface () from a initialized iDirectDRAW interface pointer (LPDD), there is a more direct "COM Way" to get the IDirectDraw7 interface. In COM, as long as you have an interface ID or IID, you can get the interface pointer of any interface, that is, the interface you want. In most cases, I personally don't admire the use of lower-level COM functions, because I have already sick this. Despite this, when you use DirectMusic, you still have to use a low-level COM method, so at least you will also introduce this process of this low-level call. The following code directly obtains idirectdraw7 interface: // first Initialize Com Libraries //iff loading the CORARIES // i in''t Already loadedif (failed (folded) {// error} // Endix
// Create the DirectDraw object by using the // CoCreateInstance () functionif (FAILED (CoCreateInstance (& CLSID_DirectDraw, NULL, CLSCTX_ALL, & IID_IDirectDraw7, & lpdd7))) {// error} // end if // now before using the DirectDraw object, IT Must // Be Initialized Using The Initialize Method
IF (iDired 4_initialize) {// error} // end if // Now this we're done with com, uninitialize itcouninitialize ();
The above code is a method of creating a DirectDraw object with Microsoft. But here it played a little pattern, it used a macro: idirectdraw7_initialize (LPDD7, NULL); you can do it, and completely with COM: LPDD7-> Initialize (null);
Regardless of which of the two calls, the parameter of the NULL represents the graphics card, and NULL represents the use of the default graphics driver. In short, it is not difficult to understand how the above macro is expanded in the code. I think this is probably trying to make things simple. Now, the good news is that Microsoft has created a function that does not have to be intermediate steps, and then the iDirectDraw7 is created. Usually, it is usually not possible, but in DirectX7.0, they created a new function called DirectDrawCreateex (). About this function, I mentioned in the previous chapter. His prototype the following statement: HRESULT WINAPI DirectDrawCreateEx (GUID FAR * lpGUID, // the GUID of the driver, NULL for active display LPVOID * lplpDD, // receiver of the interface REFIID iid, // the interface ID of the interface you are Requesting iUnknown far * punkouter // advanced COM, NULL);
This is similar to DirectDrawCreate (), but it has a parameter so that you can create any version of the DirectDraw interface. So, the function call to creating the IDirectDraw7 interface is as follows:
LPDIRECTDRAW7 LPDD; // Version 7.0 // Create Version 7.0 DirectDraw Object InterfaceDirectDrawCreateex (NULL, (VOID **) & LPDD, IID_IDIRECTDRAW7, NULL
The only strange place is the type conversion of the interface pointer - pay attention to that (void **), and you must pass an interface in the parameter IDD. In addition, it is still very simple and efficient.
Let us take a few minutes to repeat everything. If we want to use the latest version of DirectDraw, ie 7.0 (because Microsoft in DirectX 8.0 removes DirectDraw), we need an IDirectDraw7 interface. We can create an IDirectdraw1.0 interface using basic DirectDrawCreate () and then use QueryInterface () to get the iDirectDraw7 interface. On the other hand, we can use lower-level COM technology to get iDirectdraw7 directly. Or, we can use the function DirectDrawCreateEx () (from DirectX7.0 to start with this function) directly. Not bad right? DirectX is a bit like x windows, and the same can have 5,000 ways. Now you know how to create a DirectDRAW object and how to get the latest version. Let's take a step forward in the journey that is working on DirectDraw, that is, set the collaboration level.
Working with Windows As you know, Windows is a cooperative, shared environment. Although as a programmer, I have never known how to let the system cooperate with my code, but at least this is an ideal state. In short, DirectX is the same as any other Win32 application, at least, it must notify Windows to apply the resources it to use so that other programs are not applied (and get these resources when DirectX is not using these resources. Basically, as long as DirectX tells Windows what it is doing, it can get the resources it want. This looks fair to me.
In DirectDraw, your only interested is the video display hardware. There are two things you have to care: • Full-screen mode · Window mode in full screen mode, DirectDraw acts like old-fashioned DOS programs. That is to say, the entire screen surface is allocated to your game, you write directly to the video hardware. The other programs do not come into contact with video hardware. The window mode is a bit different. In window mode, DirectDRAW must work more with Windows because other programs may need to update their respective client district windows visible to the user. Therefore, in window modes, your control and exclusive of video hardware are restricted.
Chapter VII "Advanced DirectDraw and Bitmap Drawing" will further discuss window DirectDraw applications, but they may be a bit complicated. Most of this chapter will be deal with full screen mode because they are easier to operate, remember this.
Now you know some importance about the establishment of cooperation between Windows and DirectX. Let's take a look at how to tell Windows's way you need. To set the partner level of DirectDraw, use the function idirectdraw7 :: setCooperativeElevel (), which is a method in iDirectDraw7.
C : If you are a C programmer, syntax iDirectdraw7 :: setCoopeRarativeEvel () may be a little mysterious. :: Operators are called domain operators. This syntax simply represents setCoopeRATIVELEVEL () is a method (or member function) of the iDirectDraw7 interface. The interface is a class, which is just a structure with virtual functions. Sometimes I will omit the prefix and write directly into setcooPERATIVELEVEL (). However, remember that all DirectX functions are part of the interface, and must be called using the function pointer type, such as lpdd-> function (...)
Here is the prototype declaration of iDireAtDraw7 :: setCooperativeEvel (): HRESULT SETCOOPERATIVELEVEL (HWND HWND, // WINDOW Handle DWORD DWFLLAGS); // Control Flags If successful returns DD_OK, the error code is returned. Interestingly, this is the first time you need a window handle in the DirectX function. DirectX (specifically DirectDRAW) requires an HWND parameter to determine the associated window. You only need to simply use the main window handle of your program.
The second parameter of SetCoopertically () is dwflags, which affects the control flags that affect the DirectDraw and Windows collaboration. Table 6.2 lists some of the frequently used signs that can be used together through the "or" operations to obtain a part of the collaboration. Table 6.2. SETCOOPERATIVELEVEL () Control Sign Value Description DDSCL_AllowModex allows Mode X (320x200, 240, 400) display mode. Just use the DDSCL_EXCLUSIVE and DDSCL_FULLSCREEN flags. DDSCL_AllowReboot allows the Ctrl Alt Del combination key to be detected under exclusive mode (full screen mode). DDSCL_EXCLUSIVE requests use exclusive levels. This flag is necessary to use the DDSCL_FULLSCREEN flag. DDSCL_FPUSETUP indicates that the call function wishes to use an optimized DirectX3D floating point operation unit (FPU) (Single Precision and Excetions Disabled DirectX3D does not need to set up the FPU each time. To learn more Please refer to the DirectX SDK document "DirectDRAW Parts Level and FPU Accuracy". DDSCL_FULLSCREEN indicates that you use full-screen mode. Other programs will not draw on the screen. This flag must be used simultaneously with the DDSCL_EXClusive flag. DDSCL_MULTITHREADED requires DirectDraw's behavior to meet the behavior of DirectDraw Multi-threaded security This requirement. If your learning phase is now too far more. DDSCL_NORMAL indicates that the program is a normal window program. This flag cannot be used with DDSCL_AXCLUSIVE, or DDSCL_FULLSCREEN to use DDSCL_NOWIndowChanges to indicate not allowed DirectDraw minimum Depending on the program window in the activation state.
If you look at the above signs, you may find that some markers seem to be a bit. Basically, DDSCL_FULLSCREEN and DDSCL_EXCLUSIVE must be used at the same time. If you want to use Mode X mode, you must use DDSCL_FULLSCREEN, DDSCL_EXCLUSIVE, and DDSCL_AlowModex at the same time. In addition, the name of the logo and what they do are more appropriate. In most cases, you will like this set the full-screen mode as the following procedures: lpdd7-> SetCooperativeLevel (hwnd, DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT); and ordinary window procedure like the following settings: lpdd7-> SetCooperativeLevel (hwnd, DDSCL_NORMAL) Of course, when you learn multi-threaded programming technology later, you may have to add flag DDSCL_MULTITHREADED to make the program run more secure. In short, let's take a look at the complete process of creating a DirectDraw object and setting a collaboration:
LPDIRECTDRAW LPDD = NULL; // Standard DirectDraw 1.0lpdirectDraw7 LPDD7 = NULL; // DirectDraw 7.0 Interface 7
// first create base IDirectDraw interfaceif (FAILED (DirectDrawCreateEx (NULL, (void **) & lpdd7, IID_IDirectDraw7, NULL))) {// error} // end if // now set the cooperation level for windowed DirectDraw // since we Aren't going to do any drawing yetif (failed (lpdd7-> setcooperativeelevel (hwnd, ddscl_normal))) {// error} // end if
Note: In order to save pen ink, I will save such errors such as failed () and (or) succeeded (). But when you are programming, you have to hang an error.
At this moment, you have learned all the knowledge of the full DirectX program that generates a window - starting with DirectDraw and then sets the collaboration. Although you still don't know how to draw, it has started to go on the road after all. As an example, see Demo6_1.cpp corresponding to Demo6_1.exe on the CD. When you run the program, you will see the screen shown in Figure 6.5. This program is based on the T3D game console template we wrote in front. I tried some modifications to create DirectDraw and set a collaboration level in Game_init () and Game_ShutDown (). Figure 6.5 Run DEMO6_1.EXE
Below is the two functions of DirectDraw code in Demo6_1.cpp, you will see, how simple things are created to create DirectDraw. int Game_Init (void * parms = NULL, int num_parms = 0) {// this is called once after the initial window is created and // before the main event loop is entered, do all your initialization // here // first create base IDirectDraw interfaceif (FAILED (DirectDrawCreateEx (NULL, (void **) & lpdd, IID_IDirectDraw7, NULL))) {// error return (0);} // end if // set cooperation to normal since this will be a windowed applpdd- > SetCooperativeEvel (main_window_handle, ddscl_normal);
// Return Success or Failure or Your OWN Return Code Herereeturn (1);
} // end game_init
/
INT GAME_SHUTDOWN (Void * Parms = NULL, INT NUM_PARMS = 0) {// this is caled after the game is expected and the main evenet // loop while is expected, do all you cleanup and shutdown
// simply blow away the iDirectdraw interfaceif (LPDD) {LPDD-> Release (); lpdd = null;} // endiff
// Return Success or Failure or Your OWN Return Code Herereeturn (1);
} // end game_shutdown
Tip: If you plan to write Demo6_1.cpp from the head and try to compile it, remember to manually contain ddraw.lib from the lib / directory of DirectX8.0 SDK. At the same time, add the folder where the DirectX header is located to your compiler's compile search path and make the folder to the compiler to search the folder when the header is searched. In addition, you must of course create a Win32 application, I have received 10 email from the newcomer using the compiler, and I have forgot to include .lib files. You can don't make a person who sends such an email ...
Learning some knowledge about the model Related to the next step of setting DirectDraw may be the coolest part of all settings steps. In general, it is very natural to set the video mode to the ROM BIOS mode in DOS. However, due to the drawback of mode conversion, it is almost impossible to imagine DOS under Windows. However, because there is DirectX, it will take a dish. One of the main design objectives of DirectDraw is to make video mode transformations simple and transparent for programmers. There is no need to make more VGA / CRT control registration coding, just do a simple call. Any type of PRESTO mode {translator: 叫 Presto mode does not understand}, as long as you want - you can. (Of course, the graphics card is supported)
Set the function of the video mode called setDisplayMode (), which is the member function of the IDirectDraw7 interface, or uses C : iDirectdraw7 :: setDisplayMode (). Here is its prototype statement. HRESULT SetDisplayMode (DWORD dwWidth, // width of mode in pixels DWORD dwHeight, // height if mode in pixels DWORD dwBPP, // bits per pixel, 8,16,24, etc. DWORD dwRefreshRate, // desired refresh, 0 for DEFAULT DWORD DWFLAGS); // Extra Flags (Advanced) 0 for Default is the same, and if the function is successfully returned, returns DD_OK. You may want to say now: "God, great!". Have you tried to set up a MODE X mode, such as 320 × 400 or 800 × 600 mode? Even if you succeed, huh, huh, you can wish you good luck when you render the video. However, now there is a DirectDraw function, you only need to put the width, high, color, send it to the function, huh, huh, get it! DirectDraw processes the detail features of all specific graphics cards, if your demand can be created, then it is established. And, after the video mode is established, it is guaranteed to have a linear memory cache ... Of course, it also guarantees some other things, and then say later. Take a look at Table 6.3, review the commonly used video mode and the corresponding colors.
Table 6.3. Common Video Mode Wide High Color Deext The Mode X 320 200 8 * 320 240 8 * 320 400 8 * 512 512 8,16,24,32 640 480 8, 16, 24, 32 800 600 8, 16, 24, 32 1024 768 8, 16, 24, 32 1280 1024 8,16,24,32
Interestingly, you can ask anything you want. For example, you can choose 400 × 400, and if the graphics card supports this mode, you can work. However, it is best to build a mode listed in Table 6.3 because they are most common.
Tips: In fact, there is a Win32 API function to set up video mode, and I have used it in the past. But this function is easily harmed to the system, and there is always a mess of things.
Go back to the setDisplayMode () function, the top three parameters are asked, and they are not much. But the last two need to be explained. DWREFRESHRATE is used to set refresh rates for your requirements. Therefore, if you ask a 320 × 200 mode, the default system will set the refresh rate to 70 Hz, but pass this parameter, if you want, you can force it to 60Hz. And it is true, I will not discuss the refresh rate, in fact, it is simple to set to 0 (this will use the drive default value)
The last parameter dwflags is an additional sign to indicate some trivial things, and it is not very useful. Currently, by sending this DDSDM_StandardVgamode flag, you can use VGA mode for 320 × 200 {translator: I don't understand 13h is awkward} instead of Mode X 320 × 200. Once again, I will not study this question. If you write a game that uses 320 × 200 mode, then you can use this sign to do the test, see that the VGA mode is fast or Mode X 320 × 200 fast. However, it is true, the difference is not big. So now, set it into 0. Preliminary knowledge is over, let us transform mode. To convert mode, you must first create a DirectDraw object, set a collaborative level, and then set the explicit mode as follows:
LPDD-> SetDisplayMode (Width, Height, BPP, 0, 0);
For example, create a 640 × 480 256 color (8-bit color depth), you will do this:
LPDD-> SetDisplayMode (640, 480, 8, 0);
Set 800x600 16 color depth, you should do this:
LPDD-> SetDisplayMode (800, 600, 16, 0);
Now, the difference between the two modes is much larger than when setting them. 8-bit color deep mode works with 16-bit, 24-bit mode is completely different. If you still remember, the first few chapters mentioned the palette for Win32 GDI programming (Chapter III Senior Windows Programming, and Chapter 4 Windows GDI, Control, and Herphics), the same reason is also applicable in DirectDraw. That is, when you create an 8-bit mode, you are actually create a heap mode {translator: This chapter I don't have very much clear term: Palletized mode}, you must create a debug board and use RGB 8.8.8 format Fill the palette.
On the other hand, if you create a complete RGB mode with a deep color depth of 16, 247, 32 color, you don't need to want to make a palette. You can write data directly to the video cache. But at least, you should learn how to work with the DirectDraw palette (this is the next topic to discuss). But before further study, let's take a look at the full-screen DirectX program with 640 × 480 × 8 mode.
This example is this example of Demo6_2.cpp on the CD and its corresponding executable. I just give you a profile of a program, what you see is just a blank screen, because this demo is a full screen program. But I really show you the code that reaches the full screen function. Like us, this demo is based on the game console procedure we wrote before, but made some small modifications, add some changes related to DirectX in the Game_init () and Game_Shutdown () section. These modifications can be seen from the code from the Demo6_2.cpp. Take a closer study, you will be surprised to its simple ...
INT GAME_INIT (Void * Parms = NULL, INT NUM_PARMS = 0) {// this is caled overce the initial window is created and // before the main event loop is entered, do all your initialization ///th
// first create base IDirectDraw interfaceif (FAILED (DirectDrawCreateEx (NULL, (void **) & lpdd, IID_IDirectDraw7, NULL))) {// error return (0);} // end if // set cooperation to full screenif (FAILED (LPDD-> SetCoopeRATIVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVELEVel
// set Display Mode to 640x480x8if (failed (LPDD-> setDisplaymode (Screen_Width, Screen_HEight, Screen_bpp, 0, 0))) {// Error Return (0);} // end if
// Return Success or Failure or Your OWN Return Code Herereeturn (1);
} // end game_init
/
INT GAME_SHUTDOWN (Void * PARMS = NULL, INT NUM_PARMS = 0) {// this is called after the game is expected and the main evenet // loop while is exited, do all your cleanup and shutdown here
// simply blow away the iDirectdraw7 interfaceif (LPDD) {LPDD-> release (); lpdd = null;} // endiff
// Return Success or Failure or Your OWN Return Code Herereeturn (1);
} // end game_shutdown At this moment, there are two things you didn't do: control the palette and access explicit cache. Let us take a look at the color problem.
Wonderful color DirectDraw supports many different colors, including 1, 2, 4, 8, 16, 24, and 32. Obviously, 1, 2 and 4 color are a bit outdated, so you don't have too much research on these colors. On the other hand, 8, 16, 24, and 32-bit modes are very popular. Many of you wrote Many games may be run under the 8-bit panel mode (also a nice used for learning mode) due to speed. Or at 16 or at 24 to utilize all RGB colors. RGB mode operates by writing data of the same byte into the cache, as shown in Figure 6.6. The palette mode works by using a lookup table that is indexed with each pixel in the video cache. You should be familiar with this way of working, the foregoing is involved. Figure 6.6. Comparison of different colors
What you have to learn is to create a 256-color palette and inform DirectDraw you want to use it. Let's take a look at the required steps: 1 Create one or more palette data structures, such as an array with 256 PaletTentry structures. 2 Create a DirectDraw palette interface object iDirectdrawpalette from the DirectDraw object. In most cases, this palette object will be mapped directly to the registered VGA hardware palette. 3 Associate the palette with the drawing surface, such as associated with the main surface. Thus all data rendered to the surface will explicit in a suitable color. 4 (Optional) If you want, you can change some or all of the palette items. If you skip step 1, create an empty palette in step 2, then you have to do something in this step. Basically, what I have to say is: When you create a palette interface, you need to set the color of the palette. If you do it, then you have to do it later. Therefore, as long as you remember the palette in the back, then step 2 can be stepped 1. Let's start to create a palette data structure. It is nothing more than a group with 256 panel items. The palette is a Win32 structure called PaletTentry, as shown below: TypeDef strunt tagpaletteentry {byte pered; // red component 8-bits byte pegreen; // Green Component 8-Bits Byte Peblue; // Blue Component 8-bits Byte Peflags; // Control Flags: set to pc_nocollapse} PaletteEntry; Is it very familiar? well. In short, to build a palette, you only need to create an array of this structure as follows:
Paletteentry Palette [256];
Then, you fill this array with your favorite way. However, there is a rule of the rules here: you must fill the peflags domain into pc_nocollapse. This is required because you don't need Win32 or DirectX to optimize the palette for you. Remember these, the following is an example of creating a random palette. In the first array element is black, the last element is white: Paletteentry Palette [256]; // Palette Storage
// Fill EM UP with Color! for (int color = 1; color <255; color ) {// Fill with random RGB VALUES PALETTE [color] .pered = rand ()% 256; Palette [color] .pegreen = rand ()% 256; Palette [color] .peblue = rand ()% 256;
// set flags field to pc_nocollapse palette [color] .peflags = pc_nocollapse;} // end for color
// NOW FILL IN ENTRY 0 and 255 with black and whitepalette [0] .pered = 0; Palette [0] .pegreen = 0; Palette [0] .peblue = 0; Palette [0] .peflags = pc_nocollapse;
Palette [255] .pette [255] .pegreen = 255; Palette [255] .peblue = 255; Palette [255] .peflags = pc_nocollapse; this is all work pull. Of course, you can create multiple palettes and arbitrarily fill them, depending on you.
Continue, the next step is to create an actual iDirectdrawpalette interface. Fortunately, this interface has not changed since DirectX6.0, so you don't have to use queryinterface () or any other way to query the latest version of the interface. Here is the prototype statement of iDiretDraw7 :: createpalette () creates a palette object.
HRESULT CreatePalette (DWORD dwFlags, // control flags LPPALETTEENTRY lpColorTable, // palette data or NULL LPDIRECTDRAWPALETTE FAR * lplpDDPalette, // received palette interface IUnknown FAR * pUnkOuter); // advanced, make NULL if the function is successful DD_OK let us return Take a look at each parameter. The first parameter dwflags used to control various attributes of various palettes. The next parameter is a pointer to the data used to initialize the palette, if you don't want to specify, set to null. If the function call is successful, the pointer to the third parameter will store a real IDirectdrawPaletTe interface. Finally, Punkouter is a high-level COM parameter, which is generally simple to set to NULL.
The only parameter that is interested in, of course, is DWFLAGS. Let us see what you can do with this parameter. Table 6.4 lists possible values, you can use "or" to integrate them. Table 6.4. CreatePalette () Control Sign Value Description DDPCAPS_1bit 1 color depth, 2 in the palette. DDPCAPS_2BIT 2 color depth, 4 items in the palette. DDPCAPS_4BIT 4 has 16 in palette. DDPCAPS_8bit 5 color is deep, most common, 256 in palette. DDPCAPS_8BITENTRIES This is an index palette's advanced property that is used on a palette of 1, 2, 4-bit color deep. Remember to use it. DDPCAPS_ALPHA indicates that the PEFLAGS domain of the PaletteEntry structure is interpreted as an alpha value for controlling transparency in an 8-bit value. A palette created with this flag can only be associated with a D3D material surface created by the DDSCAPS_TEXTURE flag. Again, this is a high-level sign that is prepared for the master. DDPCAPS_ALLOW256 shows that 256 of this palette can be defined. Typically, 0 and 255 items are left to black and white, in some systems, such as NT systems, in any case, you can't write value to these two items. However, in most cases, you don't need this logo, because 0 generally is always black, and most palettes define the 255th item into white. Of course, use it, how to use, follow you. DDPCAPS_INITIALIZE is initialized by the array passed by LPDDCOLORARRAY. This flag is used to be palette data to be downloaded to the hardware palette. DDPCAPS_PRIMARYSURFACE This palette will be associated on the main surface. Changing the color on this palette will immediately react immediately, unless the DDPSETPAL_VSYNC flag is used and DDPSETPAL_VSYNC is supported. The DDPCAPS_VSYNC forced palette only updates the color during the vertical blank gap. This can reduce the color exception and the screen flashes. It is not fully supported. {Translator Note: The process of display explicit graphics is like this, first move the electron gun from the upper left corner of the screen; when the electron gun is moved to the right side, the electronic gun is moved to the lower end and then moved, so reciprocated. The electron gun from the right end to the right end to the left side of this gap is not electronically, but the time is also very short, so it will not be utilized. However, when the electronic gun is moved to the lower right corner, the next step will move to the left end of the first line, that is, walk the diagonal line in the lower right corner. At this time, this time is longer, this time is "vertical" Blank gap "is discounted as VBI. Just talk about it, please refer to it. YEW98. } If you ask me, you will definitely say: a lot of confessed control words. In fact, you only need to work with 8-bit palette, so you only need to use or operate a few control words.
DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE
Then, if you don't care 0 items and 255 items, you don't have to use ddpcaps_allow256. Further, if you don't want to initialize the palette during CREATEPALETTE (), you don't have to use DDPCAPS_Initialize.
Use these knowledge into your brain. Here is how you created a palette object with the random color data just now. LPDIRECTDRAWPALETTE lpddpal = NULL; // palette interfaceif (FAILED (lpdd-> CreatePalette (DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE, palette, & lpddpal, NULL))) {// error} // end if
If the function call is successful, LPDDPal will point to a valid iDirectddrawPaletTE interface. At the same time, the hardware debug board also updates yourself with the color data sent to it. Here, it is 256 random colors.
Usually, I will give you Demo at the end of the one. However, very unfortunately, this time we met a so-called "chicken and egg" problem. You must first spend the things on the screen before you can see what the color is color, and you haven't learned it. Let's learn below.
Create an explicit surface as you know, explicit graphics on the screen is nothing more than a series of pixels, and these pixels are described in memory in some formatted data, or the palette Or is RGB. In other words, let anything happen on the screen, you need to know how to paint in memory. However, DirectDraw designers decided to make a little abstraction to the memory, so that what kind of graphics card in your system (others) use, the method of accessing the video surface is constant for you (programmer view). In this way, DirectDraw supports our so-called "surface" concept.
See Figure 6.7, the surface is a rectangular memory area that can contain bitmap data. Further, there are two different surfaces: main surfaces and side surfaces. Figure 6.7. The surface can be any size
The main surface corresponds directly to the true memory of the graphics card and is always visible. Therefore, in the DirectDraw program you can only have a master surface, and it directly reflects the screen graphics and stored in VRAM (memory). When you operate the main surface, you will immediately see the result is displayed on the screen. For example, if you set the video mode to 640 × 480 × 256, you must create a main surface that is also 640 × 480 × 256, and associates it with the display device, the iDirectDraw7 object, is associated.
The sub-surface is quite flexible. They can be any size, can or saved in the VRAM or saved in the system memory, and you can also create any plural, as long as the memory is enough. In most cases, you need one to two side surfaces (buffers) to smoot animations. Like the main surface, the side surface also has the work of color deep and drawing. You are the next frame of movie drawing in the offscreen surface, then quickly copy or turn the panel to the main surface quickly, so smoothed the animation. This is the so-called double or three cache. Next chapter you will learn more about knowledge.
The second use of the side surface is to store bitmaps or animations in the game. This is a very important feature of DirectDraw, because only the DirectDraw surface can be used to call the hardware acceleration feature on bitmap data. If you go to write a block transfer program to draw a bitmap, you will lose all the benefits of all acceleration functions.
Now I am a little more advanced, so I have to slow down. My advanced reason is just to let you have the opportunity to think about thinking. Now let's take a look at how to create a main surface with your display mode size, then you will learn how to write data on the main surface and paint pixels on the screen. Create a master surface to pull, you must create any surface you must perform as follows: 1 Fill the DDSurfaceDesc2 data structure, which is used to describe the surface you created. 2 Call iDirectdraw7 :: createSurface () to create a prototype declaration below CreateSurface ():
HRESULT CREATESURFACE (LPDDSurfaceDesc2 LPDDSurfaceDesc2, LPDIRECTDRAWSURFACE4 FAR * LPLPDDSURFACE4 FAR * LPLPDDSURFACE, IUNKNOWN FAR * PUNKOUTER);
The function requires a description of the DirectDraw surface you want to create, a pointer to the interface, and finalize the Punkouter that characterizes the advanced COM property to NULL. Oh, the data structure that is filled in the surface is an annoying thing, but I will help you step by step. First, let's take a look at DDSURFACEDESC2: typedef struct _DDSURFACEDESC2 {DWORD dwSize; // size of this structure DWORD dwFlags; // control flags DWORD dwHeight; // height of surface in pixels DWORD dwWidth; // width of surface in pixels union { LONG lPitch; // memory pitch per row DWORD dwLinearSize; // size of the buffer in bytes} DUMMYUNIONNAMEN (1); DWORD dwBackBufferCount; // number of back buffers chained union {DWORD dwMipMapCount; // number of mip-map levels DWORD dwRefreshRate; // refresh rate} DUMMYUNIONNAMEN (2); DWORD dwAlphaBitDepth; // number of alpha bits DWORD dwReserved; // reserved LPVOID lpSurface; // pointer to surface memory DDCOLORKEY ddckCKDestOverlay; // dest overlay color key DDCOLORKEY ddckCKDestBlt; // Destination Color Key DdcolorKey DDCKCKSRCOVERLAY; // source overlay color key DDCOLORKEY ddckCKSrcBlt; // source color key DDPIXELFORMAT ddpfPixelFormat; // pixel format of surface DDSCAPS2 ddsCaps; // surface capabilities DWORD dwTextureStage; // used to bind a texture // to specific stage of D3D} DDSURFACEDESC2, Far * lpddsurfaceDesc2; if you see, a complicated structure. What is even more, 70% of the domain is quite strange. Fortunately, you just need to know the few items I bold, let's take a look: dwsize: This domain is important in any DirectX data structure. Many DirectX data structures are delivered with addresses, so that the function or method of obtaining the data structure is not to know the size of the data structure.
However, if the value of this 32-bit domain is always the size of the data structure, the function of obtaining the data structure will always know the size of the data structure by accessing this first domain. Therefore, DirectDraw and DirectX data structures identify the data structure itself in the first domain. This seems to be a bit redundant, but I believe me, this is really a good design. Fill this domain You only need to do this: ddsurfacedesc2 ddsd; ddsd.dwsize = sizeof (ddsurfacedesc2);
DWFLAGS: This field is used to tell DirectDraw, which you give is used to fill which domain of ddsurfacedesc2. Or, if you use this structure in a query operation, tell DirectDraw you have to get the information of which domain of ddsurfacedesc2. Take a look at Table 6.5, which lists the values for this sign word. For example, if you want to fill in valid data in dwwidth and dwheight two domains, you should set this DWFLAGS domain like this:
DDSD.DWFLAGS = DDSD_WIDTH | DDSD_HEIGHT;
In this way, DirectDraw knows to find DWWIDTH and DWHEIGHT fields, then put a valid value. Let the unit dwflags as the indicator of boot data.
Various tables dwFlags field 6.5. DDSURFACEDESC2 of possible flag values indicates that described DDSD_ALPHABITDEPTH dwAlphaBitDepth effective DDSD_BACKBUFFERCOUNT show dwBackBufferCount effective DDSD_CAPS show ddsCaps effective DDSD_CKDESTBLT show ddckCKDestBlt effective DDSD_CKDESTOVERLAY show ddckCKDestOverlay effective DDSD_CKSRCBLT show ddckCKSrcBlt effective DDSD_CKSRCOVERLAY show ddckCKSrcOverlay effective DDSD_HEIGHT show dwHeight effective DDSD_LINEARSIZE show dwLinearSize effective DDSD_LPSURFACE show lpSurface effective DDSD_MIPMAPCOUNT show dwMipMapCount effective DDSD_PITCH show lPitch effective DDSD_PIXELFORMAT show ddpfPixelFormat effective DDSD_REFRESHRATE show dwRefreshRate effective DDSD_TEXTURESTAGE show dwTextureStage effective DDSD_WIDTH show dwWidth effective
DWWIDTH: Indicates the pixel width of the surface. When you create a surface, here is where you set the width, 320, 640, etc. Also, if you want to query the properties of the surface, this domain will return the width of the surface (if you require this).
Dwheight: The pixel height of the surface surface. Similar to DWWIDTH, here is where you have a height, 300, 240, 480, etc. when you create a surface.
Lpitch: This is an interesting domain. Basically it is the horizontal memory spacing of your choice. Look at Figure 6.8. LPITCH, also known as the width or memory width, is the number of bytes per row in a given video mode. Based on the following reasons, this is a very important data field: When you ask a 640 × 480 × 8 display mode, you know 640 pixels per line, each pixel for 8-bit memory (ie 1 byte). Therefore, there are 640 bytes per line, so LPITCH seems to be set to 640. right? not necessarily. Figure 6.8. Access a surface trick: LPITCH will vary depending on the VRAM. Therefore, when you access another row of memory from a row on the surface of the DirectDraw, you must use the LPITCH to move to the next row, not the number of bytes per pixel with a width. This is very important.
Most new graphics cards support our so-called "linear memory mode" and have hardware addressing functions, which is already reality, but do not guarantee that each graphics card is implemented. So, you can't assume that a 640 × 480 × 8 video mode accounts for 640 bytes per line in memory. This is the reason for the LPITCH domain. You must apply it when you calculate the memory address to ensure correct, so you can move from a line to another. For example, to access any of the pixels in 640 × 480 × 8 (256 colors) video mode, you can use the following code. Suppose you have got a lpitch value from DirectDraw, and lpsurface already points to surface memory (I will explain this parameter below)
DDSD.LPSURFACE [X Y * DDSD.LPITCH] = Color;
Is it very simple? In most cases, DDSD.LPITCH is set to 640 to represent 640x480x8 mode. For 640 × 480 × 16 mode, DDSD.LPITCH will be set to 1280 (two bytes per pixel = 640 × 2). However, for some graphics cards, for the layout of memory, such as the establishment of intrinsic caching or something else, make things unlike the above. So the correct way is to always use LPITCH when calculating memory, you are always secure.
Tip: Although the LPITCH value is not always equal to the horizontal value of the video model you set, you can use it to test the level value to enable you to use other optimization functions. For example, in the code that completes the initialization function, you can get the LPITCH value and compare with the level of video mode you selected. If they are equal, you can switch to your functionality for the optimization program and hardcodes each line of authentication.
LPSURFACE: This domain gets a pointer to the real memory address of the surface you created. These memory may be VRAM or may be system memory, but you don't have to worry about it. Once you get a pointer to the memory, you can operate it like other memory, such as writing data or reading data, etc., this is entirely dependent on how you want to fill the pixels. Oh, make this pointer more easy! But we still have to stay here for a while. Generally, you must "lock" with the surface corresponding to the surface, and tell DirectX you want to work on the memory, and other processes do not try to read or write on the memory. Further, when you get this pointer, depending on the different color depth (8, 16, 24, 32), you have to convert it to a type of workout and a reset value.
DWBACKBUFFERCOUNT: This domain is used to set and read the number of backup caches (or associated with the main surface). If you can recall, by creating one or more virtual main surfaces (cache with the same pattern and color depth with the surface), the backup cache (ie, the screen cache) can be used to achieve smoothization of animation. Then you draw on the backup cache, this backup cache is invisible for the user. Then quickly turn the page or copy the backup to the main surface for display. If you only have a backup cache, this technology has become "dual cache technology." Use two caches to call "three cache technology", of course, have better effects than the forgoes but also take more memory. In order to be simple, most cases, you will create a flip chain including a home surface and a backup cache. DDCKCKDESTBLT: This domain is used to control the target color key. This domain controls the way to write colors when block transmission operations. More information will be described in later Chapter VII "Advanced DirectDraw and Bits Graphics".
DDCKCKSRCBLT: This domain indicates the source color button. That is, when you do Bitmapping operation {? It seems that this term is like this, I can't think of it, but I translated it again. Yew98} You don't want to pass the colors passing. This is a method of how you set a transparent color of bitmap. See Chapter VII for details.
DDPFPixElFormat: This domain is used to get the format of the surface pixel. This is very important when you go to query the properties of the surface. This is the structure below. You may have to query DirectX SDK to get more details. Because this information is too much, and the relationship with the discussion now is not big, so I will save it. typedef struct _DDPIXELFORMAT {DWORD dwSize; DWORD dwFlags; DWORD dwFourCC; union {DWORD dwRGBBitCount; DWORD dwYUVBitCount; DWORD dwZBufferBitDepth; DWORD dwAlphaBitDepth; DWORD dwLuminanceBitCount; // new for DirectX 6.0 DWORD dwBumpBitCount; // new for DirectX 6.0} DUMMYUNIONNAMEN (1) ; union {DWORD dwRBitMask; DWORD dwYBitMask; DWORD dwStencilBitDepth; // new for DirectX 6.0 DWORD dwLuminanceBitMask; // new for DirectX 6.0 DWORD dwBumpDuBitMask; // new for DirectX 6.0} DUMMYUNIONNAMEN (2); union {DWORD dwGBitMask; DWORD dwUBitMask; DWord dwzbitmask; // new for directx 6.0 dWord dwbumpdvbitmask; // new for directx 6.0} DummyunionNamen (3); Union {DWORD DWBBITMASK; DWORD DWVBITMASK; DWORD DWSTENCILBITMASK; // New for DirectX 6 .0 DWORD dwBumpLuminanceBitMask; // new for DirectX 6.0} DUMMYUNIONNAMEN (4); union {DWORD dwRGBAlphaBitMask; DWORD dwYUVAlphaBitMask; DWORD dwLuminanceAlphaBitMask; // new for DirectX 6.0 DWORD dwRGBZBitMask; DWORD dwYUVZBitMask;} DUMMYUNIONNAMEN (5);} DDPIXELFORMAT, FAR * LPDDPixElFormat; Note: I bold the domain is a common domain.
DDSCAPS: This domain is used to make those required but have not yet defined in the surface properties. In fact, this domain is another data structure. The following shows DDSCAPS2: typedef struct _DDSCAPS2 {DWORD dwCaps; // Surface capabilities DWORD dwCaps2; // More surface capabilities DWORD dwCaps3; // future expansion DWORD dwCaps4; // future expansion} DDSCAPS2, FAR * LPDDSCAPS2; 99.9% of the Next, you only need to set the first domain of this structure. DWCaps.dwcaps2 is prepared for 3D, while other domains DWCAPS3 and DWCAPS4 are used for future expansion, not yet used. In summary, Table 6.6 lists the flag values that DWCAPS may set. To see a full list, go to DirectX SDK. For example, when you want to create a main surface, you can set DDSD.DDSCAPS like this.
DDSD.DDSCAPS.DWCAPS = DDSCAPS_PRIMARYSURFACE;
I know that the above expression is complicated, and it is true to some extent. Double nested control markers are really a bit painful. But, endure ...
Table 6.6. The property control setting value of the DirectDRAW surface Description DDSCAPS_BACKBuffer indicates that this surface is a backup cache in the surface flip structure. DDSCAPS_COMPLEX indicates a review surface. A complex surface is a main surface associated with one or more backpinted back chains. DDSCAPS_FLIP indicates that this surface is part of a surface flip structure. However, this property is passed to the createSurface () method, a front-end cache and one or more backup cache will be created. DDSCAPS_LOCALVIDMEM indicates that this surface is prioritized in the memory. If this flag is selected, DDSCAPS_VIDEOMEMORY must be selected. DDSCAPS_MODEX indicates that this surface is a 320x200 or 320x240 Mode X surface. DDSCAPS_NONLOCALVIDMEM indicates that this surface is prioritized in non-local memory. If this flag is selected, DDSCAPS_VIDEOMEMORY must be selected. DDSCAPS_OFFSCREENPLAIN indicates that this surface is a left surface. This way this surface cannot be a certain special surface, such as not a cover layer, material, z-order, front end cache, backup cache, or alpha surface. (USUALLY Used for sprites.) DDSCAPS_OWNDC indicates that this surface will be associated with a device context. DDSCAPS_PRIMARYSURFACE indicates that this surface is the main surface. It describes what is seen at this moment. DDSCAPS_STANDARDVGAMODE indicates that the surface is a standard VGA mode surface instead of Mode X mode. This flag cannot be used simultaneously with the DDSCAPS_MODEX flag. DDSCAPS_SYSTEMMORY indicates that this surface is created in system memory. DDSCAPS_VIDEMEMORY indicates that this surface is created in the memory.
Now you have a concept of DirectDraw gives you the powerful and complex feature that DirectDraw gives you when you create a surface. Let us put knowledge into practice, create a major surface with a simple and color depth (the default operation, so) in the display mode. Here is the code to create a main surface: // Interface Pointer to Hold Primary Surface, Note That // It's The 7th Revision of The InterfacelpdirectDrawsurface7 LPDDSPRIMARY = NULL;
DDSurfaceDesc2 DDSD; // The DirectDraw Surface Description
// MS Recommends clearing out the structureMemset (& DDSD, 0, SIZEOF (DDSD)); // Could Use ZeromeMory () // Now Fill In Size Of StructuredDsd.dwsize = SizeOf (DDSD);
// Enable Data Fields with Values from Table 6.5 That We // Will Send Valid Data In // in this case Only the ddscaps field is enabled, we // could have enabled the width, height etc., but they // aren ' Take on the // Dimensions of the Display Mode by defaultddsd.dwflags = ddsd_caps;
// Now set the capabilities That We want from table 6.6ddsd.ddscaps.dwcaps = DDSCAPS_PRIMARYSURFACE
// Now create the primary surfaceif (Failed (LPDD, & LPDDSPRIMARY, NULL)) {// error} // end if
If the function call is successful, LPDDSPRDIMARY will point to the new surface interface, and you can call the function from it (there are many functions that can be called from it, such as in 256 color mode). Let's take a look at the example of repeating the palette.
In addition to associating the palette with a surface, the associated palette is all in the chapter of the palette. You created a palette and fill each color item, but you didn't associate the palette with a surface, because you haven't surface it yet. Now you have a surface (main surface), you can finally do the entire step.
To associate the palette to any surface, what you have to do is using the idirectdrawsurface7 :: setPalette () function, as shown below:
HRESULT SETPALETTE (LPDIRECTDRAWPALETTE LPDDPALETTE);
This function only needs one palette pointer you want to be associated. Let's use the palette created in the previous palette section. Here's how you are associated with the main surface:
IF (LPDDSPRIMARY-> SetPalette (LPDDPAL))) {// error} // endiff
Not bad, right. At this point, you have any conditions that makes you can effectively imitate the DOS32 game. You can convert video mode, set the palette, and have created the main drawing surface to depict vivid video images. However, there are still some details that you need to learn, such as locking the main surface memory and accessing the VRAM capabilities and painting a pixel. Let us learn these things now. Drawing pixels want to draw a (or some) pixels in full screen DirectDraw mode, you must first create DirectDraw, set a collaboration level, set explicit mode, create at least one main surface. Then, you have to get the access to the main surface and write data to the video. However, before you learn how to do this, let's take a look at how the video surface works from another angle.
If you still remember, all DirectDraw video patterns and surfaces are linear, as shown in Figure 6.9. This means that when you rinse, from left to right, from top to bottom, the memory is constantly increasing. Figure 6.9. The DirectDraw surface is linear tips: you may feel weird: How DirectDraw converts a nonlinear video mode to linear mode without supporting the graphics card. For example, Mode X is a completely non-linear and difficult to convert (Bank-switched) mode. The fact is this, when the DirectDraw discovery mode is non-linear in the hardware, a driver called VFLATD.VXD is called. This driver will create a software layer between you and VRAM to make VRAM look linear. However, remember that this process is at the expense of running speed.
In addition, locate it in the video cache, you only need two information: memory per line spacing (i.e., how many byte memory per line) and each pixel (8, 16, 24) 32-bit). You can use the following equation:
// Assume this points to vram or the surface memoryuchar * video_buffer8;
Video_buffer8 [x y * Memory_pitchb] = pixel_color_8;
Of course, this equation is not complete because it is only to 8-bit mode, in other words, 1 byte per pixel mode is correct. For 16-bit mode or in other words, 2 bytes per pixel pattern, you need to do this below:
// Assume this points to vram or the surface memoryUShort * video_buffer16;
Video_buffer16 [x y * (Memory_pitchb >> 1)] = Pixel_color_16;
There are many things here, so let's take a closer study. I set the pointer type to the VRAM to ushort. This is the 16-bit value when we use an array. When I said:
Video_buffer16 [1]
True access to the second integer element of the array, or by one byte pair. In addition, since Memory_pitchB is based on bytes, you must remove it 2, we use the right to 1 bit to achieve the purpose of 2, so that there is a memory interval based on integer or 16-bit. Finally, the assignment of Pixel_Color16 is often misunderstood. Because it is at this time, a complete 16-bit unconformity is written to the video cache, not the 8-bit value of the previous example. Further, the 8-bit value is just the index value of the color on the palette, and the 16-bit value must be a RGB value. Typically the RGB value is encoded as R5G6B5 format, i.e., 5 red, 6-bit green, 5-bit blue. As shown in Figure 6.10. Figure 6.10 16-bit RGB Different coding, including 5.6.5 format The macro below 16-bit RGB characters is 5.5.5 and 5.6.5 format:
// this builds a 16 Bit Color Value in 5.5.5 Format (1-bit alpha mode) #define _RGB16Bit555 (R, G, B) ((B & 31) ((G & 31) << 5) ( (R & 31) << 10))
// this Builds a 16 Bit Color Value in 5.6.5 Format (Green Dominate Mode) #define _RGB16Bit565 (R, G, B) ((B & 31) ((G & 63) << 5) ((R & 31) << 11))
If you have seen, the addressing and operation of the 16-bit mode and RGB mode is complicated than 256 color mode. So let us start from 256 color mode.
To get any access to the main surface, a side surface, etc., you must lock and unlock memory. This lock and unlocking is necessary: First, tell DirectDraw you want to control memory (so, other processes cannot control the block memory), second, indicating that when you operate the locked memory, video hardware cannot Move any cache or virtual memory cache. Remember, no one can assure you that a VRAM content is always not moved in its same storage area. Video memory can be virtual memory, but when you lock it, this memory will keep the original address space throughout the lock period so you can operate memory. The function of locking the memory is idirectdrawsurface7 :: locksurface7 :: Lock (), as shown below:
HRESULT Lock (LPRECT lpDestRect, // destination RECT to lock LPDDSURFACEDESC2 lpDDSurfaceDesc, // address of struct to receive info DWORD dwFlags, // request flags HANDLE hEvent); // advanced, make NULL
The parameter is not so terrible, but it is a bit new in it. Let's go to the parameters. The first parameter is the rectangular area of the surface memory you want to lock. Look at Figure 6.11. DirectDraw allows you to lock only part of the surface memory. I know that I can only update some part of the surface without having to lock the entire surface is a great thing. But in most cases, you can lock the entire surface. At this time, just pass NULL to the first parameter. Figure 6.11 iDirectdrawsurface 7-> LOCK (...)
The second parameter is a DDSurfaceDesc2 structure address that fills the information about the surface you requested. General, pass empty DDSurfaceDesc2. Next parameter, dwflags tells Lock () what you have to do. Table 6.7 includes some common values. Table 6.7. Lock () Control Sign Value Description DDLOCK_READONLY indicates that the locked surface will read only. DDLOCK_SURFACEMEMORYPTR indicates that a valid memory pointer to the specific rectangle is returned will be returned. If you do not specify a rectangle, return the top of the surface (this is the default action). DDLOCK_WAIT If the surface is not unrelly in the case, the function will continue to know the lock or have an error, such as Dderr_Surfacebusy. DDLOCK_WRITEONLY indicates that the locking surface will be writable.
Note: I am bold is a common sign.
The last parameter is for an advanced Win32 feature called an event. Set it to null.
It's easy to lock a main surface. What you have to do is to ask a pointer to the surface, which allows the DirectDRAW to wait until the surface is available. Below is the code:
DDSurfaceDesc2 DDSD; // this will hold the result of the lock
// Clear The Surface Description Out AlwaysMemset (& DDSD, 0, SIZEOF (DDSD));
// set the size field alwaysddsd.dwsize = sizeof (ddsd);
// Lock The Surfaceif (Failed (LPDDSPRIMARY-> Lock (Null, & DDSD, DDLOCK_SURFA Part MORYPTR | DDLOCK_WAIT, NULL)) {// Error
} // end if
// ****** At this moment, we have two domains in the discussion: DDSD.LPITCH contains each row // memory interval and ddsd.lpsurface which is a pointer to the upper left corner of the lock surface.
Once you lock the surface, you can freely operate the surface memory. The memory intervals in each row is stored in DDSD.LPITCH, and the pointer to the real surface is lpsurface. So, if you e (1 byte 1 bytes per pixel 1) in 8-bit mode, the following functions can be drawn anywhere in the main surface Pixels.
Inline void plot8 (int X, int y, // position of pixel uchar color, // color index of pixel uchar * buffer, // pointer to surface memory int memory) // memory pitch per line {// this function plots A SINGLE PIXELBUFFER [X Y * MEMPITCH] = Color;
} // end plot8
Here is how you use the above function in (100, 20), color is the color of the color index number 26:
Plot8 (100, 20, 26, (uchar *) DDSD.LPSURFACE, (int) DDSD.LPITCH);
Similarly, here is a 16-bit 5.6.5 RGB mode drawing function:
Inline void plot16 (int X, int y, // position of pixel uchar red, uchar green, uchar, blue // RGB Color of Pixel Ushort * buffer, // Pointer to Surface Memory INT MEMPITCH) // Memory PITCH BYTES Per line {// this function plots a single pixelbuffer [x y * (Mempitch >> 1)] = __RGB16BIT565 (Red, Green, Blue);} // end plot16
Below, how do you draw a pixel with RGB values (10, 14, 30) at (300, 100):
Plot16 (300, 100, 10, 14, 30, (ushort *) ddsd.lpsurface, (int) DDSD.LPITCH);
Now, once your access to all video surfaces of the current animation frame, you need to unlock the surface. This is done with iDirectdrawsurface7 :: unlock () as follows: HRESULT UNLOCK (LPRECT LPRECT);
You send unlock () you use the rectangle used in the lock, or if you lock the entire surface, you set the parameter null. In this case, what you do is to unlock the entire surface.
IF (LPDDSPRIMARY-> Unlock (null))) {// error} // endiff
After completing the job. Let us now put all the steps together to make a program that painted random pixels on the screen (did not do error handling):
LPDIRECTDRAW7 lpdd = NULL; // DirectDraw 7.0 interface 7LPDIRECTDRAWSURFACE7 lpddsprimary = NULL; // surface ptrDDSURFACEDESC2 ddsd; // surface descriptionLPDIRECTDRAWPALETTE lpddpal = NULL; // palette interfacePALETTEENTRY palette [256]; // palette storage
// First Create Base IdirectDraw 7.0 InterfaceDirectDrawCreateex (NULL, (Void **) & LPDD, IID_IDIRECTDRAW7, NULL;
// set the cooperative level for full-screen modelpdd-> setCooperativeElevel (HWnd, DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT);
// set the display mode to 640x480x256lpdd-> setdisplaymode (640, 480, 8, 0);
// Clear DDSD AND SET SIZEMEMSET (& DDSD, 0, SIZEOF (DDSD)); DDSD.dwsize = SizeOf (DDSD);
// enable valid fieldsddsd.dwflags = ddsd_caps;
// request primary surfaceddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; // create the primary surfacelpdd-> CreateSurface (& ddsd, & lpddsprimary, NULL); // build up the palette data arrayfor (int color = 1; color <255; color ) { // Fill with random RGB VALUES PALETTE [Color] .pered = rand ()% 256; Palette [color] .pegreen = rand ()% 256; Palette [color] .peblue = rand ()% 256;
// set flags field to pc_nocollapse palette [color] .peflags = pc_nocollapse;} // end for color
// NOW FILL IN ENTRY 0 and 255 with black and whitepalette [0] .pered = 0; Palette [0] .pegreen = 0; Palette [0] .peblue = 0; Palette [0] .peflags = pc_nocollapse;
Palette [255] .pette [255] .pegreen = 255; Palette [255] .peblue = 255; Palette [255] .peflags = pc_nocollapse;
// Create The Palette ObjectLpdd-> CreatePalette (DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE, PALETTE, & LPDPAL, NULL);
// Finally Attach The Palette to The Primary Surfacelpddsprimary-> SetPalette (LPDDPAL);
// and you're ready to rock n roll! // Lock The Surface First and Retrieve Memory Pointer // And Memory Pitch
// Clear DDSD AND SET SIZE, NEVER Assume It's CleanMemset; DDSD.DWSIZE = SizeOf (DDSD);
LPDDSPRIMARY-> LOCK (NULL, & DDSD, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
/ / The value of DDSD.LPITCH and DDSD.LPSURFACE is valid.
// make a couple aliases to make code cleaner, so we do not // have to castint mempitch = ddsd.lPitch; UCHAR * video_buffer = ddsd.lpSurface; // plot 1000 random pixels with random colors on the // primary surface , will be instantly visiblefor (int index = 0; index <1000; index ) {// select random position and color for 640x480x8 uchar color = rand ()% 256; int x = rand ()% 640; int y = rand ()% 480; // Plot The Pixel Video_Buffer [x y * MEMPITCH] = Color;
} // end for index
// now unlock the primary SurfaceLpddsprimary-> unlock (null);
Of course, I have skip all things such as window initialization and event cycles, but this skip does not affect what I want to tell. However, for integrity, look at Demo6_3.cpp on the CD and the corresponding Demo6_3.exe. They include the code that should be inserted into the main () function of your game console program. The following code lists updates to the GAME_INIT () function. Figure 6.12 is a screenshot of the program. Figure 6.12 Demo6_3.exe is running
INT GAME_MAIN (void * parms = null, int num_parms = 0) {// this is the main loop of the game, do all your processing // hERE
// for now test if user is hitting ESC and send WM_CLOSEif (KEYDOWN (VK_ESCAPE)) SendMessage (main_window_handle, WM_CLOSE, 0,0); // plot 1000 random pixels to the primary surface and return // clear ddsd and set size, Never Assume It's CleanMemset (& DDSD, 0, SIZEOF (DDSD); DDSD.DWSIZE = SizeOf (DDSD);
IF (LPDDSPRIMARY-> LOCK (NULL, & DDSD, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL))) {// Error Return (0);} // end if
// Now ddsd.lpitch is valid and so is ddsd.lpsurface
// make a coupletion, so we don't // have to castint mempitch = (int) ddsd.lpitch; uchar * video_buffer = (uchar *) DDSD.LPSURFACE
// plot 1000 random pixels with random colors on the // primary surface, they will be instantly visiblefor (int index = 0; index <1000; index ) {// select random position and color for 640x480x8 UCHAR color = rand ()% 256; int x = rand ()% 640; int y = rand ()% 480; // plot the pixel video_buffer [x y * MEMPITCH] = Color;
} // end for index
// Now Unlock The Primary Surfaceif (LPDDSPRIMARY-> UNLOCK (NULL)) RETURN (0);
// Sleep A Bitsleep (30);
// Return Success or Failure or Your OWN Return Code Herereeturn (1);
} // End Game_main
INT GAME_INIT (Void * Parms = NULL, INT NUM_PARMS = 0) {// this is caled overce the initial window is created and // before the main event loop is entered, do all your initialization ///th
// First Create Base IdirectDraw Interfaceif (Failed (DirectDrawCreateex (Null, (Void **) & LPDD, IID_IDIRECTDRAW7, NULL)) {// Error Return (0);} // End IF
// set cooperation to full screenif (FAILED (lpdd-> SetCooperativeLevel (main_window_handle, DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT))) {// error return (0);} // end if
// set Display Mode to 640x480x8if (failed (LPDD-> setDisplaymode (Screen_Width, Screen_HEight, Screen_bpp, 0, 0))) {// Error Return (0);} // end if
// Clear DDSD AND SET SIZEMEMSET (& DDSD, 0, SIZEOF (DDSD)); DDSD.dwsize = SizeOf (DDSD);
// enable valid fieldsddsd.dwflags = ddsd_caps;
// Request primary surfacedsd.ddscaps.dwcaps = DDSCAPS_PRIMARYSURFACE;
// Create The Primary Surfaceif (Failed (LPDD, & LPDDSPRIMARY, NULL)) {// Error Return (0);} // end if
// BUILD UP THE PALETTE DATA ARRAYFOR (INT Color = 1; Color ) {// Fill with random RGB VALUES PALETTTE [color] .pered = rand ()% 256; Palette [color] .pegreen = rand )% 256; Palette [color] .peblue = rand ()% 256; // set flags field to pc_nocollapse palette [color] .peflags = pc_nocollapse;} // end for color
// NOW FILL IN ENTRY 0 and 255 with black and whitepalette [0] .pered = 0; Palette [0] .pegreen = 0; Palette [0] .peblue = 0; Palette [0] .peflags = pc_nocollapse;
Palette [255] .pette [255] .pegreen = 255; Palette [255] .peblue = 255; Palette [255] .peflags = pc_nocollapse;
// Create the Palette Objectif (LPDD-> CreatePalette (DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIZE, PALETTE, & LPDDPAL, NULL)) {// ErrorReturn (0);} // end if
// Finally Attach THE PALETTE TO The Primary Surfaceif (Failed (LPDDSPRIMARY-> SetPalette (LPDDPAL))) {// Error Return (0);} // end if
// Return Success or Failure or Your OWN Return Code Herereeturn (1);
} // end game_init
About this Demo program code, the only thing I want to remind you that the details of your attention are the establishment of the main window. As follows:
// crete the windowex (null, // extended style window_class_name, // class "t3d directx pixel demo", // title WS_POPUP | WS_Visible, 0,0, // initial x, y 640, 480, / / Initial Width, Height Null, // Handle To Parent Null, // Instance of this Application NULL) // Extra Creation Parmsreturn (0); Note, using WS_POPUP instead of WS_OVERLAPPEDWINDOW window style. If you still remember, this WS_POPUP style is the default style of all controls and window GUI. And you must use it in full screen DirectX program.
Clean up in this chapter, I want to discuss some topics I have currently put - resource management. This topic is annoying! In short, this seems to be a non-interesting concept; when you use DirectDraw or DirectX objects, you usually want () them. For example, if you look at the source code Demo6_3.cpp, you will see a series of calls to the function Release () in the function game_shutdown () to release all DirectDraw objects to the operating system, and DirectDraw themselves. As follows:
INT GAME_SHUTDOWN (Void * Parms = NULL, INT NUM_PARMS = 0) {// this is caled after the game is expected and the main evenet // loop while is expected, do all you cleanup and shutdown
// first the Paletteif (LPDDPAL) {LPDDPAL-> Release (); lpddpal = null;} // end if
// Now the primary Surfaceif (LPDDSPRIMARY) {LPDDSPRIMARY-> Release (); lpddsprimary = null;} // end if
// Now blow away the iDirectdraw7 interfaceif (LPDD) {LPDD-> Release (); lpdd = null;} // endiff
// Return Success or Failure or Your OWN Return Code Herereeturn (1);
} // end game_shutdown
Generally, once you use the object you will release them, and you should release them in the order in which they are created. For example, you have created the DirectDraw object, the main surface, and the palette, and the better release order is the palette, the surface, the last is DirectDraw, like this: //first kill the Paletteif (LPDDPAL) {LPDDPAL- > Release (); lpddpal = null;} // endiff
// now the primary Surfaceif (LPDDSPRIMARY) LPDDSPRIMARY-> Release ();
// and finally the DirectDraw Object Itselfif (LPDD) {LPDD-> Release (); LPDD = NULL;} // endiff
Warning: Before you call Release (), pay attention to whether the test interface pointer is not NULL. This is exactly necessary because the interface pointer is possible for NULL. And if the implementation of the interface does not take into account this case, this release will cause some problems.
Summary: This chapter, you learned the basic DirectDraw knowledge, we spent a lot of space how to make DirectDraw work, and how to work in full screen mode. Similarly, we also touch the palette, display the surface, and full screen and window applications. Next chapter, I will increase the throttle, we will learn a lot, so baby, fasten the seat belt.