// // glFont.m // CGL // // Created by kat on Sat Jun 15 2002. // Copyright (c) 2001 Katherine Tattersall. All rights reserved. // #import "NSGLFont.h" //0.03125 #define xdiff 0.03125 #define ydiff 0.03125 @implementation NSGLFont -(id) outlineFont: (NSString *)fontname atSize:(int)size extrude:(float)z { CGContextRef cg_context; // we do not need to keep a cg_context: only the data needs to be kept size_t bytesPerRow; // at least (width * bitsPerComponent * number of components + 7)/8 CGColorSpaceRef colorspace; // create with CGColorSpaceCreateDevice... functions CGImageAlphaInfo alphaInfo; // see CGImage for valid enum constants size_t bitsPerComponent; // must be 1,2,4 or 8 size_t num; // number of components const char *c_fontname; int i; int n; float maxX; char jstr[2]; jstr[1] = '\0'; max_height = 8; max_width = 8; c_fontname = [fontname cString]; font = [NSFont fontWithName:fontname size:size]; [font retain]; NSLog( @"creating glFont: actual width=%f, actual height=%f, descender=%d", [font maximumAdvancement].width,[font defaultLineHeightForFont], (int)[font descender]); while( max_width < [font maximumAdvancement].width ) max_width += 8; while( max_height < [font defaultLineHeightForFont] ) max_height += 8; // CGContexts in grey space are all 8 bits bitsPerComponent = 8; // Gray color space is chosen here only because it is easy to convert to a bitmap colorspace = CGColorSpaceCreateDeviceGray(); // We do not need any alpha information alphaInfo = kCGImageAlphaNone; // we need to ensure that we have the correct number of componants in the colorspace ( exactly 1 ) num = CGColorSpaceGetNumberOfComponents(colorspace); // this is the lowest character in ASCII that we will want to draw (20) jstr[0] = ' '; // we now generate max_chars contiguous lists base = glGenLists( max_chars ); // if any of the operations above have failed, we should not continue if( colorspace != nil) for( i = 0; i < max_chars ; i++ ) // each character { height[i] = max_height; width[i] = max_width ; // width* number of componants: should be 1 componant for CGColorSpaceCreateDeviceGray() bytesPerRow = width[i]*num; // must use CALLOC <- if not, memory may not be empty, leading to strange results in the drawings // space must be at least (bytesPerRow * height) data[i] = (void *) calloc( bytesPerRow, height[i] ); if( data[i] != nil ) // calloc was successful { // create the context cg_context = CGBitmapContextCreate(data[i], width[i], height[i], bitsPerComponent, bytesPerRow, colorspace, alphaInfo); if( cg_context != nil ) { // draw the current letter [self drawLetter:jstr[0] context:cg_context atx:0 withFont:c_fontname atSize:size]; x_offset[i] = (unsigned int)[font widthOfString: [NSString stringWithCString: jstr]] +1; CGContextRelease(cg_context); } else NSLog(@"NSGLFont init ERROR: Didn't create CGContext[%d]",i); } [self getVertices:i]; //NSLog(@"For %s there are %d points", jstr, nVertices); jstr[0]++; glNewList( base+i,GL_COMPILE); // compile the following glBegin( GL_QUADS ); maxX = 0; for( n = 0; n < nVertices*4; n += 4 ) { glVertex3f(vertex[n+0]*xdiff, vertex[n+1]*ydiff, 0); glVertex3f(vertex[n+2]*xdiff, vertex[n+1]*ydiff, 0); glVertex3f(vertex[n+2]*xdiff, vertex[n+3]*ydiff, 0); glVertex3f(vertex[n+0]*xdiff, vertex[n+3]*ydiff, 0); if( z != 0 ) { glVertex3f(vertex[n+0]*xdiff, vertex[n+1]*ydiff, z); glVertex3f(vertex[n+2]*xdiff, vertex[n+1]*ydiff, z); glVertex3f(vertex[n+2]*xdiff, vertex[n+3]*ydiff, z); glVertex3f(vertex[n+0]*xdiff, vertex[n+3]*ydiff, z); glVertex3f(vertex[n+0]*xdiff, vertex[n+1]*ydiff, 0); glVertex3f(vertex[n+0]*xdiff, vertex[n+1]*ydiff, z); glVertex3f(vertex[n+2]*xdiff, vertex[n+1]*ydiff, z); glVertex3f(vertex[n+2]*xdiff, vertex[n+1]*ydiff, 0); glVertex3f(vertex[n+0]*xdiff, vertex[n+3]*ydiff, 0); glVertex3f(vertex[n+0]*xdiff, vertex[n+3]*ydiff, z); glVertex3f(vertex[n+2]*xdiff, vertex[n+3]*ydiff, z); glVertex3f(vertex[n+2]*xdiff, vertex[n+3]*ydiff, 0); glVertex3f(vertex[n+0]*xdiff, vertex[n+1]*ydiff, 0); glVertex3f(vertex[n+0]*xdiff, vertex[n+1]*ydiff, z); glVertex3f(vertex[n+0]*xdiff, vertex[n+3]*ydiff, z); glVertex3f(vertex[n+0]*xdiff, vertex[n+3]*ydiff, 0); glVertex3f(vertex[n+2]*xdiff, vertex[n+1]*ydiff, 0); glVertex3f(vertex[n+2]*xdiff, vertex[n+1]*ydiff, z); glVertex3f(vertex[n+2]*xdiff, vertex[n+3]*ydiff, z); glVertex3f(vertex[n+2]*xdiff, vertex[n+3]*ydiff, 0); } } glEnd(); glTranslatef(x_offset[i]*xdiff, 0, 0); //NSLog(@"maxX for %s is %f", jstr, x_offset[i]*xdiff); glEndList(); } return self; } -(id) bitmapFont: (NSString *)fontname atSize:(int)size { CGContextRef cg_context; // we do not need to keep a cg_context: only the data needs to be kept size_t bytesPerRow; // at least (width * bitsPerComponent * number of components + 7)/8 CGColorSpaceRef colorspace; // create with CGColorSpaceCreateDevice... functions CGImageAlphaInfo alphaInfo; // see CGImage for valid enum constants size_t bitsPerComponent; // must be 1,2,4 or 8 size_t num; // number of components const char *c_fontname; int i; char jstr[2]; jstr[1] = '\0'; max_height = 8; max_width = 8; c_fontname = [fontname cString]; font = [NSFont fontWithName:fontname size:size]; [font retain]; NSLog( @"creating glFont: actual width=%f, actual height=%f, descender=%d", [font maximumAdvancement].width,[font defaultLineHeightForFont], (int)[font descender]); while( max_width < [font maximumAdvancement].width ) max_width += 8; while( max_height < [font defaultLineHeightForFont] ) max_height += 8; // CGContexts in grey space are all 8 bits bitsPerComponent = 8; // Gray color space is chosen here only because it is easy to convert to a bitmap colorspace = CGColorSpaceCreateDeviceGray(); // We do not need any alpha information alphaInfo = kCGImageAlphaNone; // we need to ensure that we have the correct number of componants in the colorspace ( exactly 1 ) num = CGColorSpaceGetNumberOfComponents(colorspace); // this is the lowest character in ASCII that we will want to draw (20) jstr[0] = ' '; // we now generate max_chars contiguous lists base = glGenLists( max_chars ); // if any of the operations above have failed, we should not continue if( colorspace != nil) for( i = 0; i < max_chars ; i++ ) // each character { height[i] = max_height; width[i] = max_width ; // width* number of componants: should be 1 componant for CGColorSpaceCreateDeviceGray() bytesPerRow = width[i]*num; // must use CALLOC <- if not, memory may not be empty, leading to strange results in the drawings // space must be at least (bytesPerRow * height) data[i] = (void *) calloc( bytesPerRow, height[i] ); if( data[i] != nil ) // calloc was successful { // create the context cg_context = CGBitmapContextCreate(data[i], width[i], height[i], bitsPerComponent, bytesPerRow, colorspace, alphaInfo); if( cg_context != nil ) { // draw the current letter [self drawLetter:jstr[0] context:cg_context atx:0 withFont:c_fontname atSize:size]; x_offset[i] = (unsigned int)[font widthOfString: [NSString stringWithCString: jstr]] +1; CGContextRelease(cg_context); } else NSLog(@"NSGLFont init ERROR: Didn't create CGContext[%d]",i); } // create a BITMAP (as opposed to the Apple BYTEMAP CGBitmapContextRef) [self convertBitmap:i]; jstr[0]++; glNewList( base+i,GL_COMPILE); // compile the following glBitmap(width[i],height[i],0,0,x_offset[i],0,data[i]); glEndList(); } return self; } -(void) drawLetter:(char) ch context: (CGContextRef)cg_context atx:(int)xpos withFont:(const char *)fontname atSize:(int)size { // OpenGL will draw these upside down if we don't do this CGContextTranslateCTM( cg_context, 0, max_height ); CGContextScaleCTM( cg_context, 1.0,-1.0); // set the gray fill color to 1,1 which will make the bitmap work properly CGContextSetGrayFillColor(cg_context, 1.0, 1.0); // if you're doing a glDrawPixel, then leave this on // using glBitmap means converting to a bit image, and antialiasing that doesn't really work CGContextSetShouldAntialias(cg_context, 0 ); // some fonts don't work very well, like "Courier" // they are drawn very strangely CGContextSelectFont(cg_context, fontname, size, kCGEncodingMacRoman ); CGContextSetTextDrawingMode(cg_context, kCGTextFill); // draw exactly one glyph into the context CGContextShowTextAtPoint(cg_context, xpos, -[font descender], &ch, 1); } // clean up the memory -(void) dealloc { int i; for( i=0; i 0 && vertex[vertexIndex + 0 - 4] == vertex[vertexIndex + 0] && vertex[vertexIndex + 3 - 4] == row && vertex[vertexIndex + 2 - 4] == column ) { inrow = false; vertex[vertexIndex + 3 - 4] = row+outlinehelp; } else {*/ vertex[vertexIndex+2] = column; vertex[vertexIndex+3] = row+outlinehelp; inrow = false; nVertices++; vertexIndex = nVertices * 4; /* }*/ } } if( inrow ) { /* if( nVertices > 0 && vertex[vertexIndex + 0 - 4] == vertex[vertexIndex + 0] && vertex[vertexIndex + 3 - 4] == row && vertex[vertexIndex + 2 - 4] == column ) { inrow = false; vertex[vertexIndex + 3 - 4] = row+outlinehelp; } else {*/ vertex[vertexIndex+2] = column; vertex[vertexIndex+3] = row+outlinehelp; inrow = false; nVertices++; vertexIndex = nVertices * 4; /* }*/ } } if( nVertices >= 250 ) NSLog(@"too many vertices"); } /* - (void) getVertices: (int) number { int row, column, i; int vertexIndex; char *olddata = data[number]; bool inrow = false; nVertices = 0; vertexIndex = 0; for( row = 0; row < height[number] && nVertices < 250; row++ ) { for( column = 0; column < width[number] && nVertices < 250; column++ ) { } } if( nVertices >= 250 ) NSLog(@"too many vertices"); } */ @end // write to the screen using font f at location x,y with the specified string void glPrint( NSGLFont *f, float x, float y, const char *fmt, ... ) { char text[256]; va_list ap; NSString *s; GLboolean tex2d, light; // I always get a SIGSEGV 11 when glRasterPos* is called with textures off and lighting on // so here I turn them off. glGetBooleanv( GL_TEXTURE_2D, &tex2d ); glDisable(GL_TEXTURE_2D); glGetBooleanv( GL_LIGHTING, &light ); glDisable(GL_LIGHTING); if( fmt == NULL ) return; // format the string into (char *) text va_start( ap, fmt ); vsprintf( text, fmt, ap ); va_end(ap); // RasterPos to the correct location glRasterPos2f(x, y); // create an NSString s = [NSString stringWithCString: text]; // write the string [f writeString: s ]; // enable as required if( tex2d ) glEnable(GL_TEXTURE_2D); if( light ) glEnable(GL_LIGHTING); }