FreeWRL / FreeX3D 4.3.0
Component_Shape.c
1/*
2
3
4X3D Shape Component
5
6*/
7
8
9/****************************************************************************
10 This file is part of the FreeWRL/FreeX3D Distribution.
11
12 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
13
14 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
15 it under the terms of the GNU Lesser Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
26****************************************************************************/
27
28
29
30#include <config.h>
31#include <system.h>
32#include <display.h>
33#include <internal.h>
34
35#include <libFreeWRL.h>
36
37#include "../vrml_parser/Structs.h"
38#include "../main/headers.h"
39#include "../opengl/Frustum.h"
40#include "../opengl/Material.h"
41#include "../opengl/OpenGL_Utils.h"
42#include "../opengl/Textures.h"
43#include "Component_ProgrammableShaders.h"
44#include "Component_Shape.h"
45#include "RenderFuncs.h"
46#include "LinearAlgebra.h"
47#include "Polyrep.h"
48#define NOTHING 0
49
50//enum {
51// MAT_NONE = 0,
52// MAT_UNLIT = 1,
53// MAT_REGULAR = 2,
54// MAT_PHYSICAL = 3,
55//};
56
57typedef struct pComponent_Shape{
58
59 struct matpropstruct appearanceProperties;
60
61 /* pointer for a TextureTransform type of node */
62 struct X3D_Node * this_textureTransform; /* do we have some kind of textureTransform? */
63 int isBackMaterial;
64 /* for doing shader material properties */
65 //struct X3D_TwoSidedMaterial *material_twoSided;
66 //struct X3D_Material *material_oneSided;
67
68 /* Any user defined shaders here? */
69 struct X3D_Node * userShaderNode;
70 int modulation;
71
72}* ppComponent_Shape;
73
74static void *Component_Shape_constructor(){
75 void *v = MALLOCV(sizeof(struct pComponent_Shape));
76 memset(v,0,sizeof(struct pComponent_Shape));
77 return v;
78}
79void Component_Shape_init(struct tComponent_Shape *t){
80 //public
81 //private
82 t->prv = Component_Shape_constructor();
83 {
84 ppComponent_Shape p = (ppComponent_Shape)t->prv;
85 p->modulation = 0; //0 by scenefile spec version 1) v3.3(replace)- 2) v4.0+ (modulate everything)
86 p->isBackMaterial = 0;
87 }
88
89}
90void fwl_set_modulation(int modulation){
91 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
92 p->modulation = modulation; //0 per specs 1 blend texture and mat 2 blend mat x cpv x texture
93}
94int fwl_get_modulation(){
95 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
96 return p->modulation; //0 per specs 1 blend texture and mat 2 blend mat x cpv x texture
97}
98//getters
99struct matpropstruct *getAppearanceProperties(){
100 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
101
102 return &p->appearanceProperties;
103}
104
105// see if the Appearance node has a valid Shader node as a child.
106static int hasUserDefinedShader(struct X3D_Node *node) {
107#define NO_SHADER 99999
108 unsigned int rv = NO_SHADER;
109
110 if (node==NULL) return 0;
111
112 //ConsoleMessage ("hasUserDeginedShader, node ptr %p",node);
113 //ConsoleMessage ("hasUserDefinedShader, nodeType %s",stringNodeType(node->_nodeType));
114 if (node->_nodeType == NODE_Appearance) {
115 struct X3D_Appearance *ap;
116 POSSIBLE_PROTO_EXPANSION(struct X3D_Appearance *, node, ap);
117 //ConsoleMessage ("appearance node shaders is %d %p",ap->shaders.n, ap->shaders.p);
118
119 if (ap && ap->shaders.n != 0) {
120 struct X3D_ComposedShader *cps;
121
122 /* ok - what kind of node is here, and are there more than two? */
123 if (ap->shaders.n > 1) {
124 ConsoleMessage ("warning, Appearance->shaders has more than 1 node, using only first one");
125 }
126
127 POSSIBLE_PROTO_EXPANSION(struct X3D_ComposedShader *, ap->shaders.p[0], cps);
128
129 //ConsoleMessage ("node type of shaders is :%s:",stringNodeType(cps->_nodeType));
130 if(cps){
131 if (cps->_nodeType == NODE_ComposedShader) {
132 // might be set in compile_Shader already
133 //ConsoleMessage ("cps->_initialized %d",cps->_initialized);
134 //ConsoleMessage ("cps->_retrievedURLData %d",cps->_retrievedURLData);
135
136 if (cps->_retrievedURLData) {
137 if (cps->_shaderUserNumber == -1) cps->_shaderUserNumber = getNextFreeUserDefinedShaderSlot();
138 rv = cps->_shaderUserNumber;
139 }
140 } else if (cps->_nodeType == NODE_PackagedShader) {
141 // might be set in compile_Shader already
142 if (X3D_PACKAGEDSHADER(cps)->_retrievedURLData) {
143 if (X3D_PACKAGEDSHADER(cps)->_shaderUserNumber == -1)
144 X3D_PACKAGEDSHADER(cps)->_shaderUserNumber = getNextFreeUserDefinedShaderSlot();
145 rv = X3D_PACKAGEDSHADER(cps)->_shaderUserNumber;
146 }
147 } else if (cps->_nodeType == NODE_ProgramShader) {
148 // might be set in compile_Shader already
149 if (X3D_PROGRAMSHADER(cps)->_retrievedURLData) {
150 if (X3D_PROGRAMSHADER(cps)->_shaderUserNumber == -1)
151 X3D_PROGRAMSHADER(cps)->_shaderUserNumber = getNextFreeUserDefinedShaderSlot();
152
153 rv = X3D_PROGRAMSHADER(cps)->_shaderUserNumber;
154 }
155 } else {
156 ConsoleMessage ("shader field of Appearance is a %s, ignoring",stringNodeType(cps->_nodeType));
157 }
158 }
159
160 }
161 }
162
163 //ConsoleMessage ("and ste is %d",ste);
164
165 // ok - did we find an integer between 0 and some MAX_SUPPORTED_USER_SHADERS value?
166 if (rv == NO_SHADER) rv = 0;
167 //else rv = USER_DEFINED_SHADER_START * (rv+1);
168
169 //ConsoleMessage ("rv is going to be %x",rv);
170
171 //ConsoleMessage ("hasUserDefinedShader, returning %p",*shaderTableEntry);
172 return rv;
173}
174int hasGeneratedCubeMapTexture(struct X3D_Appearance *appearance){
175 int ret = FALSE;
176 struct X3D_Appearance *tmpN;
177 POSSIBLE_PROTO_EXPANSION(struct X3D_Appearance *, X3D_NODE(appearance),tmpN)
178 if(tmpN && tmpN->texture)
179 if(tmpN->texture->_nodeType == NODE_GeneratedCubeMapTexture) ret = TRUE;
180 return ret;
181}
182// Save the shader node from the render_*Shader so that we can send in parameters when required
183void setUserShaderNode(struct X3D_Node *me) {
184 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
185 p->userShaderNode = me;
186}
187
188struct X3D_Node *getThis_textureTransform(){
189 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
190 return p->this_textureTransform;
191}
192void clear_bound_textures();
193void push_isBackMaterial(){
194 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
195 p->isBackMaterial += 1;
196}
197void pop_isBackMaterial(){
198 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
199 p->isBackMaterial -= 1;
200}
201int get_isBackMaterial(){
202 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
203 return p->isBackMaterial;
204
205}
206void child_Appearance (struct X3D_Appearance *node) {
207 struct X3D_Node *tmpN;
208 ttglobal tg = gglobal();
209 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
210
211 /* printf ("in Appearance, this %d, nodeType %d\n",node, node->_nodeType);
212 printf (" vp %d geom %d light %d sens %d blend %d prox %d col %d\n",
213 render_vp,render_geom,render_light,render_sensitive,render_blend,render_proximity,render_collision); */
214 /* Render the material node... */
215
216 PRINT_GL_ERROR_IF_ANY("child_Appearance start");
217
218 RENDER_MATERIAL_SUBNODES(node->material);
219 if(node->material && node->material->_nodeType == NODE_TwoSidedMaterial)
220 getAppearanceProperties()->twosided = TRUE;
221 else if(node->backMaterial){
222 push_isBackMaterial();
223 getAppearanceProperties()->twosided = TRUE;
224 RENDER_MATERIAL_SUBNODES(node->backMaterial);
225 pop_isBackMaterial();
226 }
227 //else {
228 // memcpy(&p->appearanceProperties.fw_BackMaterial, &p->appearanceProperties.fw_FrontMaterial, sizeof(struct fw_MaterialParameters));
229 //}
230
231 if (node->fillProperties) {
232 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->fillProperties,tmpN);
233 render_node(tmpN);
234 }
235
236 /* set line widths - if we have line a lineProperties node */
237 if (node->lineProperties) {
238 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->lineProperties,tmpN);
239 render_node(tmpN);
240 }
241 if (node->pointProperties) {
242 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->pointProperties,tmpN);
243 render_node(tmpN);
244 }
245 if (node->textureTransform) {
246 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
247 // is there a TextureTransform? even if no texture in appearance, might be in new style material nodes
248 POSSIBLE_PROTO_EXPANSION(struct X3D_Node*, node->textureTransform, p->this_textureTransform);
249 }
250 if(node->texture) {
251 /* we have to do a glPush, then restore, later */
252 /* glPushAttrib(GL_ENABLE_BIT); */
253
254 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
255
256
258 //POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->textureTransform,p->this_textureTransform);
259
260 /* now, render the texture */
261 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->texture,tmpN);
262 tg->RenderFuncs.texturenode = (void*)tmpN;
263
264 render_node(tmpN);
265 if (!node->material) {
266 struct matpropstruct* mat = getAppearanceProperties();
267 mat->fw_FrontMaterial.type = MAT_UNLIT; //MAT_NONE is default, we need unlit if textures and no material node, will end up as emissive texture
268 }
269 }
270
271 /* shaders here/supported?? */
272 if (node->shaders.n !=0) {
273 int count;
274 int foundGoodShader = FALSE;
275
276 for (count=0; count<node->shaders.n; count++) {
277 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->shaders.p[count], tmpN);
278
279 /* have we found a valid shader yet? */
280 if(tmpN){
281 if (foundGoodShader) {
282 /* printf ("skipping shader %d of %d\n",count, node->shaders.n); */
283 /* yes, just tell other shaders that they are not selected */
284 SET_SHADER_SELECTED_FALSE(tmpN);
285 } else {
286 /* render this node; if it is valid, then we call this one the selected one */
287 SET_FOUND_GOOD_SHADER(tmpN);
288 DEBUG_SHADER("running shader (%s) %d of %d\n",
289 stringNodeType(X3D_NODE(tmpN)->_nodeType),count, node->shaders.n);
290 render_node(tmpN);
291 }
292 }
293 }
294 }
295
296 /* castle Effects here/supported?? */
297 if (node->effects.n !=0) {
298 //int count;
299 //int foundGoodShader = FALSE;
300 prep_sibAffectors(X3D_NODE(node),&node->effects);
301
302 //for (count=0; count<node->effects.n; count++) {
303 // POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->effects.p[count], tmpN);
304 //
305 // /* have we found a valid shader yet? */
306 // if(tmpN){
307 // //if (foundGoodShader) {
308 // // /* printf ("skipping shader %d of %d\n",count, node->shaders.n); */
309 // // /* yes, just tell other shaders that they are not selected */
310 // // SET_SHADER_SELECTED_FALSE(tmpN);
311 // //} else {
312 // // /* render this node; if it is valid, then we call this one the selected one */
313 // // SET_FOUND_GOOD_SHADER(tmpN);
314 // DEBUG_SHADER("running shader (%s) %d of %d\n",
315 // stringNodeType(X3D_NODE(tmpN)->_nodeType),count, node->effects.n);
316 // //render_node(tmpN);
317 // prep_sibAffectors(node,&node->effects);
318 // //}
319 // }
320 //}
321 }
322 PRINT_GL_ERROR_IF_ANY("child_Appearance end");
323
324}
325
326
327void render_Material (struct X3D_Material *node) {
328 COMPILE_IF_REQUIRED
329 {
330 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
331
332 /* record this node for OpenGL-ES and OpenGL-3.1 operation */
333 //p->material_oneSided = node;
334 //if(get_isBackMaterial()){
335 // p->material_twoSided = node;
336 //}
337 if (node != NULL) {
338 if(get_isBackMaterial()){
339 memcpy (&p->appearanceProperties.fw_BackMaterial, node->_material, sizeof (struct fw_MaterialParameters));
340 }else{
341 memcpy (&p->appearanceProperties.fw_FrontMaterial, node->_material, sizeof (struct fw_MaterialParameters));
342 }
343 }
344 }
345}
346//struct X3D_Material *get_material_oneSided(){
347// ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
348// return p->material_oneSided;
349//}
350//struct X3D_TwoSidedMaterial *get_material_twoSided(){
351// ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
352// return p->material_twoSided;
353//}
354
355/* bounds check the material node fields */
356void compile_Material (struct X3D_Material *node) {
357 struct X3D_Node **tnodes;
358 struct fw_MaterialParameters *q;
359 /* verify that the numbers are within range */
360 node->ambientIntensity = fclamp(node->ambientIntensity,0.0f,1.0f);
361 node->shininess = fclamp(node->shininess,0.0f,1.0f);
362 node->occlusionStrength = fclamp(node->occlusionStrength, 0.0f, 1.0f);
363 node->normalScale = fclamp(node->normalScale, 1.0f, 1.e9f); //one to infinity
364 node->transparency = fclamp(node->transparency,0.0f,1.0f);
365 fvecclamp3f(node->diffuseColor.c,0.0f,1.0f);
366 fvecclamp3f(node->emissiveColor.c,0.0f,1.0f);
367 fvecclamp3f(node->specularColor.c,0.0f,1.0f);
368
369 if(!node->_material){
370 node->_material = malloc(sizeof(struct fw_MaterialParameters));
371 register_node_gc(node,node->_material);
372 }
373 memset(node->_material,0,sizeof(struct fw_MaterialParameters));
374
375 q = (struct fw_MaterialParameters *)node->_material;
376 vecset3f(q->baseColor,1.0f,1.0f,1.0f); //saves boolean math in shader
377 veccopy3f(q->diffuse,node->diffuseColor.c);
378 veccopy3f(q->emissive,node->emissiveColor.c);
379 veccopy3f(q->specular,node->specularColor.c);
380 q->ambient = node->ambientIntensity;
381 q->shininess = node->shininess;
382 int oldway = 0;
383 if (!oldway) {
384 q->transparency = node->transparency;
385 q->occlusion = node->occlusionStrength;
386 }
387 q->normalScale = node->normalScale;
388 q->type = MAT_REGULAR;
389
390 //new v4 textures
392 //iunit [0] normal [1] emissive [2] occlusion [3] diffuse OR baseColor [4] shininess OR metallicRoughness [5] specular [6] ambient
393 tnodes = q->textures;
394 memset(tnodes,0,7*sizeof(void *));
395 if(node->normalTexture)
396 {
397 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->normalTexture,tnodes[0]);
398 if (tnodes[0]) q->map[0] = node->normalTextureMapping ? node->normalTextureMapping->strptr : NULL;
399 }
400 if(node->emissiveTexture)
401 {
402 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->emissiveTexture,tnodes[1]);
403 if (tnodes[1]) q->map[1] = node->emissiveTextureMapping ? node->emissiveTextureMapping->strptr : NULL;
404 }
405 if(node->occlusionTexture)
406 {
407 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->occlusionTexture,tnodes[2]);
408 if (tnodes[2]) q->map[2] = node->occlusionTextureMapping ? node->occlusionTextureMapping->strptr : NULL;
409 }
410 if(node->diffuseTexture)
411 {
412 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->diffuseTexture,tnodes[3]);
413 if (tnodes[3]) q->map[3] = node->diffuseTextureMapping ? node->diffuseTextureMapping->strptr : NULL;
414 }
415 if(node->shininessTexture)
416 {
417 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->shininessTexture,tnodes[4]);
418 if (tnodes[4]) q->map[4] = node->shininessTextureMapping ? node->shininessTextureMapping->strptr : NULL;
419 }
420 if(node->specularTexture)
421 {
422 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->specularTexture,tnodes[5]);
423 if (tnodes[5]) q->map[5] = node->specularTextureMapping ? node->specularTextureMapping->strptr : NULL;
424 }
425 if (node->ambientTexture)
426 {
427 POSSIBLE_PROTO_EXPANSION(struct X3D_Node*, node->ambientTexture, tnodes[6]);
428 if (tnodes[6]) q->map[6] = node->ambientTextureMapping ? node->ambientTextureMapping->strptr : NULL;
429 }
430
431 //int *cindex = q->cindex;
432 //for (int i = 0; i < 7; i++) cindex[i] = 0; //can't do this here, because texCoord.mapping order is dominant, and don't have geom node access here.
433 //cindex[0] = 0; //node->normalTextureChannel;
434 //cindex[1] = 0; //node->emissiveTextureChannel;
435 //cindex[2] = node->diffuseTextureChannel;
436 //cindex[3] = node->specularShininessTextureChannel;
437 //cindex[4] = node->ambientTextureChannel;
438 q->nt = 0; //assume no material.texturexxx to start
439 for(int i=0;i<7;i++){
440 q->tcount[i] = 0; //default: no texture for this material function
441 q->tstart[i] = q->nt; //shader: start looping over tindex where we left off, for tcount loops
442 if(tnodes[i]){
443 if(tnodes[i]->_nodeType == NODE_MultiTexture) {
444 struct X3D_MultiTexture *mt = (struct X3D_MultiTexture*)tnodes[i];
445 q->tcount[i] = mt->texture.n;
446 q->nt += mt->texture.n;
447 q->mt++;
448 }else{
449 //single texture
450 q->nt++;
451 q->tcount[i] = 1;
452 }
453 }
454 }
455 MARK_NODE_COMPILED
456}
457void clear_materialparameters_per_draw_counts() {
458 // June 2022 both TextureTransform_start (Appearance textures) and sendMaterialsToShader (Material textures)
459 // can set mat values for diffuse (iuse == 3) and emissive (iuse=1) textures
460 // and to give them a common / shared initialization so one doesn't over-write the other
461 // we do this earlier in child_Shape, so they both (could in theory) add as multitextues (although we skip material iuse if appearance already set same iuse)
462 struct matpropstruct* mat = getAppearanceProperties();
463 for (int iuse = 0; iuse < 7; iuse++) {
464 mat->fw_FrontMaterial.tstart[iuse] = 0;
465 mat->fw_FrontMaterial.tcount[iuse] = 0;
466 mat->fw_BackMaterial.tstart[iuse] = 0;
467 mat->fw_BackMaterial.tcount[iuse] = 0;
468 }
469 mat->fw_FrontMaterial.nt = 0; //total number of single textures on this draw
470 mat->fw_BackMaterial.nt = 0;
471}
472
473#define CHECK_COLOUR_FIELD(aaa) \
474 case NODE_##aaa: { \
475 struct X3D_##aaa *me = (struct X3D_##aaa *)realNode; \
476 if (me->color == NULL) return NOTHING; /* do not add any properties here */\
477 else return COLOUR_MATERIAL_SHADER; \
478 break; \
479 }
480#define CHECK_FOGCOORD_FIELD(aaa) \
481 case NODE_##aaa: { \
482 struct X3D_##aaa *me = (struct X3D_##aaa *)realNode; \
483 if (me->fogCoord == NULL) return NOTHING; /* do not add any properties here */\
484 else return HAVE_FOG_COORDS; \
485 break; \
486 }
487
488
489/* if this is a LineSet, PointSet, etc... */
490// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/lighting.html#Lightingoff
491// 'shapes that represent points or lines are unlit
492static bool getIfLinePoints(struct X3D_Node *realNode) {
493 if (realNode == NULL) return false;
494 switch (realNode->_nodeType) {
495 case NODE_IndexedLineSet:
496 case NODE_LineSet:
497 case NODE_PointSet:
498 case NODE_Polyline2D:
499 case NODE_Polypoint2D:
500 case NODE_Circle2D:
501 case NODE_Arc2D:
502 return true;
503 }
504 return false; // do not add any capabilites here.
505}
506
507/* is the texCoord field a TextureCoordinateGenerator or not? */
508struct X3D_Node *getGeomTexCoordField(struct X3D_Node *realGeomNode){
509 struct X3D_Node *tc = NULL;
510 int *fieldOffsetsPtr = NULL;
511
512 //ConsoleMessage ("getShapeTextureCoordGen, node type %s\n",stringNodeType(realNode->_nodeType));
513 if (realGeomNode == NULL) return tc;
514
515 fieldOffsetsPtr = (int *)NODE_OFFSETS[realGeomNode->_nodeType];
516 /*go thru all field*/
517 while (*fieldOffsetsPtr != -1) {
518 if (*fieldOffsetsPtr == FIELDNAMES_texCoord) {
519 // get the pointer stored here...
520 memcpy(&tc,offsetPointer_deref(void*, realGeomNode,*(fieldOffsetsPtr+1)),sizeof(struct X3D_Node *));
521 break;
522 }
523 fieldOffsetsPtr += FIELDOFFSET_LENGTH;
524 }
525 return tc;
526
527}
528static int getShapeTextureCoordGen(struct X3D_Node *realNode) {
529 struct X3D_Node *tc = NULL;
530 tc = getGeomTexCoordField(realNode);
531 if (tc != NULL) {
532 if (tc->_nodeType == NODE_TextureCoordinateGenerator) return HAVE_TEXTURECOORDINATEGENERATOR;
533 }
534 return 0;
535}
536
537
538/* Some shapes have Color nodes - if so, then we have other shaders */
539static int getShapeColourShader (struct X3D_Node *myGeom) {
540 struct X3D_Node *realNode;
541
542 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *,myGeom,realNode);
543
544 if (realNode == NULL) return NOTHING;
545
546 /* go through each node type that can have a Color node, and if it is not NULL
547 we know we have a Color node */
548
549 switch (realNode->_nodeType) {
550 CHECK_COLOUR_FIELD(IndexedFaceSet);
551 CHECK_COLOUR_FIELD(IndexedLineSet);
552 CHECK_COLOUR_FIELD(IndexedTriangleFanSet);
553 CHECK_COLOUR_FIELD(IndexedTriangleSet);
554 CHECK_COLOUR_FIELD(IndexedTriangleStripSet);
555 CHECK_COLOUR_FIELD(LineSet);
556 CHECK_COLOUR_FIELD(PointSet);
557 CHECK_COLOUR_FIELD(TriangleFanSet);
558 CHECK_COLOUR_FIELD(TriangleStripSet);
559 CHECK_COLOUR_FIELD(TriangleSet);
560 CHECK_COLOUR_FIELD(ElevationGrid);
561 CHECK_COLOUR_FIELD(GeoElevationGrid);
562 CHECK_COLOUR_FIELD(QuadSet);
563 CHECK_COLOUR_FIELD(IndexedQuadSet);
564 }
565
566 /* if we are down here, we KNOW we do not have a color field */
567 return NOTHING; /* do not add any capabilites here */
568}
569/* Some shapes have Color nodes - if so, then we have other shaders */
570static int getShapeFogShader (struct X3D_Node *myGeom) {
571 struct X3D_Node *realNode;
572
573 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *,myGeom,realNode);
574
575 if (realNode == NULL) return NOTHING;
576
577 /* go through each node type that can have a Color node, and if it is not NULL
578 we know we have a Color node */
579
580 switch (realNode->_nodeType) {
581 CHECK_FOGCOORD_FIELD(IndexedFaceSet);
582 CHECK_FOGCOORD_FIELD(IndexedLineSet);
583 CHECK_FOGCOORD_FIELD(IndexedTriangleFanSet);
584 CHECK_FOGCOORD_FIELD(IndexedTriangleSet);
585 CHECK_FOGCOORD_FIELD(IndexedTriangleStripSet);
586 CHECK_FOGCOORD_FIELD(LineSet);
587 CHECK_FOGCOORD_FIELD(PointSet);
588 CHECK_FOGCOORD_FIELD(TriangleFanSet);
589 CHECK_FOGCOORD_FIELD(TriangleStripSet);
590 CHECK_FOGCOORD_FIELD(TriangleSet);
591 CHECK_FOGCOORD_FIELD(ElevationGrid);
592 //CHECK_FOGCOORD_FIELD(GeoElevationGrid);
593 CHECK_FOGCOORD_FIELD(QuadSet);
594 CHECK_FOGCOORD_FIELD(IndexedQuadSet);
595 }
596
597 /* if we are down here, we KNOW we do not have a color field */
598 return NOTHING; /* do not add any capabilites here */
599}
600void compile_material_if_required(struct X3D_Node *node){
601 COMPILE_IF_REQUIRED(node);
602}
603
604static long long getAppearanceShader (struct X3D_Node *myApp) {
605 struct X3D_Appearance *realAppearanceNode;
606 struct X3D_Node *realMaterialNode, *realBackMaterialNode;
607
608
609 long long retval = NOTHING;
610
611 /* if there is no appearance node... */
612 if (myApp == NULL) return retval;
613
614 POSSIBLE_PROTO_EXPANSION(struct X3D_Appearance *, myApp,realAppearanceNode);
615 if (!realAppearanceNode || realAppearanceNode->_nodeType != NODE_Appearance) return retval;
616
617 // v4 Appearance.backMaterial (vs v3.3-- TwoSidedMaterial)
618 realMaterialNode = realBackMaterialNode = NULL;
619 if (realAppearanceNode->backMaterial != NULL) {
620 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, realAppearanceNode->backMaterial,realBackMaterialNode);
621 }
622 if (realAppearanceNode->material != NULL) {
623 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, realAppearanceNode->material,realMaterialNode);
624 }
625 if(realMaterialNode || realBackMaterialNode) {
626 if(1){
627 struct fw_MaterialParameters *p, *q;
628 int material, texture, multitex, twosided, physical, unlit;
629 material = texture = multitex = twosided = physical = unlit = FALSE;
630
631 p = q = NULL;
632 if(realMaterialNode){
633 compile_material_if_required(realMaterialNode);
634 switch(realMaterialNode->_nodeType){
635 case NODE_Material:
636 {
637 struct X3D_Material *mnode = (struct X3D_Material*)realMaterialNode;
638 p = (struct fw_MaterialParameters*)mnode->_material;
639 material = TRUE;
640 }
641 break;
642 case NODE_PhysicalMaterial:
643 {
644 struct X3D_PhysicalMaterial *mnode = (struct X3D_PhysicalMaterial*)realMaterialNode;
645 p = (struct fw_MaterialParameters*)mnode->_material;
646 physical = TRUE;
647 }
648 break;
649 case NODE_UnlitMaterial:
650 {
651 struct X3D_UnlitMaterial *mnode = (struct X3D_UnlitMaterial*)realMaterialNode;
652 p = (struct fw_MaterialParameters*)mnode->_material;
653 unlit = TRUE;
654 }
655 break;
656 case NODE_TwoSidedMaterial:
657 {
658 struct X3D_TwoSidedMaterial *mnode = (struct X3D_TwoSidedMaterial*)realMaterialNode;
659 p = (struct fw_MaterialParameters*)mnode->_material;
660 q = (struct fw_MaterialParameters*)mnode->_backMaterial;
661 material = TRUE;
662 twosided = TRUE;
663 }
664 break;
665 default:
666 break;
667 }
668 }
669 if(realBackMaterialNode){
670 compile_material_if_required(realBackMaterialNode);
671 switch(realBackMaterialNode->_nodeType){
672 case NODE_Material:
673 {
674 struct X3D_Material *mnode = (struct X3D_Material*)realBackMaterialNode;
675 q = (struct fw_MaterialParameters*)mnode->_material;
676 material = TRUE;
677 }
678 break;
679 case NODE_PhysicalMaterial:
680 {
681 struct X3D_PhysicalMaterial *mnode = (struct X3D_PhysicalMaterial*)realBackMaterialNode;
682 q = (struct fw_MaterialParameters*)mnode->_material;
683 physical = TRUE;
684 }
685 break;
686 case NODE_UnlitMaterial:
687 {
688 struct X3D_UnlitMaterial *mnode = (struct X3D_UnlitMaterial*)realBackMaterialNode;
689 q = (struct fw_MaterialParameters*)mnode->_material;
690 unlit = TRUE;
691 }
692 break;
693 case NODE_TwoSidedMaterial:
694 {
695 //not permitted
696 //struct X3D_TwoSidedMaterial *mnode = (struct X3D_TwoSidedMaterial*)realMaterialNode;
697 //p = (struct fw_MaterialParameters*)mnode->_material;
698 //q = (struct fw_MaterialParameters*)mnode->_backMaterial;
699 //unlit = TRUE;
700 }
701 break;
702 default:
703 break;
704 }
705 }
706 if(p){
707 if(p->nt) texture = TRUE;
708 if(p->mt) multitex = TRUE;
709 //twosided = TRUE; //uncomment if you don't want backMaterial NULL to render front material
710 }
711 if(q){
712 if(q->nt) texture = TRUE;
713 if(q->mt) multitex = TRUE;
714 twosided = TRUE; //not sure it makes sense what we are doing with TWO, should it be pipeline culling CULL_FACE GL_BACK, GL_FRONT? but need now for Appearance.backMaterial
715 }
716 if(twosided) retval |= TWO_MATERIAL_APPEARANCE_SHADER;
717 if(material) retval |= MATERIAL_APPEARANCE_SHADER;
718 if(physical) retval |= PHYSICAL_MATERIAL_APPEARANCE_SHADER;
719 if(unlit) retval |= UNLIT_MATERIAL_APPEARANCE_SHADER;
720 // need to learn | vs xor etc so this isn't un-applied below if there's a regular appearance.texture
721 if(texture) retval |= ONE_TEX_APPEARANCE_SHADER;
722 if(multitex) retval |= MULTI_TEX_APPEARANCE_SHADER;
723 } else {
724 if(realBackMaterialNode || realMaterialNode->_nodeType == NODE_TwoSidedMaterial ) {
725 retval |= TWO_MATERIAL_APPEARANCE_SHADER;
726 }
727 if (realMaterialNode->_nodeType == NODE_Material || (realBackMaterialNode && realBackMaterialNode->_nodeType == NODE_Material)) {
728 retval |= MATERIAL_APPEARANCE_SHADER;
729 }
730 if (realMaterialNode->_nodeType == NODE_PhysicalMaterial || (realBackMaterialNode && realBackMaterialNode->_nodeType == NODE_PhysicalMaterial)) {
731 retval |= PHYSICAL_MATERIAL_APPEARANCE_SHADER;
732 }
733 if (realMaterialNode->_nodeType == NODE_UnlitMaterial || (realBackMaterialNode && realBackMaterialNode->_nodeType == NODE_UnlitMaterial)) {
734 retval |= UNLIT_MATERIAL_APPEARANCE_SHADER;
735 }
736 }
737 }
738 else {
739 //v4 specs section 12.2.5 Coexistence of textures (appearance and material) >
740 // 4. if material appearance.material is NULL and appearance.textures, use UNLIT and put textures in UNLIT emissive texture
741 //if(realAppearanceNode->texture != NULL)
742 // retval |= UNLIT_MATERIAL_APPEARANCE_SHADER;
743 }
744
745
746 if (realAppearanceNode->fillProperties != NULL) {
747 struct X3D_Node *fp;
748 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, realAppearanceNode->fillProperties,fp);
749 if(fp){
750 if (fp->_nodeType != NODE_FillProperties) {
751 ConsoleMessage("getAppearanceShader, fillProperties has a node type of %s",stringNodeType(fp->_nodeType));
752 } else {
753 // is this a FillProperties node, but is it enabled?
754 if (X3D_FILLPROPERTIES(fp)->_enabled)
755 retval |= FILL_PROPERTIES_SHADER;
756 }
757 }
758 }
759
760 if (realAppearanceNode->lineProperties != NULL) {
761 struct X3D_Node *lp;
762 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, realAppearanceNode->lineProperties,lp);
763 if(lp){
764 if (lp->_nodeType != NODE_LineProperties) {
765 ConsoleMessage("getAppearanceShader, lineProperties has a node type of %s",stringNodeType(lp->_nodeType));
766 } else {
767 // is this a LineProperties node, but is it applied?
768 if (X3D_LINEPROPERTIES(lp)->applied){
769 if(X3D_LINEPROPERTIES(lp)->linetype > 1)
770 retval |= LINE_PROPERTIES_SHADER;
771 }
772 }
773 }
774 }
775
776 if (realAppearanceNode->pointProperties != NULL) {
777 struct X3D_Node *pp;
778 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, realAppearanceNode->pointProperties,pp);
779 if(pp){
780 if (pp->_nodeType != NODE_PointProperties) {
781 ConsoleMessage("getAppearanceShader, pointProperties has a node type of %s",stringNodeType(pp->_nodeType));
782 } else {
783 if(X3D_POINTPROPERTIES(pp)->_pointMethod > 0) //_colormode > 1)
784 retval |= POINT_PROPERTIES_SHADER;
785 }
786 }
787 }
788
789 if (realAppearanceNode->texture != NULL) {
790 //printf ("getAppearanceShader - rap node is %s\n",stringNodeType(realAppearanceNode->texture->_nodeType));
791 struct X3D_Node *tex;
792
793 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, realAppearanceNode->texture,tex);
794 if(tex){
795 if ((tex->_nodeType == NODE_ImageTexture) ||
796 (tex->_nodeType == NODE_MovieTexture) ||
797 (tex->_nodeType == NODE_PixelTexture) ){
798 retval |= ONE_TEX_APPEARANCE_SHADER;
799 } else if( (tex->_nodeType == NODE_PixelTexture3D) ||
800 (tex->_nodeType == NODE_ComposedTexture3D) ||
801 (tex->_nodeType == NODE_ImageTexture3D) ) {
802 retval |= ONE_TEX_APPEARANCE_SHADER;
803 retval |= TEX3D_SHADER; //VOLUME by default
804 if(tex->_nodeType == NODE_ComposedTexture3D)
805 retval |= TEX3D_LAYER_SHADER; //else VOLUME
806 } else if (tex->_nodeType == NODE_MultiTexture) {
807 retval |= MULTI_TEX_APPEARANCE_SHADER;
808 //need to recurse, but just one level, can unroll here
809 struct X3D_MultiTexture* mt = (struct X3D_MultiTexture*)tex;
810 for (int i = 0; i < mt->texture.n; i++) {
811 struct X3D_Node *stex = mt->texture.p[i];
812 if ((stex->_nodeType == NODE_PixelTexture3D) ||
813 (stex->_nodeType == NODE_ComposedTexture3D) ||
814 (stex->_nodeType == NODE_ImageTexture3D)) {
815 retval |= TEX3D_SHADER; //VOLUME by default
816 if (stex->_nodeType == NODE_ComposedTexture3D) //should this be stex or tex? change from tex to stex June 2022 on wild guess
817 retval |= TEX3D_LAYER_SHADER; //else VOLUME
818 }
819 if ((stex->_nodeType == NODE_ComposedCubeMapTexture) ||
820 (stex->_nodeType == NODE_ImageCubeMapTexture) ||
821 (stex->_nodeType == NODE_GeneratedCubeMapTexture)) {
822 retval |= HAVE_CUBEMAP_TEXTURE;
823 }
824 }
825 } else if ((tex->_nodeType == NODE_ComposedCubeMapTexture) ||
826 (tex->_nodeType == NODE_ImageCubeMapTexture) ||
827 (tex->_nodeType == NODE_GeneratedCubeMapTexture)) {
828 retval |= HAVE_CUBEMAP_TEXTURE;
829 } else {
830 ConsoleMessage ("getAppearanceShader, texture field %s not supported yet\n",
831 stringNodeType(tex->_nodeType));
832 }
833 }
834 }
835
836 #ifdef SHAPE_VERBOSE
837 printf ("getAppearanceShader, returning %x\n",retval);
838 #endif //SHAPE_VERBOSE
839
840 return retval;
841}
842
843
844/* find info on the appearance of this Shape and create a shader */
845/*
846 The possible sequence of a properly constructed appearance field is:
847
848 Shape.appearance -> Appearance
849
850 Appearance.fillProperties -> FillProperties
851 Appearance.lineProperties -> LineProperties
852 Appearance.material -> Material
853 -> TwoSidedMaterial
854 Appearance.shaders -> ComposedShader
855 Appearance.shaders -> PackagedShader
856 Appearance.shaders -> ProgramShader
857
858 Appearance.texture -> Texture
859 Appearance.texture -> MultiTexture
860 Appearance.textureTransform ->
861
862*/
863
864/* now works with our pushing matricies (norm, proj, modelview) but not for complete shader appearance replacement */
865void render_FillProperties (struct X3D_FillProperties *node) {
866 // http://learnwebgl.brown37.net/10_surface_properties/texture_mapping_procedural.html
867 // https://thebookofshaders.com/05/
868 // https://isotc.iso.org/livelink/livelink/fetch/-8916524/8916549/8916590/6208440/class_pages/hatchstyle.html
869 // Apr, 2020 change to procedural textures
870 // - just send the algo # to the frag shader
871 // - added hatchStyles 8-19
872 // = used texture coords for scale [0-1] with current coord being vert shader transformed and interpolated texture coord
873 // x X3D Text node - doesn't fill/hatch now H: we don't give vertex shader texture coords for Text
874 // - ToDo (this means _you_: fix X3D Text so it can be textured and procedurally textured
875
876 GLint algor;
877 GLint hatched;
878 GLint filled;
879
880 struct matpropstruct *me= getAppearanceProperties();
881
882 algor = node->hatchStyle; filled = node->filled; hatched = node->hatched;
883
884
885 me->filledBool = filled;
886 me->hatchedBool = hatched;
887 me->hatchAlgo = algor;
888 me->hatchColour[0]=node->hatchColor.c[0]; me->hatchColour[1]=node->hatchColor.c[1]; me->hatchColour[2] = node->hatchColor.c[2];
889 me->hatchColour[3] = 1.0;
890}
891
892void printBitsB(size_t const size, void const * const ptr);
893typedef struct vec2 {float u,v;} vec2;
894
895struct lineinfo {
896 //describes one cycle for a line pattern - for coords think in screen pixels
897 int type;
898 char * dscription;
899 int ndash; //counting both dash and gap
900 float dash[8]; //every 2nd x starts a gap ie dash-gap-dash-gap
901 float period; //sum of dash and gap length along u axis for 1 repeating cycle
902 vec2 zig[24];
903 int nzig;
904} linetypes [] = {
905{
906 1,"solid",1,
907 {48.0f},
908 0.0f,
909 {{0.0,0.0}},
910 0,
911},
912{
913 2,"dashed", 2,
914 {14.0f,10.0f},
915 0.0f,
916 {{0.0,0.0}},
917 0,
918},
919{
920 3,"dotted",2,
921 {3.0f,11.0f},
922 0.0f,
923 {{0.0,0.0}},
924 0,
925},
926{
927 4,"dash-dotted",4,
928 {10.0f,12.0f,2.0f,12.0f},
929 0.0f,
930 {{0.0,0.0}},
931 0,
932},
933{
934 5,"dash-dot-dot",6,
935 {16.0f,10.0f,2.0f,9.0f,2.0f,9.0f},
936 0.0f,
937 {{0.0,0.0}},
938 0,
939},
940{
941 6,"single arrow",1,
942 {24.0f},
943 0.0f,
944 {{0.0,0.0}},
945 0,
946},
947{
948 7,"single dot",1,
949 {24.0f},
950 0.0f,
951 {{0.0,0.0}},
952 0,
953},
954{
955 8,"double arrow",1,
956 {24.0f},
957 0.0f,
958 {{0.0,0.0}},
959 0,
960},
961{
962 9,"stitch line",2,
963 {10.0f,10.0f},
964 0.0f,
965 {{0.0,0.0}},
966 0,
967},
968{
969 10,"chain line",4,
970 {8.0f,4.0f,4.0f,4.0f},
971 0.0f,
972 {{0.0,0.0}},
973 0,
974},
975{
976 11,"cemter line",2,
977 {8.0f,4.0f},
978 0.0f,
979 {{0.0,0.0}},
980 0,
981},
982{
983 12,"hidden line",2,
984 {10.0f,4.0f},
985 0.0f,
986 {{0.0,0.0}},
987 0,
988},
989{
990 13,"phantom line",6,
991 {24.0f,3.0f,6.0f,3.0f,6.0f,3.0f},
992 0.0f,
993 {{0.0,0.0}},
994 0,
995},
996{
997 14,"break line - style 1",1,
998 {128.0f},
999 0.0f,
1000 {{ 0.00f,0.0f},{ 9.60f,-1.44f},{12.80f,-1.28f},{14.72f,-2.40f},{19.20f,-1.76f},{24.32f,1.28f},{28.80f,2.24f},{36.96f,1.60f},{42.40f,2.24f},{48.00f,1.12f},{51.20f,-1.92f},{55.36f,-0.96f},{62.40f,1.28f},{76.80f,1.12f},{82.88f,-1.60f},{85.92f,-0.64f},{97.44f,4.32f},{101.12f,4.96f},{108.80f,1.12f},{112.16f,1.12f},{120.00f,0.00f},{125.12f,2.72f},{128.0f,0.0f}},
1001 23,
1002},
1003{
1004 15,"break line - style 2",1,
1005 {36.0f},
1006 0.0f,
1007 {{0.f,0.f},{20.f,0.f},{24.f,4.f},{32.f,-4.f},{36.f,0.f},},
1008 5,
1009},
1010{
1011 16,"fallback for user style 16",1,
1012 {48.0f},
1013 0.0f,
1014 {{0.0,0.0}},
1015 0,
1016},
1017
1018};
1019
1020
1021
1022float make_linetype_atlas_row(float *dash, int ndash, vec2 *zig, int nzig,
1023 float *uv_row, float *tse_row){
1024 float period = 0.0f;
1025 for(int j=0;j<ndash;j++)
1026 period += dash[j];
1027 float u_ = 0.0f; //u bar
1028 float uu = 0.0f; //u*
1029 int idash = 0; //current dash or gap
1030 float curr_start = 0.0f;
1031 float curr_end = dash[0];
1032 int kzag = 0;
1033 float zigv = 0.0f;
1034 for(int j=0;j<(int)(period+.5);j++){
1035 u_ = (float)j; //the current pixel relative to the starting pixel
1036 if(u_ > curr_end){
1037 curr_start = curr_end;
1038 idash++;
1039 curr_end = curr_start + dash[idash];
1040 }
1041 int gap = idash % 2 != 0 ? TRUE: FALSE; //assumes all linetypes start solid
1042 if(gap){
1043 //if we're in a gap, the end-cap inclusion is tested against the closest dash end uu
1044 uu = u_ - curr_start < (curr_end - u_) ? curr_start : curr_end;
1045 }else{
1046 //if we're not in a gap, the we use a radius=linewidth/2 inclusion test to the current point along the centerline
1047 uu = u_;
1048 }
1049 uv_row[j*2] = uu;
1050 uv_row[j*2+1] = 0.0f; //v is normally 0 except zigzag lines
1051 tse_row[j*3] = gap ? 0 : 2;
1052 tse_row[j*3+1] = curr_start;
1053 tse_row[j*3+2] = curr_end;
1054 if(nzig){
1055 //find the sizgag segment we're on
1056 for(int k=1;k<nzig;k++){
1057 vec2 d1 = zig[k];
1058 vec2 d0 = zig[k-1];
1059 if(d0.u <= u_ && u_ < d1.u){
1060 //... and linearly interpolate current pixel v (perpendicular to line u direction
1061 zigv = (u_ - d0.u)/(d1.u - d0.u) * (d1.v - d0.v) + d0.v;
1062 }
1063 }
1064 uv_row[j*2+1] = zigv; //off-line-center v when zig-zagging
1065 }
1066 }
1067 return period;
1068}
1069static float *linetype_atlas_uv = NULL;
1070static float *linetype_atlas_tse = NULL;
1071
1072void make_linetype_atlas(struct matpropstruct *me){
1073/*
1074 goal: make it easy for the frag shader to know what to do with each fragment
1075 by creating a 128 screen pixel long (enough for pattern period) 5-compoent parameterization
1076 terminology:
1077 u,v axes (similar to texture coords) with u aligned to line swegment and v perpendicular
1078 uu or u* - where the pattern centerline or reference point is for u
1079 ubar or u_ - where the current fragment is, in u,v system (gl_FragCoord.xy transformed to uv system)
1080 (dx,dy) = ubar - uu
1081 pattern period - pattern length, in screen pixeels, sent separately as u_lineperiod
1082 for each pixel along period:
1083 1) reference point uu - where measuring dx distance ends from
1084 2) subtype 0= gap, 1= endcap 2= dash body
1085 3) subtype start (measured along u axis from start of pattern period)
1086 4) subtype end
1087 5) v of pattern centerline (normally 0, except for wiggle and zigzag patterns which vary with u)
1088 one author sent all linetypes as one float texture, that didn't work for us
1089 so we are sending 2 uniform arrays[128] every frame
1090 uv - uu reference point, and v (normally 0) (vec2)
1091 tse - subtype, start, end (vec3)
1092*/
1093 int nlinetypes = 20; //specs have 1-16 with 16 being user specified
1094 linetype_atlas_uv = MALLOCV(128*sizeof(float)*2*nlinetypes);
1095 linetype_atlas_tse = MALLOCV(128*sizeof(float)*3*nlinetypes);
1096 memset(linetype_atlas_uv,0,128*sizeof(float)*2*nlinetypes);
1097 memset(linetype_atlas_tse,0,128*sizeof(float)*3*nlinetypes);
1098 for(int i=0;i<16;i++){
1099 float * uv_row = &linetype_atlas_uv[128*2*i];
1100 float * tse_row = &linetype_atlas_tse[128*3*i];
1101 struct lineinfo *lt = &linetypes[i];
1102
1103 int ndash = lt->ndash;
1104 float *dash = lt->dash;
1105 int nzig = lt->nzig;
1106 vec2 *zig = (vec2 *)lt->zig;
1107 lt->period = make_linetype_atlas_row(dash,ndash,zig,nzig,uv_row,tse_row);
1108
1109 }
1110}
1111struct style16{
1112 float atlas_uv[256];
1113 float atlas_tse[384];
1114 float period;
1115};
1116void send_linetype_atlas_to_shader(struct X3D_LineProperties *node, struct matpropstruct *me){
1117 if(linetype_atlas_uv){
1118 if(me->linetype == 16 && node->__style16){
1119 struct style16 *s16 = (struct style16 *)node->__style16;
1120 me->linetype_uv = &s16->atlas_uv[0];
1121 me->linetype_tse = &s16->atlas_tse[0];
1122 }else{
1123 int irow = me->linetype-1;
1124 me->linetype_uv = &linetype_atlas_uv[irow*2*128];
1125 me->linetype_tse = &linetype_atlas_tse[irow*3*128];
1126 }
1127 int start_style, end_style;
1128 start_style = node->__styleStart;
1129 end_style = node->__styleEnd;
1130 switch(me->linetype){
1131 case 6: end_style = 1; break;
1132 case 7: end_style = 2; break;
1133 case 8: start_style = 1;
1134 end_style = 1; break;
1135 default:
1136 break;
1137 }
1138 me->linestrip_start_style = start_style;
1139 me->linestrip_end_style = end_style;
1140 }
1141}
1142
1143
1144void compile_LineProperties(struct X3D_LineProperties *node) {
1145 int start_style, end_style;
1146 start_style = end_style = 0;
1147 if(!strcmp(node->styleStart->strptr,"ARROW")) start_style = 1;
1148 if(!strcmp(node->styleStart->strptr,"DOT")) start_style = 2;
1149 if(!strcmp(node->styleEnd->strptr,"ARROW")) end_style = 1;
1150 if(!strcmp(node->styleEnd->strptr,"DOT")) end_style = 2;
1151 node->__styleStart = start_style;
1152 node->__styleEnd = end_style;
1153 if(node->type16dashes.n || node->type16wiggles.n){
1154 if(node->__style16 == NULL){
1155 node->__style16 = MALLOCV(sizeof(struct style16));
1156 memset(node->__style16,0,sizeof(struct style16));
1157 }
1158 struct style16* s16 = node->__style16;
1159 int ndash = node->type16dashes.n;
1160 float *dash = node->type16dashes.p;
1161 float *uv_row = s16->atlas_uv;
1162 float *tse_row = s16->atlas_tse;
1163 int nzig = node->type16wiggles.n;
1164 vec2 *zig = (vec2 *)node->type16wiggles.p;
1165 s16->period = make_linetype_atlas_row(dash,ndash,zig,nzig,uv_row,tse_row);
1166 }
1167 MARK_NODE_COMPILED
1168}
1169int get_GLSL_max_version();
1170void render_LineProperties (struct X3D_LineProperties *node) {
1171/*
1172 Apr 2020 re-implementation
1173 https://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/shape.html#LineProperties
1174 https://isotc.iso.org/livelink/livelink/fetch/-8916524/8916549/8916590/6208440/class_pages/linetype.html
1175 - ISO linetypes referred to in specs
1176 http://jcgt.org/published/0002/02/08/paper.pdf
1177 http://jcgt.org/published/0002/02/08/
1178 - FORMULA this researcher used an atlas to store / communicated linetype information to frag shader
1179 x but doesn't show zig-zag lines
1180 x doesn't show arrow, round start/ends - but has some formula for dash ends
1181 * sends triangles
1182 Our Modified approach Apr 2020:
1183 - we free-load off desktop opengl GL_LINE_STRIP which internally generates triangles
1184 - desktop maximum GL_LINE_STRIP linewidth is about 10 pixels
1185 -
1186 - when doing a fancy line,we boost glLineWidth to 10, and frag shader discards unwanted fragments
1187 - instead of texture atlas using full floats (x tried but didn't work),
1188 - we send linetype-specific float arrays as uniforms each frame render of a linetype
1189 - frag programmatically adds arrow / round end according to uniforms and flat info
1190 Future suggestions:
1191 - send mitered, depth mapped, near-plane-clipped triangles (instead of GL_LINE_STRIP)
1192 https://mattdesl.svbtle.com/drawing-lines-is-hard
1193 - start-of-linesegment phase offset for pattern continuity across corners (as FORMULA author does
1194 - shader anti-aliasing for finer rendering of thin lines (Apr 2020 did no anti-aliasing)
1195 - test on mobile/GLESX/ANGLE for shader versioning
1196
1197 VERTEX SHADER details
1198 1) "FLAT INTERPOLATION QUALIFIER"
1199 There's something called a Provoking Vertex and used with 'flat' interpolation qualfier in GLSL vertex shaders
1200 https://www.khronos.org/opengl/wiki/Primitive#Provoking_vertex
1201 when using flat-shading on output variables,
1202 every fragment generated by that primitive gets it's input from the output of the provoking vertex.
1203 the default is GL_LAST_VERTEX_CONVENTION.
1204 - for GL_LINE_STRIP i+1 (means its the 2nd vertex's flat outputs that the frag shader gets along 1-2 line segment)
1205 Alternate to using flat: even/odd (not attempted)
1206 -- float index attributearray aka findex with even/odd mod/div in vertex shader so 2 varyings appear flat,
1207 -- and frag needs to choose the right one
1208 2) arrow / round ends > linestrip start/end segment flagging methods:
1209 a) if sending both next and prev vertex attribute arrays
1210 linestrip_start = curr == prev? start : curr == next ? end : middle
1211 x doesn't work - provoking vertex can't get at prev-prev
1212 b) else if sending uniforms u_linestrip_start, u_linestrip_end
1213 same logic as a) except prev == u_linestrip_start or _curr == u_linestrip_end
1214 x the way we send linestrips in polyline chunks/segments makes this very awkward
1215 c) else if using findex (float index, float count) => flat_start_end
1216 our chosem method - vertex shader checks findex == 1 ? start; if findex == count -1 ? end
1217 - then send boolean or round()able float 1/0 as flat, or using even/odd technqiue, to frag shader
1218
1219*/
1220 //print_style1();
1221 COMPILE_IF_REQUIRED
1222
1223 if (node->applied) {
1224 //ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
1225 int linetype_capable_shader = get_GLSL_max_version() >= 130;
1226
1227 if (node->linewidthScaleFactor > 1.0 || !linetype_capable_shader) {
1228 struct matpropstruct *me;
1229 me= getAppearanceProperties();
1230 me->pointSize = node->linewidthScaleFactor ? node->linewidthScaleFactor : 1.0f;
1231 //me->linetype = node->linetype;
1232 glLineWidth(me->pointSize);
1233 }
1234 if(node->linetype > 1 && linetype_capable_shader){
1235 struct matpropstruct *me;
1236 me= getAppearanceProperties();
1237 //me->pointSize = node->linewidthScaleFactor;
1238 me->linetype = node->linetype;
1239 //if no atlas
1240 // create atlas
1241 if(linetype_atlas_uv == NULL){
1242 make_linetype_atlas(me);
1243 }
1244 if(linetype_atlas_uv){
1245 send_linetype_atlas_to_shader(node,me);
1246 }
1247 me->lineperiod = linetypes[node->linetype - 1].period;
1248 me->linewidth = node->linewidthScaleFactor;
1249 me->pointSize = 10.0f; //for GL_LINE_STRIP method, we let opengl make the triangles -plenty wide- and we discard frags to get linewidth
1250 glLineWidth(me->pointSize);
1251 }
1252 }
1253}
1254enum {
1255PP_COLORMODE_NONE = 0, //GL_POINTS - no texture coords or image sampler
1256PP_COLORMODE_POINT = 1, //samples any texture for alpha
1257PP_COLORMODE_TEXTURE = 2,
1258PP_COLORMODE_BOTH = 3, //specs default, perl default
1259} pointproperties_colormodes;
1260//enum {
1261//PM_NONE = 0, //reserve 0 for render_PointSet to thunk to opengl GL_POINTS when no PointProperties node
1262//PM_SCREEN = 1,
1263//PM_OBJECT = 2,
1264//PM_FANCY = 3,
1265//} pointproperties_pointmethod;
1266//markerType == 1 GL_POINTS, else draw a rectangle with texture
1267void compile_PointProperties ( struct X3D_PointProperties *node) {
1268 //a few conditions for calling update_node() to set the change flag in parents:
1269 //1) the change you are doing may need a different shader permuntation compiled
1270 //2) its the parent who's change flag triggers a shader permutation selection
1271 // both those conditions apply here - we may switch between OpnGL GL_POINTS rendering, and our own
1272 // GL_TRIANGLES approach, which needs a different shader permutation
1273 // and its the parent-parent - Shape - whose change flag triggers shape_compile which does the shader permutation.
1274 update_node(X3D_NODE(node));
1275
1276 node->_colormode = PP_COLORMODE_BOTH; // PP_COLORMODE_POINT; // 3;
1277 //H: we are now supposed to bootstrap _colormode from available appearance nodes, such as ColorNode? Fog? Texture?
1278 //if(!strcmp(node->colorMode->strptr,"POINT_COLOR")) node->_colormode = PP_COLORMODE_POINT; //1 default POINT_COLOR
1279 //if(!strcmp(node->colorMode->strptr,"TEXTURE_COLOR")) node->_colormode = PP_COLORMODE_TEXTURE; //2
1280 //if(!strcmp(node->colorMode->strptr,"TEXTURE_AND_POINT_COLOR")) node->_colormode = PP_COLORMODE_BOTH; //3
1281 {
1282 float *attenuation = node->_attenuation.c;
1283 //attenuation[0] = node->pointSizeAttenuation.n > 0 ? attenuation[0] = node->pointSizeAttenuation.p[0] : 1.0f;
1284 //attenuation[1] = node->pointSizeAttenuation.n > 1 ? attenuation[1] = node->pointSizeAttenuation.p[1] : 0.0f;
1285 //attenuation[2] = node->pointSizeAttenuation.n > 0 ? attenuation[2] = node->pointSizeAttenuation.p[2] : 0.0f;
1286 attenuation[0] = node->attenuation.n > 0 ? attenuation[0] = node->attenuation.p[0] : 1.0f;
1287 attenuation[1] = node->attenuation.n > 1 ? attenuation[1] = node->attenuation.p[1] : 0.0f;
1288 attenuation[2] = node->attenuation.n > 0 ? attenuation[2] = node->attenuation.p[2] : 0.0f;
1289 }
1290 {
1291 int SCREENSCALE = APPROX(node->_attenuation.c[0],1.0f) && APPROX(node->_attenuation.c[1],0.0f) && APPROX(node->_attenuation.c[2],0.0f) ? TRUE : FALSE; //no fancy attenuation
1292 SCREENSCALE = SCREENSCALE && APPROX(node->pointSizeMinValue,node->pointSizeMaxValue); // min = max, no fancy scaling?
1293 //SCREENSCALE = SCREENSCALE && node->_colormode == 1; //no fancy texturing?
1294 int OBJECTSCALE = APPROX(node->_attenuation.c[0],0.0f) && APPROX(node->_attenuation.c[1],1.0f) && APPROX(node->_attenuation.c[2],0.0f) ? TRUE : FALSE; //attenuates with distance
1295 OBJECTSCALE = OBJECTSCALE && APPROX(node->pointSizeMinValue,0.0F) && node->pointSizeScaleFactor && node->pointSizeMaxValue > 10.0f*node->pointSizeScaleFactor;
1296 node->_pointMethod = SCREENSCALE ? PM_SCREEN : OBJECTSCALE ? PM_OBJECT : PM_FANCY;
1297
1298 }
1299 MARK_NODE_COMPILED
1300};
1301void render_PointProperties (struct X3D_PointProperties *node) {
1302 // https://www.web3d.org/specifications/X3Dv4Draft/ISO-IEC19775-1v4-WD1/
1303 // - web3d v4 draft specs for new PointProperties node
1304 COMPILE_IF_REQUIRED
1305
1306 struct matpropstruct *me;
1307 me= getAppearanceProperties();
1308 me->pointSize = node->pointSizeScaleFactor > 0.0f ? node->pointSizeScaleFactor : 1.0f;
1309 //glPointSize(me->pointSize); //sent later frmm opegl_utils.c
1310 veccopy3f(me->pointsizeAttenuation,node->_attenuation.c);
1311 me->pointColorMode = node->_colormode;
1312 me->pointsizeRange[0] = node->pointSizeMinValue;
1313 me->pointsizeRange[1] = node->pointSizeMaxValue;
1314 me->pointMethod = node->_pointMethod;
1315}
1316
1317
1318int getImageChannelCountFromTTI(struct X3D_Node *appearanceNode ){
1319 //int channels, imgalpha, isLit, isUnlitGeometry, hasColorNode, whichShapeColorShader;
1320 int channels, imgalpha, haveTexture;
1321 struct X3D_Appearance *appearance;
1322 channels = 0;
1323 imgalpha = 0;
1324 haveTexture = 0;
1325 POSSIBLE_PROTO_EXPANSION(struct X3D_Appearance*,appearanceNode,appearance);
1326
1327 if(appearance){
1328 //do I need possible proto expansione of texture, or will compile_appearance have done that?
1329 if(appearance->texture){
1330 //mutli-texture? should loop over multitexture->texture nodes?
1331 // --to get to get max channels or hasAlpha, or need channels for each one?
1332 // H0: if nay of the multitextures has an alpha, then its alpha replaces material alpha
1333 // H1: multitexture alpha is only for composing textures, assumed to take material alpha
1334 if(appearance->texture->_nodeType == NODE_MultiTexture ||
1335 appearance->texture->_nodeType == NODE_ComposedTexture3D ){
1336 int k;
1337 struct Multi_Node * mtex = NULL;
1338 switch(appearance->texture->_nodeType){
1339 case NODE_MultiTexture: mtex = &((struct X3D_MultiTexture*)appearance->texture)->texture; break;
1340 case NODE_ComposedTexture3D: mtex = &((struct X3D_ComposedTexture3D*)appearance->texture)->texture; break;
1341 }
1342 channels = 0;
1343 imgalpha = 0;
1344 if(mtex)
1345 for(k=0;k<mtex->n;k++){
1346 textureTableIndexStruct_s *tti = getTableTableFromTextureNode(mtex->p[k]);
1347 haveTexture = 1;
1348 if(tti){
1349 //new Aug 6, 2016, check LoadTextures.c for your platform channel counting
1350 //NoImage=0, Luminance=1, LuminanceAlpha=2, RGB=3, RGBA=4
1351 //PROBLEM: if tti isn't loaded -with #channels, alpha set-, we don't want to compile child
1352 channels = max(channels,tti->channels);
1353 imgalpha = max(tti->hasAlpha,imgalpha);
1354 //if(tti->status < TEX_NEEDSBINDING)
1355 // printf("."); //should Unmark node compiled
1356 }
1357 }
1358 }else{
1359 //single texture:
1360 textureTableIndexStruct_s *tti = getTableTableFromTextureNode(appearance->texture);
1361 haveTexture = 1;
1362 if(tti){
1363 //new Aug 6, 2016, check LoadTextures.c for your platform channel counting
1364 //NoImage=0, Luminance=1, LuminanceAlpha=2, RGB=3, RGBA=4
1365 //PROBLEM: if tti isn't loaded -with #channels, alpha set-, we don't want to compile child
1366 channels = tti->channels;
1367 imgalpha = tti->hasAlpha;
1368 //if(tti->status < TEX_NEEDSBINDING)
1369 // printf("."); //should Unmark node compiled
1370 }
1371 }
1372 }
1373 }
1374 channels = haveTexture ? channels : 0; //-1;
1375 return channels;
1376}
1377
1378void initialize_fw_MaterialParameters(struct fw_MaterialParameters *mat){
1379 memset(mat,0,sizeof(struct fw_MaterialParameters));
1380 mat->ambient = .2f;
1381 mat->shininess = .2f;
1382 vecset3f(mat->diffuse,1.0f,1.0f,1.0f); //saves boolean math in shader if at 1
1383 vecset3f(mat->baseColor,1.0f,1.0f,1.0f);
1384 mat->occlusion = 1.0f;
1385 mat->normalScale = 1.0f;
1386 vecset3f(mat->emissive, 1.0f, .8f, 1.0f);
1387 mat->type = MAT_NONE; //Q MAT_UNLIT ? June 2022: MAT_NONE means use Gouraud (vertex shader) color. Unlit means use unlit.emissive. What's the diff? Background not working with Unlit.
1388}
1389void initialize_front_and_back_material_params(){
1390 ppComponent_Shape p;
1391 ttglobal tg = gglobal();
1392 p = (ppComponent_Shape)tg->Component_Shape.prv;
1393
1394 initialize_fw_MaterialParameters(&p->appearanceProperties.fw_FrontMaterial);
1395 initialize_fw_MaterialParameters(&p->appearanceProperties.fw_BackMaterial);
1396}
1397void initialize_non_material_appearance_parameters() {
1398 //zero /clear from last draw (so appearance of one node doesnt show up in another node)
1399 memset(getAppearanceProperties(), 0, sizeof(struct matpropstruct));
1400}
1401
1402//unsigned int getShaderFlags();
1403shaderflagsstruct getShaderFlags();
1404struct X3D_Node *getFogParams();
1405void update_effect_uniforms();
1406int setupShaderB();
1407void textureTransform_start();
1408void reallyDraw();
1409void reallyDrawOnce();
1410void sendProjectorInfo();
1411static struct X3D_Shape* wrap_shape = NULL;
1412void push_shape(struct X3D_Shape* node) {
1413 wrap_shape = node;
1414}
1415void pop_shape() {
1416 wrap_shape = NULL;
1417}
1418struct X3D_Shape* peek_shape() {
1419 return wrap_shape;
1420}
1421void* peek_humanoid_skinCoord();
1422struct X3D_HAnimHumanoid* peek_humanoid();
1423void sendSkinningInfo();
1424void clearSkinningInfo();
1425void PRINT_GL_ERROR(GLenum _global_gl_err);
1426void clearDraw();
1427int peek_group_visible();
1428void child_Shape (struct X3D_Shape *node) {
1429 struct X3D_Node *tmpNG;
1430 //int channels;
1431 struct X3D_Virt *v;
1432
1433 ppComponent_Shape p;
1434 ttglobal tg = gglobal();
1435
1436 COMPILE_IF_REQUIRED
1437
1438 /* JAS - if not collision, and render_geom is not set, no need to go further */
1439 /* printf ("child_Shape vp %d geom %d light %d sens %d blend %d prox %d col %d\n",
1440 render_vp,render_geom,render_light,render_sensitive,render_blend,render_proximity,render_collision); */
1441
1442 if(!(node->geometry)) { return; }
1443
1444 if((renderstate()->render_collision) || (renderstate()->render_sensitive) || (renderstate()->render_other) || (renderstate()->render_depth)) {
1445 /* only need to forward the call to the child */
1446 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *,node->geometry,tmpNG);
1447 if (renderstate()->render_depth) {
1448 if (node->castShadow) {
1449 PRINT_GL_ERROR_IF_ANY("child_shape depth start");
1450 s_shader_capabilities_t* scap;
1451 shaderflagsstruct shader_requirements;
1452 memset(&shader_requirements, 0, sizeof(shaderflagsstruct));
1453 shader_requirements.depth = TRUE;
1454 scap = getMyShaders(shader_requirements);
1455 enableGlobalShader(scap);
1456 sendMatriciesToShader(scap); //send matrices
1457 render_node(tmpNG);
1458 if (peek_group_visible()) { //v4 X3DGroupingNode .visible
1459 //reallyDraw();
1460 reallyDrawOnce();
1461 }
1462 clearDraw(); //other shaders like cursorDraw, extent6f_draw need this stack cleared
1463 finishedWithGlobalShader();
1464
1465 PRINT_GL_ERROR_IF_ANY("child_shape depth end");
1466 }
1467 }
1468 else {
1469 render_node(tmpNG);
1470 }
1471 return;
1472 }
1473 if ((renderstate()->render_cube) && hasGeneratedCubeMapTexture((struct X3D_Appearance*)node->appearance))
1474 return; //don't draw if this node uses a generatedcubemaptexture and its a cubemaptexture generation pass; is there more optimal place to do this?
1475
1476 p = (ppComponent_Shape)tg->Component_Shape.prv;
1477 PRINT_GL_ERROR_IF_ANY("child_shape START");
1478
1479 /* initialization. This will get overwritten if there is a texture in an Appearance
1480 node in this shape (see child_Appearance) */
1481 tg->RenderFuncs.last_texture_type = NOTEXTURE;
1482 tg->RenderFuncs.shapenode = node;
1483
1484 /* copy the material stuff in preparation for copying all to the shader */
1485 initialize_non_material_appearance_parameters(); //zero /clear from last draw
1486 initialize_front_and_back_material_params();
1487
1488
1489 prep_BBox((struct BBoxFields*)&node->bboxCenter);
1490
1491 /* now, are we rendering blended nodes or normal nodes?*/
1492 if (renderstate()->render_blend == (node->_renderFlags & VF_Blend)) {
1493 int isUserShader; //colorSource, isLit, alphaSource,
1494 s_shader_capabilities_t *scap;
1495 //unsigned int shader_requirements;
1496 shaderflagsstruct shader_requirements;
1497 memset(&shader_requirements,0,sizeof(shaderflagsstruct));
1498 PRINT_GL_ERROR_IF_ANY("child_shape before render_material_subnodes");
1499
1500 //prep_Appearance
1501 RENDER_MATERIAL_SUBNODES(node->appearance); //child_Appearance
1502
1503 /* enable the shader for this shape */
1504 //ConsoleMessage("turning shader on %x",node->_shaderTableEntry);
1505
1506 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->geometry,tmpNG);
1507
1508
1509
1510 shader_requirements.base = node->_shaderflags_base; //_shaderTableEntry;
1511 //is it a humanoid skinning pass?
1512 void* hsc = peek_humanoid_skinCoord(); //only pushed if GPU skinning
1513 int do_skinning = FALSE;
1514 if (hsc) {
1515 //does the geometry use the humanoid.skinCoord node?
1516 struct X3D_PolyRep* pr = (struct X3D_PolyRep*)tmpNG->_intern;
1517 if (pr && (pr->itype == 1 || pr->itype == 2)) {
1518 void* coordnode = pr->coordinate_node;
1519 if(pr->itype == 1) {
1520 struct X3D_LineRep* lr = (struct X3D_LineRep*)tmpNG->_intern;
1521 coordnode = lr->coordinate_node;
1522 }
1523 if (coordnode && coordnode == hsc) {
1524 shader_requirements.base |= SKINNING_SHADER;
1525 do_skinning = TRUE;
1526 struct X3D_HanimRep* hr = (struct X3D_HanimRep*)peek_humanoid()->_intern;
1527 if(hr->bo_dindex) shader_requirements.base |= DISPLACER_SHADER;
1528 }
1529 }
1530 }
1531
1532 shader_requirements.effects = node->_shaderflags_effects;
1533 shader_requirements.usershaders = node->_shaderflags_usershaders;
1534 isUserShader = shader_requirements.usershaders ? TRUE : FALSE; // >= USER_DEFINED_SHADER_START ? TRUE : FALSE;
1535 //if(!p->userShaderNode || !(shader_requirements >= USER_DEFINED_SHADER_START)){
1536 if(!isUserShader){
1537 //for Luminance and Luminance-Alpha images, we have to tinker a bit in the Vertex shader
1538 // New concept of operations Aug 26, 2016
1539 // in the specs there are some things that can replace other things (but not the reverse)
1540 // Texture can repace CPV, diffuse and 111
1541 // CPV can replace diffuse and 111
1542 // diffuse can replace 111
1543 // Texture > CPV > Diffuse > (1,1,1)
1544 // so there's a kind of order / sequence to it.
1545 // There can be a flag at each step saying if you want to replace the prior value (otherwise modulate)
1546 // Diffuse replacing or modulating (111) is the same thing, no flag needed
1547 // Therefore we need at most 2 flags for color:
1548 // TEXTURE_REPLACE_PRIOR and CPV_REPLACE_PRIOR.
1549 // and other flag for alpha: ALPHA_REPLACE_PRIOR (same as ! WANT_TEXALPHA)
1550 // if all those are false, then its full modulation.
1551 // our WANT_LUMINANCE is really == ! TEXTURE_REPLACE_PRIOR
1552 // we are missing a CPV_REPLACE_PRIOR, or more precisely this is a default burned into the shader
1553
1554 int channels,modulation,scenefile_specversion;
1555 //modulation:
1556 //- for Castle-style full-modulation of texture x CPV x mat.diffuse
1557 // and texalpha x (1-mat.trans), set 2
1558 //- for specs table 17-2 RGB Tex replaces CPV with modulation
1559 // of table 17-2 entries with mat.diffuse and (1-mat.trans) set 1
1560 //- for specs table 17-3 as written and ignoring modulation sentences
1561 // so CPV replaces diffuse, texture replaces CPV and diffuse- set 0
1562 // testing: KelpForest SharkLefty.x3d has CPV, ImageTexture RGB, and mat.diffuse
1563 // 29C.wrl has mat.transparency=1 and LumAlpha image, modulate=0 shows sphere, 1,2 inivisble
1564 // test all combinations of: modulation {0,1,2} x shadingStyle {gouraud,phong}: 0 looks bright texture only, 1 texture and diffuse, 2 T X C X D
1565 channels = getImageChannelCountFromTTI(node->appearance);
1566 // specversion <= 330 use v3.3 table 17-3
1567 // specversion >= 400 modulate everything
1568 scenefile_specversion = X3D_PROTO(node->_executionContext)->__specversion;
1569 // p->modulation; 0)scenefile specversion 1)v3.3- 2) v4.0+ (dug9 Mar 28, 2020)
1570
1571 switch(fwl_get_modulation()){
1572 case 0:
1573 //allows mixing modulations depending on which inline/proto/scenefile the shape was defined in
1574 modulation = scenefile_specversion >= 400 ? TRUE : FALSE;
1575 break;
1576 case 1:
1577 modulation = FALSE; break;
1578 case 2:
1579 modulation = TRUE; break;
1580 default:
1581 modulation = FALSE;
1582 }
1583 if(modulation == TRUE){
1584 shader_requirements.base |= MODULATE_TEXTURE; //web3d most browsers default: texture replaces prior by default
1585 }
1586 if(!channels || (channels == 1 || channels == 3))
1587 shader_requirements.base |= MODULATE_ALPHA; //A = (1-TM)
1588 if(channels && (channels == 1 || channels == 2) )
1589 shader_requirements.base |= MODULATE_COLOR; //ODrgb = IT x ICrgb
1590
1591 //getShaderFlags() are from non-leaf-node shader influencers:
1592 // fog, local_lights, clipplane, Effect/EffectPart (for CastlePlugs) ...
1593 // - as such they may be different for the same shape node DEF/USEd in different branches of the scenegraph
1594 // - so they are ORd here before selecting a shader permutation
1595 shader_requirements.base |= getShaderFlags().base;
1596 shader_requirements.effects |= getShaderFlags().effects;
1597 //if(shader_requirements & FOG_APPEARANCE_SHADER)
1598 // printf("fog in child_shape\n");
1599 }
1600 //printf("child_shape shader_requirements base %d effects %d user %d\n",shader_requirements.base,shader_requirements.effects,shader_requirements.usershaders);
1601 scap = getMyShaders(shader_requirements);
1602 enableGlobalShader(scap);
1603 //enableGlobalShader (getMyShader(shader_requirements)); //node->_shaderTableEntry));
1604 PRINT_GL_ERROR_IF_ANY("AFTER getMyShaders");
1605
1606 //see if we have to set up a TextureCoordinateGenerator type here
1607 if (tmpNG && tmpNG->_intern && tmpNG->_intern->itype == 2) {
1608 struct X3D_PolyRep* tmppr = (struct X3D_PolyRep*) tmpNG->_intern;
1609 if (tmppr->tcoordtype == NODE_TextureCoordinateGenerator) {
1610 getAppearanceProperties()->texCoordGeneratorType = tmppr->texgentype;
1611 //ConsoleMessage("shape, matprop val %d, geom val %d",getAppearanceProperties()->texCoordGeneratorType, node->geometry->_intern->texgentype);
1612 }
1613 }
1614 //userDefined = (whichOne >= USER_DEFINED_SHADER_START) ? TRUE : FALSE;
1615 //if (p->userShaderNode != NULL && shader_requirements >= USER_DEFINED_SHADER_START) {
1616 if(isUserShader && p->userShaderNode){
1617 //we come in here right after a COMPILE pass in APPEARANCE which renders the shader, which sets p->userShaderNode
1618 //if nothing changed with appearance -no compile pass- we don't come in here again
1619 //ConsoleMessage ("have a shader of type %s",stringNodeType(p->userShaderNode->_nodeType));
1620 switch (p->userShaderNode->_nodeType) {
1621 case NODE_ComposedShader:
1622 if (X3D_COMPOSEDSHADER(p->userShaderNode)->isValid) {
1623 if (!X3D_COMPOSEDSHADER(p->userShaderNode)->_initialized) {
1624 PRINT_GL_ERROR_IF_ANY("BEFORE send fields");
1625 sendInitialFieldsToShader(p->userShaderNode);
1626 PRINT_GL_ERROR_IF_ANY("AFTER send fields");
1627 }
1628 }
1629 break;
1630 case NODE_ProgramShader:
1631 if (X3D_PROGRAMSHADER(p->userShaderNode)->isValid) {
1632 if (!X3D_PROGRAMSHADER(p->userShaderNode)->_initialized) {
1633 sendInitialFieldsToShader(p->userShaderNode);
1634 }
1635 }
1636
1637 break;
1638 case NODE_PackagedShader:
1639 if (X3D_PACKAGEDSHADER(p->userShaderNode)->isValid) {
1640 if (!X3D_PACKAGEDSHADER(p->userShaderNode)->_initialized) {
1641 sendInitialFieldsToShader(p->userShaderNode);
1642 }
1643 }
1644
1645 break;
1646 }
1647 }
1648 //update effect field uniforms
1649 if(shader_requirements.effects){
1650 update_effect_uniforms();
1651 }
1652
1653
1654 #ifdef SHAPEOCCLUSION
1655 beginOcclusionQuery((struct X3D_VisibilitySensor*)node,renderstate()->render_geom); //BEGINOCCLUSIONQUERY;
1656 #endif
1657 //call stack to get from child_shape to sendMaterialsToShader and sendLightInfo as of Aug 13, 2016
1658 //child_shape
1659 //- render_node
1660 //-- render_indexedfaceset (or other specific shape)
1661 //--- render_polyrep
1662 //---- sendArraysToGPU (or sendElementsToGPU)
1663 //----- setupShader
1664 //------ sendMaterialsToShader
1665 // Uniforms being sent for materials and hatching
1666 //--------- sendLightInfo
1667 // Uniforms sent for lights
1668 //----- glDrawArrays/glDrawElements
1669
1670 //we have a shader, now start sending it data
1671 //clear_bound_textures(); //testing only
1672 //PRINT_GL_ERROR_IF_ANY("BEFORE clear_textureUnit_used");
1673 clear_textureUnit_used(); //appearance.texture material.textureXXX, PTMs.texture all need TEXTURE0+ XXX, where xxx starts from 0
1674 //PRINT_GL_ERROR_IF_ANY("AFTER clear_textureUnit_used");
1675 clear_material_samplers(); //PTM and material.textureXXX share frag shader sampler2D textureUnit[16] array
1676 //PRINT_GL_ERROR_IF_ANY("AFTER clear_material_samplers");
1677 clear_materialparameters_per_draw_counts(); //especially diffuse texture counts which both appearance and material share
1678 //PRINT_GL_ERROR_IF_ANY("AFTER clear materialParameters");
1679 textureTransform_start(); //send regular appearance.textures to shader
1680 sendProjectorInfo();
1681 //PRINT_GL_ERROR_IF_ANY("BEFORE setupShaderB");
1682 setupShaderB(); //send materials, fill patters miscalaneous to shader
1683 //print_bound_textures("s"); //testing only, uncomment clear_bound_textues too
1684 //are we skinning? if so send skinning matrices and skin weights
1685 if (do_skinning) sendSkinningInfo();
1686
1687 //PRINT_GL_ERROR_IF_ANY("BEFORE render node");
1688 push_shape(node);
1689 render_node(tmpNG);
1690 //PRINT_GL_ERROR_IF_ANY("AFTER render node");
1691
1692
1693 //printf("%s",stringNodeType(tmpNG->_nodeType));
1694 //solid TRUE/FALSE on geom controls if backface culling
1695 if(peek_group_visible()){ //v4 X3DGroupingNode .visible
1696 PRINT_GL_ERROR_IF_ANY("child_shape before reallyDrawOnce");
1697 //reallyDraw();
1698 reallyDrawOnce();
1699 //PRINT_GL_ERROR_IF_ANY("child_shape after reallyDrawOnce");
1700 static int err_count = 0;
1701 if (err_count < 10) {
1702 //just 10 reports, then end user gets the idea
1703 GLenum _global_gl_err = glGetError();
1704 while (_global_gl_err != GL_NONE && err_count < 10) {
1705 PRINT_GL_ERROR(_global_gl_err);
1706 printf(" here: %s (%s:%d)\n", "child_shape after reallyDrawOnce", "Component_Shape", __LINE__);
1707 _global_gl_err = glGetError();
1708 err_count++;
1709 }
1710 }
1711
1712 }
1713 pop_shape();
1714 clearDraw(); //other shaders like cursorDraw, extent6f_draw need this stack cleared
1715 if (do_skinning) clearSkinningInfo();
1716 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, 0);
1717 FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
1718 textureTransform_end();
1719
1720 #ifdef SHAPEOCCLUSION
1721 endOcclusionQuery((struct X3D_VisibilitySensor*)node,renderstate()->render_geom); //ENDOCCLUSIONQUERY;
1722 #endif
1723
1724 //fin_Appearance
1725 if(node->appearance){
1726 struct X3D_Appearance *tmpA;
1727 POSSIBLE_PROTO_EXPANSION(struct X3D_Appearance *,node->appearance,tmpA);
1728 if(tmpA->effects.n)
1729 fin_sibAffectors(X3D_NODE(tmpA),&tmpA->effects);
1730 }
1731
1732 }
1733
1734 /* any shader turned on? if so, turn it off */
1735
1736 //ConsoleMessage("turning shader off");
1737 finishedWithGlobalShader();
1738 //p->material_twoSided = NULL;
1739 //p->material_oneSided = NULL;
1740 p->userShaderNode = NULL;
1741 tg->RenderFuncs.shapenode = NULL;
1742
1743 /* load the identity matrix for textures. This is necessary, as some nodes have TextureTransforms
1744 and some don't. So, if we have a TextureTransform, loadIdentity */
1745
1746 if (p->this_textureTransform) {
1747 p->this_textureTransform = NULL;
1748 FW_GL_MATRIX_MODE(GL_TEXTURE);
1749 FW_GL_LOAD_IDENTITY();
1750 FW_GL_MATRIX_MODE(GL_MODELVIEW);
1751 }
1752
1753 /* LineSet, PointSets, set the width back to the original. */
1754 {
1755 float gl_linewidth = tg->Mainloop.gl_linewidth;
1756 glLineWidth(gl_linewidth);
1757 p->appearanceProperties.pointSize = gl_linewidth;
1758 }
1759
1760 /* did the lack of an Appearance or Material node turn lighting off? */
1761 LIGHTING_ON;
1762
1763 /* turn off face culling */
1764 DISABLE_CULL_FACE;
1765
1766 fin_BBox((struct X3D_Node*)node,(struct BBoxFields*)&node->bboxCenter,FALSE);
1767 PRINT_GL_ERROR_IF_ANY("child_shape END");
1768
1769}
1770
1771void compile_Shape (struct X3D_Shape *node) {
1772 long long whichAppearanceShader = 0;
1773 long long whichShapeColorShader = 0;
1774 long long whichShapeFogShader = 0;
1775 bool isUnlitGeometry = false;
1776 int hasTextureCoordinateGenerator = 0;
1777 long long whichUnlitGeometry = 0;
1778 struct X3D_Node *tmpN = NULL;
1779 struct X3D_Node *tmpG = NULL;
1780 // struct X3D_Appearance *appearance = NULL;
1781 int userDefinedShader = 0;
1782// int colorSource, alphaSource, channels, isLit;
1783
1784
1785 // ConsoleMessage ("**** Compile Shape ****");
1786
1787
1788 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->geometry,tmpG);
1789 whichShapeColorShader = getShapeColourShader(tmpG);
1790 whichShapeFogShader = getShapeFogShader(tmpG);
1791
1792 isUnlitGeometry = getIfLinePoints(tmpG);
1793 hasTextureCoordinateGenerator = getShapeTextureCoordGen(tmpG);
1794
1795 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->appearance,tmpN);
1796
1797
1798 /* first - does appearance have a shader node? */
1799 userDefinedShader = hasUserDefinedShader(tmpN);
1800
1801 //Aug 26 2016 change: don't fiddle around with flags here, rather report the state of the node
1802 // - then do any fiddling in child_shape, when we have the channel count and modulation flag
1803 if(isUnlitGeometry)
1804 whichUnlitGeometry = HAVE_LINEPOINTS_COLOR;
1805 whichAppearanceShader = getAppearanceShader(tmpN);
1806
1807 /* in case we had no appearance, etc, we do the bland NO_APPEARANCE_SHADER */
1808 //node->_shaderTableEntry=
1809 node->_shaderflags_base = (whichShapeColorShader | whichShapeFogShader | whichAppearanceShader |
1810 hasTextureCoordinateGenerator | whichUnlitGeometry ); //| userDefinedShader);
1811 node->_shaderflags_usershaders = userDefinedShader;
1812 node->_shaderflags_effects = 0;
1813
1814
1815 //if (node->_shaderTableEntry == NOTHING)
1816 // node->_shaderTableEntry = NO_APPEARANCE_SHADER;
1817
1818 if (node->_shaderflags_base == NOTHING)
1819 node->_shaderflags_base = NO_APPEARANCE_SHADER;
1820
1821
1822 //printf ("compile_Shape, node->_shaderTableEntry is %x\n",node->_shaderTableEntry);
1823
1824 MARK_NODE_COMPILED
1825}
1826static struct X3D_Shape *shape = NULL;
1827static struct X3D_Appearance* appearance = NULL;
1828static struct X3D_Material* material = NULL;
1829void wrap_Shape(struct X3D_Node* node) {
1830 //if there's a naked geometry node with no Shape wrapping it
1831 // this function is called by render to wrap with a generic shape and render the geom
1832 if (!shape) shape = createNewX3DNode(NODE_Shape);
1833 shape->_executionContext = node->_executionContext;
1834 if (!appearance) appearance = createNewX3DNode(NODE_Appearance);
1835 appearance->_executionContext = node->_executionContext;
1836 if (!material) material = createNewX3DNode(NODE_Material);
1837 material->_executionContext = node->_executionContext;
1838 shape->appearance = X3D_NODE(appearance);
1839 appearance->material = X3D_NODE(material);
1840 vecset3f(material->diffuseColor.c, .5f, .5f, .5f);
1841 shape->geometry = node;
1842 render_node(X3D_NODE(shape));
1843}
1844//void register_node_gc(void *node, void *p);
1845
1846void compile_TwoSidedMaterial (struct X3D_TwoSidedMaterial *node) {
1847 float *p;
1848 struct fw_MaterialParameters *q;
1849 /* verify that the numbers are within range */
1850 node->ambientIntensity = fclamp(node->ambientIntensity,0.0f,1.0f);
1851 node->shininess = fclamp(node->shininess,0.0f,1.0f);
1852 node->transparency = fclamp(node->transparency,0.0f,1.0f);
1853 fvecclamp3f(node->diffuseColor.c,0.0f,1.0f);
1854 fvecclamp3f(node->emissiveColor.c,0.0f,1.0f);
1855 fvecclamp3f(node->specularColor.c,0.0f,1.0f);
1856
1857 if(!node->_material){
1858 node->_material = malloc(sizeof(struct fw_MaterialParameters));
1859 register_node_gc(node,node->_material);
1860 }
1861 memset(node->_material,0,sizeof(struct fw_MaterialParameters));
1862 q = (struct fw_MaterialParameters *)node->_material;
1863 vecset3f(q->baseColor,1.0f,1.0f,1.0f); //saves boolean math in shader
1864 veccopy3f(q->diffuse,node->diffuseColor.c);
1865 veccopy3f(q->emissive,node->emissiveColor.c);
1866 veccopy3f(q->specular,node->specularColor.c);
1867 q->ambient = node->ambientIntensity;
1868 q->shininess = node->shininess;
1869 q->transparency = node->transparency;
1870 q->type = MAT_REGULAR;
1871
1872
1873 if (node->separateBackColor) {
1874 node->backAmbientIntensity = fclamp(node->backAmbientIntensity,0.0f,1.0f);
1875 node->backShininess = fclamp(node->backShininess,0.0f,1.0f);
1876 node->backTransparency = fclamp(node->backTransparency,0.0f,1.0f);
1877 fvecclamp3f(node->backDiffuseColor.c,0.0f,1.0f);
1878 fvecclamp3f(node->backEmissiveColor.c,0.0f,1.0f);
1879 fvecclamp3f(node->backSpecularColor.c,0.0f,1.0f);
1880
1881 if(!node->_backMaterial){
1882 node->_backMaterial = malloc(sizeof(struct fw_MaterialParameters));
1883 register_node_gc(node,node->_backMaterial);
1884 }
1885 memset(node->_backMaterial,0,sizeof(struct fw_MaterialParameters));
1886 q = (struct fw_MaterialParameters *)node->_backMaterial;
1887 vecset3f(q->baseColor,1.0f,1.0f,1.0f); //saves boolean math in shader
1888 veccopy3f(q->diffuse,node->backDiffuseColor.c);
1889 veccopy3f(q->emissive,node->backEmissiveColor.c);
1890 veccopy3f(q->specular,node->backSpecularColor.c);
1891 q->ambient = node->backAmbientIntensity;
1892 q->shininess = node->backShininess;
1893 q->transparency = node->backTransparency;
1894 q->type = MAT_REGULAR;
1895
1896 } else {
1897 /* just copy the front materials to the back */
1898 if(!node->_backMaterial){
1899 node->_backMaterial = malloc(sizeof(struct fw_MaterialParameters));
1900 register_node_gc(node,node->_backMaterial);
1901 }
1902 memset(node->_backMaterial,0,sizeof(struct fw_MaterialParameters));
1903 memcpy(node->_backMaterial,node->_material,sizeof(struct fw_MaterialParameters));
1904 }
1905 MARK_NODE_COMPILED
1906}
1907
1908void render_TwoSidedMaterial (struct X3D_TwoSidedMaterial *node) {
1909
1910 COMPILE_IF_REQUIRED
1911 {
1912 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
1913 if (node != NULL) {
1914 memcpy (&p->appearanceProperties.fw_FrontMaterial, node->_material, sizeof (struct fw_MaterialParameters));
1915 memcpy (&p->appearanceProperties.fw_BackMaterial, node->_backMaterial, sizeof (struct fw_MaterialParameters));
1916 }
1917 }
1918}
1919
1920void compile_UnlitMaterial (struct X3D_UnlitMaterial *node) {
1921 struct X3D_Node **tnodes;
1922 struct fw_MaterialParameters *q;
1923 /* verify that the numbers are within range */
1924 node->transparency = fclamp(node->transparency,0.0f,1.0f);
1925 fvecclamp3f(node->emissiveColor.c,0.0f,1.0f);
1926 node->normalScale = fclamp(node->normalScale, 1.0f, 1.e9f); //1 to infinity
1927 if(!node->_material){
1928 node->_material = malloc(sizeof(struct fw_MaterialParameters));
1929 register_node_gc(node,node->_material);
1930 }
1931 memset(node->_material,0,sizeof(struct fw_MaterialParameters));
1932
1933 q = (struct fw_MaterialParameters *)node->_material;
1934 vecset3f(q->baseColor,1.0f,1.0f,1.0f); //saves boolean math in shader
1935 vecset3f(q->diffuse,1.0f,1.0f,1.0f); //saves boolean math in shader
1936 veccopy3f(q->emissive,node->emissiveColor.c);
1937 q->transparency = node->transparency;
1938 q->normalScale = node->normalScale;
1939 q->type = MAT_UNLIT;
1940
1941 //new v4 textures
1942 //iunit [0] normal [1] emissive [2] occlusion [3] diffuse OR base [4] shininess OR metallicRoughness [5] specular [6] ambient
1943 tnodes = q->textures;
1944 memset(tnodes,0,7*sizeof(void *));
1945 if(node->normalTexture)
1946 {
1947 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->normalTexture,tnodes[0]);
1948 if (tnodes[0]) q->map[0] = node->normalTextureMapping ? node->normalTextureMapping->strptr : NULL;
1949 }
1950 if(node->emissiveTexture)
1951 {
1952 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->emissiveTexture,tnodes[1]);
1953 if (tnodes[1]) q->map[1] = node->emissiveTextureMapping ? node->emissiveTextureMapping->strptr : NULL;
1954 }
1955 //int *cindex = q->cindex;
1956 //for (int i = 0; i < 7; i++) {
1957 // cindex[i] = 0;
1958 //
1959 // //cindex[0] = 0; //node->normalTextureChannel;
1960 // //cindex[1] = 0; //node->emissiveTextureChannel;
1961 //}
1962 q->nt = 0; //assume no material.texturexxx to start
1963 for(int i=0;i<7;i++){
1964 q->tcount[i] = 0; //default: no texture for this material function
1965 q->tstart[i] = q->nt; //shader: start looping over tindex where we left off, for tcount loops
1966 if(tnodes[i]){
1967 if(tnodes[i]->_nodeType == NODE_MultiTexture) {
1968 struct X3D_MultiTexture *mt = (struct X3D_MultiTexture*)tnodes[i];
1969 q->tcount[i] = mt->texture.n;
1970 q->nt += mt->texture.n;
1971 q->mt++;
1972 }else{
1973 //single texture
1974 q->nt++;
1975 q->tcount[i] = 1;
1976 }
1977 }
1978 }
1979 MARK_NODE_COMPILED
1980}
1981void render_UnlitMaterial (struct X3D_UnlitMaterial *node) {
1982 COMPILE_IF_REQUIRED
1983 {
1984 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
1985 if (node != NULL) {
1986 if(get_isBackMaterial()){
1987 memcpy (&p->appearanceProperties.fw_BackMaterial, node->_material, sizeof (struct fw_MaterialParameters));
1988 }else{
1989 memcpy (&p->appearanceProperties.fw_FrontMaterial, node->_material, sizeof (struct fw_MaterialParameters));
1990 }
1991 }
1992 }
1993}
1994
1995
1996/*
1997
1998PBR Physics Based Rendering
1999https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materials
2000- describes how to do BRDF calculations (don't I have a book on BRDF? with shaders?)
2001https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#appendix-b-brdf-implementation
2002- Appendix B shows the BRDF math, and link to example viewer implementation:
2003https://github.com/KhronosGroup/glTF-Sample-Viewer/
2004https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/master/src/shaders/metallic-roughness.frag
2005- implements BRDF in frag, including ifdefs for 'maps' vs scalars.
2006https://www.cs.virginia.edu/~jdl/bib/appearance/analytic%20models/schlick94b.pdf
2007- Schlick BRDF model
2008example x3dom:
2009https://github.com/x3dom/x3dom/blob/master/src/nodes/Shape/PhysicalMaterial.js
2010exmaple CGE:
2011https://github.com/castle-engine/castle-engine/blob/master/src/x3d/opengl/glsl/source/lighting_model_physical/shading_phong.fs
2012
2013H: specular-glossiness and metallic-roughness are different ways to declare the same thing
2014so only one is needed. And since web3d does specular-glossiness in the regular material, no need for it in the physical.
2015
2016PhysicalMaterialNode:
2017the textures are optional, and have specific packing of effects
2018occlusionRoughnessMetallicTexture (occlusion=R,Roughness=G,Metallic=B)
2019
2020There are a lot of (optional) textures with this, with the v4 extended Material node, and with PTM projective texture mapping.
2021IDEA: generalize what we did with PTM:
2022- have a generic list of sampler2D textureUnit[xx]
2023- and through a separate int32 array say which textureUnit goes with which texture.
2024That would allow combining PTM and (PhysicalMaterial or Matierial with textures)
2025-- in a flexible way that minimizes (GPU limited resource) sampler2Ds
2026
2027GPU textureUnits / samplers needed:
2028Gross: 7
2029max needed: 4 (assuming physics channel packing): normal, emissive, baseColor, occlusion-metallic-roughness
2030possible Array-ization assuming same widthxheight for all:
20311 samplerArray for the physics, 1 sampler2D for baseColorTexture
2032https://www.web3d.org/specifications/X3Dv4Draft/ISO-IEC19775-1v4-CD1/Part01/components/shape.html
203312.4.5 Material
2034texture channels-start-at
2035diffuse 0 (rgb)
2036emissive 0 (rgb)
2037specular 0 (rgb)
2038shininess 3 (.a, typically of specular texture)
2039occlusion 0 (.r single channel)
204012.4.6 PhysicalMaterial
2041texture channels-start-at
2042MetalicRoughness 2 (.b for metalic)
2043MetalicRoughness 1 (.g for roughness)
2044base 3 (.a) opacity
2045In this case you don't supply separate texture node for each field. Its assumed partly packed, the roughness, and metalic, in one image
2046
2047*/
2048void compile_PhysicalMaterial (struct X3D_PhysicalMaterial *node) {
2049 struct X3D_Node **tnodes;
2050 struct fw_MaterialParameters *q;
2051 /* verify that the numbers are within range */
2052 node->roughness = fclamp(node->roughness,0.0f,1.0f);
2053 node->metallic = fclamp(node->metallic,0.0f,1.0f);
2054 node->transparency = fclamp(node->transparency,0.0f,1.0f);
2055 node->occlusionStrength = fclamp(node->occlusionStrength, 0.0f, 1.0f);
2056 node->normalScale = fclamp(node->normalScale, 1.0f, 1.e9f); //one to infinity
2057 fvecclamp3f(node->baseColor.c,0.0f,1.0f);
2058 fvecclamp3f(node->emissiveColor.c,0.0f,1.0f);
2059
2060 if(!node->_material){
2061 node->_material = malloc(sizeof(struct fw_MaterialParameters));
2062 register_node_gc(node,node->_material);
2063 }
2064 memset(node->_material,0,sizeof(struct fw_MaterialParameters));
2065
2066 q = (struct fw_MaterialParameters *)node->_material;
2067 vecset3f(q->diffuse,1.0f,1.0f,1.0f); //saves boolean math in shader
2068 veccopy3f(q->baseColor,node->baseColor.c);
2069 veccopy3f(q->emissive,node->emissiveColor.c);
2070 q->metallic = node->metallic;
2071 q->roughness = node->roughness;
2072 q->transparency = node->transparency;
2073 q->occlusion = node->occlusionStrength;
2074 q->normalScale = node->normalScale;
2075 q->type = MAT_PHYSICAL;
2076
2077 //new v4 textures
2079 //iunit [0] normal [1] emissive [2] occlusion [3] diffuse OR base [4] shininess OR metallicRoughness [5] specular [6] ambient
2080 tnodes = q->textures;
2081 memset(tnodes,0,7*sizeof(void *));
2082 if(node->normalTexture)
2083 {
2084 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->normalTexture,tnodes[0]);
2085 if (tnodes[0]) q->map[0] = node->normalTextureMapping ? node->normalTextureMapping->strptr : NULL;
2086
2087 }
2088 if(node->emissiveTexture)
2089 {
2090 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->emissiveTexture,tnodes[1]);
2091 if (tnodes[1]) q->map[1] = node->emissiveTextureMapping ? node->emissiveTextureMapping->strptr : NULL;
2092
2093 }
2094 if(node->occlusionTexture)
2095 {
2096 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->occlusionTexture,tnodes[2]);
2097 if (tnodes[2]) q->map[2] = node->occlusionTextureMapping ? node->occlusionTextureMapping->strptr : NULL;
2098
2099 }
2100 if(node->baseTexture)
2101 {
2102 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->baseTexture,tnodes[3]);
2103 if (tnodes[3]) q->map[3] = node->baseTextureMapping ? node->baseTextureMapping->strptr : NULL;
2104
2105 }
2106 if(node->metallicRoughnessTexture)
2107 {
2108 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->metallicRoughnessTexture,tnodes[4]);
2109 if (tnodes[4]) q->map[4] = node->metallicRoughnessTextureMapping ? node->metallicRoughnessTextureMapping->strptr : NULL;
2110
2111 }
2112 //int *cindex = q->cindex;
2113 //for (int i = 0; i < 7; i++) cindex[i] = 0;
2114 //cindex[0] = 0; //node->normalTextureChannel;
2115 //cindex[1] = 0; //node->emissiveTextureChannel;
2116 //cindex[2] = node->baseTextureChannel;
2117 //cindex[3] = node->metallicRoughnessTextureChannel;
2118 q->nt = 0; //assume no material.texturexxx to start
2119 for(int i=0;i<7;i++){
2120 q->tcount[i] = 0; //default: no texture for this material function
2121 q->tstart[i] = q->nt; //shader: start looping over tindex where we left off, for tcount loops
2122 if(tnodes[i]){
2123 if(tnodes[i]->_nodeType == NODE_MultiTexture) {
2124 struct X3D_MultiTexture *mt = (struct X3D_MultiTexture*)tnodes[i];
2125 q->tcount[i] = mt->texture.n;
2126 q->nt += mt->texture.n;
2127 q->mt++;
2128 }else{
2129 //single texture
2130 q->nt++;
2131 q->tcount[i] = 1;
2132 }
2133 }
2134 }
2135 MARK_NODE_COMPILED
2136}
2137
2138void render_PhysicalMaterial (struct X3D_PhysicalMaterial *node) {
2139
2140 COMPILE_IF_REQUIRED
2141 {
2142 ppComponent_Shape p = (ppComponent_Shape)gglobal()->Component_Shape.prv;
2143 if (node != NULL) {
2144 if(get_isBackMaterial()){
2145 memcpy (&p->appearanceProperties.fw_BackMaterial, node->_material, sizeof (struct fw_MaterialParameters));
2146 }else{
2147 memcpy (&p->appearanceProperties.fw_FrontMaterial, node->_material, sizeof (struct fw_MaterialParameters));
2148 }
2149 }
2150 }
2151}
2152
2153void compile_AcousticProperties (struct X3D_AcousticProperties *node){
2154 MARK_NODE_COMPILED
2155}
2156void render_AcousticProperties (struct X3D_AcousticProperties *node){
2157 COMPILE_IF_REQUIRED
2158}