FreeWRL/FreeX3D  3.0.0
Textures.c
1 /*
2 
3  FreeWRL support library.
4  Texture handling code.
5 
6 */
7 
8 /****************************************************************************
9  This file is part of the FreeWRL/FreeX3D Distribution.
10 
11  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
12 
13  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
14  it under the terms of the GNU Lesser Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  GNU General Public License for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
25 ****************************************************************************/
26 
27 
28 
29 #include <config.h>
30 #include <system.h>
31 #include <system_threads.h>
32 #include <display.h>
33 #include <internal.h>
34 
35 #include <libFreeWRL.h>
36 #include <list.h>
37 
38 #include <threads.h>
39 
40 #include "../vrml_parser/Structs.h"
41 #include "../main/headers.h"
42 
43 #include "../scenegraph/readpng.h"
44 #include "../input/InputFunctions.h"
45 #include "../opengl/Material.h"
46 #include "../opengl/OpenGL_Utils.h"
47 #include "Textures.h"
48 #include "../world_script/fieldSet.h"
49 #include "../scenegraph/Component_Shape.h"
50 #include "../scenegraph/Component_CubeMapTexturing.h"
51 #include "../scenegraph/RenderFuncs.h"
52 #include "LoadTextures.h"
53 
54 // OLD_IPHONE_AQUA #ifdef AQUA
55 // OLD_IPHONE_AQUA #ifndef IPHONE
56 // OLD_IPHONE_AQUA # include <Carbon/Carbon.h>
57 // OLD_IPHONE_AQUA # include <QuickTime/QuickTime.h>
58 // OLD_IPHONE_AQUA #endif
59 // OLD_IPHONE_AQUA #else
60 // OLD_IPHONE_AQUA # if HAVE_JPEGLIB_H
61 // OLD_IPHONE_AQUA #undef HAVE_STDLIB_H
62 // OLD_IPHONE_AQUA #undef FAR
63 // OLD_IPHONE_AQUA # include <jpeglib.h>
64 // OLD_IPHONE_AQUA # include <setjmp.h>
65 // OLD_IPHONE_AQUA # endif
66 // OLD_IPHONE_AQUA #endif
67 
68 
69 
70 struct multiTexParams {
71 int multitex_mode[2];
72 int multitex_source[2];
73 int multitex_function;
74 };
75 
76 
77 #ifndef GL_EXT_texture_cube_map
78 //OLDCODE # define GL_NORMAL_MAP_EXT 0x8511
79 //OLDCODE # define GL_REFLECTION_MAP_EXT 0x8512
80 # define GL_TEXTURE_CUBE_MAP_EXT 0x8513
81 //OLDCODE # define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514
82 # define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515
83 //OLDCODE # define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516
84 //OLDCODE # define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517
85 //OLDCODE # define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518
86 //OLDCODE # define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519
87 //OLDCODE # define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A
88 //OLDCODE # define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B
89 //OLDCODE # define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C
90 #endif
91 
92 
93 static void new_bind_image(struct X3D_Node *node, struct multiTexParams *vparam);
94 textureTableIndexStruct_s *getTableIndex(int i);
95 
96 typedef struct pTextures{
97  struct Vector *activeTextureTable;
98  textureTableIndexStruct_s* loadThisTexture;
99 
100  /* current index into loadparams that texture thread is working on */
101  int currentlyWorkingOn;// = -1;
102  int textureInProcess;// = -1;
103 }* ppTextures;
104 
105 
106 void *Textures_constructor(){
107  void *v = MALLOCV(sizeof(struct pTextures));
108  memset(v,0,sizeof(struct pTextures));
109  return v;
110 }
111 void Textures_init(struct tTextures *t){
112  //public
113 
114  //private
115  t->prv = Textures_constructor();
116  {
117  ppTextures p = (ppTextures)t->prv;
118  p->activeTextureTable = NULL;
119 
120  /* current index into loadparams that texture thread is working on */
121  p->currentlyWorkingOn = -1;
122 
123  p->textureInProcess = -1;
124  }
125 }
126 void Textures_clear(struct tTextures *t){
127  //public
128  glDeleteBuffers (1,&t->defaultBlankTexture);
129  //private
130  {
131  //int i;
132  ppTextures p = (ppTextures)t->prv;
133  //for(i=0;i<vectorSize(p->activeTextureTable);i++){
134  // textureTableIndexStruct_s *tti = vector_get(textureTableIndexStruct_s *,p->activeTextureTable,i);
135  // if(tti && tti->texdata)
136  // FREE_IF_NZ(tti->texdata);
137  //}
138  deleteVector(textureTableIndexStruct_s *, p->activeTextureTable);
139  }
140 }
141 // OLD_IPHONE_AQUA #if defined(AQUA) /* for AQUA OS X sharing of OpenGL Contexts */
142 
143 // OLD_IPHONE_AQUA #elif defined(_MSC_VER)
144 #if defined(_MSC_VER)
145 
146 
147 #else
148 #if !defined(_ANDROID) && !defined(ANDROIDNDK) && !defined(GLES2)
149 GLXContext textureContext = NULL;
150 #endif
151 
152 #endif
153 
154 /* function Prototypes */
155 int findTextureFile(textureTableIndexStruct_s *entry);
156 //void _textureThread(void);
157 
158 void move_texture_to_opengl(textureTableIndexStruct_s*);
159 struct Uni_String *newASCIIString(char *str);
160 
161 int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight);
162 void readpng_cleanup(int free_image_data);
163 
164 
165 static void myTexImage2D (int generateMipMaps, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLubyte *pixels);
166 
167 /* gluScaleImage replacement */
168 
169 /* we manipulate things here as 4 byte colours (RGBA, or BGRA) so we try and ensure
170 that we have 32 bit numbers, thus this definition. ES-2.0 is 32 bits, but in case
171 someone compiles on a 64 bit system, with Material shader definitions in OpenGL-3.x,
172 then hopefully this will work for them, too */
173 
174 #ifndef uint32
175 # define uint32 uint32_t
176 #endif
177 
178 
179 
180 static void myScaleImage(int srcX,int srcY,int destX,int destY,unsigned char *src, unsigned char *dest) {
181  float YscaleFactor;
182  float XscaleFactor;
183  int wye, yex;
184  uint32 *src32 = (uint32 *)src;
185  uint32 *dest32 = (uint32 *)dest;
186 
187  if ((srcY<=0) || (destY<=0) || (srcX<=0) || (destX<=0)) return;
188  if (src == NULL) return;
189  if (dest == NULL) return;
190 
191  if ((srcY==destY) && (srcX==destX)) {
192  /* printf ("simple copy\n"); */
193  memcpy (dest,src,srcY*srcX*4); /* assuming FreeWRL-standard RGBA or BGRA textures */
194  }
195 
196  /* do x direction first */
197  YscaleFactor = ((float)srcY) / ((float)destY);
198  XscaleFactor = ((float)srcX) / ((float)destX);
199 
200  for (wye=0; wye<destY; wye++) {
201  for (yex=0; yex<destX; yex++) {
202  float fx, fy;
203  int row, column;
204  int oldIndex;
205 
206  fx = YscaleFactor * ((float) wye);
207  fy = XscaleFactor * ((float) yex);
208  row = (int)(fx);
209  column = (int)(fy);
210  oldIndex = row * srcX + column; /* so many rows, each row has srcX columns */
211  dest32[wye*destX+yex] = src32[oldIndex];
212  }
213  }
214 }
215 
216 static void myScaleImage3D(int srcX,int srcY,int srcZ, int destX,int destY,int destZ, unsigned char *src, unsigned char *dest) {
217  float YscaleFactor;
218  float XscaleFactor;
219  float ZscaleFactor;
220  float fx,fy,fz;
221  int iy, ix, iz;
222  uint32 *src32 = (uint32 *)src;
223  uint32 *dest32 = (uint32 *)dest;
224 
225  if ((srcY<=0) || (destY<=0) || (srcX<=0) || (destX<=0) || (srcZ<=0) || (destZ<=0)) return;
226  if (src == NULL) return;
227  if (dest == NULL) return;
228 
229  if ((srcY==destY) && (srcX==destX) && (srcZ==destZ)) {
230  /* printf ("simple copy\n"); */
231  memcpy (dest,src,srcY*srcX*srcZ*4); /* assuming FreeWRL-standard RGBA or BGRA textures */
232  }
233 
234  /* do x direction first */
235  YscaleFactor = ((float)srcY) / ((float)destY);
236  XscaleFactor = ((float)srcX) / ((float)destX);
237  ZscaleFactor = ((float)srcZ) / ((float)destZ);
238 
239  for (iz=0; iz<destZ; iz++) {
240  int page;
241  fz = ZscaleFactor * ((float) iz);
242  page = (int)fz;
243  for (iy=0; iy<destY; iy++) {
244  int row;
245  fy = YscaleFactor * ((float) iy);
246  row = (int)(fy);
247  for (ix=0; ix<destX; ix++) {
248  int column;
249  int oldIndex;
250 
251  fx = XscaleFactor * ((float) ix);
252  column = (int)(fx);
253  oldIndex = (page * srcY + row) * srcX + column; /* so many rows, each row has srcX columns */
254  dest32[(iz*destY + iy)*destX+ix] = src32[oldIndex];
255  }
256  }
257  }
258 }
259 int iclamp(int ival, int istart, int iend) {
260  int iret = ival;
261  iret = ival > iend? iend : ival;
262  iret = iret < istart ? istart : iret;
263  return iret;
264 }
265 void compute_3D_alpha_gradient_store_rgb(char *dest,int x,int y, int z){
266  //assumes we have a scalar image with info only in alpha, but (unused) RGB channels
267  //we compute 3D alpha/scalar gradient using one of sobel, roberts ...
268  //gradient has magnitude and direction (vs normal, which is of unit length)
269  //here we do an axis-aligned roberts ie gradient_x = x1 - x0
270  int iz,iy,ix, jz,jy,jx,jzz,jyy,jxx, k;
271  char *rgba0, *rgba1;
272  int gradient[3], maxgradient[3], mingradient[3];
273  unsigned char *urgba;
274  uint32 *pixels = (uint32 *)dest;
275 
276  for(k=0;k<3;k++) {
277  maxgradient[k] = -1;
278  mingradient[k] = 1;
279  }
280 
281 
282  for(iz=0;iz<z;iz++){
283  for(iy=0;iy<y;iy++){
284  for(ix=0;ix<x;ix++){
285  //initialize gradient
286  for(k=0;k<3;k++) gradient[k] = 0;
287  rgba0 = (char *) &pixels[(iz*y +iy)*x + ix];
288  urgba = (unsigned char *)rgba0;
289  if(1){
290  //sum onto gradient
291  jxx = jyy = jzz = 0;
292  //what if we are on the edge? for roberts, just duplicate next-to-edge by backing up one
293  if(iz == z-1) jzz = -1;
294  if(iy == y-1) jyy = -1;
295  if(ix == x-1) jxx = -1;
296  jx = jxx; jy = jyy; jz = jzz;
297  jx = jxx + 1;
298  rgba1 = (char *) &pixels[((iz+jz)*y +(iy+jy))*x + (ix+jx)];
299  gradient[0] = (int)rgba1[3] - (int)rgba0[3];
300  jx = jxx;
301  jy = jyy+1;
302  rgba1 = (char *) &pixels[((iz+jz)*y +(iy+jy))*x + (ix+jx)];
303  gradient[1] = (int)rgba1[3] - (int)rgba0[3];
304  jy = jyy;
305  jz = jzz+1;
306  rgba1 = (char *) &pixels[((iz+jz)*y +(iy+jy))*x + (ix+jx)];
307  gradient[2] = (int)rgba1[3] - (int)rgba0[3];
308  }else {
309  //extract edge-clamped 3x3x3
310  // X Y Z with [1] in center
311  int cube[3][3][3], i,j,ii,jj,kk;
312  for(i=-1;i<2;i++){
313  ii = iclamp(ix+i,0,x-1);
314  for(j=-1;j<2;j++){
315  jj= iclamp(iy+j,0,y-1);
316  for(k=-1;k<2;k++){
317  kk = iclamp(iz+k,0,z-1);
318  cube[i+1][j+1][k+1] = ((unsigned char *)&pixels[(kk*y +jj)*x + ii])[3];
319  }
320  }
321  }
322  if(1){
323  //roberts cross
324  //gradient[0] = (cube[2][2][2] - cube[1][1][1]) + (cube[2][0][0] - cube[1][1][1];
325  }
326  if(1){
327  //sobel gradient
328  gradient[0] = 0;
329  gradient[0] += cube[0][0][1] + 2*cube[0][1][1] + cube[0][2][1];
330  gradient[0] -= cube[2][0][1] + 2*cube[2][1][1] + cube[2][2][1];
331  gradient[0] += cube[0][1][0] + 2*cube[0][1][1] + cube[0][1][2];
332  gradient[0] -= cube[2][1][0] + 2*cube[2][1][1] + cube[2][1][2];
333 
334  gradient[1] = 0;
335  gradient[1] += cube[1][0][0] + 2*cube[1][0][1] + cube[1][0][2];
336  gradient[1] -= cube[1][2][0] + 2*cube[1][2][1] + cube[1][2][2];
337  gradient[1] += cube[0][0][1] + 2*cube[1][0][1] + cube[2][0][1];
338  gradient[1] -= cube[9][2][1] + 2*cube[1][2][1] + cube[2][2][1];
339 
340  gradient[2] = 0;
341  gradient[2] += cube[0][1][0] + 2*cube[1][1][0] + cube[2][1][0];
342  gradient[2] -= cube[0][1][2] + 2*cube[1][1][2] + cube[2][1][2];
343  gradient[2] += cube[1][0][0] + 2*cube[1][1][0] + cube[1][2][0];
344  gradient[2] -= cube[1][9][2] + 2*cube[1][1][2] + cube[1][2][2];
345  for(k=0;k<3;k++)
346  gradient[k] /= 2;
347 
348  }
349  }
350 
351  //scale gradient to -127 to +127 in each dimension
352  //roberts: a1 - a0 could be in range (255 - 0) to (0 -255) or -255 to 255,
353  // we need -127 to 127 signed char on each dim
354  for(k=0;k<3;k++) gradient[k] /= 2;
355  for(k=0;k<3;k++) {
356  maxgradient[k] = max(maxgradient[k],gradient[k]);
357  mingradient[k] = min(mingradient[k],gradient[k]);
358  }
359 
360  //but when texture2D / sampler2D convert from image pixel to float,
361  //the expect the pixels to be unsigned char.
362  //so we add 127 here, and subtract .5 in the shader, once they are float
363  for(k=0;k<3;k++) gradient[k] += 127;
364 
365  //set gradient in RGB channels
366  for(k=0;k<3;k++) urgba[k] = (unsigned char)gradient[k];
367  //if(rgba0[0] || rgba0[1] || rgba0[2]){
368  // if(rgba0[0] != rgba0[1] || rgba0[1] != rgba0[2])
369  // printf("[%d %d %d]",(int)rgba0[0],(int)rgba0[1],(int)rgba0[2]);
370  //}
371  }
372  }
373  }
374  if(0){
375  printf("mingradient %d %d %d\n",mingradient[0],mingradient[1],mingradient[2]);
376  printf("maxgradient %d %d %d\n",maxgradient[0],maxgradient[1],maxgradient[2]);
377  }
378  if(0){
379  //save gradient image for testing
380  textureTableIndexStruct_s *tti2, tt;
381  tti2 = &tt;
382  tti2->x = x;
383  tti2->y = y;
384  tti2->z = z;
385  tti2->texdata = dest;
386  tti2->channels = 3;
387  saveImage_web3dit(tti2,"gradientRGB.web3dit");
388  tti2->channels = 4;
389  saveImage_web3dit(tti2,"gradientRGBA.web3dit");
390 
391  }
392 
393 }
394 static void GenMipMap2D( GLubyte *src, GLubyte **dst, int srcWidth, int srcHeight, int *dstWidth, int *dstHeight )
395 {
396  int x,
397  y;
398  int texelSize = 4;
399 
400  *dstWidth = srcWidth / 2;
401  if ( *dstWidth <= 0 )
402  *dstWidth = 1;
403 
404  *dstHeight = srcHeight / 2;
405  if ( *dstHeight <= 0 )
406  *dstHeight = 1;
407 
408  *dst = MALLOC(void *, sizeof(GLubyte) * texelSize * (*dstWidth) * (*dstHeight) );
409  if ( *dst == NULL )
410  return;
411 
412  for ( y = 0; y < *dstHeight; y++ )
413  {
414  for( x = 0; x < *dstWidth; x++ )
415  {
416  int srcIndex[4];
417  float r = 0.0f,
418  g = 0.0f,
419  b = 0.0f,
420  a = 0.0f;
421 
422  int sample;
423 
424  // Compute the offsets for 2x2 grid of pixels in previous
425  // image to perform box filter
426  srcIndex[0] =
427  (((y * 2) * srcWidth) + (x * 2)) * texelSize;
428  srcIndex[1] =
429  (((y * 2) * srcWidth) + (x * 2 + 1)) * texelSize;
430  srcIndex[2] =
431  ((((y * 2) + 1) * srcWidth) + (x * 2)) * texelSize;
432  srcIndex[3] =
433  ((((y * 2) + 1) * srcWidth) + (x * 2 + 1)) * texelSize;
434 
435  // Sum all pixels
436  for ( sample = 0; sample < 4; sample++ )
437  {
438  r += src[srcIndex[sample]];
439  g += src[srcIndex[sample] + 1];
440  b += src[srcIndex[sample] + 2];
441  a += src[srcIndex[sample] + 3];
442  }
443 
444  // Average results
445  r /= 4.0f;
446  g /= 4.0f;
447  b /= 4.0f;
448  a /= 4.0f;
449 
450  // Store resulting pixels
451  (*dst)[ ( y * (*dstWidth) + x ) * texelSize ] = (GLubyte)( r );
452  (*dst)[ ( y * (*dstWidth) + x ) * texelSize + 1] = (GLubyte)( g );
453  (*dst)[ ( y * (*dstWidth) + x ) * texelSize + 2] = (GLubyte)( b );
454  (*dst)[ ( y * (*dstWidth) + x ) * texelSize + 3] = (GLubyte)( a );
455  }
456  }
457 }
458 /* create the MIPMAPS ourselves, as the OpenGL ES 2.0 can not do it */
459 static void myTexImage2D (int generateMipMaps, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLubyte *pixels) {
460  GLubyte *prevImage = NULL;
461  GLubyte *newImage = NULL;
462 
463  /* first, base image */
464  FW_GL_TEXIMAGE2D(target,level,internalformat,width,height,border,format,type,pixels);
465 
466  if (!generateMipMaps) return;
467  if ((width <=1) && (height <=1)) return;
468 
469 
470  /* go and create a bunch of mipmaps */
471 
472  prevImage = MALLOC(GLubyte *, width * height * 4);
473  memcpy (prevImage, pixels, width * height * 4);
474 
475  /* from the OpenGL-ES 2.0 book, page 189 */
476  level = 1;
477 
478  while ((width > 1) && (height > 1)) {
479  GLint newWidth, newHeight;
480 
481  GenMipMap2D(prevImage,&newImage, width, height, &newWidth, &newHeight);
482 
483  FW_GL_TEXIMAGE2D(target,level,internalformat,newWidth,newHeight,0,format,GL_UNSIGNED_BYTE,newImage);
484 
485  FREE_IF_NZ(prevImage);
486  prevImage = newImage;
487  level++;
488  width = newWidth;
489  height = newHeight;
490  }
491 
492  FREE_IF_NZ(newImage);
493 }
494 
495 
499 const char *texst(int num)
500 {
501  if (num == TEX_NOTLOADED) return "TEX_NOTLOADED";
502  if (num == TEX_LOADING) return "TEX_LOADING";
503  if (num == TEX_NEEDSBINDING)return "TEX_NEEDSBINDING";
504  if (num == TEX_LOADED)return "TEX_LOADED";
505  if (num == TEX_UNSQUASHED)return "UNSQUASHED";
506  return "unknown";
507 }
508 
509 
510 /* does a texture have alpha? - pass in a __tableIndex from a MovieTexture, ImageTexture or PixelTexture. */
511 int isTextureAlpha(int texno) {
513 
514  /* no, have not even started looking at this */
515  /* if (texno == 0) return FALSE; */
516 
517  ti = getTableIndex(texno);
518  if (ti==NULL) return FALSE;
519 
520  if (ti->status==TEX_LOADED) {
521  return ti->hasAlpha;
522  }
523  return FALSE;
524 }
525 
526 
527 /* is the texture thread initialized yet? */
528 int fwl_isTextureinitialized() {
529  return gglobal()->threads.TextureThreadRunning; // gglobal()->LoadTextures.TextureThreadInitialized;
530 }
531 
532 /* is this texture loaded? used in LoadSensor */
533 int fwl_isTextureLoaded(int texno) {
535 
536  /* no, have not even started looking at this */
537  /* if (texno == 0) return FALSE; */
538 
539  ti = getTableIndex(texno);
540  return (ti->status==TEX_LOADED);
541 }
542 
543 /* statusbar uses this to tell user that we are still loading */
544 int fwl_isTextureParsing() {
545  ppTextures p = (ppTextures)gglobal()->Textures.prv;
546 
547  /* return currentlyWorkingOn>=0; */
548 #ifdef TEXVERBOSE
549  if (p->textureInProcess > 0) {
550  printf("call to fwl_isTextureParsing %d, returning %d\n",
551  p->textureInProcess,p->textureInProcess > 0);
552  }
553 #endif
554  return p->textureInProcess >0;
555 }
556 
557 /* this node has changed - if there was a texture, destroy it */
558 void releaseTexture(struct X3D_Node *node) {
559 
560  int tableIndex;
562 
563  if (node->_nodeType == NODE_ImageTexture) {
564  tableIndex = ((struct X3D_ImageTexture *)node)->__textureTableIndex;
565  } else if (node->_nodeType == NODE_PixelTexture) {
566  tableIndex = ((struct X3D_PixelTexture *)node)->__textureTableIndex;
567  } else if (node->_nodeType == NODE_MovieTexture) {
568  tableIndex = ((struct X3D_MovieTexture *)node)->__textureTableIndex;
569  } else if (node->_nodeType == NODE_PixelTexture3D) {
570  tableIndex = ((struct X3D_PixelTexture3D *)node)->__textureTableIndex;
571  } else if (node->_nodeType == NODE_ImageTexture3D) {
572  tableIndex = ((struct X3D_ImageTexture3D *)node)->__textureTableIndex;
573  } else if (node->_nodeType == NODE_ComposedTexture3D) {
574  tableIndex = ((struct X3D_ComposedTexture3D *)node)->__textureTableIndex;
575 
576  } else return;
577 
578 #ifdef TEXVERBOSE
579  printf ("releaseTexture, calling getTableIndex\n");
580  ti = getTableIndex(tableIndex);
581  printf ("releaseTexture, ti %p, ti->status %d\n",ti,ti->status);
582  ti->status = TEX_NOTLOADED;
583 
584  if (ti->OpenGLTexture != TEXTURE_INVALID) {
585  printf ("deleting %d textures, starting at %u\n",ti->frames, ti->OpenGLTexture);
586  ti->OpenGLTexture = TEXTURE_INVALID;
587 /* FREE_IF_NZ(ti->OpenGLTexture); */
588  }
589 #endif
590 
591  ti = getTableIndex(tableIndex);
592  if(ti){
593  ti->status = TEX_NOTLOADED;
594  if (ti->OpenGLTexture != TEXTURE_INVALID) {
595  FW_GL_DELETETEXTURES(1, &ti->OpenGLTexture);
596  ti->OpenGLTexture = TEXTURE_INVALID;
597  /* FREE_IF_NZ(ti->OpenGLTexture); */
598  }
599  }
600 }
601 
602 
603 textureTableIndexStruct_s *getTableIndex(int indx) {
604  ppTextures p = (ppTextures)gglobal()->Textures.prv;
605 
606 #ifdef VERBOSE
607 {char line[200];
608 sprintf (line,"getTableIndex, looking for %d",indx);
609 ConsoleMessage (line);}
610 #endif
611  if (indx < 0) {
612  ConsoleMessage ("getTableIndex, texture <0 requested");
613  return NULL;
614  }
615 
616  if (p->activeTextureTable ==NULL ) {
617  ConsoleMessage ("NULL sizing errror in getTableIndex");
618  return NULL;
619  }
620 
621 
622  if (indx >= vectorSize(p->activeTextureTable)) {
623  ConsoleMessage ("sizing errror in getTableIndex");
624  return NULL;
625  }
626 
627 
628 #ifdef VERBOSE
629 {char line[200];
630 printf ("getTableIndex - valid request\n");
631 sprintf (line,"getTableIndex, for %d, size %d",indx, vectorSize(p->activeTextureTable));
632 ConsoleMessage (line);}
633 #endif
634 
635  return vector_get(textureTableIndexStruct_s *, p->activeTextureTable, indx);
636 }
637 int getTextureTableIndexFromFromTextureNode(struct X3D_Node *node){
638  int thisTexture = -1;
639  int thisTextureType = node->_nodeType;
640  if (thisTextureType==NODE_ImageTexture){
641  struct X3D_ImageTexture* it = (struct X3D_ImageTexture*) node;
642  thisTexture = it->__textureTableIndex;
643  } else if (thisTextureType==NODE_PixelTexture){
644  struct X3D_PixelTexture* pt = (struct X3D_PixelTexture*) node;
645  thisTexture = pt->__textureTableIndex;
646  } else if (thisTextureType==NODE_MovieTexture){
647  struct X3D_MovieTexture* mt = (struct X3D_MovieTexture*) node;
648  thisTexture = mt->__textureTableIndex;
649  } else if (thisTextureType==NODE_ImageCubeMapTexture){
650  struct X3D_ImageCubeMapTexture* ict = (struct X3D_ImageCubeMapTexture*) node;
651  thisTexture = ict->__textureTableIndex;
652  } else if (thisTextureType==NODE_GeneratedCubeMapTexture){
653  struct X3D_GeneratedCubeMapTexture* ict = (struct X3D_GeneratedCubeMapTexture*) node;
654  thisTexture = ict->__textureTableIndex;
655  } else if (thisTextureType==NODE_PixelTexture3D){
656  struct X3D_PixelTexture3D* pt = (struct X3D_PixelTexture3D*) node;
657  thisTexture = pt->__textureTableIndex;
658  } else if (thisTextureType==NODE_ImageTexture3D){
659  struct X3D_ImageTexture3D* pt = (struct X3D_ImageTexture3D*) node;
660  thisTexture = pt->__textureTableIndex;
661  } else if (thisTextureType==NODE_ComposedTexture3D){
662  struct X3D_ComposedTexture3D* pt = (struct X3D_ComposedTexture3D*) node;
663  thisTexture = pt->__textureTableIndex;
664  } else {
665  ConsoleMessage ("Invalid type for texture, %s\n",stringNodeType(thisTextureType));
666  }
667  return thisTexture;
668 }
669 textureTableIndexStruct_s *getTableTableFromTextureNode(struct X3D_Node *textureNode){
670  textureTableIndexStruct_s *ret = NULL;
671  int index = getTextureTableIndexFromFromTextureNode(textureNode);
672  if(index > -1)
673  ret = getTableIndex(index);
674  return ret;
675 }
676 /* is this node a texture node? if so, lets keep track of its textures. */
677 /* worry about threads - do not make anything reallocable */
678 void registerTexture0(int iaction, struct X3D_Node *tmp) {
679  //iaction =1 add, =0 remove
680  struct X3D_ImageTexture *it;
681 
682 
683  it = (struct X3D_ImageTexture *) tmp;
684  /* printf ("registerTexture, found a %s\n",stringNodeType(it->_nodeType)); */
685 
686  if ((it->_nodeType == NODE_ImageTexture) || (it->_nodeType == NODE_PixelTexture) ||
687  (it->_nodeType == NODE_ImageCubeMapTexture) ||
688  (it->_nodeType == NODE_GeneratedCubeMapTexture) ||
689  (it->_nodeType == NODE_PixelTexture3D) ||
690  (it->_nodeType == NODE_ImageTexture3D) ||
691  (it->_nodeType == NODE_ComposedTexture3D) ||
692  (it->_nodeType == NODE_MovieTexture)
693  ) {
694  ppTextures p = (ppTextures)gglobal()->Textures.prv;
695  if(iaction){
696  //ADD
697  // for the index, stored in the X3D node.
698  int textureNumber;
699  // new texture table entry. Zero all data
701  memset(newTexture,0,sizeof(textureTableIndexStruct_s));
702  newTexture->z = 1; //just texturing3D is > 1
703 
704 
705  if (p->activeTextureTable == NULL) {
706  p->activeTextureTable =newVector(textureTableIndexStruct_s *, 16);
707  }
708 
709  // keep track of which texture this one is.
710  textureNumber = vectorSize(p->activeTextureTable);
711 
712  //{char line[200]; sprintf (line,"registerTexture textureNumber %d",textureNumber); ConsoleMessage(line);}
713 
714  DEBUG_TEX("CREATING TEXTURE NODE: type %d\n", it->_nodeType);
715  /* I need to know the texture "url" here... */
716 
717  switch (it->_nodeType) {
718  /* save this index in the scene graph node */
719  case NODE_ImageTexture:
720  it->__textureTableIndex = textureNumber;
721  break;
722  case NODE_PixelTexture: {
723  struct X3D_PixelTexture *pt;
724  pt = (struct X3D_PixelTexture *) tmp;
725  pt->__textureTableIndex = textureNumber;
726  break; }
727  case NODE_PixelTexture3D: {
728  struct X3D_PixelTexture3D *pt;
729  pt = (struct X3D_PixelTexture3D *) tmp;
730  pt->__textureTableIndex = textureNumber;
731  break; }
732  case NODE_ImageTexture3D: {
733  struct X3D_ImageTexture3D *pt;
734  pt = (struct X3D_ImageTexture3D *) tmp;
735  pt->__textureTableIndex = textureNumber;
736  break; }
737  case NODE_ComposedTexture3D: {
738  struct X3D_ComposedTexture3D *pt;
739  pt = (struct X3D_ComposedTexture3D *) tmp;
740  pt->__textureTableIndex = textureNumber;
741  break; }
742  case NODE_MovieTexture: {
743  struct X3D_MovieTexture *mt;
744  mt = (struct X3D_MovieTexture *) tmp;
745  mt->__textureTableIndex = textureNumber;
746  break; }
747 
748  case NODE_ImageCubeMapTexture: {
749  struct X3D_ImageCubeMapTexture *v1t;
750  v1t = (struct X3D_ImageCubeMapTexture *) tmp;
751  v1t->__textureTableIndex = textureNumber;
752  break;
753  }
754 
755  case NODE_GeneratedCubeMapTexture: {
756  struct X3D_GeneratedCubeMapTexture *v1t;
757  v1t = (struct X3D_GeneratedCubeMapTexture *) tmp;
758  v1t->__textureTableIndex = textureNumber;
759  break;
760  }
761 
762  }
763 
764  /* set the scenegraphNode here */
765  newTexture->nodeType = it->_nodeType;
766  newTexture->scenegraphNode = X3D_NODE(tmp);
767  newTexture->textureNumber = textureNumber;
768  // save this to our texture table
769  vector_pushBack(textureTableIndexStruct_s *, p->activeTextureTable, newTexture);
770  }else{
771  //REMOVE
772  //we're using int indexes so we can't compact the vector to remove the element
773  //we need to flag it some how, and many functions use tti *getTableIndex(int num)
774  //and check if the returned value is null before trying to use it.
775  //we'll try using NULL as the signal its deleted.
776  textureTableIndexStruct_s * tti = NULL;
777  int *textureNumber = NULL;
778 
779  releaseTexture(tmp); //Mar 23, 2015 added, to zap from gl texture name list (and its texture storage)
780  //otherwise for geoLOD and inline, the OS MEM usage keeps going up after unload/load cycle
781 
782  switch (it->_nodeType) {
783  /* save this index in the scene graph node */
784  case NODE_ImageTexture:
785  textureNumber = &it->__textureTableIndex;
786  break;
787  case NODE_PixelTexture: {
788  struct X3D_PixelTexture *pt;
789  pt = (struct X3D_PixelTexture *) tmp;
790  textureNumber = &pt->__textureTableIndex;
791  break; }
792  case NODE_PixelTexture3D: {
793  struct X3D_PixelTexture3D *pt;
794  pt = (struct X3D_PixelTexture3D *) tmp;
795  textureNumber = &pt->__textureTableIndex;
796  break; }
797  case NODE_ImageTexture3D: {
798  struct X3D_ImageTexture3D *pt;
799  pt = (struct X3D_ImageTexture3D *) tmp;
800  textureNumber = &pt->__textureTableIndex;
801  break; }
802  case NODE_ComposedTexture3D: {
803  struct X3D_ComposedTexture3D *pt;
804  pt = (struct X3D_ComposedTexture3D *) tmp;
805  textureNumber = &pt->__textureTableIndex;
806  break; }
807  case NODE_MovieTexture: {
808  struct X3D_MovieTexture *mt;
809  mt = (struct X3D_MovieTexture *) tmp;
810  textureNumber = &mt->__textureTableIndex;
811  break; }
812 
813  case NODE_ImageCubeMapTexture: {
814  struct X3D_ImageCubeMapTexture *v1t;
815  v1t = (struct X3D_ImageCubeMapTexture *) tmp;
816  textureNumber = &v1t->__textureTableIndex;
817  break; }
818 
819  case NODE_GeneratedCubeMapTexture: {
820  struct X3D_GeneratedCubeMapTexture *v1t;
821  v1t = (struct X3D_GeneratedCubeMapTexture *) tmp;
822  textureNumber = &v1t->__textureTableIndex;
823  break; }
824  }
825  if(textureNumber){
826  tti = getTableIndex(*textureNumber);
827  if(tti){
828  // (*textureNumber) = -1; //is there a better flag?
829  vector_set(textureTableIndexStruct_s *,p->activeTextureTable,*textureNumber,NULL);
830  //unregister/unbind/deallocate anything else that was registered/bound/allocated above
831 
832  //Problem: when unloading an inline (including geoLOD inlines) with images that haven't yet loaded,
833  // load_inline > unload_broto > unregister_broto_instance > unRegisterX3DAnyNode > unRegisterTexture > registerTexture0 (here)
834  // if we zap the tti, then when the resource thread finishes downloading the image and goes to paste
835  // into wheretoplacedata* which is a tti* that's been zapped, we crash.
836  //Solution:
837  // quick fix: don't zap tti here, leave a memory leak TRIED, WORKED AS BANDAID
838  // proper fix: redesign resource fetch so it has a way to check if tti still exists, IMPLEMENTED Dec5,2014
839  // for example, have it use the table index number instead of a pointer directly to *tti,
840  // and here leave a NULL in the table at that index so resource thread can check if its been zapped
841  FREE_IF_NZ(tti->texdata);
842  //->filename is not strduped, just a pointer to actual_file which is freed in resource
843  FREE_IF_NZ(tti);
844  }
845  }
846  }
847  } else {
848  //ConsoleMessage ("registerTexture, ignoring this node");
849  }
850 }
851 void registerTexture(struct X3D_Node *tmp) {
852  registerTexture0(1,tmp);
853 }
854 void unRegisterTexture(struct X3D_Node *tmp) {
855  registerTexture0(0,tmp);
856 }
857 
858 void free_polyrep(struct X3D_PolyRep *rep);
859 
860 void unRegisterPolyRep(struct X3D_Node *tmp)
861 {
862  if (tmp->_intern)
863  {
864  free_polyrep(tmp->_intern);
865  }
866 }
867 
868 
869 void add_node_to_broto_context(struct X3D_Proto *currentContext,struct X3D_Node *node);
870 /* do TextureBackground textures, if possible */
871 void reallyDraw();
872 void loadBackgroundTextures (struct X3D_Background *node) {
873  struct X3D_ImageTexture *thistex;
874  struct X3D_TextureProperties *thistp;
875  struct Multi_String thisurl;
876  int count;
877 
878  /* initialization */
879  struct textureVertexInfo mtf = {boxtex,2,GL_FLOAT,0,NULL,NULL};
880  thisurl.n = 0; thisurl.p = NULL;
881  thistex = NULL;
882 
883  for (count=0; count<6; count++) {
884  /* go through these, back, front, top, bottom, right left */
885  switch (count) {
886  case 0: {thistex = X3D_IMAGETEXTURE(node->__frontTexture); thisurl = node->frontUrl; break;}
887  case 1: {thistex = X3D_IMAGETEXTURE(node->__backTexture); thisurl = node->backUrl; break;}
888  case 2: {thistex = X3D_IMAGETEXTURE(node->__topTexture); thisurl = node->topUrl; break;}
889  case 3: {thistex = X3D_IMAGETEXTURE(node->__bottomTexture); thisurl = node->bottomUrl; break;}
890  case 4: {thistex = X3D_IMAGETEXTURE(node->__rightTexture); thisurl = node->rightUrl; break;}
891  case 5: {thistex = X3D_IMAGETEXTURE(node->__leftTexture); thisurl = node->leftUrl; break;}
892  }
893  if (thisurl.n != 0 ) {
894  /* we might have to create a "shadow" node for the image texture */
895  if (thistex == NULL) {
896  int i;
897  thistex = createNewX3DNode(NODE_ImageTexture);
898  thistp = createNewX3DNode (NODE_TextureProperties);
899  if(node->_executionContext){
900  add_node_to_broto_context(X3D_PROTO(node->_executionContext),X3D_NODE(thistex));
901  add_node_to_broto_context(X3D_PROTO(node->_executionContext),X3D_NODE(thistp));
902  }
903 
904  /* set up TextureProperties, and link it in */
905 
906  /* we use the generic TextureProperties - especially the GenerateMipMaps flag... */
907  thistp->generateMipMaps = GL_FALSE; /* default settings, put here to ensure that */
908  /* future changes to the spec do no harm */
909 
910  thistex->textureProperties = X3D_NODE(thistp);
911  ADD_PARENT(X3D_NODE(thistp), X3D_NODE(thistex));
912 
913 #ifdef TEXVERBOSE
914  printf ("bg, creating shadow texture node url.n = %d\n",thisurl.n);
915 #endif
916 
917  /* copy over the urls */
918  thistex->url.p = MALLOC(struct Uni_String **, sizeof (struct Uni_String) * thisurl.n);
919  for (i=0; i<thisurl.n; i++) {
920  thistex->url.p[i] = newASCIIString (thisurl.p[i]->strptr);
921  }
922  thistex->url.n = thisurl.n;
923 
924  switch (count) {
925  case 0: {node->__frontTexture = X3D_NODE(thistex); break;}
926  case 1: {node->__backTexture = X3D_NODE(thistex); break;}
927  case 2: {node->__topTexture = X3D_NODE(thistex); break;}
928  case 3: {node->__bottomTexture = X3D_NODE(thistex); break;}
929  case 4: {node->__rightTexture = X3D_NODE(thistex); break;}
930  case 5: {node->__leftTexture = X3D_NODE(thistex); break;}
931  }
932  }
933 
934  /* we have an image specified for this face */
935  gglobal()->RenderFuncs.textureStackTop = 0;
936  /* render the proper texture */
937  render_node(X3D_NODE(thistex));
938  //OLDCODE FW_GL_COLOR3D(1.0,1.0,1.0);
939  textureTransform_start();
940  setupShaderB();
941 
942  textureCoord_send(&mtf);
943  FW_GL_VERTEX_POINTER(3,GL_FLOAT,0,BackgroundVert);
944  FW_GL_NORMAL_POINTER(GL_FLOAT,0,Backnorms);
945 
946  sendArraysToGPU (GL_TRIANGLES, count*6, 6);
947  reallyDraw();
948  textureTransform_end();
949 
950  }
951  }
952 }
953 /* do TextureBackground textures, if possible */
954 void loadTextureBackgroundTextures (struct X3D_TextureBackground *node) {
955  struct X3D_Node *thistex = NULL;
956  struct X3D_TextureProperties *thistp = NULL;
957  int count;
958  struct textureVertexInfo mtf = {boxtex,2,GL_FLOAT,0,NULL,NULL};
959 
960  for (count=0; count<6; count++) {
961  /* go through these, back, front, top, bottom, right left */
962  switch (count) {
963  case 0: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->frontTexture,thistex); break;}
964  case 1: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->backTexture,thistex); break;}
965  case 2: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->topTexture,thistex); break;}
966  case 3: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->bottomTexture,thistex); break;}
967  case 4: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->rightTexture,thistex); break;}
968  case 5: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->leftTexture,thistex); break;}
969  }
970  if (thistex != 0) {
971  /* we have an image specified for this face */
972  /* the X3D spec says that a X3DTextureNode has to be one of... */
973  if ((thistex->_nodeType == NODE_ImageTexture) ||
974  (thistex->_nodeType == NODE_PixelTexture) ||
975  (thistex->_nodeType == NODE_MovieTexture) ||
976  (thistex->_nodeType == NODE_MultiTexture)) {
977 
978  /* if we have no texture properties, add one here to disable mipmapping */
979  switch (thistex->_nodeType) {
980  case NODE_ImageTexture: {
981  if (X3D_IMAGETEXTURE(thistex)->textureProperties == NULL) {
982  thistp = createNewX3DNode (NODE_TextureProperties);
983  if(node->_executionContext){
984  add_node_to_broto_context(X3D_PROTO(node->_executionContext),X3D_NODE(thistp));
985  }
986  X3D_IMAGETEXTURE(thistex)->textureProperties = X3D_NODE(thistp);
987  ADD_PARENT(X3D_NODE(thistp),thistex);
988  }
989  break;
990  }
991 
992  case NODE_PixelTexture: {
993  if (X3D_PIXELTEXTURE(thistex)->textureProperties == NULL) {
994  thistp = createNewX3DNode (NODE_TextureProperties);
995  if(node->_executionContext){
996  add_node_to_broto_context(X3D_PROTO(node->_executionContext),X3D_NODE(thistp));
997  }
998 
999  X3D_PIXELTEXTURE(thistex)->textureProperties = X3D_NODE(thistp);
1000  ADD_PARENT(X3D_NODE(thistp),thistex);
1001  }
1002  break;
1003  }
1004 
1005  case NODE_MovieTexture:
1006  case NODE_MultiTexture:
1007  break;
1008  };
1009 
1010  gglobal()->RenderFuncs.textureStackTop = 0;
1011  /* render the proper texture */
1012  render_node((void *)thistex);
1013  //OLDCODE FW_GL_COLOR3D(1.0,1.0,1.0);
1014 
1015  textureCoord_send(&mtf);
1016  FW_GL_VERTEX_POINTER(3,GL_FLOAT,0,BackgroundVert);
1017  FW_GL_NORMAL_POINTER(GL_FLOAT,0,Backnorms);
1018 
1019  sendArraysToGPU (GL_TRIANGLES, count*6, 6);
1020  reallyDraw();
1021  }
1022  }
1023  }
1024 }
1025 
1026 
1027 /* load in a texture, if possible */
1028 void loadTextureNode (struct X3D_Node *node, void *vparam)
1029 {
1030  //printf ("loadTextureNode, node %p, params %p",node,param);
1031  if (NODE_NEEDS_COMPILING) {
1032 
1033  DEBUG_TEX ("FORCE NODE RELOAD: %p %s\n", node, stringNodeType(node->_nodeType));
1034 
1035  /* force a node reload - make it a new texture. Don't change
1036  the parameters for the original number, because if this
1037  texture is shared, then ALL references will change! so,
1038  we just accept that the current texture parameters have to
1039  be left behind. */
1040  MARK_NODE_COMPILED;
1041 
1042  /* this will cause bind_image to create a new "slot" for this texture */
1043  /* cast to GLuint because __texture defined in VRMLNodes.pm as SFInt */
1044 
1045  switch (node->_nodeType) {
1046 
1047  case NODE_MovieTexture: {
1048  //releaseTexture(node);
1049  }
1050  break;
1051 
1052  case NODE_PixelTexture:
1053  releaseTexture(node);
1054  break;
1055 
1056  case NODE_ImageTexture:
1057  releaseTexture(node);
1058  break;
1059 
1060  case NODE_ImageCubeMapTexture:
1061  releaseTexture(node);
1062  break;
1063 
1064  case NODE_GeneratedCubeMapTexture:
1065  //releaseTexture(node);
1066  break;
1067 
1068  case NODE_PixelTexture3D:
1069  releaseTexture(node);
1070  break;
1071  case NODE_ImageTexture3D:
1072  releaseTexture(node);
1073  break;
1074  case NODE_ComposedTexture3D:
1075  releaseTexture(node);
1076  break;
1077 
1078  default: {
1079  printf ("loadTextureNode, unknown node type %s\n",stringNodeType(node->_nodeType));
1080  return;
1081  }
1082 
1083  }
1084  }
1085 
1086  new_bind_image (X3D_NODE(node), (struct multiTexParams *)vparam);
1087  return;
1088 }
1089 
1090 static void compileMultiTexture (struct X3D_MultiTexture *node) {
1091  struct multiTexParams *paramPtr;
1092  int count;
1093  int max;
1094  s_renderer_capabilities_t *rdr_caps;
1095  ttglobal tg = gglobal();
1096  rdr_caps = tg->display.rdr_caps;
1097 
1098  /* have to regen the shape*/
1099  MARK_NODE_COMPILED;
1100 
1101  /* alloc fields, if required - only do this once, even if node changes */
1102  if (node->__xparams == 0) {
1103  /* printf ("loadMulti, MALLOCing for params\n"); */
1104  node->__xparams = MALLOC (void *, sizeof (struct multiTexParams) * rdr_caps->texture_units);
1105 
1106  //printf ("just mallocd %ld in size for __params\n",sizeof (struct multiTexParams) * gglobal()->display.rdr_caps.texture_units);
1107 
1108  //printf ("paramPtr is %p\n",(int *)node->__params);
1109 
1110  paramPtr = (struct multiTexParams*) node->__xparams;
1111 
1112  /* set defaults for these fields */
1113  for (count = 0; count < rdr_caps->texture_units; count++) {
1114  paramPtr->multitex_mode[0]= MTMODE_MODULATE; //rgba (or rgb if a > 0)
1115  paramPtr->multitex_mode[1]= 0; //0=unused -1=default else alpha channel part
1116  paramPtr->multitex_source[0]=INT_ID_UNDEFINED; //rgba (or rgb if a > 0)
1117  paramPtr->multitex_source[1]=0; //0=unused -1=default else alpha channel part
1118  paramPtr->multitex_function=INT_ID_UNDEFINED;
1119  paramPtr++;
1120  }
1121  }
1122 
1123  /* how many textures can we use? no sense scanning those we cant use */
1124  //max = node->mode.n;
1125  max = node->texture.n;
1126  if (max > rdr_caps->texture_units) max = rdr_caps->texture_units;
1127 
1128  // warn users that function and source parameters not looked at right now
1129  //if ((node->source.n>0) || (node->function.n>0)) {
1130  // ConsoleMessage ("currently, MultiTexture source and function parameters defaults used");
1131  //}
1132  /* go through the params, and change string name into an int */
1133  paramPtr = (struct multiTexParams*) node->__xparams;
1134  for (count = 0; count < max; count++) {
1135  char *smode, *ssource, *sfunc;
1136  smode = ssource = sfunc = NULL;
1137  if(node->mode.n>count){
1138  int mode, modea;
1139  smode = node->mode.p[count]->strptr;
1140  modea = 0; //unused
1141  mode = findFieldInMULTITEXTUREMODE(smode); //we offset by 1 in the #defines
1142  if(mode > -1) mode += 1; //one-based defines
1143  if(mode == -1){
1144  //might be Castle style "RGB / ALPHA" dual modes
1145  if(strchr(smode,'/') || strchr(smode,',')){
1146  //yes, castle protocol
1147  char *srgb, *salpha, *b1,*b2, *splittable;
1148  int modergb, modealpha;
1149  splittable = strdup(smode);
1150  b1 = strchr(splittable,' ');
1151  b2 = strrchr(splittable,' ');
1152  salpha = b2+1;
1153  splittable[b1 - splittable] = '\0';
1154  srgb = splittable;
1155  modergb = findFieldInMULTITEXTUREMODE(srgb);
1156  if(modergb == -1)
1157  modergb = MTMODE_MODULATE;
1158  else
1159  modergb +=1; //one-based defines
1160  modealpha = findFieldInMULTITEXTUREMODE(salpha);
1161  if(modealpha == -1)
1162  modealpha = MTMODE_MODULATE; //default
1163  else
1164  modealpha += 1; //one-based defines
1165  free(splittable);
1166  mode = modergb;
1167  modea = modealpha;
1168  }
1169  }
1170  if(mode > -1){
1171  paramPtr->multitex_mode[0] = mode;
1172  paramPtr->multitex_mode[1] = modea;
1173  }
1174  //else default
1175  }
1176  if(node->source.n > count) {
1177  int source, sourcea;
1178  ssource = node->source.p[count]->strptr;
1179  source = findFieldInMULTITEXTURESOURCE(ssource); //we offset by 1 in the #defines
1180  if(source > -1) source += 1; //one-based defines
1181  sourcea = 0; //0=unused
1182  if(source == -1){
1183  //might be Castle style "RGB / ALPHA" dual modes
1184  if(strchr(ssource,'/') || strchr(ssource,',')){
1185  //yes, castle protocol
1186  char *srgb, *salpha, *b1,*b2, *splittable;
1187  int sourcergb, sourcealpha;
1188  splittable = strdup(ssource);
1189  b1 = strchr(splittable,' ');
1190  b2 = strrchr(splittable,' ');
1191  salpha = b2+1;
1192  splittable[b1 - splittable] = '\0';
1193  srgb = splittable;
1194  sourcergb = findFieldInMULTITEXTURESOURCE(srgb);
1195  if(sourcergb == -1)
1196  sourcergb = INT_ID_UNDEFINED; //default
1197  else
1198  sourcergb +=1; //one-based defines
1199  sourcealpha = findFieldInMULTITEXTURESOURCE(salpha);
1200  free(splittable);
1201  source = sourcergb;
1202  sourcea = sourcealpha;
1203  }
1204  }
1205  if(source > -1){
1206  paramPtr->multitex_source[0] = source;
1207  paramPtr->multitex_source[1] = sourcea;
1208  }
1209  //else default
1210  }
1211 
1212  if (node->function.n>count) {
1213  int ifunc;
1214  sfunc = node->function.p[count]->strptr;
1215  {
1216  ifunc = findFieldInMULTITEXTUREFUNCTION(sfunc);
1217  }
1218  if(ifunc > -1)
1219  paramPtr->multitex_function = ifunc;
1220  //else default
1221  }
1222 
1223 #ifdef TEXVERBOSE
1224 printf ("compile_MultiTexture, %d of %d, mode %d %d source %d %d function %d m %s s %s f %s\n",
1225 count,max,paramPtr->multitex_mode[0],paramPtr->multitex_mode[1],paramPtr->multitex_source[0],paramPtr->multitex_source[1],paramPtr->multitex_function,smode,ssource,sfunc);
1226 #endif //TEXVERBOSE
1227 
1228  paramPtr++;
1229  }
1230  //printf("end of compileMultiTexture\n");
1231 }
1232 
1233 void loadMultiTexture (struct X3D_MultiTexture *node) {
1234  int count;
1235  int max;
1236  struct multiTexParams *paramPtr;
1237  struct X3D_ImageTexture *nt;
1238  s_renderer_capabilities_t *rdr_caps;
1239  ttglobal tg = gglobal();
1240  rdr_caps = tg->display.rdr_caps;
1241 
1242 #ifdef TEXVERBOSE
1243  printf ("loadMultiTexture, this %s has %d textures %x %x\n",stringNodeType(node->_nodeType),
1244  node->texture.n,
1245  (int) node->texture.p[0], (int) node->texture.p[1]);
1246  printf (" change %d ichange %d\n",node->_change, node->_ichange);
1247 #endif
1248 
1249  /* new node, or node paramaters changed */
1250  if (NODE_NEEDS_COMPILING) {
1251  compileMultiTexture(node);
1252  }
1253 
1254  /* ok, normally the scene graph contains function pointers. What we have
1255  here is a set of pointers to datastructures of (hopefully!)
1256  types like X3D_ImageTexture, X3D_PixelTexture, and X3D_MovieTexture.
1257 
1258  */
1259 
1260  /* how many textures can we use? */
1261  max = node->texture.n;
1262  //printf ("texture.n %d, texture_units %d, MAX_MULTITEXTURE %d\n", node->texture.n, gglobal()->display.rdr_caps.texture_units, MAX_MULTITEXTURE);
1263 
1264  if (max > rdr_caps->texture_units) max = rdr_caps->texture_units;
1265  if (max > MAX_MULTITEXTURE) max = MAX_MULTITEXTURE;
1266 
1267 
1268  /* go through and get all of the textures */
1269  paramPtr = (struct multiTexParams *) node->__xparams;
1270 
1271 #ifdef TEXVERBOSE
1272  printf ("loadMultiTExture, param stack:\n");
1273  for (count=0; count<max; count++) {
1274  printf (" tex %d source %d mode %d\n",count,paramPtr[count].multitex_source,paramPtr[count].multitex_mode);
1275  }
1276 #endif
1277 
1278  for (count=0; count < max; count++) {
1279 #ifdef TEXVERBOSE
1280  printf ("loadMultiTexture, working on texture %d\n",count);
1281 #endif
1282 
1283  /* get the texture */
1284  nt = X3D_IMAGETEXTURE(node->texture.p[count]);
1285 
1286  switch (nt->_nodeType) {
1287  case NODE_PixelTexture:
1288  case NODE_ImageTexture :
1289  /* printf ("MultiTexture %d is a ImageTexture param %d\n",count,*paramPtr); */
1290  loadTextureNode (X3D_NODE(nt),paramPtr);
1291  break;
1292  case NODE_MultiTexture:
1293  printf ("MultiTexture texture %d is a MULTITEXTURE!!\n",count);
1294  break;
1295  default:
1296  printf ("MultiTexture - unknown sub texture type %d\n",
1297  nt->_nodeType);
1298  }
1299 
1300  /* now, lets increment textureStackTop. The current texture will be
1301  stored in boundTextureStack[textureStackTop]; textureStackTop will be 1
1302  for "normal" textures; at least 1 for MultiTextures. */
1303 
1304  tg->RenderFuncs.textureStackTop++;
1305 
1306 
1307 
1308  paramPtr++;
1309 
1310 #ifdef TEXVERBOSE
1311  printf ("loadMultiTexture, textureStackTop %d\n",gglobal()->RenderFuncs.textureStackTop);
1312  printf ("loadMultiTexture, finished with texture %d\n",count);
1313 #endif
1314  }
1315  //tg->RenderFuncs.multitexturenode = (void*)node;
1316 }
1317 
1318 #define BOUNDARY_TO_GL(direct) \
1319  switch (findFieldInTEXTUREBOUNDARYKEYWORDS(tpNode->boundaryMode##direct->strptr)) { \
1320  case TB_CLAMP: direct##rc=GL_CLAMP; break; \
1321  case TB_CLAMP_TO_EDGE: direct##rc=GL_CLAMP_TO_EDGE; break; \
1322  case TB_CLAMP_TO_BOUNDARY: direct##rc=GL_CLAMP_TO_BORDER; break; \
1323  case TB_MIRRORED_REPEAT: direct##rc=GL_MIRRORED_REPEAT; break; \
1324  case TB_REPEAT: direct##rc=GL_REPEAT; break; \
1325  default: direct##rc = GL_REPEAT; \
1326  }
1327 
1328 /* do we do 1 texture, or is this a series of textures, requiring final binding
1329  by this thread? */
1330 #define DEF_FINDFIELD(arr) \
1331  static int findFieldIn##arr(const char* field) \
1332  { \
1333  return findFieldInARR(field, arr, arr##_COUNT); \
1334  }
1335 
1336 DEF_FINDFIELD(TEXTUREMINIFICATIONKEYWORDS)
1337 DEF_FINDFIELD(TEXTUREMAGNIFICATIONKEYWORDS)
1338 DEF_FINDFIELD(TEXTUREBOUNDARYKEYWORDS)
1339 DEF_FINDFIELD(TEXTURECOMPRESSIONKEYWORDS)
1340 
1341 void unpackImageCubeMap6 (textureTableIndexStruct_s* me);
1342 void move_texture_to_opengl(textureTableIndexStruct_s* me) {
1343  int rx,ry,rz,sx,sy,sz;
1344  int x,y,z;
1345  GLint iformat;
1346  GLenum format;
1347 
1348  /* default texture properties; can be changed by a TextureProperties node */
1349  float anisotropicDegree=1.0f;
1350  int borderWidth;
1351 
1352  GLint Trc,Src,Rrc;
1353  GLint minFilter, magFilter;
1354  GLint compression;
1355  int generateMipMaps;
1356 
1357  unsigned char *mytexdata;
1358 
1359 
1360  /* for getting repeatS and repeatT info. */
1361  struct X3D_PixelTexture *pt = NULL;
1362  struct X3D_MovieTexture *mt = NULL;
1363  struct X3D_ImageTexture *it = NULL;
1364  struct X3D_PixelTexture3D *pt3d = NULL;
1365 
1366  struct X3D_TextureProperties *tpNode = NULL;
1367  int haveValidTexturePropertiesNode;
1368  GLfloat texPri;
1369  struct SFColorRGBA borderColour;
1370  s_renderer_capabilities_t *rdr_caps;
1371  ttglobal tg = gglobal();
1372  rdr_caps = tg->display.rdr_caps;
1373 
1374 
1375  /* initialization */
1376  Src = FALSE; Trc = FALSE; Rrc = FALSE;
1377  tpNode = NULL;
1378  haveValidTexturePropertiesNode = FALSE;
1379  texPri=0.0f;
1380  borderColour.c[0]=0.0f;borderColour.c[1]=0.0f;borderColour.c[2]=0.0f;borderColour.c[3]=0.0f;
1381  compression = GL_FALSE;
1382  borderWidth = 0;
1383  mytexdata = NULL;
1384 
1385  /* did this node get killed on the way here? */
1386  if (!checkNode(me->scenegraphNode, __FILE__,__LINE__)) {
1387  ConsoleMessage ("main node disappeared, ignoring texture\n");
1388  me->status = TEXTURE_INVALID;
1389  return;
1390  }
1391  /* printf ("move_texture_to_opengl, node of type %s\n",stringNodeType(me->scenegraphNode->_nodeType)); */
1392 
1393  /* is this texture invalid and NOT caught before here? */
1394  /* this is the same as the defaultBlankTexture; the following code should NOT be executed */
1395  if (me->texdata == NULL) {
1396  char buff[] = {0x70, 0x70, 0x70, 0xff} ; /* same format as ImageTextures - GL_BGRA or GL_RGBA here */
1397  me->x = 1;
1398  me->y = 1;
1399  me->z = 1;
1400  me->hasAlpha = FALSE;
1401  me->texdata = MALLOC(unsigned char *, 4);
1402  memcpy (me->texdata, buff, 4);
1403  }
1404 
1405  /* do we need to convert this to an OpenGL texture stream?*/
1406 
1407  /* we need to get parameters. */
1408  if (me->OpenGLTexture == TEXTURE_INVALID) {
1409 /* me->OpenGLTexture = MALLOC (GLuint *, sizeof (GLuint) * me->frames); */
1410  if ((getAppearanceProperties()->cubeFace==0) || (getAppearanceProperties()->cubeFace == GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT)) {
1411  FW_GL_GENTEXTURES (1, &me->OpenGLTexture);
1412  }
1413 
1414 #ifdef TEXVERBOSE
1415  printf ("just glGend texture for block %p is %u, type %s\n",
1416  me, me->OpenGLTexture,stringNodeType(me->nodeType));
1417 #endif
1418 
1419  }
1420 
1421  /* get the repeatS and repeatT info from the scenegraph node */
1422  if (me->nodeType == NODE_ImageTexture) {
1423  it = (struct X3D_ImageTexture *) me->scenegraphNode;
1424  Src = it->repeatS; Trc = it->repeatT;
1425  tpNode = X3D_TEXTUREPROPERTIES(it->textureProperties);
1426  } else if (me->nodeType == NODE_PixelTexture) {
1427  pt = (struct X3D_PixelTexture *) me->scenegraphNode;
1428  Src = pt->repeatS; Trc = pt->repeatT;
1429  tpNode = X3D_TEXTUREPROPERTIES(pt->textureProperties);
1430  } else if (me->nodeType == NODE_MovieTexture) {
1431  mt = (struct X3D_MovieTexture *) me->scenegraphNode;
1432  Src = mt->repeatS; Trc = mt->repeatT;
1433  tpNode =X3D_TEXTUREPROPERTIES(mt->textureProperties);
1434  } else if (me->nodeType == NODE_PixelTexture3D) {
1435  pt3d = (struct X3D_PixelTexture3D *) me->scenegraphNode;
1436  Src = pt3d->repeatS; Trc = pt3d->repeatT; Rrc = pt3d->repeatR;
1437  tpNode = X3D_TEXTUREPROPERTIES(pt3d->textureProperties);
1438  } else if (me->nodeType == NODE_ImageTexture3D) {
1439  struct X3D_ImageTexture3D * it3d;
1440  it3d = (struct X3D_ImageTexture3D *) me->scenegraphNode;
1441  Src = it3d->repeatS; Trc = it3d->repeatT; Rrc = it3d->repeatR;
1442  tpNode = X3D_TEXTUREPROPERTIES(it3d->textureProperties);
1443  } else if (me->nodeType == NODE_ComposedTexture3D) {
1444  struct X3D_ComposedTexture3D * ct3d;
1445  ct3d = (struct X3D_ComposedTexture3D *) me->scenegraphNode;
1446  Src = ct3d->repeatS; Trc = ct3d->repeatT; Rrc = ct3d->repeatR;
1447  tpNode = X3D_TEXTUREPROPERTIES(ct3d->textureProperties);
1448  } else if (me->nodeType == NODE_ImageCubeMapTexture) {
1449  struct X3D_ImageCubeMapTexture *mi = (struct X3D_ImageCubeMapTexture *) me->scenegraphNode;
1450  tpNode = X3D_TEXTUREPROPERTIES(mi->textureProperties);
1451  } else if (me->nodeType == NODE_GeneratedCubeMapTexture) {
1452  struct X3D_GeneratedCubeMapTexture *mi = (struct X3D_GeneratedCubeMapTexture *) me->scenegraphNode;
1453  tpNode = X3D_TEXTUREPROPERTIES(mi->textureProperties);
1454  }
1455  //texure3D faked via texture2D (in non-extended GLES2)
1456  //.. needs repeats for manual wrap vs clamp, will send in
1457  //.. passedInGenTex
1458  me->repeatSTR[0] = Src;
1459  me->repeatSTR[1] = Trc;
1460  me->repeatSTR[2] = Rrc;
1461 
1462 
1463  /* do we have a TextureProperties node? */
1464  if (tpNode) {
1465  if (tpNode->_nodeType != NODE_TextureProperties) {
1466  ConsoleMessage ("have a %s as a textureProperties node",stringNodeType(tpNode->_nodeType));
1467  } else {
1468  haveValidTexturePropertiesNode = TRUE;
1469  generateMipMaps = tpNode->generateMipMaps?GL_TRUE:GL_FALSE;
1470  texPri = tpNode->texturePriority;
1471  if ((texPri < 0.0) || (texPri>1.0)) {
1472  texPri = 0.0f;
1473  ConsoleMessage ("invalid texturePriority of %f",tpNode->texturePriority);
1474  }
1475  memcpy(&borderColour,&(tpNode->borderColor),sizeof(struct SFColorRGBA));
1476 
1477  anisotropicDegree = tpNode->anisotropicDegree;
1478  if ((anisotropicDegree < 1.0) || (anisotropicDegree>rdr_caps->anisotropicDegree)) {
1479  /* we can be quiet here
1480  ConsoleMessage ("anisotropicDegree error %f, must be between 1.0 and %f",anisotropicDegree, gglobal()->display.rdr_caps.anisotropicDegree);
1481  */
1482  anisotropicDegree = rdr_caps->anisotropicDegree;
1483  }
1484 
1485  borderWidth = tpNode->borderWidth;
1486  if (borderWidth < 0) borderWidth=0; if (borderWidth>1) borderWidth = 1;
1487 
1488  // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/texturing.html#t-TextureMagnificationModes
1489 
1490  switch (findFieldInTEXTUREMAGNIFICATIONKEYWORDS(tpNode->magnificationFilter->strptr)) {
1491  case TMAG_AVG_PIXEL:
1492  magFilter = GL_LINEAR; break; // GL_NEAREST; break;
1493  case TMAG_DEFAULT: magFilter = GL_LINEAR; break;
1494  case TMAG_FASTEST: magFilter = GL_LINEAR; break; /* DEFAULT */
1495  case TMAG_NEAREST_PIXEL: magFilter = GL_NEAREST; break;
1496  case TMAG_NICEST: magFilter = GL_NEAREST; break;
1497  default: magFilter = GL_NEAREST; ConsoleMessage ("unknown magnification filter %s",
1498  tpNode->magnificationFilter->strptr);
1499  }
1500 
1501  /* minFilter depends on Mipmapping */
1502  if (generateMipMaps) switch (findFieldInTEXTUREMINIFICATIONKEYWORDS(tpNode->minificationFilter->strptr)) {
1503  case TMIN_AVG_PIXEL: minFilter = GL_NEAREST; break;
1504  case TMIN_AVG_PIXEL_AVG_MIPMAP: minFilter = GL_NEAREST_MIPMAP_NEAREST; break;
1505  case TMIN_AVG_PIXEL_NEAREST_MIPMAP: minFilter = GL_NEAREST_MIPMAP_NEAREST; break;
1506  case TMIN_DEFAULT: minFilter = GL_NEAREST_MIPMAP_LINEAR; break;
1507  case TMIN_FASTEST: minFilter = GL_NEAREST_MIPMAP_LINEAR; break;
1508  case TMIN_NICEST: minFilter = GL_NEAREST_MIPMAP_NEAREST; break;
1509  case TMIN_NEAREST_PIXEL: minFilter = GL_NEAREST; break;
1510  case TMIN_NEAREST_PIXEL_NEAREST_MIPMAP: minFilter = GL_NEAREST_MIPMAP_LINEAR; break;
1511  default: minFilter = GL_NEAREST_MIPMAP_NEAREST;
1512  ConsoleMessage ("unknown minificationFilter of %s",
1513  tpNode->minificationFilter->strptr);
1514  }
1515  else switch (findFieldInTEXTUREMINIFICATIONKEYWORDS(tpNode->minificationFilter->strptr)) {
1516  case TMIN_AVG_PIXEL:
1517  case TMIN_AVG_PIXEL_AVG_MIPMAP:
1518  case TMIN_AVG_PIXEL_NEAREST_MIPMAP:
1519  case TMIN_DEFAULT:
1520  case TMIN_FASTEST:
1521  case TMIN_NICEST:
1522  case TMIN_NEAREST_PIXEL: minFilter = GL_NEAREST; break;
1523  case TMIN_NEAREST_PIXEL_NEAREST_MIPMAP: minFilter = GL_LINEAR; break;
1524  default: minFilter = GL_NEAREST;
1525  ConsoleMessage ("unknown minificationFilter of %s",
1526  tpNode->minificationFilter->strptr);
1527  }
1528 
1529  switch (findFieldInTEXTURECOMPRESSIONKEYWORDS(tpNode->textureCompression->strptr)) {
1530  case TC_DEFAULT: compression = GL_FASTEST; break;
1531  case TC_FASTEST: compression = GL_NONE; break; /* DEFAULT */
1532  case TC_HIGH: compression = GL_FASTEST; break;
1533  case TC_LOW: compression = GL_NONE; break;
1534  case TC_MEDIUM: compression = GL_NICEST; break;
1535  case TC_NICEST: compression = GL_NICEST; break;
1536 
1537  default: compression = GL_NEAREST_MIPMAP_NEAREST;
1538  ConsoleMessage ("unknown textureCompression of %s",
1539  tpNode->textureCompression->strptr);
1540  }
1541 
1542  BOUNDARY_TO_GL(S);
1543  BOUNDARY_TO_GL(T);
1544  BOUNDARY_TO_GL(R);
1545  }
1546  }
1547 
1548 
1549 
1550  if (!haveValidTexturePropertiesNode) {
1551  /* convert TRUE/FALSE to GL_TRUE/GL_FALSE for wrapS and wrapT */
1552  Src = Src ? GL_REPEAT : GL_CLAMP_TO_EDGE; //GL_CLAMP; //du9 changed from CLAMP to CLAMP_TO_EDGE Sept18,2011 to fix panorama seamline visibility
1553  Trc = Trc ? GL_REPEAT : GL_CLAMP_TO_EDGE; //GL_CLAMP;
1554  Rrc = Rrc ? GL_REPEAT : GL_CLAMP_TO_EDGE; //GL_CLAMP;
1555  generateMipMaps = GL_TRUE;
1556 
1557  if(me->x > 0 && me->y > 0)
1558  {
1559  // experimental code to deal with oblong texture images
1560  // The 'cause' of blurry oblong textures with GLES2 is the anisotropic
1561  // scaling of the image needed to square up the image for mipmapping.
1562  // For example if your texture image is oblong by a factor of 3, then
1563  // your avatar will need to be 3 times closer to the object to see the
1564  // same mipmap level as you would with an unscaled image.
1565  // (OpenGL redbook talks about MipMap levels and rho and lambda.)
1566  // here we detect if there's big anisotropic scaling/squaring coming up,
1567  // and if so turn off mipmapping and squaring
1568  // scene authors need to make their repeating textures (brick, siding,
1569  // shingles etc) squarish to get mipmapping and avoid moire/scintilation
1570  float ratio = 1.0f;
1571  if(me->x < me->y*me->z) ratio = (float)(me->y*me->z) / (float)me->x;
1572  else ratio = (float)me->x / (float)(me->y*me->z);
1573  if(ratio > 2.0f) generateMipMaps = GL_FALSE;
1574  }
1575 
1576  /* choose smaller images to be NEAREST, larger ones to be LINEAR */
1577  if ((me->x<=256) || ((me->y*me->z)<=256)) {
1578  minFilter = GL_NEAREST_MIPMAP_NEAREST;
1579  if(!generateMipMaps) minFilter = GL_NEAREST;
1580  magFilter = GL_NEAREST;
1581  } else {
1582  minFilter = GL_LINEAR_MIPMAP_NEAREST;
1583  if(!generateMipMaps) minFilter = GL_LINEAR;
1584  magFilter = GL_LINEAR;
1585  }
1586  }
1587 
1588  //ConsoleMessage ("move_texture_to_opengl cubeFace %x\n",getAppearanceProperties()->cubeFace);
1589 
1590  /* is this a CubeMap? If so, lets try this... */
1591 
1592  if (getAppearanceProperties()->cubeFace != 0) {
1593  //this is a single cubmap face pixeltexture tti (ie from __subTextures in ImageCubemap)
1594  unsigned char *dest = me->texdata;
1595  uint32 *sp;
1596 
1597  int cx;
1598 
1599 
1600  //#if defined (GL_BGRA)
1601  //iformat = GL_RGBA; format = GL_BGRA;
1602  //#else
1603  iformat = GL_RGBA; format = GL_RGBA;
1604  //#endif
1605 
1606 
1607  /* first image in the ComposedCubeMap, do some setups */
1608  if (getAppearanceProperties()->cubeFace == GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT) {
1609  FW_GL_TEXPARAMETERI(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1610  FW_GL_TEXPARAMETERI(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1611  FW_GL_TEXPARAMETERI(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1612  FW_GL_TEXPARAMETERI(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1613  FW_GL_TEXPARAMETERI(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
1614  }
1615 
1616  rx = me->x;
1617  ry = me->y;
1618  dest = me->texdata;
1619  if(1){
1620  //flip cubemap textures to be y-down following opengl specs table 3-19
1621  //'renderman' convention
1622  //stack method: row chunks at a time
1623  uint32 tp[512];
1624  int cy, cyy, icsize;
1625  sp = (uint32 *) me->texdata;
1626  for (cy=0; cy<ry/2; cy++) {
1627  cyy = ry - cy -1;
1628  for(cx=0;cx<rx;cx+=512){
1629  icsize = min(512,rx-cx-1)*4;
1630  memcpy(tp,&sp[cy*rx + cx],icsize);
1631  memcpy(&sp[cy*rx + cx],&sp[cyy*rx + cx],icsize);
1632  memcpy(&sp[cyy*rx + cx],tp,icsize);
1633  }
1634  }
1635  //printf("__flipping__\n"); //are we in here on every frame? yes, for generatedcubemaptexture, no for other cubemaps
1636  }
1637  generateMipMaps = 0;
1638  myTexImage2D(generateMipMaps, getAppearanceProperties()->cubeFace, 0, iformat, rx, ry, 0, format, GL_UNSIGNED_BYTE, dest);
1639 
1640  /* last thing to do at the end of the setup for the 6th face */
1641  if (getAppearanceProperties()->cubeFace == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) {
1642  glEnable(GL_TEXTURE_CUBE_MAP);
1643  glEnable(GL_TEXTURE_GEN_S);
1644  glEnable(GL_TEXTURE_GEN_T);
1645  glEnable(GL_TEXTURE_GEN_R);
1646  }
1647 
1648  } else {
1649 
1650  if (me->nodeType == NODE_ImageCubeMapTexture) {
1651  if(me->z == 1){
1652  /* if we have an single 2D image, ImageCubeMap, we have most likely got a png map;
1653  ________
1654  | T | - Top
1655  |L F R B| - Left, Front, Right, Back
1656  |__D____| - Down(bottom)
1657  let the render_ImageCubeMapTexture code unpack the maps from this one png */
1658  /* this is ok - what is happening is that we have one image, that needs to be
1659  split up into each face */
1660  /* this should print if we are actually working ok
1661  if (me->status != TEX_LOADED) {
1662  printf ("have ImageCubeMapTexture, but status != TEX_LOADED\n");
1663  }
1664  */
1665 
1666  /* call the routine in Component_CubeMapTexturing.c to split this baby apart */
1667  unpackImageCubeMap(me);
1668  me->status = TEX_LOADED; /* finito */
1669  }else if(me->z == 6){
1670  //likely a .DDS (MS invention) or web3dit (dug9 invention)
1671  //order of images: +x,-x,+y,-y,+z,-z (or R,L,F,B,T,D)
1672  unpackImageCubeMap6(me);
1673  me->status = TEX_LOADED; /* finito */
1674  }
1675  //now the __subTextures individual face textures will show as single faces above
1676  } else if(me->nodeType == NODE_GeneratedCubeMapTexture){
1677  //already unpacked into 6 separate PixelTexture tti->texdata during cubemap generation
1678  me->status = TEX_LOADED; /* finito */
1679  } else {
1680  int npot;
1681  /* a pointer to the tex data. We increment the pointer for movie texures */
1682  mytexdata = me->texdata;
1683  if (mytexdata == NULL) {
1684  printf ("mytexdata is null, texture failed, put something here\n");
1685  }
1686 
1687  glBindTexture (GL_TEXTURE_2D, me->OpenGLTexture);
1688 
1689  /* save this to determine whether we need to do material node
1690  within appearance or not */
1691 
1692  /*
1693  repeatS,repeatT,repeatR
1694  https://open.gl/textures
1695  how the texture should be sampled when a coordinate outside the range of 0to 1 is given
1696  - repeat (*1)
1697  - mirrored repeat
1698  - clamp to edge (*2)
1699  - clamp to border
1700  subset of opengl supported by web3d:
1701  http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/texturing.html#Texturecoordinates
1702  (*1) If repeatS is TRUE (the default), the texture map is repeated outside
1703  the [0.0, 1.0] texture coordinate range in the S direction so that it fills the shape.
1704  (*2) If repeatS is FALSE, the texture coordinates are clamped in the S direction to lie
1705  within the [0.0, 1.0] range.
1706  */
1707 
1708  FW_GL_TEXPARAMETERI( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, Src);
1709  FW_GL_TEXPARAMETERI( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, Trc);
1710 #if !defined(GL_ES_VERSION_2_0)
1711  FW_GL_TEXPARAMETERI( GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, Rrc);
1712  FW_GL_TEXPARAMETERF(GL_TEXTURE_2D,GL_TEXTURE_PRIORITY, texPri);
1713  FW_GL_TEXPARAMETERFV(GL_TEXTURE_2D,GL_TEXTURE_BORDER_COLOR,(GLfloat *)&borderColour);
1714 #endif /* GL_ES_VERSION_2_0 */
1715 
1716 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
1717  FW_GL_TEXPARAMETERF(GL_TEXTURE_2D,GL_TEXTURE_MAX_ANISOTROPY_EXT,anisotropicDegree);
1718 #endif
1719 
1720  if (compression != GL_NONE) {
1721  FW_GL_TEXPARAMETERI(GL_TEXTURE_2D, GL_TEXTURE_INTERNAL_FORMAT, GL_COMPRESSED_RGBA);
1722  glHint(GL_TEXTURE_COMPRESSION_HINT, compression);
1723  }
1724  npot = rdr_caps->av_npot_texture;
1725  x = me->x;
1726  y = me->y; // * me->z; //takes care of texture3D using strip image
1727  z = me->z;
1728 
1729  FW_GL_TEXPARAMETERI( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
1730  FW_GL_TEXPARAMETERI( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
1731  me->magFilter = magFilter == GL_LINEAR ? 1 : 0; //needed in frag shader for TEX3D simulation of texture3D with texture2D
1732 
1733  /* BGRA is seemingly faster on desktop machines... */
1734  //#if defined (GL_BGRA)
1735  //iformat = GL_RGBA; format = GL_BGRA;
1736  //#else
1737  iformat = GL_RGBA; format = GL_RGBA;
1738  //#endif
1739 
1740  /* do the image. */
1741  if(x && y) {
1742  unsigned char *dest = mytexdata;
1743 
1744  /* do we have to do power of two textures? */
1745  if (npot) { //rdr_caps->av_npot_texture) {
1746  rx = x; ry = y; rz = z;
1747  } else {
1748  /* find a power of two that fits */
1749  rx = 1;
1750  sx = x;
1751  while(sx) {sx /= 2; rx *= 2;}
1752  if(rx/2 == x) {rx /= 2;}
1753  ry = 1;
1754  sy = y;
1755  while(sy) {sy /= 2; ry *= 2;}
1756  if(ry/2 == y) {ry /= 2;}
1757 
1758  rz = 1;
1759  sz = z;
1760  while(sz) {sz /= 2; rz *= 2;}
1761  if(rz/2 == z) {rz /= 2;}
1762  }
1763 
1764  if (gglobal()->internalc.global_print_opengl_errors) {
1765  DEBUG_MSG("initial texture scale to %d %d\n",rx,ry);
1766  }
1767 
1768  //ConsoleMessage ("loadTextureNode, runtime texture size %d",gglobal()->display.rdr_caps.runtime_max_texture_size);
1769  if(z > 1){
1770  //its a texture3D / volume image
1771  int emulating3D_TILED;
1772  emulating3D_TILED = TRUE;
1773  generateMipMaps = FALSE;
1774  if(emulating3D_TILED){
1775  //tiled uses more of the max_texture_size x max_texture_size
1776  // texture3D emulator via TILED texture2D
1777  // reason for emulating: 2016 GLES2 via ANGLEPROJECT(gles emulator over DirectX on windows)
1778  // doesn't have Texture3D or Texture3DOES or Texture3DEXT.
1779  // reason for TILES: an oblong Y-STRIP approach exceded max texture size in Y (but had lots left in X)
1780  // desktop computer max_size (of 2D image in one dimension) 16384
1781  // android phone max_size 4096
1782  // and so would be resampled (blurry) in y and good in x
1783  // using tiles means room for more full z slices ie 256x256x256 == 4096x4096 == 16M,
1784  // 512x512x512 == 134M == 16384x16384/2, and therefore less blurry images
1785  // tiles start in upper left with z=0, increase in y,
1786  // then when hit ny tiles in a y strip, move right one tile, and restart at top
1787  // uniform tex3dTiles[3] = {nx,ny,z}
1788  // example ny = 4, nx = 3, z = 11
1789  // 1 5 9
1790  // 2 6 10
1791  // 3 7 11
1792  // 4 8
1793  //
1794  //
1795  int rc,sc,c,cube_root, max_size;
1796  unsigned char *texdataTiles = NULL;
1797  uint32 *p2, *p1;
1798  int nx, ny, ix, iy, nxx, nyy;
1799  int iz,j,k;
1800 
1801  max_size = rdr_caps->runtime_max_texture_size;
1802  //if(32bit) I find process doesn't have enough RAM left for opengl to malloc 512x512x512x4byte.
1803  //could try single channel, single byte textures, but for now we'll keep it under 17M pixels
1804  if(x * y * z > 256 * 256 * 256)
1805  max_size = min(max_size,4096);
1806  //max_size = 2048; //can re-set here for experiments
1807  cube_root = (int)pow( max_size * max_size + 3, 1.0/3.0);
1808  c = cube_root;
1809  //need lower-power-of-two so we squeeze into space available, and leave a little
1810  rc = 1;
1811  sc = c;
1812  while(sc) {sc /= 2; rc *= 2;}
1813  if(rc > c) {rc /= 2;}
1814  //ConsoleMessage("pow2 cube root %d\n",rc);
1815  cube_root = rc;
1816  if(rx != x || ry != y || rz != z || rx > cube_root || ry > cube_root || rz > cube_root) {
1817  /* do we have texture limits???
1818  dug9: windows intel i5: desktop opengl and uwp/angleproject 16384
1819  16384 x 16394 = 268M. cube-root 268M = 645.xx lets round down to pow2: 512
1820  android LG nexus 4096
1821  4096 x 4096 = 16.7M; cube-root 16.7M = 256.
1822  */
1823  if (rx > cube_root) rx = cube_root;
1824  if (ry > cube_root) ry = cube_root;
1825  if (rz > cube_root) rz = cube_root;
1826  }
1827 
1828  if (gglobal()->internalc.global_print_opengl_errors) {
1829  DEBUG_MSG("texture size after maxTextureSize taken into account: %d %d, from %d %d\n",rx,ry,x,y);
1830  }
1831  //ConsoleMessage("texture size after maxTextureSize taken into account: %d %d %d, from %d %d %d\n",rx,ry,rz,x,y,z);
1832 
1833  //rescale sub-images if/as needed
1834  dest = mytexdata;
1835  //if(rx != x || ry != y || rz != z){
1836  //if(rx > x || ry > y || rz > z){
1837  if(x > rx || y > ry || z > rz){
1838  int mx,my,mz;
1839  mx = min(x,rx);
1840  my = min(y,ry);
1841  mz = min(z,rz);
1842  dest = MALLOC(unsigned char *, 4 * rx * ry * rz);
1843  myScaleImage3D(x,y,z,mx,my,mz,mytexdata,dest);
1844  x = mx;
1845  y = my;
1846  z = mz;
1847  FREE_IF_NZ(me->texdata);
1848  }
1849 
1850  //COMPUTE GRADIENT - we'll do unconditionally if channels == 1 for 3D image
1851  //and hope that the one info channel is alpha because we overwrite rgb
1852  if(me->channels == 1){
1853  //alpha only scalar image, RGB are free to hold gradient
1854  compute_3D_alpha_gradient_store_rgb(dest,x,y,z);
1855  }
1856 
1857  ny = (int) sqrt(z+1);
1858  nx = z / ny;
1859  nx = z - nx*ny > 0 ? nx+1 : nx;
1860 
1861  me->tiles[0] = nx; //let the shader tiled emulator for texture3D know via uniform about the tile layout
1862  me->tiles[1] = ny;
1863  me->tiles[2] = z;
1864  //ConsoleMessage("Tiles ny %d nx %d zplanes %d\n",nx,ny,z);
1865  nxx = nx*rx;
1866  nyy = ny*ry;
1867 
1868  //place in tile formation - a series of fullish y strips
1869  texdataTiles = MALLOC(unsigned char *,nxx * nyy * 4);
1870  p2 = (uint32 *)texdataTiles;
1871  p1 = (uint32 *)dest;
1872  for(iz=0;iz<z;iz++){
1873  iy = iz % ny;
1874  ix = iz / ny;
1875  for(j=0;j<y;j++){
1876  for(k=0;k<x;k++){
1877  int ifrom, ito;
1878  uint32 pixel;
1879  ifrom = (iz*y + j)*x + k;
1880  ito = (iy*y + j)*nxx + (ix*x) + k;
1881  pixel = p1[ifrom];
1882  p2[ito] = pixel;
1883  }
1884  }
1885  }
1886  if(0){
1887  //write out tiled image for inspection
1888  textureTableIndexStruct_s tti2, *tti3;
1889  tti3 = &tti2;
1890  tti3->x = nxx;
1891  tti3->y = nyy;
1892  tti3->z = 1;
1893  tti3->channels = 4;
1894  tti3->texdata = texdataTiles;
1895  saveImage_web3dit(tti3, "test_tiled_texture.web3dit");
1896  }
1897 
1898  myTexImage2D(generateMipMaps, GL_TEXTURE_2D, 0, iformat, nxx, nyy, 0, format, GL_UNSIGNED_BYTE, texdataTiles);
1899  ConsoleMessage("final texture2D size %d %d\n",nxx,nyy);
1900  FREE_IF_NZ(texdataTiles);
1901  if(dest != me->texdata) FREE_IF_NZ(dest);
1902  }else{
1903  //use Texture3D which android and winRT/uwp don't have
1904  }
1905  }else{
1906  //ordinary 2D image textures
1907  if(rx != x || ry != y || rx > rdr_caps->runtime_max_texture_size || ry > rdr_caps->runtime_max_texture_size) {
1908  /* do we have texture limits???
1909  dug9: windows intel i5: desktop opengl and uwp/angleproject 16384
1910  16384 x 16394 = 268M. cube-root 268M = 645.xx lets round down to pow2: 512
1911  android LG nexus 4096
1912  4096 x 4096 = 16.7M; cube-root 16.7M = 256.
1913  */
1914  if (rx > rdr_caps->runtime_max_texture_size) rx = rdr_caps->runtime_max_texture_size;
1915  if (ry > rdr_caps->runtime_max_texture_size) ry = rdr_caps->runtime_max_texture_size;
1916  }
1917 
1918  if (gglobal()->internalc.global_print_opengl_errors) {
1919  DEBUG_MSG("texture size after maxTextureSize taken into account: %d %d, from %d %d\n",rx,ry,x,y);
1920  }
1921  //ConsoleMessage("texture size after maxTextureSize taken into account: %d %d, from %d %d\n",rx,ry,x,y);
1922 
1923  /* it is a power of 2, lets make sure it is square */
1924  /* ES 2.0 needs this for cross-platform; do not need to do this for desktops, but
1925  lets just keep things consistent
1926  But if not mipmapping, then (experience with win32 GLES2 emulator and QNX device)
1927  then it's not necessary to square the image, although current code will get here with
1928  generateMipMap always true.
1929  */
1930  if (rx != ry) {
1931  if(generateMipMaps){
1932  if (rx>ry)ry=rx;
1933  else rx=ry;
1934  }
1935  }
1936 
1937  /* if scaling is ok... */
1938  if ((x==rx) && (y==ry)) {
1939  dest = mytexdata;
1940  } else {
1941 
1942  /* try this texture on for size, keep scaling down until we can do it */
1943  /* all textures are 4 bytes/pixel */
1944  dest = MALLOC(unsigned char *, 4 * rx * ry);
1945 
1946  myScaleImage(x,y,rx,ry,mytexdata,dest);
1947  }
1948 
1949 
1950  myTexImage2D(generateMipMaps, GL_TEXTURE_2D, 0, iformat, rx, ry, 0, format, GL_UNSIGNED_BYTE, dest);
1951  }
1952  if(mytexdata != dest) {
1953  FREE_IF_NZ(dest);
1954  }
1955  }
1956 
1957  /* we can get rid of the original texture data here */
1958  FREE_IF_NZ (me->texdata);
1959  }
1960  }
1961 
1962 
1963  /* ensure this data is written to the driver for the rendering context */
1964  FW_GL_FLUSH();
1965 
1966  /* and, now, the Texture is loaded */
1967  me->status = TEX_LOADED;
1968 }
1969 
1970 
1971 /**********************************************************************************
1972  bind the image,
1973 
1974  itype tells us whether it is a PixelTexture, ImageTexture or MovieTexture.
1975 
1976  parenturl is a pointer to the url of the parent (for relative loads) OR
1977  a pointer to the image data (PixelTextures only)
1978 
1979  url the list of urls from the VRML file, or NULL (for PixelTextures)
1980 
1981  texture_num the OpenGL texture identifier
1982 
1983  repeatS, repeatT VRML fields
1984 
1985  param - vrml fields, but translated into GL_TEXTURE_ENV_MODE, GL_MODULATE, etc.
1986 ************************************************************************************/
1987 
1988 void new_bind_image(struct X3D_Node *node, struct multiTexParams *param) {
1989  int thisTexture;
1990  int thisTextureType;
1991  struct X3D_ImageTexture *it;
1992  struct X3D_PixelTexture *pt;
1993  struct X3D_MovieTexture *mt;
1994  struct X3D_ImageCubeMapTexture *ict;
1995  struct X3D_GeneratedCubeMapTexture *gct;
1996 
1997  textureTableIndexStruct_s *myTableIndex;
1998  //float dcol[] = {0.8f, 0.8f, 0.8f, 1.0f};
1999  ppTextures p;
2000  struct Multi_String *mfurl = NULL;
2001  ttglobal tg = gglobal();
2002  p = (ppTextures)tg->Textures.prv;
2003  //#define DEBUG_TEX ConsoleMessage
2004 
2005 // GET_THIS_TEXTURE;
2006 //#define GET_THIS_TEXTURE
2007  thisTextureType = node->_nodeType;
2008  if (thisTextureType==NODE_ImageTexture){
2009  it = (struct X3D_ImageTexture*) node;
2010  mfurl = &it->url;
2011  thisTexture = it->__textureTableIndex;
2012  } else if (thisTextureType==NODE_PixelTexture){
2013  pt = (struct X3D_PixelTexture*) node;
2014  thisTexture = pt->__textureTableIndex;
2015  } else if (thisTextureType==NODE_MovieTexture){
2016  mt = (struct X3D_MovieTexture*) node;
2017  thisTexture = mt->__textureTableIndex;
2018  mfurl = &mt->url;
2019  } else if (thisTextureType==NODE_ImageCubeMapTexture){
2020  ict = (struct X3D_ImageCubeMapTexture*) node;
2021  thisTexture = ict->__textureTableIndex;
2022  mfurl = &ict->url;
2023  } else if (thisTextureType==NODE_GeneratedCubeMapTexture){
2024  gct = (struct X3D_GeneratedCubeMapTexture*) node;
2025  thisTexture = gct->__textureTableIndex;
2026  } else if (thisTextureType==NODE_PixelTexture3D){
2027  struct X3D_PixelTexture3D *pt3d;
2028  pt3d = (struct X3D_PixelTexture3D*) node;
2029  thisTexture = pt3d->__textureTableIndex;
2030  } else if (thisTextureType==NODE_ImageTexture3D){
2031  struct X3D_ImageTexture3D *pt3d;
2032  pt3d = (struct X3D_ImageTexture3D*) node;
2033  thisTexture = pt3d->__textureTableIndex;
2034  mfurl = &pt3d->url;
2035  } else if (thisTextureType==NODE_ComposedTexture3D){
2036  struct X3D_ComposedTexture3D *pt3d;
2037  pt3d = (struct X3D_ComposedTexture3D*) node;
2038  thisTexture = pt3d->__textureTableIndex;
2039  } else {
2040  ConsoleMessage ("Invalid type for texture, %s\n",stringNodeType(thisTextureType));
2041  return;
2042  }
2043 
2044  myTableIndex = getTableIndex(thisTexture);
2045  if (myTableIndex->status != TEX_LOADED) {
2046  DEBUG_TEX("new_bind_image, I am %p, textureStackTop %d, thisTexture is %d myTableIndex %p status %s\n",
2047  node,tg->RenderFuncs.textureStackTop,thisTexture,myTableIndex, texst(myTableIndex->status));
2048  }
2049 
2050  /* default here; this is just a blank texture */
2051  tg->RenderFuncs.boundTextureStack[tg->RenderFuncs.textureStackTop] = tg->Textures.defaultBlankTexture;
2052  switch (myTableIndex->status) {
2053  case TEX_NOTLOADED:
2054  DEBUG_TEX("feeding texture %p to texture thread...\n", myTableIndex);
2055  if(mfurl && mfurl->n == 0) {
2056  //for <ImageTexture /> with url not declared, we should get the default blank image
2057  myTableIndex->status = TEX_NEEDSBINDING;
2058  } else {
2059  myTableIndex->status = TEX_LOADING;
2060  send_texture_to_loader(myTableIndex);
2061  }
2062  break;
2063 
2064  case TEX_LOADING:
2065  case TEX_READ:
2066  DEBUG_TEX("I've to wait for %p...\n", myTableIndex);
2067  break;
2068 
2069  case TEX_NEEDSBINDING:
2070  DEBUG_TEX("texture loaded into memory... now lets load it into OpenGL...\n");
2071  move_texture_to_opengl(myTableIndex);
2072  break;
2073 
2074  case TEX_LOADED:
2075  //DEBUG_TEX("now binding to pre-bound tex %u\n", myTableIndex->OpenGLTexture);
2076 
2077  /* set the texture depth - required for Material diffuseColor selection */
2078  if (myTableIndex->hasAlpha) tg->RenderFuncs.last_texture_type = TEXTURE_ALPHA;
2079  else tg->RenderFuncs.last_texture_type = TEXTURE_NO_ALPHA;
2080 
2081 //printf ("last_texture_type = TEXTURE_NO_ALPHA now\n"); last_texture_type=TEXTURE_NO_ALPHA;
2082 
2083  if (myTableIndex->OpenGLTexture == TEXTURE_INVALID) {
2084 
2085  DEBUG_TEX("no openGLtexture here status %s\n", texst(myTableIndex->status));
2086  return;
2087  }
2088 
2089  tg->RenderFuncs.boundTextureStack[tg->RenderFuncs.textureStackTop] = myTableIndex->OpenGLTexture;
2090  //printf ("new_bind, boundTextureStack[%d] set to %d\n",tg->RenderFuncs.textureStackTop,myTableIndex->OpenGLTexture);
2091 
2092 
2093  /* save the texture params for when we go through the MultiTexture stack. Non
2094  MultiTextures should have this textureStackTop as 0 */
2095 
2096  if (param != NULL) {
2097  struct multiTexParams *textureParameterStack = (struct multiTexParams *) tg->RenderTextures.textureParameterStack;
2098  memcpy(&(textureParameterStack[tg->RenderFuncs.textureStackTop]), param,sizeof (struct multiTexParams));
2099  //memcpy(&(tg->RenderTextures.textureParameterStack[tg->RenderFuncs.textureStackTop]), param,sizeof (struct multiTexParams));
2100  }
2101  p->textureInProcess = -1; /* we have finished the whole process */
2102  break;
2103 
2104  case TEX_UNSQUASHED:
2105  default: {
2106  printf ("unknown texture status %d\n",myTableIndex->status);
2107  }
2108  }
2109  //#define DEBUG_TEX
2110 }
2111 
Definition: Vector.h:36