1 /*
2 * File: gl_text.cpp
3 * Author: TeslaRus
4 *
5 * Created on October 24, 2015, 11:34 AM
6 */
7
8 #include <SDL2/SDL_platform.h>
9 #include <SDL2/SDL_opengl.h>
10 #include <math.h>
11 #include <stdint.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14
15 #include "gl_text.h"
16 #include "gl_font.h"
17 #include "gl_util.h"
18
19
20 #define vec4_copy(x, y) {(x)[0] = (y)[0]; (x)[1] = (y)[1]; (x)[2] = (y)[2]; (x)[3] = (y)[3];}
21
22 static struct
23 {
24 gl_text_line_p gl_base_lines;
25 gl_text_line_t gl_temp_lines[GLTEXT_MAX_TEMP_LINES];
26 uint16_t temp_lines_used;
27 uint16_t max_styles;
28 struct gl_fontstyle_s *styles;
29
30 uint16_t max_fonts;
31 struct gl_font_cont_s *fonts;
32 } font_data;
33
34 static int screen_width = 0;
35 static int screen_height = 0;
36
37
GLText_Init()38 void GLText_Init()
39 {
40 int i;
41
42 font_data.max_styles = GLTEXT_MAX_FONTSTYLES;
43 font_data.styles = (gl_fontstyle_p)malloc(font_data.max_styles * sizeof(gl_fontstyle_t));
44 for(i = 0; i < font_data.max_styles; i++)
45 {
46 font_data.styles[i].rect_color[0] = 1.0;
47 font_data.styles[i].rect_color[1] = 1.0;
48 font_data.styles[i].rect_color[2] = 1.0;
49 font_data.styles[i].rect_color[3] = 0.0;
50
51 font_data.styles[i].font_color[0] = 0.0;
52 font_data.styles[i].font_color[1] = 0.0;
53 font_data.styles[i].font_color[2] = 0.0;
54 font_data.styles[i].font_color[3] = 1.0;
55
56 font_data.styles[i].shadowed = 0x00;
57 font_data.styles[i].rect = 0x00;
58 }
59
60 font_data.max_fonts = GLTEXT_MAX_FONTS;
61 font_data.fonts = (gl_font_cont_p)malloc(font_data.max_fonts * sizeof(gl_font_cont_t));
62 for(i = 0; i < font_data.max_fonts; i++)
63 {
64 font_data.fonts[i].font_size = 0;
65 font_data.fonts[i].gl_font = NULL;
66 }
67
68 for(int i = 0; i < GLTEXT_MAX_TEMP_LINES; i++)
69 {
70 font_data.gl_temp_lines[i].text_size = GUI_LINE_DEFAULTSIZE;
71 font_data.gl_temp_lines[i].text = (char*)malloc(GUI_LINE_DEFAULTSIZE * sizeof(char));
72 font_data.gl_temp_lines[i].text[0] = 0;
73 font_data.gl_temp_lines[i].show = 0;
74
75 font_data.gl_temp_lines[i].next = NULL;
76 font_data.gl_temp_lines[i].prev = NULL;
77
78 font_data.gl_temp_lines[i].font_id = FONT_SECONDARY;
79 font_data.gl_temp_lines[i].style_id = FONTSTYLE_GENERIC;
80 }
81
82 font_data.temp_lines_used = 0;
83 }
84
85
GLText_Destroy()86 void GLText_Destroy()
87 {
88 int i;
89
90 for(i = 0; i < GLTEXT_MAX_TEMP_LINES ; i++)
91 {
92 font_data.gl_temp_lines[i].show = 0;
93 font_data.gl_temp_lines[i].text_size = 0;
94 free(font_data.gl_temp_lines[i].text);
95 font_data.gl_temp_lines[i].text = NULL;
96 }
97
98 font_data.temp_lines_used = GLTEXT_MAX_TEMP_LINES;
99
100 for(i = 0; i < font_data.max_fonts; i++)
101 {
102 glf_free_font(font_data.fonts[i].gl_font);
103 font_data.fonts[i].font_size = 0;
104 font_data.fonts[i].gl_font = NULL;
105 }
106 free(font_data.fonts);
107 font_data.fonts = NULL;
108
109 free(font_data.styles);
110 font_data.styles = NULL;
111
112 font_data.max_fonts = 0;
113 font_data.max_styles = 0;
114 }
115
116
GLText_UpdateResize(int w,int h,float scale)117 void GLText_UpdateResize(int w, int h, float scale)
118 {
119 screen_width = w;
120 screen_height = h;
121 if(font_data.max_fonts > 0)
122 {
123 for(uint16_t i = 0; i < font_data.max_fonts; i++)
124 {
125 if(font_data.fonts[i].gl_font)
126 {
127 glf_resize(font_data.fonts[i].gl_font, (uint16_t)(((float)font_data.fonts[i].font_size) * scale));
128 }
129 }
130 }
131 }
132
133
GLText_RenderStringLine(gl_text_line_p l)134 void GLText_RenderStringLine(gl_text_line_p l)
135 {
136 gl_tex_font_p gl_font = NULL;
137 gl_fontstyle_p style = NULL;
138
139 if(l->show && (gl_font = GLText_GetFont(l->font_id)) && (style = GLText_GetFontStyle(l->style_id)))
140 {
141 GLfloat real_x = 0.0f, real_y = 0.0f;
142 int32_t x0, y0, x1, y1;
143 GLfloat shadow_color[4];
144 int32_t w_pt = (l->line_width * 64.0f + 0.5f);
145 int32_t dy = l->line_height * gl_font->font_size;
146 int n_lines = 1;
147 char *begin = l->text;
148 char *end = begin;
149
150 shadow_color[0] = 0.0f;
151 shadow_color[1] = 0.0f;
152 shadow_color[2] = 0.0f;
153 shadow_color[3] = (float)style->font_color[3] * GUI_FONT_SHADOW_TRANSPARENCY;
154
155 if(l->line_width > 0.0f)
156 {
157 int n_sym = 0;
158 n_lines = 0;
159 for(char *ch = glf_get_string_for_width(gl_font, l->text, w_pt, &n_sym); *begin; ch = glf_get_string_for_width(gl_font, ch, w_pt, &n_sym))
160 {
161 if(!n_lines)
162 {
163 glf_get_string_bb(gl_font, l->text, n_sym, &x0, &y0, &x1, &y1);
164 }
165 ++n_lines;
166 begin = ch;
167 }
168 begin = l->text;
169 x1 = x0 + w_pt;
170 y1 = y0 + n_lines * gl_font->font_size * l->line_height * 64.0f;
171 }
172 else
173 {
174 glf_get_string_bb(gl_font, l->text, -1, &x0, &y0, &x1, &y1);
175 }
176
177 l->rect[0] = (GLfloat)x0 / 64.0f;
178 l->rect[1] = (GLfloat)y0 / 64.0f;
179 l->rect[2] = (GLfloat)x1 / 64.0f;
180 l->rect[3] = (GLfloat)y1 / 64.0f;
181
182 switch(l->x_align)
183 {
184 case GLTEXT_ALIGN_LEFT:
185 real_x = l->x; // Used with center and right alignments.
186 break;
187 case GLTEXT_ALIGN_RIGHT:
188 real_x = (float)screen_width - (l->rect[2] - l->rect[0]) - l->x;
189 break;
190 case GLTEXT_ALIGN_CENTER:
191 real_x = l->x - 0.5f * (l->rect[2] - l->rect[0]);
192 break;
193 }
194
195 switch(l->y_align)
196 {
197 case GLTEXT_ALIGN_BOTTOM:
198 real_y = l->y;
199 break;
200 case GLTEXT_ALIGN_TOP:
201 real_y = (float)screen_height - (l->rect[3] - l->rect[1]) - l->y;
202 break;
203 case GLTEXT_ALIGN_CENTER:
204 real_y = l->y - 0.5f * (l->rect[3] - l->rect[1]);
205 break;
206 }
207
208 if(style->rect) // it is BS
209 {
210 BindWhiteTexture();
211 GLfloat x0 = l->rect[0] + real_x - style->rect_border * screen_width;
212 GLfloat y0 = l->rect[1] + real_y - style->rect_border * screen_height;
213 GLfloat x1 = l->rect[2] + real_x + style->rect_border * screen_width;
214 GLfloat y1 = l->rect[3] + real_y + style->rect_border * screen_height;
215 GLfloat *v, backgroundArray[32];
216
217 v = backgroundArray;
218 *v++ = x0; *v++ = y0;
219 vec4_copy(v, style->rect_color);
220 v += 4;
221 *v++ = 0.0; *v++ = 0.0;
222
223 *v++ = x1; *v++ = y0;
224 vec4_copy(v, style->rect_color);
225 v += 4;
226 *v++ = 0.0; *v++ = 0.0;
227
228 *v++ = x1; *v++ = y1;
229 vec4_copy(v, style->rect_color);
230 v += 4;
231 *v++ = 0.0; *v++ = 0.0;
232
233 *v++ = x0; *v++ = y1;
234 vec4_copy(v, style->rect_color);
235 v += 4;
236 *v++ = 0.0; *v++ = 0.0;
237
238 qglVertexPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), backgroundArray);
239 qglColorPointer(4, GL_FLOAT, 8 * sizeof(GLfloat), backgroundArray + 2);
240 qglTexCoordPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), backgroundArray + 6);
241 qglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
242 }
243
244
245 for(int line = n_lines - 1; line >= 0; --line)
246 {
247 int n_sym = -1;
248 if(n_lines > 1)
249 {
250 end = glf_get_string_for_width(gl_font, begin, w_pt, &n_sym);
251 }
252 if(style->shadowed)
253 {
254 vec4_copy(gl_font->gl_font_color, shadow_color);
255 glf_render_str(gl_font,
256 (real_x + GUI_FONT_SHADOW_HORIZONTAL_SHIFT),
257 (real_y + line * dy + GUI_FONT_SHADOW_VERTICAL_SHIFT),
258 begin, n_sym);
259 }
260 vec4_copy(gl_font->gl_font_color, style->font_color);
261 glf_render_str(gl_font, real_x, real_y + line * dy, begin, n_sym);
262 begin = end;
263 }
264 }
265 }
266
267
GLText_RenderStrings()268 void GLText_RenderStrings()
269 {
270 gl_text_line_p l = font_data.gl_base_lines;
271
272 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
273 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
274
275 while(l)
276 {
277 GLText_RenderStringLine(l);
278 l = l->next;
279 }
280
281 l = font_data.gl_temp_lines;
282 for(uint16_t i = 0; i < font_data.temp_lines_used; i++, l++)
283 {
284 if(l->show)
285 {
286 GLText_RenderStringLine(l);
287 l->show = 0;
288 }
289 }
290
291 font_data.temp_lines_used = 0;
292 }
293
294
GLText_AddLine(gl_text_line_p line)295 void GLText_AddLine(gl_text_line_p line)
296 {
297 if(font_data.gl_base_lines == NULL)
298 {
299 font_data.gl_base_lines = line;
300 line->next = NULL;
301 line->prev = NULL;
302 return;
303 }
304
305 line->prev = NULL;
306 line->next = font_data.gl_base_lines;
307 font_data.gl_base_lines->prev = line;
308 font_data.gl_base_lines = line;
309 }
310
311
312 // line must be in the list, otherway You crash engine!
GLText_DeleteLine(gl_text_line_p line)313 void GLText_DeleteLine(gl_text_line_p line)
314 {
315 if(line == font_data.gl_base_lines)
316 {
317 font_data.gl_base_lines = line->next;
318 if(font_data.gl_base_lines != NULL)
319 {
320 font_data.gl_base_lines->prev = NULL;
321 }
322 return;
323 }
324
325 line->prev->next = line->next;
326 if(line->next)
327 {
328 line->next->prev = line->prev;
329 }
330 }
331
332 /**
333 * For simple temporary lines rendering.
334 * Really all strings will be rendered in Gui_Render() function.
335 */
GLText_OutTextXY(GLfloat x,GLfloat y,const char * fmt,...)336 gl_text_line_p GLText_OutTextXY(GLfloat x, GLfloat y, const char *fmt, ...)
337 {
338 gl_text_line_p ret = NULL;
339 va_list argptr;
340
341 va_start(argptr, fmt);
342 ret = GLText_VOutTextXY(x, y, fmt, argptr);
343 va_end(argptr);
344
345 return ret;
346 }
347
348
GLText_VOutTextXY(GLfloat x,GLfloat y,const char * fmt,va_list argptr)349 gl_text_line_p GLText_VOutTextXY(GLfloat x, GLfloat y, const char *fmt, va_list argptr)
350 {
351 if(font_data.temp_lines_used < GLTEXT_MAX_TEMP_LINES - 1)
352 {
353 gl_text_line_p l = font_data.gl_temp_lines + font_data.temp_lines_used;
354
355 l->font_id = FONT_SECONDARY;
356 l->style_id = FONTSTYLE_GENERIC;
357 l->line_width = -1.0f;
358 l->line_height = 1.75f;
359
360 vsnprintf(l->text, GUI_LINE_DEFAULTSIZE, fmt, argptr);
361
362 l->next = NULL;
363 l->prev = NULL;
364
365 font_data.temp_lines_used++;
366
367 l->x = x;
368 l->y = y;
369 l->x_align = GLTEXT_ALIGN_LEFT;
370 l->y_align = GLTEXT_ALIGN_BOTTOM;
371
372 l->show = 1;
373 return l;
374 }
375
376 return NULL;
377 }
378
379
GLText_AddFont(uint16_t index,uint16_t size,const char * path)380 int GLText_AddFont(uint16_t index, uint16_t size, const char* path)
381 {
382 if(index < font_data.max_fonts)
383 {
384 gl_tex_font_p new_font = glf_create_font(path, size);
385 if(new_font)
386 {
387 if(font_data.fonts[index].gl_font)
388 {
389 glf_free_font(font_data.fonts[index].gl_font);
390 }
391 font_data.fonts[index].font_size = size;
392 font_data.fonts[index].gl_font = new_font;
393 return 1;
394 }
395 }
396
397 return 0;
398 }
399
400
GLText_RemoveFont(uint16_t index)401 int GLText_RemoveFont(uint16_t index)
402 {
403 if((index < font_data.max_fonts) && (font_data.fonts[index].gl_font))
404 {
405 glf_free_font(font_data.fonts[index].gl_font);
406 font_data.fonts[index].gl_font = NULL;
407 return 1;
408 }
409
410 return 0;
411 }
412
413
GLText_AddFontStyle(uint16_t index,GLfloat R,GLfloat G,GLfloat B,GLfloat A,uint8_t shadow,uint8_t rect,uint8_t rect_border,GLfloat rect_R,GLfloat rect_G,GLfloat rect_B,GLfloat rect_A)414 int GLText_AddFontStyle(uint16_t index,
415 GLfloat R, GLfloat G, GLfloat B, GLfloat A,
416 uint8_t shadow, uint8_t rect, uint8_t rect_border,
417 GLfloat rect_R, GLfloat rect_G, GLfloat rect_B, GLfloat rect_A)
418 {
419 if(index < font_data.max_styles)
420 {
421 gl_fontstyle_p desired_style = font_data.styles + index;
422
423 desired_style->rect_border = rect_border;
424 desired_style->rect_color[0] = rect_R;
425 desired_style->rect_color[1] = rect_G;
426 desired_style->rect_color[2] = rect_B;
427 desired_style->rect_color[3] = rect_A;
428
429 desired_style->font_color[0] = R;
430 desired_style->font_color[1] = G;
431 desired_style->font_color[2] = B;
432 desired_style->font_color[3] = A;
433
434 desired_style->shadowed = shadow;
435 desired_style->rect = rect;
436 return 1;
437 }
438
439 return 0;
440 }
441
442
GLText_RemoveFontStyle(uint16_t index)443 int GLText_RemoveFontStyle(uint16_t index)
444 {
445 if(index < font_data.max_styles)
446 {
447 font_data.styles[index].rect_color[0] = 1.0;
448 font_data.styles[index].rect_color[1] = 1.0;
449 font_data.styles[index].rect_color[2] = 1.0;
450 font_data.styles[index].rect_color[3] = 0.0;
451
452 font_data.styles[index].font_color[0] = 0.0;
453 font_data.styles[index].font_color[1] = 0.0;
454 font_data.styles[index].font_color[2] = 0.0;
455 font_data.styles[index].font_color[3] = 1.0;
456
457 font_data.styles[index].shadowed = 0x00;
458 font_data.styles[index].rect = 0x00;
459 return 1;
460 }
461
462 return 0;
463 }
464
465
GLText_GetFont(uint16_t index)466 gl_tex_font_p GLText_GetFont(uint16_t index)
467 {
468 if(index < font_data.max_fonts)
469 {
470 return font_data.fonts[index].gl_font;
471 }
472
473 return NULL;
474 }
475
476
GLText_GetFontStyle(uint16_t index)477 gl_fontstyle_p GLText_GetFontStyle(uint16_t index)
478 {
479 if(index < font_data.max_styles)
480 {
481 return font_data.styles + index;
482 }
483
484 return NULL;
485 }
486