2 //metadoc Font copyright Steve Dekorte, 2004
3 //metadoc Font license BSD revised
4 //metadoc Font category Graphics
5 /*metadoc Font description
6 The Font object can be used to load and render TypeTrype fonts. Example use;
8 // within a GLUT display callback...
10 timesFont = Font clone open(\"times.ttf\")
11 if (timesFont error, write(\"Error loading font: \", timesFont error, \"\n\"); return)
12 timesFont setPointSize(16)
14 timesFont draw(\"This is a test.\")
17 <b>Rendering fonts using OpenGL textures</b>
19 Smaller fonts (those having a point size around 30 or smaller, depending on the font) will automatically be cached in and rendered from a texture. This technique is very fast and should support rendering speeds as fast (or faster than) those of typical desktop font rendering systems. Larger font sizes(due to texture memory constraints) will be rendered to a pixelmap when displayed. Thanks to Mike Austin for implementing the font texturing system.
31 #include "FreeTypeErrorCodes.h"
32 #include <freetype/ftglyph.h>
35 #define DATA(self) ((IoFontData *)IoObject_dataPointer(self))
37 IoTag
*IoFont_newTag(void *state
)
39 IoTag
*tag
= IoTag_newWithName_("Font");
40 IoTag_state_(tag
, state
);
41 IoTag_cloneFunc_(tag
, (IoTagCloneFunc
*)IoFont_rawClone
);
42 IoTag_freeFunc_(tag
, (IoTagFreeFunc
*)IoFont_free
);
43 IoTag_markFunc_(tag
, (IoTagMarkFunc
*)IoFont_mark
);
47 IoFont
*IoFont_proto( void *state
)
49 IoObject
*self
= IoObject_new(state
);
50 IoObject_tag_(self
, IoFont_newTag(state
));
52 IoObject_setDataPointer_(self
, calloc(1, sizeof(IoFontData
)));
53 DATA(self
)->path
= IOSYMBOL(".");
54 DATA(self
)->font
= GLFont_new();
55 DATA(self
)->isProto
= 1;
56 IoState_registerProtoWithFunc_(state
, self
, IoFont_proto
);
59 IoMethodTable methodTable
[] = {
60 {"open", IoFont_open
},
62 {"setPath", IoFont_setPath
},
63 {"path", IoFont_path
},
65 {"setPixelSize", IoFont_setPixelSize
},
66 {"pixelSize", IoFont_pixelSize
},
68 {"drawString", IoFont_drawString
},
69 {"widthOfString", IoFont_lengthOfString
},
70 {"widthOfCharacter", IoFont_lengthOfCharacter
},
71 {"pixelHeight", IoFont_fontHeight
},
72 {"isTextured", IoFont_isTextured
},
73 {"error", IoFont_error
},
74 {"stringIndexAtWidth", IoFont_stringIndexAtWidth
},
77 IoObject_addMethodTable_(self
, methodTable
);
83 IoFont
*IoFont_rawClone(IoFont
*proto
)
85 IoObject
*self
= IoObject_rawClonePrimitive(proto
);
86 IoObject_setDataPointer_(self
, cpalloc(IoObject_dataPointer(proto
), sizeof(IoFontData
)));
87 DATA(self
)->font
= GLFont_new();
88 DATA(self
)->isProto
= 0;
92 IoFont
*IoFont_new(void *state
)
94 IoObject
*proto
= IoState_protoWithInitFunction_(state
, IoFont_proto
);
95 return IOCLONE(proto
);
98 /* -------------------------------------------------------------------------- */
100 void IoFont_free( IoFont
*self
)
102 GLFont_free( DATA(self
)->font
);
103 if (DATA(self
)->isProto
) { GLFont_done(); }
107 void IoFont_mark( IoFont
*self
)
109 IoObject_shouldMark( (IoObject
*)DATA(self
)->path
);
112 /* -------------------------------------------------------------------------- */
114 IoObject
*IoFont_clone(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
116 IoFont
*newObject
= IoFont_new(IOSTATE
);
117 DATA(newObject
)->path
= DATA(self
)->path
;
121 IoObject
*IoFont_setPath(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
123 /*doc Font setPath(aString)
124 Sets the Font path. Returns self.
127 DATA(self
)->path
= IOREF(IoMessage_locals_seqArgAt_(m
, locals
, 0));
131 IoObject
*IoFont_path(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
134 Returns the Font path.
136 return DATA(self
)->path
;
139 IoObject
*IoFont_setPixelSize(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
141 /*doc Font setPixelSize(aNumber)
142 Sets the size of the font in pixels. Returns self.
145 int size
= IoMessage_locals_intArgAt_(m
, locals
, 0);
146 GLFont_setPixelSize(DATA(self
)->font
, size
);
150 IoObject
*IoFont_pixelSize(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
153 Returns the font's pixelSize.
156 return IONUMBER(GLFont_pixelSize( DATA(self
)->font
));
159 void IoFont_checkError(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
161 const char *e
= GLFont_error(DATA(self
)->font
);
165 IoState_error_(IOSTATE
, m
, "Font %s", e
);
169 IoObject
*IoFont_open(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
171 /*doc Font open(optionalPath)
172 Opens the font. Sets path using optionalPath if supplied. Returns self.
175 if (IoMessage_argCount(m
) > 0)
177 DATA(self
)->path
= IOREF(IoMessage_locals_seqArgAt_(m
, locals
, 0));
180 GLFont_loadFont( DATA(self
)->font
, CSTRING(DATA(self
)->path
) );
181 IoFont_checkError(self
, locals
, m
);
185 IoObject
*IoFont_lengthOfString(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
187 /*doc Font widthOfString(aString)
188 Returns a Number with the width that aString would render
189 to with the receiver's current settings.
192 IoSymbol
*text
= IoMessage_locals_seqArgAt_(m
, locals
, 0);
194 int max
= IoSeq_rawSize(text
);
197 if (IoMessage_argCount(m
) == 2)
199 startIndex
= IoNumber_asInt(IoMessage_locals_numberArgAt_(m
, locals
, 1));
200 if (startIndex
> max
) startIndex
= max
;
203 if (IoMessage_argCount(m
) > 2)
205 endIndex
= IoNumber_asInt(IoMessage_locals_numberArgAt_(m
, locals
, 2));
206 if (startIndex
> max
) endIndex
= max
;
209 return IONUMBER( GLFont_lengthOfString( DATA(self
)->font
, CSTRING(text
), startIndex
, endIndex
) );
212 IoObject
*IoFont_lengthOfCharacter(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
214 /*doc Font lengthOfCharacter(aNumber)
215 Returns the width of the character specified by aNumber in the receiver's font.
218 unsigned char c
= IoNumber_asInt(IoMessage_locals_numberArgAt_(m
, locals
, 0));
219 return IONUMBER( GLFont_lengthOfCharacter_( DATA(self
)->font
, c
) );
222 IoObject
*IoFont_fontHeight(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
224 /*doc Font fontHeight
225 Returns the height of the font measured in pixels.
228 return (IoObject
*)IONUMBER( GLFont_fontHeight( DATA(self
)->font
) );
231 IoObject
*IoFont_stringIndexAtWidth(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
233 /*doc Font stringIndexAtWidth(aString, startIndex, width)
234 Returns the max index of the character in String (starting at startIndex)
235 that fits within width.
238 IoSymbol
*text
= IoMessage_locals_seqArgAt_(m
, locals
, 0);
241 //IOASSERT(IoMessage_argCount(m) == 2, "requires 3 arguments");
242 startIndex
= IoNumber_asInt(IoMessage_locals_numberArgAt_(m
, locals
, 1));
243 if (startIndex
> (int)IoSeq_rawSize(text
)) startIndex
= (int)IoSeq_rawSize(text
);
245 width
= IoNumber_asInt(IoMessage_locals_numberArgAt_(m
, locals
, 2));
247 return IONUMBER(GLFont_stringIndexAtWidth(DATA(self
)->font
, CSTRING(text
), startIndex
, width
));
250 IoObject
*IoFont_drawString(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
252 /*doc Font drawString(aString, optionalStartIndex, optionalEndIndex)
253 Draws aString using the optional start and end indexes, if supplied. Returns self.
255 Note; Fonts are draw as RGBA pixel maps. These blending options are recommended:
258 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
262 IoSymbol
*textString
= IoMessage_locals_seqArgAt_(m
, locals
, 0);
266 if (IoMessage_argCount(m
) > 1)
268 startIndex
= IoNumber_asInt(IoMessage_locals_numberArgAt_(m
, locals
, 1));
269 if (startIndex
> (int)IoSeq_rawSize(textString
)) startIndex
= (int)IoSeq_rawSize(textString
);
272 if (IoMessage_argCount(m
) > 2)
274 endIndex
= IoNumber_asInt(IoMessage_locals_numberArgAt_(m
, locals
, 2));
278 endIndex
= IoSeq_rawSize(textString
);
281 GLFont_drawString(DATA(self
)->font
, CSTRING(textString
) , startIndex
, endIndex
);
282 IoFont_checkError(self
, locals
, m
);
286 IoObject
*IoFont_isTextured(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
288 /*doc Font isTextured
289 Returns true if the font is being cached in and rendered from a texture, false otherwise.
292 return IOBOOL(self
, GLFont_isTextured(DATA(self
)->font
));
295 IoObject
*IoFont_error(IoFont
*self
, IoObject
*locals
, IoMessage
*m
)
298 Returns the current error string or nil if there is no error.
301 const char *e
= GLFont_error(DATA(self
)->font
);
302 return strlen(e
) ? (IoObject
*)IOSYMBOL((char *)e
) : IONIL(self
);