diff --git a/reaction/code/renderergl2/tr_font.c b/reaction/code/renderergl2/tr_font.c index bdb4251b..5a3673a4 100644 --- a/reaction/code/renderergl2/tr_font.c +++ b/reaction/code/renderergl2/tr_font.c @@ -58,11 +58,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // 4. Exit the game and there will be three dat files and at least three tga files. The // tga's are in 256x256 pages so if it takes three images to render a 24 point font you // will end up with fontImage_0_24.tga through fontImage_2_24.tga -// 5. You will need to flip the tga's in Photoshop as the tga output code writes them upside -// down. -// 6. In future runs of the game, the system looks for these images and data files when a s +// 5. In future runs of the game, the system looks for these images and data files when a s // specific point sized font is rendered and loads them for use. -// 7. Because of the original beta nature of the FreeType code you will probably want to hand +// 6. Because of the original beta nature of the FreeType code you will probably want to hand // touch the font bitmaps. // // Currently a define in the project turns on or off the FreeType code which is currently @@ -75,11 +73,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifdef BUILD_FREETYPE #include -#include -#include -#include -#include -#include +#include FT_ERRORS_H +#include FT_SYSTEM_H +#include FT_IMAGE_H +#include FT_FREETYPE_H +#include FT_OUTLINE_H #define _FLOOR(x) ((x) & -64) #define _CEIL(x) (((x)+63) & -64) @@ -94,62 +92,62 @@ static fontInfo_t registeredFont[MAX_FONTS]; #ifdef BUILD_FREETYPE void R_GetGlyphInfo(FT_GlyphSlot glyph, int *left, int *right, int *width, int *top, int *bottom, int *height, int *pitch) { + *left = _FLOOR( glyph->metrics.horiBearingX ); + *right = _CEIL( glyph->metrics.horiBearingX + glyph->metrics.width ); + *width = _TRUNC(*right - *left); - *left = _FLOOR( glyph->metrics.horiBearingX ); - *right = _CEIL( glyph->metrics.horiBearingX + glyph->metrics.width ); - *width = _TRUNC(*right - *left); - - *top = _CEIL( glyph->metrics.horiBearingY ); - *bottom = _FLOOR( glyph->metrics.horiBearingY - glyph->metrics.height ); - *height = _TRUNC( *top - *bottom ); - *pitch = ( qtrue ? (*width+3) & -4 : (*width+7) >> 3 ); + *top = _CEIL( glyph->metrics.horiBearingY ); + *bottom = _FLOOR( glyph->metrics.horiBearingY - glyph->metrics.height ); + *height = _TRUNC( *top - *bottom ); + *pitch = ( qtrue ? (*width+3) & -4 : (*width+7) >> 3 ); } FT_Bitmap *R_RenderGlyph(FT_GlyphSlot glyph, glyphInfo_t* glyphOut) { + FT_Bitmap *bit2; + int left, right, width, top, bottom, height, pitch, size; - FT_Bitmap *bit2; - int left, right, width, top, bottom, height, pitch, size; + R_GetGlyphInfo(glyph, &left, &right, &width, &top, &bottom, &height, &pitch); - R_GetGlyphInfo(glyph, &left, &right, &width, &top, &bottom, &height, &pitch); + if ( glyph->format == ft_glyph_format_outline ) { + size = pitch*height; - if ( glyph->format == ft_glyph_format_outline ) { - size = pitch*height; + bit2 = ri.Malloc(sizeof(FT_Bitmap)); - bit2 = Z_Malloc(sizeof(FT_Bitmap)); + bit2->width = width; + bit2->rows = height; + bit2->pitch = pitch; + bit2->pixel_mode = ft_pixel_mode_grays; + //bit2->pixel_mode = ft_pixel_mode_mono; + bit2->buffer = ri.Malloc(pitch*height); + bit2->num_grays = 256; - bit2->width = width; - bit2->rows = height; - bit2->pitch = pitch; - bit2->pixel_mode = ft_pixel_mode_grays; - //bit2->pixel_mode = ft_pixel_mode_mono; - bit2->buffer = Z_Malloc(pitch*height); - bit2->num_grays = 256; + Com_Memset( bit2->buffer, 0, size ); - Com_Memset( bit2->buffer, 0, size ); + FT_Outline_Translate( &glyph->outline, -left, -bottom ); - FT_Outline_Translate( &glyph->outline, -left, -bottom ); + FT_Outline_Get_Bitmap( ftLibrary, &glyph->outline, bit2 ); - FT_Outline_Get_Bitmap( ftLibrary, &glyph->outline, bit2 ); + glyphOut->height = height; + glyphOut->pitch = pitch; + glyphOut->top = (glyph->metrics.horiBearingY >> 6) + 1; + glyphOut->bottom = bottom; - glyphOut->height = height; - glyphOut->pitch = pitch; - glyphOut->top = (glyph->metrics.horiBearingY >> 6) + 1; - glyphOut->bottom = bottom; - - return bit2; - } - else { - ri.Printf(PRINT_ALL, "Non-outline fonts are not supported\n"); - } - return NULL; + return bit2; + } else { + ri.Printf(PRINT_ALL, "Non-outline fonts are not supported\n"); + } + return NULL; } void WriteTGA (char *filename, byte *data, int width, int height) { - byte *buffer; - int i, c; + byte *buffer; + int i, c; + int row; + unsigned char *flip; + unsigned char *src, *dst; - buffer = Z_Malloc(width*height*4 + 18); + buffer = ri.Malloc(width*height*4 + 18); Com_Memset (buffer, 0, 18); buffer[2] = 2; // uncompressed type buffer[12] = width&255; @@ -168,78 +166,85 @@ void WriteTGA (char *filename, byte *data, int width, int height) { buffer[i+3] = data[i-18+3]; // alpha } + // flip upside down + flip = (unsigned char *)ri.Malloc(width*4); + for(row = 0; row < height/2; row++) + { + src = buffer + 18 + row * 4 * width; + dst = buffer + 18 + (height - row - 1) * 4 * width; + + Com_Memcpy(flip, src, width*4); + Com_Memcpy(src, dst, width*4); + Com_Memcpy(dst, flip, width*4); + } + ri.Free(flip); + ri.FS_WriteFile(filename, buffer, c); //f = fopen (filename, "wb"); //fwrite (buffer, 1, c, f); //fclose (f); - Z_Free (buffer); + ri.Free (buffer); } static glyphInfo_t *RE_ConstructGlyphInfo(unsigned char *imageOut, int *xOut, int *yOut, int *maxHeight, FT_Face face, const unsigned char c, qboolean calcHeight) { - int i; - static glyphInfo_t glyph; - unsigned char *src, *dst; - float scaled_width, scaled_height; - FT_Bitmap *bitmap = NULL; + int i; + static glyphInfo_t glyph; + unsigned char *src, *dst; + float scaled_width, scaled_height; + FT_Bitmap *bitmap = NULL; - Com_Memset(&glyph, 0, sizeof(glyphInfo_t)); - // make sure everything is here - if (face != NULL) { - FT_Load_Glyph(face, FT_Get_Char_Index( face, c), FT_LOAD_DEFAULT ); - bitmap = R_RenderGlyph(face->glyph, &glyph); - if (bitmap) { - glyph.xSkip = (face->glyph->metrics.horiAdvance >> 6) + 1; - } else { - return &glyph; - } + Com_Memset(&glyph, 0, sizeof(glyphInfo_t)); + // make sure everything is here + if (face != NULL) { + FT_Load_Glyph(face, FT_Get_Char_Index( face, c), FT_LOAD_DEFAULT ); + bitmap = R_RenderGlyph(face->glyph, &glyph); + if (bitmap) { + glyph.xSkip = (face->glyph->metrics.horiAdvance >> 6) + 1; + } else { + return &glyph; + } - if (glyph.height > *maxHeight) { - *maxHeight = glyph.height; - } + if (glyph.height > *maxHeight) { + *maxHeight = glyph.height; + } - if (calcHeight) { - Z_Free(bitmap->buffer); - Z_Free(bitmap); - return &glyph; - } + if (calcHeight) { + ri.Free(bitmap->buffer); + ri.Free(bitmap); + return &glyph; + } /* - // need to convert to power of 2 sizes so we do not get - // any scaling from the gl upload - for (scaled_width = 1 ; scaled_width < glyph.pitch ; scaled_width<<=1) - ; - for (scaled_height = 1 ; scaled_height < glyph.height ; scaled_height<<=1) - ; + // need to convert to power of 2 sizes so we do not get + // any scaling from the gl upload + for (scaled_width = 1 ; scaled_width < glyph.pitch ; scaled_width<<=1) + ; + for (scaled_height = 1 ; scaled_height < glyph.height ; scaled_height<<=1) + ; */ - scaled_width = glyph.pitch; - scaled_height = glyph.height; + scaled_width = glyph.pitch; + scaled_height = glyph.height; - // we need to make sure we fit - if (*xOut + scaled_width + 1 >= 255) { - if (*yOut + *maxHeight + 1 >= 255) { - *yOut = -1; - *xOut = -1; - Z_Free(bitmap->buffer); - Z_Free(bitmap); - return &glyph; - } else { - *xOut = 0; - *yOut += *maxHeight + 1; - } - } else if (*yOut + *maxHeight + 1 >= 255) { - *yOut = -1; - *xOut = -1; - Z_Free(bitmap->buffer); - Z_Free(bitmap); - return &glyph; - } + // we need to make sure we fit + if (*xOut + scaled_width + 1 >= 255) { + *xOut = 0; + *yOut += *maxHeight + 1; + } + + if (*yOut + *maxHeight + 1 >= 255) { + *yOut = -1; + *xOut = -1; + ri.Free(bitmap->buffer); + ri.Free(bitmap); + return &glyph; + } - src = bitmap->buffer; - dst = imageOut + (*yOut * 256) + *xOut; + src = bitmap->buffer; + dst = imageOut + (*yOut * 256) + *xOut; if (bitmap->pixel_mode == ft_pixel_mode_mono) { for (i = 0; i < glyph.height; i++) { @@ -256,7 +261,7 @@ static glyphInfo_t *RE_ConstructGlyphInfo(unsigned char *imageOut, int *xOut, in *_dst = 0xff; } mask >>= 1; - + if ( mask == 0 ) { mask = 0x80; } @@ -265,33 +270,32 @@ static glyphInfo_t *RE_ConstructGlyphInfo(unsigned char *imageOut, int *xOut, in src += glyph.pitch; dst += 256; - } } else { - for (i = 0; i < glyph.height; i++) { - Com_Memcpy(dst, src, glyph.pitch); - src += glyph.pitch; + for (i = 0; i < glyph.height; i++) { + Com_Memcpy(dst, src, glyph.pitch); + src += glyph.pitch; dst += 256; - } + } } - // we now have an 8 bit per pixel grey scale bitmap - // that is width wide and pf->ftSize->metrics.y_ppem tall + // we now have an 8 bit per pixel grey scale bitmap + // that is width wide and pf->ftSize->metrics.y_ppem tall - glyph.imageHeight = scaled_height; - glyph.imageWidth = scaled_width; - glyph.s = (float)*xOut / 256; - glyph.t = (float)*yOut / 256; - glyph.s2 = glyph.s + (float)scaled_width / 256; - glyph.t2 = glyph.t + (float)scaled_height / 256; + glyph.imageHeight = scaled_height; + glyph.imageWidth = scaled_width; + glyph.s = (float)*xOut / 256; + glyph.t = (float)*yOut / 256; + glyph.s2 = glyph.s + (float)scaled_width / 256; + glyph.t2 = glyph.t + (float)scaled_height / 256; - *xOut += scaled_width + 1; - } + *xOut += scaled_width + 1; + } - Z_Free(bitmap->buffer); - Z_Free(bitmap); + ri.Free(bitmap->buffer); + ri.Free(bitmap); - return &glyph; + return &glyph; } #endif @@ -328,26 +332,26 @@ float readFloat( void ) { void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) { #ifdef BUILD_FREETYPE - FT_Face face; - int j, k, xOut, yOut, lastStart, imageNumber; - int scaledSize, newSize, maxHeight, left, satLevels; - unsigned char *out, *imageBuff; - glyphInfo_t *glyph; - image_t *image; - qhandle_t h; + FT_Face face; + int j, k, xOut, yOut, lastStart, imageNumber; + int scaledSize, newSize, maxHeight, left; + unsigned char *out, *imageBuff; + glyphInfo_t *glyph; + image_t *image; + qhandle_t h; float max; #endif - void *faceData; + void *faceData; int i, len; - char name[1024]; + char name[1024]; float dpi = 72; // float glyphScale = 72.0f / dpi; // change the scale to be relative to 1 based on 72 dpi ( so dpi of 144 means a scale of .5 ) - if (!fontName) { - ri.Printf(PRINT_ALL, "RE_RegisterFont: called with empty name\n"); - return; - } + if (!fontName) { + ri.Printf(PRINT_ALL, "RE_RegisterFont: called with empty name\n"); + return; + } if (pointSize <= 0) { pointSize = 12; @@ -358,10 +362,10 @@ void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) { // make sure the render thread is stopped R_SyncRenderThread(); - if (registeredFontCount >= MAX_FONTS) { - ri.Printf(PRINT_ALL, "RE_RegisterFont: Too many fonts registered already.\n"); - return; - } + if (registeredFontCount >= MAX_FONTS) { + ri.Printf(PRINT_WARNING, "RE_RegisterFont: Too many fonts registered already.\n"); + return; + } Com_sprintf(name, sizeof(name), "fonts/fontImage_%i.dat",pointSize); for (i = 0; i < registeredFontCount; i++) { @@ -389,8 +393,8 @@ void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) { font->glyphs[i].s2 = readFloat(); font->glyphs[i].t2 = readFloat(); font->glyphs[i].glyph = readInt(); - Com_Memcpy(font->glyphs[i].shaderName, &fdFile[fdOffset], 32); - fdOffset += 32; + Q_strncpyz(font->glyphs[i].shaderName, (const char *)&fdFile[fdOffset], sizeof(font->glyphs[i].shaderName)); + fdOffset += sizeof(font->glyphs[i].shaderName); } font->glyphScale = readFloat(); Com_Memcpy(font->name, &fdFile[fdOffset], MAX_QPATH); @@ -400,128 +404,127 @@ void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) { for (i = GLYPH_START; i < GLYPH_END; i++) { font->glyphs[i].glyph = RE_RegisterShaderNoMip(font->glyphs[i].shaderName); } - Com_Memcpy(®isteredFont[registeredFontCount++], font, sizeof(fontInfo_t)); + Com_Memcpy(®isteredFont[registeredFontCount++], font, sizeof(fontInfo_t)); return; } #ifndef BUILD_FREETYPE - ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType code not available\n"); + ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType code not available\n"); #else - if (ftLibrary == NULL) { - ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType not initialized.\n"); - return; - } + if (ftLibrary == NULL) { + ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType not initialized.\n"); + return; + } - len = ri.FS_ReadFile(fontName, &faceData); - if (len <= 0) { - ri.Printf(PRINT_ALL, "RE_RegisterFont: Unable to read font file\n"); - return; - } + len = ri.FS_ReadFile(fontName, &faceData); + if (len <= 0) { + ri.Printf(PRINT_WARNING, "RE_RegisterFont: Unable to read font file '%s'\n", fontName); + return; + } - // allocate on the stack first in case we fail - if (FT_New_Memory_Face( ftLibrary, faceData, len, 0, &face )) { - ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType2, unable to allocate new face.\n"); - return; - } + // allocate on the stack first in case we fail + if (FT_New_Memory_Face( ftLibrary, faceData, len, 0, &face )) { + ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType, unable to allocate new face.\n"); + return; + } - if (FT_Set_Char_Size( face, pointSize << 6, pointSize << 6, dpi, dpi)) { - ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType2, Unable to set face char size.\n"); - return; - } + if (FT_Set_Char_Size( face, pointSize << 6, pointSize << 6, dpi, dpi)) { + ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType, unable to set face char size.\n"); + return; + } - //*font = ®isteredFonts[registeredFontCount++]; + //*font = ®isteredFonts[registeredFontCount++]; - // make a 256x256 image buffer, once it is full, register it, clean it and keep going - // until all glyphs are rendered + // make a 256x256 image buffer, once it is full, register it, clean it and keep going + // until all glyphs are rendered - out = Z_Malloc(1024*1024); - if (out == NULL) { - ri.Printf(PRINT_ALL, "RE_RegisterFont: Z_Malloc failure during output image creation.\n"); - return; - } - Com_Memset(out, 0, 1024*1024); + out = ri.Malloc(1024*1024); + if (out == NULL) { + ri.Printf(PRINT_WARNING, "RE_RegisterFont: ri.Malloc failure during output image creation.\n"); + return; + } + Com_Memset(out, 0, 1024*1024); - maxHeight = 0; + maxHeight = 0; - for (i = GLYPH_START; i < GLYPH_END; i++) { - glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qtrue); - } + for (i = GLYPH_START; i < GLYPH_END; i++) { + glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qtrue); + } - xOut = 0; - yOut = 0; - i = GLYPH_START; - lastStart = i; - imageNumber = 0; + xOut = 0; + yOut = 0; + i = GLYPH_START; + lastStart = i; + imageNumber = 0; - while ( i <= GLYPH_END ) { + while ( i <= GLYPH_END ) { - glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qfalse); + glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qfalse); - if (xOut == -1 || yOut == -1 || i == GLYPH_END) { - // ran out of room - // we need to create an image from the bitmap, set all the handles in the glyphs to this point - // + if (xOut == -1 || yOut == -1 || i == GLYPH_END) { + // ran out of room + // we need to create an image from the bitmap, set all the handles in the glyphs to this point + // - scaledSize = 256*256; - newSize = scaledSize * 4; - imageBuff = Z_Malloc(newSize); - left = 0; - max = 0; - satLevels = 255; - for ( k = 0; k < (scaledSize) ; k++ ) { - if (max < out[k]) { - max = out[k]; - } - } + scaledSize = 256*256; + newSize = scaledSize * 4; + imageBuff = ri.Malloc(newSize); + left = 0; + max = 0; + for ( k = 0; k < (scaledSize) ; k++ ) { + if (max < out[k]) { + max = out[k]; + } + } if (max > 0) { max = 255/max; } - for ( k = 0; k < (scaledSize) ; k++ ) { - imageBuff[left++] = 255; - imageBuff[left++] = 255; - imageBuff[left++] = 255; + for ( k = 0; k < (scaledSize) ; k++ ) { + imageBuff[left++] = 255; + imageBuff[left++] = 255; + imageBuff[left++] = 255; - imageBuff[left++] = ((float)out[k] * max); - } + imageBuff[left++] = ((float)out[k] * max); + } Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i.tga", imageNumber++, pointSize); if (r_saveFontData->integer) { - WriteTGA(name, imageBuff, 256, 256); + WriteTGA(name, imageBuff, 256, 256); } - //Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i", imageNumber++, pointSize); - image = R_CreateImage(name, imageBuff, 256, 256, qfalse, qfalse, GL_CLAMP_TO_EDGE); - h = RE_RegisterShaderFromImage(name, LIGHTMAP_2D, image, qfalse); - for (j = lastStart; j < i; j++) { - font->glyphs[j].glyph = h; + //Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i", imageNumber++, pointSize); + image = R_CreateImage(name, imageBuff, 256, 256, qfalse, qfalse, GL_CLAMP_TO_EDGE); + h = RE_RegisterShaderFromImage(name, LIGHTMAP_2D, image, qfalse); + for (j = lastStart; j < i; j++) { + font->glyphs[j].glyph = h; Q_strncpyz(font->glyphs[j].shaderName, name, sizeof(font->glyphs[j].shaderName)); - } - lastStart = i; - Com_Memset(out, 0, 1024*1024); - xOut = 0; - yOut = 0; - Z_Free(imageBuff); + } + lastStart = i; + Com_Memset(out, 0, 1024*1024); + xOut = 0; + yOut = 0; + ri.Free(imageBuff); i++; - } else { - Com_Memcpy(&font->glyphs[i], glyph, sizeof(glyphInfo_t)); - i++; - } - } + } else { + Com_Memcpy(&font->glyphs[i], glyph, sizeof(glyphInfo_t)); + i++; + } + } registeredFont[registeredFontCount].glyphScale = glyphScale; font->glyphScale = glyphScale; - Com_Memcpy(®isteredFont[registeredFontCount++], font, sizeof(fontInfo_t)); + Com_Memcpy(®isteredFont[registeredFontCount++], font, sizeof(fontInfo_t)); - if (r_saveFontData->integer) { + if (r_saveFontData->integer) { ri.FS_WriteFile(va("fonts/fontImage_%i.dat", pointSize), font, sizeof(fontInfo_t)); } - Z_Free(out); - - ri.FS_FreeFile(faceData); + ri.Free(out); + + ri.FS_FreeFile(faceData); #endif } @@ -529,20 +532,20 @@ void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) { void R_InitFreeType(void) { #ifdef BUILD_FREETYPE - if (FT_Init_FreeType( &ftLibrary )) { - ri.Printf(PRINT_ALL, "R_InitFreeType: Unable to initialize FreeType.\n"); - } + if (FT_Init_FreeType( &ftLibrary )) { + ri.Printf(PRINT_WARNING, "R_InitFreeType: Unable to initialize FreeType.\n"); + } #endif - registeredFontCount = 0; + registeredFontCount = 0; } void R_DoneFreeType(void) { #ifdef BUILD_FREETYPE - if (ftLibrary) { - FT_Done_FreeType( ftLibrary ); - ftLibrary = NULL; - } + if (ftLibrary) { + FT_Done_FreeType( ftLibrary ); + ftLibrary = NULL; + } #endif registeredFontCount = 0; }