Mercurial > hg > forks > bilotrip-mj12
comparison src/texture-font.c @ 0:785057719d9b
Import.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 05 Aug 2013 12:25:43 +0300 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:785057719d9b |
---|---|
1 /* =========================================================================== | |
2 * Freetype GL - A C OpenGL Freetype engine | |
3 * Platform: Any | |
4 * WWW: http://code.google.com/p/freetype-gl/ | |
5 * ---------------------------------------------------------------------------- | |
6 * Copyright 2011,2012 Nicolas P. Rougier. All rights reserved. | |
7 * | |
8 * Redistribution and use in source and binary forms, with or without | |
9 * modification, are permitted provided that the following conditions are met: | |
10 * | |
11 * 1. Redistributions of source code must retain the above copyright notice, | |
12 * this list of conditions and the following disclaimer. | |
13 * | |
14 * 2. Redistributions in binary form must reproduce the above copyright | |
15 * notice, this list of conditions and the following disclaimer in the | |
16 * documentation and/or other materials provided with the distribution. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR | |
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
21 * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 * | |
29 * The views and conclusions contained in the software and documentation are | |
30 * those of the authors and should not be interpreted as representing official | |
31 * policies, either expressed or implied, of Nicolas P. Rougier. | |
32 * ============================================================================ | |
33 */ | |
34 #include <ft2build.h> | |
35 #include FT_FREETYPE_H | |
36 #include FT_STROKER_H | |
37 // #include FT_ADVANCES_H | |
38 #include FT_LCD_FILTER_H | |
39 #include <stdint.h> | |
40 #include <stdlib.h> | |
41 #include <stdio.h> | |
42 #include <assert.h> | |
43 #include <math.h> | |
44 #include <wchar.h> | |
45 #include "platform.h" | |
46 #include "texture-font.h" | |
47 | |
48 #undef __FTERRORS_H__ | |
49 #define FT_ERRORDEF( e, v, s ) { e, s }, | |
50 #define FT_ERROR_START_LIST { | |
51 #define FT_ERROR_END_LIST { 0, 0 } }; | |
52 const struct { | |
53 int code; | |
54 const char* message; | |
55 } FT_Errors[] = | |
56 #include FT_ERRORS_H | |
57 | |
58 | |
59 | |
60 | |
61 // ------------------------------------------------- texture_font_load_face --- | |
62 int | |
63 texture_font_load_face( FT_Library * library, | |
64 const char * filename, | |
65 const float size, | |
66 FT_Face * face ) | |
67 { | |
68 size_t hres = 64; | |
69 FT_Error error; | |
70 FT_Matrix matrix = { (int)((1.0/hres) * 0x10000L), | |
71 (int)((0.0) * 0x10000L), | |
72 (int)((0.0) * 0x10000L), | |
73 (int)((1.0) * 0x10000L) }; | |
74 | |
75 assert( library ); | |
76 assert( filename ); | |
77 assert( size ); | |
78 | |
79 /* Initialize library */ | |
80 error = FT_Init_FreeType( library ); | |
81 if( error ) | |
82 { | |
83 fprintf(stderr, "FT_Error (0x%02x) : %s\n", | |
84 FT_Errors[error].code, FT_Errors[error].message); | |
85 return 0; | |
86 } | |
87 | |
88 /* Load face */ | |
89 error = FT_New_Face( *library, filename, 0, face ); | |
90 if( error ) | |
91 { | |
92 fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", | |
93 __LINE__, FT_Errors[error].code, FT_Errors[error].message); | |
94 FT_Done_FreeType( *library ); | |
95 return 0; | |
96 } | |
97 | |
98 /* Select charmap */ | |
99 error = FT_Select_Charmap( *face, FT_ENCODING_UNICODE ); | |
100 if( error ) | |
101 { | |
102 fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", | |
103 __LINE__, FT_Errors[error].code, FT_Errors[error].message ); | |
104 FT_Done_Face( *face ); | |
105 FT_Done_FreeType( *library ); | |
106 return 0; | |
107 } | |
108 | |
109 /* Set char size */ | |
110 error = FT_Set_Char_Size( *face, (int)(size*64), 0, 72*hres, 72 ); | |
111 if( error ) | |
112 { | |
113 fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", | |
114 __LINE__, FT_Errors[error].code, FT_Errors[error].message ); | |
115 FT_Done_Face( *face ); | |
116 FT_Done_FreeType( *library ); | |
117 return 0; | |
118 } | |
119 | |
120 /* Set transform matrix */ | |
121 FT_Set_Transform( *face, &matrix, NULL ); | |
122 | |
123 return 1; | |
124 } | |
125 | |
126 | |
127 // ------------------------------------------------------ texture_glyph_new --- | |
128 texture_glyph_t * | |
129 texture_glyph_new( void ) | |
130 { | |
131 texture_glyph_t *self = (texture_glyph_t *) malloc( sizeof(texture_glyph_t) ); | |
132 if( self == NULL) | |
133 { | |
134 fprintf( stderr, | |
135 "line %d: No more memory for allocating data\n", __LINE__ ); | |
136 exit( EXIT_FAILURE ); | |
137 } | |
138 self->id = 0; | |
139 self->width = 0; | |
140 self->height = 0; | |
141 self->outline_type = 0; | |
142 self->outline_thickness = 0.0; | |
143 self->offset_x = 0; | |
144 self->offset_y = 0; | |
145 self->advance_x = 0.0; | |
146 self->advance_y = 0.0; | |
147 self->s0 = 0.0; | |
148 self->t0 = 0.0; | |
149 self->s1 = 0.0; | |
150 self->t1 = 0.0; | |
151 self->kerning = vector_new( sizeof(kerning_t) ); | |
152 return self; | |
153 } | |
154 | |
155 | |
156 // --------------------------------------------------- texture_glyph_delete --- | |
157 void | |
158 texture_glyph_delete( texture_glyph_t *self ) | |
159 { | |
160 assert( self ); | |
161 vector_delete( self->kerning ); | |
162 free( self ); | |
163 } | |
164 | |
165 // ---------------------------------------------- texture_glyph_get_kerning --- | |
166 float | |
167 texture_glyph_get_kerning( const texture_glyph_t * self, | |
168 const wchar_t charcode ) | |
169 { | |
170 size_t i; | |
171 | |
172 assert( self ); | |
173 for( i=0; i<vector_size(self->kerning); ++i ) | |
174 { | |
175 kerning_t * kerning = (kerning_t *) vector_get( self->kerning, i ); | |
176 if( kerning->charcode == charcode ) | |
177 { | |
178 return kerning->kerning; | |
179 } | |
180 } | |
181 return 0; | |
182 } | |
183 | |
184 | |
185 // ------------------------------------------ texture_font_generate_kerning --- | |
186 void | |
187 texture_font_generate_kerning( texture_font_t *self ) | |
188 { | |
189 size_t i, j; | |
190 FT_Library library; | |
191 FT_Face face; | |
192 FT_UInt glyph_index, prev_index; | |
193 texture_glyph_t *glyph, *prev_glyph; | |
194 FT_Vector kerning; | |
195 | |
196 assert( self ); | |
197 | |
198 /* Load font */ | |
199 if( !texture_font_load_face( &library, self->filename, self->size, &face ) ) | |
200 { | |
201 return; | |
202 } | |
203 | |
204 /* For each glyph couple combination, check if kerning is necessary */ | |
205 /* Starts at index 1 since 0 is for the special backgroudn glyph */ | |
206 for( i=1; i<self->glyphs->size; ++i ) | |
207 { | |
208 glyph = *(texture_glyph_t **) vector_get( self->glyphs, i ); | |
209 glyph_index = FT_Get_Char_Index( face, glyph->charcode ); | |
210 vector_clear( glyph->kerning ); | |
211 | |
212 for( j=1; j<self->glyphs->size; ++j ) | |
213 { | |
214 prev_glyph = *(texture_glyph_t **) vector_get( self->glyphs, j ); | |
215 prev_index = FT_Get_Char_Index( face, prev_glyph->charcode ); | |
216 FT_Get_Kerning( face, prev_index, glyph_index, FT_KERNING_UNFITTED, &kerning ); | |
217 // printf("%c(%d)-%c(%d): %ld\n", | |
218 // prev_glyph->charcode, prev_glyph->charcode, | |
219 // glyph_index, glyph_index, kerning.x); | |
220 if( kerning.x ) | |
221 { | |
222 // 64 * 64 because of 26.6 encoding AND the transform matrix used | |
223 // in texture_font_load_face (hres = 64) | |
224 kerning_t k = {prev_glyph->charcode, kerning.x / (float)(64.0f*64.0f)}; | |
225 vector_push_back( glyph->kerning, &k ); | |
226 } | |
227 } | |
228 } | |
229 FT_Done_Face( face ); | |
230 FT_Done_FreeType( library ); | |
231 } | |
232 | |
233 | |
234 // ------------------------------------------------------- texture_font_new --- | |
235 texture_font_t * | |
236 texture_font_new( texture_atlas_t * atlas, | |
237 const char * filename, | |
238 const float size) | |
239 { | |
240 texture_font_t *self = (texture_font_t *) malloc( sizeof(texture_font_t) ); | |
241 FT_Library library; | |
242 FT_Face face; | |
243 FT_Size_Metrics metrics; | |
244 | |
245 assert( filename ); | |
246 assert( size ); | |
247 | |
248 if( self == NULL) | |
249 { | |
250 fprintf( stderr, | |
251 "line %d: No more memory for allocating data\n", __LINE__ ); | |
252 exit( EXIT_FAILURE ); | |
253 } | |
254 self->glyphs = vector_new( sizeof(texture_glyph_t *) ); | |
255 self->atlas = atlas; | |
256 self->height = 0; | |
257 self->ascender = 0; | |
258 self->descender = 0; | |
259 self->filename = strdup( filename ); | |
260 self->size = size; | |
261 self->outline_type = 0; | |
262 self->outline_thickness = 0.0; | |
263 self->hinting = 1; | |
264 self->kerning = 1; | |
265 self->filtering = 1; | |
266 // FT_LCD_FILTER_LIGHT is (0x00, 0x55, 0x56, 0x55, 0x00) | |
267 // FT_LCD_FILTER_DEFAULT is (0x10, 0x40, 0x70, 0x40, 0x10) | |
268 self->lcd_weights[0] = 0x10; | |
269 self->lcd_weights[1] = 0x40; | |
270 self->lcd_weights[2] = 0x70; | |
271 self->lcd_weights[3] = 0x40; | |
272 self->lcd_weights[4] = 0x10; | |
273 | |
274 /* Get font metrics at high resolution */ | |
275 | |
276 if( !texture_font_load_face( &library, self->filename, self->size*100, &face ) ) | |
277 { | |
278 return self; | |
279 } | |
280 | |
281 // 64 * 64 because of 26.6 encoding AND the transform matrix used | |
282 // in texture_font_load_face (hres = 64) | |
283 self->underline_position = face->underline_position / (float)(64.0f*64.0f) * self->size; | |
284 self->underline_position = round( self->underline_position ); | |
285 if( self->underline_position > -2 ) | |
286 { | |
287 self->underline_position = -2.0; | |
288 } | |
289 | |
290 self->underline_thickness = face->underline_thickness / (float)(64.0f*64.0f) * self->size; | |
291 self->underline_thickness = round( self->underline_thickness ); | |
292 if( self->underline_thickness < 1 ) | |
293 { | |
294 self->underline_thickness = 1.0; | |
295 } | |
296 | |
297 metrics = face->size->metrics; | |
298 self->ascender = (metrics.ascender >> 6) / 100.0; | |
299 self->descender = (metrics.descender >> 6) / 100.0; | |
300 self->height = (metrics.height >> 6) / 100.0; | |
301 self->linegap = self->height - self->ascender + self->descender; | |
302 FT_Done_Face( face ); | |
303 FT_Done_FreeType( library ); | |
304 | |
305 /* -1 is a special glyph */ | |
306 texture_font_get_glyph( self, -1 ); | |
307 | |
308 return self; | |
309 } | |
310 | |
311 | |
312 // ---------------------------------------------------- texture_font_delete --- | |
313 void | |
314 texture_font_delete( texture_font_t *self ) | |
315 { | |
316 size_t i; | |
317 texture_glyph_t *glyph; | |
318 | |
319 assert( self ); | |
320 | |
321 if( self->filename ) | |
322 { | |
323 free( self->filename ); | |
324 } | |
325 | |
326 | |
327 for( i=0; i<vector_size( self->glyphs ); ++i) | |
328 { | |
329 glyph = *(texture_glyph_t **) vector_get( self->glyphs, i ); | |
330 texture_glyph_delete( glyph); | |
331 } | |
332 | |
333 vector_delete( self->glyphs ); | |
334 free( self ); | |
335 } | |
336 | |
337 | |
338 // ----------------------------------------------- texture_font_load_glyphs --- | |
339 size_t | |
340 texture_font_load_glyphs( texture_font_t * self, | |
341 const wchar_t * charcodes ) | |
342 { | |
343 size_t i, x, y, width, height, depth, w, h; | |
344 FT_Library library; | |
345 FT_Error error; | |
346 FT_Face face; | |
347 FT_Glyph ft_glyph; | |
348 FT_GlyphSlot slot; | |
349 FT_Bitmap ft_bitmap; | |
350 | |
351 FT_UInt glyph_index; | |
352 texture_glyph_t *glyph; | |
353 ivec4 region; | |
354 size_t missed = 0; | |
355 | |
356 assert( self ); | |
357 assert( charcodes ); | |
358 | |
359 | |
360 width = self->atlas->width; | |
361 height = self->atlas->height; | |
362 depth = self->atlas->depth; | |
363 | |
364 if( !texture_font_load_face( &library, self->filename, self->size, &face ) ) | |
365 { | |
366 return wcslen(charcodes); | |
367 } | |
368 | |
369 /* Load each glyph */ | |
370 for( i=0; i<wcslen(charcodes); ++i ) | |
371 { | |
372 FT_Int32 flags = 0; | |
373 int ft_bitmap_width = 0; | |
374 int ft_bitmap_rows = 0; | |
375 int ft_bitmap_pitch = 0; | |
376 int ft_glyph_top = 0; | |
377 int ft_glyph_left = 0; | |
378 glyph_index = FT_Get_Char_Index( face, charcodes[i] ); | |
379 // WARNING: We use texture-atlas depth to guess if user wants | |
380 // LCD subpixel rendering | |
381 | |
382 if( self->outline_type > 0 ) | |
383 { | |
384 flags |= FT_LOAD_NO_BITMAP; | |
385 } | |
386 else | |
387 { | |
388 flags |= FT_LOAD_RENDER; | |
389 } | |
390 | |
391 if( !self->hinting ) | |
392 { | |
393 flags |= FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT; | |
394 } | |
395 else | |
396 { | |
397 flags |= FT_LOAD_FORCE_AUTOHINT; | |
398 } | |
399 | |
400 | |
401 if( depth == 3 ) | |
402 { | |
403 FT_Library_SetLcdFilter( library, FT_LCD_FILTER_LIGHT ); | |
404 flags |= FT_LOAD_TARGET_LCD; | |
405 if( self->filtering ) | |
406 { | |
407 FT_Library_SetLcdFilterWeights( library, self->lcd_weights ); | |
408 } | |
409 } | |
410 error = FT_Load_Glyph( face, glyph_index, flags ); | |
411 if( error ) | |
412 { | |
413 fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", | |
414 __LINE__, FT_Errors[error].code, FT_Errors[error].message ); | |
415 FT_Done_Face( face ); | |
416 FT_Done_FreeType( library ); | |
417 return wcslen(charcodes)-i; | |
418 } | |
419 | |
420 | |
421 if( self->outline_type == 0 ) | |
422 { | |
423 slot = face->glyph; | |
424 ft_bitmap = slot->bitmap; | |
425 ft_bitmap_width = slot->bitmap.width; | |
426 ft_bitmap_rows = slot->bitmap.rows; | |
427 ft_bitmap_pitch = slot->bitmap.pitch; | |
428 ft_glyph_top = slot->bitmap_top; | |
429 ft_glyph_left = slot->bitmap_left; | |
430 } | |
431 else | |
432 { | |
433 FT_Stroker stroker; | |
434 FT_BitmapGlyph ft_bitmap_glyph; | |
435 error = FT_Stroker_New( library, &stroker ); | |
436 if( error ) | |
437 { | |
438 fprintf(stderr, "FT_Error (0x%02x) : %s\n", | |
439 FT_Errors[error].code, FT_Errors[error].message); | |
440 FT_Done_Face( face ); | |
441 FT_Stroker_Done( stroker ); | |
442 FT_Done_FreeType( library ); | |
443 return 0; | |
444 } | |
445 FT_Stroker_Set( stroker, | |
446 (int)(self->outline_thickness *64), | |
447 FT_STROKER_LINECAP_ROUND, | |
448 FT_STROKER_LINEJOIN_ROUND, | |
449 0); | |
450 error = FT_Get_Glyph( face->glyph, &ft_glyph); | |
451 if( error ) | |
452 { | |
453 fprintf(stderr, "FT_Error (0x%02x) : %s\n", | |
454 FT_Errors[error].code, FT_Errors[error].message); | |
455 FT_Done_Face( face ); | |
456 FT_Stroker_Done( stroker ); | |
457 FT_Done_FreeType( library ); | |
458 return 0; | |
459 } | |
460 | |
461 if( self->outline_type == 1 ) | |
462 { | |
463 error = FT_Glyph_Stroke( &ft_glyph, stroker, 1 ); | |
464 } | |
465 else if ( self->outline_type == 2 ) | |
466 { | |
467 error = FT_Glyph_StrokeBorder( &ft_glyph, stroker, 0, 1 ); | |
468 } | |
469 else if ( self->outline_type == 3 ) | |
470 { | |
471 error = FT_Glyph_StrokeBorder( &ft_glyph, stroker, 1, 1 ); | |
472 } | |
473 if( error ) | |
474 { | |
475 fprintf(stderr, "FT_Error (0x%02x) : %s\n", | |
476 FT_Errors[error].code, FT_Errors[error].message); | |
477 FT_Done_Face( face ); | |
478 FT_Stroker_Done( stroker ); | |
479 FT_Done_FreeType( library ); | |
480 return 0; | |
481 } | |
482 | |
483 if( depth == 1) | |
484 { | |
485 error = FT_Glyph_To_Bitmap( &ft_glyph, FT_RENDER_MODE_NORMAL, 0, 1); | |
486 if( error ) | |
487 { | |
488 fprintf(stderr, "FT_Error (0x%02x) : %s\n", | |
489 FT_Errors[error].code, FT_Errors[error].message); | |
490 FT_Done_Face( face ); | |
491 FT_Stroker_Done( stroker ); | |
492 FT_Done_FreeType( library ); | |
493 return 0; | |
494 } | |
495 } | |
496 else | |
497 { | |
498 error = FT_Glyph_To_Bitmap( &ft_glyph, FT_RENDER_MODE_LCD, 0, 1); | |
499 if( error ) | |
500 { | |
501 fprintf(stderr, "FT_Error (0x%02x) : %s\n", | |
502 FT_Errors[error].code, FT_Errors[error].message); | |
503 FT_Done_Face( face ); | |
504 FT_Stroker_Done( stroker ); | |
505 FT_Done_FreeType( library ); | |
506 return 0; | |
507 } | |
508 } | |
509 ft_bitmap_glyph = (FT_BitmapGlyph) ft_glyph; | |
510 ft_bitmap = ft_bitmap_glyph->bitmap; | |
511 ft_bitmap_width = ft_bitmap.width; | |
512 ft_bitmap_rows = ft_bitmap.rows; | |
513 ft_bitmap_pitch = ft_bitmap.pitch; | |
514 ft_glyph_top = ft_bitmap_glyph->top; | |
515 ft_glyph_left = ft_bitmap_glyph->left; | |
516 FT_Stroker_Done(stroker); | |
517 } | |
518 | |
519 | |
520 // We want each glyph to be separated by at least one black pixel | |
521 // (for example for shader used in demo-subpixel.c) | |
522 w = ft_bitmap_width/depth + 1; | |
523 h = ft_bitmap_rows + 1; | |
524 region = texture_atlas_get_region( self->atlas, w, h ); | |
525 if ( region.x < 0 ) | |
526 { | |
527 missed++; | |
528 fprintf( stderr, "Texture atlas is full (line %d)\n", __LINE__ ); | |
529 continue; | |
530 } | |
531 w = w - 1; | |
532 h = h - 1; | |
533 x = region.x; | |
534 y = region.y; | |
535 texture_atlas_set_region( self->atlas, x, y, w, h, | |
536 ft_bitmap.buffer, ft_bitmap.pitch ); | |
537 | |
538 glyph = texture_glyph_new( ); | |
539 glyph->charcode = charcodes[i]; | |
540 glyph->width = w; | |
541 glyph->height = h; | |
542 glyph->outline_type = self->outline_type; | |
543 glyph->outline_thickness = self->outline_thickness; | |
544 glyph->offset_x = ft_glyph_left; | |
545 glyph->offset_y = ft_glyph_top; | |
546 glyph->s0 = x/(float)width; | |
547 glyph->t0 = y/(float)height; | |
548 glyph->s1 = (x + glyph->width)/(float)width; | |
549 glyph->t1 = (y + glyph->height)/(float)height; | |
550 | |
551 // Discard hinting to get advance | |
552 FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING); | |
553 slot = face->glyph; | |
554 glyph->advance_x = slot->advance.x/64.0; | |
555 glyph->advance_y = slot->advance.y/64.0; | |
556 | |
557 vector_push_back( self->glyphs, &glyph ); | |
558 | |
559 if( self->outline_type > 0 ) | |
560 { | |
561 FT_Done_Glyph( ft_glyph ); | |
562 } | |
563 } | |
564 FT_Done_Face( face ); | |
565 FT_Done_FreeType( library ); | |
566 texture_atlas_upload( self->atlas ); | |
567 texture_font_generate_kerning( self ); | |
568 return missed; | |
569 } | |
570 | |
571 | |
572 // ------------------------------------------------- texture_font_get_glyph --- | |
573 texture_glyph_t * | |
574 texture_font_get_glyph( texture_font_t * self, | |
575 wchar_t charcode ) | |
576 { | |
577 size_t i; | |
578 wchar_t buffer[2] = {0,0}; | |
579 texture_glyph_t *glyph; | |
580 | |
581 assert( self ); | |
582 | |
583 assert( self ); | |
584 assert( self->filename ); | |
585 assert( self->atlas ); | |
586 | |
587 /* Check if charcode has been already loaded */ | |
588 for( i=0; i<self->glyphs->size; ++i ) | |
589 { | |
590 glyph = *(texture_glyph_t **) vector_get( self->glyphs, i ); | |
591 // If charcode is -1, we don't care about outline type or thickness | |
592 if( (glyph->charcode == charcode) && | |
593 ((charcode == (wchar_t)(-1) ) || | |
594 ((glyph->outline_type == self->outline_type) && | |
595 (glyph->outline_thickness == self->outline_thickness)) )) | |
596 { | |
597 return glyph; | |
598 } | |
599 } | |
600 | |
601 /* charcode -1 is special : it is used for line drawing (overline, | |
602 * underline, strikethrough) and background. | |
603 */ | |
604 if( charcode == (wchar_t)(-1) ) | |
605 { | |
606 size_t width = self->atlas->width; | |
607 size_t height = self->atlas->height; | |
608 ivec4 region = texture_atlas_get_region( self->atlas, 5, 5 ); | |
609 texture_glyph_t * glyph = texture_glyph_new( ); | |
610 static unsigned char data[4*4*3] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | |
611 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | |
612 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | |
613 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; | |
614 if ( region.x < 0 ) | |
615 { | |
616 fprintf( stderr, "Texture atlas is full (line %d)\n", __LINE__ ); | |
617 return NULL; | |
618 } | |
619 texture_atlas_set_region( self->atlas, region.x, region.y, 4, 4, data, 0 ); | |
620 glyph->charcode = (wchar_t)(-1); | |
621 glyph->s0 = (region.x+2)/(float)width; | |
622 glyph->t0 = (region.y+2)/(float)height; | |
623 glyph->s1 = (region.x+3)/(float)width; | |
624 glyph->t1 = (region.y+3)/(float)height; | |
625 vector_push_back( self->glyphs, &glyph ); | |
626 return glyph; //*(texture_glyph_t **) vector_back( self->glyphs ); | |
627 } | |
628 | |
629 /* Glyph has not been already loaded */ | |
630 buffer[0] = charcode; | |
631 if( texture_font_load_glyphs( self, buffer ) == 0 ) | |
632 { | |
633 return *(texture_glyph_t **) vector_back( self->glyphs ); | |
634 } | |
635 return NULL; | |
636 } | |
637 | |
638 |