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