core/vgui/vgui_font_textured.cxx
Go to the documentation of this file.
00001 // This is core/vgui/vgui_font_textured.cxx
00002 //=========================================================================
00003 #include "vgui_font_textured.h"
00004 //:
00005 // \file
00006 // \brief  vgui_font derived class that uses hardcoded fonts.
00007 //
00008 // See vgui_font_textured.h for details.
00009 //=========================================================================
00010 
00011 #include <vgui/vgui_macro.h>
00012 
00013 #include <vil/vil_load.h>
00014 #include <vil/vil_copy.h>
00015 #include <vil/vil_plane.h>
00016 #include <vil/vil_stream_fstream.h>
00017 #include <vil/vil_stream_section.h>
00018 
00019 #include <vcl_cassert.h>
00020 
00021 //-------------------------------------------------------------------------
00022 // Helper functions.
00023 //-------------------------------------------------------------------------
00024 namespace
00025 {
00026   void swap32(char *a, unsigned n)
00027   {
00028     char c;
00029     for (unsigned int i = 0; i < n * 4; i += 4)
00030     {
00031       c = a[i];
00032       a[i] = a[i+3];
00033       a[i+3] = c;
00034       c = a[i+1];
00035       a[i+1] = a[i+2];
00036       a[i+2] = c;
00037     }
00038   }
00039 }
00040 
00041 //-------------------------------------------------------------------------
00042 // vgui_font_textured implementation.
00043 //-------------------------------------------------------------------------
00044 //: Constructor - from a font file (BMF font file only, for now).
00045 vgui_font_textured::vgui_font_textured(const vcl_string& font_file)
00046   : display_list_base_id_(0)
00047   , texture_id_(0)
00048 {
00049   vgui_macro_report_errors;
00050 
00051   if (load_bmf_font(font_file)) { create_display_lists(); }
00052 
00053   vgui_macro_report_errors;
00054 }
00055 
00056 vgui_font_textured::~vgui_font_textured(void)
00057 {
00058   if (display_list_base_id_) { glDeleteLists(display_list_base_id_, 256); }
00059   if (texture_id_) { glDeleteTextures(1, &texture_id_); }
00060 }
00061 
00062 //: Draw font symbol.
00063 void vgui_font_textured::gl_draw(unsigned int i) const
00064 {
00065   // The texture coordinates have a positive y-axis pointing up
00066   // (cartesian coordinate system), while the OpenGL context in vgui
00067   // has a positive y-axis pointing down (image coordinate system).
00068   glBegin(GL_QUADS);
00069 
00070     glTexCoord2f(symbol_coords_[i].x,
00071                  1.f - symbol_coords_[i].y - symbol_coords_[i].height);
00072     glVertex2f(0.f, 0.f);
00073 
00074     glTexCoord2f(symbol_coords_[i].x + symbol_coords_[i].width,
00075                  1.f - symbol_coords_[i].y - symbol_coords_[i].height);
00076     glVertex2f(symbol_coords_[i].width, 0.f);
00077 
00078     glTexCoord2f(symbol_coords_[i].x + symbol_coords_[i].width,
00079                  1.f - symbol_coords_[i].y);
00080     glVertex2f(symbol_coords_[i].width, symbol_coords_[i].height);
00081 
00082     glTexCoord2f(symbol_coords_[i].x,
00083                  1.f - symbol_coords_[i].y);
00084     glVertex2f(0.f, symbol_coords_[i].height);
00085 
00086   glEnd();
00087 
00088   const float spacing_ = 0.001f;
00089   glTranslatef(symbol_coords_[i].width + spacing_, 0.f, 0.f);
00090 }
00091 
00092 //: Draw a string of font symbols.
00093 void vgui_font_textured::draw(const vcl_string& str) const
00094 {
00095   draw(str, 24);
00096 }
00097 
00098 //: Draw a string of font symbols.
00099 void vgui_font_textured::draw(const vcl_string& str,
00100                               unsigned int size) const
00101 {
00102   if (!display_list_base_id_) { return; }
00103 
00104   GLboolean  prev_texture_enabled;
00105   glGetBooleanv(GL_TEXTURE_2D, &prev_texture_enabled);
00106 
00107   glEnable(GL_TEXTURE_2D);
00108   glBindTexture(GL_TEXTURE_2D, texture_id_);
00109 
00110   glPushMatrix();
00111 
00112   // scale to size
00113   const float scale = size / symbol_coords_[0].height;
00114   glScalef(scale, scale, 1.f);
00115 
00116   // print the string
00117   glPushAttrib(GL_LIST_BIT);
00118   glListBase(display_list_base_id_);
00119   glCallLists(str.size(), GL_UNSIGNED_BYTE, str.c_str());
00120   glPopAttrib();
00121 
00122   glPopMatrix();
00123 
00124   if (!prev_texture_enabled) { glDisable(GL_TEXTURE_2D); }
00125 }
00126 
00127 //: Load font from file.
00128 bool vgui_font_textured::load_bmf_font(const vcl_string &font_file)
00129 {
00130   // create and open the file
00131   vil_smart_ptr<vil_stream> stream
00132     = new vil_stream_fstream(font_file.c_str(), "r");
00133   if (!stream->ok())
00134   {
00135     vcl_cerr << __FILE__ ":couldn't open font file:"
00136              << font_file << vcl_endl;
00137     return false;
00138   }
00139 
00140   // read format magic number
00141   char format[3];
00142   if (stream->read(format, 3) != 3)
00143   {
00144     vcl_cerr << __FILE__ ":couldn't read magic number!\n";
00145     return false;
00146   }
00147   if (vcl_string(format, 3) != "BMF")
00148   {
00149     vcl_cerr << __FILE__ ":not a BMF file!\n";
00150     return false;
00151   }
00152 
00153   // read font name
00154   char font_name[96];
00155   if (stream->read(font_name, 96) != 96)
00156   {
00157     vcl_cerr << __FILE__ ":couldn't read font name!\n";
00158     return false;
00159   }
00160 
00161   // *****
00162   // read 256 x 4 floats (assuming float is of size 4 bytes)
00163   assert(sizeof(float) == 4);
00164   float sum = 0.f;
00165   for (unsigned int i = 0; i < 256; i++)
00166   {
00167     sum += stream->read(&symbol_coords_[i].x,      4);
00168     sum += stream->read(&symbol_coords_[i].y,      4);
00169     sum += stream->read(&symbol_coords_[i].width,  4);
00170     sum += stream->read(&symbol_coords_[i].height, 4);
00171 
00172 #if VXL_BIG_ENDIAN
00173     // &symbol_coords_[i] is of type *texture_coord;
00174     // swap32 expects a char* as its first argument
00175     // original code:
00176 #if 0 // this causes a compile error when VXL_BIG_ENDIAN is true
00177     swap32(&symbol_coords_[i], 4);
00178 #else // I *think* this is what the original author had in mind:
00179     swap32((char *) &symbol_coords_[i].x,      4);
00180     swap32((char *) &symbol_coords_[i].y,      4);
00181     swap32((char *) &symbol_coords_[i].width,  4);
00182     swap32((char *) &symbol_coords_[i].height, 4);
00183 #endif // 0
00184 #endif // VXL_BIG_ENDIAN
00185   }
00186   if (sum != 256*4*4) // 256 symbols * 4 floats * 4 bytes
00187   {
00188     vcl_cerr << __FILE__ ":couldn't read symbol info!\n";
00189     return false;
00190   }
00191 
00192   // read sgi (iris) embedded image
00193   vil_smart_ptr<vil_stream> sgi_section
00194     = new vil_stream_section(stream.ptr(), 3 + 96 + 256*4*4);
00195   vil_image_view<GLubyte> texture_image
00196     = vil_load_image_resource_raw(sgi_section.ptr())->get_view();
00197 
00198   load_texture(texture_image);
00199 
00200   return true;
00201 }
00202 
00203 //: Load OpenGL texture for all symbols.
00204 void vgui_font_textured::load_texture(const vil_image_view<GLubyte>& image)
00205 {
00206   vgui_macro_report_errors;
00207 
00208   // set row alignment to byte aligned
00209   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00210 
00211   // generate a texture id
00212   glGenTextures(1, &texture_id_);
00213 
00214   // bind this texture to a target object
00215   glBindTexture(GL_TEXTURE_2D, texture_id_);
00216 
00217   // sets some properties on the target object
00218   //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00219   //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00220   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00221   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00222 
00223   vil_image_view<GLubyte> texture(image.ni(), image.nj());
00224   vil_copy_reformat(vil_plane(image, 1), texture);
00225 
00226   // specify the 2D texture image
00227   glTexImage2D(GL_TEXTURE_2D,          // texture object
00228                0,                      // resolution level
00229                GL_RGBA,                // OpenGL internalformat
00230                image.ni(),             // width
00231                image.nj(),             // height
00232                0,                      // add border
00233                GL_LUMINANCE,           // pixel format
00234                GL_UNSIGNED_BYTE,       // pixel data type
00235                texture.memory_chunk()->data());  // pointer to image
00236 
00237   vgui_macro_report_errors;
00238 }
00239 
00240 //: Create OpenGL display list for each symbol.
00241 void vgui_font_textured::create_display_lists(void)
00242 {
00243   vgui_macro_report_errors;
00244 
00245   // build the display list for each symbol
00246   display_list_base_id_ = glGenLists(256);
00247 
00248   for (unsigned int i = 0; i < 256; i++)
00249   {
00250     glNewList(display_list_base_id_ + i, GL_COMPILE);
00251     gl_draw(i);
00252     glEndList();
00253   }
00254 
00255   vgui_macro_report_errors;
00256 }