FreeWRL / FreeX3D 4.3.0
Component_Text.c
1/*
2
3
4X3D Text Component
5
6*/
7
8
9/****************************************************************************
10 This file is part of the FreeWRL/FreeX3D Distribution.
11
12 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
13
14 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
15 it under the terms of the GNU Lesser Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
26****************************************************************************/
27
28
29#include <config.h>
30#include <system.h>
31
32#include <system_fonts.h>
33
34#include <display.h>
35#include <internal.h>
36
37#include <libFreeWRL.h>
38
39#include "../vrml_parser/Structs.h"
40#include "../input/InputFunctions.h"
41#include "../main/headers.h"
42#include "../scenegraph/Viewer.h"
43#include "../opengl/OpenGL_Utils.h"
44#include "../opengl/Textures.h"
45
46#include "Collision.h"
47#include "LinearAlgebra.h"
48#include "Component_Shape.h"
49#include "../scenegraph/Tess.h"
50#include "../scenegraph/Polyrep.h"
51#include "../x3d_parser/Bindable.h"
52
53
54#ifdef _ANDROID
55#ifdef ANDROID_DEBUG
56#include <time.h>
57#include <sys/types.h>
58#include <sys/stat.h>
59#endif //ANDROID_DEBUG
60#endif //ANDROID
61#define HAVE_COMPILED_IN_FONT 1
62
63//googling for info on DPI, PPI:
64//DPI dots per inch (one dot == 1 pixel), in non-mac its 96 DPI constant for historical reasons
65//PPI points per inch 72 is a typography constant ie 1 point = 1/72 inch
66#define XRES 96
67#define YRES 96
68#define PPI 72
69#define POINTSIZE 200 //20 before forced TTF hinting, which triggered tesselation combiner calls on intersections
70
71
72#define TOPTOBOTTOM (fsparam & 0x04)
73#define LEFTTORIGHT (fsparam & 0x02)
74#define HORIZONTAL (fsparam & 0x01)
75
76
77/* units and numerics with freetype2:
78 Even a very experienced programmer like dug9 can find the units and numerical precision
79 with freetype2 a bit bewildering at first. Here's freetype2's 'developer must-read concepts':
80 http://www.freetype.org/freetype2/docs/glyphs/index.html
81 http://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html
82 - baseline, pens, origin, advance
83 http://www.freetype.org/freetype2/docs/glyphs/glyphs-5.html
84 - text layout algorithms
85 Here's my summary:
86 http://www.freetype.org/freetype2/docs/tutorial/step2.html
87 - see near the bottom of this link page for examples of playing with transforming variables.
88 x except its not good at expressing units, you need to read paragraphs carefully,
89 check different documentation, example code, API reference, put breakpoints to compare values
90 * I'll express the units here, like engineers do:
91 [fu] - font units or font design units or design units or grid units or EM units
92 - can be -32767 to +32767
93 - usually EMsquare is 2048 fu in size for truetype, 1000 for type1 fonts, both directions
94 - often expressed in fixed-point numbers
95 [du] - device units or display-device units or pixels on screen
96 [em] - 0 to 1 with 1 being the whole EMsquare, equivalent to [1] in most cases
97 http://designwithfontforge.com/en-US/The_EM_Square.html
98 [m/em] - the x3d units for mysize, spacing ie final coords [m] = mysize[m/em] * emcoords [em]
99 [in] - inch on screen/display device
100 [pt] - points ie 12 point font. There are 72 points per inch. [pt/in]
101 [1] - [one] - unitless, or a ratio of 2 like-units ie [m/m] = [1]. ie usage: [unit] = [1] * [unit]
102 units must balance on each side of an equation, examples:
103 x_scale [du/fu] = pixel_size_per_EM_x [du/em] / EM_size [fu/em]
104 device_x [du] = design_x [fu] * x_scale [du/fu]
105
106
107 Precision: Fixed-point numbers
108 many of the freetype2 parameters are expressed as fixed-point numbers 16.16 or 26.6:
109 https://en.wikibooks.org/wiki/Floating_Point/Fixed-Point_Numbers
110 dot16 - 16.16 Fixed-Point (a 32 bit integer, with half for radix, half for mantissa) 1111111111111111.1111111111111111
111 dot6 - 26.6 Fixed-Point (32 bit integer, with last 6 for radix 11111111111111111111111111.111111
112 int32 - normal int
113 dble - normal double
114
115 Two ways to convert precision:
116 a) all int, with truncation:
117 dot16 = int32 << 16 or int32 * 0x10000 or int32 * 65536
118 dot6 = int32 << 6 or int32 * 64
119 int32 = dot16 >> 16 or int32 / 65536 (truncates decimals)
120 int32 = dot6 >> 6 or int32 / 64
121 dot6 = dot16 >> 10 or dot16 / 1024 (truncates least significant decimals)
122 dot16 = dot6 << 10 or dot6 * 1024
123 freetype2 has some scaling functions optimized for speed:
124 http://www.freetype.org/freetype2/docs/reference/ft2-computations.html#FT_MulFix
125
126 b) to/from doubles (preserves precision) (see wiwibooks link above for formulas):
127 dot16 = round( dble * 2**16)
128 dble = dot16 * 2**(-16) or (double)dot16 / (double) 65536
129 dot6 = round( dble * 2**6) = round(dble * 64.0) ~= dble * 64.0
130 dble = dot6 * 2**(-6) or (double)dot6 / (double)64
131 if you go dble = (double)dot6 you'll get coordinates x 2**6 or 64
132
133 Combining units and precision:
134 freetype's transformed glyph coordinates - the ones that come out in the callbacks lineto, moveto etc
135 are in in [du_dot6] http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html
136 [du_dot6] = [du]*64 - '1/64 of device units'
137 Exmaple:
138 let DOT16 [dot16] = pow(2.0,16.0) == 2**16 = 65536.0
139 let DOT6 [dot6] = pow(2.0,6.0) == 2**6 = 64.0
140 //face->size->metrics.x_scale is in dot16, and scales directly to '1/64 of device pixels' or [du_dot6], from [fu]
141 x_scale = (double)(face->size->metrics.x_scale) / DOT16;
142 // [du_dot6/fu] = [du_dot16/fu] /[dot16]
143 x_scale1 = x_scale / DOT6;
144 // [du/fu] = [du_dot6/fu]/[dot6]
145
146 Specific variables:
147 the EM square concept:
148 http://designwithfontforge.com/en-US/The_EM_Square.html
149 - truetype fonts usually EM_size = 2048 [fu/em]
150 PPI - points per inch [pt/in], 72 by typographic convention
151 XRES - device resolution in dots or pixels per inch DPI [du/in],
152 96 for screen by MS windows convention
153 72 for mac by convention
154 (using freetype for a printer/plotter, you might use 300 for 300 DPI)
155 pixel_size = point_size * resolution / 72
156 [du/em] = [pt/em] * [du/in] / [pt/in]
157 pixel_coord = grid_coord * pixel_size / EM_size
158 [du] = [fu] * [du/em] / [fu/em]
159 http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec
160 Face->height [fu_dot6/em] - baseline-to-baseline in font units 26.6
161 glyphslot->advance.x [du_dot16]
162
163 patterns to units and precision:
164 - as of Feb 2016 we keep our rowvec variables usually in meters [m] or x3d local coordinates
165 - freetype2 calls into the lineto, moveto etc callbacks with [du_dot6] (pixels) which we
166 transform back to meters[m] or x3d local coords via OUT2GLB() + pen_x,y
167*/
168
169// [du_dot6] to [m]
170// freetype 'kerns' - moves glyphs slightly to align with output pixels to look great. But to do that
171// it needs some at least arbitrary font size in pixels, which we set in Set_Char_Size, to keep it happy.
172// Now we want to convert coordinates back from the callback units [du_dot6] or pixels
173// -which includes our Set_Char_Size() pointsize and XRES values-
174// to unitless[1] or [m] x3d local coordinates for opengl, by taking back the XRES and pointsize
175// [du] = [du_dot6]/[dot6]
176// a = ftvertex / 64.0
177// [m] = [du] * [m/em]/[pt/em] * [pt/in]/[du/in] * [1]
178// v = a * size /POINTSIZE * PPI / XRES * s
179#define OUT2GLB(a,s) ((double)(a) * p->size/64.0 / p->pointsize * (double)PPI/(double)XRES *s)
180
181
182/*
183//don't need, not tested:
184// [m] to [du_dot6]
185// [du] = [m] * [pt/em] / [m/em] *[du/in] / [pt/in] * [1]
186// a = v * POINTSIZE / size * XRES / PPI * 1/s
187// [du_dot6] = [du]*[dot6]
188// ftvertex = a * 64.0
189#define IN2DUDOT6(v,s) ((int)(((double)(v) / p->pointsize / p->size * (double)XRES/(double)PPI * 1.0/s)*64.0))
190*/
191
192/* now defined in system_fonts.h
193include <ft2build.h>
194** include <ftoutln.h>
195include FT_FREETYPE_H
196include FT_GLYPH_H */
197
198enum {
199 FONTSTATE_NONE,
200 FONTSTATE_TRIED,
201 FONTSTATE_LOADED,
202} fontstate;
203typedef struct chardata{
204 unsigned int iglyph; //glyph index in p->gplyphs[iglyph]
205 double advance; //char width or more precisely, advance of penx to next char start
206 double x; //pen_x [m]
207 double y; //pen_y [m]
208 double sx; //scale = shrink*rshrink [1]
209 double sy; //scale = shrink*rshrink [1]
210} chardata;
211typedef struct row32 {
212 int allocn;
213 int len32;
214 unsigned int *str32;
215 int iglyphstartindex;
216 double hrowsize; //sum of char widths [m]
217 double vcolsize; //len32 x charheight [m]
218 double widestchar; //widest char in the row [m]
219 chardata *chr;
220}row32;
221
222//this goes in text node _screendata field when _isScreen
223typedef struct screentextdata {
224 int nalloc;
225 int nrow;
226 row32 *rowvec;
227 void *atlasfont;
228 //void *set;
229 float size; //[m]
230 float faceheight;
231 float emsize;
233typedef struct pComponent_Text{
234
235#if defined(_ANDROID) || defined(IPHONE)
236 // Android UI sends in file descriptors and open file for fonts.
237 // files are in the assets folder; we assume that the fd is open and fseek'd properly.
238
239 FILE *androidFontFile;
240 int fileLen;
241#endif //ANDROID
242
243 /* initialize the library with this variable */
244 FT_Library library; /* handle to library */
245
246 #define num_fonts 32
247 FT_Face font_face[num_fonts]; /* handle to face object */
248 int font_state[num_fonts]; /* is this font opened */
249
250
251 /* we load so many gliphs into an array for processing */
252 #define MAX_GLYPHS 2048
253 FT_Glyph glyphs[MAX_GLYPHS];
254 int cur_glyph;
255 int TextVerbose;// = FALSE;
256 int rowvec_allocn;
257 row32 *rowvec;
258
259 /* decompose interface func pointer */
260 FT_Outline_Funcs FW_outline_interface;
261
262
263 /* lets store the font paths here */
264 #define fp_name_len 256
265 char *font_directory;// = NULL;
266 char thisfontname[fp_name_len];
267
268 /* where are we? */
269 double pen_x, pen_y;
270 double shrink_x, shrink_y;
271
272 /* if this is a status bar, put depth different than 0.0 */
273 float TextZdist;
274
275 double size; /* size of chars from file */
276 double pointsize; /*POINTSIZE for FontStyle, pointSize for ScreenFontStyle*/
277 int myff; /* which index into font_face are we using */
278
279
280 /* for keeping track of tesselated points */
281 int FW_RIA[500]; /* pointer to which point is returned by tesselator */
282 int FW_RIA_indx; /* index into FW_RIA */
283 struct X3D_PolyRep *FW_rep_; /* this is the internal rep of the polyrep */
284 int FW_pointctr; /* how many points used so far? maps into rep-_coord */
285 int indx_count; /* maps intp FW_rep_->cindex */
286 int coordmaxsize; /* maximum coords before needing to REALLOC */
287 int cindexmaxsize; /* maximum cindexes before needing to REALLOC */
288
289
290 /* Outline callbacks and global vars */
291 int contour_started;
292 FT_Vector last_point;
293 int FW_Vertex;
294
295 /* flag to determine if we need to call the open_font call */
296 int started;// = FALSE;
297 GLfloat *textpanel_vert;
298 GLfloat *textpanel_tex;
299 GLushort *textpanel_ind;
300 int textpanel_size;
301 int textpanel_vert_size;
302 int textpanel_tex_size;
303 int textpanel_ind_size;
304 struct Vector *font_table;
305 struct Vector *atlas_table;
306 //bitmap font shader variables
307 GLuint positionLoc;
308 GLuint texCoordLoc;
309 GLuint textureLoc;
310 GLuint color4fLoc;
311 GLuint textureID; // = 0;
312 GLuint blendLoc;
313 GLuint modelviewLoc;
314 GLuint projectionLoc;
315 GLuint programObject;// = 0;
316
317
319void *Component_Text_constructor(){
320 void *v = MALLOCV(sizeof(struct pComponent_Text));
321 memset(v,0,sizeof(struct pComponent_Text));
322 return v;
323}
324void Component_Text_init(struct tComponent_Text *t){
325 //public
326 //private
327 t->prv = Component_Text_constructor();
328 {
330
331 p->TextVerbose = FALSE;
332 p->font_directory = NULL;
333 /* flag to determine if we need to call the open_font call */
334 p->started = FALSE;
335 p->rowvec_allocn = 0;
336 p->rowvec = NULL;
337 p->pointsize = 0;
338 p->textpanel_vert = NULL;
339 p->textpanel_tex = NULL;
340 p->textpanel_ind = NULL;
341 p->textpanel_size = 0;
342 p->font_table = NULL;
343 p->atlas_table = NULL;
344 p->textureID = 0;
345 p->programObject = 0;
346 }
347}
348
349
351// Function Prototypes
352
353static void GUItablefree(struct Vector **guitable);
354static void dug9gui_DrawSubImage(float xpos,float ypos, float xsize, float ysize, int ix, int iy, int iw, int ih, int width, int height, int bpp, unsigned char *buffer);
355void finishedWithGlobalShader(void);
356void restoreGlobalShader();
357GLuint esLoadProgram ( const char *vertShaderSrc, const char *fragShaderSrc ); //defined in statuasbarHud.c
358static int FW_Open_Face(FT_Library library, char *thisfontname, int faceIndex, FT_Face *face);
359
361
362void Component_Text_clear(struct tComponent_Text *t){
363 //public
364 //private
365 {
367 FREE_IF_NZ(p->font_directory);
368 {
369 int row;
370 if(p->rowvec)
371 for(row=0;row<p->rowvec_allocn;row++){
372 FREE_IF_NZ(p->rowvec[row].str32);
373 FREE_IF_NZ(p->rowvec[row].chr);
374 }
375 FREE_IF_NZ(p->rowvec);
376 }
377 if(p->textpanel_size){
378 FREE_IF_NZ(p->textpanel_vert);
379 FREE_IF_NZ(p->textpanel_tex);
380 FREE_IF_NZ(p->textpanel_ind);
381 }
382 if(p->atlas_table){
383 GUItablefree(&p->atlas_table);
384 }
385 if(p->font_table){
386 GUItablefree(&p->font_table);
387 }
388
389 }
390}
391// ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
392
393void fwl_fontFileLocation(char *fontFileLocation) {
395 ttglobal tg = gglobal();
396 p = (ppComponent_Text)tg->Component_Text.prv;
397 /* Check if dir exists */
398 if (fontFileLocation){
399 char * lfontFileLocation = STRDUP(fontFileLocation);
400 if(strstr(lfontFileLocation,".ttf")){
401 //osx passes in the veramono.ttf path, strip to get just the directory
402 char * pend = strrchr(lfontFileLocation,'/');
403 if(pend) *pend = '\0';
404 }
405 if (do_dir_exists(lfontFileLocation)) {
406 FREE_IF_NZ(p->font_directory);
407 p->font_directory = lfontFileLocation;
408 }
409 }
410}
411
412/* function prototypes */
413static void FW_NewVertexPoint();
414static int FW_moveto (FT_Vector* to, void* user);
415static int FW_lineto(FT_Vector* to, void* user);
416static int FW_conicto(FT_Vector* control, FT_Vector* to, void* user);
417static int FW_cubicto(FT_Vector* control1, FT_Vector* control2, FT_Vector* to, void* user);
418static void FW_make_fontname (int num);
419static void render_screentext(struct X3D_Text * node);
420
421//static int FW_init_face(void);
422//static double FW_extent (int start, int length);
423
424static FT_Error FW_Load_Char(unsigned int idx);
425static void FW_draw_outline(FT_OutlineGlyph oglyph);
426static void FW_draw_character(FT_Glyph glyph);
427static int open_font(void);
428
429#if defined(_ANDROID) || defined(IPHONE)
430/* Android UI finds the font file(s) and sends them in here */
431void fwg_AndroidFontFile(FILE *myFile,int len) {
432 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
433 p->androidFontFile = myFile;
434 p->fileLen = len;
435}
436
437#endif //ANDROID
438
439
440void render_Text (struct X3D_Text * node)
441{
442 if(node) {
443 if(node->_isScreen){
444 render_screentext(node);
445 }else{
446 COMPILE_POLY_IF_REQUIRED (NULL, NULL, NULL, NULL, NULL);
447 //DISABLE_CULL_FACE;
448 CULL_FACE(node->solid)
449 render_polyrep(node);
450 }
451 }
452}
453
454static void FW_NewVertexPoint ()
455{
456 GLDOUBLE v2[3];
458 ttglobal tg = gglobal();
459 p = (ppComponent_Text)tg->Component_Text.prv;
460
461 /* //testing
462 {
463 double xx, yy, xx1,yy1, penx, peny, sx, sy, height, size;
464 int lastx,lasty, ppi, xres, dot6height, x_ppem, y_ppem;
465 double x_scale, y_scale, pixel_size_x, pixel_size_y, device_x, device_y, design_x, design_y;
466 double x_scale1, y_scale1;
467 double x_scale2, y_scale2;
468 ushort fu_per_em;
469 //FT_Size ftsize;
470 lastx = p->last_point.x;
471 lasty = p->last_point.y;
472 penx = p->pen_x;
473 peny = p->pen_y;
474 sx = p->shrink_x;
475 sy = p->shrink_y;
476 height = p->font_face[p->myff]->height;
477 fu_per_em = p->font_face[p->myff]->units_per_EM;
478 //ftsize = p->font_face[p->myff]->size;
479 dot6height = p->font_face[p->myff]->size->metrics.height;
480 x_ppem = p->font_face[p->myff]->size->metrics.x_ppem;
481 y_ppem = p->font_face[p->myff]->size->metrics.y_ppem;
482 x_scale = (double)(p->font_face[p->myff]->size->metrics.x_scale) / pow(2.0,16.0); // [du_dot6/fu] scales directly to 1/64 of device pixels
483 y_scale = (double)(p->font_face[p->myff]->size->metrics.y_scale) / pow(2.0,16.0); // [du_dot6/fu]
484 x_scale1 = x_scale / 64.0; // [du/fu] = [du_dot6/fu]*[1/dot6]
485 y_scale1 = y_scale / 64.0;
486 x_scale2 = (double)x_ppem / (double) fu_per_em; // [du/fu] = [du/em] / [fu/em]
487 y_scale2 = (double)y_ppem / (double) fu_per_em; // [du/fu] = [du/em] / [fu/em]
488 size = p->size;
489 ppi = PPI;
490 xres = XRES;
491 xx = OUT2GLB(p->last_point.x+p->pen_x,p->shrink_x);
492 //yy = OUT2GLB(p->last_point.y + p->pen_y,p->shrink_y);
493 yy = OUT2GLB(p->last_point.y ,p->shrink_y) + p->pen_y;
494 //#define OUT2GLB(a,s) (p->size * (0.0 +a) / ((1.0*(p->font_face[p->myff]->height)) / PPI*XRES) *s)
495 xx1 = size * (0.0 +lastx + penx) / (height /ppi * xres) *sx;
496 yy1 = (size * (0.0 +lasty ) / (height /ppi * xres) *sy) + peny;
497
498 }
499 */
500
501
502 /* printf ("FW_NewVertexPoint setting coord index %d %d %d\n", */
503 /* p->FW_pointctr, p->FW_pointctr*3+2,p->FW_rep_->actualCoord[p->FW_pointctr*3+2]); */
504
505 p->FW_rep_->actualCoord[p->FW_pointctr*3+0] = (float) (OUT2GLB(p->last_point.x,p->shrink_x) + p->pen_x);
506 p->FW_rep_->actualCoord[p->FW_pointctr*3+1] = (float) (OUT2GLB(p->last_point.y,p->shrink_y) + p->pen_y);
507 p->FW_rep_->actualCoord[p->FW_pointctr*3+2] = p->TextZdist;
508
509 /* the following should NEVER happen.... */
510 if (p->FW_RIA_indx >500) {
511 ConsoleMessage ("Text, relative index too small\n");
512 freewrlDie("FW_NewVertexPoint: this should never happen...");
513 }
514
515 p->FW_RIA[p->FW_RIA_indx]=p->FW_pointctr;
516 v2[0]=p->FW_rep_->actualCoord[p->FW_pointctr*3+0];
517 v2[1]=p->FW_rep_->actualCoord[p->FW_pointctr*3+1];
518 v2[2]=p->FW_rep_->actualCoord[p->FW_pointctr*3+2];
519 //July 2016 if you change things around here, you may want to check Tess.c Combiner callback
520 /* printf("glu s.b. rev 1.2 or newer, is: %s\n",gluGetString(GLU_VERSION)); */
521 FW_GLU_TESS_VERTEX(tg->Tess.text_tessobj,v2,&p->FW_RIA[p->FW_RIA_indx]);
522
523 if (p->TextVerbose) {
524 printf ("FW_NewVertexPoint %f %f %f index %d\n",
525 p->FW_rep_->actualCoord[p->FW_pointctr*3+0],
526 p->FW_rep_->actualCoord[p->FW_pointctr*3+1],
527 p->FW_rep_->actualCoord[p->FW_pointctr*3+2],
528 p->FW_RIA_indx);
529 }
530 p->FW_pointctr++;
531 p->FW_RIA_indx++;
532
533 if (p->FW_pointctr >= p->coordmaxsize) {
534 p->coordmaxsize+=800;
535 p->FW_rep_->actualCoord = (float *)REALLOC(p->FW_rep_->actualCoord,
536 sizeof(*(p->FW_rep_->actualCoord))*p->coordmaxsize*3);
537 printf("realloc actualCoord=%p\n",p->FW_rep_->actualCoord);
538 }
539}
540#define GLU_UNKNOWN 100124
541static int FW_moveto (FT_Vector* to, void* user)
542{
544 ttglobal tg = gglobal();
545 p = (ppComponent_Text)tg->Component_Text.prv;
546 UNUSED(user);
547
548 /* Have we started a new line */
549 if (p->contour_started) {
550 FW_GLU_NEXT_CONTOUR(tg->Tess.text_tessobj,GLU_UNKNOWN);
551 }
552
553 /* well if not, tell us that we have started one */
554 p->contour_started = TRUE;
555
556 p->last_point.x = to->x; p->last_point.y = to->y;
557
558 if (p->TextVerbose)
559 printf ("FW_moveto tox %ld toy %ld\n",to->x, to->y);
560
561
562
563 return 0;
564}
565
566static int FW_lineto (FT_Vector* to, void* user)
567{
568 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
569 UNUSED(user);
570
571
572 if ((p->last_point.x == to->x) && (p->last_point.y == to->y)) {
573 /* printf ("FW_lineto, early return\n"); */
574 return 0;
575 }
576
577 p->last_point.x = to->x;
578 p->last_point.y = to->y;
579
580 if (p->TextVerbose) {
581 printf ("FW_lineto, going to %ld %ld\n",to->x, to->y);
582 }
583 FW_NewVertexPoint();
584
585
586
587 return 0;
588}
589
590
591static int FW_conicto (FT_Vector* control, FT_Vector* to, void* user)
592{
593 FT_Vector ncontrol;
594 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
595
596
597
598 /* Bezier curve calcs; fairly rough, but makes ok characters */
599
600 if (p->TextVerbose)
601 printf ("FW_conicto\n");
602
603 /* Possible fix here!!! */
604 ncontrol.x = (int) ((double) 0.25*p->last_point.x + 0.5*control->x + 0.25*to->x);
605 ncontrol.y = (int) ((double) 0.25*p->last_point.y + 0.5*control->y + 0.25*to->y);
606
607 /* printf ("Cubic points (%d %d) (%d %d) (%d %d)\n", p->last_point.x,p->last_point.y, */
608 /* ncontrol.x, ncontrol.y, to->x,to->y); */
609
610 FW_lineto (&ncontrol,user);
611 FW_lineto (to,user);
612
613
614
615 return 0;
616}
617
618static int FW_cubicto (FT_Vector* control1, FT_Vector* control2, FT_Vector* to, void* user)
619{
620 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
621 /* really ignore control points */
622 if (p->TextVerbose)
623 printf ("FW_cubicto\n");
624
625 FW_lineto (control1, user);
626 FW_lineto (control2, user);
627 FW_lineto (to, user);
628 return 0;
629}
630/*
631 bit: 0 BOLD (boolean)
632 bit: 1 ITALIC (boolean)
633 bit: 2 SERIF
634 bit: 3 SANS
635 bit: 4 TYPEWRITER
636*/
637
638struct name_num {
639 char * facename;
640 char *family;
641 char *style;
642 char *style2; //linux installed font systme may use oblique instead of italic - this is alternate oblique
643 int num; //= (F << 2) + (I << 1) + B
644 int bold; //B
645 int italic; //I
646 int ifamily; //F 1=serif, 2=sans, 4=typewriter/mono
647} font_name_table [] = {
648 //face family, style , style2, num,B,I,F
649 {"VeraSe", "serif", NULL, NULL, 0x04,0,0,1}, /* Serif */
650 {"VeraSeBd","serif", "bold", NULL, 0x05,1,0,1}, /* Serif Bold */
651 {"VeraSe", "serif", "italic", NULL, 0x06,0,1,1}, /* Serif Ital */
652 {"VeraSeBd","serif","bold italic", "bold oblique", 0x07,1,1,1}, /* Serif Bold Ital */
653 {"Vera", "sans", NULL, NULL, 0x08,0,0,2}, /* Sans */
654 {"VeraBd", "sans", "bold", NULL, 0x09,0,1,2}, /* Sans Bold */
655 {"VeraIt", "sans", "italic", NULL, 0x0a,1,0,2}, /* Sans Ital */
656 {"VeraBI", "sans","bold italic", "bold oblique", 0x0b,1,1,2}, /* Sans Bold Ital */
657 {"VeraMono","monospace",NULL, NULL, 0x10,0,0,4}, /* Monospace */
658 {"VeraMoBd","monospace","bold", NULL, 0x11,1,0,4}, /* Monospace Bold */
659 {"VeraMoIt","monospace","italic", NULL, 0x12,0,1,4}, /* Monospace Ital */
660 {"VeraMoBI","monospace","bold italic","bold oblique", 0x13,1,1,4}, /* Monospace Bold Ital */
661 {NULL, NULL, NULL, NULL, 0,0,0,0},
662};
663struct name_num *get_fontname_entry_by_num(int num){
664 int i;
665 struct name_num *retval = NULL;
666 i = 0;
667 while(font_name_table[i].facename){
668 if(font_name_table[i].num == num) {
669 retval = &font_name_table[i];
670 break;
671 }
672 i++;
673 }
674 return retval;
675}
676struct name_num *get_fontname_entry_by_facename(char *facename){
677 int i;
678 struct name_num *retval = NULL;
679 i = 0;
680 while(font_name_table[i].facename){
681 if(!strcmp(font_name_table[i].facename,facename)) {
682 retval = &font_name_table[i];
683 break;
684 }
685 i++;
686 }
687 return retval;
688}
689char *facename_from_num(int num){
690 char *retval;
691 struct name_num *val;
692 retval = NULL;
693 val = get_fontname_entry_by_num(num);
694 if(val) retval = val->facename;
695 return retval;
696}
697/* make up the font name */
698//#define HAVE_FONTCONFIG 1
699#ifdef HAVE_FONTCONFIG
700void FW_make_fontname(int num) {
701/*
702 bit: 0 BOLD (boolean)
703 bit: 1 ITALIC (boolean)
704 bit: 2 SERIF
705 bit: 3 SANS
706 bit: 4 TYPEWRITER
707
708 JAS - May 2005 - The Vera freely distributable ttf files
709 are:
710
711 Vera.ttf
712 VeraMono.ttf
713 VeraSeBd.ttf
714 VeraSe.ttf
715 VeraMoBI.ttf
716 VeraMoIt.ttf
717 VeraIt.ttf
718 VeraMoBd.ttf
719 VeraBd.ttf
720 VeraBI.ttf
721
722 The files that were included were copyright Bitstream;
723 the Vera files are also from Bitstream, but are
724 freely distributable. See the copyright file in the
725 fonts directory.
726*/
727
728 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
729 FcPattern *FW_fp=NULL;
730 FcChar8 *FW_file=NULL;
731 FcResult result;
732
733 // check whether we have a config file
734 char* configfile = (char*)FcConfigFilename(0);
735 FILE*fi = fopen(configfile, "rb");
736 if(fi) {
737 fclose(fi);
738 //printf("<debug> Initializing FontConfig (configfile=%s)\n", configfile);
739 } else {
740 //printf("<debug> Initializing FontConfig (no configfile)\n");
741 }
742
743 if(!FcInit()) {
744 printf("<debug> FontConfig Initialization failed.\n");
745 }
746 FcConfig * config = FcConfigGetCurrent();
747 if(!config) {
748 printf("<debug> FontConfig Config Initialization failed.\n");
749 }
750
751 FcFontSet *set = FcConfigGetFonts(config, FcSetSystem);
752 //printf("<verbose> FontConfig initialized. Found %d fonts\n", set?set->nfont:0);
753 if(!set || !set->nfont) {
754 printf("<debug> FontConfig has found zero fonts. This is probably a bad thing.\n");
755 }
756
757 switch (num) {
758 case 0x04: /* Serif */
759 FW_fp=FcPatternBuild(NULL,FC_FAMILY,FcTypeString,"serif",FC_OUTLINE,FcTypeBool,FcTrue,NULL);
760 break;
761 case 0x05: /* Serif Bold */
762 FW_fp=FcPatternBuild(NULL,FC_FAMILY,FcTypeString,"serif",FC_OUTLINE,FcTypeBool,FcTrue,NULL);
763 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"bold");
764 break;
765 case 0x06: /* Serif Ital */
766 FW_fp=FcPatternBuild(NULL,FC_FAMILY,FcTypeString,"serif",FC_OUTLINE,FcTypeBool,FcTrue,NULL);
767 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"italic");
768 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"oblique");
769 break;
770 case 0x07: /* Serif Bold Ital */
771 FW_fp=FcPatternBuild(NULL,FC_FAMILY,FcTypeString,"serif",FC_OUTLINE,FcTypeBool,FcTrue,NULL);
772 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"bold italic");
773 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"bold oblique");
774 break;
775 case 0x08: /* Sans */
776 FW_fp=FcPatternBuild(NULL,FC_FAMILY,FcTypeString,"sans",FC_OUTLINE,FcTypeBool,FcTrue,NULL);
777 break;
778 case 0x09: /* Sans Bold */
779 FW_fp=FcPatternBuild(NULL,FC_FAMILY,FcTypeString,"sans",FC_OUTLINE,FcTypeBool,FcTrue,NULL);
780 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"bold");
781 break;
782 case 0x0a: /* Sans Ital */
783 FW_fp=FcPatternBuild(NULL,FC_FAMILY,FcTypeString,"sans",FC_OUTLINE,FcTypeBool,FcTrue,NULL);
784 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"italic");
785 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"oblique");
786 break;
787 case 0x0b: /* Sans Bold Ital */
788 FW_fp=FcPatternBuild(NULL,FC_FAMILY,FcTypeString,"sans",FC_OUTLINE,FcTypeBool,FcTrue,NULL);
789 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"bold italic");
790 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"bold oblique");
791 break;
792 case 0x10: /* Monospace */
793 FW_fp=FcPatternBuild(NULL,FC_FAMILY,FcTypeString,"monospace",FC_OUTLINE,FcTypeBool,FcTrue,NULL);
794 break;
795 case 0x11: /* Monospace Bold */
796 FW_fp=FcPatternBuild(NULL,FC_FAMILY,FcTypeString,"monospace",FC_OUTLINE,FcTypeBool,FcTrue,NULL);
797 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"bold");
798 break;
799 case 0x12: /* Monospace Ital */
800 FW_fp=FcPatternBuild(NULL,FC_FAMILY,FcTypeString,"monospace",FC_OUTLINE,FcTypeBool,FcTrue,NULL);
801 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"italic");
802 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"oblique");
803 break;
804 case 0x13: /* Monospace Bold Ital */
805 FW_fp=FcPatternBuild(NULL,FC_FAMILY,FcTypeString,"monospace",FC_OUTLINE,FcTypeBool,FcTrue,NULL);
806 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"bold italic");
807 FcPatternAddString(FW_fp,FC_STYLE,(const FcChar8*)"bold oblique");
808 break;
809 default:
810 printf ("dont know how to handle font id %x\n",num);
811 return;
812 }
813
814 FcConfigSubstitute(0,FW_fp,FcMatchPattern);
815 FcDefaultSubstitute(FW_fp);
816 set = FcFontSort(0, FW_fp, 1, 0, &result);
817
818 /* This isn't very smart, but we just go with the first match in the set that we can find a valid file for. */
819 if(set) {
820 // printf("<debug> okay, found a set with %d fonts\n", set?set->nfont:0);
821 int t;
822 for(t=0;t<set->nfont;t++) {
823 FcPattern *match = set->fonts[t];
824 if (FcPatternGetString(match,FC_FILE,0,&FW_file) != FcResultMatch) {
825 printf("<debug> FontConfig: Couldn't get fontconfig's filename for font id %x\n", num);
826 FW_file=0;
827 } else {
828 // printf("<debug> setting p->thisfontname to %s\n", FW_file);
829 /* strcpy didn't work, use strncpy and set the null character by hand */
830 memcpy(p->thisfontname,(char *)FW_file,strlen((char *)FW_file));
831 p->thisfontname[strlen((char *)FW_file)] = '\0';
832 break;
833 }
834 }
835 } else {
836 printf("<debug> no set? wha?\n");
837 }
838 FcPatternDestroy(FW_fp);
839 //FcPatternDestroy(set); bad - corrupts heap, set isn't a Pattern
840 if (set) FcFontSetSortDestroy(set);
841
842}
843#else
844
845void FW_make_fontname(int num) {
846/*
847 bit: 0 BOLD (boolean)
848 bit: 1 ITALIC (boolean)
849 bit: 2 SERIF
850 bit: 3 SANS
851 bit: 4 TYPEWRITER
852
853 JAS - May 2005 - The Vera freely distributable ttf files
854 are:
855
856 Vera.ttf
857 VeraMono.ttf
858 VeraSeBd.ttf
859 VeraSe.ttf
860 VeraMoBI.ttf
861 VeraMoIt.ttf
862 VeraIt.ttf
863 VeraMoBd.ttf
864 VeraBd.ttf
865 VeraBI.ttf
866
867 The files that were included were copyright Bitstream;
868 the Vera files are also from Bitstream, but are
869 freely distributable. See the copyright file in the
870 fonts directory.
871*/
872 char *fontname;
873 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
874 if (!p->font_directory) {
875 printf("Internal error: no font directory.\n");
876 //return;
877 }
878
879 fontname = facename_from_num(num);
880 if(!fontname){
881 printf ("dont know how to handle font id %x\n",num);
882 p->thisfontname[0] = 0;
883 }else{
884 if(p->font_directory){
885 strcpy (p->thisfontname, p->font_directory);
886 strcat(p->thisfontname,"/");
887 }
888 strcat(p->thisfontname,fontname);
889 strcat(p->thisfontname,".ttf");
890 }
891}
892#endif
893/* initialize the freetype library */
894static FT_Face FW_init_face0(FT_Library library, char* thisfontname)
895{
896 int err;
897 FT_Face ftface;
898#ifdef _ANDROID
899 FT_Open_Args myArgs;
900#endif
901 ftface = NULL;
902
903#ifdef _ANDROID
904 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
905
906
907 if ((p->fileLen == 0) || (p->androidFontFile ==NULL)) {
908 ConsoleMessage ("FW_init_face, fileLen and/or androidFontFile issue");
909 return ftface; //FALSE;
910 }
911
912#ifdef ANDROID_DEBUG
913 {
914 struct stat buf;
915 int fh,result;
916 ConsoleMessage ("TEXT INITIALIZATION - checking on the font file before doing anything");
917 if (0 == fstat(fileno(p->androidFontFile), &buf)) {
918 ConsoleMessage("TEXT INITIALIZATION file size is %ld\n", buf.st_size);
919 ConsoleMessage("TEXT INITIALIZATION time modified is %s\n", ctime(&buf.st_atime));
920 }
921 }
922#endif //ANDROID_DEBUG
923
924
925 // ConsoleMessage("FT_Open_Face looks ok to go");
926
927 unsigned char *myFileData = MALLOC(void *, p->fileLen+1);
928 size_t frv;
929 frv = fread (myFileData, (size_t)p->fileLen, (size_t)1, p->androidFontFile);
930 myArgs.flags = FT_OPEN_MEMORY;
931 myArgs.memory_base = myFileData;
932 myArgs.memory_size = p->fileLen;
933
934 err = FT_Open_Face(library, &myArgs, 0, &ftface);
935 if (err) {
936 char line[2000];
937 sprintf (line,"FreeWRL - FreeType, can not set char size for font %s\n",thisfontname);
938 ConsoleMessage(line);
939 return NULL; //FALSE;
940 }
941
942#ifdef ANDROID_DEBUG
943 {
944 struct stat buf;
945 int fh,result;
946 if (0 == fstat(fileno(p->androidFontFile), &buf)) {
947 ConsoleMessage("FIN TEXT INITIALIZATION file size is %ld\n", buf.st_size);
948 ConsoleMessage("FIN TEXT INITIALIZATION time modified is %s\n", ctime(&buf.st_atime));
949 }
950 }
951#endif //ANDROID_DEBUG
952
953 fclose(p->androidFontFile);
954 p->androidFontFile = NULL;
955
956#else //ANDROID
957 /* load a font face */
958 err = FW_Open_Face(library, thisfontname, 0, &ftface);
959
960#endif //ANDROID
961
962 if (err) {
963 printf ("FreeType - can not use font %s\n",thisfontname);
964 ftface = NULL; //FALSE;
965 }
966
967 return ftface;
968}
969int FW_set_facesize(FT_Face ftface,char *thisfontname, double pointsize){
970 // you can re-set the facesize after the fontface is loaded
971 //http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Set_Char_Size
972 // googling, some say there are 72 points per inch in typography, or 1 point = 1/72 inch
973 FT_Error err;
974 int iret;
975 iret = FALSE;
976 if(ftface){
977 int pt_dot6;
978 iret = TRUE;
979 pt_dot6 = (int)(pointsize * 64.0 + .5);
980 err = FT_Set_Char_Size(ftface, /* handle to face object */
981 pt_dot6, //pointsize*64, /* char width in 1/64th of points [pt dot6] */
982 pt_dot6, //pointsize*64, /* char height in 1/64th of points [pt dot6]*/
983 XRES, /* horiz device resolution [du/in] */
984 YRES); /* vert device resolution [du/in] */
985
986 if (err) {
987 printf ("FreeWRL - FreeType, can not set char size for font %s\n",thisfontname);
988 iret = FALSE;
989 }
990 }
991 return iret;
992}
993
994/* Load a character, a maximum of MAX_GLYPHS are here. Note that no
995 line formatting is done here; this is just for pre-calculating
996 extents, etc.
997
998 NOTE: we store the handles to each glyph object for each
999 character in the glyphs array
1000*/
1001FT_Error FW_Load_Char(unsigned int idx)
1002{
1003 FT_Glyph glyph = NULL;
1004 FT_UInt glyph_index;
1005 int error;
1006 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
1007
1008 if (p->cur_glyph >= MAX_GLYPHS) {
1009 return 1;
1010 }
1011
1012 /* retrieve glyph index from character code */
1013 glyph_index = FT_Get_Char_Index(p->font_face[p->myff],idx);
1014
1015 /* loads the glyph in the glyph slot */
1016
1017 error = FT_Load_Glyph(p->font_face[p->myff], glyph_index, FT_LOAD_DEFAULT) ||
1018 FT_Get_Glyph(p->font_face[p->myff]->glyph, &glyph);
1019
1020 if (!error) { p->glyphs[p->cur_glyph++] = glyph; }
1021 return error;
1022}
1023//typedef struct our_combiner_data {
1024// float *coords;
1025// int *counter;
1026//} our_combiner_data;
1027static void FW_draw_outline (FT_OutlineGlyph oglyph)
1028{
1029 int thisptr = 0;
1030 int retval = 0;
1032 text_combiner_data cbdata;
1033 ttglobal tg = gglobal();
1034 p = (ppComponent_Text)tg->Component_Text.prv;
1035
1036 /* gluTessBeginPolygon(global_tessobj,NULL); */
1037 gluTessNormal(tg->Tess.text_tessobj,0.0,0.0,1.0);
1038 // FW_GLU_BEGIN_POLYGON(tg->Tess.global_tessobj);
1039 //p->FW_rep_->actualCoord[p->FW_pointctr*3+0] = (float) (OUT2GLB(p->last_point.x,p->shrink_x) + p->pen_x);
1040 cbdata.coords = p->FW_rep_->actualCoord;
1041 cbdata.counter = &p->FW_pointctr;
1042 cbdata.ria = p->FW_RIA;
1043 cbdata.riaindex = &p->FW_RIA_indx;
1044 //p->FW_RIA[p->FW_RIA_indx]=p->FW_pointctr;
1045 //July 2016 if you change things around here, you may want to also check Tess.c Combiner callback
1046
1047 gluTessBeginPolygon( tg->Tess.text_tessobj, &cbdata );
1048 gluTessBeginContour( tg->Tess.text_tessobj );
1049 p->FW_Vertex = 0;
1050
1051 /* thisptr may possibly be null; I dont think it is use in freetype */
1052 retval = FT_Outline_Decompose( &oglyph->outline, &p->FW_outline_interface, &thisptr);
1053
1054 /* gluTessEndPolygon(global_tessobj); */
1055 gluTessEndContour( tg->Tess.text_tessobj );
1056 gluTessEndPolygon( tg->Tess.text_tessobj );
1057 //FW_GLU_END_POLYGON(tg->Tess.global_tessobj);
1058
1059 if (retval != FT_Err_Ok)
1060 printf("FT_Outline_Decompose, error %d\n",retval);
1061}
1062
1063/* draw a glyph object */
1064static void FW_draw_character (FT_Glyph glyph)
1065{
1066 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
1067 if (glyph->format == ft_glyph_format_outline) {
1068 FW_draw_outline ((FT_OutlineGlyph) glyph);
1069 p->pen_x += (glyph->advance.x >> 10); //[fu dot6] = [fu dot16_to_dot6(dot16)]
1070 } else {
1071 printf ("FW_draw_character; glyphformat -- need outline for %s %s\n",
1072 p->font_face[p->myff]->family_name,p->font_face[p->myff]->style_name);
1073 }
1074 if (p->TextVerbose) printf ("done character\n");
1075}
1076
1077
1078int open_font()
1079{
1080 int len;
1081 int err;
1082 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
1083
1084 if (p->TextVerbose)
1085 printf ("open_font called\n");
1086
1087 p->FW_outline_interface.move_to = (FT_Outline_MoveTo_Func)FW_moveto;
1088 p->FW_outline_interface.line_to = (FT_Outline_LineTo_Func)FW_lineto;
1089 p->FW_outline_interface.conic_to = (FT_Outline_ConicTo_Func)FW_conicto;
1090 p->FW_outline_interface.cubic_to = (FT_Outline_CubicTo_Func)FW_cubicto;
1091 p->FW_outline_interface.shift = 0;
1092 p->FW_outline_interface.delta = 0;
1093
1094#ifndef _ANDROID
1095
1096#ifndef HAVE_FONTCONFIG
1097 /* where are the fonts stored? */
1098 if(!p->font_directory)
1099 p->font_directory = makeFontDirectory();
1100 //ConsoleMessage("font directory=%s\n",p->font_directory);
1101 /* were fonts not found? */
1102 if (p->font_directory == NULL) {
1103
1104 ConsoleMessage ("Have a Text node, but no font library or directory found; continuing with a default builtin font\n");
1105
1106 }
1107#endif //HAVE_FONTCONFIG
1108#endif //ANDROID
1109
1110 /* lets initialize some things */
1111 for (len = 0; len < num_fonts; len++) {
1112 p->font_state[len] = FONTSTATE_NONE;
1113 }
1114
1115 if ((err = FT_Init_FreeType(&p->library))) {
1116 fprintf(stderr, "FreeWRL FreeType Initialize error %d\n",err);
1117 return FALSE;
1118 }
1119
1120 return TRUE;
1121}
1122int open_FTlibrary_if_not_already(){
1123 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
1124 if (!p->started) {
1125 if (open_font()) {
1126 p->started = TRUE;
1127 } else {
1128 printf ("Could not find System Fonts for Text nodes\n");
1129 }
1130 }
1131 return p->started;
1132}
1133FT_Library getFontLibrary(){
1134 FT_Library library;
1135 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
1136 library = NULL;
1137 if(open_FTlibrary_if_not_already())
1138 library = p->library;
1139 return library;
1140}
1141
1142/* UTF-8 to UTF-32 conversion -
1143// x3d and wrl strings are supposed to be in UTF-8
1144// when drawing strings, FreeType will take a UTF-32"
1145// http://en.wikipedia.org/wiki/UTF-32/UCS-4
1146// conversion method options:
1147// libicu
1148// - not used - looks big
1149// - http://site.icu-project.org/ LIBICU - opensource, C/C++ and java.
1150// mbstocws
1151// - win32 version didn't seem to do any converting
1152// iconv - gnu libiconv
1153// - http://gnuwin32.sourceforge.net/packages/libiconv.htm
1154// - the win32 version didn't run - bombs on open
1155// guru code:
1156// - adopted - or at least the simplest parts
1157// - not rigourous checking though - should draw bad characters if
1158// if you have it wrong in the file
1159// - http://floodyberry.wordpress.com/2007/04/14/utf-8-conversion-tricks/
1160// - not declared opensource, so we are using the general idea
1161// in our own code
1162*/
1163static const unsigned int Replacement = ( 0xfffd );
1164static const unsigned char UTF8TailLengths[256] = {
1165 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1166 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1167 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1168 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1169 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1170 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1171 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1172 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1173 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1174 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1175 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1176 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1177 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1178 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1179 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
1180 3,3,3,3,3,3,3,3,4,4,4,4,5,5,0,0
1181};
1182
1183static unsigned int utf8_to_utf32_char(unsigned char *s, unsigned char *end, unsigned int *inc ) {
1184 unsigned int tail, i, c;
1185 c = (*s);
1186 s++;
1187 (*inc)++;
1188 if( c < 0x80 )
1189 return c; //regular ASCII
1190 tail = UTF8TailLengths[c];
1191 if( !tail || (s + tail > end))
1192 return Replacement;
1193
1194 //decoding loop
1195 c &= ( 0x3f >> tail );
1196 for(i=0;i<tail;++i) {
1197 if( (s[i] & 0xc0) != 0x80 )
1198 break;
1199 c = (c << 6) + (s[i] & 0x3f);
1200 }
1201
1202 //s += i;
1203 (*inc) += i;
1204 if( i != tail )
1205 return Replacement;
1206 return c;
1207}
1208
1209// called in MainLoop.c
1210unsigned int *utf8_to_utf32(unsigned char *utf8string, unsigned int *str32, unsigned int *len32)
1211{
1212 //does the UTF-8 to UTF-32 conversion
1213 //it allocates the unsigned int array it returns - please FREE() it
1214 //it adds an extra on the end and null-terminates
1215 //len32 is the length, not including the null/0 termination.
1216 unsigned int *to, *to0;
1217 unsigned char *start, *end;
1218 int lenchar, l32;
1219 lenchar = (int)strlen((const char *)utf8string);
1220 to0 = to = str32; //MALLOC(unsigned int*,(lenchar + 1)*sizeof(unsigned int));
1221 start = utf8string;
1222 end = (unsigned char *)&utf8string[lenchar];
1223 l32 = 0;
1224 while ( start < end ) {
1225 while ( ( *start < 0x80 ) && ( start < end ) ) {
1226 *to++ = *start++;
1227 l32++;
1228 }
1229 if ( start < end ) {
1230 unsigned int inc = 0;
1231 *to++ = utf8_to_utf32_char(start,end,&inc);
1232 start += inc;
1233 //start++; //done in above function
1234 l32++;
1235 }
1236 }
1237 //to0[l32] = 0;
1238 *len32 = l32;
1239 return to0;
1240}
1241
1242#ifdef OLDCODE
1243
1244Seems to be unused - JAS - April 2017
1245
1246static unsigned int utf8_to_utf32_bytes(unsigned char *s, unsigned char *end)
1247{
1248 unsigned int tail, c;
1249 int inc =0;
1250 c = (*s);
1251 s++;
1252 inc++;
1253 if( c < 0x80 )
1254 return 1; //regular ASCII 1 byte
1255 tail = UTF8TailLengths[c];
1256 tail = s + tail > end ? (unsigned int)end - (unsigned int)s : tail; //min(tail,end-s)
1257 return tail + 1;
1258}
1259#endif //OLDCODE
1260
1261
1262#ifdef OLDCODE
1263
1264Seems to be unused - JAS - April 2017
1265
1266static unsigned int len_utf8(unsigned char *utf8string)
1267{
1268 unsigned char *start, *end;
1269 int lenchar, l32;
1270 lenchar = (int)strlen((const char *)utf8string);
1271 start = utf8string;
1272 end = (unsigned char *)&utf8string[lenchar];
1273 l32 = 0;
1274 while ( start < end ) {
1275 while ( ( *start < 0x80 ) && ( start < end ) ) {
1276 start++;
1277 l32++; //ASCII char
1278 }
1279 if ( start < end ) {
1280 start += utf8_to_utf32_bytes(start,end);
1281 l32++;
1282 }
1283 }
1284 return l32;
1285}
1286#endif //OLDCODE
1287
1288
1289
1290#include <malloc.h>
1291
1292//void register_Polyrep_combiner();
1293void prep_screentext(struct X3D_Text *tnode, int num, double screensize);
1294/* take a text string, font spec, etc, and make it into an OpenGL Polyrep or rowvec[] for screen(pixel) font
1295 For placing text on the screen directly from freewrl ie GUI or HUD like use the CaptionText contenttype
1296 described elsewhere.
1297 spacing [em/em] or [1]
1298 mysize [m/em]
1299 maxextent [m]
1300 length[] [m]
1301 */
1302//void register_Text_combiner();
1303void FW_rendertext(struct X3D_Text *tnode, unsigned int numrows,struct Uni_String **ptr,
1304 unsigned int nl, float *length, double maxext,
1305 double spacing, double mysize, unsigned int fsparam,
1306 struct X3D_PolyRep *rp)
1307{
1308 unsigned char *str = NULL; /* string pointer- initialization gets around compiler warning */
1309 unsigned int i,row,ii,irow;
1310 row32 *rowvec;
1311 int rowvec_allocn;
1312 double shrink = 0;
1313 double rshrink = 0;
1314 //int counter=0;
1315 int char_count=0;
1316 int est_tri=0;
1318 ttglobal tg = gglobal();
1319 p = (ppComponent_Text)tg->Component_Text.prv;
1320
1321 p->shrink_x = 1.0;
1322 p->shrink_y = 1.0;
1323 /* fsparam has the following bitmaps:
1324
1325 bit: 0 horizontal (boolean)
1326 bit: 1 leftToRight (boolean)
1327 bit: 2 topToBottom (boolean)
1328 (style)
1329 bit: 3 BOLD (boolean)
1330 bit: 4 ITALIC (boolean)
1331 (family)
1332 bit: 5 SERIF
1333 bit: 6 SANS
1334 bit: 7 TYPEWRITER
1335 bit: 8 indicates exact font pointer (future use)
1336 (Justify - major)
1337 bit: 9 FIRST
1338 bit: 10 BEGIN
1339 bit: 11 MIDDLE
1340 bit: 12 END
1341 (Justify - minor)
1342 bit: 13 FIRST
1343 bit: 14 BEGIN
1344 bit: 15 MIDDLE
1345 bit: 16 END
1346
1347 bit: 17-31 spare
1348 */
1349
1350 /* z distance for text - only the status bar has anything other than 0.0 */
1351 p->TextZdist = 0.0f;
1352
1353 /* have we done any rendering yet */
1354 /* do we need to call open font? */
1355 if(!open_FTlibrary_if_not_already()) return;
1356
1357 if (p->TextVerbose)
1358 printf ("entering FW_Render_text \n");
1359
1360 p->pen_x = 0.0; //[m]
1361 p->pen_y = 0.0; //[m]
1362 p->cur_glyph = 0;
1363
1364
1365 /* is this fontface opened */
1366 p->myff = (fsparam >> 3) & 0x1F;
1367#if defined (ANDROID)
1368// Android - for now, all fonts are identical
1369p->myff = 4;
1370#endif
1371 if (p->myff <4) {
1372 /* we dont yet allow externally specified fonts, so one of
1373 the font style bits HAS to be set. If there was no FontStyle
1374 node, this will be blank, so... */
1375 p->myff = 4;
1376 }
1377 if (p->font_state[p->myff] < FONTSTATE_TRIED) {
1378 //try just once, not every time we come in here
1379 FT_Face fontface;
1380 FW_make_fontname(p->myff);
1381 fontface = FW_init_face0(p->library,p->thisfontname);
1382 if (fontface) {
1383 p->font_face[p->myff] = fontface;
1384 p->font_state[p->myff] = FONTSTATE_LOADED;
1385 }else{
1386 p->font_state[p->myff] = FONTSTATE_TRIED;
1387 }
1388 }
1389 if(!p->font_face[p->myff]) return; //couldn't load fonts
1390
1391 if(tnode->_isScreen){
1392 p->pointsize = mysize;
1393 p->size = mysize * (double)XRES/(double)PPI; //[du] = [pt]*[du/in]/[pt/in]
1394 }else{
1395 p->pointsize = POINTSIZE;
1396 p->size = mysize; /* global variable for size [m/em] */
1397
1398 }
1399 FW_set_facesize(p->font_face[p->myff],p->thisfontname,p->pointsize);
1400
1401 //realloc row vector if necessary
1402 if(tnode->_isScreen){
1403 //per-text-node rowvec
1404 screentextdata *sdata;
1405 if(!tnode->_screendata)
1406 prep_screentext(tnode,p->myff, p->pointsize);
1407 sdata = (screentextdata*)tnode->_screendata;
1408 rowvec_allocn = sdata->nalloc;
1409 rowvec = sdata->rowvec;
1410 }else{
1411 //vectorized text, per-freewrl-tglobal rowvec (re-usable via realloc)
1412 rowvec_allocn = p->rowvec_allocn;
1413 rowvec = p->rowvec;
1414 }
1415 if(!rowvec){
1416 rowvec = (row32*)MALLOCV(numrows * sizeof(row32));
1417 memset(rowvec,0,numrows * sizeof(row32));
1418 }
1419 if(rowvec_allocn < numrows){
1420 rowvec = REALLOC(rowvec,numrows * sizeof(row32));
1421 memset(&rowvec[rowvec_allocn],0,(numrows - rowvec_allocn)*sizeof(row32));
1422 rowvec_allocn = numrows;
1423 }
1424 //realloc any str8 or str32s in each row
1425 for (row=0; row<numrows; row++) {
1426 unsigned int len;
1427 str = (unsigned char *)ptr[row]->strptr;
1428 len = strlen((const char *)str);
1429 if(rowvec[row].allocn < len){
1430 rowvec[row].str32 = (unsigned int *)REALLOC(rowvec[row].str32,(len+1) * sizeof(unsigned int));
1431 rowvec[row].chr = (chardata *) REALLOC(rowvec[row].chr,len*sizeof(chardata));
1432 rowvec[row].allocn = len;
1433 rowvec[row].len32 = 0;
1434 }
1435 }
1436 if(tnode->_isScreen){
1437 screentextdata *sdata;
1438 sdata = (screentextdata*)tnode->_screendata;
1439 sdata->rowvec = rowvec;
1440 sdata->nalloc = rowvec_allocn;
1441 sdata->nrow = numrows;
1442 sdata->faceheight = (float)p->font_face[p->myff]->height;
1443 sdata->size = p->size;
1444 sdata->emsize = mysize;
1445 }else{
1446 p->rowvec = rowvec;
1447 p->rowvec_allocn = rowvec_allocn;
1448 }
1449
1450 /* load all of the characters first... */
1451 for (row=0; row<numrows; row++) {
1452 unsigned int len32, *str32;
1453 double total_row_advance, widest_char;
1454 str = (unsigned char *)ptr[row]->strptr;
1455 //len = strlen(str);
1456 /* utf8_to_utf32 */
1457 //in theory str32 will always have # of chars <= len str8
1458 // so allocating len8 chars will be enough or sometimes too much
1459 str32 = rowvec[row].str32;
1460 utf8_to_utf32(str,str32,&len32);
1461 rowvec[row].iglyphstartindex = p->cur_glyph;
1462 rowvec[row].len32 = len32;
1463 rowvec[row].str32 = str32;
1464 total_row_advance = 0;
1465 widest_char = 0;
1466 for(i=0;i<len32;i++){
1467 int icount;
1468 FW_Load_Char(str32[i]);
1469 icount = p->cur_glyph -1;
1470 rowvec[row].chr[i].iglyph = icount;
1471 //http://www.freetype.org/freetype2/docs/reference/ft2-glyph_management.html#FT_GlyphRec Glyph->advance dot16
1472 rowvec[row].chr[i].advance = OUT2GLB(p->glyphs[icount]->advance.x >> 10,1.0); //[m] = fu_dot6_to_m([fu_dot16/DOT10])
1473 total_row_advance += rowvec[row].chr[i].advance; //[m] = [m]
1474 widest_char = rowvec[row].chr[i].advance > widest_char ? rowvec[row].chr[i].advance : widest_char;
1475 //[m] = [m] [m]
1476 }
1477 rowvec[row].hrowsize = total_row_advance; //[m] = [m]
1478 rowvec[row].vcolsize = len32 * p->size; //[m] = [m/em] = [em] * [em/em] * [m/em]
1479 rowvec[row].widestchar = widest_char; //[m] = [m]
1480 char_count += len32;
1481 //FREE_IF_NZ(utf32); //see bottom of this function
1482 }
1483
1484 if (p->TextVerbose) {
1485 printf ("Text: rows %d char_count %d\n",numrows,char_count);
1486 }
1487
1488 /* Jan 2016/dug9 - got all the permutations shown here -both horizontal and vertical- working:
1489 http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/text.html#t-horizontalTRUE
1490 */
1491
1492 if(HORIZONTAL){
1493 //find the longest row dimension
1494 shrink = 1.0; //[1]
1495 if(maxext > 0) {
1496 double maxlen = 0; //[m] or [m/em]
1497 for(row = 0; row < numrows; row++) {
1498 double hrowsize;
1499 hrowsize = rowvec[row].hrowsize; //[m] = [m]
1500 maxlen = hrowsize > maxlen ? hrowsize : maxlen; //[m] = [m] or [m]
1501 }
1502 if(maxlen > maxext)
1503 shrink = maxext / maxlen; //[1] = [m]/[m]
1504 }
1505 //shrink = 1.0;
1506 /* Justify MINOR (verticle), FIRST, BEGIN, MIDDLE and END */
1507 //bit: 13 FIRST
1508 //bit: 14 BEGIN
1509 //bit: 15 MIDDLE
1510 //bit: 16 END
1511 //http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/text.html#t-horizontalTRUE
1512
1513 /* BEGIN */
1514 p->pen_y = 0.0; //[em] default Begin (top), if no (proper) minor justify entered
1515 if(fsparam & (0x400<<(4))){
1516 p->pen_y = 0.0; //[em] = [em]
1517 }
1518 /* FIRST */
1519 if(fsparam & (0x200<<(4))){
1520 p->pen_y = 1.0; //[em] = [em]
1521 }
1522 /* MIDDLE */
1523 if (fsparam & (0x800<<(4))) {
1524 p->pen_y = (double)(numrows)/2.0; //[em] = [em]
1525 }
1526 /* END */
1527 if (fsparam & (0x1000<<(4))) {
1528 /* printf ("rowlen is %f\n",rowlen); */
1529 p->pen_y = (double)numrows; //[em] = [em]
1530 }
1531
1532
1534 if (TOPTOBOTTOM) {
1535 p->pen_y -= 1.0; //[em] = [em]
1536 }else{
1537 if(fsparam & (0x200<<(4))) //if first, make like begin
1538 p->pen_y -= 1.0; //[em] = [em]
1539 p->pen_y = numrows - 1.0 - p->pen_y; //[em] = [em] - [em] - [em]
1540 }
1541 p->pen_y *= mysize; //[m] = [em] * [m/em]
1542 //screen/vector-agnostic loop to compute penx,y and shrinkage for each glyph
1543 for(irow = 0; irow < numrows; irow++) {
1544 unsigned int lenchars;
1545 double rowlen;
1546
1547 row = irow; //[em]
1548 if(!TOPTOBOTTOM) row = numrows - irow -1;
1549
1550 str = (unsigned char *)ptr[row]->strptr;
1551 if (p->TextVerbose)
1552 printf ("text2 row %d :%s:\n",row, str);
1553 p->pen_x = 0.0; //[m]
1554 rshrink = 1.0; //[1]
1555 rowlen = rowvec[row].hrowsize; //[m] = [m]
1556 lenchars = rowvec[row].len32;
1557
1558 if((row < nl) && !(APPROX(length[row],0.0))) {
1559 rshrink = length[row] / rowlen; //[1] = [m]/[m]
1560 }
1561
1562 /* MAJOR Justify, FIRST, BEGIN, */
1563 if (((fsparam & 0x200) || (fsparam & 0x400)) && !LEFTTORIGHT ) {
1564 /* printf ("rowlen is %f\n",rowlen); */
1565 p->pen_x = -rowlen; //[m] = [m]
1566 }
1567
1568 /* MAJOR MIDDLE */
1569 if (fsparam & 0x800) {
1570 p->pen_x = -rowlen/2.0; //[m] = [m]
1571 }
1572
1573 /* MAJOR END */
1574 //if ((fsparam & 0x1000) && (fsparam & 0x01)) {
1575 if ((fsparam & 0x1000) && LEFTTORIGHT ) {
1576 /* printf ("rowlen is %f\n",rowlen); */
1577 p->pen_x = -rowlen; //[m] = [m]
1578 }
1579
1580 for(ii=0; ii<lenchars; ii++) {
1581 /* FT_UInt glyph_index; */
1582 i = ii;
1583 if(!LEFTTORIGHT)
1584 i = lenchars - ii -1;
1585 rowvec[row].chr[i].x = p->pen_x; //[m]
1586 rowvec[row].chr[i].y = p->pen_y; //[m]
1587 rowvec[row].chr[i].sx = shrink*rshrink; //[1] = [1]*[1]
1588 rowvec[row].chr[i].sy = 1.0; //[1]
1589 p->pen_x += rowvec[row].chr[i].advance * shrink*rshrink;// [m] = [m] * [1]
1590 }
1591 p->pen_y += -spacing * p->size; //[m] = [em] * [m/em]
1592 }
1593 //END HORIZONTAL
1594 }else{
1595 //IF VERTICAL
1596 //
1597 double widest_column, column_spacing;
1598 //find the longest row dimension
1599 double maxlen = 0.0;
1600 shrink = 1.0;
1601 for(row = 0; row < numrows; row++) {
1602 double vcolsize = rowvec[row].vcolsize; //[m] = [m]
1603 maxlen = vcolsize > maxlen ? vcolsize : maxlen; //[m] = [m] or [m]
1604 }
1605 if(maxext > 0) {
1606 if(maxlen > maxext) shrink = maxext / maxlen; //[1] = [m]/[m]
1607 }
1608 widest_column = 0.0;
1609 for(row=0;row<numrows;row++)
1610 widest_column = rowvec[row].widestchar > widest_column ? rowvec[row].widestchar : widest_column;
1611 //[m] = [m] or [m]
1612 //column_spacing = widest_column;
1613 column_spacing = spacing * p->size; //[m] = [1] * [m]
1614 /* Justify MINOR (verticle), FIRST, BEGIN, MIDDLE and END */
1615 //bit: 13 FIRST
1616 //bit: 14 BEGIN
1617 //bit: 15 MIDDLE
1618 //bit: 16 END
1619 //http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/text.html#t-horizontalTRUE
1620
1621 /* BEGIN */
1622 /* FIRST */
1623 if(fsparam & (0x200<<(4)) || fsparam & (0x400<<(4))){
1624 //p->pen_x = -1.0 * widest_column;
1625 if(LEFTTORIGHT)
1626 p->pen_x = 0.0; //[m]
1627 else
1628 p->pen_x = -(double)numrows * column_spacing;
1629 //[m] = [1] * [m]
1630 }
1631 /* MIDDLE */
1632 if (fsparam & (0x800<<(4))) {
1633 p->pen_x = -(double)(numrows)/2.0 *column_spacing; //[m] = [1] * [m]
1634 }
1635 /* END */
1636 if (fsparam & (0x1000<<(4))) {
1637 /* printf ("rowlen is %f\n",rowlen); */
1638 if(LEFTTORIGHT)
1639 p->pen_x = -(double)numrows * column_spacing; //[m] = [1] * [m]
1640 else
1641 p->pen_x = 0.0; //[m]
1642 }
1643
1644 //screen/vector-agnostic loop to compute penx,y and shrinkage for each glyph
1645 for(irow = 0; irow < numrows; irow++) {
1646 unsigned int lenchars;
1647 double rowlen;
1648 double starty;
1649
1650 row = irow;
1651 if(!LEFTTORIGHT) row = numrows - irow -1;
1652
1653 str = (unsigned char *)ptr[row]->strptr;
1654 if (p->TextVerbose)
1655 printf ("text2 row %d :%s:\n",row, str);
1656 p->pen_y = 0.0;
1657 rshrink = 1.0;
1658 rowlen = rowvec[row].vcolsize; //[m] = [m]
1659 lenchars = rowvec[row].len32;
1660
1661 if((row < nl) && !(APPROX(length[row],0.0))) {
1662 rshrink = length[row] / rowlen;
1663 //[1] = [m] / [m]
1664 }
1665 starty = -1.0*shrink*rshrink*p->size; //[m] = [em]*[1]*[1]*[m/em]
1666 /* MAJOR Justify, FIRST, BEGIN, */
1667 if ((fsparam & 0x200) || (fsparam & 0x400)){
1668 if(TOPTOBOTTOM )
1669 p->pen_y = starty; //[m] = [m]
1670 else
1671 p->pen_y = rowlen + starty; //[m] = [m] + [m]
1672 }
1673
1674 /* MAJOR MIDDLE */
1675 if (fsparam & 0x800) {
1676 p->pen_y = rowlen/2.0 + starty; //[m] = [m] + [m]
1677 }
1678
1679 /* MAJOR END */
1680 if (fsparam & 0x1000 ) {
1681 if(TOPTOBOTTOM)
1682 p->pen_y = rowlen + starty; //[m] = [m] + [m]
1683 else
1684 p->pen_y = starty; //[m] = [m]
1685 }
1686
1687 for(ii=0; ii<lenchars; ii++) {
1688 /* FT_UInt glyph_index; */
1689 /* int error; */
1690 // int kk;
1691 double penx;
1692 i = ii;
1693 if(!TOPTOBOTTOM)
1694 i = lenchars - ii -1;
1695 penx = p->pen_x; //[m] = [m]
1696 if(!LEFTTORIGHT)
1697 penx = penx + column_spacing - rowvec[row].chr[i].advance;
1698 //[m] = [m] + [m] *[1] - [m]
1699 rowvec[row].chr[i].x = penx; //[m] = [m]
1700 rowvec[row].chr[i].y = p->pen_y; //[m] = [m]
1701 rowvec[row].chr[i].sx = 1.0; //[1]
1702 rowvec[row].chr[i].sy = shrink*rshrink; //[1] = [1]*[1]
1703 p->pen_y += -p->size * shrink * rshrink; //[m] = [m] - [m/em]*[1]*[1]
1704 //[1] = [1/em] = [m/em] * [1] * [1/m] LOOKS WRONG
1705 }
1706 p->pen_x += column_spacing; //[m] = [m] + [m]*[1]
1707 }
1708 }
1709
1710 if(!tnode->_isScreen){
1711 //vector glyph construction
1712 //register_Text_combiner(); //Tess.c
1713 p->FW_rep_ = rp;
1714 //PER TEXT NODE
1715 //rep->actualCoords[FW_pointctr] cumulative XYZ points over all glyphs in Text node
1716 p->FW_pointctr=0; /* how many points used so far? maps into rep-_coord */
1717 //rep->cindex[indx_count] cumulative triangle vertex indexes over all glyphs in text node
1718 p->indx_count=0; /* maps intp FW_rep_->cindex */
1719 p->contour_started = FALSE;
1720
1721 /* what is the estimated number of triangles? assume a certain number of tris per char */
1722 est_tri = char_count*800; /* 800 was TESS_MAX_COORDS - REALLOC if needed */
1723 p->coordmaxsize=est_tri;
1724 p->cindexmaxsize=est_tri;
1725 p->FW_rep_->cindex=MALLOC(GLuint *, sizeof(*(p->FW_rep_->cindex))*est_tri);
1726 p->FW_rep_->actualCoord = MALLOC(float *, sizeof(*(p->FW_rep_->actualCoord))*est_tri*3);
1727 for(row = 0; row < numrows; row++) {
1728 unsigned int lenchars = rowvec[row].len32;
1729 for(i=0; i<lenchars; i++) {
1730 int kk,x;
1731 chardata chr;
1732
1733 chr = rowvec[row].chr[i];
1734 p->pen_x = chr.x; //[m] = [m]
1735 p->pen_y = chr.y; //[m] = [m]
1736 p->shrink_x = chr.sx; //[1]
1737 p->shrink_y = chr.sy; //[1]
1738 //PER GLYPH
1739 //gobal_IFS_Coords[global_IFS_Coord_count] - Triangle vertex indexes into actualCoords
1740 tg->Tess.text_IFS_Coord_count = 0;
1741 //FW_RIA[FW_RIA_indx] - glyph outline contour point indexes into actualCoord
1742 p->FW_RIA_indx = 0; // index into FW_RIA
1743 kk = rowvec[row].chr[i].iglyph;
1744 FW_draw_character (p->glyphs[kk]);
1745 FT_Done_Glyph (p->glyphs[kk]);
1746 /* copy over the tesselated coords for the character to
1747 * the rep structure */
1748
1749 for (x=0; x<tg->Tess.text_IFS_Coord_count; x++) {
1750 /*printf ("copying %d\n",global_IFS_Coords[x]); */
1751
1752 /* did the tesselator give us back garbage? */
1753
1754 if ((tg->Tess.text_IFS_Coords[x] >= p->cindexmaxsize) ||
1755 (p->indx_count >= p->cindexmaxsize) ||
1756 (tg->Tess.text_IFS_Coords[x] < 0)) {
1757 if (p->TextVerbose)
1758 printf ("Tesselated index %d out of range; skipping indx_count, %d cindexmaxsize %d global_IFS_Coord_count %d\n",
1759 tg->Tess.text_IFS_Coords[x],p->indx_count,p->cindexmaxsize,tg->Tess.text_IFS_Coord_count);
1760 /* just use last point - this sometimes happens when */
1761 /* we have intersecting lines. Lets hope first point is */
1762 /* not invalid... JAS */
1763 p->FW_rep_->cindex[p->indx_count] = p->FW_rep_->cindex[p->indx_count-1];
1764 if (p->indx_count < (p->cindexmaxsize-1)) p->indx_count ++;
1765 } else {
1766 /*
1767 printf("global_ifs_coords is %d indx_count is %d \n",global_IFS_Coords[x],p->indx_count);
1768 printf("filling up cindex; index %d now points to %d\n",p->indx_count,global_IFS_Coords[x]);
1769 */
1770 p->FW_rep_->cindex[p->indx_count++] = tg->Tess.text_IFS_Coords[x];
1771 }
1772 }
1773
1774 if (p->indx_count > (p->cindexmaxsize-400)) {
1775 p->cindexmaxsize += 800; /* 800 was TESS_MAX_COORDS; */
1776 p->FW_rep_->cindex=(GLuint *)REALLOC(p->FW_rep_->cindex,sizeof(*(p->FW_rep_->cindex))*p->cindexmaxsize);
1777 }
1778 if(0){
1779 //as a test, write out a glyph to a wrl file,
1780 //then load the wrl in another instance of frewrl to see if its properly formed
1781 //this can show you if you have the right idea
1782 static int _once = 0;
1783 int ii,jj,ntris;
1784 ntris = tg->Tess.text_IFS_Coord_count / 3;
1785 if(!_once){
1786 //_once means it will output the first character in the text string here
1787 FILE *fptris = fopen("test_glyph_triangles.wrl","w+");
1788 fprintf(fptris,"%s\n","#VRML V2.0 utf8");
1789 fprintf(fptris,"Transform {\n children [\n Shape {\n appearance Appearance { material Material { diffuseColor .6 .6 .6 }}\n");
1790 fprintf(fptris," geometry IndexedFaceSet { solid FALSE \n");
1791 fprintf(fptris," coordIndex ");
1792 //indexes
1793 fprintf(fptris,"[");
1794 for(ii=0;ii<ntris;ii++){
1795 for(jj=0;jj<3;jj++){
1796 fprintf(fptris," %d",p->FW_rep_->cindex[ii*3+jj]);
1797 }
1798 fprintf(fptris," -1");
1799 }
1800 fprintf(fptris,"]\n");
1801
1802 fprintf(fptris,"coord Coordinate { \n");
1803 fprintf(fptris," point [");
1804 //we use FW_RIA_indx instead of IFS_Coord_count to print out the coords:
1805 // FW_RIA_indx includes contour points dropped by tesselation Combiner,
1806 // that are still in actualCoords, and the indexing above needs as filler
1807 // in order for the captured indexing to still make sense
1808 // IFS_Coord_count: its 3 x number of triangles, but doesn't know how long actualCoord is
1809 // that its indexes refer to
1810 for(ii=0;ii<p->FW_RIA_indx;ii++){
1811 for(jj=0;jj<3;jj++){
1812 fprintf(fptris," %f",p->FW_rep_->actualCoord[ii*3 + jj]);
1813 }
1814 fprintf(fptris,",");
1815 }
1816
1817 fprintf(fptris," ] }}}\n");
1818 fprintf(fptris," ]}");
1819 fclose(fptris);
1820 // original closed polygon as 1 face IFS
1821 fptris = fopen("test_glyph_polygon.wrl","w+");
1822 fprintf(fptris,"%s\n","#VRML V2.0 utf8");
1823 fprintf(fptris,"Transform {\n children [\n Shape {\n appearance Appearance { material Material { diffuseColor .5 .5 .5 }}\n");
1824 fprintf(fptris," geometry IndexedFaceSet { solid FALSE convex FALSE \n");
1825 fprintf(fptris," coordIndex ");
1826 //indexes
1827 fprintf(fptris,"[");
1828 for(ii=0;ii<p->FW_RIA_indx;ii++){
1829 fprintf(fptris," %d",ii);
1830 }
1831 fprintf(fptris," -1");
1832 fprintf(fptris,"]\n");
1833
1834 fprintf(fptris,"coord Coordinate { \n");
1835 fprintf(fptris," point [");
1836 //we use FW_RIA_indx instead of IFS_Coord_count to print out the coords:
1837 // FW_RIA_indx includes contour points dropped by tesselation Combiner,
1838 // that are still in actualCoords, and the indexing above needs as filler
1839 // in order for the captured indexing to still make sense
1840 // IFS_Coord_count: its 3 x number of triangles, but doesn't know how long actualCoord is
1841 // that its indexes refer to
1842 for(ii=0;ii<p->FW_RIA_indx;ii++){
1843 for(jj=0;jj<3;jj++){
1844 fprintf(fptris," %f",p->FW_rep_->actualCoord[ii*3 + jj]);
1845 }
1846 fprintf(fptris,",");
1847 }
1848
1849 fprintf(fptris," ] }}}\n");
1850 fprintf(fptris," ]}");
1851 //fclose(fptris);
1852
1853 // original closed polygon as Polygon2D
1854 //fptris = fopen("test_glyph_polygon.wrl","w+");
1855 fprintf(fptris,"%s\n","#VRML V2.0 utf8");
1856 fprintf(fptris,"Transform {\n translation 0 0 .1 children [\n Shape {\n appearance Appearance { material Material { emissiveColor .1 .8 .2 }}\n");
1857 fprintf(fptris," geometry Polyline2D { \n");
1858 fprintf(fptris," lineSegments [");
1859 //we use FW_RIA_indx instead of IFS_Coord_count to print out the coords:
1860 // FW_RIA_indx includes contour points dropped by tesselation Combiner,
1861 // that are still in actualCoords, and the indexing above needs as filler
1862 // in order for the captured indexing to still make sense
1863 // IFS_Coord_count: its 3 x number of triangles, but doesn't know how long actualCoord is
1864 // that its indexes refer to
1865 for(ii=0;ii<p->FW_RIA_indx;ii++){
1866 for(jj=0;jj<2;jj++){
1867 fprintf(fptris," %f",p->FW_rep_->actualCoord[ii*3 + jj]);
1868 }
1869 fprintf(fptris,",");
1870 }
1871
1872 fprintf(fptris," ] }}\n");
1873 fprintf(fptris," ]}");
1874 fclose(fptris);
1875
1876
1877 _once = 1;
1878 }
1879
1880 }
1881 }
1882 }
1883 /* save the triangle count (note, we have a "vertex count", not a "triangle count" */
1884 p->FW_rep_->ntri=p->indx_count/3;
1885 /* set these variables so they are not uninitialized */
1886 p->FW_rep_->ccw=FALSE;
1887
1888 /* if indx count is zero, DO NOT get rid of MALLOCd memory - creates a bug as pointers cant be null */
1889 if (p->indx_count !=0) {
1890 /* REALLOC bug in linux - this causes the pointers to be eventually lost... */
1891 /* REALLOC (p->FW_rep_->cindex,sizeof(*(p->FW_rep_->cindex))*p->indx_count); */
1892 /* REALLOC (p->FW_rep_->actualCoord,sizeof(*(p->FW_rep_->actualCoord))*p->FW_pointctr*3); */
1893 }
1894
1895 /* now, generate normals */
1896 p->FW_rep_->normal = MALLOC(float *, sizeof(*(p->FW_rep_->normal))*p->indx_count*3);
1897 for (i = 0; i<(unsigned int)p->indx_count; i++) {
1898 p->FW_rep_->normal[i*3+0] = 0.0f;
1899 p->FW_rep_->normal[i*3+1] = 0.0f;
1900 p->FW_rep_->normal[i*3+2] = 1.0f;
1901 }
1902
1903 /* do we have texture mapping to do? */
1904 if (HAVETODOTEXTURES) {
1905 p->FW_rep_->GeneratedTexCoords[0] = MALLOC(float *, sizeof(*(p->FW_rep_->GeneratedTexCoords[0]))*(p->FW_pointctr+1)*3);
1906 /* an attempt to try to make this look like the NIST example */
1907 /* I can't find a standard as to how to map textures to text JAS */
1908 for (i=0; i<(unsigned int)p->FW_pointctr; i++) {
1909 p->FW_rep_->GeneratedTexCoords[0][i*3+0] = p->FW_rep_->actualCoord[i*3+0]*1.66f;
1910 p->FW_rep_->GeneratedTexCoords[0][i*3+1] = 0.0f;
1911 p->FW_rep_->GeneratedTexCoords[0][i*3+2] = p->FW_rep_->actualCoord[i*3+1]*1.66f;
1912 }
1913 }
1914 //register_Polyrep_combiner(); //Tess.c - polyrep is the default
1915 } //if isScreenFont
1916
1917 if (p->TextVerbose) printf ("exiting FW_Render_text\n");
1918}
1919
1920int avatarCollisionVolumeIntersectMBBf(double *modelMatrix, float *minVals, float *maxVals);
1921
1922void collide_Text (struct X3D_Text *node)
1923{
1924 struct sNaviInfo *naviinfo;
1925 GLDOUBLE awidth,atop,abottom,astep,modelMatrix[16];
1926 struct point_XYZ delta = {0,0,-1};
1927 struct X3D_PolyRep pr;
1928 ttglobal tg;
1929 int change = 0;
1930 tg = gglobal();
1931
1932 if(node->_isScreen > 0) return; //don't collide with screentext
1933
1934 naviinfo = (struct sNaviInfo*)tg->Bindable.naviinfo;
1935
1936 awidth = naviinfo->width; /*avatar width*/
1937 atop = naviinfo->width; /*top of avatar (relative to eyepoint)*/
1938 abottom = -naviinfo->height; /*bottom of avatar (relative to eyepoint)*/
1939 astep = -naviinfo->height+naviinfo->step;
1940
1941
1942 /*JAS - normals are always this way - helps because some
1943 normal calculations failed because of very small triangles
1944 which made collision calcs fail, which moved the Viewpoint...
1945 so, if there is no need to calculate normals..., why do it? */
1946
1947 /* JAS - first pass, intern is probably zero */
1948 if (node->_intern == NULL) return;
1949
1950 /* JAS - no triangles in this text structure */
1951 if (node->_intern->ntri == 0) return;
1952
1953 /*save changed state.*/
1954 if (node->_intern)
1955 change = node->_intern->irep_change;
1956
1957 COMPILE_POLY_IF_REQUIRED(NULL, NULL, NULL, NULL, NULL);
1958
1959 if (node->_intern)
1960 node->_intern->irep_change = change;
1961
1962 /* restore changes state, invalidates compile_polyrep work done, so it can be done
1963 correclty in the RENDER pass */
1964
1965 pr = *(node->_intern);
1966
1967 /* do the triangle test again, now that we may have compiled the node. */
1968 if (pr.ntri == 0) {
1969 /* printf ("TRIANGLE NOW HAS ZERO NODES...\n"); */
1970 return;
1971 }
1972
1973 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
1974
1975 matmultiplyAFFINE(modelMatrix,modelMatrix,FallInfo()->avatar2collision);
1976 //dug9july2011 matmultiply(modelMatrix,FallInfo()->avatar2collision,modelMatrix);
1977
1978 if(!avatarCollisionVolumeIntersectMBBf(modelMatrix,pr.minVals,pr.maxVals) )return;
1979 delta = planar_polyrep_disp(abottom,atop,astep,awidth,pr,modelMatrix,PR_DOUBLESIDED,delta);
1980 /* delta used as zero */
1981
1982 vecscale(&delta,&delta,-1);
1983
1984 accumulate_disp(CollisionInfo(),delta);
1985
1986#ifdef COLLISIONVERBOSE
1987 if((fabs(delta.x) != 0. || fabs(delta.y) != 0. || fabs(delta.z) != 0.)) {
1988 fprintf(stderr,"COLLISION_TXT: (%f %f %f) (%f %f %f)\n",
1989 t_orig.x, t_orig.y, t_orig.z,
1990 delta.x, delta.y, delta.z);
1991 }
1992#endif
1993}
1994
1995void make_Text (struct X3D_Text *node)
1996{
1997 struct X3D_PolyRep *rep_ = node->_intern;
1998 double spacing = 1.0;
1999 double size = 1.0;
2000 int isScreenFontStyle;
2001 unsigned int fsparams = 0;
2002
2003 isScreenFontStyle = FALSE;
2004 /* We need both sides */
2005 DISABLE_CULL_FACE;
2006
2007 if (node->fontStyle) {
2008 /* We have a FontStyle. Parse params (except size and spacing) and
2009 make up an unsigned int with bits indicating params, to be
2010 passed to the Text Renderer
2011
2012 bit: 0 horizontal (boolean)
2013 bit: 1 leftToRight (boolean)
2014 bit: 2 topToBottom (boolean)
2015 (style)
2016 bit: 3 BOLD (boolean)
2017 bit: 4 ITALIC (boolean)
2018 (family)
2019 bit: 5 SERIF
2020 bit: 6 SANS
2021 bit: 7 TYPEWRITER
2022 bit: 8 indicates exact font pointer (future use)
2023 (Justify - major)
2024 bit: 9 FIRST
2025 bit: 10 BEGIN
2026 bit: 11 MIDDLE
2027 bit: 12 END
2028 (Justify - minor)
2029 bit: 13 FIRST
2030 bit: 14 BEGIN
2031 bit: 15 MIDDLE
2032 bit: 16 END
2033
2034 bit: 17-31 spare
2035 */
2036
2037 struct X3D_FontStyle *fsp;
2038 unsigned char *lang;
2039 unsigned char *style;
2040 struct Multi_String family;
2041 struct Multi_String justify;
2042 int tmp; int tx;
2043 struct Uni_String **svptr;
2044 unsigned char *stmp;
2045
2046 /* step 0 - is the FontStyle a proto? */
2047 POSSIBLE_PROTO_EXPANSION(struct X3D_FontStyle *, node->fontStyle,fsp);
2048 if(fsp){
2049 /* fsp = (struct X3D_FontStyle *)node->fontStyle; */
2050 if (fsp->_nodeType != NODE_FontStyle && fsp->_nodeType != NODE_ScreenFontStyle) {
2051 ConsoleMessage ("Text node has FontStyle of %s\n",stringNodeType(fsp->_nodeType));
2052 node->fontStyle = NULL; /* stop dumping these messages */
2053 }
2054
2055 /* step 0.5 - now that we know FontStyle points ok, go for
2056 * the other pointers */
2057 lang = (unsigned char *)fsp->language->strptr;
2058 style = (unsigned char *)fsp->style->strptr;
2059
2060 family = fsp->family;
2061 justify = fsp->justify;
2062
2063 /* Step 1 - record the spacing and size, for direct use */
2064 spacing = fsp->spacing;
2065 size = fsp->size;
2066 if(fsp->_nodeType == NODE_ScreenFontStyle){
2067 struct X3D_ScreenFontStyle *fsps = (struct X3D_ScreenFontStyle *)fsp;
2068 //if the scene file said size='.8' by mistake instead of pointSize='10',
2069 // ..x3d parser will leave pointSize at its default 12.0
2070 size = fsps->pointSize;
2071 isScreenFontStyle = TRUE;
2072 }
2073
2074 /* Step 2 - do the SFBools */
2075 fsparams = (fsp->horizontal)|(fsp->leftToRight<<1)|(fsp->topToBottom<<2);
2076
2077 /* Step 3 - the SFStrings - style and language */
2078 /* actually, language is not parsed yet */
2079
2080 if (strlen((const char *)style)) {
2081 if (!strcmp((const char *)style,"ITALIC")) {fsparams |= 0x10;}
2082 else if(!strcmp((const char *)style,"BOLD")) {fsparams |= 0x08;}
2083 else if (!strcmp((const char *)style,"BOLDITALIC")) {fsparams |= 0x18;}
2084 else if (strcmp((const char *)style,"PLAIN")) {
2085 printf ("Warning - FontStyle style %s assuming PLAIN\n",style);}
2086 }
2087 if (strlen((const char *)lang)) {
2088 printf ("Warning - FontStyle - language param unparsed\n");
2089 }
2090
2091
2092 /* Step 4 - the MFStrings now. Family, Justify. */
2093 /* family can be blank, or one of the pre-defined ones. Any number of elements */
2094
2095 svptr = family.p;
2096 for (tmp = 0; tmp < family.n; tmp++) {
2097 stmp = (unsigned char *)svptr[tmp]->strptr;
2098 if (strlen((const char *)stmp) == 0) {fsparams |=0x20; }
2099 else if (!strcmp((const char *)stmp,"SERIF")) { fsparams |= 0x20;}
2100 else if(!strcmp((const char *)stmp,"SANS")) { fsparams |= 0x40;}
2101 else if (!strcmp((const char *)stmp,"TYPEWRITER")) { fsparams |= 0x80;}
2102 /* else { printf ("Warning - FontStyle family %s unknown\n",stmp);}*/
2103 }
2104
2105 svptr = justify.p;
2106 tx = justify.n;
2107 /* default is "BEGIN" "FIRST" */
2108 if (tx == 0) { fsparams |= 0x2400; }
2109 else if (tx == 1) { fsparams |= 0x2000; }
2110 else if (tx > 2) {
2111 printf ("Warning - FontStyle, max 2 elements in Justify\n");
2112 tx = 2;
2113 }
2114
2115 for (tmp = 0; tmp < tx; tmp++) {
2116 stmp = (unsigned char *)svptr[tmp]->strptr;
2117 if (strlen((const char *)stmp) == 0) {
2118 if (tmp == 0) {
2119 fsparams |= 0x400;
2120 } else {
2121 fsparams |= 0x2000;
2122 }
2123 }
2124 else if (!strcmp((const char *)stmp,"FIRST")) { fsparams |= (0x200<<(tmp*4));}
2125 else if(!strcmp((const char *)stmp,"BEGIN")) { fsparams |= (0x400<<(tmp*4));}
2126 else if (!strcmp((const char *)stmp,"MIDDLE")) { fsparams |= (0x800<<(tmp*4));}
2127 else if (!strcmp((const char *)stmp,"END")) { fsparams |= (0x1000<<(tmp*4));}
2128 /* else { printf ("Warning - FontStyle family %s unknown\n",stmp);}*/
2129 }
2130 } //if(fsp)
2131 } else {
2132 /* send in defaults */
2133 fsparams = 0x2427;
2134 }
2135
2136 /* do the Text parameters, guess at the number of triangles required*/
2137 rep_->ntri = 0;
2138
2139 /*
2140 printf ("Text, calling FW_rendertext\n");
2141 call render text - NULL means get the text from the string
2142 */
2143 //normal scene 3D vectorized text
2144 node->_isScreen = isScreenFontStyle;
2145
2146 FW_rendertext(node,((node->string).n),((node->string).p),
2147 ((node->length).n),((node->length).p),
2148 (node->maxExtent),spacing,size,fsparams,rep_);
2149
2150
2151}
2152
2153
2154
2155
2156
2157
2158
2159//==========================SCREENFONT===============================================
2160/* thanks go to dug9 for contributing atlasfont code to freewrl from his dug9gui project
2161
2162 Notes on freewrl use of atlas/screen fonts, new Jan 2016:
2163 CaptionText -a kind of direct-to-screen text - see mainloop.c contenttype_captiontext-
2164 and Text + Component_Layout > ScreenFontStyle
2165 both need speedy rendering of what could be rapidly changing text strings, such
2166 as Time or FPS that might change on every frame. For that we don't want to recompile
2167 a new polyrep on each frame. Just run down the string printing characters as textured rectangles.
2168 And we want to share fonts and anyone can load a font Text -vector or screen- or CaptionText,
2169 and once loaded the others recognize and don't need to reload.
2170 The texture used -called a font atlas- holds all the ascii chars by default -with a fast lookup-,
2171 plus it can add as-needed extended utf8 characters with a slower lookup method.
2172
2173 AtlasFont - the facename, font path, one per fontface
2174 Atlas - the bitmap, used as texture, one per AtlasFont
2175 AtlasEntrySet - the lookup table for ascii and extended characters,
2176 one per fontsize for a given AtlasFont
2177*/
2178
2179/* UTF8 String literal support
2180 if you want to put extended (non ASCII, > 127) chars in CaptionText:
2181 a) keep/make the string literals utf8 somehow, and
2182 b) we call a utf8 to utf32 function below
2183 a) How to keep/make string literals utf8:
2184 DO NOT (non-portable):
2185 X use u8"" or utf8"" string literals, which gcc supports I think, MS does not (by default uses locale codepage which crashes freetype lib), so not portable
2186 X use wchar_t and L"", which both msvc and gcc support, but gcc is 32bit unicode and MS is 16bit unicode,
2187 so not quite portable, although you could convert either to utf8 from literals early,
2188 using platform specific code
2189 DO (portable):
2190 a) embed escape sequences. Capital Omega is hex CE A9 "\xCE\xA9" or octal 316 251 "\316\251" http://calc.50x.eu/
2191 b) convert from codepage to utf8 externally, and paste sequence into string: codepage windows-1250 è = utf8 "è" é = "é" http://www.motobit.com/util/charset-codepage-conversion.asp
2192 or use linux iconv
2193 c) read strings from a utf8 encoded file (utf16 and utf32 files requires BOM byte order mark
2194 to determine endieness of file, utf8 does not need this mark, except your reading software needs to know
2195 whether to convert from UTF8 or trust it's ASCII, or convert from a specific codepage. Determining heuristically
2196 is difficult. So just put an ascii string UTF8 or ASCII or CODEPAGE-12500 on the first line to tell your own code)
2197*/
2198
2199static int iyup = 0; //iyup = 1 means y is up on texture (like freewrl) (doesn't work right), iyup=0 means y-down texture coords (works)
2200
2201struct _AtlasFont;
2202struct _Atlas;
2203struct _AtlasEntry;
2204struct _GUIElement;
2205
2206typedef struct _AtlasFont AtlasFont;
2207typedef struct _Atlas Atlas;
2208typedef struct _AtlasEntry AtlasEntry;
2209typedef struct _GUIElement GUIElement;
2210
2211typedef struct ivec2 {int X; int Y;} ivec2;
2212// OLDCODE static ivec2 ivec2_init(int x, int y);
2213
2214typedef enum GUIElementType
2215{
2216 GUI_FONT = 9,
2217 GUI_ATLAS = 10,
2218 GUI_ATLASENTRY = 11,
2219 GUI_ATLASENTRYSET = 12,
2220} GUIElementType;
2221
2222
2223//a fontsize with the alphabet, or a whole set of named widgets, comprise an AtlasEntrySet
2224// in theory more than one AtlasEntrySet could use the same atlas, allowing fewer textures, and
2225// better texture surface utilization %
2226// You need to do a separate 'Set for each fontsize, because there's only one ascii lookup table per Set
2227typedef struct AtlasEntrySet {
2228 char *name;
2229 int type;
2230 int EMpixels;
2231 int maxadvancepx; //max_advance for x for a fontface
2232 int rowheight; //if items are in regular rows, this is a hint, during making of the atlas
2233 int lastascii;
2234 char *atlasName;
2235 Atlas *atlas;
2236 AtlasFont *font;
2237 AtlasEntry *ascii[128]; //fast lookup table, especially for ascii 32 - 126 to get entry *. NULL if no entry.
2238 struct Vector *entries; //atlasEntry * -all entries -including ascii as first 128- sorted for binary searching
2240
2241
2242//atlas entry has the box for one glyph, or one widget icon
2244 char *name;
2245 int type;
2246 ivec2 apos; //position in atlas texture, pixels from UL of texture image
2247 ivec2 size; //size in atlas texture, pixels
2248 int ichar; //int pseudoname instead of char * name, used for unicode char
2249 ivec2 pos; //shift/offset from target placement ie glyph image shift from lower left corner of character
2250 ivec2 advance; //used for glyphs, advance to the next char which may be different -wider- than pixel row width
2251};
2252
2253
2254//atlas is an image buffer. It doesn't care what's stored in the image, although it
2255//does help when adding things to the atlas, by storing the last location as penx,y
2256//The reason for using an atlas versus individual little images: fewer texture changes sent to the GPU
2257// which dramatically speeds rendering of the gui.
2258// For example drawing a textpanel full of text glyph by glyph slows rendering to 8 FPS on intel i5,
2259// and using an atlas it's 60FPS - hardly notice the gui rendering.
2260// The reason we don't do all font as atlasses by default: some font ie textCaption could be dynamically
2261// resizable by design, and if it's just a few chars, its more efficent to do glyph by glyph than
2262// render several atlases. But in theory if its just a few chars, you could render just those chars
2263// to an atlas at different sizes.
2264struct _Atlas {
2265 char *name;
2266 int type;
2267 unsigned char *texture; //the GLubyte* buffer
2268 //int textureID; //gl texture buffer
2269 int bytesperpixel; //1 for alpha, 2 lumalpha 4 rgba. font should be 1 alpha
2270 //FT_Face fontFace;
2271 ivec2 size; //pixels, of texture: X=width, Y=height
2272 int rowheight; //if items are in regular rows, this is a hint, during making of the atlas
2273 ivec2 pen; //have a cursor, so it's easy to position an additional entry in unoccupied place in atlas
2274};
2275
2276
2277// named type is for upcasting any GUI* to a simple name
2278// so a generic table search can be done by name for any type
2279typedef struct GUINamedType {
2280 char *name;
2281 int type;
2282} GUINamedType;
2283
2284//GUIFont instances go in a public lookup table, so a fontface is loaded only once
2285//and if an atlas has been generated for that fontface by the programmer, it's added
2286//to the font
2288 char *name;
2289 int type;
2290 char *path;
2291 FT_Face fontFace;
2292 int EMsize;
2293 //struct Vector atlasSizes; //GUIAtlasEntrySet*
2294 AtlasEntrySet *set;
2295};
2296
2297
2298typedef struct vec2 {float X; float Y;} vec2;
2299typedef struct vec4 {float X; float Y; float Z; float W;} vec4;
2300
2302{
2303 char *name;
2304 GUIElementType type; //element = 0, panel 1, image 2, button 3, checkBox 4, textCaption 5, textPanel 6
2305 //ivec2 anchors;
2306 void * userData;
2307};
2308
2309
2310
2311
2312
2313
2314//STATICS
2315//static struct Vector *font_table; //AtlasFontSize*
2316//static struct Vector *atlas_table; //Atlas *
2317
2318static void *GUImalloc(struct Vector **guitable, int type);
2319static AtlasEntry * AtlasAddIChar(AtlasFont *font, AtlasEntrySet *entryset, int ichar);
2320
2322
2323static void AtlasEntrySet_init(AtlasFont *font, AtlasEntrySet *me, char *name){
2324 me->name = name;
2325 me->font = font;
2326 me->type = GUI_ATLASENTRYSET;
2327 me->entries = newVector(AtlasEntry *,256);
2328 me->lastascii = -1;
2329 memset(me->ascii,0,128*sizeof(int)); //initialize ascii fast lookup table to NULL, which means no char glyph stored
2330}
2331
2332
2333#ifdef OLDCODE
2334
2335Code appears to be unused - JAS April 2017
2336
2337static void AtlasEntry_init1(AtlasEntry *me, char *name, int index, int x, int y, int width, int height){
2338 //use this for .bmp atlases that are already tiled
2339 me->name = name;
2340 me->type = GUI_ATLASENTRY;
2341 me->apos.X = x;
2342 me->apos.Y = y;
2343 me->size.X = width;
2344 me->size.Y = height;
2345 me->ichar = index;
2346}
2347#endif //OLDCODE
2348
2349static void Atlas_init(Atlas *me, int size, int rowheight){
2350 me->type = GUI_ATLAS;
2351 me->name = NULL;
2352 //use this for generating font atlas from .ttf
2353 me->pen.X = me->pen.Y = 0;
2354 me->size.X = me->size.Y = size;
2355 me->rowheight = rowheight; //spacing between baselines for textpanel, in pixels (can get this from fontFace once loaded and sized to EM)
2356 //me->EMpixels = EMpixels; //desired size of "EM" square (either x or y dimension, same) in pixels
2357 me->bytesperpixel = 1; //TT fonts are rendered to an antialiased 8-bit alpha texture
2358 //me->bytesperpixel = 2;
2359#ifdef ANGLEPROJECT
2360 #ifdef WINRT
2361 me->bytesperpixel = 1; //ANGLEPROJECT winrt 8.1 - can't seem to mipmap 1 BPP GL_ALPHA/A8/ii needs 2 bpp GL_LUMINANCE_ALPHA/A8L8 or bombs
2362 //possible patch shown here: https://bugs.chromium.org/p/angleproject/issues/detail?id=632
2363 //got a 2014 era copy of MSOpenTech VS2013-WINRT successfully built with patch and 1bpp/GL_ALPHA runs and looks good
2364 //DirectX Surface Formats: https://msdn.microsoft.com/en-us/library/windows/desktop/bb153349(v=vs.85).aspx
2365 #else
2366 me->bytesperpixel = 1; //ANGLEPROJECT desktop - 1 bpp/A8/ii/GL_ALPHA is good
2367 #endif
2368#endif
2369 me->texture = (unsigned char*)MALLOCV(me->size.X *me->size.Y*me->bytesperpixel);
2370 memset(me->texture,127,me->size.X *me->size.Y*me->bytesperpixel); //make it black by default
2371 /*
2372 //here are some fun stripes to initialize the texture data, for debugging:
2373 int kk;
2374 for(int i=0;i<size;i++){
2375 for(int j=0;j<size;j++){
2376 kk = (i*size + j)*me->bytesperpixel;
2377 me->texture[kk+me->bytesperpixel-1] = i % 2 == 0 ? 255 : 0;
2378 }
2379 }
2380 */
2381}
2382
2383static void subimage_paste(unsigned char *image, ivec2 size, unsigned char* subimage, int bpp, ivec2 ulpos, ivec2 subsize ){
2384 int i;
2385 int imrow, imcol, impos,bpp1;
2386 int iscol, ispos;
2387 bpp1 = 1; //bits per pixel of the subimage (bpp is for the atlas)
2388 for(i=0;i<subsize.Y;i++ ){
2389 imrow = ulpos.Y + i;
2390 imcol = ulpos.X;
2391 impos = (imrow * size.X + imcol)*bpp;
2392 //isrow = i;
2393 iscol = 0;
2394 ispos = (i*subsize.X + iscol)*bpp1;
2395 if(impos >= 0 && (impos+subsize.X*bpp <= size.X*size.Y*bpp))
2396 {
2397 if(bpp == 1) memcpy(&image[impos],&subimage[ispos],subsize.X*bpp1);
2398 else {
2399 //we receive a 1byte-per-pixel GL_ALPHA image chip from font library
2400 //here we expand it to 2 bytes per pixel GL_LUMINANCE_ALPHA
2401 int j, k;
2402 for(k=0;k<subsize.X;k++){
2403 for(j=0;j<bpp;j++){
2404 //x looks fuzzy, unreadable, unlike the opengl 1bpp GL_ALPHA
2405 if(j ==5) image[impos+k+j] = 255;
2406 else image[impos+k+j] = subimage[ispos+k];
2407 }
2408 }
2409 }
2410 }
2411 else
2412 printf("!");
2413 }
2414}
2415
2416
2417static GUINamedType *searchGUItable(struct Vector* guitable, char *name){
2418 int i;
2419 GUINamedType *retval = NULL;
2420 if(guitable)
2421 for(i=0;i<vectorSize(guitable);i++){
2422 GUINamedType *el = vector_get(GUINamedType*,guitable,i);
2424 if(!strcmp(name,el->name)){
2425 retval = el;
2426 break;
2427 }
2428 }
2429 return retval;
2430}
2431
2432
2433static void Atlas_addEntry(Atlas *me, AtlasEntry *entry, unsigned char *gray){
2434 ivec2 pos;
2435 //use this with atlasEntry_init for .ttf font atlas
2436 //paste in somewhere, and update cRow,cCol by width,height of gray
2437 //layout in rows
2438 //if((me->pen.X + me->rowheight) > me->size.X){
2439 // me->pen.Y += me->rowheight;
2440 // me->pen.X = 0;
2441 //}
2442 if((me->pen.X + entry->size.X) > me->size.X){
2443 me->pen.Y += me->rowheight;
2444 me->pen.X = 0;
2445 }
2446 if(me->pen.Y > me->size.Y){
2447 ConsoleMessage("Atlas too small, skipping %d\n",entry->ichar);
2448 return;
2449 }
2450
2451 //paste glyph image into atlas image
2452 pos.X = me->pen.X + entry->pos.X;
2453 pos.Y = me->pen.Y + entry->pos.Y;
2454
2455 if(1) subimage_paste(me->texture,me->size,gray,me->bytesperpixel,me->pen,entry->size);
2456 if(0) subimage_paste(me->texture,me->size,gray,1,pos,entry->size);
2457
2458 if(1) {
2459 entry->apos.X = me->pen.X;
2460 entry->apos.Y = me->pen.Y;
2461 }else{
2462 entry->apos.X = pos.X;
2463 entry->apos.Y = pos.Y;
2464 }
2465 me->pen.X += entry->size.X; //entry->advance.X;
2466 //me->pen.Y += entry->advance.Y;
2467}
2468
2469
2470#ifdef OLDCODE
2471
2472Code appears to be unused - JAS April 2017
2473
2474static void AtlasEntrySet_addEntry1(AtlasEntrySet *me, AtlasEntry *entry){
2475 //use this with atlasEntry_init1 for .bmp widget texture atlas
2476 vector_pushBack(AtlasEntry*,me->entries,entry);
2477 if(entry->ichar > 0 && entry->ichar < 128){
2478 //if its an ascii char, add to fast lookup table
2479 me->ascii[entry->ichar] = entry;
2480 me->lastascii = max(me->lastascii,me->entries->n); //for lookup optimization
2481 }
2482}
2483#endif //OLDCODE
2484
2485
2486static void AtlasEntrySet_addEntry(AtlasEntrySet *me, AtlasEntry *entry, unsigned char *gray){
2487 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
2488 vector_pushBack(AtlasEntry*,me->entries,entry);
2489 if(entry->ichar > 0 && entry->ichar < 128){
2490 //if its an ascii char, add to fast lookup table
2491 me->ascii[entry->ichar] = entry;
2492 me->lastascii = max(me->lastascii,me->entries->n); //for lookup optimization
2493 }
2494 if(!me->atlas)
2495 me->atlas = (Atlas*)searchGUItable(p->atlas_table,me->atlasName);
2496 if(me->atlas)
2497 Atlas_addEntry(me->atlas, entry, gray);
2498}
2499
2500#ifdef OLDCODE
2501
2502Code appears to be unused - JAS April 2017
2503
2504static AtlasEntry *AtlasEntrySet_getEntry1(AtlasEntrySet *me, char *name){
2505 //use this to get an atlas entry by char* name, slow
2506 int i;
2507 for(i=0;i<vectorSize(me->entries);i++){
2508 AtlasEntry *entry = vector_get(AtlasEntry*,me->entries,i);
2509 if(!strcmp(entry->name,name))
2510 return entry;
2511 }
2512 return NULL;
2513}
2514#endif // OLDCODE
2515
2516
2517static AtlasEntry *AtlasEntrySet_getEntry(AtlasEntrySet *me, int ichar){
2518 //use this to get an atlas entry for a font glyph
2519 // uses fast lookup for ASCII chars first, then slow lookup since its a 16 char x 16 char atlas, max 256 chars stored
2520 // ichar is unicode
2521 AtlasEntry *ae = NULL;
2522 if(ichar > 0 && ichar < 128){ // < 0x80
2523 ae = me->ascii[ichar];
2524 }else{
2525 //could be a binary search here
2526 int i;
2527 for(i=me->lastascii;i<vectorSize(me->entries);i++){
2528 AtlasEntry *entry = vector_get(AtlasEntry*,me->entries,i);
2529 if(entry->ichar == ichar){
2530 ae = entry;
2531 break;
2532 }
2533 }
2534 if(!ae){
2535 //printf("not found in atlasEntrySet %d adding\n",ichar);
2536 //add
2537 ae = AtlasAddIChar(me->font, me, ichar);
2538 for(i=0;i<vectorSize(me->entries);i++){
2539 AtlasEntry *entry = vector_get(AtlasEntry*,me->entries,i);
2540 if(entry->ichar == ichar){
2541 ae = entry;
2542 break;
2543 }
2544 }
2545 if(!ae){
2546 printf("tried to add char %d to atlas, but didn't show up\n",ichar);
2547 }
2548
2549 }
2550 }
2551 return ae;
2552}
2553
2554
2555
2556static void AtlasFont_init(AtlasFont *me,char *facename, int EMsize, char* path){
2557
2558 me->name = facename;
2559 me->type = GUI_FONT;
2560 me->path = path;
2561 me->fontFace = NULL;
2562 me->EMsize = EMsize;
2563 me->set = NULL;
2564 //me->atlasSizes.n = 0; //no atlas renderings to begin with
2565 //me->atlasSizes.allocn = 2;
2566 //me->atlasSizes.data = malloc(2*sizeof(AtlasEntrySet*));
2567}
2568
2569//AtlasEntrySet* searchAtlasFontForSizeOrMake(AtlasFont *font,int EMpixels){
2570// AtlasEntrySet *set = NULL;
2571// if(font){
2572// if(font->atlasSizes.n){
2573// int i;
2574// for(i=0;i<font->atlasSizes.n;i++){
2575// AtlasEntrySet *aes = vector_get(AtlasEntrySet*,&font->atlasSizes,i);
2576// if(aes){
2577// if(aes->EMpixels == EMpixels){
2578// set = aes;
2579// break;
2580// }
2581// }
2582// }
2583// }
2584// if(!set){
2585// //make set
2586// }
2587// }
2588// return set;
2589//}
2590
2591
2592
2593static char *newstringfromchar(char c){
2594 char *ret = MALLOCV(2);
2595 ret[0] = c;
2596 ret[1] = '\0';
2597 return ret;
2598}
2599//static FT_Library fontlibrary; /* handle to library */
2600
2601
2602static AtlasEntry * AtlasAddIChar(AtlasFont *font, AtlasEntrySet *entryset, int ichar){
2603 FT_Face fontFace = font->fontFace;
2604
2605 FT_GlyphSlot glyph;
2606 FT_Error error;
2607 AtlasEntry *entry;
2608 unsigned long c;
2609
2610 c = FT_Get_Char_Index(fontFace, ichar);
2611 error = FT_Load_Glyph(fontFace, c, FT_LOAD_RENDER);
2612 if(error)
2613 {
2614 //Logger::LogWarning("Character %c not found.", wText.GetCharAt(i));
2615 printf("ouch87");
2616 return NULL;
2617 }
2618 glyph = fontFace->glyph;
2619
2620 entry = MALLOCV(sizeof(AtlasEntry));
2621 //atlasEntry_init1(entry,names[i*2],(int)cText[i],0,0,16,16);
2622 entry->ichar = ichar;
2623 entry->pos.X = glyph->bitmap_left;
2624 entry->pos.Y = glyph->bitmap_top;
2625 entry->advance.X = glyph->advance.x >> 6;
2626 entry->advance.Y = glyph->advance.y >> 6;
2627 entry->size.X = glyph->bitmap.width;
2628 entry->size.Y = glyph->bitmap.rows;
2629 entry->name = NULL; //utf8_to_utf32(str,str32,&len32);
2630 AtlasEntrySet_addEntry(entryset,entry,glyph->bitmap.buffer);
2631 return entry;
2632}
2633
2634
2635static int RenderFontAtlas(AtlasFont *font, AtlasEntrySet *entryset, char * cText){
2636 //pass in a string with your alphabet, numbers, symbols or whatever,
2637 // and we use freetype2 to render to bitmap, and then tile those little
2638 // bitmaps into an atlas texture
2639 //wText is UTF-8 since FreeType expect this
2640 int i;
2641 FT_Face fontFace = font->fontFace;
2642
2643 for (i = 0; i < strlen(cText); i++)
2644 {
2645 FT_GlyphSlot glyph;
2646 FT_Error error;
2647 AtlasEntry *entry;
2648 unsigned long c;
2649
2650 c = FT_Get_Char_Index(fontFace, (int) cText[i]);
2651 error = FT_Load_Glyph(fontFace, c, FT_LOAD_RENDER);
2652 if(error)
2653 {
2654 //Logger::LogWarning("Character %c not found.", wText.GetCharAt(i));
2655 printf("ouch87");
2656 continue;
2657 }
2658 glyph = fontFace->glyph;
2659 entry = MALLOCV(sizeof(AtlasEntry));
2660 //atlasEntry_init1(entry,names[i*2],(int)cText[i],0,0,16,16);
2661 entry->ichar = 0;
2662 if( cText[i] > 31 && cText[i] < 128 ) entry->ichar = cText[i]; //add to fast lookup table if ascii
2663 entry->pos.X = glyph->bitmap_left;
2664 entry->pos.Y = glyph->bitmap_top;
2665 entry->advance.X = glyph->advance.x >> 6;
2666 entry->advance.Y = glyph->advance.y >> 6;
2667 entry->size.X = glyph->bitmap.width;
2668 entry->size.Y = glyph->bitmap.rows;
2669 entry->name = newstringfromchar(cText[i]);
2670 AtlasEntrySet_addEntry(entryset,entry,glyph->bitmap.buffer);
2671 }
2672 //for(int i=0;i<256;i++){
2673 // for(int j=0;j<256;j++)
2674 // atlas->texture[i*256 + j] = (i*j) %2 ? 0 : 127; //checkerboard, to see if fonts twinkle
2675 //}
2676 return TRUE;
2677}
2678
2679static int AtlasFont_LoadFont(AtlasFont *font){
2680 FT_Face fontface;
2681 FT_Library fontlibrary;
2682 int err;
2683 struct name_num *fontname_entry;
2684 char thisfontname[2048];
2685 ttglobal tg;
2687 tg = gglobal();
2688 p = (ppComponent_Text)tg->Component_Text.prv;
2689
2690 if(!p->font_directory)
2691 p->font_directory = makeFontDirectory();
2692
2693 strcpy (thisfontname, p->font_directory);
2694 strcat(thisfontname,"/");
2695 strcat(thisfontname,font->path);
2696
2697 fontlibrary = getFontLibrary();
2698 if(!fontlibrary)
2699 return FALSE;
2700
2701 fontname_entry = get_fontname_entry_by_facename(font->name);
2702 if(fontname_entry){
2703 //a font we also use for Component_Text ie Vera series
2704 int num = fontname_entry->num;
2705 if(p->font_state[num] < FONTSTATE_TRIED){
2706 FW_make_fontname(num);
2707 fontface = FW_init_face0(fontlibrary,p->thisfontname);
2708 if (fontface) {
2709 p->font_face[num] = fontface;
2710 p->font_state[num] = FONTSTATE_LOADED;
2711 font->fontFace = fontface;
2712 }else{
2713 p->font_state[num] = FONTSTATE_TRIED;
2714 return FALSE;
2715 }
2716 }
2717 else{
2718 //already loaded, just retrieve
2719 font->fontFace = p->font_face[num];
2720 }
2721 }else{
2722 //not a Vera, could be a scrolling-text pixel or proggy font
2723 err = FT_New_Face(fontlibrary, thisfontname, 0, &fontface);
2724 if (err) {
2725 printf ("FreeType - can not use font %s\n",thisfontname);
2726 return FALSE;
2727 }
2728 font->fontFace = fontface;
2729 }
2730 if(1){
2731 int nsizes;
2732 printf("fontface flags & Scalable? = %ld \n",font->fontFace->face_flags & FT_FACE_FLAG_SCALABLE );
2733 nsizes = font->fontFace->num_fixed_sizes;
2734 printf("num_fixed_sizes = %d\n",nsizes);
2735 }
2736 return TRUE;
2737}
2738
2739
2740static int AtlasFont_setFontSize(AtlasFont *me, int EMpixels, int *rowheight, int *maxadvancepx){
2741 int err;
2742 FT_Face fontFace = me->fontFace;
2743
2744 if(!fontFace) return FALSE;
2745 //#define POINTSIZE 20
2746 //#define XRES 96
2747 //#define YRES 96
2748 //if(0){
2749 // err = FT_Set_Char_Size(fontFace, /* handle to face object */
2750 // POINTSIZE*64, /* char width in 1/64th of points */
2751 // POINTSIZE*64, /* char height in 1/64th of points */
2752 // XRES, /* horiz device resolution */
2753 // YRES); /* vert device resolution */
2754 //}
2755 err = FT_Set_Pixel_Sizes(
2756 fontFace, /* handle to face object */
2757 0, /* pixel_width */
2758 EMpixels ); /* pixel_height */
2759
2760 if(1){
2761 // int h;
2762 // int max_advance_px;
2763
2764 //printf("spacing between rows = %f\n",fontFace->height);
2765 // h = fontFace->size->metrics.height;
2766 //printf("height(px)= %d.%d x_ppem=%d\n",(int)(h >>6),(int)(h<<26)>>26,(unsigned int)fontFace->size->metrics.x_ppem);
2767 *rowheight = fontFace->size->metrics.height >> 6;
2768 //fs->EMpixels = (unsigned int)fontFace->size->metrics.x_ppem;
2769 // max_advance_px = fontFace->size->metrics.max_advance >> 6;
2770 //printf("max advance px=%d\n",max_advance_px);
2771 }
2772 *maxadvancepx = fontFace->size->metrics.max_advance >> 6;
2773 if (err) {
2774 printf ("FreeWRL - FreeType, can not set char size for font %s\n",me->path);
2775 return FALSE;
2776 }
2777 return TRUE;
2778}
2779
2780static unsigned int upperPowerOfTwo(unsigned int k){
2781 int ipow;
2782 unsigned int kk = 1;
2783 for(ipow=2;ipow<32;ipow++){
2784 kk = kk << 1;
2785 if(kk > k) return kk;
2786 }
2787 return 1 << 31;
2788}
2789
2790
2791static void AtlasFont_RenderFontAtlas(AtlasFont *me, int EMpixels, char* alphabet){
2792 //this method assumes one fontsize per atlas,
2793 // and automatically adjusts atlas size to minimize wastage
2794 int rowheight, maxadvancepx, pixelsNeeded;
2795 unsigned int dimension;
2796 AtlasEntrySet *aes;
2797 char *name;
2798 Atlas *atlas = NULL;
2799
2800 // initialize - JAS
2801 rowheight = 0;
2802 maxadvancepx = 0;
2803 pixelsNeeded = 0;
2804
2805 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
2806
2807 //printf("start of RenderFontAtlas\n");
2808
2809 if(!me->fontFace) return; //font .ttf file not loaded (likely not found, or programmer didn't load flont first)
2810
2811 atlas = GUImalloc(&p->atlas_table,GUI_ATLAS); //malloc(sizeof(GUIAtlas));
2812 aes = MALLOCV(sizeof(AtlasEntrySet));
2813 //GUIFontSize *fsize = malloc(sizeof(GUIFontSize));
2814 name = MALLOCV(strlen(me->name)+12); //base10 -2B has 11 chars, plus \0
2815 strcpy(name,me->name);
2816 sprintf(&name[strlen(me->name)],"%d",EMpixels); //or itoa()
2817 //itoa(EMpixels,&name[strlen(name)],10);
2818 AtlasEntrySet_init(me,aes,name);
2819 //somehow, I need the EMsize and rowheight, or a more general function to compute area needed by string
2820 AtlasFont_setFontSize(me,EMpixels, &rowheight, &maxadvancepx);
2821 pixelsNeeded = rowheight * EMpixels / 2 * strlen(alphabet);
2822 dimension = (unsigned int)sqrt((double)pixelsNeeded);
2823 dimension = upperPowerOfTwo(dimension);
2824 //printf("creating atlas %s with dimension %d advance %d rowheight %d\n",name,dimension,EMpixels/2,rowheight);
2825 Atlas_init(atlas,dimension,rowheight);
2826 aes->atlas = atlas;
2827 aes->EMpixels = EMpixels;
2828 aes->maxadvancepx = maxadvancepx;
2829 aes->rowheight = rowheight;
2830 atlas->name = name;
2831 aes->atlasName = name;
2832 //init ConsoleMessage font atlas
2833 RenderFontAtlas(me,aes,alphabet);
2834 //vector_pushBack(AtlasEntrySet*,&me->atlasSizes,aes);
2835 me->set = aes;
2837 //printf("end of RenderFontAtlas\n");
2838}
2839
2840
2841
2842
2843static int bin2hex(char *inpath, char *outpath){
2844 // converts any binary file -.ttf, .png etc- into a .c file, so you can compile it in
2845 // then in your code refer to it:
2846 // extern unsigned char my_data[];
2847 // extern int my_size;
2848 int ncol = 15;
2849 FILE *fin, *fout;
2850 fin = fopen(inpath,"r+b");
2851 fout = fopen(outpath,"w+");
2852
2853 if(fin && fout){
2854 char *bufname, *bufdup, *ir, *sep;
2855 int more, m, j, nc;
2856 unsigned int hh;
2857 unsigned char *buf;
2858 buf = MALLOCV(ncol + 1);
2859 //convert ..\ProggyClean.ttf to ProggyClean_ttf
2860 bufname = bufdup = STRDUP(inpath);
2861 ir = strrchr(bufname,'\\');
2862 if(ir) bufname = &ir[1];
2863 ir = strrchr(bufname,'/');
2864 if(ir) bufname = &ir[1];
2865 ir = strrchr(bufname,'.');
2866 if(ir) ir[0] = '_';
2867 //print data
2868 fprintf(fout,"unsigned char %s_data[] = \n",bufname);
2869 sep = "{";
2870 more = 1;
2871 m = 0;
2872 do{
2873 nc = ncol;
2874 nc = fread(buf,1,nc,fin);
2875 if(nc < ncol) more = 0;
2876 for(j=0;j<nc;j++){
2877 fprintf(fout,"%s",sep);
2878 hh = buf[j];
2879 fprintf(fout,"0x%.2x",hh);
2880 sep = ",";
2881 }
2882 if(more) fprintf(fout,"\n");
2883 m += nc;
2884 }while(more);
2885 fprintf(fout,"};\n");
2886 //print size
2887 fprintf(fout,"int %s_size = %d;\n",bufname,m);
2888 fclose(fout);
2889 fclose(fin);
2890 free(buf);
2891 free(bufdup);
2892 }
2893 return 1;
2894}
2895
2896
2897static int AtlasFont_LoadFromDotC(AtlasFont *font, unsigned char *start, int size){
2898 FT_Face fontFace;
2899 FT_Library fontlibrary;
2900 FT_Open_Args args;
2901 int err;
2902 char *fontname;
2903 fontname = font->path;
2904
2905 if(!size || !start){
2906 printf("not compiled in C %s\n", font->name);
2907 return FALSE;
2908 }
2909
2910 fontlibrary = getFontLibrary();
2911 if(!fontlibrary)
2912 return FALSE;
2913
2914 args.flags = FT_OPEN_MEMORY;
2915 args.memory_base = start;
2916 args.memory_size = size;
2917 err = FT_Open_Face(fontlibrary, &args, 0, &fontFace);
2918 // err = FT_New_Face(fontlibrary, fontname, 0, &fontFace);
2919 if (err) {
2920 printf ("FreeType - can not use font %s\n",fontname);
2921 return FALSE;
2922 }
2923 font->fontFace = fontFace;
2924
2925 if(0){
2926 int nsizes;
2927 printf("fontface flags & Scalable? = %ld \n",fontFace->face_flags & FT_FACE_FLAG_SCALABLE );
2928 nsizes = fontFace->num_fixed_sizes;
2929 printf("num_fixed_sizes = %d\n",nsizes);
2930 }
2931 return TRUE;
2932}
2933
2934
2935
2936static AtlasFont *searchAtlasFontTable(struct Vector* guitable, char *name, int EMsize){
2937 int i;
2938 AtlasFont *retval = NULL;
2939 if(guitable)
2940 for(i=0;i<vectorSize(guitable);i++){
2941 AtlasFont *el = vector_get(AtlasFont *,guitable,i);
2943 if(!strcmp(name,el->name) && EMsize == el->EMsize){
2944 retval = el;
2945 break;
2946 }
2947 }
2948 return retval;
2949}
2950
2951#define DOTC_NONE 0
2952#define DOTC_SAVE 1
2953#define DOTC_LOAD 2
2954//#define HAVE_COMPILED_IN_FONT 1 //AT TOP OF THIS MODULE
2955#ifdef HAVE_COMPILED_IN_FONT
2956extern unsigned char VeraMono_ttf_data[];
2957extern int VeraMono_ttf_size;
2958extern unsigned char freewrl_wingding_ttf_data[];
2959extern int freewrl_wingding_ttf_size;
2960#else
2961unsigned char *VeraMono_ttf_data = NULL;
2962int VeraMono_ttf_size = 0;
2963
2964#endif
2965
2966static int FW_Open_Face(FT_Library library, char *thisfontname, int faceIndex, FT_Face *face)
2967{
2968 //FONT THUNKING
2969 //this function can be used by Text and FontStyle to load Typewriter automatically from .c if compiled in,
2970 // and/or substitute (THUNK) typewriter if the desired font file can't be found
2971 int err = 0;
2972
2973 if(VeraMono_ttf_size && strstr(thisfontname,"VeraMono.ttf")){
2974 //always try to get VeraMono from .c
2975 FT_Open_Args args;
2976 args.flags = FT_OPEN_MEMORY;
2977 args.memory_base = VeraMono_ttf_data;
2978 args.memory_size = VeraMono_ttf_size;
2979 err = FT_Open_Face(library, &args, 0, face);
2980 }else{
2981 err = FT_New_Face(library, thisfontname, faceIndex, face);
2982 if(err && VeraMono_ttf_size)
2983 {
2984 //for any other font face, only substitute/thunk (to veramono) if it can't be found
2985 FT_Open_Args args;
2986 args.flags = FT_OPEN_MEMORY;
2987 args.memory_base = VeraMono_ttf_data;
2988 args.memory_size = VeraMono_ttf_size;
2989 err = FT_Open_Face(library, &args, faceIndex, face);
2990 }
2991 }
2992 return err;
2993}
2994
2995
2996// called in MainLoop, and locally here
2997AtlasFont *searchAtlasTableOrLoad(char *facename, int EMpixels){
2998 AtlasFont *font;
2999 ppComponent_Text p = (ppComponent_Text)gglobal()->Component_Text.prv;
3000 font = (AtlasFont*)searchAtlasFontTable(p->font_table,facename,EMpixels);
3001 if(!font){
3002 static char * ascii32_126 = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQURSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
3003 int font_tactic, len; //atlas_tactic,
3004 char* facenamettf;
3005
3006 font = GUImalloc(&p->font_table,GUI_FONT); //sizeof(GUIFont));
3007 //AtlasFont_init(font,"ProggyClean","ProggyClean.ttf");
3008 len = strlen(facename) + 7;
3009 facenamettf = MALLOCV(len);
3010 strcpy(facenamettf,facename);
3011 facenamettf = strcat(facenamettf,".ttf");
3012 AtlasFont_init(font,facename,EMpixels,facenamettf);
3013
3014 font_tactic = DOTC_NONE; //DOTC_NONE, DOTC_SAVE, DOTC_LOAD
3015 if(!strcmp(facename,"VeraMono")){
3016 //we want one font we can rely on even if vera fonts aren't installed or hard to find
3017 //so we compile one it, and if no other font we can thunk to it
3018 if(0) font_tactic = DOTC_SAVE; //you would do this once in your lifetime to generate a .c, then compile that into your program, then define HAVE_COMPILED_IN_FONT above
3019 else font_tactic = DOTC_LOAD; //then for the rest of your life, you would use this to load it from .c
3020 if(font_tactic == DOTC_LOAD)
3021 AtlasFont_LoadFromDotC(font, VeraMono_ttf_data, VeraMono_ttf_size);
3022 }
3023 if(!strcmp(facename,"freewrl_wingding")){
3024 //we want one font we can rely on even if vera fonts aren't installed or hard to find
3025 //so we compile one it, and if no other font we can thunk to it
3026 if(0) font_tactic = DOTC_SAVE; //you would do this once in your lifetime to generate a .c, then compile that into your program, then define HAVE_COMPILED_IN_FONT above
3027 else font_tactic = DOTC_LOAD; //then for the rest of your life, you would use this to load it from .c
3028 if(font_tactic == DOTC_LOAD)
3029 AtlasFont_LoadFromDotC(font, freewrl_wingding_ttf_data, freewrl_wingding_ttf_size);
3030 }
3031 if(font_tactic == DOTC_SAVE) {
3032 //you need to put the .ttf file in the 'local' directory where you freewrl thinks its running,
3033 // otherwise you'll get nothing.
3034 char *facenamettfc;
3035 facenamettfc = alloca(strlen(facenamettf)+3);
3036 strcpy(facenamettfc,facenamettf);
3037 facenamettfc[len-7] = '_';
3038 strcat(facenamettfc,".c");
3039 bin2hex(font->path, facenamettfc); // "ProggyClean_ttf.c");
3040 }
3041 if(font_tactic != DOTC_LOAD)
3042 AtlasFont_LoadFont(font); //normal loading of installed font
3043
3044 AtlasFont_RenderFontAtlas(font,EMpixels,ascii32_126);
3045 //font = (AtlasFont*)searchGUItable(p->font_table,facename); //too simple, need (facename,size) tuple to get correct font
3046
3047 }
3048 if(!font){
3049 printf("dug9gui: Can't find font %s did you misname the fontface sb Vera or VeraMono etc?\n",facename);
3050 }
3051 return font;
3052}
3053
3054
3055
3056// called in MainLoop
3057vec4 vec4_init(float x, float y, float z, float w){
3058 vec4 ret;
3059 ret.X = x, ret.Y = y; ret.Z = z; ret.W = w;
3060 return ret;
3061}
3062
3063#ifdef OLDCODE
3064static vec2 vec2_init(float x, float y){
3065 vec2 ret;
3066 ret.X = x, ret.Y = y;
3067 return ret;
3068}
3069
3070#endif //OLDCODE
3071
3072typedef struct ivec4 {int X; int Y; int W; int H;} ivec4;
3073ivec4 ivec4_init(int x, int y, int w, int h);
3074
3075
3076//static Stack *_vpstack = NULL; //ivec4 in y-down pixel coords - viewport stack used for clipping drawing
3078 int X,Y; //placeholder for screen WxH
3079} screen;
3080 //singleton, screen allows mouse passthrough (vs panel, captures mouse)
3081
3082
3083static vec2 pixel2normalizedViewportScale( GLfloat x, GLfloat y)
3084{
3085 vec2 xy;
3086 //GLfloat yup;
3087
3088 ivec4 currentvp = stack_top(ivec4,gglobal()->Mainloop._vportstack);
3089
3090 //convert to -1 to 1 range
3091 xy.X = ((GLfloat)(x)/(GLfloat)currentvp.W) * 2.0f;
3092 xy.Y = ((GLfloat)(y)/(GLfloat)currentvp.H) * 2.0f;
3093 return xy;
3094}
3095
3096static vec2 pixel2normalizedViewport( GLfloat x, GLfloat y){
3097 ivec4 currentvp = stack_top(ivec4,gglobal()->Mainloop._vportstack);
3098
3099 vec2 xy;
3100 xy.X = ((GLfloat)(x - currentvp.X)/(GLfloat)currentvp.W) * 2.0f;
3101 xy.Y = ((GLfloat)(y - currentvp.Y)/(GLfloat)currentvp.H) * 2.0f;
3102 xy.X -= 1.0f;
3103 xy.Y -= 1.0f;
3104 xy.Y *= -1.0f;
3105 return xy;
3106}
3107
3108#ifdef FOR_DEBUGGING
3109
3110Calls commented out, removing from active compile - JAS April 2017
3111static void printvpstacktop(Stack *vpstack, int line){
3112 ivec4 currentvp = stack_top(ivec4,vpstack);
3113 int n = ((struct Vector*)vpstack)->n;
3114 int xx = ((ivec4*)((struct Vector*)vpstack)->data)[3].X;
3115 printf("vp top[%d] = [%d %d %d %d] line %d xx=%d\n",n,currentvp.X,currentvp.Y,currentvp.W,currentvp.H,line,xx);
3116}
3117#endif //FOR_DEBUGGING
3118
3119#ifdef OLDCODE
3120
3121Code appears not to be called - JAS April 2017
3122
3123static vec2 pixel2normalizedScreenScale( GLfloat x, GLfloat y)
3124{
3125 vec2 xy;
3126 //GLfloat yup;
3127 //convert to -1 to 1 range
3128 xy.X = ((GLfloat)x/(GLfloat)screen.X) * 2.0f;
3129 xy.Y = ((GLfloat)y/(GLfloat)screen.Y) * 2.0f;
3130 return xy;
3131}
3132#endif //OLDCODE
3133
3134
3135#ifdef OLDCODE
3136
3137Code appears not to be called - JAS April 2017
3138
3139static vec2 pixel2normalizedScreen( GLfloat x, GLfloat y){
3140 vec2 xy = pixel2normalizedScreenScale(x,y);
3141 xy.X -= 1.0f;
3142 xy.Y -= 1.0f;
3143 xy.Y *= -1.0f;
3144 return xy;
3145}
3146#endif
3147
3148
3149
3150static GLbyte vShaderStr[] =
3151 "attribute vec4 a_position; \n"
3152 "attribute vec2 a_texCoord; \n"
3153 "uniform mat4 u_ModelViewMatrix; \n"
3154 "uniform mat4 u_ProjectionMatrix; \n"
3155 "varying vec2 v_texCoord; \n"
3156 "void main() \n"
3157 "{ \n"
3158 " gl_Position = u_ProjectionMatrix * u_ModelViewMatrix * a_position; \n"
3159 " v_texCoord = a_texCoord; \n"
3160 "} \n";
3161
3162
3163// using Luminance images, you need to set a color in order for it to show up different than white
3164// and if the luminance is an opacity gray-scale for anti-aliased bitmap patterns ie font glyphs
3165// then transparency = 1 - opacity
3166
3167//this shader works in win32 desktop angleproject (gets translated to HLSL), although it's a mystery why/how it works Dec 24, 2014.
3168//In theory:
3169// the blend should be 1111 if you want all texture
3170// and blend should be 0000 if you want all vector color (ie drawing a colored rectangle or border)
3171// and blend should be 0001 if you have an alpha image (ie font glyph image)- so you ignor .rgb of texture
3172//In practice: there's a (1-blend.a) and (1-texColor.a) I don't understand
3173//to use an rgba image's own color, set your blend to 1111 and vector color to 1110
3174//to colorize a gray rgba image using the rgb as a luminance factor, and vector color as the hue,
3175// set blend to 1111 and vector color to your chosen color
3176static GLbyte fShaderStr[] =
3177#ifdef GL_ES_VERSION_2_0
3178 "precision mediump float; \n"
3179#endif //GL_ES_VERSION_2_0
3180 "varying vec2 v_texCoord; \n"
3181 "uniform sampler2D Texture0; \n"
3182 "uniform vec4 Color4f; \n"
3183 "uniform vec4 blend; \n"
3184 "void main() \n"
3185 "{ \n"
3186 " vec4 texColor = texture2D( Texture0, v_texCoord ); \n"
3187 " vec4 one = vec4(1.0,1.0,1.0,1.0); \n"
3188 " vec4 omb = vec4(one.rgb - blend.rgb,1.0 - blend.a); \n"
3189 " vec4 tcolor = omb + (blend*texColor);\n"
3190 " float aa = omb.a*Color4f.a + blend.a*(1.0 -texColor.a);\n"
3191 " tcolor = Color4f * tcolor;\n"
3192 " vec4 finalColor = vec4(tcolor.rgb, 1.0 - aa ); \n"
3193 " gl_FragColor = finalColor; \n"
3194 "} \n";
3195// " gl_FragColor = vec4(1.0,1.0,1.0,1.0); \n"
3196 //" texColor.a = one.a*blend.a + (one.a - blend.a)*texColor.a;\n"
3197 // " vec4 finalColor = vec4(Color4f.rgb * texColor.rgb, 1.0 - (1.0 - Color4f.a)*(1.0 - texColor.a)); \n" //vector rgb color, and vector.a * (1-L) for alpha
3198 // " texColor.rgb = blend.rgb + (one.rgb - blend.rgb)*texColor.rgb;\n"
3199 //" texColor.a = blend.a*Color4f.a + (one.a - blend.a)*texColor.a;\n"
3200 // " vec4 finalColor = vec4(Color4f.rgb * texColor.rgb, texColor.a); \n" //vector rgb color, and vector.a * (1-L) for alpha
3201//STATICS
3202static GLfloat modelviewIdentityf[] = {
3203 1.0f, 0.0f, 0.0f, 0.0f,
3204 0.0f, 1.0f, 0.0f, 0.0f,
3205 0.0f, 0.0f, 1.0f, 0.0f,
3206 0.0f, 0.0f, 0.0f, 1.0f
3207};
3208static GLfloat projectionIdentityf[] = {
3209 1.0f, 0.0f, 0.0f, 0.0f,
3210 0.0f, 1.0f, 0.0f, 0.0f,
3211 0.0f, 0.0f, 1.0f, 0.0f,
3212 0.0f, 0.0f, 0.0f, 1.0f
3213};
3214
3215static void initProgramObject(){
3217 ttglobal tg = gglobal();
3218 p = (ppComponent_Text)tg->Component_Text.prv;
3219
3220 // Load the shaders and get a linked program object
3221 p->programObject = esLoadProgram ( (const char*) vShaderStr, (const char *)fShaderStr );
3222 // Get the attribute locations
3223 p->positionLoc = glGetAttribLocation ( p->programObject, "a_position" );
3224 p->texCoordLoc = glGetAttribLocation ( p->programObject, "a_texCoord" );
3225 // Get the sampler location
3226 p->textureLoc = glGetUniformLocation ( p->programObject, "Texture0" );
3227 p->color4fLoc = glGetUniformLocation ( p->programObject, "Color4f" );
3228 p->blendLoc = glGetUniformLocation ( p->programObject, "blend" );
3229 p->modelviewLoc = glGetUniformLocation ( p->programObject, "u_ModelViewMatrix" );
3230 p->projectionLoc = glGetUniformLocation ( p->programObject, "u_ProjectionMatrix" );
3231
3232}
3233
3234#ifdef OLDCODE
3235
3236JAS - possibly unused - Apr 2017
3237
3238static void dug9gui_DrawImage(int xpos,int ypos, int width, int height, char *buffer){
3239//xpos, ypos upper left location of image in pixels, on the screen
3240// hardwired to draw glyph (1-alpha) images
3241// 1 - 2 4
3242// | / / | 2 triangles, 6 points, in y-up coords
3243// 0 3 - 5
3244
3245GLfloat cursorVert[] = {
3246 0.0f, 0.0f, 0.0f,
3247 0.0f, 1.0f, 0.0f,
3248 1.0f, 1.0f, 0.0f,
3249 0.0f, 0.0f, 0.0f,
3250 1.0f, 1.0f, 0.0f,
3251 1.0f, 0.0f, 0.0f,
3252 };
3253
3254GLfloat cursorTex[] = {
3255 0.0f, 0.0f,
3256 0.0f, 1.0f,
3257 1.0f, 1.0f,
3258 0.0f, 0.0f,
3259 1.0f, 1.0f,
3260 1.0f, 0.0f,
3261 };
3262 GLushort ind[] = {0,1,2,3,4,5};
3263 //GLint pos, tex;
3264 vec2 fxy, fwh;
3265 //ivec2 xy;
3266 int i; //,j;
3267 GLfloat cursorVert2[18];
3268 //unsigned char buffer2[1024];
3270 ttglobal tg = gglobal();
3271 p = (ppComponent_Text)tg->Component_Text.prv;
3272
3273
3274 if(0) glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE , GL_UNSIGNED_BYTE, buffer);
3275 //for(int i=0;i<width*height;i++)
3276 // buffer2[i] = 255 - (unsigned char)(buffer[i]); //change from (1-alpha) to alpha image
3277 if(1) glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA , GL_UNSIGNED_BYTE, buffer);
3278 glUniform4f(p->blendLoc,0.0f,0.0f,0.0f,1.0f); //-1 is because glyph grayscale are really (1.0 - alpha)
3279
3280 if(0){
3281 //upper left
3282 fxy = pixel2normalizedScreen((GLfloat)xpos,(GLfloat)ypos);
3283 fwh = pixel2normalizedScreenScale((GLfloat)width,(GLfloat)height);
3284 //lower left
3285 fxy.Y = fxy.Y - fwh.Y;
3286 }
3287 if(1){
3288 //upper left
3289 //printvpstacktop(__LINE__);
3290 fxy = pixel2normalizedViewport((GLfloat)xpos,(GLfloat)ypos);
3291 //printvpstacktop(__LINE__);
3292 fwh = pixel2normalizedViewportScale((GLfloat)width,(GLfloat)height);
3293 //printvpstacktop(__LINE__);
3294 //lower left
3295 fxy.Y = fxy.Y - fwh.Y;
3296 }
3297
3298 //fxy.Y -= 1.0; //DUG9GUI y=0 at top
3299 //fxy.X -= 1.0;
3300 memcpy(cursorVert2,cursorVert,2*3*3*sizeof(GLfloat));
3301 //printvpstacktop(__LINE__);
3302
3303 for(i=0;i<6;i++){
3304 cursorVert2[i*3 +0] *= fwh.X;
3305 cursorVert2[i*3 +0] += fxy.X;
3306 if(!iyup) cursorVert2[i*3 +1] = 1.0f - cursorVert2[i*3 +1];
3307 cursorVert2[i*3 +1] *= fwh.Y;
3308 cursorVert2[i*3 +1] += fxy.Y;
3309 }
3310 //printvpstacktop(__LINE__);
3311
3312 // Set the base map sampler to texture unit to 0
3313 // Bind the base map - see above
3314 glActiveTexture ( GL_TEXTURE0 );
3315 glBindTexture ( GL_TEXTURE_2D, p->textureID );
3316 glUniform1i ( p->textureLoc, 0 );
3317
3318 glVertexAttribPointer (p->positionLoc, 3, GL_FLOAT,
3319 GL_FALSE, 0, cursorVert2 );
3320 // Load the texture coordinate
3321 glVertexAttribPointer (p->texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, cursorTex );
3322 glEnableVertexAttribArray (p->positionLoc );
3323 glEnableVertexAttribArray (p->texCoordLoc);
3324
3325
3326 //Q do I need to bind a buffer for indexes, just for glew config?
3327 //printvpstacktop(__LINE__);
3328 //char *saveme[4*4*4];
3329 //memcpy(saveme,_vpstack->data,4*4*4); //glew config overwrites vpstack->data top.X
3330 glDrawElements ( GL_TRIANGLES, 3*2, GL_UNSIGNED_SHORT, ind );
3331 //memcpy(_vpstack->data,saveme,4*4*4);
3332 //printvpstacktop(__LINE__);
3333
3334}
3335#endif //OLDCODE
3336
3337
3338
3339
3340static void dug9gui_DrawSubImage(float xpos,float ypos, float xsize, float ysize,
3341 int ix, int iy, int iw, int ih, int width, int height, int bpp, unsigned char *buffer){
3342
3343//xpos, ypos upper left location of where to draw the sub-image, in pixels, on the screen
3344//xsize,ysize - size to stretch the sub-image to on the screen, in pixels
3345// ix,iy,iw,ih - position and size in pixels of the subimage in a bigger/atlas image, ix,iy is upper left
3346// width, height - size of bigger/atlas image
3347// bpp - bytes per pixel: usually 1 for apha images like freetype antialiased glyph imagery, usually 4 for RGBA from .bmp
3348// buffer - the bigger/atlas imagery pixels
3349// 1 - 2 4
3350// | / / | 2 triangles, 6 points
3351// 0 3 - 5
3352// I might want to split this function, so loading the texture to gpu is outside, done once for a series of sub-images
3353/*
3354GLfloat cursorVert[] = {
3355 0.0f, 1.0f, 0.0f,
3356 0.0f, 0.0f, 0.0f,
3357 1.0f, 0.0f, 0.0f,
3358 0.0f, 1.0f, 0.0f,
3359 1.0f, 0.0f, 0.0f,
3360 1.0f, 1.0f, 0.0f};
3361*/
3362GLfloat cursorVert[] = {
3363 0.0f, 0.0f, 0.0f,
3364 0.0f, 1.0f, 0.0f,
3365 1.0f, 1.0f, 0.0f,
3366 0.0f, 0.0f, 0.0f,
3367 1.0f, 1.0f, 0.0f,
3368 1.0f, 0.0f, 0.0f};
3369//remember texture coordinates are 0,0 in lower left of texture image
3370GLfloat cursorTex[] = {
3371 0.0f, 0.0f,
3372 0.0f, 1.0f,
3373 1.0f, 1.0f,
3374 0.0f, 0.0f,
3375 1.0f, 1.0f,
3376 1.0f, 0.0f};
3377 GLushort ind[] = {0,1,2,3,4,5};
3378 //GLint pos, tex;
3379 vec2 fixy, fiwh; //fxy, fwh,
3380 //ivec2 xy;
3381 int i;
3382 GLfloat cursorVert2[18];
3383 GLfloat cursorTex2[12];
3385 ttglobal tg = gglobal();
3386 p = (ppComponent_Text)tg->Component_Text.prv;
3387
3388
3389 // Bind the base map - see above
3390 glActiveTexture ( GL_TEXTURE0 );
3391 glBindTexture ( GL_TEXTURE_2D, p->textureID );
3392 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //GL_LINEAR);
3393 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); //GL_LINEAR);
3394
3395 // Set the base map sampler to texture unit to 0
3396 glUniform1i ( p->textureLoc, 0 );
3397
3398 switch(bpp){
3399 case 1:
3400 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA , GL_UNSIGNED_BYTE, buffer);
3401 //glUniform4f(color4fLoc,1.0f,1.0f,1.0f,0.0f);
3402 glUniform4f(p->blendLoc,0.0f,0.0f,0.0f,1.0f); // take color from vector, take alpha from texture2D
3403 break;
3404 case 2:
3405 //doesn't seem to come in here if my .png is gray+alpha on win32
3406 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buffer);
3407 break;
3408 case 4:
3409 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA , GL_UNSIGNED_BYTE, buffer);
3410 glUniform4f(p->blendLoc,1.0f,1.0f,1.0f,1.0f); //trust the texture2D color and alpha
3411 break;
3412 default:
3413 return;
3414 }
3415
3416 //fxy.Y -= 1.0; //DUG9GUI y=0 at top
3417 //fxy.X -= 1.0;
3418 memcpy(cursorVert2,cursorVert,2*3*3*sizeof(GLfloat));
3419 for(i=0;i<6;i++){
3420 cursorVert2[i*3 +0] *= xsize; //fwh.X;
3421 cursorVert2[i*3 +0] += xpos; //fxy.X;
3422 if(!iyup) cursorVert2[i*3 +1] = 1.0f - cursorVert2[i*3 +1];
3423 cursorVert2[i*3 +1] *= ysize; //fwh.Y;
3424 cursorVert2[i*3 +1] += ypos; //fxy.Y;
3425 }
3426
3427 glVertexAttribPointer (p->positionLoc, 3, GL_FLOAT,
3428 GL_FALSE, 0, cursorVert2 );
3429 // Load the texture coordinate
3430 fixy.X = (float)ix/(float)width;
3431 fiwh.X = (float)iw/(float)width;
3432 if(!iyup){
3433 fixy.Y = (float)iy/(float)height;
3434 fiwh.Y = (float)ih/(float)height;
3435 }else{
3436 fixy.Y = (float)(height -iy)/(float)height;
3437 fiwh.Y =-(float)ih/(float)height;
3438 }
3439 memcpy(cursorTex2,cursorTex,2*3*2*sizeof(GLfloat));
3440 for(i=0;i<6;i++){
3441 cursorTex2[i*2 +0] *= fiwh.X;
3442 cursorTex2[i*2 +0] += fixy.X;
3443 cursorTex2[i*2 +1] *= fiwh.Y;
3444 cursorTex2[i*2 +1] += fixy.Y;
3445 }
3446 glVertexAttribPointer (p->texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, cursorTex2 );
3447 glEnableVertexAttribArray (p->positionLoc );
3448 glEnableVertexAttribArray (p->texCoordLoc);
3449
3451 //glActiveTexture ( GL_TEXTURE0 );
3452 //glBindTexture ( GL_TEXTURE_2D, textureID );
3453
3455 //glUniform1i ( textureLoc, 0 );
3456 glDrawElements ( GL_TRIANGLES, 3*2, GL_UNSIGNED_SHORT, ind );
3457}
3458
3459
3460// called in MainLoop
3461int render_captiontext(AtlasFont *font, int *utf32, int len32, vec4 color){
3462 //pass in a string with your alphabet, numbers, symbols or whatever,
3463 // and we use freetype2 to render to bitmpa, and then tile those little
3464 // bitmaps into an atlas texture
3465 //wText is UTF-8 since FreeType expect this
3466 //FT_Face fontFace;
3467 int i, pen_x, pen_y;
3468 Stack *vportstack;
3469 ivec4 ivport;
3470 AtlasEntrySet* set;
3472 ttglobal tg = gglobal();
3473 p = (ppComponent_Text)tg->Component_Text.prv;
3474
3475
3476 if(len32 == 0) return FALSE;
3477 // you need to pre-load the font during layout init
3478 if(!font) return FALSE;
3479 set = font->set;
3480 //uses simplified (2D) shader like statusbarHud
3481 finishedWithGlobalShader();
3482 glDepthMask(GL_FALSE);
3483 glDisable(GL_DEPTH_TEST);
3484 if(!p->programObject) initProgramObject();
3485
3486 glUseProgram ( p->programObject );
3487 if(!p->textureID)
3488 glGenTextures(1, &p->textureID);
3489
3490 glBindTexture(GL_TEXTURE_2D, p->textureID);
3491 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); //GL_LINEAR);
3492 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); //GL_LINEAR);
3493
3494 glUniformMatrix4fv(p->modelviewLoc, 1, GL_FALSE,modelviewIdentityf);
3495 glUniformMatrix4fv(p->projectionLoc, 1, GL_FALSE, projectionIdentityf);
3496
3497 glUniform4f(p->color4fLoc,color.X,color.Y,color.Z,color.W); //0.7f,0.7f,0.9f,1.0f);
3498
3499 vportstack = (Stack*)tg->Mainloop._vportstack;
3500 ivport = stack_top(ivec4,vportstack);
3501 pen_x = ivport.X;
3502 pen_y = ivport.Y + ivport.H - set->EMpixels; //MAGIC FORMULA - I'm not sure what this should be, but got something drawing
3503
3504 for (i = 0; i < len32; i++)
3505 {
3506 AtlasEntry *entry = NULL;
3507 unsigned int ichar;
3508 ichar = utf32[i];
3509 if(set){
3510 //check atlas
3511 entry = AtlasEntrySet_getEntry(set,ichar);
3512 if(entry){
3513 // drawsubimage(destination on screen, source glpyh details, source atlas)
3514 float xpos, ypos, xsize, ysize;
3515 vec2 fxy, fwh;
3516 xpos = pen_x + entry->pos.X;
3517 ypos = pen_y - entry->pos.Y;
3518 xsize = entry->size.X;
3519 ysize = entry->size.Y;
3520 //upper left
3521 fxy = pixel2normalizedViewport((GLfloat)xpos,(GLfloat)ypos);
3522 fwh = pixel2normalizedViewportScale((GLfloat)xsize,(GLfloat)ysize);
3523 //lower left
3524 fxy.Y = fxy.Y - fwh.Y;
3525 xpos = fxy.X;
3526 ypos = fxy.Y;
3527 xsize = fwh.X;
3528 ysize = fwh.Y;
3529 dug9gui_DrawSubImage(xpos,ypos,xsize,ysize,
3530 entry->apos.X, entry->apos.Y, entry->size.X, entry->size.Y,
3531 set->atlas->size.X,set->atlas->size.Y,set->atlas->bytesperpixel,set->atlas->texture);
3532 pen_x += entry->advance.X;
3533 }
3534 }
3535 }
3536
3537 glEnable(GL_DEPTH_TEST);
3538 glDepthMask(GL_TRUE);
3539 restoreGlobalShader();
3540
3541 return TRUE;
3542}
3543
3544// called in MainLoop
3545void atlasfont_get_rowheight_charwidth_px(AtlasFont *font, int *rowheight, int *maxadvancepx){
3546 *rowheight = font->set->rowheight;
3547 *maxadvancepx = font->set->maxadvancepx;
3548}
3549
3550
3551// this is called in MainLoop
3552int before_textpanel_render_rows(AtlasFont *font, vec4 color){
3553 AtlasEntrySet *entryset;
3554 Atlas *atlas;
3556 ttglobal tg = gglobal();
3557 p = (ppComponent_Text)tg->Component_Text.prv;
3558
3559 if(font == NULL) return FALSE;
3560 entryset = font->set; //GUIFont_getMatchingAtlasEntrySet(self->font,self->fontSize);
3561 if(entryset == NULL) return FALSE;
3562 if(entryset->atlas == NULL) return FALSE;
3563
3564 atlas = entryset->atlas;
3565 //set atlas and shader
3566 finishedWithGlobalShader();
3567 glDepthMask(GL_FALSE);
3568 glDisable(GL_DEPTH_TEST);
3569 if(!p->programObject) initProgramObject();
3570
3571 glUseProgram ( p->programObject );
3572 if(!p->textureID)
3573 glGenTextures(1, &p->textureID);
3574
3575 // Set the base map sampler to texture unit to 0
3576 glActiveTexture ( GL_TEXTURE0 );
3577 glBindTexture ( GL_TEXTURE_2D, p->textureID );
3578 glUniform1i ( p->textureLoc, 0 );
3579
3580 if (atlas->bytesperpixel == 1){
3581 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); //GL_LINEAR);
3582 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3583 }else{
3584 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //GL_LINEAR);
3585 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
3586 }
3587
3588
3589 if(atlas->bytesperpixel == 1){
3590 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, atlas->size.X, atlas->size.Y, 0, GL_ALPHA , GL_UNSIGNED_BYTE, atlas->texture);
3591 }else if(atlas->bytesperpixel == 2){
3592 //angleproject can't seem to mipmap GL_ALPHA, needs GL_LUMINANCE_ALPHA
3593 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, atlas->size.X, atlas->size.Y, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, atlas->texture);
3594 }else if(atlas->bytesperpixel == 4){
3595 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, atlas->size.X, atlas->size.Y, 0, GL_RGBA , GL_UNSIGNED_BYTE, atlas->texture);
3596 }
3597
3598 glUniform4f(p->color4fLoc,color.X,color.Y,color.Z,color.W); //0.7f,0.7f,0.9f,1.0f);
3599 glUniform4f(p->blendLoc,0.0f,0.0f,0.0f,1.0f);
3600
3601 glUniformMatrix4fv(p->modelviewLoc, 1, GL_FALSE,modelviewIdentityf);
3602 glUniformMatrix4fv(p->projectionLoc, 1, GL_FALSE, projectionIdentityf);
3603
3604 return TRUE;
3605}
3606
3607// This is called in MainLoop
3608int textpanel_render_row(AtlasFont *font, char * cText, int len, int *pen_x, int *pen_y){
3609 //we use a font atlas
3610 //current Feb 2016: recomputes verts, indices on each loop
3611 //potential optimizatio: in theory its the y that changes for a row,
3612 // and tex for each char, with mono-spaced fonts, if we could guarantee that
3613 AtlasEntrySet *entryset;
3614
3615
3616 if(cText == NULL) return FALSE;
3617 if(len == 0) return FALSE;
3618 if(font == NULL) return FALSE;
3619 entryset = font->set; //GUIFont_getMatchingAtlasEntrySet(self->font,self->fontSize);
3620 if(entryset == NULL) return FALSE;
3621 if(entryset->atlas == NULL) return FALSE;
3622 {
3623 AtlasEntry *ae;
3624 Atlas *atlas;
3625 vec2 charScreenSize;
3626 vec2 charScreenOffset;
3627 vec2 charScreenAdvance;
3628 vec2 penxy;
3629 int i, ichar;
3630 // not used right now int bmscale;
3631 GLfloat x,y,z, xx, yy;
3632 float aw,ah;
3633 int ih, kk;
3634 //bmscale = 2; not used right now
3635 //(2 end vert + (2 vert/glyph * max 128 glyhps per line)) x 3 coords per vert = (2+(256))*3 = 258*3 = 774
3636 GLfloat *vert; //vert[774];
3637 //(4 tex / glyph * max 128 glyphs per line) * 2 coords per tex = (4 * 128)*2 = (512)*2 = 1024;
3638 GLfloat *tex; //tex[1024];
3639 //(2 triangles * 3 ind / triangle) * max 128 glyphs/line = 6 * 128 = 768
3640 GLushort *ind; //ind[768];
3641 int maxlen = 128;
3642 ttglobal tg = gglobal();
3643 ppComponent_Text p = (ppComponent_Text)tg->Component_Text.prv;
3644
3645 if(p->textpanel_size < max(maxlen,128)){
3646 int newsize = max(maxlen,128);
3647 p->textpanel_size = newsize;
3648 p->textpanel_vert_size = (2+(2*(newsize*2)))*3;
3649 p->textpanel_tex_size = (4*newsize)*2;
3650 p->textpanel_ind_size = (2*3)*(newsize*2);
3651 //vert: (2 end vert + (2 vert/glyph * max 128 glyhps per line)) x 3 coords per vert = (2+(256))*3 = 258*3 = 774
3652 p->textpanel_vert = REALLOC(p->textpanel_vert,p->textpanel_vert_size*sizeof(GLfloat));
3653 //tex: (4 tex / glyph * max 128 glyphs per line) * 2 coords per tex = (4 * 128)*2 = (512)*2 = 1024;
3654 p->textpanel_tex = REALLOC(p->textpanel_tex,p->textpanel_tex_size*sizeof(GLfloat));
3655 //ind: (2 triangles * 3 ind / triangle) * max 128 glyphs/line = 6 * 128 = 768
3656 p->textpanel_ind = REALLOC(p->textpanel_ind,p->textpanel_ind_size*sizeof(GLushort));
3657 }
3658 vert = p->textpanel_vert;
3659 tex = p->textpanel_tex;
3660 ind = p->textpanel_ind;
3661
3662 maxlen = min(maxlen,len);
3663 x=y=z = 0.0f;
3664 //penxy = pixel2normalizedScreen((float)(*pen_x),(float)(*pen_y));
3665 penxy = pixel2normalizedViewport((GLfloat)(*pen_x),(GLfloat)(*pen_y));
3666 penxy.Y = penxy.Y - 2.0f + .05; //heuristic (band-aid)
3667
3668 x = penxy.X;
3669 y = penxy.Y;
3670 atlas = entryset->atlas;
3671 aw = 1.0f/(float)atlas->size.X;
3672 ah = 1.0f/(float)atlas->size.Y;
3673 ih = atlas->size.Y;
3674 for(i=0;i<maxlen;i++)
3675 {
3676 ichar = (int)cText[i];
3677 if (ichar == '\t') ichar = ' '; //trouble with tabs, quick hack
3678 ae = AtlasEntrySet_getEntry(entryset,ichar);
3679 if(!ae)
3680 ae = AtlasEntrySet_getEntry(entryset,(int)' ');
3681 if(ae)
3682 {
3683 // 1 2
3684 // 0 3
3685 charScreenSize = pixel2normalizedViewportScale(ae->size.X, ae->size.Y);
3686 charScreenAdvance = pixel2normalizedViewportScale(ae->advance.X, ae->advance.Y);
3687 charScreenOffset = pixel2normalizedViewportScale(ae->pos.X,ae->pos.Y);
3688 //from baseline origin, add offset to get to upper left corner of image box
3689 xx = x + charScreenOffset.X;
3690 yy = y + charScreenOffset.Y;
3691 kk = i*4*3;
3692 vert[kk +0] = xx;
3693 vert[kk +1] = yy - charScreenSize.Y;
3694 vert[kk +2] = z;
3695 vert[kk +3] = xx;
3696 vert[kk +4] = yy;
3697 vert[kk +5] = z;
3698 vert[kk +6] = xx + charScreenSize.X;
3699 vert[kk +7] = yy;
3700 vert[kk +8] = z;
3701 vert[kk +9] = xx + charScreenSize.X;
3702 vert[kk+10] = yy - charScreenSize.Y;
3703 vert[kk+11] = z;
3704 if(kk+11 >= p->textpanel_vert_size)
3705 printf("ouch vert not big enough, need %d have %d\n",kk+11 +1,p->textpanel_vert_size);
3706 x = x + charScreenAdvance.X;
3707 (*pen_x) += ae->advance.X;
3708 kk = i*4*2;
3709 tex[kk +0] = ((float)(ae->apos.X))*aw;
3710 tex[kk +2] = ((float)(ae->apos.X))*aw;
3711
3712 tex[kk +4] = ((float)(ae->apos.X + ae->size.X))*aw;
3713 tex[kk +6] = ((float)(ae->apos.X + ae->size.X))*aw;
3714
3715 if(iyup){
3716 tex[kk +1] = ((float)(ih - (ae->apos.Y + ae->size.Y)))*ah;
3717 tex[kk +3] = ((float)(ih - ae->apos.Y))*ah;
3718
3719 tex[kk +5] = ((float)(ih - ae->apos.Y))*ah;
3720 tex[kk +7] = ((float)(ih - (ae->apos.Y + ae->size.Y)))*ah;
3721 }else{
3722 tex[kk +1] = ((float)((ae->apos.Y + ae->size.Y)))*ah;
3723 tex[kk +3] = ((float)(ae->apos.Y))*ah;
3724
3725 tex[kk +5] = ((float)(ae->apos.Y))*ah;
3726 tex[kk +7] = ((float)((ae->apos.Y + ae->size.Y)))*ah;
3727 }
3728 if(kk+7 >= p->textpanel_tex_size)
3729 printf("ouch tex not big enough, need %d have %d\n",kk+7 +1,p->textpanel_tex_size);
3730
3731 // 1-2 2
3732 // |/ /|
3733 // 0 0-3
3734 kk = i*3*2;
3735 ind[kk +0] = i*4 + 0;
3736 ind[kk +1] = i*4 + 1;
3737 ind[kk +2] = i*4 + 2;
3738 ind[kk +3] = i*4 + 2;
3739 ind[kk +4] = i*4 + 3;
3740 ind[kk +5] = i*4 + 0;
3741 if(kk+5 >= p->textpanel_ind_size)
3742 printf("ouch ind not big enough, need %d have %d\n",kk+5 +1,p->textpanel_ind_size);
3743
3744 }
3745 }
3746
3747if(0) glEnableVertexAttribArray (p->positionLoc );
3748if(0) glEnableVertexAttribArray (p->texCoordLoc );
3749 // Load the vertex position
3750 glVertexAttribPointer (p->positionLoc, 3, GL_FLOAT,
3751 GL_FALSE, 0, vert );
3752 // Load the texture coordinate
3753 glVertexAttribPointer ( p->texCoordLoc, 2, GL_FLOAT,
3754 GL_FALSE, 0, tex );
3755
3756 glDrawElements ( GL_TRIANGLES, len*3*2, GL_UNSIGNED_SHORT, ind );
3757
3758
3759 }
3760 return TRUE;
3761}
3762
3763// this is called in MainLoop.c
3764void after_textpanel_render_rows(){
3765 //restore shader
3766 glEnable(GL_DEPTH_TEST);
3767 glDepthMask(GL_TRUE);
3768 restoreGlobalShader();
3769}
3770
3771#ifdef OLDCODE
3772
3773This code may not be used anymore - JAS - Apr 2017
3774
3775static void render_screentext0(struct X3D_Text *tnode){
3776 /* to be called from Text node render_Text for case of ScreenFontStyle
3777 this is a copy of the CaptionText method,
3778 x uses different shader (shader is simple like statusbarHud's)
3779 x doesn't use the Transform stack
3780 x doesn't use glColor
3781 */
3782 if(tnode && tnode->_nodeType == NODE_Text){
3783 screentextdata *sdata;
3784 AtlasEntrySet *set;
3785 AtlasFont *font;
3786 int nrow, row,i;
3787 row32 *rowvec;
3788 static int once = 0;
3790 ttglobal tg = gglobal();
3791 p = (ppComponent_Text)tg->Component_Text.prv;
3792
3793 finishedWithGlobalShader();
3794 glDepthMask(GL_FALSE);
3795 glDisable(GL_DEPTH_TEST);
3796 if(!p->programObject) initProgramObject();
3797
3798 glUseProgram ( p->programObject );
3799 if(!p->textureID)
3800 glGenTextures(1, &p->textureID);
3801
3802 glBindTexture(GL_TEXTURE_2D, p->textureID);
3803 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); //GL_LINEAR);
3804 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); //GL_LINEAR);
3805 glUniformMatrix4fv(p->modelviewLoc, 1, GL_FALSE,modelviewIdentityf);
3806 glUniformMatrix4fv(p->projectionLoc, 1, GL_FALSE, projectionIdentityf);
3807
3808
3809 sdata = (screentextdata*)tnode->_screendata;
3810 if(!sdata) return;
3811 nrow = sdata->nrow;
3812 font = (AtlasFont*)sdata->atlasfont;
3813 set = font->set;
3814 rowvec = sdata->rowvec;
3815 //render_captiontext(tnode->_font,tnode->_set, self->_caption,self->color);
3816 if(!once) printf("%s %5s %10s %10s %10s %10s !\n","c","adv","sx","sy","x","y");
3817
3818 for(row=0;row<nrow;row++){
3819 for(i=0;i<rowvec[row].len32;i++){
3820 AtlasEntry *entry;
3821 unsigned int ichar;
3822 ichar = rowvec[row].str32[i];
3823 entry = AtlasEntrySet_getEntry(set,ichar);
3824 if(entry){
3825 // drawsubimage(destination on screen, source glpyh details, source atlas)
3826 //int cscale;
3827 float xpos, ypos, xsize, ysize;
3828 vec2 fxy, fwh;
3829 chardata chr = rowvec[row].chr[i];
3830
3831 //[du] = [m] * [du/m]
3832 xpos = (float)chr.x + 90.0f + entry->pos.X;
3833 ypos = (float)chr.y + 30.0f - entry->pos.Y;
3834 xsize = entry->size.X;
3835 ysize = entry->size.Y;
3836 if(0){
3837 //upper left
3838 fxy = pixel2normalizedScreen((GLfloat)xpos,(GLfloat)ypos);
3839 fwh = pixel2normalizedScreenScale((GLfloat)xsize,(GLfloat)ysize);
3840 //lower left
3841 fxy.Y = fxy.Y - fwh.Y;
3842 xpos = fxy.X;
3843 ypos = fxy.Y;
3844 xsize = fwh.X;
3845 ysize = fwh.Y;
3846
3847 }
3848 if(1){
3849 //upper left
3850 fxy = pixel2normalizedViewport((GLfloat)xpos,(GLfloat)ypos);
3851 fwh = pixel2normalizedViewportScale((GLfloat)xsize,(GLfloat)ysize);
3852 //lower left
3853 fxy.Y = fxy.Y - fwh.Y;
3854 xpos = fxy.X;
3855 ypos = fxy.Y;
3856 xsize = fwh.X;
3857 ysize = fwh.Y;
3858 }
3859
3860
3861 if(!once) printf("%c %5f %10f %10f %10f %10f\n",(char)rowvec[row].str32[i],chr.advance,chr.sx,chr.sy,chr.x,chr.y);
3862 //dug9gui_DrawSubImage(xpos,ypos,xsize,ysize,
3863 dug9gui_DrawSubImage(xpos,ypos, xsize, ysize,
3864 entry->apos.X, entry->apos.Y, entry->size.X, entry->size.Y,
3865 set->atlas->size.X,set->atlas->size.Y,set->atlas->bytesperpixel,set->atlas->texture);
3866 }
3867 }
3868 }
3869 once = 1;
3870 glEnable(GL_DEPTH_TEST);
3871 glDepthMask(GL_TRUE);
3872 restoreGlobalShader();
3873 }
3874}
3875#endif //OLDCODE
3876
3877
3878static void dug9gui_DrawSubImage_scene(float xpos,float ypos, float xsize, float ysize,
3879 int ix, int iy, int iw, int ih, int width, int height, int bpp, unsigned char *buffer){
3880//xpos, ypos upper left location of where to draw the sub-image, in local coordinates
3881//xsize,ysize - size to stretch the sub-image to on the screen, in pixels
3882// ix,iy,iw,ih - position and size in pixels of the subimage in a bigger/atlas image, ix,iy is upper left
3883// width, height - size of bigger/atlas image
3884// bpp - bytes per pixel: usually 1 for apha images like freetype antialiased glyph imagery, usually 4 for RGBA from .bmp
3885// buffer - the bigger/atlas imagery pixels
3886// 1 - 2 4
3887// | / / | 2 triangles, 6 points
3888// 0 3 - 5
3889// I might want to split this function, so loading the texture to gpu is outside, done once for a series of sub-images
3890
3891/*
3892GLfloat cursorVert[] = {
3893 0.0f, 1.0f, 0.0f,
3894 0.0f, 0.0f, 0.0f,
3895 1.0f, 0.0f, 0.0f,
3896 0.0f, 1.0f, 0.0f,
3897 1.0f, 0.0f, 0.0f,
3898 1.0f, 1.0f, 0.0f};
3899*/
3900GLfloat cursorVert[] = {
3901 0.0f, 0.0f, 0.0f,
3902 0.0f, 1.0f, 0.0f,
3903 1.0f, 1.0f, 0.0f,
3904 0.0f, 0.0f, 0.0f,
3905 1.0f, 1.0f, 0.0f,
3906 1.0f, 0.0f, 0.0f};
3907//remember texture coordinates are 0,0 in lower left of texture image
3908GLfloat cursorTex[] = {
3909 0.0f, 0.0f,
3910 0.0f, 1.0f,
3911 1.0f, 1.0f,
3912 0.0f, 0.0f,
3913 1.0f, 1.0f,
3914 1.0f, 0.0f};
3915 GLushort ind[] = {0,1,2,3,4,5};
3916 //GLint pos, tex;
3917 vec2 fixy, fiwh; //fxy, fwh,
3918 //ivec2 xy;
3919 int i; //,j;
3920 GLfloat cursorVert2[18];
3921 GLfloat cursorTex2[12];
3923 ttglobal tg = gglobal();
3924 p = (ppComponent_Text)tg->Component_Text.prv;
3925
3926
3927 // Bind the base map - see above
3928 glActiveTexture ( GL_TEXTURE0 );
3929 glBindTexture ( GL_TEXTURE_2D, p->textureID );
3930
3931 // Set the base map sampler to texture unit to 0
3932 glUniform1i ( p->textureLoc, 0 );
3933
3934 switch(bpp){
3935 case 1:
3936 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA , GL_UNSIGNED_BYTE, buffer);
3937 //glUniform4f(color4fLoc,1.0f,1.0f,1.0f,0.0f);
3938 glUniform4f(p->blendLoc,0.0f,0.0f,0.0f,1.0f); // take color from vector, take alpha from texture2D
3939 break;
3940 case 2:
3941 //doesn't seem to come in here if my .png is gray+alpha on win32
3942 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buffer);
3943 break;
3944 case 4:
3945 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA , GL_UNSIGNED_BYTE, buffer);
3946 glUniform4f(p->blendLoc,1.0f,1.0f,1.0f,1.0f); //trust the texture2D color and alpha
3947 break;
3948 default:
3949 return;
3950 }
3951
3952 //fxy.Y -= 1.0; //DUG9GUI y=0 at top
3953 //fxy.X -= 1.0;
3954 iyup = 0;
3955 memcpy(cursorVert2,cursorVert,2*3*3*sizeof(GLfloat));
3956 for(i=0;i<6;i++){
3957 cursorVert2[i*3 +0] *= xsize; //fwh.X;
3958 cursorVert2[i*3 +0] += xpos; //fxy.X;
3959 if(!iyup) cursorVert2[i*3 +1] = 1.0f - cursorVert2[i*3 +1];
3960 cursorVert2[i*3 +1] *= ysize; //fwh.Y;
3961 cursorVert2[i*3 +1] += ypos; //fxy.Y;
3962 }
3963
3964 glVertexAttribPointer (p->positionLoc, 3, GL_FLOAT,
3965 GL_FALSE, 0, cursorVert2 );
3966 // Load the texture coordinate
3967 fixy.X = (float)ix/(float)width;
3968 fiwh.X = (float)iw/(float)width;
3969 if(!iyup){
3970 fixy.Y = (float)iy/(float)height;
3971 fiwh.Y = (float)ih/(float)height;
3972 }else{
3973 fixy.Y = (float)(height -iy)/(float)height;
3974 fiwh.Y =-(float)ih/(float)height;
3975 }
3976 memcpy(cursorTex2,cursorTex,2*3*2*sizeof(GLfloat));
3977 for(i=0;i<6;i++){
3978 cursorTex2[i*2 +0] *= fiwh.X;
3979 cursorTex2[i*2 +0] += fixy.X;
3980 cursorTex2[i*2 +1] *= fiwh.Y;
3981 cursorTex2[i*2 +1] += fixy.Y;
3982 }
3983 glVertexAttribPointer (p->texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, cursorTex2 );
3984 glEnableVertexAttribArray (p->positionLoc );
3985 glEnableVertexAttribArray (p->texCoordLoc);
3986
3988 //glActiveTexture ( GL_TEXTURE0 );
3989 //glBindTexture ( GL_TEXTURE_2D, textureID );
3990
3992 //glUniform1i ( textureLoc, 0 );
3993 glDrawElements ( GL_TRIANGLES, 3*2, GL_UNSIGNED_SHORT, ind );
3994
3995
3996}
3997
3998
3999static void render_screentext_aligned(struct X3D_Text *tnode, int screenAligned){
4000 /* to be called from Text node render_Text for case of ScreenFontStyle
4001 alignment = 0 - aligned to screen
4002 alignemnt = 1 - 3D in scene
4003 */
4004 if(tnode && tnode->_nodeType == NODE_Text){
4005 screentextdata *sdata;
4006 AtlasEntrySet *set;
4007 AtlasFont *font;
4008 int nrow, row,i;
4009 double rescale;
4010 row32 *rowvec;
4011 static int once = 0;
4012 GLfloat modelviewf[16], projectionf[16];
4013 GLdouble modelviewd[16], projectiond[16];
4015 ttglobal tg = gglobal();
4016 p = (ppComponent_Text)tg->Component_Text.prv;
4017
4018 finishedWithGlobalShader();
4019 glDepthMask(GL_FALSE);
4020 glDisable(GL_DEPTH_TEST);
4021 if(!p->programObject) initProgramObject();
4022
4023 glUseProgram ( p->programObject );
4024 if(!p->textureID)
4025 glGenTextures(1, &p->textureID);
4026
4027 glBindTexture(GL_TEXTURE_2D, p->textureID);
4028 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); //GL_LINEAR);
4029 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); //GL_LINEAR);
4030
4031 //get current color and send to shader
4032 {
4033 struct matpropstruct *myap = getAppearanceProperties();
4034 if (!myap) {
4035 glUniform4f(p->color4fLoc,.5f,.5f,.5f,1.0f); //default
4036 }else{
4037 float *dc;
4038 dc = myap->fw_FrontMaterial.diffuse;
4039 glUniform4f(p->color4fLoc,dc[0],dc[1],dc[2],dc[3]); //0.7f,0.7f,0.9f,1.0f);
4040 }
4041 }
4042
4043 if(!screenAligned){
4044 //text in 3D space
4045 // Text -> screenFontStyle should come in here
4046 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewd);
4047 matdouble2float4(modelviewf, modelviewd);
4048 glUniformMatrix4fv(p->modelviewLoc, 1, GL_FALSE,modelviewf);
4049 FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, projectiond);
4050 matdouble2float4(projectionf,projectiond);
4051 glUniformMatrix4fv(p->projectionLoc, 1, GL_FALSE, projectionf);
4052 }else{
4053 //EXPERIMENTAL - for testing, don't use for Text -> screenFontStyle
4054 glUniformMatrix4fv(p->modelviewLoc, 1, GL_FALSE,modelviewIdentityf);
4055 glUniformMatrix4fv(p->projectionLoc, 1, GL_FALSE, projectionIdentityf);
4056 }
4057
4058 sdata = (screentextdata*)tnode->_screendata;
4059 if(!sdata) return;
4060 nrow = sdata->nrow;
4061 font = (AtlasFont*)sdata->atlasfont;
4062 set = font->set;
4063 if(!set)
4064 return;
4065 rowvec = sdata->rowvec;
4066 //render_captiontext(tnode->_font,tnode->_set, self->_caption,self->color);
4067 if(!once) printf("%s %5s %10s %10s %10s %10s\n","c","adv","sx","sy","x","y");
4068 //if(!once) printf("%c %3d %10d %10d %10d %10d\n",(char)rowvec[row].str32[i],chr.advance,chr.sx,chr.sy,chr.x,chr.y);
4069 for(row=0;row<nrow;row++){
4070 for(i=0;i<rowvec[row].len32;i++){
4071 AtlasEntry *entry;
4072 unsigned int ichar;
4073 int set_emsize; //set_rowheight,
4074
4075 ichar = rowvec[row].str32[i];
4076 //set_rowheight = set->rowheight;
4077 set_emsize = set->EMpixels;
4078 entry = AtlasEntrySet_getEntry(set,ichar);
4079 if(entry){
4080 // drawsubimage(destination on screen, source glpyh details, source atlas)
4081 //int cscale;
4082 float x,y,sx,sy,scale;
4083 chardata chr = rowvec[row].chr[i];
4084 if(screenAligned){
4085 //EXPERIMENTAL - for testing, don't use for Text -> screenFontStyle
4086 //vec2 pp;
4087 GLint viewPort[4];
4088 double ptresize;
4089 //rescale = .03; //otherwise 1 char is half the screen
4090 rescale = (double)XRES/(double)PPI; //[du] = [du/in]/[pt/in]
4091 //scale = sdata->size/sdata->faceheight*XRES/PPI; //[du/em] = [pt/em] * [du/in] / [pt/in]
4092 scale = 1.0;
4093 //sx = chr.sx *scale * rescale *chr.advance * (float) entry->size.X / (float) set_emsize;
4094 //sy = chr.sy *scale * rescale *sdata->size * (float) entry->size.Y / (float) set_emsize;
4095 sx = sdata->size *rescale / (float)(set_emsize + 1) * (float) (entry->size.X + 1) ;
4096 sy = sdata->size *rescale / (float)(set_emsize + 1) * (float) (entry->size.Y + 1) ;
4097 sx = entry->size.X;
4098 sy = entry->size.Y;
4099 ptresize = 20.0/12.0; //MAGIC NUMBER
4100 x = ptresize * chr.x * scale *rescale;
4101 y = ptresize * chr.y * scale *rescale + (float)(entry->pos.Y - entry->size.Y)/(float)set_emsize*sdata->size*rescale;
4102 //pp = pixel2normalizedScreenScale( x, y);
4103 //pp = pixel2normalizedViewport(x,y);
4104 FW_GL_GETINTEGERV(GL_VIEWPORT, viewPort);
4105 x = ((GLfloat)x/(GLfloat)(viewPort[2]-viewPort[0])) * 2.0f -1.0f;
4106 y = ((GLfloat)y/(GLfloat)(viewPort[3]-viewPort[1])) * 2.0f -1.0f;
4107 sx = ((GLfloat)sx/(GLfloat)(viewPort[2]-viewPort[0])) * 2.0f;
4108 sy = ((GLfloat)sy/(GLfloat)(viewPort[3]-viewPort[1])) * 2.0f;
4109
4110 //x = pp.X;
4111 //y = pp.Y;
4112 if(!once) printf("%c %5f %10f %10f %10f %10f\n",(char)rowvec[row].str32[i],chr.advance,chr.sx,chr.sy,chr.x,chr.y);
4113 dug9gui_DrawSubImage_scene(x,y, sx, sy, //entry->size.X, entry->size.Y,
4114 entry->apos.X, entry->apos.Y, entry->size.X, entry->size.Y,
4115 set->atlas->size.X,set->atlas->size.Y,set->atlas->bytesperpixel,set->atlas->texture);
4116
4117 }else{
4118 // 3D screen Text -> screenFontStyle should come in here
4119 // we need to scale the rectangles in case there was maxextent, length[] specified
4120 // dug9 feb 4, 2016: not sure I've got the right formula, especially spacing
4121 //sx = chr.sx *chr.advance * (float) entry->size.X / (float) set_emsize;
4122 sx = chr.sx *chr.advance/(float) set_emsize * (float) entry->size.X;
4123 sy = chr.sy *sdata->size/(float) set_emsize * (float) entry->size.Y ;
4124 x = chr.x ;
4125 y = chr.y + sdata->size/(float)set_emsize * (float)(entry->pos.Y - entry->size.Y);
4126 if(!once) printf("%c %5f %10f %10f %10f %10f\n",(char)rowvec[row].str32[i],chr.advance,chr.sx,chr.sy,chr.x,chr.y);
4127 if(1) dug9gui_DrawSubImage_scene(x,y, sx, sy, //entry->size.X, entry->size.Y,
4128 entry->apos.X, entry->apos.Y, entry->size.X, entry->size.Y,
4129 set->atlas->size.X,set->atlas->size.Y,set->atlas->bytesperpixel,set->atlas->texture);
4130 }
4131 }
4132 }
4133 }
4134 once = 1;
4135 glEnable(GL_DEPTH_TEST);
4136 glDepthMask(GL_TRUE);
4137 restoreGlobalShader();
4138 }
4139}
4140void render_screentext(struct X3D_Text *tnode){
4141 //render_screentext0(tnode);
4142 //render_screentext_aligned(tnode,1); //aligned to screen
4143 render_screentext_aligned(tnode,0); //new shaderTrans
4144}
4145void prep_screentext(struct X3D_Text *tnode, int num, double screensize){
4146 if(tnode && tnode->_nodeType == NODE_Text && !tnode->_screendata){
4147 //called from make_text > FWRenderText first time to malloc,
4148 // and when FontStyle is ScreenFontStyle
4149 char *fontname;
4150 int iscreensize;
4151 screentextdata *sdata;
4152 iscreensize = (int)(screensize + .5);
4153 fontname = facename_from_num(num);
4154 tnode->_screendata = MALLOCV(sizeof(screentextdata));
4155 memset(tnode->_screendata,0,sizeof(screentextdata));
4156 sdata = (screentextdata*)tnode->_screendata;
4157 sdata->atlasfont = (AtlasFont*)searchAtlasTableOrLoad(fontname,iscreensize);
4158 if(!sdata->atlasfont){
4159 printf("dug9gui: Can't find font %s do you have the wrong name?\n",fontname);
4160 }
4161 //else{
4162 // sdata->set = (void*)sdata->atlasfont->set; //searchAtlasFontForSizeOrMake(sdata->atlasfont,iscreensize);
4163 // if(!sdata->set){
4164 // printf("couldn't create screentext for size %d\n",iscreensize);
4165 // }
4166 //}
4167 }
4168}
4169
4170static void *GUImalloc(struct Vector **guitable, int type){
4171 void *retval = NULL;
4172 int size = 0;
4173
4174 switch(type){
4175 //auxiliary types
4176 case GUI_ATLAS: size = sizeof(Atlas); break;
4177 case GUI_FONT: size = sizeof(AtlasFont); break;
4178 case GUI_ATLASENTRY: size = sizeof(AtlasEntry); break;
4179 case GUI_ATLASENTRYSET: size = sizeof(AtlasEntrySet); break;
4180 default:
4181 printf("no guielement of this type %d\n",type);
4182 }
4183 if(size){
4184 retval = MALLOCV(size);
4185 //add to any tables
4186 if(guitable){
4187 if(*guitable == NULL) *guitable = newVector(GUIElement*,20);
4188 vector_pushBack(GUIElement*,*guitable,retval);
4189 }
4190 }
4191 return retval;
4192}
4193
4194static void GUItablefree(struct Vector **guitable){
4195 int i;
4196 struct Vector *table = (*guitable);
4197 for(i=0;i<table->n;i++){
4198 int itype;
4199 GUIElement* el = vector_get(GUIElement*,table,i);
4200 itype = el->type;
4201 switch(itype){
4202 case GUI_ATLAS:
4203 {
4204 Atlas *a = (Atlas *)el;
4205 FREE_IF_NZ(a->texture);
4206 FREE_IF_NZ(a->name);
4207 //a->set
4208 }
4209 break;
4210 case GUI_FONT:
4211 {
4212 int j;
4213 AtlasFont *f = (AtlasFont *)el;
4214 //FREE_IF_NZ(f->name);
4215 FREE_IF_NZ(f->path);
4216 for(j=0;j<f->set->entries->n;j++){
4217 AtlasEntry *e = vector_get(AtlasEntry*,f->set->entries,j);
4218 FREE_IF_NZ(e->name);
4219 FREE_IF_NZ(e);
4220 }
4221 deleteVector(AtlasEntry*,f->set->entries);
4222 FREE_IF_NZ(f->set);
4223 }
4224 break;
4225 default:
4226 printf("mystery type %d\n",itype);
4227 break;
4228 }
4229 FREE_IF_NZ(el);
4230 }
4231 deleteVector(GUIElement*,*guitable);
4232 *guitable = NULL;
4233}