2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
30 #include "../idlib/precompiled.h"
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"
42 #define _FLOOR(x) ((x) & -64)
43 #define _CEIL(x) (((x)+63) & -64)
44 #define _TRUNC(x) ((x) >> 6)
46 FT_Library ftLibrary = NULL;
57 void R_GetGlyphInfo(FT_GlyphSlot glyph, int *left, int *right, int *width, int *top, int *bottom, int *height, int *pitch) {
59 *left = _FLOOR( glyph->metrics.horiBearingX );
60 *right = _CEIL( glyph->metrics.horiBearingX + glyph->metrics.width );
61 *width = _TRUNC(*right - *left);
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 );
74 FT_Bitmap *R_RenderGlyph(FT_GlyphSlot glyph, glyphInfo_t* glyphOut) {
76 int left, right, width, top, bottom, height, pitch, size;
78 R_GetGlyphInfo(glyph, &left, &right, &width, &top, &bottom, &height, &pitch);
80 if ( glyph->format == ft_glyph_format_outline ) {
83 bit2 = Mem_Alloc(sizeof(FT_Bitmap));
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;
93 memset( bit2->buffer, 0, size );
95 FT_Outline_Translate( &glyph->outline, -left, -bottom );
97 FT_Outline_Get_Bitmap( ftLibrary, &glyph->outline, bit2 );
99 glyphOut->height = height;
100 glyphOut->pitch = pitch;
101 glyphOut->top = (glyph->metrics.horiBearingY >> 6) + 1;
102 glyphOut->bottom = bottom;
107 common->Printf( "Non-outline fonts are not supported\n" );
114 RE_ConstructGlyphInfo
117 glyphInfo_t *RE_ConstructGlyphInfo( unsigned char *imageOut, int *xOut, int *yOut, int *maxHeight, FT_Face face, const unsigned char c, qboolean calcHeight ) {
119 static glyphInfo_t glyph;
120 unsigned char *src, *dst;
121 float scaled_width, scaled_height;
122 FT_Bitmap *bitmap = NULL;
124 memset(&glyph, 0, sizeof(glyphInfo_t));
125 // make sure everything is here
127 FT_Load_Glyph(face, FT_Get_Char_Index( face, c), FT_LOAD_DEFAULT );
128 bitmap = R_RenderGlyph(face->glyph, &glyph);
130 glyph.xSkip = (face->glyph->metrics.horiAdvance >> 6) + 1;
135 if (glyph.height > *maxHeight) {
136 *maxHeight = glyph.height;
140 Mem_Free(bitmap->buffer);
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)
150 for (scaled_height = 1 ; scaled_height < glyph.height ; scaled_height<<=1)
154 scaled_width = glyph.pitch;
155 scaled_height = glyph.height;
157 // we need to make sure we fit
158 if (*xOut + scaled_width + 1 >= 255) {
159 if (*yOut + *maxHeight + 1 >= 255) {
162 Mem_Free(bitmap->buffer);
167 *yOut += *maxHeight + 1;
169 } else if (*yOut + *maxHeight + 1 >= 255) {
172 Mem_Free(bitmap->buffer);
177 src = bitmap->buffer;
178 dst = imageOut + (*yOut * 256) + *xOut;
180 if (bitmap->pixel_mode == ft_pixel_mode_mono) {
181 for (i = 0; i < glyph.height; i++) {
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++) {
207 for (i = 0; i < glyph.height; i++) {
208 memcpy( dst, src, glyph.pitch );
214 // we now have an 8 bit per pixel grey scale bitmap
215 // that is width wide and pf->ftSize->metrics.y_ppem tall
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;
224 *xOut += scaled_width + 1;
227 Mem_Free(bitmap->buffer);
243 int readInt( void ) {
244 int i = fdFile[fdOffset]+(fdFile[fdOffset+1]<<8)+(fdFile[fdOffset+2]<<16)+(fdFile[fdOffset+3]<<24);
259 float readFloat( void ) {
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];
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];
280 Loads 3 point sizes, 12, 24, and 48
283 bool idRenderSystemLocal::RegisterFont( const char *fontName, fontInfoEx_t &font ) {
284 #ifdef BUILD_FREETYPE
286 int j, k, xOut, yOut, lastStart, imageNumber;
287 int scaledSize, newSize, maxHeight, left, satLevels;
288 unsigned char *out, *imageBuff;
296 int i, len, fontCount;
301 if ( registeredFontCount >= MAX_FONTS ) {
302 common->Warning( "RegisterFont: Too many fonts registered already." );
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, ®isteredFont[i], sizeof( fontInfoEx_t ) );
316 memset( &font, 0, sizeof( font ) );
318 for ( fontCount = 0; fontCount < 3; fontCount++ ) {
320 if ( fontCount == 0) {
322 } else if ( fontCount == 1 ) {
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;
331 idStr::snPrintf( name, sizeof(name), "%s/fontImage_%i.dat", fontName, pointSize );
334 if ( fontCount == 0 ) {
335 outFont = &font.fontInfoSmall;
337 else if ( fontCount == 1 ) {
338 outFont = &font.fontInfoMedium;
341 outFont = &font.fontInfoLarge;
344 idStr::Copynz( outFont->name, name, sizeof( outFont->name ) );
346 len = fileSystem->ReadFile( name, NULL, &ftime );
347 if ( len != sizeof( fontInfo_t ) ) {
348 common->Warning( "RegisterFont: couldn't find font: '%s'", name );
352 fileSystem->ReadFile( name, &faceData, &ftime );
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 );
372 outFont->glyphScale = readFloat();
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;
383 if (mw < outFont->glyphs[i].xSkip) {
384 mw = outFont->glyphs[i].xSkip;
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;
394 font.maxWidthLarge = mw;
395 font.maxHeightLarge = mh;
397 fileSystem->FreeFile( faceData );
400 //memcpy( ®isteredFont[registeredFontCount++], &font, sizeof( fontInfoEx_t ) );
404 #ifndef BUILD_FREETYPE
405 common->Warning( "RegisterFont: couldn't load FreeType code %s", name );
408 if (ftLibrary == NULL) {
409 common->Warning( "RegisterFont: FreeType not initialized." );
413 len = fileSystem->ReadFile(fontName, &faceData, &ftime);
415 common->Warning( "RegisterFont: Unable to read font file" );
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." );
426 if ( FT_Set_Char_Size( face, pointSize << 6, pointSize << 6, dpi, dpi) ) {
427 common->Warning( "RegisterFont: FreeType2, Unable to set face char size." );
431 // font = registeredFonts[registeredFontCount++];
433 // make a 256x256 image buffer, once it is full, register it, clean it and keep going
434 // until all glyphs are rendered
436 out = Mem_Alloc( 1024*1024 );
438 common->Warning( "RegisterFont: Mem_Alloc failure during output image creation." );
441 memset( out, 0, 1024*1024 );
445 for (i = GLYPH_START; i < GLYPH_END; i++) {
446 glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qtrue);
455 while ( i <= GLYPH_END ) {
457 glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qfalse);
459 if (xOut == -1 || yOut == -1 || i == GLYPH_END) {
461 // we need to create an image from the bitmap, set all the handles in the glyphs to this point
464 scaledSize = 256*256;
465 newSize = scaledSize * 4;
466 imageBuff = Mem_Alloc(newSize);
470 for ( k = 0; k < (scaledSize) ; k++ ) {
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);
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);
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 ) );
500 memset( out, 0, 1024*1024 );
503 Mem_Free( imageBuff );
506 memcpy( &font.glyphs[i], glyph, sizeof( glyphInfo_t ) );
511 registeredFont[registeredFontCount].glyphScale = glyphScale;
512 font.glyphScale = glyphScale;
513 memcpy( ®isteredFont[registeredFontCount++], &font, sizeof( fontInfo_t ) );
515 if ( r_saveFontData->integer ) {
516 fileSystem->WriteFile( va( "fonts/fontImage_%i.dat", pointSize), &font, sizeof( fontInfo_t ) );
521 fileSystem->FreeFile( faceData );
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" );
537 // registeredFontCount = 0;
545 void R_DoneFreeType( void ) {
546 #ifdef BUILD_FREETYPE
548 FT_Done_FreeType( ftLibrary );
552 // registeredFontCount = 0;