Using Xft Fonts on linux
by Gregory "Centove" McLean · 10/24/2005 (8:03 am) · 3 comments
Download Code File
Recently I upgraded my X Window install and somehow managed to hose up my font configuration and broke torque in the process! I went digging and found the font code on linux was fragile at best. Here is my attempt to improve things a bit. This will require that you are using Xfree 4.0 or Xorg 6.0 or higher.
To install (on a fresh torque 1.3 install):
Copy the existing x86UNIXFont.cc somewhere (x86UNIXFont.cc.orig)
Replace it with the attached code file.
Edit the mk/conf.UNIX.mk file
and
save that file and build the engine.
then from the example directory
Now enjoy your newly rendered fonts.
Here is the file:
Better screenshots:
Old XFLD rendering (Xlib) slyvester.gxsnmp.org/torque/screenshots/oldfont-screenshot.jpg
XFT Rendering slyvester.gxsnmp.org/torque/screenshots/font-screenshot.jpg
Recently I upgraded my X Window install and somehow managed to hose up my font configuration and broke torque in the process! I went digging and found the font code on linux was fragile at best. Here is my attempt to improve things a bit. This will require that you are using Xfree 4.0 or Xorg 6.0 or higher.
To install (on a fresh torque 1.3 install):
Copy the existing x86UNIXFont.cc somewhere (x86UNIXFont.cc.orig)
Replace it with the attached code file.
Edit the mk/conf.UNIX.mk file
CFLAGS.GENERAL = -DUSE_FILE_REDIRECT -I/usr/X11R6/include/ -MD -march=i586 \becomes
CFLAGS.GENERAL = -DUSE_FILE_REDIRECT -I/usr/X11R6/include/ 'freetype-config --cflags' -MD -march=i586 \
and
LINK.LIBS.RELEASE = LINK.LIBS.DEBUG =becomes
LINK.LIBS.RELEASE = -lXft LINK.LIBS.DEBUG = -lXft
save that file and build the engine.
then from the example directory
torque-1.3/example $ rm common/ui/cache/* torque-1.3/example $ ./torqueDemo.bin -nohomedir
Now enjoy your newly rendered fonts.
Here is the file:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "platformX86UNIX/platformX86UNIX.h"
#include "dgl/gFont.h"
#include "dgl/gBitmap.h"
#include "math/mRect.h"
#include "console/console.h"
// Needed by createFont
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
#include <X11/extensions/Xrender.h> // For XRenderColor
// Needed for getenv in createFont
#include <stdlib.h>
XftFont *loadFont(const char *name, S32 size, Display *display)
{
XftFont *fontInfo = NULL;
char* fontname = const_cast<char*>(name);
if (dStrlen(fontname)==0)
fontname = "arial";
else if (stristr(const_cast<char*>(name), "arial") != NULL)
fontname = "arial";
else if (stristr(const_cast<char*>(name), "lucida console") != NULL)
fontname = "lucida console";
char* weight = "medium";
char* slant = "roman"; // no slant
if (stristr(const_cast<char*>(name), "bold") != NULL)
weight = "bold";
if (stristr(const_cast<char*>(name), "italic") != NULL)
slant = "italic";
char xfontName[512];
// We specify a lower DPI to get 'correct' looking fonts, if we go with the
// native DPI the fonts are to big and don't fit the widgets.
dSprintf(xfontName, 512, "%s-%d:%s:slant=%s:dpi=65", fontname, size, weight, slant);
// Lets see if Xft can get a font for us.
char xftname[1024];
fontInfo = XftFontOpenName(display, DefaultScreen(display), xfontName);
if (fontInfo)
{
XftNameUnparse(fontInfo->pattern, xftname, 1024);
Con::printf("Font '%s %d' mapped to '%s'\n", name, size, xftname);
}
return fontInfo;
}
GFont *createFont(const char *name, dsize_t size)
{
// Our connection to the X Server, can't do anything without this
Display *display = XOpenDisplay(getenv("DISPLAY"));
if (!display)
AssertFatal(false, "createFont: cannot connect to X server");
XftFont *font = loadFont(name, size, display);
if (!font) // This should almost never trigger anymore.
AssertFatal(false, "createFont: cannot load font");
int screen = DefaultScreen(display);
int width, height;
width = font->max_advance_width;
height = font->height;
// Create the pixmap to draw on.
Pixmap pixmap = XCreatePixmap(display,
DefaultRootWindow(display),
width,
height,
DefaultDepth(display, screen));
// And the Xft wrapper around it.
XftDraw *draw = XftDrawCreate(display,
pixmap,
DefaultVisual(display, screen),
DefaultColormap(display, screen));
// Allocate some colors, we don't use XftColorAllocValue here as that
// Don't appear to function correctly (or I'm using it wrong) As we only do
// this twice per new un cached font it isn't that big of a penalty. (Each
// call to XftColorAllocName involves a round trip to the X Server)
XftColor black, white;
XftColorAllocName(display,
DefaultVisual(display, screen),
DefaultColormap(display, screen),
"black",
&black);
// White
XftColorAllocName(display,
DefaultVisual(display, screen),
DefaultColormap(display, screen),
"white",
&white);
// The font.
GFont *retFont = new GFont;
static U8 scratchPad[65536];
int x = 0;
int y = 0;
// Build the bitmaps
for (U16 i = 32; i < 256; i++)
{
XGlyphInfo extent;
FT_UInt glyph;
if (!XftCharExists(display, font, i))
{
retFont->insertBitmap(i, scratchPad, 0, 0, 0, 0, 0, width);
continue;
}
// Get the glyph and its extents.
glyph = XftCharIndex(display, font, i);
XftGlyphExtents (display, font, &glyph, 1, &extent);
// Clear the bounding box and draw the glyph
XftDrawRect (draw, &black, 0, 0, width, height);
XftDrawGlyphs (draw, &white, font, 0, font->ascent, &glyph, 1);
// Grab the rendered image ...
XImage *ximage = XGetImage(display, pixmap, 0, 0,
extent.xOff, height,
AllPlanes, XYPixmap);
if (ximage == NULL)
AssertFatal(false, "cannot get x image");
// And store each pixel in the scratchPad for insertion into the bitmap.
// We grab the full height of the pixmap.
for(y = 0; y < height; y++)
{
// and the width of the glyph and its padding.
for(x = 0; x < extent.xOff; x++)
{
U8 val = static_cast<U8>(XGetPixel(ximage, x, y));
scratchPad[y * extent.xOff + x] = val;
}
}
// Done with the image.
XDestroyImage(ximage);
// Add it to the bitmap.
retFont->insertBitmap(i, // index
scratchPad, // src
extent.xOff, // stride
extent.xOff, // width
height, // height
0, // xOrigin
font->ascent, // yOrigin
extent.xOff); // xIncrement
}
retFont->pack(height, font->ascent);
XftColorFree(display, DefaultVisual(display, screen),
DefaultColormap(display, screen), &black);
XftColorFree(display, DefaultVisual(display, screen),
DefaultColormap(display, screen), &white);
XftDrawDestroy(draw);
XFreePixmap(display, pixmap);
// XftFontClose(display, font); //-- Why do we crash on this?
XCloseDisplay(display);
return retFont;
}Better screenshots:
Old XFLD rendering (Xlib) slyvester.gxsnmp.org/torque/screenshots/oldfont-screenshot.jpg
XFT Rendering slyvester.gxsnmp.org/torque/screenshots/font-screenshot.jpg
About the author
#2
11/24/2005 (4:21 pm)
The only issue I bumped into was getting fonts that were waaay to big, I haven't figured out the correct way to scale things from what windows uses as a DPI and what X uses as a DPI. I however always got _a_ font which is one issue I was trying to solve with this.
#3
I managed to link without it.
01/01/2008 (12:54 am)
do I really need that line if im making dedicated?I managed to link without it.

Associate Ron Yacketta
notice issues loading fonts, one solution would be to use the orig loadFont() to find a standard xLib font and save its name then use the xFont call to load a XLFD (uses old style naming etc..) and then use all the xFt calls to do the font rendering. This has fixed the font rending issue on my ubuntoo box, not sure why xFt can not find the stock fonts. Kind of figured if I have the issue then someone else will as well..
-Ron