FreeWRL / FreeX3D 4.3.0
RenderTextures.c
1/*
2
3
4Texturing during Runtime
5texture enabling - works for single texture, for multitexture.
6
7*/
8
9
10/****************************************************************************
11 This file is part of the FreeWRL/FreeX3D Distribution.
12
13 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
14
15 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
16 it under the terms of the GNU Lesser Public License as published by
17 the Free Software Foundation, either version 3 of the License, or
18 (at your option) any later version.
19
20 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
27****************************************************************************/
28
29
30
31#include <config.h>
32#include <system.h>
33#include <display.h>
34#include <internal.h>
35
36#include <libFreeWRL.h>
37
38#include "../vrml_parser/Structs.h"
39#include "../main/headers.h"
40#include "../opengl/OpenGL_Utils.h"
41#include "../scenegraph/Component_Shape.h"
42#include "../scenegraph/RenderFuncs.h"
43#include "../scenegraph/LinearAlgebra.h"
44#include "../scenegraph/Polyrep.h"
45#include "Textures.h"
46#include "Material.h"
47
48
50int multitex_mode[2];
51int multitex_source[2];
52int multitex_function;
53};
54
55typedef struct pRenderTextures{
56 struct multiTexParams textureParameterStack[MAX_MULTITEXTURE];
57 int textureUnit_used;
58 GLint texture_in_unit[32];
59 GLint sampler_type[32];
60
61}* ppRenderTextures;
62
63void *RenderTextures_constructor(){
64 void *v = MALLOCV(sizeof(struct pRenderTextures));
65 memset(v,0,sizeof(struct pRenderTextures));
66 return v;
67}
68void RenderTextures_init(struct tRenderTextures *t){
69 t->prv = RenderTextures_constructor();
70 {
71 ppRenderTextures p = (ppRenderTextures)t->prv;
72 /* variables for keeping track of status */
73 t->textureParameterStack = (void *)p->textureParameterStack;
74 p->textureUnit_used = 0;
75 }
76}
77
78unsigned char* generate_checkerboard_texture_data_RGBA(int size8, int divisions8, int black255, int white255, int opacity255) {
79 int texSize = size8;
80 int checkerSize = texSize / divisions8;
81 unsigned char* texdata = malloc(texSize * texSize * 4);
82 //initialize to black transparent
83 memset(texdata, 0, texSize * texSize * 4);
84 unsigned char black[4];
85 unsigned char white[4];
86 unsigned char* pixel;
87 black[0] = black[1] = black[2] = black255; black[3] = opacity255;
88 white[0] = white[1] = white[2] = white255; white[3] = opacity255;
89 for (int i = 0; i < texSize; ++i) {
90 for (int j = 0; j < texSize; ++j) {
91 int ii = i / checkerSize;
92 int jj = j / checkerSize;
93 int evenii = (ii % 2) == 0;
94 int evenjj = (jj % 2) == 0;
95
96 int drawWhite = evenii == evenjj;
97 pixel = black;
98 if (drawWhite)
99 pixel = white;
100 int location = (i * texSize + j) * 4;
101 memcpy(&texdata[location], pixel, 4);
102 }
103 }
104 return texdata;
105}
106static GLuint checkerboard_texture2D = 0;
107static GLuint checkerboard_textureCube = 0;
108static unsigned char* checkerboard_data = NULL;
109static int checkerboard_size = 64;
110void compile_checkerboard_texture2D() {
111 if (checkerboard_texture2D < 1) {
112 PRINT_GL_ERROR_IF_ANY("compile_checkerboard_texture2D start");
113
114 int texSize = checkerboard_size;
115 int divisions = 8;
116 int black = 0;
117 int white = 255;
118 int opacity = 127;
119 unsigned char* texdata = generate_checkerboard_texture_data_RGBA(texSize, divisions, black, white, opacity);
120 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
121 glGenTextures(1, &checkerboard_texture2D);
122 glBindTexture(GL_TEXTURE_2D, checkerboard_texture2D);
123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
124 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
125 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
126 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
127
128 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texSize, texSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, texdata);
129 //free(texdata);
130 checkerboard_data = texdata;
131 PRINT_GL_ERROR_IF_ANY("compile_checkerboard_texture2D end");
132
133 }
134}
135void compile_checkerboard_textureCube() {
136 if (checkerboard_textureCube < 1) {
137 compile_checkerboard_texture2D();
138 PRINT_GL_ERROR_IF_ANY("compile_checkerboard_textureCube start");
139
140 glActiveTexture(GL_TEXTURE0);
141 PRINT_GL_ERROR_IF_ANY("compile_checkerboard_textureCube very early");
142 glGenTextures(1, &checkerboard_textureCube);
143 glBindTexture(GL_TEXTURE_CUBE_MAP, checkerboard_textureCube);
144 PRINT_GL_ERROR_IF_ANY("compile_checkerboard_textureCube early");
145 //glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_RGBA, checkerboard_size, checkerboard_size);
146 PRINT_GL_ERROR_IF_ANY("compile_checkerboard_textureCube middle");
147 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
148 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
149 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
150 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
151 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
152
153 //-allocates storage for all 6 faces
154 for (int face = 0; face < 6; face++) {
155 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+face, 0, GL_RGBA, checkerboard_size, checkerboard_size, 0, GL_RGBA, GL_UNSIGNED_BYTE, checkerboard_data);
156 //glTextureSubImage3D(GL_TEXTURE_2D_ARRAY, //face
157 // 0, //level
158 // 0, 0, //x,y offset
159 // face, //Z offset is the face
160 // checkerboard_size, checkerboard_size, //size of face
161 // 1, //one face at a time (depth)
162 // GL_RGBA, //format
163 // GL_UNSIGNED_BYTE, //type
164 // checkerboard_data); //Data if you have it)
165 PRINT_GL_ERROR_IF_ANY("compile_checkerboard_textureCube face");
166
167 }
168 PRINT_GL_ERROR_IF_ANY("compile_checkerboard_textureCube end");
169
170 }
171}
172//void render_checkerboard_default_texture() {
173// compile_checkerboard_texture2D();
174// //glActiveTexture(GL_TEXTURE0);
175// //glBindTexture(GL_TEXTURE_2D, checkerboard_texture);
176//}
177GLuint getCheckerboardTexture2D() {
178 compile_checkerboard_texture2D();
179 return checkerboard_texture2D;
180}
181GLuint getCheckerboardTextureCube() {
182 compile_checkerboard_textureCube();
183 return checkerboard_textureCube;
184}
185void clear_textureUnit_used(){
186 //call this in child_shape just before you start sending data / textures to the shader program
187 ppRenderTextures p;
188 ttglobal tg = gglobal();
189 p = (ppRenderTextures)tg->RenderTextures.prv;
190 //render_checkerboard_default_texture();
191 for (int i = 0; i < 16; i++) {
192 glBindTextureUnit(i, 0);
193 //glBindTextureUnit(i, checkerboard_texture2D);
194 //glBindTextureUnit(i, checkerboard_textureCube);
195 }
196 p->textureUnit_used = 0; //start at 1 and leave TEXTURE0 for debugging?
197}
198int next_textureUnit(){
199 ppRenderTextures p;
200 ttglobal tg = gglobal();
201 p = (ppRenderTextures)tg->RenderTextures.prv;
202 p->textureUnit_used++;
203 return p->textureUnit_used -1;
204}
205
206int textureUnit_used(){
207 ppRenderTextures p;
208 ttglobal tg = gglobal();
209 p = (ppRenderTextures)tg->RenderTextures.prv;
210 return p->textureUnit_used;
211}
212int bind_or_share_next_textureUnit(const int samplerType, GLint texture){
213 // call this when sending textures to the shader
214 // benefits over gl_activeTexture + glBindTexture:
215 // this one automatically
216 // a) checks if this texture is already bound, perhaps by another PTM projector, or another material
217 // and if so return the texture unit OR
218 // b) if not already bound, increments the texture unit, binds (and returns its texture unit index
219
220 ppRenderTextures p;
221 ttglobal tg = gglobal();
222 p = (ppRenderTextures)tg->RenderTextures.prv;
223
224 //check if sharable
225 int unit = -1;
226 for(int i=0;i<p->textureUnit_used;i++){
227 if(p->texture_in_unit[i] == texture && samplerType == p->sampler_type[i]){
228 unit = i;
229 break;
230 }
231 }
232 if(unit == -1) {
233 unit = next_textureUnit();
234 p->texture_in_unit[unit] = texture;
235 p->sampler_type[unit] = samplerType;
236 glBindTextureUnit(unit, 0); //clears all targets for a unit, gl 4.5 https://www.khronos.org/opengl/wiki/Sampler_(GLSL)
237 glActiveTexture(GL_TEXTURE0+unit);
238 glBindTexture(samplerType,texture);
239 }
240 return unit;
241}
242
243
244
245/* function params */
246//static void passedInGenTex(struct textureVertexInfo *genTex);
247
248/* which texture unit are we going to use? is this texture not OFF?? Should we set the
249 background coloUr??? Larry the Cucumber, help! */
250
251static int setActiveTexture (int c, GLint *texUnit, GLint *texMode)
252{
253 ppRenderTextures p;
254 ttglobal tg = gglobal();
255 p = (ppRenderTextures)tg->RenderTextures.prv;
256
257 /* which texture unit are we working on? */
258
259 /* tie each fw_TextureX uniform into the correct texture unit */
260
261 /* here we assign the texture unit to a specific number. NOTE: in the current code, this will ALWAYS
262 * be [0] = 0, [1] = 1; etc. */
263 texUnit[c] = c;
264
265#ifdef TEXVERBOSE
266 if (getAppearanceProperties()->currentShaderProperties != NULL) {
267 printf ("setActiveTexture %d, boundTextureStack is %d, sending to uniform %d\n",c,
268 tg->RenderFuncs.boundTextureStack[c],
269 getAppearanceProperties()->currentShaderProperties->TextureUnit[c]);
270 } else {
271 printf ("setActiveTexture %d, boundTextureStack is %d, sending to uniform [NULL--No Shader]\n",c,
272 tg->RenderFuncs.boundTextureStack[c]);
273 }
274#endif
275
276 /* is this a MultiTexture, or just a "normal" single texture? When we
277 * bind_image, we store a pointer for the texture parameters. It is
278 * NULL, possibly different for MultiTextures */
279
280 if (p->textureParameterStack[c].multitex_mode[0] == INT_ID_UNDEFINED) {
281
282 #ifdef TEXVERBOSE
283 printf ("setActiveTexture - simple texture NOT a MultiTexture \n");
284 #endif
285
286 /* should we set the coloUr to 1,1,1,1 so that the material does not show
287 * through a RGB texture?? */
288 /* only do for the first texture if MultiTexturing */
289 if (c == 0) {
290 #ifdef TEXVERBOSE
291 printf ("setActiveTexture - firsttexture \n");
292 #endif
293 texMode[c]= GL_MODULATE;
294 } else {
295 texMode[c]=GL_ADD;
296 }
297
298 } else {
299 /* printf ("muititex source for %d is %d\n",c,tg->RenderTextures.textureParameterStack[c].multitex_source); */
300 if (p->textureParameterStack[c].multitex_source[0] != MTMODE_OFF) {
301 } else {
302 //glDisable(GL_TEXTURE_2D); /* DISABLE_TEXTURES */
303 //return FALSE;
304 // we do OFF right in the shader
305 }
306 }
307
308
309 PRINT_GL_ERROR_IF_ANY("");
310
311 return TRUE;
312}
313
314
315/* lets disable texture transforms here */
316void textureTransform_end(void) {
317 int j;
318 ttglobal tg = gglobal();
319
320#ifdef TEXVERBOSE
321 printf ("start of textureTransform_end\n");
322#endif
323
324 /* DISABLE_TEXTURES */
325 /* setting this ENSURES that items, like the HUD, that are not within the normal
326 rendering path do not try and use textures... */
327 FW_GL_MATRIX_MODE(GL_TEXTURE);
328 int ntransforms;
329 fw_glGetInteger(GL_TEXTURE_STACK_DEPTH, &ntransforms);
330 //for(j=0;j<tg->RenderFuncs.textureStackTop;j++)
331 for (j = 0; j < ntransforms; j++)
332 FW_GL_POP_MATRIX(); //pushed in passedInGenTex
333
334 tg->RenderFuncs.textureStackTop = 0;
335 tg->RenderFuncs.texturenode = NULL;
336 FW_GL_MATRIX_MODE(GL_MODELVIEW);
337}
338
339/* did we have a TextureTransform in the Appearance node? */
340void do_textureTransform0 (struct X3D_Node *textureNode, int ttnum, char **tmap, int *igen, int *parameter_n, float *parameter) {
341 *tmap = NULL;
342 *igen = TCGT_REGULAR;
343 /* is this a simple TextureTransform? */
344 if (textureNode->_nodeType == NODE_TextureTransform) {
345 //ConsoleMessage ("do_textureTransform, node is indeed a NODE_TextureTransform");
346 struct X3D_TextureTransform* ttt = (struct X3D_TextureTransform*)textureNode;
347 *tmap = ttt->mapping ? ttt->mapping->strptr : NULL;
348 /* Render transformations according to spec.*/
349 //http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/texturing.html#TextureTransform
350 //specs say 'translate, rotate, then scale'
351 FW_GL_TRANSLATE_F(-((ttt->center).c[0]), -((ttt->center).c[1]), 0); /* 5*/
352 FW_GL_SCALE_F(((ttt->scale).c[0]), ((ttt->scale).c[1]), 1); /* 4*/
353 FW_GL_ROTATE_RADIANS(ttt->rotation, 0, 0, 1); /* 3*/
354 FW_GL_TRANSLATE_F(((ttt->center).c[0]), ((ttt->center).c[1]), 0); /* 2*/
355 FW_GL_TRANSLATE_F(((ttt->translation).c[0]), ((ttt->translation).c[1]), 0); /* 1*/
356 } else if (textureNode->_nodeType == NODE_TextureTransformGenerator) {
357 struct X3D_TextureTransformGenerator* ttg = (struct X3D_TextureTransformGenerator*)textureNode;
358 *tmap = ttg->mapping ? ttg->mapping->strptr : NULL;
359 *igen = findFieldInARR((ttg)->mode->strptr, TEXTURECOORDINATEGENERATOR, TEXTURECOORDINATEGENERATOR_COUNT);
360 //any matrix prep that would simplify GPU / vertex shader side?
361 //any clock-time animations?
362 //any routed parameter[] updates?
363 } else if (textureNode->_nodeType == NODE_MultiTextureTransform) {
364 /* is this a MultiTextureTransform? */
365 struct X3D_MultiTextureTransform *mtt = (struct X3D_MultiTextureTransform *) textureNode;
366 if (ttnum < mtt->textureTransform.n) {
367 struct X3D_TextureTransform *ttt = (struct X3D_TextureTransform *) mtt->textureTransform.p[ttnum];
368 /* is this a simple TextureTransform? */
369 if (ttt->_nodeType == NODE_TextureTransform) {
370 *tmap = ttt->mapping ? ttt->mapping->strptr : NULL;
371
372 /* Render transformations according to spec.*/
373 FW_GL_TRANSLATE_F(-((ttt->center).c[0]), -((ttt->center).c[1]), 0); /* 5*/
374 FW_GL_SCALE_F(((ttt->scale).c[0]), ((ttt->scale).c[1]), 1); /* 4*/
375 FW_GL_ROTATE_RADIANS(ttt->rotation, 0, 0, 1); /* 3*/
376 FW_GL_TRANSLATE_F(((ttt->center).c[0]), ((ttt->center).c[1]), 0); /* 2*/
377 FW_GL_TRANSLATE_F(((ttt->translation).c[0]), ((ttt->translation).c[1]), 0); /* 1*/
378 } else if(ttt->_nodeType == NODE_TextureTransformGenerator){
380 *tmap = ttg->mapping ? ttg->mapping->strptr : NULL;
381 *igen = findFieldInARR((ttg)->mode->strptr, TEXTURECOORDINATEGENERATOR, TEXTURECOORDINATEGENERATOR_COUNT);
382
383 *parameter_n = ttg->parameter.n;
384 memcpy(parameter, ttg->parameter.p, ttg->parameter.n * sizeof(float));
385 //any matrix prep that would simplify GPU / vertex shader side?
386 //any clock-time animations?
387 //any routed parameter[] updates?
388 } else {
389 static int once = 0;
390 if(!once){
391 printf ("MultiTextureTransform expected a textureTransform for texture %d, got %d %s \n",
392 ttnum, ttt->_nodeType, stringNodeType(ttt->_nodeType));
393 once = 1;
394 }
395 }
396 } else {
397 static int once = 0;
398 if(!once){
399 printf ("not enough transforms in MultiTextureTransform -will fill with Identity matrix\n");
400 once = 1;
401 }
402 }
403 } else if (textureNode->_nodeType == NODE_TextureTransform3D) {
404 //ConsoleMessage ("do_textureTransform, node is indeed a NODE_TextureTransform");
405 struct X3D_TextureTransform3D *ttt = (struct X3D_TextureTransform3D *) textureNode;
406 *tmap = ttt->mapping ? ttt->mapping->strptr : NULL;
407
408 /* Render transformations according to spec.*/
409 FW_GL_TRANSLATE_F(-((ttt->center).c[0]),-((ttt->center).c[1]), -((ttt->center).c[2])); /* 5*/
410 FW_GL_SCALE_F(((ttt->scale).c[0]),((ttt->scale).c[1]),((ttt->scale).c[2])); /* 4*/
411 FW_GL_ROTATE_RADIANS(ttt->rotation.c[3], ttt->rotation.c[0],ttt->rotation.c[1],ttt->rotation.c[2]);
412 FW_GL_TRANSLATE_F(((ttt->center).c[0]),((ttt->center).c[1]), ((ttt->center).c[2])); /* 2*/
413 FW_GL_TRANSLATE_F(((ttt->translation).c[0]), ((ttt->translation).c[1]), ((ttt->translation).c[2])); /* 1*/
414 } else if (textureNode->_nodeType == NODE_TextureTransformMatrix3D) {
415 //ConsoleMessage ("do_textureTransform, node is indeed a NODE_TextureTransform");
416 int i;
417 double mat[16];
418 struct X3D_TextureTransformMatrix3D *ttt = (struct X3D_TextureTransformMatrix3D *) textureNode;
419 *tmap = ttt->mapping ? ttt->mapping->strptr : NULL;
420
421 for(i=0;i<16;i++)
422 mat[i] = (double)ttt->matrix.c[i];
423 FW_GL_SETDOUBLEV(GL_TEXTURE_MATRIX,mat);
424 } else {
425 static int once = 0;
426 if(!once){
427 printf ("expected a textureTransform node, got %d %s\n",textureNode->_nodeType, stringNodeType(textureNode->_nodeType));
428 once = 1;
429 }
430 }
431
432 //FW_GL_MATRIX_MODE(GL_MODELVIEW);
433}
434//void do_textureTransform(struct X3D_Node* textureNode, int ttnum) {
435// char *tmap;
436// do_textureTransform0(textureNode, ttnum, &tmap);
437//}
438/***********************************************************************************/
439int isMultiTexture(struct X3D_Node *node){
440 int ret = FALSE;
441 if(node && node->_nodeType == NODE_MultiTexture)
442 ret = TRUE;
443 return ret;
444}
445int isTex3D(struct X3D_Node *node);
446
447
448int is_cubeMap(struct X3D_Node* node) {
449 int iret = FALSE;
450 if (node) {
451 switch (node->_nodeType) {
452 case NODE_ComposedCubeMapTexture:
453 case NODE_ImageCubeMapTexture:
454 case NODE_GeneratedCubeMapTexture:
455 iret = TRUE;
456 break;
457 }
458 }
459 return iret;
460}
461int is_or_has_cubeMap(struct X3D_Node* node) {
462 int ret = FALSE;
463 if (!node) return ret;
464 struct X3D_Node** p;
465 p = &node;
466 int n = 1;
467 if (node->_nodeType == NODE_MultiTexture) {
468 struct X3D_MultiTexture* mnode = (struct X3D_MultiTexture*)node;
469 p = mnode->texture.p;
470 n = mnode->texture.n;
471 }
472 for (int i = 0; i < n; i++) {
473 switch (p[i]->_nodeType) {
474 case NODE_ComposedCubeMapTexture:
475 case NODE_ImageCubeMapTexture:
476 case NODE_GeneratedCubeMapTexture:
477 ret = TRUE;
478 break;
479 default:
480 break;
481 }
482 }
483 return ret;
484}
485int is_or_has_Tex3D(struct X3D_Node* node);
486char* trans_name_from_texture_mapping(char* mmap, char* scratch) {
487 char* aret = NULL;
488 if (mmap) {
489 aret = scratch;
490 memset(scratch, 0, 10);
491 //advanced way - look for "C0T2" style string from gltf_loader and split, else just copy
492 if (mmap[0] == 'T') scratch[0] = mmap[1];
493 else if (mmap[2] == 'T') scratch[0] = mmap[3];
494 else strcpy(scratch, mmap);
495 }
496 return aret;
497}
498char* coord_name_from_texture_mapping(char* mmap, char* scratch) {
499 char* aret = NULL;
500 if (mmap) {
501 aret = scratch;
502 memset(scratch, 0, 10);
503 //advanced way - look for "C0T2" style string from gltf_loader and split, else just copy
504 if (mmap[0] == 'C') scratch[0] = mmap[1];
505 else if (mmap[2] == 'C') scratch[0] = mmap[3];
506 else strcpy(scratch, mmap);
507 }
508 return aret;
509}
510int find_in_char_list(char *name, char** list, int n) {
511 int iret = -1;
512 if(list && n && name)
513 for(int i=0;i<n;i++)
514 if (strcmp(name, list[i]) == 0) {
515 iret = i;
516 break;
517 }
518 return iret;
519}
520// https://stackoverflow.com/questions/3911400/how-to-pass-2d-array-matrix-in-a-function-in-c
521int find_or_make_combo_by_index(int itrans, int icoord, int combo_list[][2], int* ncombo) {
522 int found = 0;
523 int iret = -1;
524 for (int i = 0; i < *ncombo; i++) {
525 // Q. in freewrl does icoord == -1 mean the same as icoord == 0, both refer to first texcoord?
526 if (combo_list[i][0] == icoord && combo_list[i][1] == itrans) {
527 found = TRUE;
528 iret = i;
529 break;
530 }
531 }
532 if (!found) {
533 iret = (*ncombo);
534 combo_list[iret][0] = icoord;
535 combo_list[iret][1] = itrans;
536 (*ncombo)++;
537 }
538 return iret; //this will be the index into frag shader fw_TexCoord[iret] for a given texture.
539
540}
541int find_or_make_combo(char* trans_name, char* coord_name, char** coord_name_list, int ntcoord,
542 char** trans_name_list, int ntrans, int combo_list[][2], int* ncombo) {
543 int itrans = find_in_char_list(trans_name, trans_name_list, ntrans);
544 int icoord = find_in_char_list(coord_name, coord_name_list, ntcoord);
545 int iret = find_or_make_combo_by_index(itrans, icoord, combo_list, ncombo);
546 //int found = 0;
547 //int iret = -1;
548 //for (int i = 0; i < *ncombo; i++) {
549 // // Q. in freewrl does icoord == -1 mean the same as icoord == 0, both refer to first texcoord?
550 // if (combo_list[i][0] == icoord && combo_list[i][1] == itrans) {
551 // found = TRUE;
552 // iret = i;
553 // break;
554 // }
555 //}
556 //if (!found) {
557 // iret = (*ncombo);
558 // combo_list[iret][0] = icoord;
559 // combo_list[iret][1] = itrans;
560 // (* ncombo)++;
561 //}
562 return iret; //this will be the index into frag shader fw_TexCoord[iret] for a given texture.
563}
564int next_or_last_sampler_compatible_trans(int lasttrans, int ntrans, int jsamplr, int* igen) {
565 int itrans = -1;
566 //find the prior compatible if any
567 for (int i = 0; i < lasttrans + 1; i++){
568 if (jsamplr == 0 && igen[i] == TCGT_REGULAR) itrans = i;
569 if (jsamplr == 2 && igen[i] == TCGT_REGULAR) itrans = i;
570 if (jsamplr == 1 && igen[i] != TCGT_REGULAR) itrans = i;
571 }
572 //over-ride with the next compatible if any
573 for (int i = lasttrans + 1; i < ntrans; i++) {
574 if (jsamplr == 1 && igen[i] != TCGT_REGULAR) {
575 itrans = i;
576 break;
577 }
578 if (jsamplr == 0 && igen[i] == TCGT_REGULAR) {
579 itrans = i;
580 break;
581 }
582 if (jsamplr == 2 && igen[i] == TCGT_REGULAR) {
583 itrans = i;
584 break;
585 }
586 }
587 return itrans;
588}
589
590
591int getTextureDescriptors(struct X3D_Node* textureNode, int* textures, int* modes, int* sources, int* funcs, int* width, int* height, int* samplr);
592GLint tunit(int index);
593void textureTransform_start() {
594 int c;
595 int i, isStrict, isMulti, isIdentity, ntransforms[2];
596 GLint texUnit[MAX_MULTITEXTURE];
597 //GLint tunit[MAX_MULTITEXTURE];
598 GLint texMode[MAX_MULTITEXTURE];
599 s_shader_capabilities_t* me;
600 struct X3D_Node* tnode;
601 int itmap[MAX_MULTITEXTURE];
602 int igen[MAX_MULTITEXTURE];
603
604 int parameter_n;
605 float parameter[7];
606
607 int icombo[MAX_MULTITEXTURE + 2][2];
608 int immap[MAX_MULTITEXTURE];
609
610 int ncombo;
611 char* tmap[MAX_MULTITEXTURE];
612 ppRenderTextures p;
613 ttglobal tg = gglobal();
614 p = (ppRenderTextures)tg->RenderTextures.prv;
615 tnode = tg->RenderFuncs.texturenode;
616
617 me = getAppearanceProperties()->currentShaderProperties;
618
619 //PRINT_GL_ERROR_IF_ANY("TT_start_start");
620
621#ifdef TEXVERBOSE
622 printf("passedInGenTex, using passed in genTex, textureStackTop %d\n", tg->RenderFuncs.textureStackTop);
623 printf("passedInGenTex, cubeFace %d\n", getAppearanceProperties()->cubeFace);
624#endif
625 int oldway = 0;
626 FW_GL_MATRIX_MODE(GL_TEXTURE);
627 if (oldway) for (int i = 0; i < MAX_MULTITEXTURE; i++) immap[i] = 0;
628 for (int i = 0; i < MAX_MULTITEXTURE + 2; i++) {
629 icombo[i][0] = icombo[i][1] = -1; //[0] index of texcoord ie 0 = TEXCOORD_0, -1 means 0, [1] index of textrans, -1 means idenity
630 }
631 ncombo = 1; // de-minimus for shapeless things
632
633 parameter_n = 0;
634 //printf ("passedInGenTex, B\n");
635 isStrict = 1; //web3d specs say if its a multitexture,
636 //and you give it a single textureTransform instead of multitexturetransform
637 //it should ignore the singleTextureTransform and use identities.
638 //strict: This is a change of functionality for freewrl Aug 31, 2016
639
640 if (!tg->RenderFuncs.shapenode) {
641 //May 1 2022 annoying Background comes through here - please fix
642 //we still use ubershader on background textures, send de-minimus uniforms to vertex shader
643 glUniform1i(me->cmap[0], icombo[0][0]);
644 glUniform1i(me->tmap[0], icombo[0][1]);
645 glUniform1i(me->ntexcombo, ncombo);
646 }
647 else
648 {
649 // April 29, 2022: cases not handled: .mapping to 2 textrans, but only one texcoord or vice versa
650 // khronos gltf GreenChair has one texcoord, and multiple textrans
651 // https://github.com/KhronosGroup/3DC-Certification/tree/main/models
652 // https://github.khronos.org/3DC-Sample-Viewer/
653 // tests\multitexture\multimap_material_2trans_1coord.x3dv
654 // May 2, 2022 change of concept of operations
655 // vertex shader produces out fw_TexCoord[4] from combinations of input texcoord and textrans
656 // frag shader / material.texture needs to know which combination, by index, for use in sample_map()
657 // here we prepare combinations, up to one for each texture, from given and default textrans and texcoords
658 // we store the combo index in the material.texture.cmap,
659 // and send vertex shader 2 values for each combo: index to texcoord or -1, index to textran or -1
660 // -1 means default: for texcoord that's texcoord[0], for textrans that's identity
661 // benefit over old concept: frag fw_TexCoord[] length and index is decoupled from geometry.texcoord[] order, length and index
662 // allowing more combinations of textrans and texcoords
663 struct matpropstruct* matprop;
664 struct X3D_Node* gn = NULL;
665 int ntcoord = 0;
666 char** ccmap = NULL;
667 struct X3D_Shape* sn = (struct X3D_Shape*)tg->RenderFuncs.shapenode;
668 POSSIBLE_PROTO_EXPANSION(struct X3D_Node*, sn->geometry, gn);
669
670 //step 1 get all the texcoords from geometry, and their ccmap names, and ntcoord count
671 ntcoord = 1;
672 if (gn && gn->_intern) {
673 struct X3D_GeomRep* gr = (struct X3D_GeomRep*)gn->_intern;
674 if (gr->itype == 2) {
675 struct X3D_PolyRep* prep = (struct X3D_PolyRep*)gn->_intern;
676 ccmap = prep->map;
677 ntcoord = prep->ntcoord;
678 //for (int i = 0; i < 4; i++)
679 // printf("gn.map[%d]=%p\n", i, (prep->map[i]);
680 }
681 else if (gr->itype == 3) {
682 // gltf_loader puts geometry in BufferGeometry._intern = MeshRep
683 struct X3D_MeshRep* mrep = (struct X3D_MeshRep*)gn->_intern;
684 ntcoord = mrep->nuv;
685 static char* mrallmap[] = { "0","1","2","3" }; //gltf_loader uses texcoord index as map string
686 static char* nullmap[4] = { NULL,NULL,NULL,NULL };
687 static char* usemap[4];
688 memcpy(usemap, nullmap, 4 * sizeof(char*));
689 ccmap = usemap;
690 for (int i = 0; i < ntcoord; i++)
691 ccmap[i] = mrallmap[i];
692 }
693 }
694 //if(ccmap) for (int i = 0; i < 4; i++)
695 // printf("ccmap[%d]=%p\n", i, ccmap[i]);
696
697 //step 2 get all the textrans, and their tmap names and ntrans count
698 matprop = getAppearanceProperties();
699 //unconditionally load any supplied texture transforms
700 for (int i = 0; i < MAX_MULTITEXTURE; i++) {
701 tmap[i] = NULL;
702 igen[i] = TCGT_REGULAR;
703 }
704 struct X3D_Node* tt = getThis_textureTransform();
705 int ntrans = 0;
706 int ntrans_specified = 0;
707 if (tt != NULL) {
708 switch (tt->_nodeType) {
709 case NODE_TextureTransform:
710 case NODE_TextureTransform3D:
711 case NODE_TextureTransformMatrix3D:
712 case NODE_TextureTransformGenerator:
713 ntrans = 1;
714 break;
715 case NODE_MultiTextureTransform:
716 ntrans = ((struct X3D_MultiTextureTransform*)(tt))->textureTransform.n;
717 break;
718 default:
719 ntrans = 0;
720 }
721 for (int i = 0; i < ntrans; i++) {
722 FW_GL_PUSH_MATRIX(); //POPPED in textureTransform_end
723 FW_GL_LOAD_IDENTITY();
724 do_textureTransform0(tt, i, &tmap[i], &igen[i], & parameter_n, parameter);
725
726 }
727 }
728 ntrans_specified = ntrans;
729 int ngen = 0;
730 for (int ig = 0; ig < ntrans; ig++) if (igen[ig] != TCGT_REGULAR) ngen++;
731 //printf("ntrans %d ngen %d is_or_has_cubemap %d\n", ntrans, ngen, is_or_has_cubeMap(tnode));
732 if (is_or_has_cubeMap(tnode) && !ngen) {
733 FW_GL_PUSH_MATRIX(); //POPPED in textureTransform_end
734 FW_GL_LOAD_IDENTITY();
735 igen[ntrans] = TCGT_CAMERASPACEREFLECTIONVECTOR;
736 ntrans++;
737 //printf("adding igen for cubemap \n");
738 }
739 //add any computed 3D texture matrices
740 if (is_or_has_Tex3D(tnode) && !ngen) {
741 if (tg->RenderFuncs.shapenode) {
742 //_if_ no TextureTransform3D was explicitly specified for Texture3D,
743 //_and_ no textureCoordinate3D or textureCoordinate4D was explicilty specified with the goem node
744 //_then_ bounding box of shape, in local coordinates, is used to scale/translate
745 //geometry vertices into 0-1 range on each axis for re-use as default texture3D coordinates
746 float bbox[6], * bmin, * bmax;
747 if (gn) {
748 //first vec3 is minimum xyz
749 bmin = bbox;
750 bmax = &bbox[3];
751 for (i = 0; i < 3; i++) {
752 bmin[i] = gn->_extent[i * 2 + 1];
753 bmax[i] = gn->_extent[i * 2];
754 }
755 //second vec3 is 1/size - so can be applied directly in vertex shader
756 vecdif3f(bmax, bmax, bmin);
757 for (i = 0; i < 3; i++) {
758 if (bmax[i] != 0.0f)
759 bmax[i] = 1.0f / bmax[i];
760 else
761 bmax[i] = 1.0f;
762 }
763 //if(fabs(bmin[0]) > 10.0f)
764 // printf("bbox shift [%f %f %f] scale [%f %f %f]\n",bmin[0],bmin[1],bmin[2],bmax[0],bmax[1],bmax[2]);
765
766 //special default texture transform for 3D textures posing as 2D textures
767
768 //the order of applying transform elements seems reversed for texture transforms
769 //H: related to order of operands in mat * vec in shader:
770 // fw_TexCoord[0] = vec3(fw_TextureMatrix0 *vec4(texcoord,1.0));
771 // but sign on elements is what you expect
772 //flip z from RHS to LHS in fragment shader plug_tex3d apply
773 //printf("default tt\n");
774 FW_GL_PUSH_MATRIX(); //POPPED in textureTransform_end
775 FW_GL_LOAD_IDENTITY();
776 igen[ntrans] = TCGT_REGULAR;
777 ntrans++;
778 FW_GL_SCALE_F(bmax[0], bmax[1], bmax[2]);
779 FW_GL_TRANSLATE_F(-bmin[0], -bmin[1], -bmin[2]);
780 }
781 }
782 }
783 glUniform1i(me->nTexMatrix, ntrans); //see also sendMatricesToShader and FW_GL_MATRIX_MODE(GL_TEXTURE); above
784 for (int ig = 0; ig < MAX_MULTITEXTURE; ig++)
785 glUniform1i(me->tgen[ig], igen[ig]);
786 // ideally parameters would be 1:1 with texture stage / single texture. For now, allow one stage of multitexture to have refraction parameters.
787
788 glUniform1i(me->parameter_n, parameter_n);
789 for (int ig = 0; ig < parameter_n; ig++)
790 glUniform1f(me->parameter[ig], parameter[ig]);
791 //Step 3 go over appearance and/or material textures, and generate up to 1 combo (texcoord,textrans) for each
792 //pair appearance.textures with texture coordinates
793 int ntextures = tg->RenderFuncs.textureStackTop;
794 // defaults for appearance.multitexture:
795 ncombo = 0;
796 if (tnode && X3D_APPEARANCE(sn->appearance)->texture == tnode) {
797 //texture is coming from appearance.texture
798 if (0) {
799 for (int i = 0; i < tg->RenderFuncs.textureStackTop; i++) {
800 int itrans = min(i, ntrans - 1);
801 int icoord = min(i, ntcoord - 1);
802 int jcombo = find_or_make_combo_by_index(itrans, icoord, &icombo[0], &ncombo);
803 matprop->fw_FrontMaterial.cmap[i] = jcombo;
804 }
805 }
806 else {
807 struct X3D_Node** p;
808 int n = 1;
809 p = &tnode;
810 if (tnode->_nodeType == NODE_MultiTexture) {
811 struct X3D_MultiTexture* mnode = (struct X3D_MultiTexture*)tnode;
812 p = mnode->texture.p;
813 n = mnode->texture.n;
814 }
815 int lasttrans = -1;
816 for (int i = 0; i < n; i++) {
817 int jsamplr = is_cubeMap(p[i]) ? 1 : isTex3D(p[i]) ? 2 : 0;
818 int itrans = i > ntrans_specified - 1 ? -1 : i; // min(i, ntrans - 1);
819 if (itrans == -1) {
820 itrans = next_or_last_sampler_compatible_trans(lasttrans, ntrans, jsamplr, igen);
821 }
822 lasttrans = itrans;
823 int icoord = min(i, ntcoord - 1); //next_or_last_sampler_compatible_coord(icoord, ntcoord, jsamplr);
824 int jcombo = find_or_make_combo_by_index(itrans, icoord, &icombo[0], &ncombo);
825 matprop->fw_FrontMaterial.cmap[i] = jcombo;
826 }
827 }
828 }
829 else {
830 // by TextureCoordinate.mapping and material.xxxTextureMapping if they exist
831 char** mmapf = matprop->fw_FrontMaterial.map;
832 char** mmapb = matprop->fw_BackMaterial.map;
833 for (int i = 0; i < 7; i++) {
834 char scratch1[20], scratch2[20];
835 char* trans_name;
836 char* coord_name;
837 int jcombo;
838 // front material
839 if (mmapf && mmapf[i]) {
840 trans_name = trans_name_from_texture_mapping(mmapf[i], scratch1);
841 coord_name = coord_name_from_texture_mapping(mmapf[i], scratch2);
842 jcombo = find_or_make_combo(trans_name, coord_name, ccmap, ntcoord,
843 tmap, ntrans, &icombo[0], &ncombo);
844 matprop->fw_FrontMaterial.cmap[i] = jcombo;
845 }
846 //back material
847 if (mmapb && mmapb[i]) {
848 trans_name = trans_name_from_texture_mapping(mmapb[i], scratch1);
849 coord_name = coord_name_from_texture_mapping(mmapb[i], scratch2);
850 jcombo = find_or_make_combo(trans_name, coord_name, ccmap, ntcoord,
851 tmap, ntrans, icombo, &ncombo);
852 matprop->fw_BackMaterial.cmap[i] = jcombo;
853 }
854 }
855 }
856 for (int i = 0; i < ncombo; i++) {
857 //printf("icmap[%d] = %d uniform %d\n", i, icombo[i][0], me->cmap[i]);
858 //printf("itmap[%d] = %d uniform %d\n", i, icombo[i][1], me->tmap[i]);
859 glUniform1i(me->cmap[i], icombo[i][0]);
860 glUniform1i(me->tmap[i], icombo[i][1]);
861 }
862 glUniform1i(me->ntexcombo, ncombo);
863 //printf("ncombo=%d\n", ncombo);
864
865 }
866
867 /* set up the selected shader for this texture(s) config */
868 //PRINT_GL_ERROR_IF_ANY("TT_start_middle");
869
870 if (me != NULL) {
871 tnode = tg->RenderFuncs.texturenode;
872 //printf ("passedInGenTex, we have tts %d tc %d\n",tg->RenderFuncs.textureStackTop, me->textureCount);
873
874 if (me->textureCount != -1) {
875 glUniform1i(me->textureCount, tg->RenderFuncs.textureStackTop);
876 }
877 if(tg->RenderFuncs.textureStackTop){
878 if(isMultiTexture(tnode)){
879 struct X3D_MultiTexture * mtnode = (struct X3D_MultiTexture *)tnode;
880 glUniform4f(me->multitextureColor,mtnode->color.c[0],mtnode->color.c[1],mtnode->color.c[2],mtnode->alpha);
881 }
882 if (isTex3D(tnode)) {
883 textureTableIndexStruct_s* tti;
884 tti = getTableTableFromTextureNode(tg->RenderFuncs.texturenode);
885 if (tti && tti->status >= TEX_LOADED) {
886 GLint ttiles, tex3dUseVertex, repeatSTR, magFilter;
887 //ttiles = GET_UNIFORM(myProg, "tex3dTiles");
888 GLUNIFORM1IV(me->tex3dTiles, 3, tti->tiles);
889
890 //me->tex3dUseVertex = GET_UNIFORM(myProg,"tex3dUseVertex");
891 glUniform1i(me->tex3dUseVertex, 1);
892 //repeatSTR = GET_UNIFORM(myProg, "repeatSTR");
893 glUniform1iv(me->repeatSTR, 3, tti->repeatSTR);
894 //magFilter = GET_UNIFORM(myProg, "magFilter");
895 glUniform1i(me->magFilter, tti->magFilter);
896 }
897 }
898 }
899 if (tg->RenderFuncs.textureStackTop) {
900 //June 2022 new approach: cubemaps are textures and should be treated as such
901 {
902 struct matpropstruct* myap = getAppearanceProperties();
903 struct fw_MaterialParameters* mp;
904
905 int textures[4], modes[4], sources[4], funcs[4], width[4], height[4], samplr[4];
906 GLint saveTextureStackTop = tg->RenderFuncs.textureStackTop;
907 int ntdesc = getTextureDescriptors(tnode, textures, modes, sources, funcs, width, height,samplr);
908 // https://www.web3d.org/documents/specifications/19775-1/V4.0/Part01/components/shape.html#CoexistenceMaterialTexturesWithAppearanceTexture
909 // material.maps: iuse [0] normal [1] emissive [2] occlusion [3] diffuse OR base [4] shininess OR metallicRoughness [5] specular [6] ambient
910 //material.type: 0 NONE 1 UNLIT 2 DEFUSE/SPECULAR 3 PHYSICAL/PBR
911 mp = &myap->fw_FrontMaterial;
912 int iuse = 3; // MAT_REGULAR;
913 if (mp->type < 2) iuse = 1; //if none or UnlitMaterial, put appearance textures in emissive iuse
914 else if (mp->type == 2) iuse = 3; // if diffuse/specular Material put appearance textures in diffuse iuse
915 else if (mp->type == 3) iuse = 3; // if PhysicalMaterial (PBR) put appearance textures in base iuse
916 int nt = mp->nt; //assume appearance.texture has fwFrontMaterial all to itself, no material.texture to coordinte with
917 mp->tcount[iuse] += ntdesc;
918 mp->tstart[iuse] = nt;
919 //mp->cindex[iuse] = 0; //appearance.texture - cindex (coordinate index) 1:1 singletexture m:1 multitexture
920 // // material.texture - cindex 1:1 xxxTexture 1:1 xxxTexture.multitexture 1:m multitexture.singletexture
921 for (int j = 0; j < ntdesc; j++) {
922 int kunit, iunit;
923 kunit = iunit = 0;
924 mp->samplr[nt] = samplr[j];
925 if (mp->samplr[nt] == 1) {
926 if (0) {
927 GLenum target;
928 printf("%s ", stringNodeType(tnode->_nodeType));
929 glGetTextureParameteriv(textures[j], GL_TEXTURE_TARGET, (GLint*)&target);
930 switch (target) {
931 case GL_TEXTURE_CUBE_MAP: printf("CUBE MAP \n"); break;
932 case GL_TEXTURE_2D: printf("texture2D\n"); break;
933 case GL_TEXTURE_3D: printf("texture3D\n"); break;
934 case GL_TEXTURE_2D_ARRAY: printf("GL_TEXTURE_2D_ARRAY\n");
935 default: printf("unknown %d \n",target); break;
936 }
937 }
938 PRINT_GL_ERROR_IF_ANY("TT_start_ bfor bind cube");
939
940 kunit = share_or_next_material_sampler_index_Cube(textures[j]);//returns index into shader samplerCube texterUnitCube[kunit]
941 //kunit = share_or_next_material_sampler_index_Cube(getCheckerboardTextureCube());//returns index into shader samplerCube texterUnitCube[kunit]
942 PRINT_GL_ERROR_IF_ANY("TT_start_ aftr bind cube");
943 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
944 PRINT_GL_ERROR_IF_ANY("TT_start_ aftr seamless");
945
946 }
947 else {
948 kunit = share_or_next_material_sampler_index_2D(textures[j]);//returns index into shader sampler2D texterUnit[kunit]
949 }
950 mp->tindex[nt] = kunit;
951 mp->source[nt] = sources[j];
952 mp->mode[nt] = modes[j];
953 mp->func[nt] = funcs[j];
954 //if(oldway)
955 // mp->cmap[nt] = immap[j];
956 //mp->cmap[nt] = icombo[j][0]; // immap[j]; //assigned above? or is this different?
957 glUniform1i(me->myMaterialCmap[nt], mp->cmap[nt]); //would be mp->cmap[iuse] in material?
958 if (mp->samplr[nt] == 1) {
959 iunit = tunitCube(kunit);//returns i as in GL_TEXTUREi, to be stored in samplerCube textureUnitCube[kunit]
960 glUniform1i(me->textureUnitCube[kunit], iunit);
961 }
962 else {
963 iunit = tunit2D(kunit);//returns i as in GL_TEXTUREi, to be stored in sampler2D textureUnit[kunit]
964 glUniform1i(me->textureUnit[kunit], iunit);
965 }
966 mp->binding[nt] = iunit; //for debugging around here (already sent to shader)
967 //printf("textureUnit(Cube)[%d]=%d ogl %d samplr %d\n", kunit, iunit,textures[j], samplr[j]);
968
969 glUniform1i(me->myMaterialTindex[nt], mp->tindex[nt]);
970 glUniform1i(me->myMaterialMode[nt], mp->mode[nt]);
971 glUniform1i(me->myMaterialSource[nt], mp->source[nt]);
972 glUniform1i(me->myMaterialFunc[nt], mp->func[nt]);
973 glUniform1i(me->myMaterialSampler[nt], mp->samplr[nt]);
974 nt++;
975 }
976 mp->nt = nt;
977 //something about the multitexture..
978 //printf("sampler type samplr[%d]=%d start[%d]=%d ", iuse, mp->samplr[iuse], iuse, mp->tstart[iuse]); //samplr 0=2D 1=cube
979 //something about the first sub-texture in the multitexture..
980 //printf("textureUnit(Cube)[%d]=%d\n", mp->tindex[mp->tstart[iuse]], mp->binding[mp->tstart[iuse]] );
981 //GLUNIFORM1I(me->myMaterialCindex[iuse], mp->cindex[iuse]);
982 GLUNIFORM1I(me->myMaterialTcount[iuse], mp->tcount[iuse]);
983 GLUNIFORM1I(me->myMaterialTstart[iuse], mp->tstart[iuse]);
984
985 tg->RenderFuncs.textureStackTop = saveTextureStackTop; //keep this frmo building up
986 }
987 }
988 #ifdef TEXVERBOSE
989 } else {
990 printf (" NOT sending in %d i+tu+mode because currentShaderProperties is NULL\n",tg->RenderFuncs.textureStackTop);
991 #endif
992 }
993
994 FW_GL_MATRIX_MODE(GL_MODELVIEW);
995
996 PRINT_GL_ERROR_IF_ANY("TT_start_finish");
997}
998
999void textureCoord_send(struct textureVertexInfo *genTex) {
1000 // Oct 2016 refactoring before particleSystem
1001 // moved texturetransform stuff out of here and into (below) textureTransform_start()
1002 int c;
1003 //int isIdentity; //isMulti, isStrict,i,
1004 //GLint texUnit[MAX_MULTITEXTURE];
1005 //GLint texMode[MAX_MULTITEXTURE];
1006 s_shader_capabilities_t *me;
1007 struct textureVertexInfo *genTexPtr;
1008 // OLDCODE struct X3D_Node *tnode;
1009
1010 // OLDCODE ppRenderTextures p;
1011 ttglobal tg = gglobal();
1012 // OLDCODE p = (ppRenderTextures)tg->RenderTextures.prv;
1013 // OLDCODE tnode = tg->RenderFuncs.texturenode;
1014
1015 me = getAppearanceProperties()->currentShaderProperties;
1016
1017 genTexPtr = genTex;
1018 //for (c=0; c < tg->RenderFuncs.textureStackTop; c++) {
1019 c = 0;
1020 while(genTexPtr){ //PBR: send all you got and say how many (channels)
1021 if(genTexPtr->VBO)
1022 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER,genTexPtr->VBO);
1023
1024 if (genTexPtr->pre_canned_textureCoords != NULL) {
1025 /* simple shapes, like Boxes and Cones and Spheres will have pre-canned arrays */
1026 FW_GL_TEXCOORD_POINTER (2,GL_FLOAT,0,genTexPtr->pre_canned_textureCoords,c);
1027 }else{
1028 FW_GL_TEXCOORD_POINTER (genTexPtr->TC_size,
1029 genTexPtr->TC_type,
1030 genTexPtr->TC_stride,
1031 genTexPtr->TC_pointer,c);
1032 }
1033 //genTexPtr = genTexPtr->next ? genTexPtr->next : genTexPtr; //duplicate the prior coords if not enough for all MultiTextures
1034 genTexPtr = genTexPtr->next; //PBR: send all you got, and say how many (channels)
1035 c++;
1036 }
1037 glUniform1i(me->nTexCoordChannels,c); //PBR: send all you got, and say how many (channels)
1038 //printf("nTexCoordChannels = %d uniform= %d\n", c, me->nTexCoordChannels);
1039 glUniform1i(me->flipuv, 0);
1040}