开发者

Best way to display diagnostic text in Windows OpenGL

开发者 https://www.devze.com 2022-12-18 05:58 出处:网络
I have an artsy opengl app that I am working on.The final product will have no need to display text.But during developement I want to display odd bits of data for diagnostic purposes, like framerate,

I have an artsy opengl app that I am working on. The final product will have no need to display text. But during developement I want to display odd bits of data for diagnostic purposes, like framerate, object count. I would like the rendering of the text not to dramatically decrease the performance of the code.

I realize this is a mildly subjective question, 开发者_运维问答but all the same I would appreciate your thoughts


I wrote an opengl text renderer using just the gl_line primitives if that suits your needs:

#ifndef SIMPLETEXT_H
#define SIMPLETEXT_H

#include <GL/gl.h>

namespace SimpleText  {

   // internal vertex
   union vertex  {
      float data[3];
   };

   // use 15 verts to hold all possible letters
   // 0 - 1 - 2
   // 3 - 4 - 5
   // 6 - 7 - 8
   // 9 - 10- 11
   // 12- 13- 14
   vertex verts[15] = {
      {0, 4, 0}, {1, 4, 0}, {2, 4, 0},
      {0, 3, 0}, {1, 3, 0}, {2, 3, 0},
      {0, 2, 0}, {1, 2, 0}, {2, 2, 0},
      {0, 1, 0}, {1, 1, 0}, {2, 1, 0},
      {0, 0, 0}, {1, 0, 0}, {2, 0, 0}
   };

   // start/end char values
   const int START = 33;
   const int END = 90;

   // size of the window (assumed square)
   // increase this to decrease the size of text
   const int WINDOW_EXTENT = 300;

   // use index arrays to create letters
   unsigned int letters[END - START + 1][15] = {
      {4, 1, 7, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},      // !
      {4, 1, 4, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},        // "
      {8, 0, 12, 2, 14, 3, 5, 9, 11, 0, 0, 0, 0, 0, 0},     // #
      {8, 2, 3, 3, 11, 11, 12, 1, 13, 0, 0, 0, 0, 0, 0},    // $
      {14, 2, 12, 0, 3, 3, 1, 1, 0, 11, 13, 13, 14, 14, 11}, // %
      {14, 14, 3, 3, 1, 1, 7, 7, 9, 9, 12, 12, 13, 13, 11}, // &
      {2, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},        // '
      {6, 1, 3, 3, 9, 9, 13, 0, 0, 0, 0, 0, 0, 0, 0},       // (
      {6, 1, 5, 5, 11, 11, 13, 0, 0, 0, 0, 0, 0, 0, 0},     // )
      {6, 0, 8, 6, 2, 1, 7, 0, 0, 0, 0, 0, 0, 0, 0},        // *
      {4, 6, 8, 4, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},       // +
      {2, 10, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},      // ,
      {2, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},        // -
      {8, 12, 13, 13, 10, 10, 9, 9, 12, 0, 0, 0, 0, 0, 0},  // .
      {2, 2, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},       // /
      {10, 0, 2, 2, 14, 14, 12, 12, 0, 0, 14, 0, 0, 0, 0},  // 0
      {6, 3, 1, 1, 13, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0},     // 1
      {10, 3, 1, 1, 5, 5, 8, 8, 12, 12, 14, 0, 0, 0, 0},    // 2
      {12, 0, 1, 1, 5, 5, 11, 11, 13, 13, 12, 8, 7, 0, 0},  // 3
      {6, 14, 2, 2, 6, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0},       // 4
      {12, 2, 0, 0, 6, 6, 7, 7, 11, 11, 13, 13, 12, 0, 0},  // 5
      {14, 2, 1, 1, 3, 3, 12, 12, 13, 13, 11, 11, 7, 7, 6}, // 6
      {4, 0, 2, 2, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},       // 7
      {12, 1, 3, 3, 11, 11, 13, 13, 9, 9, 5, 5, 1, 0, 0},   // 8
      {10, 2, 1, 1, 3, 3, 7, 7, 8, 2, 14, 0, 0, 0, 0},      // 9
      {4, 1, 4, 10, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},      // :
      {4, 1, 4, 10, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},      // ;
      {4, 5, 6, 6, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},       // <
      {4, 5, 3, 9, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},       // =
      {4, 3, 8, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},        // >
      {8, 3, 1, 1, 5, 5, 7, 7, 10, 0, 0, 0, 0, 0, 0},       // ?
      {14, 4, 7, 7, 8, 8, 5, 5, 1, 1, 3, 3, 9, 9, 14},      // @
      {10, 1, 6, 1, 8, 6, 12, 8, 14, 6, 8, 0, 0, 0, 0},     // A
      {14, 0, 12, 0, 5, 5, 7, 7, 6, 7, 11, 11, 13, 13, 12}, // B
      {10, 2, 1, 1, 3, 3, 9, 9, 13, 13, 14, 0, 0, 0, 0},    // C
      {12, 0, 1, 1, 5, 5, 11, 11, 13, 13, 12, 12, 0, 0, 0}, // D
      {8, 0, 12, 0, 2, 6, 7, 12, 14, 0, 0, 0, 0, 0, 0},     // E
      {6, 0, 12, 0, 2, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0},       // F
      {14, 2, 1, 1, 3, 3, 9, 9, 13, 13, 11, 11, 8, 8, 7},   // G
      {6, 0, 12, 6, 8, 2, 14, 0, 0, 0, 0, 0, 0, 0, 0},      // H
      {6, 0, 2, 1, 13, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0},     // I
      {8, 1, 2, 2, 11, 11, 13, 13, 9, 0, 0, 0, 0, 0, 0},    // J
      {6, 0, 12, 6, 2, 6, 14, 0, 0, 0, 0, 0, 0, 0, 0},      // K
      {4, 0, 12, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},     // L
      {8, 0, 12, 0, 7, 7, 2, 2, 14, 0, 0, 0, 0, 0, 0},      // M
      {6, 0, 12, 0, 14, 14, 2, 0, 0, 0, 0, 0, 0, 0, 0},     // N
      {12, 1, 5, 5, 11, 11, 13, 13, 9, 9, 3, 3, 1, 0, 0},   // O
      {10, 0, 12, 0, 1, 1, 5, 5, 7, 7, 6, 0, 0, 0, 0},      // P
      {12, 0, 12, 12, 13, 13, 11, 11, 2, 2, 0, 10, 14, 0, 0},  // Q
      {12, 0, 12, 0, 1, 1, 5, 5, 7, 7, 6, 7, 14, 0, 0},     // R
      {14, 2, 1, 1, 3, 3, 6, 6, 8, 8, 11, 11, 13, 13, 12},  // S
      {4, 0, 2, 1, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},       // T
      {8, 0, 9, 9, 13, 13, 11, 11, 2, 0, 0, 0, 0, 0, 0},    // U
      {4, 0, 13, 13, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},      // V
      {8, 0, 12, 12, 1, 1, 14, 14, 2, 0, 0, 0, 0, 0, 0},    // W
      {4, 0, 14, 2, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},      // X
      {6, 0, 7, 7, 2, 7, 13, 0, 0, 0, 0, 0, 0, 0, 0},       // Y
      {6, 0, 2, 2, 12, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0}      // Z
   };

}

// Draws a string of length <len> at an <x>/<y> position on the screen, optionally with a <shadow>
//  The screen is set up to be 0,0 at the lower left and 150,150 at the upper right for positioning
//  by default.
static void DrawText(const char * string, int len, float x, float y, bool shadow = false)  {
   if (len <= 0) return;

   glPushMatrix();
   glLoadIdentity();

   glMatrixMode(GL_PROJECTION);
   glPushMatrix();

   glLoadIdentity();
   glOrtho(0, SimpleText::WINDOW_EXTENT, 0, SimpleText::WINDOW_EXTENT, -10, 10);

   glMatrixMode(GL_MODELVIEW);

   glBindTexture(GL_TEXTURE_2D, 0);

   glVertexPointer(3, GL_FLOAT, 0, SimpleText::verts);
   glEnableClientState(GL_VERTEX_ARRAY);

   char temp = 0;

   // draw first copy if we need a shadow
   if (shadow)  {
      glTranslatef(x + 0.3, y - 0.5, 0);
      glColor4f(0.0f, 0.0f, 0.0f, 1.0f);

      for (int i = 0; i < len; i++)  {
         temp = string[i];
         temp = (temp < 97) ? temp : temp - 32;
         if (temp >= SimpleText::START && temp <= SimpleText::END)  {

            glDrawElements(
               GL_LINES, 
               SimpleText::letters[temp - SimpleText::START][0], 
               GL_UNSIGNED_INT, 
               &(SimpleText::letters[temp - SimpleText::START][1])
            );
         }

         glTranslatef(2.7f, 0, 0);
      }
   }

   glLoadIdentity();
   glTranslatef(x, y, 0);
   glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

   // draw regular text
   for (int i = 0; i < len; i++)  {
      temp = string[i];
      temp = (temp < 97) ? temp : temp - 32;
      if (temp >= SimpleText::START && temp <= SimpleText::END)  {

         glDrawElements(
            GL_LINES, 
            SimpleText::letters[temp - SimpleText::START][0], 
            GL_UNSIGNED_INT, 
            &(SimpleText::letters[temp - SimpleText::START][1])
         );
      }

      glTranslatef(2.7f, 0, 0);
   }

   glDisableClientState(GL_VERTEX_ARRAY);


   glMatrixMode(GL_PROJECTION);
   glPopMatrix();

   glMatrixMode(GL_MODELVIEW);
   glPopMatrix();
}

#endif


Given that you're doing this on Windows, the easy way to handle things is to use wglUseFontBitmaps to load a set of characters into a display list, then glRasterPos2i to pick where to draw the text, and glCallLists to draw a string. If you wanted something fancier than diagnostics, you could use wglUseFontOutlines to get a little fancier, such as creating 2.5D (extruded) text.


If you need it only during development, you might want to check out the Win32 function OutputDebugString(). It sends the text to an attached debugger and requires no changes to your existing program at all. You could also build your program as a console application and simply write the text to stdout (printf, std::cout). This might not be as beautiful as a custom OpenGL text renderer, but it's as simple as it gets.


Grab the 8x8 CP437 glyphs and stick them (in ASCII order) in a 128x128 texture. Since they're tightly packed, make sure to turn of bilinear filtering or else you'll get bleeding into adjacent glyphs.

0

精彩评论

暂无评论...
验证码 换一张
取 消