rev |
line source |
nuclear@2
|
1 #include <math.h>
|
nuclear@2
|
2 #include <ctype.h>
|
nuclear@2
|
3 #define GL_GLEXT_PROTOTYPES
|
nuclear@2
|
4 #if defined(__APPLE__) && defined(__MACH__)
|
nuclear@2
|
5 #include <GLUT/glut.h>
|
nuclear@2
|
6 #else
|
nuclear@2
|
7 #include <GL/glut.h>
|
nuclear@2
|
8 #endif
|
nuclear@2
|
9 #include <ft2build.h>
|
nuclear@2
|
10 #include FT_FREETYPE_H
|
nuclear@2
|
11 #include <vmath.h>
|
nuclear@2
|
12 #include "utktext.h"
|
nuclear@2
|
13 #include "utk_common.h"
|
nuclear@2
|
14
|
nuclear@2
|
15 #ifndef GL_BGRA
|
nuclear@2
|
16 #define GL_BGRA 0x80E1
|
nuclear@2
|
17 #endif
|
nuclear@2
|
18
|
nuclear@2
|
19 #ifndef GL_ABGR
|
nuclear@2
|
20 #define GL_ABGR 0x8000
|
nuclear@2
|
21 #endif
|
nuclear@2
|
22
|
nuclear@2
|
23 #ifdef UTK_BIG_ENDIAN
|
nuclear@2
|
24 #define PIXFMT GL_ABGR
|
nuclear@2
|
25 #else
|
nuclear@2
|
26 #define PIXFMT GL_BGRA
|
nuclear@2
|
27 #endif
|
nuclear@2
|
28
|
nuclear@2
|
29 #define MAX_CHARS 128
|
nuclear@2
|
30 #define MAX_IMG_WIDTH 1024
|
nuclear@2
|
31 #define SIZE_PIXELS(x) ((x) / 64)
|
nuclear@2
|
32
|
nuclear@2
|
33 struct Font {
|
nuclear@2
|
34 unsigned int tex_id;
|
nuclear@2
|
35 float scale; // this compensates if a higher res font is loaded in its stead, with a new CreateFont
|
nuclear@2
|
36 float line_adv; // vertical advance to go to the next line
|
nuclear@2
|
37 struct {
|
nuclear@2
|
38 Vector2 pos, size; // glyph position (from origin) and size in normalized coords [0, 1]
|
nuclear@2
|
39 float advance; // advance in normalized coords
|
nuclear@2
|
40 Vector2 tc_pos, tc_sz; // tex coord box pos/size
|
nuclear@2
|
41 } glyphs[MAX_CHARS];
|
nuclear@2
|
42 };
|
nuclear@2
|
43
|
nuclear@2
|
44 static void BlitFontGlyph(Font *fnt, int x, int y, FT_GlyphSlot glyph, unsigned int *img, int xsz, int ysz);
|
nuclear@2
|
45 static void CleanUp();
|
nuclear@2
|
46
|
nuclear@2
|
47 static FT_Library ft;
|
nuclear@2
|
48 static Vector2 text_pos;
|
nuclear@2
|
49 static float text_size = 1.0;
|
nuclear@2
|
50 static Color text_color;
|
nuclear@2
|
51 static Font *act_fnt;
|
nuclear@2
|
52
|
nuclear@2
|
53 #if !defined(GLIBC) && !defined(__GLIBC__)
|
nuclear@2
|
54 float log2(float x) {
|
nuclear@2
|
55 float res = 0.0;
|
nuclear@2
|
56 while(x > 1.0) {
|
nuclear@2
|
57 x /= 2.0;
|
nuclear@2
|
58 res += 1.0;
|
nuclear@2
|
59 }
|
nuclear@2
|
60 return res;
|
nuclear@2
|
61 }
|
nuclear@2
|
62 #endif // _MSC_VER
|
nuclear@2
|
63
|
nuclear@2
|
64
|
nuclear@2
|
65 static inline int NextPow2(int x)
|
nuclear@2
|
66 {
|
nuclear@2
|
67 float lg2 = log2((float)x);
|
nuclear@2
|
68 return (int)pow(2.0f, (int)ceil(lg2));
|
nuclear@2
|
69 }
|
nuclear@2
|
70
|
nuclear@2
|
71
|
nuclear@2
|
72 unsigned int CreateFont(const char *fname, int font_size)
|
nuclear@2
|
73 {
|
nuclear@2
|
74 if(!ft) {
|
nuclear@2
|
75 if(FT_Init_FreeType(&ft) != 0) {
|
nuclear@2
|
76 fprintf(stderr, "failed to initialize freetype\n");
|
nuclear@2
|
77 return 0;
|
nuclear@2
|
78 }
|
nuclear@2
|
79 atexit(CleanUp);
|
nuclear@2
|
80 }
|
nuclear@2
|
81
|
nuclear@2
|
82 FT_Face face;
|
nuclear@2
|
83 if(FT_New_Face(ft, fname, 0, &face) != 0) {
|
nuclear@2
|
84 fprintf(stderr, "failed to load font: %s\n", fname);
|
nuclear@2
|
85 return 0;
|
nuclear@2
|
86 }
|
nuclear@2
|
87
|
nuclear@2
|
88 FT_Set_Pixel_Sizes(face, 0, font_size);
|
nuclear@2
|
89
|
nuclear@2
|
90 Font *fnt = new Font;
|
nuclear@2
|
91 int max_width = MAX_CHARS * SIZE_PIXELS(face->bbox.xMax - face->bbox.xMin);
|
nuclear@2
|
92 int foo_xsz = MAX_IMG_WIDTH;
|
nuclear@2
|
93 int foo_ysz = SIZE_PIXELS(face->bbox.yMax - face->bbox.yMin) * max_width / foo_xsz;
|
nuclear@2
|
94
|
nuclear@2
|
95 int tex_xsz = NextPow2(foo_xsz);
|
nuclear@2
|
96 int tex_ysz = NextPow2(foo_ysz);
|
nuclear@2
|
97
|
nuclear@2
|
98 unsigned int *img;
|
nuclear@2
|
99 img = new unsigned int[tex_xsz * tex_ysz];
|
nuclear@2
|
100 memset(img, 0, tex_xsz * tex_ysz * sizeof *img);
|
nuclear@2
|
101
|
nuclear@2
|
102 extern int xsz, ysz;
|
nuclear@2
|
103 int vport_xsz = xsz, vport_ysz = ysz;
|
nuclear@2
|
104
|
nuclear@2
|
105 int max_glyph_y = 0;
|
nuclear@2
|
106 int max_glyph_x = 0;
|
nuclear@2
|
107 for(int i=0; i<MAX_CHARS; i++) {
|
nuclear@2
|
108 FT_Load_Char(face, i, 0);
|
nuclear@2
|
109 int width = SIZE_PIXELS(face->glyph->metrics.width);
|
nuclear@2
|
110 int height = SIZE_PIXELS(face->glyph->metrics.height);
|
nuclear@2
|
111
|
nuclear@2
|
112 if(height > max_glyph_y) {
|
nuclear@2
|
113 max_glyph_y = height;
|
nuclear@2
|
114 }
|
nuclear@2
|
115
|
nuclear@2
|
116 if(width > max_glyph_x) {
|
nuclear@2
|
117 max_glyph_x = width;
|
nuclear@2
|
118 }
|
nuclear@2
|
119 }
|
nuclear@2
|
120
|
nuclear@2
|
121 int gx = 0, gy = 0;
|
nuclear@2
|
122 for(int i=0; i<MAX_CHARS; i++) {
|
nuclear@2
|
123 FT_Load_Char(face, i, FT_LOAD_RENDER);
|
nuclear@2
|
124 FT_GlyphSlot g = face->glyph;
|
nuclear@2
|
125
|
nuclear@2
|
126 int gwidth = SIZE_PIXELS(g->metrics.width);
|
nuclear@2
|
127 int gheight = SIZE_PIXELS(g->metrics.height);
|
nuclear@2
|
128
|
nuclear@2
|
129 if(gx > MAX_IMG_WIDTH - gwidth) {
|
nuclear@2
|
130 gx = 0;
|
nuclear@2
|
131 gy += max_glyph_y;
|
nuclear@2
|
132 }
|
nuclear@2
|
133
|
nuclear@2
|
134 BlitFontGlyph(fnt, gx, gy, g, img, tex_xsz, tex_ysz);
|
nuclear@2
|
135 fnt->scale = 1.0;
|
nuclear@2
|
136 fnt->line_adv = (float)SIZE_PIXELS(g->metrics.vertAdvance) / (float)vport_ysz;
|
nuclear@2
|
137 fnt->glyphs[i].tc_pos.x = (float)gx / (float)tex_xsz;
|
nuclear@2
|
138 fnt->glyphs[i].tc_pos.y = (float)gy / (float)tex_ysz;
|
nuclear@2
|
139 fnt->glyphs[i].tc_sz.x = (float)gwidth / (float)tex_xsz;
|
nuclear@2
|
140 fnt->glyphs[i].tc_sz.y = (float)gheight / (float)tex_ysz;
|
nuclear@2
|
141 fnt->glyphs[i].size.x = (float)gwidth / (float)vport_xsz;
|
nuclear@2
|
142 fnt->glyphs[i].size.y = (float)gheight / (float)vport_ysz;
|
nuclear@2
|
143 fnt->glyphs[i].pos.x = (float)SIZE_PIXELS(g->metrics.horiBearingX) / (float)vport_xsz;
|
nuclear@2
|
144 fnt->glyphs[i].pos.y = -(float)SIZE_PIXELS(g->metrics.horiBearingY) / (float)vport_ysz;
|
nuclear@2
|
145 fnt->glyphs[i].advance = (float)SIZE_PIXELS(g->metrics.horiAdvance) / (float)vport_xsz;
|
nuclear@2
|
146
|
nuclear@2
|
147 gx += gwidth;
|
nuclear@2
|
148 }
|
nuclear@2
|
149
|
nuclear@2
|
150 FT_Done_Face(face);
|
nuclear@2
|
151
|
nuclear@2
|
152 glGenTextures(1, &fnt->tex_id);
|
nuclear@2
|
153 glBindTexture(GL_TEXTURE_2D, fnt->tex_id);
|
nuclear@2
|
154 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
nuclear@2
|
155 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
nuclear@2
|
156 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
nuclear@2
|
157 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
nuclear@2
|
158 glTexImage2D(GL_TEXTURE_2D, 0, 4, tex_xsz, tex_ysz, 0, PIXFMT, GL_UNSIGNED_BYTE, img);
|
nuclear@2
|
159
|
nuclear@2
|
160 #ifdef DUMP_FONT_IMG
|
nuclear@2
|
161 FILE *fp;
|
nuclear@2
|
162 unsigned int *ptr = img;
|
nuclear@2
|
163
|
nuclear@2
|
164 if((fp = fopen("fnt.ppm", "wb"))) {
|
nuclear@2
|
165 fprintf(fp, "P6\n%d %d\n255\n", tex_xsz, tex_ysz);
|
nuclear@2
|
166
|
nuclear@2
|
167 for(int i=0; i<tex_xsz * tex_ysz; i++) {
|
nuclear@2
|
168 fputc((*ptr >> 24) & 0xff, fp);
|
nuclear@2
|
169 fputc((*ptr >> 24) & 0xff, fp);
|
nuclear@2
|
170 fputc((*ptr >> 24) & 0xff, fp);
|
nuclear@2
|
171 ptr++;
|
nuclear@2
|
172 }
|
nuclear@2
|
173 fclose(fp);
|
nuclear@2
|
174 }
|
nuclear@2
|
175 #endif
|
nuclear@2
|
176
|
nuclear@2
|
177 delete [] img;
|
nuclear@2
|
178
|
nuclear@2
|
179 act_fnt = fnt;
|
nuclear@2
|
180
|
nuclear@2
|
181 return 1;
|
nuclear@2
|
182 }
|
nuclear@2
|
183
|
nuclear@2
|
184 void DeleteFont(unsigned int fid)
|
nuclear@2
|
185 {
|
nuclear@2
|
186 }
|
nuclear@2
|
187
|
nuclear@2
|
188 unsigned int GetFont(const char *fname, int sz)
|
nuclear@2
|
189 {
|
nuclear@2
|
190 return 1;
|
nuclear@2
|
191 }
|
nuclear@2
|
192
|
nuclear@2
|
193 bool BindFont(unsigned int fid)
|
nuclear@2
|
194 {
|
nuclear@2
|
195 return true;
|
nuclear@2
|
196 }
|
nuclear@2
|
197
|
nuclear@2
|
198 void SetTextPos(const Vector2 &pos)
|
nuclear@2
|
199 {
|
nuclear@2
|
200 text_pos = pos;
|
nuclear@2
|
201 }
|
nuclear@2
|
202
|
nuclear@2
|
203 Vector2 GetTextPos()
|
nuclear@2
|
204 {
|
nuclear@2
|
205 return text_pos;
|
nuclear@2
|
206 }
|
nuclear@2
|
207
|
nuclear@2
|
208 void TextLineAdvance(int adv)
|
nuclear@2
|
209 {
|
nuclear@2
|
210 text_pos.y += (float)adv * act_fnt->line_adv;
|
nuclear@2
|
211 }
|
nuclear@2
|
212
|
nuclear@2
|
213 void TextCRet()
|
nuclear@2
|
214 {
|
nuclear@2
|
215 text_pos.x = 0.0;
|
nuclear@2
|
216 }
|
nuclear@2
|
217
|
nuclear@2
|
218 void SetTextSize(float sz)
|
nuclear@2
|
219 {
|
nuclear@2
|
220 text_size = sz;
|
nuclear@2
|
221 }
|
nuclear@2
|
222
|
nuclear@2
|
223 float GetTextSize()
|
nuclear@2
|
224 {
|
nuclear@2
|
225 return text_size;
|
nuclear@2
|
226 }
|
nuclear@2
|
227
|
nuclear@2
|
228 void SetTextColor(const Color &col)
|
nuclear@2
|
229 {
|
nuclear@2
|
230 text_color = col;
|
nuclear@2
|
231 }
|
nuclear@2
|
232
|
nuclear@2
|
233 Color GetTextColor()
|
nuclear@2
|
234 {
|
nuclear@2
|
235 return text_color;
|
nuclear@2
|
236 }
|
nuclear@2
|
237
|
nuclear@2
|
238 static void ImOverlay(const Vector2 &v1, const Vector2 &v2, const Color &col, unsigned int tex)
|
nuclear@2
|
239 {
|
nuclear@2
|
240 float l = v1.x * 2.0f - 1.0f;
|
nuclear@2
|
241 float r = v2.x * 2.0f - 1.0f;
|
nuclear@2
|
242 float u = -v1.y * 2.0f + 1.0f;
|
nuclear@2
|
243 float d = -v2.y * 2.0f + 1.0f;
|
nuclear@2
|
244
|
nuclear@2
|
245 glMatrixMode(GL_PROJECTION);
|
nuclear@2
|
246 glPushMatrix();
|
nuclear@2
|
247 glLoadIdentity();
|
nuclear@2
|
248 glMatrixMode(GL_MODELVIEW);
|
nuclear@2
|
249 glPushMatrix();
|
nuclear@2
|
250 glLoadIdentity();
|
nuclear@2
|
251
|
nuclear@2
|
252 glBindTexture(GL_TEXTURE_2D, tex);
|
nuclear@2
|
253
|
nuclear@2
|
254 glDisable(GL_DEPTH_TEST);
|
nuclear@2
|
255 glDisable(GL_LIGHTING);
|
nuclear@2
|
256 glDisable(GL_CULL_FACE);
|
nuclear@2
|
257
|
nuclear@2
|
258 glBegin(GL_QUADS);
|
nuclear@2
|
259 glColor4f(col.r, col.g, col.b, col.a);
|
nuclear@2
|
260 glTexCoord2f(0, 0);
|
nuclear@2
|
261 glVertex2f(l, u);
|
nuclear@2
|
262 glTexCoord2f(1, 0);
|
nuclear@2
|
263 glVertex2f(r, u);
|
nuclear@2
|
264 glTexCoord2f(1, 1);
|
nuclear@2
|
265 glVertex2f(r, d);
|
nuclear@2
|
266 glTexCoord2f(0, 1);
|
nuclear@2
|
267 glVertex2f(l, d);
|
nuclear@2
|
268 glEnd();
|
nuclear@2
|
269
|
nuclear@2
|
270 glEnable(GL_LIGHTING);
|
nuclear@2
|
271 glEnable(GL_DEPTH_TEST);
|
nuclear@2
|
272
|
nuclear@2
|
273 glMatrixMode(GL_PROJECTION);
|
nuclear@2
|
274 glPopMatrix();
|
nuclear@2
|
275 glMatrixMode(GL_MODELVIEW);
|
nuclear@2
|
276 glPopMatrix();
|
nuclear@2
|
277 }
|
nuclear@2
|
278
|
nuclear@2
|
279 float PrintChar(char c)
|
nuclear@2
|
280 {
|
nuclear@2
|
281 // get texture coordinates for the glyph, and construct the texture matrix
|
nuclear@2
|
282 float tx = act_fnt->glyphs[(int)c].tc_pos.x;
|
nuclear@2
|
283 float ty = act_fnt->glyphs[(int)c].tc_pos.y;
|
nuclear@2
|
284 float sx = act_fnt->glyphs[(int)c].tc_sz.x;
|
nuclear@2
|
285 float sy = act_fnt->glyphs[(int)c].tc_sz.y;
|
nuclear@2
|
286
|
nuclear@2
|
287 float mat[] = {
|
nuclear@2
|
288 sx, 0, tx, 0,
|
nuclear@2
|
289 0, sy, ty, 0,
|
nuclear@2
|
290 0, 0, 1, 0,
|
nuclear@2
|
291 0, 0, 0, 1
|
nuclear@2
|
292 };
|
nuclear@2
|
293
|
nuclear@2
|
294 glMatrixMode(GL_TEXTURE);
|
nuclear@2
|
295 glPushMatrix();
|
nuclear@2
|
296 glLoadMatrixf(mat);
|
nuclear@2
|
297
|
nuclear@2
|
298 Vector2 pos = text_pos + act_fnt->glyphs[(int)c].pos * act_fnt->scale;
|
nuclear@2
|
299 ImOverlay(pos, pos + act_fnt->glyphs[(int)c].size * act_fnt->scale, text_color, act_fnt->tex_id);
|
nuclear@2
|
300
|
nuclear@2
|
301 glMatrixMode(GL_TEXTURE);
|
nuclear@2
|
302 glPopMatrix();
|
nuclear@2
|
303
|
nuclear@2
|
304 return act_fnt->glyphs[(int)c].advance * act_fnt->scale;
|
nuclear@2
|
305 }
|
nuclear@2
|
306
|
nuclear@2
|
307 // this function contains the preamble of all block text drawing functions (i.e. not printchar above)
|
nuclear@2
|
308 static void PreDraw()
|
nuclear@2
|
309 {
|
nuclear@2
|
310 glMatrixMode(GL_PROJECTION);
|
nuclear@2
|
311 glPushMatrix();
|
nuclear@2
|
312 /*glLoadTransposeMatrixf(OrthoProj(2, 2, 0, 10).m);*/
|
nuclear@2
|
313 glLoadIdentity();
|
nuclear@2
|
314 glMatrixMode(GL_MODELVIEW);
|
nuclear@2
|
315 glPushMatrix();
|
nuclear@2
|
316 glLoadIdentity();
|
nuclear@2
|
317 glMatrixMode(GL_TEXTURE);
|
nuclear@2
|
318 glPushMatrix();
|
nuclear@2
|
319 glLoadIdentity();
|
nuclear@2
|
320
|
nuclear@2
|
321 glEnable(GL_TEXTURE_2D);
|
nuclear@2
|
322 glBindTexture(GL_TEXTURE_2D, act_fnt->tex_id);
|
nuclear@2
|
323
|
nuclear@2
|
324 glBegin(GL_QUADS);
|
nuclear@2
|
325 glColor4f(text_color.r, text_color.g, text_color.b, text_color.a);
|
nuclear@2
|
326 }
|
nuclear@2
|
327
|
nuclear@2
|
328 static void PostDraw()
|
nuclear@2
|
329 {
|
nuclear@2
|
330 glEnd();
|
nuclear@2
|
331
|
nuclear@2
|
332 glDisable(GL_TEXTURE_2D);
|
nuclear@2
|
333
|
nuclear@2
|
334 glMatrixMode(GL_TEXTURE);
|
nuclear@2
|
335 glPopMatrix();
|
nuclear@2
|
336 glMatrixMode(GL_MODELVIEW);
|
nuclear@2
|
337 glPopMatrix();
|
nuclear@2
|
338 glMatrixMode(GL_PROJECTION);
|
nuclear@2
|
339 glPopMatrix();
|
nuclear@2
|
340 }
|
nuclear@2
|
341
|
nuclear@2
|
342 float PrintString(const char *str, bool standalone)
|
nuclear@2
|
343 {
|
nuclear@2
|
344 if(standalone) PreDraw();
|
nuclear@2
|
345
|
nuclear@2
|
346 float start_x = text_pos.x;
|
nuclear@2
|
347 while(*str) {
|
nuclear@2
|
348 float tx = act_fnt->glyphs[(int)*str].tc_pos.x;
|
nuclear@2
|
349 float ty = act_fnt->glyphs[(int)*str].tc_pos.y;
|
nuclear@2
|
350 float sx = act_fnt->glyphs[(int)*str].tc_sz.x;
|
nuclear@2
|
351 float sy = act_fnt->glyphs[(int)*str].tc_sz.y;
|
nuclear@2
|
352
|
nuclear@2
|
353 Vector2 tc1 = Vector2(tx, ty);
|
nuclear@2
|
354 Vector2 tc2 = Vector2(tx + sx, ty + sy);
|
nuclear@2
|
355
|
nuclear@2
|
356 Vector2 v1 = text_pos + act_fnt->glyphs[(int)*str].pos * act_fnt->scale * text_size;
|
nuclear@2
|
357 Vector2 v2 = v1 + act_fnt->glyphs[(int)*str].size * act_fnt->scale * text_size;
|
nuclear@2
|
358 float l = v1.x * 2.0f - 1.0f;
|
nuclear@2
|
359 float r = v2.x * 2.0f - 1.0f;
|
nuclear@2
|
360 float u = -v1.y * 2.0f + 1.0f;
|
nuclear@2
|
361 float d = -v2.y * 2.0f + 1.0f;
|
nuclear@2
|
362
|
nuclear@2
|
363 glTexCoord2f(tc1.x, tc1.y);
|
nuclear@2
|
364 glVertex2f(l, u);
|
nuclear@2
|
365 glTexCoord2f(tc2.x, tc1.y);
|
nuclear@2
|
366 glVertex2f(r, u);
|
nuclear@2
|
367 glTexCoord2f(tc2.x, tc2.y);
|
nuclear@2
|
368 glVertex2f(r, d);
|
nuclear@2
|
369 glTexCoord2f(tc1.x, tc2.y);
|
nuclear@2
|
370 glVertex2f(l, d);
|
nuclear@2
|
371
|
nuclear@2
|
372 text_pos.x += act_fnt->glyphs[(int)*str++].advance * act_fnt->scale * text_size;
|
nuclear@2
|
373 }
|
nuclear@2
|
374
|
nuclear@2
|
375 if(standalone) PostDraw();
|
nuclear@2
|
376 return text_pos.x - start_x;
|
nuclear@2
|
377 }
|
nuclear@2
|
378
|
nuclear@2
|
379 void PrintStringLines(const char **str, int lines)
|
nuclear@2
|
380 {
|
nuclear@2
|
381 PreDraw();
|
nuclear@2
|
382
|
nuclear@2
|
383 while(lines-- > 0) {
|
nuclear@2
|
384 PrintString(*str++, false);
|
nuclear@2
|
385 TextLineAdvance();
|
nuclear@2
|
386 TextCRet();
|
nuclear@2
|
387 }
|
nuclear@2
|
388
|
nuclear@2
|
389 PostDraw();
|
nuclear@2
|
390 }
|
nuclear@2
|
391
|
nuclear@2
|
392 static void BlitFontGlyph(Font *fnt, int x, int y, FT_GlyphSlot glyph, unsigned int *img, int xsz, int ysz)
|
nuclear@2
|
393 {
|
nuclear@2
|
394 if(glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY) {
|
nuclear@2
|
395 fprintf(stderr, "BlitFontGlyph: unsupported pixel mode: %d\n", glyph->bitmap.pixel_mode);
|
nuclear@2
|
396 return;
|
nuclear@2
|
397 }
|
nuclear@2
|
398
|
nuclear@2
|
399 unsigned int *dest = img + y * xsz + x;
|
nuclear@2
|
400 unsigned char *src = glyph->bitmap.buffer;
|
nuclear@2
|
401
|
nuclear@2
|
402 for(int j=0; j<glyph->bitmap.rows; j++) {
|
nuclear@2
|
403 for(int i=0; i<glyph->bitmap.width; i++) {
|
nuclear@2
|
404 dest[i] = 0x00ffffff | ((unsigned int)src[i] << 24);
|
nuclear@2
|
405 }
|
nuclear@2
|
406 dest += xsz;
|
nuclear@2
|
407 src += glyph->bitmap.pitch;
|
nuclear@2
|
408 }
|
nuclear@2
|
409 }
|
nuclear@2
|
410
|
nuclear@2
|
411 static void CleanUp()
|
nuclear@2
|
412 {
|
nuclear@2
|
413 FT_Done_FreeType(ft);
|
nuclear@2
|
414 }
|
nuclear@2
|
415
|
nuclear@2
|
416 float GetMaxDescent()
|
nuclear@2
|
417 {
|
nuclear@2
|
418 Font *fnt = act_fnt;
|
nuclear@2
|
419
|
nuclear@2
|
420 float max_descent = 0.0f;
|
nuclear@2
|
421
|
nuclear@2
|
422 for(int i=0; i<MAX_CHARS; i++) {
|
nuclear@2
|
423 float des = fnt->glyphs[i].pos.y + fnt->glyphs[i].size.y;
|
nuclear@2
|
424 if(isprint(i) && des > max_descent) {
|
nuclear@2
|
425 max_descent = des;
|
nuclear@2
|
426 }
|
nuclear@2
|
427 }
|
nuclear@2
|
428
|
nuclear@2
|
429 return max_descent;
|
nuclear@2
|
430 }
|
nuclear@2
|
431
|
nuclear@2
|
432 float GetLineAdvance()
|
nuclear@2
|
433 {
|
nuclear@2
|
434 return act_fnt->line_adv;
|
nuclear@2
|
435 }
|
nuclear@2
|
436
|
nuclear@2
|
437 float GetTextWidth(const char *str)
|
nuclear@2
|
438 {
|
nuclear@2
|
439 float width = 0;
|
nuclear@2
|
440 while(*str) {
|
nuclear@2
|
441 width += act_fnt->glyphs[(int)*str++].advance * act_fnt->scale * text_size;
|
nuclear@2
|
442 }
|
nuclear@2
|
443 return width;
|
nuclear@2
|
444 }
|