Cooperating with WindowsAs you know, Windows is a cooperative, shared environment. At least that's the idea, although as a programmer I still haven't figured out how to make it cooperate with my code! Anyway, DirectX is similar to any Win32 system, and at the very least, it must inform Windows that it's going to use various resources so that other Windows applications don't try to request (and get) resources that DirectX has control over. Basically, DirectX can be a complete resource hog as long is it tells Windows what it's doing—seems fair to me <BG>. In the case of DirectDraw, about the only thing that you should be interested in is the video display hardware. There are two cases that you must concern yourselves with:
In full-screen mode, DirectDraw acts much like an old DOS program. That is, the entire screen surface is allocated to your game, and you write directly to the video hardware. No other application can touch the hardware. Windowed mode is a little different. In windowed mode, DirectDraw must cooperate much more with Windows because other applications may need to update their own client window areas (which may be visible to the user). Hence, in windowed mode your control and monopolization of the video hardware is much more restrained. However, you still have full access to 2D and 3D acceleration, so that's a good thing. But then, so were bell-bottoms at first… Chapter 7, "Advanced DirectDraw and Bitmapped Graphics," will talk more about windowed DirectX applications, but they are a little more complex to handle. Most of this chapter will deal with full-screen modes because they are easier to work with, so keep that in mind. Now that you know a little bit about why there needs to be cooperation between Windows and DirectX, let's see how to tell Windows how you want to cooperate. To set the cooperation level of DirectDraw, use the IDirectDraw7:: SetCooperativeLevel() function, which is a method of IDirectDraw7. C++ For you C programmers, the syntax IDirectDraw7::SetCooperative Level() may be a little cryptic. The :: operator is called the scope resolution operator, and the syntax simply means that SetCooperativeLevel() is a method (or member function) of the IDirectDraw7 interface. This is basically a class that is nothing more than a structure with data and a virtual function table. In some cases, I may forgo using the interface to prefix the method and write it like SetCooperativeLevel(). However, be advised that all DirectX functions are part of an interface and thus must be called using a function pointer style call, like lpdd->function(...). Here's the prototype of IDirectDraw7::SetCooperativeLevel(): HRESULT SetCooperativeLevel(HWND hWnd, // window handle DWORD dwFlags);// control flags This returns DD_OK if successful, and an error code if not. Interestingly enough, this is the first time that the window handle has entered into the DirectX equation. The hWnd parameter is needed so that DirectX (or more specifically, DirectDraw) has something to anchor to. Simply use your main window handle in all cases. The second and last parameter to SetCoopertiveLevel() is dwFlags, which is the control flags parameter and directly influences the way that DirectDraw works with Windows. Table 6.2 lists the most commonly used values that can be logically ORed together to obtain the desired cooperation level. If you take a good look at the various flags, it may seem that some of them are redundant—very true. Basically, DDSCL_FULLSCREEN and DDSCL_EXCLUSIVE must be used together, and if you decide to use any Mode X modes, you must use DDSCL_FULLSCREEN, DDSCL_EXCLUSIVE, and DDSCL_ALLOWMODEX all together. Other than that, the flags pretty much do what they would seem to from their definitions. In most cases, you'll set full-screen applications like this: lpdd7->SetCooperativeLevel(hwnd, DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT); and normal windowed applications like this: lpdd7->SetCooperativeLevel(hwnd, DDSCL_NORMAL); Of course, when you get to multithreaded programming techniques later in the book, you might want to add the multithreading flag DDSCL_MULTITHREADED to play it safe. Anyway, let's see how you would create a DirectDraw object and set the cooperation level together: LPDIRECTDRAW lpdd = NULL; // standard DirectDraw 1.0 LPDIRECTDRAW7 lpdd7 = NULL; // DirectDraw 7.0 interface 7 // first create base IDirectDraw interface if (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 yet if (FAILED(lpdd7->SetCooperativeLevel(hwnd, DDSCL_NORMAL))) { // error } // end if NOTE I may start leaving out the error handling calls to FAILED() and/or SUCCEEDED() to save space, but remember that you should always check for errors! At this point, you have enough information to create a complete DirectX application that creates a window, starts up DirectDraw, and sets the cooperation level. Although you don't know how to draw, it's a start. As an example, take a look at DEMO6_1.CPP on the CD, along with its executable DEMO6_1.EXE. When you run the program, you'll see something like what's shown in Figure 6.5. I based the program on the T3D Game Console template, so the only changes I made were in the Game_Init() and Game_Shutdown() to create and set the cooperation level for DirectDraw. Figure 6.5. DEMO6_1.EXE in action.Here are those functions with the added DirectDraw code from DEMO6_1.CPP, so you can see how simple DirectDraw is to set up: 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 interface if (FAILED(DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL))) { // error return(0); } // end if // set cooperation to normal since this will be a windowed app lpdd->SetCooperativeLevel(main_window_handle, DDSCL_NORMAL); // return success or failure or your own return code here return(1); } // end Game_Init ///////////////////////////////////////////////////////////// int Game_Shutdown(void *parms = NULL, int num_parms = 0) { // this is called after the game is exited and the main event // loop while is exited, do all you cleanup and shutdown here // simply blow away the IDirectDraw interface if (lpdd) { lpdd->Release(); lpdd = NULL; } // end if // return success or failure or your own return code here return(1); } // end Game_Shutdown TIP If you're about to jump in head-first and try to compile DEMO6_1.CPP, please remember to manually include DDRAW.LIB from the DirectX 8.0 SDK LIB\ directory, along with adding the DirectX header paths to your compiler's .H search directories as the first directory! And of course, you should build a Win32 .EXE. I get at least 10 emails a day from rookie compiler users who forget to include the .LIB files, so don't be another statistic… |