Tricks of the Windows Game Programming Gurus:DirectX Fundamentals and the Dreaded COM

All ITKnowledge Source Code Search Tips Advanced Search |

| Tricks of the Windows Game Programming Gurus by Andre LaMothe Sams, Macmillan Computer Publishing ISBN: 0672313618 Pub Date: 09/27/99

Search this book:

Previous | Table of Contents | Next

Notice that `SetPixel()` is, in a way, an alias for `SetPixel_ATI()`. This is the key to function pointers. Now, to call `SetPixel()` you make a normal call, but instead of calling the empty `SetPixel()`, the call really calls `SetPixel_ATI()`:

    // this really calls SetPixel_ATI(10,20,4);

    SetPixel(10,20,4);

The point is that your code always looks like same, but it does different things based on how you assign the function pointer. This is such a cool technology that much of C++ and virtual functions are based on it. That’s all virtual functions really are—late binding of function pointers, but nicely built into the language and then built up as you’ve done here.

With that in mind, let’s see how you would finish your generic video driver link-up… All you have to do is test to see which card is installed, set the `SetPixel()` function pointer once to the proper `SetPixel*()` function, and that’s it. Take a look:

    int SetCard(int card)

    {

    // assign the function pointer based on the card

    switch(card)

          {

          case ATI:

               {

               SetPixel = SetPixel_ATI;

               } break;

          case VOODOO:

               {

               SetPixel = SetPixel_VOODOO;

               } break;

          case SIII:

               {

               SetPixel = SetPixel_SIII;

               } break;

          default: break;

          } // end switch

    } // end SetCard

At the beginning of your code, you would make a call to the set up function like this:

    SetCard(card);

And from then on, you’re good to go. This is how function pointers and virtual functions are used in C++, so now let’s see how these techniques are used with DirectX.

#### Creating and Using DirectX Interfaces

At this point, I think you understand that COM objects are collections of interfaces, which are simply function pointers (and more specifically, VTABLEs). Hence, all you need to do to work with a DirectX COM object is create it, retrieve an interface pointer, and then make calls to the interface using the proper syntax. As an example, I’ll use the main DirectDraw interface to show how this is done.

First off, you need three things to experiment with DirectDraw:

  • The DirectDraw run-time COM object(s) and DLLs must be loaded and registered. This is what the DirectX installer does.
  • You must include the `DDRAW.LIB` import library in your Win32 programs so that the wrapper functions you call are linked in.
  • You need to include `DDRAW.H` in your program so the compiler can see the header information, prototypes, and data types for DirectDraw.

With that in mind, here’s the data type for a DirectDraw interface pointer:

    LPDIRECTDRAW lpdd = NULL;

Now, to create a DirectDraw COM object and retrieve an interface pointer to the DirectDraw object (which represents the video card), all you need to do is use the wrapper function `DirectDrawCreate()` like this:

    DirectDrawCreate(NULL, &lpdd, NULL);

In Chapter 6, “First Contact: DirectDraw,” I go into the parameters in detail. But for now, just be aware that this call creates a DirectDraw object and assigns the interface pointer to `lpdd`.

> Note: Of course, there’s a lot going on in the function. It opens a DLL, loads it, makes calls, and does about a million other things. But you don’t have to worry about it.

Now you’re in business and can make calls to DirectDraw. But wait a minute! You don’t know the methods or functions that are available—that’s why you’re reading this book <BG>. As an example, here’s how you would set the video mode to 640×480 with 256 colors:

    lpdd->SetVideoMode(640, 480, 256);

Is that simple or what? About the only extra work is the pointer dereference from the DirectDraw interface pointer `lpdd`—that’s it. Of course, what’s really happening is a lookup in the virtual table of the interface, but don’t be concerned about that.

In essence, any call to DirectX takes the following form:

    interface_pointer->method_name(parameter list);

Also, you can get any other interfaces that you might want to work with (for example, Direct3D) from the original DirectDraw interface by using `QueryInterface()`. Moreover, since there are multiple versions of DirectX floating around, a while ago Microsoft stopped writing wrapped functions to retrieve the latest interface. What this means is that you must manually retrieve the latest DirectX interface yourself with `QueryInterface()`. Let’s take a look at that.

Previous | Table of Contents | Next

Copyright © Macmillan Computer Publishing, Inc.

Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.