News
DirectX
Links
Contact Me

In Association with Amazon.com
In Association with Amazon.ca

$5 via PayPal


Direct3D Lesson 13



Direct3D Lesson 13:D3DXFont

The associated NeHe tutorial builds Font bitmaps using wglUseFontBitmaps. A close analog to that in Direct3D8 is the D3DXFont class. It's extremely easy to set up, and the results look really nice. D3DXFont supports anti-aliasing and kerning. The cost is that it's not incredibly fast.

This tutorial uses my dhEngine for initialization and my dhFPSTimer to provide FPS stats. The base code for this tutorial is the dhEngine_shell.cpp provided in the dhEngine archive. Only the significant changes from that shell are shown here.


To create a D3DXFont, we're going to need to declare our pointer

//Declare our D3DXFont interface pointer
ID3DXFont *g_font=NULL;

Our build font function does pretty much what you would expect. We define the font we would like to build, pass it to D3DXCreateFontIndirect and that's pretty much all there is to it!

//********************************************************************
// Function:build_font
// Whazzit:Creates our D3DXFont.
//********************************************************************
void build_font(void){
HRESULT hr;

//our LOGFONT structure defines the font we're requesting.  A lot of
//this information is option and you can use defaults instead.  See
//your SDK docs for more info.
LOGFONT log_font={
   32, //height
   0,  //width; 
   0,  // lfEscapement; 
   0,  //lfOrientation; 
   FW_BOLD, // lfWeight; 
   FALSE, // lfItalic; 
   FALSE, // lfUnderline; 
   FALSE, // lfStrikeOut; 
   DEFAULT_CHARSET, // lfCharSet; 
   OUT_DEFAULT_PRECIS, //lfOutPrecision; 
   CLIP_DEFAULT_PRECIS, // lfClipPrecision; 
   ANTIALIASED_QUALITY,// lfQuality; 
   DEFAULT_PITCH,// lfPitchAndFamily; 
   "Arial"// lfFaceName[LF_FACESIZE]; 
   };

   //This is all there is to creating a D3DXFont.  Pretty easy, eh?
   hr=D3DXCreateFontIndirect(g_engine.GetEngineDevice(),&log_font,&g_font);
   if(FAILED(hr)){
      g_engine.dhERROR("Error creating font");
   }
}

Our free_font function couldn't be much simpler. We call the Release method and it goes away.

//********************************************************************
// Function:free_font
// Whazzit:Frees our D3DXFont.
//********************************************************************
void free_font(void){

   //it just doesn't get much simpler than this
   if(g_font){
      g_font->Release();
      g_font=NULL;
   }

}

The most complicated part of this whole tutorial is the Render function. And as you can see below, there really isn't much to it.

//********************************************************************
// Function:Render
// Whazzit:This is where the magic happens.  Where our hopes and dreams
//         become visual reality!! (also known as the place where we
//         draw stuff)
//********************************************************************
void Render(void){
char buffer[20];
float fps=0.0f;
DWORD dummy1,dummy2;
//This rect is used to position our text.  Because of the flags we're using the
//right & bottom values don't really matter so we make them huge.  We use the
//top & left to position the text
RECT font_rect={0,0,9000,9000};

   g_engine.ClearC();

   //Get our current FPS stats, we only care about the average FPS, not min or max
   g_timer.CheckTimer(&fps,&dummy1,&dummy2);

   //Build our FPS into a nice string
   sprintf(buffer,"FPS:%.2f",fps);

   //Notify the device that we're ready to render
   if(SUCCEEDED(g_engine.BeginScene())){
      //the Begin() method sets up all the renderstates required to use ID3DXFont
      //If you don't call it, DrawText will call it internally every time you draw
      //so it's generally best to call it yourself.
      g_font->Begin();

      //All of our text is going to be draw at the left side of the screen, if you want to
      //move the text away from the left, just change font_rect.left to something other than 0

      //Each time, before we draw, set the top location for our text rendering.
      font_rect.top=0;
      g_font->DrawText(buffer,     //This is the text to be rendered
                       -1,         //This is the string length, -1 indicates that it's a NULL
                                   //terminated string, so it can calculate the length.
                       &font_rect, //Our rect, used to position the text
                       DT_LEFT,    //Our flags.  This one means that the text should be
                                   //left justified.  See the docs for more options.
                       0xFFBBBBBB);//This is our rendering colour.  Notice the Alpha component
                                   //is 0xFF, this makes it opaque, you can change that for some
                                   //cool effects

      font_rect.top=50;
      g_font->DrawText("I have the best intentions, but the worst ideas.",-1,&font_rect,DT_LEFT,0xFFFFFFFF);

      font_rect.top=90;
      g_font->DrawText("What we learn to do, we learn by doing.-Aristotle",-1,&font_rect,DT_LEFT,0xFFFFFF33);

      font_rect.top=130;
      g_font->DrawText("The best mind-altering drug is truth.-Lily Tomlin",-1,&font_rect,DT_LEFT,0xFF33FFFF);

      font_rect.top=170;
      g_font->DrawText("Hello World! This is a bunch of text!",-1,&font_rect,DT_LEFT,0xFFFFFFFF);

      //End registers that we're done rendering text for now and does whatever internal
      //voodoo is required.
      g_font->End();
      g_engine.EndScene();
   }

   //Show the results
   g_timer.Present();
}

That's all there is to it!