Anti-aliased bitmapped fonts
Right now for GL Golf I'm using the bitmap font code from NeHe tutorial 13 (http://nehe.gamedev.net/data/lessons/les...?lesson=13) . The problem is the text is always aliased, with each pixel being either fully on or fully off. Even after enabling full screen anti-aliasing, the text still shows up aliased (while everything else is smoothed as it should be!). I've also tried using these two pieces of code in the setup, with no luck -
[ [ NSGraphicsContext currentContext ] setShouldAntialias:NO ];
[ [ NSGraphicsContext currentContext ] setImageInterpolation:NSImageInterpolationHigh];
Any ideas on how to get this to anti-alias, either through FSAA or on its own? Do I need to look into something else? I tried to find a good demo using Freetype or something, but I couldn't find anything.
Here is the code that I'm using for the bitmapped fonts -
[ [ NSGraphicsContext currentContext ] setShouldAntialias:NO ];
[ [ NSGraphicsContext currentContext ] setImageInterpolation:NSImageInterpolationHigh];
Any ideas on how to get this to anti-alias, either through FSAA or on its own? Do I need to look into something else? I tried to find a good demo using Freetype or something, but I couldn't find anything.
Here is the code that I'm using for the bitmapped fonts -
Code:
- (bool) makeGLDisplayListFirst:(unichar)first count:(int)count base:(GLint)base
{
GLint curListIndex;
NSColor *blackColor;
NSDictionary *attribDict;
GLint dListNum;
NSString *currentChar;
unichar currentUnichar;
NSSize charSize;
NSRect charRect;
NSImage *theImage;
bool retval;
// Make sure a list isn't already under construction
glGetIntegerv( GL_LIST_INDEX, &curListIndex );
if( curListIndex != 0 )
{
[ NSFont doOpenGLLog:@"Display list already under construction" ];
return FALSE;
}
// Save pixel unpacking state
glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT );
glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE );
glPixelStorei( GL_UNPACK_LSB_FIRST, GL_FALSE );
glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
blackColor = [ NSColor blackColor ];
attribDict = [ NSDictionary dictionaryWithObjectsAndKeys:
self, NSFontAttributeName,
[ NSColor whiteColor ],
NSForegroundColorAttributeName,
blackColor, NSBackgroundColorAttributeName,
nil ];
charRect.origin.x = charRect.origin.y = 0;
theImage = [ [ [ NSImage alloc ] initWithSize:NSMakeSize( 0, 0 ) ]
autorelease ];
retval = TRUE;
for( dListNum = base, currentUnichar = first; currentUnichar < first + count;
dListNum++, currentUnichar++ )
{
currentChar = [ NSString stringWithCharacters:¤tUnichar length:1 ];
charSize = [ currentChar sizeWithAttributes:attribDict ];
charRect.size = charSize;
charRect = NSIntegralRect( charRect );
if( charRect.size.width > 0 && charRect.size.height > 0 )
{
[ theImage setSize:charRect.size ];
[ theImage lockFocus ];
[ [ NSGraphicsContext currentContext ] setShouldAntialias:NO ];
[ blackColor set ];
[ NSBezierPath fillRect:charRect ];
[ currentChar drawInRect:charRect withAttributes:attribDict ];
[ theImage unlockFocus ];
if( ![ self makeDisplayList:dListNum withImage:theImage ] )
{
retval = FALSE;
break;
}
}
}
glPopClientAttrib();
return retval;
}
/*
* Create one display list based on the given image. This assumes the image
* uses 8-bit chunks to represent a sample
*/
- (bool) makeDisplayList:(GLint)listNum withImage:(NSImage *)theImage
{
NSBitmapImageRep *bitmap;
int bytesPerRow, pixelsHigh, pixelsWide, samplesPerPixel;
unsigned char *bitmapBytes;
int currentBit, byteValue;
unsigned char *newBuffer, *movingBuffer;
int rowIndex, colIndex;
bitmap = [ NSBitmapImageRep imageRepWithData:[ theImage
TIFFRepresentationUsingCompression:NSTIFFCompressionNone
factor:0 ] ];
pixelsHigh = [ bitmap pixelsHigh ];
pixelsWide = [ bitmap pixelsWide ];
bitmapBytes = [ bitmap bitmapData ];
bytesPerRow = [ bitmap bytesPerRow ];
samplesPerPixel = [ bitmap samplesPerPixel ];
newBuffer = (unsigned char *) calloc( ceil( (float) bytesPerRow / 8.0 ), pixelsHigh );
if( newBuffer == NULL )
{
[ NSFont doOpenGLLog:@"Failed to calloc() memory in "
@"makeDisplayList:withImage:" ];
return FALSE;
}
movingBuffer = newBuffer;
/*
* Convert the color bitmap into a true bitmap, ie, one bit per pixel. We
* read at last row, write to first row as Cocoa and OpenGL have opposite
* y origins
*/
for( rowIndex = pixelsHigh - 1; rowIndex >= 0; rowIndex-- )
{
currentBit = 0x80;
byteValue = 0;
for( colIndex = 0; colIndex < pixelsWide; colIndex++ )
{
if( bitmapBytes[ rowIndex * bytesPerRow + colIndex * samplesPerPixel ] )
byteValue |= currentBit;
currentBit >>= 1;
if( currentBit == 0 )
{
*movingBuffer++ = byteValue;
currentBit = 0x80;
byteValue = 0;
}
}
/*
* Fill out the last byte; extra is ignored by OpenGL, but each row
* must start on a new byte
*/
if( currentBit != 0x80 )
*movingBuffer++ = byteValue;
}
glNewList( listNum, GL_COMPILE );
glBitmap( pixelsWide, pixelsHigh, 0, 0, pixelsWide, 0, newBuffer );
glEndList();
free( newBuffer );
return TRUE;
}
Code:
- (void) glPrint:(NSString *)fmt, ...
{
NSString *text;
va_list ap; // Pointer To List Of Arguments
unichar *uniBuffer;
if( fmt == nil || [ fmt length ] == 0 ) // If There's No Text
return; // Do Nothing
va_start( ap, fmt ); // Parses The String For Variables
text = [ [ [ NSString alloc ] initWithFormat:fmt arguments:ap ] autorelease ];
va_end( ap ); // Results Are Stored In Text
glPushAttrib( GL_LIST_BIT ); // Pushes The Display List Bits
glListBase( base - 32 ); // Sets The Base Character to 32
uniBuffer = (unichar *) calloc( [ text length ], sizeof( unichar ) );
[ text getCharacters:uniBuffer ];
// Draws The Display List Text
glCallLists( [ text length ], GL_UNSIGNED_SHORT, uniBuffer );
free( uniBuffer );
glPopAttrib(); // Pops The Display List Bits
}
I use http://onesadcookie.com/svn/NSViewTexture for the purpose (requires 10.4) though obviously it works rather differently from your code.
You're welcome to use any output from http://fax.twilightcoders.net/GlyphTool/ in any software you want. It generates bitmap fonts and there's some code to load them which works (or should do) on any system with opengl.
Sir, e^iπ + 1 = 0, hence God exists; reply!
Thanks for the info guys.
Unfortunately I can't drop 10.3.9 yet, still to many users (although I finally did give up on 10.2.8 last month!). I did figure out NSViewTexture and it looks pretty cool!
Unknown, I tried building for 10.3.9 and it didn't work, am I correct saying it requires 10.4?
Unfortunately I can't drop 10.3.9 yet, still to many users (although I finally did give up on 10.2.8 last month!). I did figure out NSViewTexture and it looks pretty cool!
Unknown, I tried building for 10.3.9 and it didn't work, am I correct saying it requires 10.4?
yea, it only works with 10.4. Have you considered using freetype, and bundle it dynamically with your app?
It's not magic, it's Ruby.
Nayr Wrote:yea, it only works with 10.4. Have you considered using freetype, and bundle it dynamically with your app?
I have, but I haven't found any good simple demos showing it yet , I guess thats my next step tomorrow.
http://onesadcookie.com/svn/SimpleText and http://onesadcookie.com/svn/SimpleTextCDemo (not without bugs, but a decent starting point). http://onesadcookie.com/svn/Third-Party builds freetype for all the architectures you have an SDK for.
Jake Wrote:Unknown, I tried building for 10.3.9 and it didn't work, am I correct saying it requires 10.4?
try the binary, and the output should be useable on anything (not just macs)
Sir, e^iπ + 1 = 0, hence God exists; reply!
Some code from one of my projects that works on 10.3.9. It works a bit differently from yours (draws a whole string at a time), but anti-aliasing works:
Code:
- (id) initWithTextString: (NSString *) string attributes: (NSDictionary *) attributes {
NSAttributedString * attributedString;
void * pixels;
GLenum format;
attributedString = [[NSAttributedString alloc] initWithString: string attributes: attributes];
isText = YES;
width = [attributedString size].width;
height = [attributedString size].height;
widthPOT = 1;
while (widthPOT < width) {
widthPOT <<= 1;
}
heightPOT = 1;
while (heightPOT < height) {
heightPOT <<= 1;
}
pixels = getStringImageData(attributedString, widthPOT, heightPOT, &format);
glGenTextures(1, &name);
glBindTexture(GL_TEXTURE_2D, name);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_ALPHA,
widthPOT,
heightPOT,
0,
format,
GL_UNSIGNED_BYTE,
pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
free(pixels);
[attributedString release];
return self;
}
static void * getStringImageData(NSAttributedString * string, int maxWidth, int maxHeight, GLenum * outFormat) {
static long systemVersion = 0x0000;
void * pixels;
if (systemVersion == 0x0000) {
Gestalt(gestaltSystemVersion, &systemVersion);
}
if (systemVersion >= 0x1040) {
NSBitmapImageRep * bitmap;
NSGraphicsContext * context;
pixels = (unsigned char *) calloc(maxWidth, maxHeight);
bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: (unsigned char **) &pixels
pixelsWide: maxWidth
pixelsHigh: maxHeight
bitsPerSample: 8
samplesPerPixel: 1
hasAlpha: NO
isPlanar: NO
colorSpaceName: NSDeviceWhiteColorSpace
bitmapFormat: 0
bytesPerRow: maxWidth
bitsPerPixel: 8];
context = [NSGraphicsContext graphicsContextWithBitmapImageRep: bitmap];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext: context];
[string drawAtPoint: NSMakePoint(0, 0)];
[NSGraphicsContext restoreGraphicsState];
*outFormat = GL_ALPHA;
[bitmap release];
} else {
NSImage * image;
NSBitmapImageRep * bitmap;
pixels = (unsigned char *) calloc(maxWidth, maxHeight * 4);
image = [[NSImage alloc] initWithSize: NSMakeSize(maxWidth, maxHeight)];
[image lockFocus];
[string drawAtPoint: NSMakePoint(0, 0)];
bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect: NSMakeRect(0.0f, 0.0f, maxWidth, maxHeight)];
[image unlockFocus];
memcpy(pixels, [bitmap bitmapData], maxWidth * maxHeight * 4);
*outFormat = GL_RGBA;
[image release];
[bitmap release];
}
return pixels;
}
Thanks for the links OSC and the info unknown.
ThemsAllTook - That code was pretty easy to add to my project, do you have a project on your site that uses it that I can download, or a snippet of code to render the text once its created into a texture?
ThemsAllTook - That code was pretty easy to add to my project, do you have a project on your site that uses it that I can download, or a snippet of code to render the text once its created into a texture?
Full source code for this project isn't publicly available, but here are the relevant snippets:
Code:
- (void) apply {
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
if (isText) {
glTranslatef(0.0f, (1.0f - (((float) height / (float) heightPOT) * 0.5f)), 0.0f);
glScalef(((float) width / (float) widthPOT), -((float) height / (float) heightPOT), 1.0f);
glTranslatef(0.0f, -0.5f, 0.0f);
}
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, name);
}
...
/* Simple example usage */
[texture apply];
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(left, bottom);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(right, bottom);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(right, top);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(left, top);
glEnd();
I was using something similar to lesson 13 in my stuff.
Though, I've switched to freetype -- nehe lesson 43 which addresses anti aliasing. The lesson is written clearly.
Works well. Anti aliases and positions the text correctly.
Though, I've switched to freetype -- nehe lesson 43 which addresses anti aliasing. The lesson is written clearly.
Works well. Anti aliases and positions the text correctly.

ThemsAllTook Wrote:Full source code for this project isn't publicly available, but here are the relevant snippets:
Thanks, but after tinkering for a while I'm getting white rectangles instead of text - does this look right to set it up?
Code:
NSFont *font = [NSFont fontWithName:@"Lucida Grande" size:14.0];
NSDictionary *attrsDictionary =[NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
id tmptxt = [[Text alloc] initWithTextString:@"This is my test string. /n/n Line 2" attributes:attrsDictionary];
Thanks for the link to lesson 43, I didn't realize that one existed!
Possibly Related Threads...
Thread: | Author | Replies: | Views: | Last Post | |
How do I flip upside down fonts in FTGL | mr5z | 4 | 5,852 |
Mar 3, 2014 03:36 PM Last Post: JustinFic |
|
Bitmap fonts | markhula | 6 | 12,282 |
Feb 27, 2011 12:55 PM Last Post: markhula |
|
Bitmapped Font | OptimisticMonkey | 8 | 6,227 |
Aug 16, 2009 01:27 AM Last Post: Ingemar |
|
shared context breaking FTGL texture fonts | akb825 | 12 | 10,242 |
Sep 7, 2006 08:56 PM Last Post: akb825 |
|
Fonts with OpenGL & GLF | Jones | 15 | 11,800 |
Jul 5, 2006 11:32 AM Last Post: akb825 |