doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
tr_font.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 
30 #include "../idlib/precompiled.h"
31 #pragma hdrstop
32 
33 #include "tr_local.h"
34 
35 #ifdef BUILD_FREETYPE
36 #include "../ft2/fterrors.h"
37 #include "../ft2/ftsystem.h"
38 #include "../ft2/ftimage.h"
39 #include "../ft2/freetype.h"
40 #include "../ft2/ftoutln.h"
41 
42 #define _FLOOR(x) ((x) & -64)
43 #define _CEIL(x) (((x)+63) & -64)
44 #define _TRUNC(x) ((x) >> 6)
45 
46 FT_Library ftLibrary = NULL;
47 #endif
48 
49 
50 #ifdef BUILD_FREETYPE
51 
52 /*
53 ============
54 R_GetGlyphInfo
55 ============
56 */
57 void R_GetGlyphInfo(FT_GlyphSlot glyph, int *left, int *right, int *width, int *top, int *bottom, int *height, int *pitch) {
58 
59  *left = _FLOOR( glyph->metrics.horiBearingX );
60  *right = _CEIL( glyph->metrics.horiBearingX + glyph->metrics.width );
61  *width = _TRUNC(*right - *left);
62 
63  *top = _CEIL( glyph->metrics.horiBearingY );
64  *bottom = _FLOOR( glyph->metrics.horiBearingY - glyph->metrics.height );
65  *height = _TRUNC( *top - *bottom );
66  *pitch = ( qtrue ? (*width+3) & -4 : (*width+7) >> 3 );
67 }
68 
69 /*
70 ============
71 R_RenderGlyph
72 ============
73 */
74 FT_Bitmap *R_RenderGlyph(FT_GlyphSlot glyph, glyphInfo_t* glyphOut) {
75  FT_Bitmap *bit2;
76  int left, right, width, top, bottom, height, pitch, size;
77 
78  R_GetGlyphInfo(glyph, &left, &right, &width, &top, &bottom, &height, &pitch);
79 
80  if ( glyph->format == ft_glyph_format_outline ) {
81  size = pitch*height;
82 
83  bit2 = Mem_Alloc(sizeof(FT_Bitmap));
84 
85  bit2->width = width;
86  bit2->rows = height;
87  bit2->pitch = pitch;
88  bit2->pixel_mode = ft_pixel_mode_grays;
89  //bit2->pixel_mode = ft_pixel_mode_mono;
90  bit2->buffer = Mem_Alloc(pitch*height);
91  bit2->num_grays = 256;
92 
93  memset( bit2->buffer, 0, size );
94 
95  FT_Outline_Translate( &glyph->outline, -left, -bottom );
96 
97  FT_Outline_Get_Bitmap( ftLibrary, &glyph->outline, bit2 );
98 
99  glyphOut->height = height;
100  glyphOut->pitch = pitch;
101  glyphOut->top = (glyph->metrics.horiBearingY >> 6) + 1;
102  glyphOut->bottom = bottom;
103 
104  return bit2;
105  }
106  else {
107  common->Printf( "Non-outline fonts are not supported\n" );
108  }
109  return NULL;
110 }
111 
112 /*
113 ============
114 RE_ConstructGlyphInfo
115 ============
116 */
117 glyphInfo_t *RE_ConstructGlyphInfo( unsigned char *imageOut, int *xOut, int *yOut, int *maxHeight, FT_Face face, const unsigned char c, qboolean calcHeight ) {
118  int i;
119  static glyphInfo_t glyph;
120  unsigned char *src, *dst;
121  float scaled_width, scaled_height;
122  FT_Bitmap *bitmap = NULL;
123 
124  memset(&glyph, 0, sizeof(glyphInfo_t));
125  // make sure everything is here
126  if (face != NULL) {
127  FT_Load_Glyph(face, FT_Get_Char_Index( face, c), FT_LOAD_DEFAULT );
128  bitmap = R_RenderGlyph(face->glyph, &glyph);
129  if (bitmap) {
130  glyph.xSkip = (face->glyph->metrics.horiAdvance >> 6) + 1;
131  } else {
132  return &glyph;
133  }
134 
135  if (glyph.height > *maxHeight) {
136  *maxHeight = glyph.height;
137  }
138 
139  if (calcHeight) {
140  Mem_Free(bitmap->buffer);
141  Mem_Free(bitmap);
142  return &glyph;
143  }
144 
145 /*
146  // need to convert to power of 2 sizes so we do not get
147  // any scaling from the gl upload
148  for (scaled_width = 1 ; scaled_width < glyph.pitch ; scaled_width<<=1)
149  ;
150  for (scaled_height = 1 ; scaled_height < glyph.height ; scaled_height<<=1)
151  ;
152 */
153 
154  scaled_width = glyph.pitch;
155  scaled_height = glyph.height;
156 
157  // we need to make sure we fit
158  if (*xOut + scaled_width + 1 >= 255) {
159  if (*yOut + *maxHeight + 1 >= 255) {
160  *yOut = -1;
161  *xOut = -1;
162  Mem_Free(bitmap->buffer);
163  Mem_Free(bitmap);
164  return &glyph;
165  } else {
166  *xOut = 0;
167  *yOut += *maxHeight + 1;
168  }
169  } else if (*yOut + *maxHeight + 1 >= 255) {
170  *yOut = -1;
171  *xOut = -1;
172  Mem_Free(bitmap->buffer);
173  Mem_Free(bitmap);
174  return &glyph;
175  }
176 
177  src = bitmap->buffer;
178  dst = imageOut + (*yOut * 256) + *xOut;
179 
180  if (bitmap->pixel_mode == ft_pixel_mode_mono) {
181  for (i = 0; i < glyph.height; i++) {
182  int j;
183  unsigned char *_src = src;
184  unsigned char *_dst = dst;
185  unsigned char mask = 0x80;
186  unsigned char val = *_src;
187  for (j = 0; j < glyph.pitch; j++) {
188  if (mask == 0x80) {
189  val = *_src++;
190  }
191  if (val & mask) {
192  *_dst = 0xff;
193  }
194  mask >>= 1;
195 
196  if ( mask == 0 ) {
197  mask = 0x80;
198  }
199  _dst++;
200  }
201 
202  src += glyph.pitch;
203  dst += 256;
204 
205  }
206  } else {
207  for (i = 0; i < glyph.height; i++) {
208  memcpy( dst, src, glyph.pitch );
209  src += glyph.pitch;
210  dst += 256;
211  }
212  }
213 
214  // we now have an 8 bit per pixel grey scale bitmap
215  // that is width wide and pf->ftSize->metrics.y_ppem tall
216 
217  glyph.imageHeight = scaled_height;
218  glyph.imageWidth = scaled_width;
219  glyph.s = (float)*xOut / 256;
220  glyph.t = (float)*yOut / 256;
221  glyph.s2 = glyph.s + (float)scaled_width / 256;
222  glyph.t2 = glyph.t + (float)scaled_height / 256;
223 
224  *xOut += scaled_width + 1;
225  }
226 
227  Mem_Free(bitmap->buffer);
228  Mem_Free(bitmap);
229 
230  return &glyph;
231 }
232 
233 #endif
234 
235 static int fdOffset;
236 static byte *fdFile;
237 
238 /*
239 ============
240 readInt
241 ============
242 */
243 int readInt( void ) {
244  int i = fdFile[fdOffset]+(fdFile[fdOffset+1]<<8)+(fdFile[fdOffset+2]<<16)+(fdFile[fdOffset+3]<<24);
245  fdOffset += 4;
246  return i;
247 }
248 
249 typedef union {
250  byte fred[4];
251  float ffred;
252 } poor;
253 
254 /*
255 ============
256 readFloat
257 ============
258 */
259 float readFloat( void ) {
260  poor me;
261 #ifdef __ppc__
262  me.fred[0] = fdFile[fdOffset+3];
263  me.fred[1] = fdFile[fdOffset+2];
264  me.fred[2] = fdFile[fdOffset+1];
265  me.fred[3] = fdFile[fdOffset+0];
266 #else
267  me.fred[0] = fdFile[fdOffset+0];
268  me.fred[1] = fdFile[fdOffset+1];
269  me.fred[2] = fdFile[fdOffset+2];
270  me.fred[3] = fdFile[fdOffset+3];
271 #endif
272  fdOffset += 4;
273  return me.ffred;
274 }
275 
276 /*
277 ============
278 RegisterFont
279 
280 Loads 3 point sizes, 12, 24, and 48
281 ============
282 */
283 bool idRenderSystemLocal::RegisterFont( const char *fontName, fontInfoEx_t &font ) {
284 #ifdef BUILD_FREETYPE
285  FT_Face face;
286  int j, k, xOut, yOut, lastStart, imageNumber;
287  int scaledSize, newSize, maxHeight, left, satLevels;
288  unsigned char *out, *imageBuff;
289  glyphInfo_t *glyph;
290  idImage *image;
291  idMaterial *h;
292  float max;
293 #endif
294  void *faceData;
295  ID_TIME_T ftime;
296  int i, len, fontCount;
297  char name[1024];
298 
299  int pointSize = 12;
300 /*
301  if ( registeredFontCount >= MAX_FONTS ) {
302  common->Warning( "RegisterFont: Too many fonts registered already." );
303  return false;
304  }
305 
306  int pointSize = 12;
307  idStr::snPrintf( name, sizeof(name), "%s/fontImage_%i.dat", fontName, pointSize );
308  for ( i = 0; i < registeredFontCount; i++ ) {
309  if ( idStr::Icmp(name, registeredFont[i].fontInfoSmall.name) == 0 ) {
310  memcpy( &font, &registeredFont[i], sizeof( fontInfoEx_t ) );
311  return true;
312  }
313  }
314 */
315 
316  memset( &font, 0, sizeof( font ) );
317 
318  for ( fontCount = 0; fontCount < 3; fontCount++ ) {
319 
320  if ( fontCount == 0) {
321  pointSize = 12;
322  } else if ( fontCount == 1 ) {
323  pointSize = 24;
324  } else {
325  pointSize = 48;
326  }
327  // we also need to adjust the scale based on point size relative to 48 points as the ui scaling is based on a 48 point font
328  float glyphScale = 1.0f; // change the scale to be relative to 1 based on 72 dpi ( so dpi of 144 means a scale of .5 )
329  glyphScale *= 48.0f / pointSize;
330 
331  idStr::snPrintf( name, sizeof(name), "%s/fontImage_%i.dat", fontName, pointSize );
332 
333  fontInfo_t *outFont;
334  if ( fontCount == 0 ) {
335  outFont = &font.fontInfoSmall;
336  }
337  else if ( fontCount == 1 ) {
338  outFont = &font.fontInfoMedium;
339  }
340  else {
341  outFont = &font.fontInfoLarge;
342  }
343 
344  idStr::Copynz( outFont->name, name, sizeof( outFont->name ) );
345 
346  len = fileSystem->ReadFile( name, NULL, &ftime );
347  if ( len != sizeof( fontInfo_t ) ) {
348  common->Warning( "RegisterFont: couldn't find font: '%s'", name );
349  return false;
350  }
351 
352  fileSystem->ReadFile( name, &faceData, &ftime );
353  fdOffset = 0;
354  fdFile = reinterpret_cast<unsigned char*>(faceData);
355  for( i = 0; i < GLYPHS_PER_FONT; i++ ) {
356  outFont->glyphs[i].height = readInt();
357  outFont->glyphs[i].top = readInt();
358  outFont->glyphs[i].bottom = readInt();
359  outFont->glyphs[i].pitch = readInt();
360  outFont->glyphs[i].xSkip = readInt();
361  outFont->glyphs[i].imageWidth = readInt();
362  outFont->glyphs[i].imageHeight = readInt();
363  outFont->glyphs[i].s = readFloat();
364  outFont->glyphs[i].t = readFloat();
365  outFont->glyphs[i].s2 = readFloat();
366  outFont->glyphs[i].t2 = readFloat();
367  int junk /* font.glyphs[i].glyph */ = readInt();
368  //FIXME: the +6, -6 skips the embedded fonts/
369  memcpy( outFont->glyphs[i].shaderName, &fdFile[fdOffset + 6], 32 - 6 );
370  fdOffset += 32;
371  }
372  outFont->glyphScale = readFloat();
373 
374  int mw = 0;
375  int mh = 0;
376  for (i = GLYPH_START; i < GLYPH_END; i++) {
377  idStr::snPrintf(name, sizeof(name), "%s/%s", fontName, outFont->glyphs[i].shaderName);
378  outFont->glyphs[i].glyph = declManager->FindMaterial(name);
379  outFont->glyphs[i].glyph->SetSort( SS_GUI );
380  if (mh < outFont->glyphs[i].height) {
381  mh = outFont->glyphs[i].height;
382  }
383  if (mw < outFont->glyphs[i].xSkip) {
384  mw = outFont->glyphs[i].xSkip;
385  }
386  }
387  if (fontCount == 0) {
388  font.maxWidthSmall = mw;
389  font.maxHeightSmall = mh;
390  } else if (fontCount == 1) {
391  font.maxWidthMedium = mw;
392  font.maxHeightMedium = mh;
393  } else {
394  font.maxWidthLarge = mw;
395  font.maxHeightLarge = mh;
396  }
397  fileSystem->FreeFile( faceData );
398  }
399 
400  //memcpy( &registeredFont[registeredFontCount++], &font, sizeof( fontInfoEx_t ) );
401 
402  return true ;
403 
404 #ifndef BUILD_FREETYPE
405  common->Warning( "RegisterFont: couldn't load FreeType code %s", name );
406 #else
407 
408  if (ftLibrary == NULL) {
409  common->Warning( "RegisterFont: FreeType not initialized." );
410  return;
411  }
412 
413  len = fileSystem->ReadFile(fontName, &faceData, &ftime);
414  if ( len <= 0 ) {
415  common->Warning( "RegisterFont: Unable to read font file" );
416  return;
417  }
418 
419  // allocate on the stack first in case we fail
420  if ( FT_New_Memory_Face( ftLibrary, faceData, len, 0, &face ) ) {
421  common->Warning( "RegisterFont: FreeType2, unable to allocate new face." );
422  return;
423  }
424 
425 
426  if ( FT_Set_Char_Size( face, pointSize << 6, pointSize << 6, dpi, dpi) ) {
427  common->Warning( "RegisterFont: FreeType2, Unable to set face char size." );
428  return;
429  }
430 
431  // font = registeredFonts[registeredFontCount++];
432 
433  // make a 256x256 image buffer, once it is full, register it, clean it and keep going
434  // until all glyphs are rendered
435 
436  out = Mem_Alloc( 1024*1024 );
437  if ( out == NULL ) {
438  common->Warning( "RegisterFont: Mem_Alloc failure during output image creation." );
439  return;
440  }
441  memset( out, 0, 1024*1024 );
442 
443  maxHeight = 0;
444 
445  for (i = GLYPH_START; i < GLYPH_END; i++) {
446  glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qtrue);
447  }
448 
449  xOut = 0;
450  yOut = 0;
451  i = GLYPH_START;
452  lastStart = i;
453  imageNumber = 0;
454 
455  while ( i <= GLYPH_END ) {
456 
457  glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qfalse);
458 
459  if (xOut == -1 || yOut == -1 || i == GLYPH_END) {
460  // ran out of room
461  // we need to create an image from the bitmap, set all the handles in the glyphs to this point
462  //
463 
464  scaledSize = 256*256;
465  newSize = scaledSize * 4;
466  imageBuff = Mem_Alloc(newSize);
467  left = 0;
468  max = 0;
469  satLevels = 255;
470  for ( k = 0; k < (scaledSize) ; k++ ) {
471  if (max < out[k]) {
472  max = out[k];
473  }
474  }
475 
476  if (max > 0) {
477  max = 255/max;
478  }
479 
480  for ( k = 0; k < (scaledSize) ; k++ ) {
481  imageBuff[left++] = 255;
482  imageBuff[left++] = 255;
483  imageBuff[left++] = 255;
484  imageBuff[left++] = ((float)out[k] * max);
485  }
486 
487  idStr::snprintf( name, sizeof(name), "fonts/fontImage_%i_%i.tga", imageNumber++, pointSize );
488  if (r_saveFontData->integer) {
489  R_WriteTGA(name, imageBuff, 256, 256);
490  }
491 
492  //idStr::snprintf( name, sizeof(name), "fonts/fontImage_%i_%i", imageNumber++, pointSize );
493  image = R_CreateImage(name, imageBuff, 256, 256, qfalse, qfalse, GL_CLAMP);
494  h = RE_RegisterShaderFromImage(name, LIGHTMAP_2D, image, qfalse);
495  for (j = lastStart; j < i; j++) {
496  font.glyphs[j].glyph = h;
497  idStr::Copynz( font.glyphs[j].shaderName, name, sizeof( font.glyphs[j].shaderName ) );
498  }
499  lastStart = i;
500  memset( out, 0, 1024*1024 );
501  xOut = 0;
502  yOut = 0;
503  Mem_Free( imageBuff );
504  i++;
505  } else {
506  memcpy( &font.glyphs[i], glyph, sizeof( glyphInfo_t ) );
507  i++;
508  }
509  }
510 
511  registeredFont[registeredFontCount].glyphScale = glyphScale;
512  font.glyphScale = glyphScale;
513  memcpy( &registeredFont[registeredFontCount++], &font, sizeof( fontInfo_t ) );
514 
515  if ( r_saveFontData->integer ) {
516  fileSystem->WriteFile( va( "fonts/fontImage_%i.dat", pointSize), &font, sizeof( fontInfo_t ) );
517  }
518 
519  Mem_Free( out );
520 
521  fileSystem->FreeFile( faceData );
522 #endif
523  return true;
524 }
525 
526 /*
527 ============
528 R_InitFreeType
529 ============
530 */
531 void R_InitFreeType( void ) {
532 #ifdef BUILD_FREETYPE
533  if ( FT_Init_FreeType( &ftLibrary ) ) {
534  common->Printf( "R_InitFreeType: Unable to initialize FreeType.\n" );
535  }
536 #endif
537 // registeredFontCount = 0;
538 }
539 
540 /*
541 ============
542 R_DoneFreeType
543 ============
544 */
545 void R_DoneFreeType( void ) {
546 #ifdef BUILD_FREETYPE
547  if ( ftLibrary ) {
548  FT_Done_FreeType( ftLibrary );
549  ftLibrary = NULL;
550  }
551 #endif
552 // registeredFontCount = 0;
553 }
GLdouble GLdouble bottom
Definition: qgl.h:273
static int snPrintf(char *dest, int size, const char *fmt,...) id_attribute((format(printf
Definition: Str.cpp:1465
Definition: Image.h:146
const idMaterial * glyph
Definition: RenderSystem.h:121
glyphInfo_t glyphs[GLYPHS_PER_FONT]
Definition: RenderSystem.h:126
GLenum GLint GLuint mask
Definition: glext.h:5864
fontInfo_t fontInfoLarge
Definition: RenderSystem.h:134
virtual int ReadFile(const char *relativePath, void **buffer, ID_TIME_T *timestamp=NULL)=0
float glyphScale
Definition: RenderSystem.h:127
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
case const float
Definition: Callbacks.cpp:62
GLenum GLsizei GLenum GLenum const GLvoid * image
Definition: glext.h:2855
float readFloat(void)
Definition: tr_font.cpp:259
virtual const idMaterial * FindMaterial(const char *name, bool makeDefault=true)=0
void R_DoneFreeType(void)
Definition: tr_font.cpp:545
GLuint src
Definition: glext.h:5390
GLenum GLsizei len
Definition: glext.h:3472
GLdouble right
Definition: qgl.h:273
int i
Definition: process.py:33
virtual void FreeFile(void *buffer)=0
fontInfo_t fontInfoMedium
Definition: RenderSystem.h:133
virtual int WriteFile(const char *relativePath, const void *buffer, int size, const char *basePath="fs_savepath")=0
fontInfo_t fontInfoSmall
Definition: RenderSystem.h:132
GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte * bitmap
Definition: qgl.h:183
const int GLYPH_END
Definition: RenderSystem.h:104
GLuint dst
Definition: glext.h:5285
const GLubyte * c
Definition: glext.h:4677
virtual bool RegisterFont(const char *fontName, fontInfoEx_t &font)
Definition: tr_font.cpp:283
char name[64]
Definition: RenderSystem.h:128
idCommon * common
Definition: Common.cpp:206
#define NULL
Definition: Lib.h:88
byte fred[4]
Definition: tr_font.cpp:250
static void Copynz(char *dest, const char *src, int destsize)
Definition: Str.cpp:1376
void R_WriteTGA(const char *filename, const byte *data, int width, int height, bool flipVertical=false)
Definition: Image_files.cpp:85
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
GLenum GLsizei width
Definition: glext.h:2846
virtual void Printf(const char *fmt,...) id_attribute((format(printf
char shaderName[32]
Definition: RenderSystem.h:122
GLenum GLsizei GLsizei height
Definition: glext.h:2856
GLdouble GLdouble GLdouble top
Definition: qgl.h:273
idDeclManager * declManager
void R_InitFreeType(void)
Definition: tr_font.cpp:531
unsigned char byte
Definition: Lib.h:75
#define snprintf
Definition: Str.h:70
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
const int GLYPHS_PER_FONT
Definition: RenderSystem.h:107
void SetSort(float s) const
Definition: Material.h:513
void * Mem_Alloc(const int size)
Definition: Heap.cpp:1067
GLint j
Definition: qgl.h:264
char * va(const char *fmt,...)
Definition: Str.cpp:1568
#define max(x, y)
Definition: os.h:70
virtual void virtual void Warning(const char *fmt,...) id_attribute((format(printf
int readInt(void)
Definition: tr_font.cpp:243
float ffred
Definition: tr_font.cpp:251
const int GLYPH_START
Definition: RenderSystem.h:103