Commits

Blake Winton  committed 2eb6e9f

Get strings working!!!

  • Participants
  • Parent commits a0a3d7d

Comments (0)

Files changed (7)

+//
+// File:		GLString.h 
+//				(Originally StringTexture.h)
+//
+// Abstract:	Uses Quartz to draw a string into an OpenGL texture
+//
+// Version:		1.1 - Minor enhancements and bug fixes.
+//				1.0 - Original release.
+//				
+//
+// Disclaimer:	IMPORTANT:  This Apple software is supplied to you by Apple Inc. ("Apple")
+//				in consideration of your agreement to the following terms, and your use,
+//				installation, modification or redistribution of this Apple software
+//				constitutes acceptance of these terms.  If you do not agree with these
+//				terms, please do not use, install, modify or redistribute this Apple
+//				software.
+//
+//				In consideration of your agreement to abide by the following terms, and
+//				subject to these terms, Apple grants you a personal, non - exclusive
+//				license, under Apple's copyrights in this original Apple software ( the
+//				"Apple Software" ), to use, reproduce, modify and redistribute the Apple
+//				Software, with or without modifications, in source and / or binary forms;
+//				provided that if you redistribute the Apple Software in its entirety and
+//				without modifications, you must retain this notice and the following text
+//				and disclaimers in all such redistributions of the Apple Software. Neither
+//				the name, trademarks, service marks or logos of Apple Inc. may be used to
+//				endorse or promote products derived from the Apple Software without specific
+//				prior written permission from Apple.  Except as expressly stated in this
+//				notice, no other rights or licenses, express or implied, are granted by
+//				Apple herein, including but not limited to any patent rights that may be
+//				infringed by your derivative works or by other works in which the Apple
+//				Software may be incorporated.
+//
+//				The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+//				WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+//				WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+//				PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
+//				ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+//
+//				IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+//				CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+//				SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+//				INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
+//				AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
+//				UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR
+//				OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Copyright ( C ) 2003-2007 Apple Inc. All Rights Reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#import <OpenGL/gl.h>
+#import <OpenGL/glext.h>
+#import <OpenGL/OpenGL.h>
+#import <OpenGL/CGLContext.h>
+
+@interface NSBezierPath (RoundRect)
++ (NSBezierPath *)bezierPathWithRoundedRect:(NSRect)rect cornerRadius:(float)radius;
+
+- (void)appendBezierPathWithRoundedRect:(NSRect)rect cornerRadius:(float)radius;
+@end
+
+@interface GLString : NSObject {
+	CGLContextObj cgl_ctx; // current context at time of texture creation
+	GLuint texName;
+	NSSize texSize;
+	
+	NSAttributedString * string;
+	NSColor * textColor; // default is opaque white
+	NSColor * boxColor; // default transparent or none
+	NSColor * borderColor; // default transparent or none
+	BOOL staticFrame; // default in NO
+	BOOL antialias;	// default to YES
+	NSSize marginSize; // offset or frame size, default is 4 width 2 height
+	NSSize frameSize; // offset or frame size, default is 4 width 2 height
+	float	cRadius; // Corner radius, if 0 just a rectangle. Defaults to 4.0f
+	
+	BOOL requiresUpdate;
+}
+
+// this API requires a current rendering context and all operations will be performed in regards to thar context
+// the same context should be current for all method calls for a particular object instance
+
+// designated initializer
+- (id) initWithAttributedString:(NSAttributedString *)attributedString withTextColor:(NSColor *)color withBoxColor:(NSColor *)color withBorderColor:(NSColor *)color;
+
+- (id) initWithString:(NSString *)aString withAttributes:(NSDictionary *)attribs withTextColor:(NSColor *)color withBoxColor:(NSColor *)color withBorderColor:(NSColor *)color;
+
+// basic methods that pick up defaults
+- (id) initWithString:(NSString *)aString withAttributes:(NSDictionary *)attribs;
+- (id) initWithAttributedString:(NSAttributedString *)attributedString;
+
+- (void) dealloc;
+
+- (GLuint) texName; // 0 if no texture allocated
+- (NSSize) texSize; // actually size of texture generated in texels, (0, 0) if no texture allocated
+
+- (NSColor *) textColor; // get the pre-multiplied default text color (includes alpha) string attributes could override this
+- (NSColor *) boxColor; // get the pre-multiplied box color (includes alpha) alpha of 0.0 means no background box
+- (NSColor *) borderColor; // get the pre-multiplied border color (includes alpha) alpha of 0.0 means no border
+- (BOOL) staticFrame; // returns whether or not a static frame will be used
+
+- (NSSize) frameSize; // returns either dynamc frame (text size + margins) or static frame size (switch with staticFrame)
+
+- (NSSize) marginSize; // current margins for text offset and pads for dynamic frame
+
+- (void) genTexture; // generates the texture without drawing texture to current context
+- (void) drawWithBounds:(NSRect)bounds; // will update the texture if required due to change in settings (note context should be setup to be orthographic scaled to per pixel scale)
+- (void) drawAtPoint:(NSPoint)point;
+
+// these will force the texture to be regenerated at the next draw
+- (void) setMargins:(NSSize)size; // set offset size and size to fit with offset
+- (void) useStaticFrame:(NSSize)size; // set static frame size and size to frame
+- (void) useDynamicFrame; // set static frame size and size to frame
+
+- (void) setString:(NSAttributedString *)attributedString; // set string after initial creation
+- (void) setString:(NSString *)aString withAttributes:(NSDictionary *)attribs; // set string after initial creation
+
+- (void) setTextColor:(NSColor *)color; // set default text color
+- (void) setBoxColor:(NSColor *)color; // set default text color
+- (void) setBorderColor:(NSColor *)color; // set default text color
+
+- (BOOL) antialias;
+- (void) setAntialias:(bool)request;
+
+@end
+
+//
+// File:		GLString.m
+//				(Originally StringTexture.m)
+//
+// Abstract:	Uses Quartz to draw a string into an OpenGL texture
+//
+// Version:		1.1 - Antialiasing option, Rounded Corners to the frame
+//					  self contained OpenGL state, performance enhancements,
+//					  other bug fixes.
+//				1.0 - Original release.
+//				
+//
+// Disclaimer:	IMPORTANT:  This Apple software is supplied to you by Apple Inc. ("Apple")
+//				in consideration of your agreement to the following terms, and your use,
+//				installation, modification or redistribution of this Apple software
+//				constitutes acceptance of these terms.  If you do not agree with these
+//				terms, please do not use, install, modify or redistribute this Apple
+//				software.
+//
+//				In consideration of your agreement to abide by the following terms, and
+//				subject to these terms, Apple grants you a personal, non - exclusive
+//				license, under Apple's copyrights in this original Apple software ( the
+//				"Apple Software" ), to use, reproduce, modify and redistribute the Apple
+//				Software, with or without modifications, in source and / or binary forms;
+//				provided that if you redistribute the Apple Software in its entirety and
+//				without modifications, you must retain this notice and the following text
+//				and disclaimers in all such redistributions of the Apple Software. Neither
+//				the name, trademarks, service marks or logos of Apple Inc. may be used to
+//				endorse or promote products derived from the Apple Software without specific
+//				prior written permission from Apple.  Except as expressly stated in this
+//				notice, no other rights or licenses, express or implied, are granted by
+//				Apple herein, including but not limited to any patent rights that may be
+//				infringed by your derivative works or by other works in which the Apple
+//				Software may be incorporated.
+//
+//				The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+//				WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+//				WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+//				PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
+//				ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+//
+//				IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+//				CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+//				SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+//				INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
+//				AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
+//				UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR
+//				OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Copyright ( C ) 2003-2007 Apple Inc. All Rights Reserved.
+//
+
+#import "GLString.h"
+
+// The following is a NSBezierPath category to allow
+// for rounded corners of the border
+
+#pragma mark -
+#pragma mark NSBezierPath Category
+
+@implementation NSBezierPath (RoundRect)
+
++ (NSBezierPath *)bezierPathWithRoundedRect:(NSRect)rect cornerRadius:(float)radius {
+    NSBezierPath *result = [NSBezierPath bezierPath];
+    [result appendBezierPathWithRoundedRect:rect cornerRadius:radius];
+    return result;
+}
+
+- (void)appendBezierPathWithRoundedRect:(NSRect)rect cornerRadius:(float)radius {
+    if (!NSIsEmptyRect(rect)) {
+		if (radius > 0.0) {
+			// Clamp radius to be no larger than half the rect's width or height.
+			float clampedRadius = MIN(radius, 0.5 * MIN(rect.size.width, rect.size.height));
+			
+			NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect));
+			NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect));
+			NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect));
+			
+			[self moveToPoint:NSMakePoint(NSMidX(rect), NSMaxY(rect))];
+			[self appendBezierPathWithArcFromPoint:topLeft     toPoint:rect.origin radius:clampedRadius];
+			[self appendBezierPathWithArcFromPoint:rect.origin toPoint:bottomRight radius:clampedRadius];
+			[self appendBezierPathWithArcFromPoint:bottomRight toPoint:topRight    radius:clampedRadius];
+			[self appendBezierPathWithArcFromPoint:topRight    toPoint:topLeft     radius:clampedRadius];
+			[self closePath];
+		} else {
+			// When radius == 0.0, this degenerates to the simple case of a plain rectangle.
+			[self appendBezierPathWithRect:rect];
+		}
+    }
+}
+
+@end
+
+
+#pragma mark -
+#pragma mark GLString
+
+// GLString follows
+
+@implementation GLString
+
+#pragma mark -
+#pragma mark Deallocs
+
+- (void) deleteTexture
+{
+	if (texName && cgl_ctx) {
+		(*cgl_ctx->disp.delete_textures)(cgl_ctx->rend, 1, &texName);
+		texName = 0; // ensure it is zeroed for failure cases
+		cgl_ctx = 0;
+	}
+}
+
+- (void) dealloc
+{
+	[self deleteTexture];
+	[textColor release];
+	[boxColor release];
+	[borderColor release];
+	[string release];
+	[super dealloc];
+}
+
+#pragma mark -
+#pragma mark Initializers
+
+// designated initializer
+- (id) initWithAttributedString:(NSAttributedString *)attributedString withTextColor:(NSColor *)text withBoxColor:(NSColor *)box withBorderColor:(NSColor *)border
+{
+	[super init];
+	cgl_ctx = NULL;
+	texName = 0;
+	texSize.width = 0.0f;
+	texSize.height = 0.0f;
+	[attributedString retain];
+	string = attributedString;
+	[text retain];
+	[box retain];
+	[border retain];
+	textColor = text;
+	boxColor = box;
+	borderColor = border;
+	staticFrame = NO;
+	antialias = YES;
+	marginSize.width = 4.0f; // standard margins
+	marginSize.height = 2.0f;
+	cRadius = 4.0f;
+	requiresUpdate = YES;
+	// all other variables 0 or NULL
+	return self;
+}
+
+- (id) initWithString:(NSString *)aString withAttributes:(NSDictionary *)attribs withTextColor:(NSColor *)text withBoxColor:(NSColor *)box withBorderColor:(NSColor *)border
+{
+	return [self initWithAttributedString:[[[NSAttributedString alloc] initWithString:aString attributes:attribs] autorelease] withTextColor:text withBoxColor:box withBorderColor:border];
+}
+
+// basic methods that pick up defaults
+- (id) initWithAttributedString:(NSAttributedString *)attributedString;
+{
+	return [self initWithAttributedString:attributedString withTextColor:[NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:1.0f] withBoxColor:[NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:0.0f] withBorderColor:[NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:0.0f]];
+}
+
+- (id) initWithString:(NSString *)aString withAttributes:(NSDictionary *)attribs
+{
+	return [self initWithAttributedString:[[[NSAttributedString alloc] initWithString:aString attributes:attribs] autorelease] withTextColor:[NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:1.0f] withBoxColor:[NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:0.0f] withBorderColor:[NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:0.0f]];
+}
+
+- (void) genTexture; // generates the texture without drawing texture to current context
+{
+	NSImage * image;
+	NSBitmapImageRep * bitmap;
+	
+	NSSize previousSize = texSize;
+	
+	if ((NO == staticFrame) && (0.0f == frameSize.width) && (0.0f == frameSize.height)) { // find frame size if we have not already found it
+		frameSize = [string size]; // current string size
+		frameSize.width += marginSize.width * 2.0f; // add padding
+		frameSize.height += marginSize.height * 2.0f;
+	}
+	image = [[NSImage alloc] initWithSize:frameSize];
+	
+	[image lockFocus];
+	[[NSGraphicsContext currentContext] setShouldAntialias:antialias];
+	
+	if ([boxColor alphaComponent]) { // this should be == 0.0f but need to make sure
+		[boxColor set]; 
+		NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(NSMakeRect (0.0f, 0.0f, frameSize.width, frameSize.height) , 0.5, 0.5)
+														cornerRadius:cRadius];
+		[path fill];
+	}
+
+	if ([borderColor alphaComponent]) {
+		[borderColor set]; 
+		NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(NSMakeRect (0.0f, 0.0f, frameSize.width, frameSize.height), 0.5, 0.5) 
+														cornerRadius:cRadius];
+		[path setLineWidth:1.0f];
+		[path stroke];
+	}
+	
+	[textColor set]; 
+	[string drawAtPoint:NSMakePoint (marginSize.width, marginSize.height)]; // draw at offset position
+	bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect (0.0f, 0.0f, frameSize.width, frameSize.height)];
+	[image unlockFocus];
+	texSize.width = [bitmap pixelsWide];
+	texSize.height = [bitmap pixelsHigh];
+	
+	if (cgl_ctx = CGLGetCurrentContext ()) { // if we successfully retrieve a current context (required)
+		glPushAttrib(GL_TEXTURE_BIT);
+		if (0 == texName) glGenTextures (1, &texName);
+		glBindTexture (GL_TEXTURE_RECTANGLE_EXT, texName);
+		if (NSEqualSizes(previousSize, texSize)) {
+			glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT,0,0,0,texSize.width,texSize.height,[bitmap hasAlpha] ? GL_RGBA : GL_RGB,GL_UNSIGNED_BYTE,[bitmap bitmapData]);
+		} else {
+			glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+			glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+			glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, texSize.width, texSize.height, 0, [bitmap hasAlpha] ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, [bitmap bitmapData]);
+		}
+		glPopAttrib();
+	} else
+		NSLog (@"StringTexture -genTexture: Failure to get current OpenGL context\n");
+	
+	[bitmap release];
+	[image release];
+	
+	requiresUpdate = NO;
+}
+
+#pragma mark -
+#pragma mark Accessors
+
+- (GLuint) texName
+{
+	return texName;
+}
+
+- (NSSize) texSize
+{
+	return texSize;
+}
+
+#pragma mark Text Color
+
+- (void) setTextColor:(NSColor *)color // set default text color
+{
+	[color retain];
+	[textColor release];
+	textColor = color;
+	requiresUpdate = YES;
+}
+
+- (NSColor *) textColor
+{
+	return textColor;
+}
+
+#pragma mark Box Color
+
+- (void) setBoxColor:(NSColor *)color // set default text color
+{
+	[color retain];
+	[boxColor release];
+	boxColor = color;
+	requiresUpdate = YES;
+}
+
+- (NSColor *) boxColor
+{
+	return boxColor;
+}
+
+#pragma mark Border Color
+
+- (void) setBorderColor:(NSColor *)color // set default text color
+{
+	[color retain];
+	[borderColor release];
+	borderColor = color;
+	requiresUpdate = YES;
+}
+
+- (NSColor *) borderColor
+{
+	return borderColor;
+}
+
+#pragma mark Margin Size
+
+// these will force the texture to be regenerated at the next draw
+- (void) setMargins:(NSSize)size // set offset size and size to fit with offset
+{
+	marginSize = size;
+	if (NO == staticFrame) { // ensure dynamic frame sizes will be recalculated
+		frameSize.width = 0.0f;
+		frameSize.height = 0.0f;
+	}
+	requiresUpdate = YES;
+}
+
+- (NSSize) marginSize
+{
+	return marginSize;
+}
+
+#pragma mark Antialiasing
+- (BOOL) antialias
+{
+	return antialias;
+}
+
+- (void) setAntialias:(bool)request
+{
+	antialias = request;
+	requiresUpdate = YES;
+}
+
+
+#pragma mark Frame
+
+- (NSSize) frameSize
+{
+	if ((NO == staticFrame) && (0.0f == frameSize.width) && (0.0f == frameSize.height)) { // find frame size if we have not already found it
+		frameSize = [string size]; // current string size
+		frameSize.width += marginSize.width * 2.0f; // add padding
+		frameSize.height += marginSize.height * 2.0f;
+	}
+	return frameSize;
+}
+
+- (BOOL) staticFrame
+{
+	return staticFrame;
+}
+
+- (void) useStaticFrame:(NSSize)size // set static frame size and size to frame
+{
+	frameSize = size;
+	staticFrame = YES;
+	requiresUpdate = YES;
+}
+
+- (void) useDynamicFrame
+{
+	if (staticFrame) { // set to dynamic frame and set to regen texture
+		staticFrame = NO;
+		frameSize.width = 0.0f; // ensure frame sizes will be recalculated
+		frameSize.height = 0.0f;
+		requiresUpdate = YES;
+	}
+}
+
+#pragma mark String
+
+- (void) setString:(NSAttributedString *)attributedString // set string after initial creation
+{
+	[attributedString retain];
+	[string release];
+	string = attributedString;
+	if (NO == staticFrame) { // ensure dynamic frame sizes will be recalculated
+		frameSize.width = 0.0f;
+		frameSize.height = 0.0f;
+	}
+	requiresUpdate = YES;
+}
+
+- (void) setString:(NSString *)aString withAttributes:(NSDictionary *)attribs; // set string after initial creation
+{
+	[self setString:[[[NSAttributedString alloc] initWithString:aString attributes:attribs] autorelease]];
+}
+
+
+#pragma mark -
+#pragma mark Drawing
+
+- (void) drawWithBounds:(NSRect)bounds
+{
+	if (requiresUpdate)
+		[self genTexture];
+	if (texName) {
+		glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT); // GL_COLOR_BUFFER_BIT for glBlendFunc, GL_ENABLE_BIT for glEnable / glDisable
+		
+		glDisable (GL_DEPTH_TEST); // ensure text is not remove by depth buffer test.
+		glEnable (GL_BLEND); // for text fading
+		glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // ditto
+		glEnable (GL_TEXTURE_RECTANGLE_EXT);	
+		
+		glBindTexture (GL_TEXTURE_RECTANGLE_EXT, texName);
+		glBegin (GL_QUADS);
+			glTexCoord2f (0.0f, 0.0f); // draw upper left in world coordinates
+			glVertex2f (bounds.origin.x, bounds.origin.y);
+	
+			glTexCoord2f (0.0f, texSize.height); // draw lower left in world coordinates
+			glVertex2f (bounds.origin.x, bounds.origin.y + bounds.size.height);
+	
+			glTexCoord2f (texSize.width, texSize.height); // draw upper right in world coordinates
+			glVertex2f (bounds.origin.x + bounds.size.width, bounds.origin.y + bounds.size.height);
+	
+			glTexCoord2f (texSize.width, 0.0f); // draw lower right in world coordinates
+			glVertex2f (bounds.origin.x + bounds.size.width, bounds.origin.y);
+		glEnd ();
+		
+		glPopAttrib();
+	}
+}
+
+- (void) drawAtPoint:(NSPoint)point
+{
+	if (requiresUpdate)
+		[self genTexture]; // ensure size is calculated for bounds
+	if (texName) // if successful
+		[self drawWithBounds:NSMakeRect (point.x, point.y, texSize.width, texSize.height)];
+}
+
+@end

File PixelCity-Saver.xcodeproj/project.pbxproj

 	objects = {
 
 /* Begin PBXBuildFile section */
+		0B857B1912B5A6AB00FFCD60 /* GLString.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B857B1712B5A6AB00FFCD60 /* GLString.m */; };
+		0B857B1A12B5A6AB00FFCD60 /* GLString.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B857B1812B5A6AB00FFCD60 /* GLString.h */; };
+		0B8809E312B5695B006947E6 /* AGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B8809E212B5695B006947E6 /* AGL.framework */; };
 		0B9E7FE212B53392001C01F5 /* Info-Saver.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0B9E7FE112B53392001C01F5 /* Info-Saver.plist */; };
 		0BD7F9C71295CF1000AB9075 /* Defs.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BD7F9AD1295CF1000AB9075 /* Defs.h */; };
 		0BD7F9C81295CF1000AB9075 /* Random.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0BD7F9AE1295CF1000AB9075 /* Random.cpp */; };
 		06F27B2DFFEEEFEF11CA0E56 /* ScreenSaver.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ScreenSaver.framework; path = /System/Library/Frameworks/ScreenSaver.framework; sourceTree = "<absolute>"; };
 		089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
 		089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		0B857B1712B5A6AB00FFCD60 /* GLString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLString.m; sourceTree = "<group>"; };
+		0B857B1812B5A6AB00FFCD60 /* GLString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLString.h; sourceTree = "<group>"; };
+		0B8809E212B5695B006947E6 /* AGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AGL.framework; path = System/Library/Frameworks/AGL.framework; sourceTree = SDKROOT; };
 		0B9E7FE112B53392001C01F5 /* Info-Saver.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Saver.plist"; sourceTree = "<group>"; };
 		0BD7F9AD1295CF1000AB9075 /* Defs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Defs.h; sourceTree = "<group>"; };
 		0BD7F9AE1295CF1000AB9075 /* Random.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Random.cpp; sourceTree = "<group>"; };
 		0BD7FA261295CF7F00AB9075 /* Light.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Light.h; sourceTree = "<group>"; };
 		0BD7FA271295CF7F00AB9075 /* Mesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mesh.cpp; sourceTree = "<group>"; };
 		0BD7FA281295CF7F00AB9075 /* Mesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mesh.h; sourceTree = "<group>"; };
-		0BD7FACE1295DA3E00AB9075 /* PixelCity-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PixelCity-Info.plist"; sourceTree = "<group>"; };
 		0BD7FAE71295DAAD00AB9075 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
 		0BD7FAEB1295DAB300AB9075 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
 		0BD7FC7B1295DCA100AB9075 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = "<group>"; };
 				8D255ACF0486D3F9007BF209 /* ScreenSaver.framework in Frameworks */,
 				0BD7F9E71295CF3C00AB9075 /* OpenGL.framework in Frameworks */,
 				0BD7F9FB1295CF4E00AB9075 /* CoreData.framework in Frameworks */,
+				0B8809E312B5695B006947E6 /* AGL.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 				089C167CFE841241C02AAC07 /* Resources */,
 				089C1671FE841209C02AAC07 /* Frameworks and Libraries */,
 				19C28FB8FE9D52D311CA2CBB /* Products */,
-				0BD7FACE1295DA3E00AB9075 /* PixelCity-Info.plist */,
 				0BD7FAE71295DAAD00AB9075 /* Cocoa.framework */,
 				0BD7FAEB1295DAB300AB9075 /* OpenGL.framework */,
 			);
 			children = (
 				0B9E7FE112B53392001C01F5 /* Info-Saver.plist */,
 				0BD7FC7A1295DCA100AB9075 /* MainMenu.xib */,
-				0BD7F9E61295CF3C00AB9075 /* OpenGL.framework */,
 				089C167DFE841241C02AAC07 /* InfoPlist.strings */,
 			);
 			name = Resources;
 				0BD7FA281295CF7F00AB9075 /* Mesh.h */,
 				F50079790118B23001CA0E54 /* PixelCity_SaverView.h */,
 				F500797A0118B23001CA0E54 /* PixelCity_SaverView.m */,
+				0B857B1812B5A6AB00FFCD60 /* GLString.h */,
+				0B857B1712B5A6AB00FFCD60 /* GLString.m */,
 			);
 			name = Classes;
 			sourceTree = "<group>";
 		1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				0BD7F9E61295CF3C00AB9075 /* OpenGL.framework */,
 				1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */,
 				06F27B2DFFEEEFEF11CA0E56 /* ScreenSaver.framework */,
+				0B8809E212B5695B006947E6 /* AGL.framework */,
 			);
 			name = "Linked Frameworks";
 			sourceTree = "<group>";
 				0BD7FA341295CF7F00AB9075 /* Entity.h in Headers */,
 				0BD7FA361295CF7F00AB9075 /* Light.h in Headers */,
 				0BD7FA381295CF7F00AB9075 /* Mesh.h in Headers */,
+				0B857B1A12B5A6AB00FFCD60 /* GLString.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 				0BD7FA331295CF7F00AB9075 /* Entity.cpp in Sources */,
 				0BD7FA351295CF7F00AB9075 /* Light.cpp in Sources */,
 				0BD7FA371295CF7F00AB9075 /* Mesh.cpp in Sources */,
+				0B857B1912B5A6AB00FFCD60 /* GLString.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

File PixelCity.xcodeproj/project.pbxproj

 	objects = {
 
 /* Begin PBXBuildFile section */
+		0B68EB5A12B53955004E431B /* AGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B68EB5912B53955004E431B /* AGL.framework */; };
+		0B857B5412B5AA5E00FFCD60 /* GLString.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B857B5312B5AA5E00FFCD60 /* GLString.m */; };
 		1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; };
 		8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
 		8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
 
 /* Begin PBXFileReference section */
 		089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		0B68EB5912B53955004E431B /* AGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AGL.framework; path = System/Library/Frameworks/AGL.framework; sourceTree = SDKROOT; };
+		0B857B5212B5AA5E00FFCD60 /* GLString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLString.h; sourceTree = "<group>"; };
+		0B857B5312B5AA5E00FFCD60 /* GLString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLString.m; sourceTree = "<group>"; };
 		1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
 		13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
 		1DDD58150DA1D0A300B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = "<group>"; };
 			files = (
 				8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
 				FB409C89101F70AB00E36B1D /* OpenGL.framework in Frameworks */,
+				0B68EB5A12B53955004E431B /* AGL.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		080E96DDFE201D6D7F000001 /* Classes */ = {
 			isa = PBXGroup;
 			children = (
+				0B857B5212B5AA5E00FFCD60 /* GLString.h */,
+				0B857B5312B5AA5E00FFCD60 /* GLString.m */,
 				FB409C4C101F6ED700E36B1D /* Deco.cpp */,
 				FB409C4D101F6ED700E36B1D /* Deco.h */,
 				FB409C6B101F6EEE00E36B1D /* Sky.cpp */,
 				29B97324FDCFA39411CA2CEA /* AppKit.framework */,
 				13E42FB307B3F0F600E4EEF1 /* CoreData.framework */,
 				29B97325FDCFA39411CA2CEA /* Foundation.framework */,
+				0B68EB5912B53955004E431B /* AGL.framework */,
 			);
 			name = "Other Frameworks";
 			sourceTree = "<group>";
 				FB409C77101F6EEE00E36B1D /* Texture.cpp in Sources */,
 				FB409C78101F6EEE00E36B1D /* Visible.cpp in Sources */,
 				FB409C79101F6EEE00E36B1D /* World.cpp in Sources */,
+				0B857B5412B5AA5E00FFCD60 /* GLString.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

File PixelCityView.m

     return [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes] autorelease];
 }
 
+- (void)animationTimer:(NSTimer *)timer
+{
+    [self setNeedsDisplay:YES];
+}
+
+- (void) awakeFromNib {
+    glView = self;
+    
+    // start animation timer
+    timer = [NSTimer timerWithTimeInterval:(1.0f/60.0f) target:self selector:@selector(animationTimer:) userInfo:nil repeats:YES];
+    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
+}
+
 - (void)setFrameSize:(NSSize)newSize
 {
     [super setFrameSize:newSize];
   CarUpdate ();
   RenderUpdate ();
   [[self openGLContext] flushBuffer];
-
 }
 
 - (BOOL)acceptsFirstResponder 
     case 'f': RenderFPSToggle (); break;
     case 'g': RenderFogToggle (); break;
     case 't': RenderFlatToggle (); break;
+    case 'h': RenderHelpToggle (); break;
     //Dev mode keys
     case 'c': CameraAutoToggle ();  break;
     case 'b': CameraNextBehavior (); break;
 #include <stdarg.h>
 #include <math.h>
 
+#include "AGL/agl.h"				// Use Apple's extensions to OpenGL
 #include <OpenGL/OpenGL.h>
 #include <OpenGL/glu.h>
+#include <OpenGL/glext.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/time.h>
 
 #include "gltypes.h"
+#include "GLString.h"
 #include "entity.h"
 #include "car.h"
 #include "camera.h"
 		  return;						
   va_start(ap, fmt);		
   vsprintf(text, fmt, ap);				
-  va_end(ap);		
-  glPushAttrib(GL_LIST_BIT);				
-  glListBase(fonts[font % FONT_COUNT].base_char - 32);
-  glColor3fv (&color.red);
-	glRasterPos2i (x, y);
-  glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
-  glPopAttrib();
+  va_end(ap);
+
+  NSMutableDictionary *attribs = [NSMutableDictionary dictionary];
+  [attribs setObject: [NSFont fontWithName: [NSString stringWithCString:fonts[font % FONT_COUNT].name
+                                                               encoding:NSUTF8StringEncoding]
+                                      size: 20.0f]
+              forKey: NSFontAttributeName];
+  [attribs setObject: [NSColor colorWithDeviceRed:color.red
+                                            green:color.green
+                                             blue:color.blue
+                                            alpha:color.alpha]
+              forKey: NSForegroundColorAttributeName];
+
+  GLString *glString = [[GLString alloc]initWithString:[NSString stringWithCString:text encoding:NSUTF8StringEncoding]
+                                        withAttributes:attribs];
+  [glString drawAtPoint:NSMakePoint(x, y)];
+  [glString release];
 }
 
 /*-----------------------------------------------------------------------------
 
 void RenderInit (void)
 {
-
-//  HWND              hWnd;
-//	unsigned		      PixelFormat;
-//  HFONT	            font;		
-//	HFONT	            oldfont;
-//
-//  hWnd = WinHwnd ();
-//  if (!(hDC = GetDC (hWnd))) 
-//		YOUFAIL ("Can't Create A GL Device Context.") ;
-//	if (!(PixelFormat = ChoosePixelFormat(hDC,&pfd)))
-//		YOUFAIL ("Can't Find A Suitable PixelFormat.") ;
-//  if(!SetPixelFormat(hDC,PixelFormat,&pfd))
-//		YOUFAIL ("Can't Set The PixelFormat.");
-//	if (!(hRC = wglCreateContext (hDC)))	
-//		YOUFAIL ("Can't Create A GL Rendering Context.");
-//  if(!wglMakeCurrent(hDC,hRC))	
-//		YOUFAIL ("Can't Activate The GL Rendering Context.");
-//  //Load the fonts for printing debug info to the window.
-//  for (int i = 0; i < FONT_COUNT; i++) {
-//	  fonts[i].base_char = glGenLists(96); 
-//	  font = CreateFont (FONT_SIZE,	0, 0,	0,	
-//				  FW_BOLD, FALSE,	FALSE, FALSE,	DEFAULT_CHARSET,	OUT_TT_PRECIS,		
-//				  CLIP_DEFAULT_PRECIS,	ANTIALIASED_QUALITY, FF_DONTCARE|DEFAULT_PITCH,
-//				  fonts[i].name);
-//	  oldfont = (HFONT)SelectObject(hDC, font);	
-//	  wglUseFontBitmaps(hDC, 32, 96, fonts[i].base_char);
-//	  SelectObject(hDC, oldfont);
-//	  DeleteObject(font);		
-//  }
   //If the program is running for the first time, set the defaults.
   if (!IniInt ("SetDefaults")) {
     IniIntSet ("SetDefaults", 1);
   "Financial",
   "Industrial",
   "Media",
+  "Latte",
   "Materials",
   "Foods",
   "Networks",
   "Co",
   "World",
   ".Com",
+  ".ca",
   " USA",
   " Ltd.",
   "Net",