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