]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/renderer/tr_font.cpp
Use the same OpenAL headers on all platforms.
[icculus/iodoom3.git] / neo / renderer / tr_font.cpp
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 }