00001
00002
00003 #include "vgui_font_textured.h"
00004
00005
00006
00007
00008
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
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
00043
00044
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
00063 void vgui_font_textured::gl_draw(unsigned int i) const
00064 {
00065
00066
00067
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
00093 void vgui_font_textured::draw(const vcl_string& str) const
00094 {
00095 draw(str, 24);
00096 }
00097
00098
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
00113 const float scale = size / symbol_coords_[0].height;
00114 glScalef(scale, scale, 1.f);
00115
00116
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
00128 bool vgui_font_textured::load_bmf_font(const vcl_string &font_file)
00129 {
00130
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
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
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
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
00174
00175
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)
00187 {
00188 vcl_cerr << __FILE__ ":couldn't read symbol info!\n";
00189 return false;
00190 }
00191
00192
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
00204 void vgui_font_textured::load_texture(const vil_image_view<GLubyte>& image)
00205 {
00206 vgui_macro_report_errors;
00207
00208
00209 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00210
00211
00212 glGenTextures(1, &texture_id_);
00213
00214
00215 glBindTexture(GL_TEXTURE_2D, texture_id_);
00216
00217
00218
00219
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
00227 glTexImage2D(GL_TEXTURE_2D,
00228 0,
00229 GL_RGBA,
00230 image.ni(),
00231 image.nj(),
00232 0,
00233 GL_LUMINANCE,
00234 GL_UNSIGNED_BYTE,
00235 texture.memory_chunk()->data());
00236
00237 vgui_macro_report_errors;
00238 }
00239
00240
00241 void vgui_font_textured::create_display_lists(void)
00242 {
00243 vgui_macro_report_errors;
00244
00245
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 }