JavaScript EditorFree JavaScript Editor     Ajax Editor 



Main Page
  Previous Section Next Section

Mixing GDI and DirectX

AAHAHAHAHAHAAHAHAHAHAH! Sorry, I just needed some tension relief. Now back to business. GDI, or the Graphics Device Interface, is the Win32 graphics subsystem responsible for all Windows rendering. You've already seen how to work with GDI in the previous sections on Windows programming, so I'm not going to reiterate device contexts and such.

To use GDI with DirectDraw, all you need to do is retrieve a compatible DC from DirectDraw and then use it like you'd use the DC from the standard GetDC() call. The cool thing is that once you retrieve a GDI-compatible DC from DirectDraw, there's really no difference in how you use the GDI functions. In fact, all of your code will work almost without change!

Now, you may be wondering how GDI can work with DirectDraw if DirectDraw takes over the graphics system, as it does in full-screen mode. Well, Windows can't use GDI to draw on any of your DirectDraw surfaces while in exclusive mode, but you can. This is the important detail that confuses many newbies to DirectX. In general, Windows sends messages to its subsystems like GDI, MCI, and so on. If DirectX has control of the hardware systems and is sharing them exclusively, the messages won't be processed. For example, a GDI graphics call to draw something while in full-screen mode will be dumped.

However, you can always use the software of the subsystems to do work for you because you're the one in charge. It's like a plasma blaster that's encoded to your DNA; if I pick it up it won't fire, but it will if you pick it up. So the user dictates when the blaster works, but the blaster is always functional. Weird example, huh? You try not sleeping for weeks—it's going to get weirder <BG>.

Because you do all your drawing on surfaces, you would assume that there's a way to get a GDI-compatible DC from a DirectDraw surface, and there is. The name of the function is IDIRECTDRAWSURFACE7::GetDC() and it's shown here:

HRESULT GetDC(HDC FAR *lphDC);

All you do is make a call with some storage for the DC, and you're good to go. Here's an example:

LPDIRECTDRAWSURFACE7 lpdds; // assume this is valid

HDC xdc; // I like calling DirectX DC XDC's

if (FAILED(lpdds->GetDC(&xdc)))
    { /* error */ }

// do what you will with the DC...

Once you're done with the DirectDraw-compatible DC, you must release it just as you would a normal GDI DC. The function is IDIRECTDRAWSURFACE7::ReleaseDC() and is shown here:

HRESULT ReleaseDC(HDC hDC);

Basically, just send it the DC you retrieved like this:

if (FAILED(lpdds->ReleaseDC(xdc)))
    { /* error */ }

WARNING

If a surface is locked, GetDC() won't work on it because GetDC() also locks the surface. In addition, once you get the DC from a surface, make sure you ReleaseDC() as soon as you're done because GetDC() creates an internal lock on the surface, and you won't be able to access it. In essence, only GDI or DirectDraw can write to a surface at any time, not both.


For an example of using GDI, take a look at DEMO7_17.CPP|EXE. It creates a full-screen DirectDraw application in 640x480x256 and then prints GDI text at random locations. The code that prints the text is shown here:

int Draw_Text_GDI(char *text, int x,int y,
                  COLORREF color, LPDIRECTDRAWSURFACE7 lpdds)
{
// this function draws the sent text on the sent surface
// using color index as the color in the palette

HDC xdc; // the working dc

// get the dc from surface
if (FAILED(lpdds->GetDC(&xdc)))
   return(0);

// set the colors for the text up
SetTextColor(xdc,color);

// set background mode to transparent so black isn't copied
SetBkMode(xdc, TRANSPARENT);

// draw the text a
TextOut(xdc,x,y,text,strlen(text));

// release the dc
lpdds->ReleaseDC(xdc);

// return success
return(1);
} // end Draw_Text_GDI

TRICK

Please note that color is in the form of a COLORREF. This is a very important performance issue. COLORREFs are 24-bit RGB-encoded structures, meaning that the requested color is always in 24-bit RGB form. The problem with this is that when DirectX is in palettized mode, it must hunt for the nearest match to the requested color. This is in addition to the slow speed of GDI in general, which makes text printing using GDI very slow. I highly recommend writing your own text blitter for any speed-intensive text printing.


The function does all the manipulation of the DC itself, so all you have to do is call it. For example, to print out "You da Man!" at (100,100) in pure green on the primary surface, you would write

Draw_Text_GDI("You da Man!",
              100,100,
              RGB(0,255,0),
              lpddsprimary);

Before moving on, I want to talk a little about when to use GDI. In general, GDI is slow. I usually use it during development to print text, draw GUI stuff, and so on. Also, it's very useful for slow emulation during development. For example, let's say that you're planning to write a really fast line-drawing algorithm called Draw_Line(). You might not have time to do it yet, but you can always emulate Draw_Line() with GDI calls. That way at least you get something on the screen, and later you can write the fast line-drawing algorithm.

      Previous Section Next Section
    



    JavaScript EditorAjax Editor     JavaScript Editor