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