If that fails, could you perhaps attach some sample renderings in png format?
In order to try and factor out any effect of the GL side of things, I wrote a small stand-alone windows app which just loads a font, renders a single glyph, and then writes out the rendered bitmap in the glyph slot to a .png and .txt file. So there's nothing here but calling FreeType and then storing the resultant gray scale bitmap.
At first I didn't see a huge difference, but this was before changing the flags Werner suggested. I changed those (to ensure the byte code interpreter is enabled) and rebuilt this sample and it does look a little different. The text is brighter, so maybe there's a darkening happening when rendering to GL.
The FreeTypeGL rendering code is shown below. Its storing the gray scale image in a texture which gets treated as the alpha channel to render a solid rectangle. Since I'm doing 2D rendering with GL, there should be a 1-to-1 between the rendered pixels and the texture pixels so I don't believe any texture filtering should be ocurring.
*>>> setup the texture for the glyph
*
err = FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL);
FT_Bitmap bitmap = glyph->bitmap;
destWidth = bitmap.width;
destHeight = bitmap.rows;
if(destWidth && destHeight)
{
glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, glTextureID);
glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, destWidth,
destHeight, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.buffer);
glPopClientAttrib();
}
// 0
// +----+
// | |
// | |
// | |
// +----+
// 1
uv[0].X(static_cast<float>(xOffset) / static_cast<float>(width));
uv[0].Y(static_cast<float>(yOffset) / static_cast<float>(height));
uv[1].X(static_cast<float>(xOffset + destWidth) /
static_cast<float>(width));
uv[1].Y(static_cast<float>(yOffset + destHeight) /
static_cast<float>(height));
corner = FTPoint(glyph->bitmap_left, glyph->bitmap_top);
*>>> render the glyph texture
*
float dx, dy;
if(activeTextureID != glTextureID)
{
glBindTexture(GL_TEXTURE_2D, (GLuint)glTextureID);
activeTextureID = glTextureID;
}
dx = floor(pen.Xf() + corner.Xf());
dy = floor(pen.Yf() + corner.Yf());
glBegin(GL_QUADS);
glTexCoord2f(uv[0].Xf(), uv[0].Yf());
glVertex2f(dx, dy);
glTexCoord2f(uv[0].Xf(), uv[1].Yf());
glVertex2f(dx, dy - destHeight);
glTexCoord2f(uv[1].Xf(), uv[1].Yf());
glVertex2f(dx + destWidth, dy - destHeight);
glTexCoord2f(uv[1].Xf(), uv[0].Yf());
glVertex2f(dx + destWidth, dy);
glEnd();
return advance;
<<attachment: glyph.png>>
rows=8 width=6 pitch=6 num_grays=256 pixel_mode=2 palette_mode=0 00 00 00 66 FF 00 00 00 39 E5 FF 00 00 19 D7 33 FF 00 06 BC 3C 00 FF 00 93 47 00 00 FF 00 FF FF FF FF FF FF 00 00 00 00 FF 00 00 00 00 00 FF 00
#include "main.h"
#include "SaveToPNG.h"
#include "SaveToTXT.h"
FT_Error err = 0;
FT_Library libFreeType = NULL;
FT_Face fontFace = NULL;
FT_UInt glyphIndex = 0;
int screenResX = 0;
int screenResY = 0;
#define FONT_FILE "C:\\Windows\\Fonts\\l_10646.ttf" // Lucida Sans Unicode
#define FONT_POINT_SIZE 8
#define CHAR_TO_RENDER _T('4')
#define PNG_FILE _T("c:\\glyph.png")
#define TEXT_FILE _T("c:\\glyph.txt")
#define ON_ERR(m) MessageBox(NULL,m,_T("ERROR!"),MB_OK); return 0
void Cleanup()
{
if (fontFace != NULL)
{
FT_Done_Face(fontFace);
fontFace = NULL;
}
if (libFreeType != NULL)
{
FT_Done_FreeType(libFreeType);
libFreeType = NULL;
}
}
int WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int
nCmdShow)
{
// init FreeType
err = FT_Init_FreeType(&libFreeType);
if (err != 0)
{
ON_ERR(_T("Unable to init FreeType"));
}
// load face
err = FT_New_Face(libFreeType,FONT_FILE,0,&fontFace);
if (err != 0)
{
Cleanup();
ON_ERR(_T("Unable to load font"));
}
// verify font face is scalable
if (!FT_IS_SCALABLE(fontFace))
{
Cleanup();
ON_ERR(_T("Font is not scalable"));
}
// get screen device resolution
HDC hDC = CreateDC(_T("DISPLAY"),NULL,NULL,NULL);
screenResX = GetDeviceCaps(hDC,LOGPIXELSX);
screenResY = GetDeviceCaps(hDC,LOGPIXELSY);
DeleteDC(hDC);
// size the font face
err =
FT_Set_Char_Size(fontFace,0,FONT_POINT_SIZE*64,screenResX,screenResY);
if (err != 0)
{
Cleanup();
ON_ERR(_T("Unable to size the font"));
}
// get glyph index
glyphIndex = FT_Get_Char_Index(fontFace,CHAR_TO_RENDER);
if (glyphIndex == 0)
{
Cleanup();
ON_ERR(_T("Undefined char code"));
}
// load glyph
err = FT_Load_Glyph(fontFace,glyphIndex,FT_LOAD_DEFAULT);
if (err != 0)
{
Cleanup();
ON_ERR(_T("Unable to load glyph"));
}
// render glyph
err = FT_Render_Glyph(fontFace->glyph,FT_RENDER_MODE_NORMAL);
if (err != 0)
{
Cleanup();
ON_ERR(_T("Unable to render the glyph"));
}
// save rendered glyph to PNG image file
if (!SaveRenderedGlyphToPNG(fontFace->glyph->bitmap,PNG_FILE))
{
Cleanup();
ON_ERR(_T("Unable to save the rendered glyph to an image
file"));
}
// save rendered glyph to text file
if (!SaveRenderedGlyphToTXT(fontFace->glyph->bitmap,TEXT_FILE))
{
Cleanup();
ON_ERR(_T("Unable to save the rendered glyph to a text file"));
}
// done
Cleanup();
MessageBox(NULL,_T("Finished successfully!"),_T("Success!"),MB_OK);
return 0;
}
#pragma once // Modify the following defines if you have to target a platform prior to the ones specified below. // Refer to MSDN for the latest info on corresponding values for different platforms. #ifndef WINVER // Allow use of features specific to Windows XP or later. #define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. #define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. #endif #ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later. #define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE. #endif #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files: #include <windows.h> // C RunTime Header Files #include <stdlib.h> #include <malloc.h> #include <memory.h> #include <tchar.h> // FreeType #include <ft2build.h> #include FT_FREETYPE_H // libpng #include <png.h>
#include "main.h"
#include "SaveToPNG.h"
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
unsigned long user_error = 0;
extern int screenResX;
extern int screenResY;
#define METERS_TO_INCHES 39.370079
void user_error_fn(png_structp png_ptr, png_const_charp png_errstr)
{
}
void user_warning_fn(png_structp png_ptr, png_const_charp png_errstr)
{
}
bool SaveRenderedGlyphToPNG(FT_Bitmap& bmp, LPCTSTR file)
{
if (bmp.rows > PNG_UINT_32_MAX/png_sizeof(png_bytep))
return false;
FILE* fp = _tfopen(file,_T("wb"));
if (!fp)
return false;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
(png_voidp)(&user_error), user_error_fn, user_warning_fn);
if (png_ptr == NULL)
{
fclose(fp);
return false;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL)
{
fclose(fp);
png_destroy_write_struct(&png_ptr, NULL);
return false;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
fclose(fp);
png_destroy_write_struct(&png_ptr, &info_ptr);
return false;
}
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr,info_ptr,bmp.width,bmp.rows,8,PNG_COLOR_TYPE_GRAY,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
png_color_8 sig_bit;
sig_bit.gray = 8;
png_set_sBIT(png_ptr,info_ptr,&sig_bit);
png_set_pHYs(png_ptr,info_ptr,
(png_uint_32)(((double)screenResX * METERS_TO_INCHES) + 0.5),
(png_uint_32)(((double)screenResY * METERS_TO_INCHES) + 0.5),
PNG_RESOLUTION_METER);
png_write_info(png_ptr,info_ptr);
png_bytep * row_pointers = new png_bytep[bmp.rows];
unsigned char* bufferPos = bmp.buffer;
for (int row = 0; row < bmp.rows; row++)
{
row_pointers[row] = bufferPos;
bufferPos += bmp.pitch;
}
png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr,info_ptr);
png_destroy_write_struct(&png_ptr,&info_ptr);
delete [] row_pointers;
fflush(fp);
fclose(fp);
return true;
}
#pragma once bool SaveRenderedGlyphToPNG(FT_Bitmap& bmp, LPCTSTR file);
#include "main.h"
#include "SaveToTXT.h"
bool SaveRenderedGlyphToTXT(FT_Bitmap& bmp, LPCTSTR file)
{
FILE* fp = _tfopen(file,_T("wt"));
if (!fp)
return false;
_ftprintf(fp,_T("rows=%d\nwidth=%d\npitch=%d\nnum_grays=%d\npixel_mode=%d\npalette_mode=%d\n\n"),
bmp.rows,bmp.width,bmp.pitch,bmp.num_grays,bmp.pixel_mode,bmp.palette_mode);
unsigned char* bufferPos = bmp.buffer;
for (int row = 0; row < bmp.rows; row++)
{
for (int col = 0; col < bmp.width; col++)
{
if (col > 0)
_ftprintf(fp,_T(" "));
_ftprintf(fp,_T("%02X"),bufferPos[col]);
}
_ftprintf(fp,_T("\n"));
bufferPos += bmp.pitch;
}
fflush(fp);
fclose(fp);
return true;
}
#pragma once bool SaveRenderedGlyphToTXT(FT_Bitmap& bmp, LPCTSTR file);
_______________________________________________ Freetype mailing list [email protected] http://lists.nongnu.org/mailman/listinfo/freetype
