50 |
- (FT_Vector) position; |
- (FT_Vector) position; |
51 |
@end |
@end |
52 |
|
|
53 |
|
/** |
54 |
|
* UiGlyph is a private class, that stores a glyph, and its position |
55 |
|
* in the window. |
56 |
|
*/ |
57 |
@implementation UiGlyph |
@implementation UiGlyph |
58 |
|
|
59 |
|
/** |
60 |
|
* Returns an autoreleased glyph container, containing glyph, |
61 |
|
* and position in 1/64th of point. |
62 |
|
*/ |
63 |
+ (id) glyphWithGlyph: (FT_Glyph)glyph |
+ (id) glyphWithGlyph: (FT_Glyph)glyph |
64 |
position: (FT_Vector)position |
position: (FT_Vector)position |
65 |
{ |
{ |
67 |
position: position]); |
position: position]); |
68 |
} |
} |
69 |
|
|
70 |
|
/** |
71 |
|
* Initialize the glyph container, containing glyph, |
72 |
|
* and position in 1/64th of point. |
73 |
|
*/ |
74 |
- (id) initWithGlyph: (FT_Glyph)glyph |
- (id) initWithGlyph: (FT_Glyph)glyph |
75 |
position: (FT_Vector)position |
position: (FT_Vector)position |
76 |
{ |
{ |
84 |
return self; |
return self; |
85 |
} |
} |
86 |
|
|
87 |
|
|
88 |
|
/** |
89 |
|
* Returns the glyph. |
90 |
|
*/ |
91 |
- (FT_Glyph) glyph |
- (FT_Glyph) glyph |
92 |
{ |
{ |
93 |
return _glyph; |
return _glyph; |
94 |
} |
} |
95 |
|
|
96 |
|
/** |
97 |
|
* Returns the position of the glyph, in 1/64th of point. |
98 |
|
*/ |
99 |
- (FT_Vector) position |
- (FT_Vector) position |
100 |
{ |
{ |
101 |
return _position; |
return _position; |
104 |
@end |
@end |
105 |
|
|
106 |
|
|
107 |
|
/** |
108 |
|
* UiText implements an OpenGL text displaying library, using OpenGL |
109 |
|
* and FreeType to display anti-aliased text. |
110 |
|
*/ |
111 |
@implementation UiText |
@implementation UiText |
112 |
|
|
113 |
static FT_Library _library; |
static FT_Face _face; |
|
static FT_Face _face; |
|
114 |
|
|
115 |
|
/** |
116 |
|
* Initialise the FreeType library, and loads the default font. |
117 |
|
*/ |
118 |
+ (void) initialize |
+ (void) initialize |
119 |
{ |
{ |
120 |
|
FT_Library _library; |
121 |
|
|
122 |
if (FT_Init_FreeType (&_library)) |
if (FT_Init_FreeType (&_library)) |
123 |
{ |
{ |
124 |
perror ("Library initialisation failed"); |
perror ("Library initialisation failed"); |
129 |
{ |
{ |
130 |
perror ("Loading face failed"); |
perror ("Loading face failed"); |
131 |
abort (); |
abort (); |
132 |
} |
} |
|
|
|
|
if (FT_Set_Pixel_Sizes (_face, 0, 256)) |
|
|
{ |
|
|
perror ("Setting char size failed"); |
|
|
abort (); |
|
|
} |
|
133 |
} |
} |
134 |
|
|
135 |
|
/** |
136 |
|
* Initialise the glyphes array with text, storring the glyph for each |
137 |
|
* character. |
138 |
|
*/ |
139 |
- (void) _initGlyphesWithText: (NSString *)text |
- (void) _initGlyphesWithText: (NSString *)text |
140 |
{ |
{ |
141 |
|
|
153 |
FT_UInt glyph_index; |
FT_UInt glyph_index; |
154 |
FT_Glyph glyph; |
FT_Glyph glyph; |
155 |
|
|
156 |
|
if ([text characterAtIndex: i] == '\n') |
157 |
|
{ |
158 |
|
pen.x = 0; |
159 |
|
pen.y -= (int)(_face->height * 1.24); |
160 |
|
previous = 0; |
161 |
|
continue; |
162 |
|
} |
163 |
|
|
164 |
glyph_index = FT_Get_Char_Index (_face, [text characterAtIndex: i]); |
glyph_index = FT_Get_Char_Index (_face, [text characterAtIndex: i]); |
165 |
|
|
166 |
if (use_kerning && previous && glyph_index) |
if (use_kerning && previous && glyph_index) |
170 |
FT_Get_Kerning (_face, previous, glyph_index, |
FT_Get_Kerning (_face, previous, glyph_index, |
171 |
ft_kerning_default, &delta); |
ft_kerning_default, &delta); |
172 |
|
|
173 |
pen.x += delta.x >> 6; |
pen.x += delta.x; |
174 |
} |
} |
175 |
|
|
176 |
if (FT_Load_Glyph (_face, glyph_index, FT_LOAD_DEFAULT)) |
if (FT_Load_Glyph (_face, glyph_index, FT_LOAD_DEFAULT)) |
180 |
if (FT_Get_Glyph (_face->glyph, &glyph)) |
if (FT_Get_Glyph (_face->glyph, &glyph)) |
181 |
continue; |
continue; |
182 |
|
|
183 |
[_glyphes addObject: [UiGlyph glyphWithGlyph: glyph |
if (!isspace ([text characterAtIndex: i])) |
184 |
position: pen]]; |
{ |
185 |
|
[_glyphes addObject: [UiGlyph glyphWithGlyph: glyph |
186 |
|
position: pen]]; |
187 |
|
} |
188 |
|
|
189 |
pen.x += slot->advance.x >> 6; |
pen.x += slot->advance.x; |
190 |
|
|
191 |
previous = glyph_index; |
previous = glyph_index; |
192 |
} |
} |
193 |
} |
} |
194 |
|
|
195 |
|
|
196 |
|
/** |
197 |
|
* Initialiaze the text with text, and the characters height in points. |
198 |
|
*/ |
199 |
- (id) initWithText: (NSString *)text |
- (id) initWithText: (NSString *)text |
200 |
|
height: (unsigned)height |
201 |
{ |
{ |
202 |
NSParameterAssert (text); |
NSParameterAssert (text); |
203 |
NSParameterAssert ([text length] != 0); |
NSParameterAssert ([text length] != 0); |
204 |
|
NSParameterAssert (height > 0); |
205 |
|
|
206 |
self = [super init]; |
self = [super init]; |
207 |
if (self != nil) |
if (self != nil) |
208 |
{ |
{ |
209 |
|
if (FT_Set_Char_Size (_face, 0, height << 6, 0, 0)) |
210 |
|
{ |
211 |
|
perror ("Setting char size failed"); |
212 |
|
abort (); |
213 |
|
} |
214 |
|
|
215 |
_glyphes = [NSMutableArray arrayWithCapacity: [text length]]; |
_glyphes = [NSMutableArray arrayWithCapacity: [text length]]; |
216 |
[self _initGlyphesWithText: text]; |
[self _initGlyphesWithText: text]; |
217 |
} |
} |
219 |
return self; |
return self; |
220 |
} |
} |
221 |
|
|
222 |
|
- (void) dealloc |
223 |
|
{ |
224 |
|
RELEASE (_glyphes); |
225 |
|
[super dealloc]; |
226 |
|
} |
227 |
|
|
228 |
|
/** |
229 |
|
* Clamp the image size, to an acceptable OpenGL texture size, |
230 |
|
* ie : the nearest power of two. |
231 |
|
*/ |
232 |
static int inline |
static int inline |
233 |
_texture_size (int size) |
_texture_size (int size) |
234 |
{ |
{ |
235 |
NSCParameterAssert (size > 0); |
NSCParameterAssert (size > 0); |
236 |
|
|
237 |
|
/* very inneficient way to calculate the size, |
238 |
|
* except if we are using small sizes |
239 |
|
*/ |
240 |
int texture_size = 2; |
int texture_size = 2; |
241 |
while (texture_size < size) |
while (texture_size < size) |
242 |
texture_size = texture_size << 1; |
texture_size = texture_size << 1; |
244 |
return texture_size; |
return texture_size; |
245 |
} |
} |
246 |
|
|
247 |
|
/** |
248 |
|
* Map the glyph bitmap as an OpenGL texture. The texture size will be clamped |
249 |
|
* to the nearest power of two. |
250 |
|
*/ |
251 |
static void inline |
static void inline |
252 |
_generate_texture (const FT_Bitmap *bitmap) |
_map_texture (const FT_Bitmap *bitmap) |
253 |
{ |
{ |
254 |
NSCParameterAssert (bitmap); |
NSCParameterAssert (bitmap); |
255 |
NSCParameterAssert (bitmap->pixel_mode == FT_PIXEL_MODE_GRAY); |
NSCParameterAssert (bitmap->pixel_mode == FT_PIXEL_MODE_GRAY); |
270 |
GL_ALPHA, GL_UNSIGNED_BYTE, bitmap->buffer); |
GL_ALPHA, GL_UNSIGNED_BYTE, bitmap->buffer); |
271 |
} |
} |
272 |
|
|
273 |
|
/** |
274 |
|
* Draw the glyph bitmap using an OpenGL texture. |
275 |
|
*/ |
276 |
static void inline |
static void inline |
277 |
_draw_bitmap (const FT_Bitmap *bitmap, FT_Int left, FT_Int top) |
_draw_bitmap (const FT_Bitmap *bitmap, FT_Int left, FT_Int top) |
278 |
{ |
{ |
279 |
NSCParameterAssert (bitmap); |
NSCParameterAssert (bitmap); |
280 |
|
|
281 |
_generate_texture (bitmap); |
_map_texture (bitmap); |
282 |
|
|
283 |
glPushMatrix(); |
glPushMatrix(); |
284 |
glTranslatef (left, top, 0); |
glTranslatef (left, top, 0); |
304 |
} |
} |
305 |
|
|
306 |
|
|
307 |
|
/** |
308 |
|
* Display the text, using OpenGL textures. Use glTranslate if you want to |
309 |
|
* position it. |
310 |
|
*/ |
311 |
- (void) display |
- (void) display |
312 |
{ |
{ |
313 |
NSEnumerator *enumerator = [_glyphes objectEnumerator]; |
NSEnumerator *enumerator = [_glyphes objectEnumerator]; |
324 |
FT_BitmapGlyph bit = (FT_BitmapGlyph)image; |
FT_BitmapGlyph bit = (FT_BitmapGlyph)image; |
325 |
|
|
326 |
_draw_bitmap (&bit->bitmap, |
_draw_bitmap (&bit->bitmap, |
327 |
pen.x + bit->left, |
(pen.x >> 6) + bit->left, |
328 |
pen.y + bit->top - bit->bitmap.rows + 200); |
(pen.y >> 6) + bit->top - bit->bitmap.rows); |
329 |
|
|
330 |
FT_Done_Glyph (image); |
FT_Done_Glyph (image); |
331 |
} |
} |
332 |
|
|
333 |
} |
} |
334 |
|
|
335 |
|
/** |
336 |
|
* Returns the size of bounding box of the text. |
337 |
|
*/ |
338 |
- (NSSize) size |
- (NSSize) size |
339 |
{ |
{ |
340 |
FT_BBox bbox = {0, 0, 0, 0}; |
FT_BBox bbox = {0, 0, 0, 0}; |