FreeWRL / FreeX3D 4.3.0
Component_VolumeRendering.c
1/*
2
3
4X3D Volume Rendering 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/OpenGL_Utils.h"
41#include "../opengl/Textures.h"
42#include "../scenegraph/Component_Shape.h"
43#include "../scenegraph/RenderFuncs.h"
44#include "../scenegraph/LinearAlgebra.h"
45
46/*
47Volumee Rendering aka voxels
48http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html
49- VolumeData is like shape node with its own equivalents to appearance, geometry
50- Style nodes - like appearance, except sometimes composable
51
52
53Before starting to implement this there are a few other nodes and components that might be needed:
54- clipPlane - besides transparent voxels, you may want to slice a volumetric image with a clipplane to look inside IMPLEMENTED SEPT 2016
55- we have TextureProperties to get the RST
56- Texturing3D component > for 3D image file format reading:
57 http://paulbourke.net/dataformats/volumetric/
58 - Simplest 3d texture file, if you are writing your own
59 http://www.web3d.org/x3d/content/examples/Basic/VolumeRendering/
60 - these examples use nrrd format, not much harder IMPLEMENTED Oct 2, 2016
61Links:
62 http://http.developer.nvidia.com/GPUGems/gpugems_ch39.html
63 - GpuGems online, ideas about volume rendering
64 http://teem.sourceforge.net/
65 - same place as nrrd file format lib
66 - unu.exe commandline program is handy:
67 print nrrd file header:
68 unu head brain.nrrd
69 resize an image ie from 512x512x512 to 128x128x128:
70 unu resample -s 128 128 128 -i brain.nrrd -o brain128.nrrd
71
72 http://castle-engine.sourceforge.net/compositing_shaders.php
73 - in the "Compositing Shaders in X3D" .pdf, page 9 mentions volume nodes
74 - the VolumeRendering Component has 10 style nodes, and Kambu is suggesting his Plug/hook method
75 http://cs.iupui.edu/~tuceryan/research/Microscopy/vis98.pdf
76 - paper: "Image-Based Transfer Function Design for Data Exploration in Volume Visualization"
77 pain: hard to stay organized with general functions in volume data
78 solution: goal-directed composable steps ie sharpen surface, colorize via 'transfer functions'
79 1. Apply transfer functions
80 A. Gray = F(Gray) or F(F(F(F(Gray)))) ie can chain grayscale functions for each voxel processed
81 a) F() image functions - anything from 2D image processing generalized to 3D
82 b) F() spatial functions - edge sharpening ie sobel or smoothing also from image processing
83 B. Gray to RGBA - lookup table
84 2. do your raycasting on RGBA
85 http://demos.vicomtech.org/
86 - uses webgl and x3dom
87 https://www.slicer.org/
88 - Uses teem
89 http://teem.sourceforge.net/mite/opts.html
90 - teem > Mite - has some transfer tables
91 http://graphicsrunner.blogspot.ca/2009/01/volume-rendering-101.html
92 - shows 'volume raycasting' method, shader (directx) and results
93 http://prideout.net/blog/?tag=volume-rendering
94 - shows volume raycasting shader example
95 https://www.opengl.org/discussion_boards/showthread.php/174814-Save-vertices-to-texture-problem
96 - xyz texture preparation, related to volume raycasting shader technique
97 http://http.developer.nvidia.com/GPUGems3/gpugems3_ch30.html
98 - see 30.3.1 Volume Rendering for raymarching nuances
99
100
101COMPONENT VOLUMERENDERING ISSUES Oct 29, 2016
102http://dug9.users.sourceforge.net/web3d/tests/volume/
103- these sample scenes use max size 128 .nrrd textures
104
105By Node:
106
107VoiumeData
108 - works
109SegmentedVolumeData
110 - no confirmation its working
111 - SegmentedVentricles.x3d - cycles every 3 seconds or so
112IsoSurfaceVolumeData
113 - no confirm
114 - IsoSurfaceSkull.x3d
115
116BlendedVolumeStyle
117 - blackscreens
118 - BlendedBodyInternals.x3d - blackscreens
119 - BlendedComposedVolumes.x3d - blackscreens
120BoundaryEnhancementVolumeStyle
121 - no confirm
122 - BoundaryEnhancementInternals.x3d - blackscreens
123 - BlendedComposedVolumes.x3d - blackscreens
124CartoonVolumeStyle
125 - works
126 - CartoonBackpack.x3d
127 - BlendedComposedVolumes.x3d
128ComposedVolumeStyle
129 - no confirm
130 - ComposedBackpack.x3d
131 - BlendedComposedVolumes.x3d
132EdgeEnhancementVolumeStyle
133 - works
134 - EdgeBrain.x3d
135 - ComposedBackpack.x3d
136 - BlendedComposedVolumes.x3d
137OpacityMapVolumeStyle
138 - no TransferFunction verification
139 - basics (implicit) works, plus explicit:
140 - BlendedComposedVolumes.x3d
141 - SegmentedVentricles.x3d
142ProjectionVolumeStyle
143 - works
144 - ProjectionMaxVentricles.x3d
145ShadedVolumeStyle
146 - no confirm
147 - ShadedBrain.x3d - no evidence of shading
148SillouetteEnhancementVolumeStyle
149 - works but hard to see a difference
150 - SilhouetteSkull.x3d
151 - ComposedBackpack.x3d
152 - BlendedComposedVolumes.x3d
153ToneMappedVolumeStyle
154 - works
155 - BlendedComposedVolumes.x3d
156 - ToneInternal.x3d - blackscreens
157
158
159By Technique:
160
161gradients:
162 IsoSurfaceVolumeData
163
164surfaceNormals:
165 CartoonVolumeStyle
166 EdgeEnhacementVolumeStyle
167 BoundaryEnhancementVolumeStyle
168 ShadedVolumeStyle
169 SilhouetteEnhancementVolumeStyle
170 ToneMappedVolumeStyle
171
172segmentIdentifiers:
173 SegmentedVolumeData
174
175Texture2D as transfer function:
176 BlendedVolumeStyle > weightTransferFunction1, weightTransferFunction2
177 OpacityMapVolumeStyle > transferFunction
178
179MF list:
180MFNode -renderStyle > ComposedVolumeStyle, IsoSurfaceVolumeData, SegmentedVolumeStyle
181MFFloat -surfaceValues > IsoSurfaceVolumeData
182
183
184*/
185
187 GLuint front_texture;
188 GLuint back_texture;
189 GLint ifbobuffer;
190 GLint idepthbuffer;
191 int width, height;
192 GLfloat *quad;
193}* ppComponent_VolumeRendering;
194void *Component_VolumeRendering_constructor(){
195 void *v = MALLOCV(sizeof(struct pComponent_VolumeRendering));
196 memset(v,0,sizeof(struct pComponent_VolumeRendering));
197 return v;
198}
199void Component_VolumeRendering_init(struct tComponent_VolumeRendering *t){
200 //public
201 //private
202 t->prv = Component_VolumeRendering_constructor();
203 {
204 ppComponent_VolumeRendering p = (ppComponent_VolumeRendering)t->prv;
205 p->back_texture = 0;
206 p->front_texture = 0;
207 p->ifbobuffer = 0;
208 p->idepthbuffer = 0;
209 p->width = 0;
210 p->height = 0;
211 p->quad = NULL;
212 }
213}
214void Component_VolumeRendering_clear(struct tComponent_VolumeRendering *t){
215 //public
216 //private
217 {
218 ppComponent_VolumeRendering p = (ppComponent_VolumeRendering)t->prv;
219 //p->front_texture;
220 //p->back_texture;
221 FREE_IF_NZ(p->quad);
222 }
223}
224//ppComponent_VolumeRendering p = (ppComponent_VolumeRendering)gglobal()->Component_VolumeRendering.prv;
225
226
227
228
229//6 faces x 2 triangles per face x 3 vertices per triangle x 3 scalars (xyz) per vertex = 6 x 2 x 3 x 3 = 108
230GLfloat box [108] = {1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, };
231
232// 6 7 //back far z
233// 4 5
234// 2 3 //front near z
235// 0 1
236float boxvert [24] = {
237-.5f,-.5f, .5f, .5f,-.5f, .5f, -.5f,.5f, .5f, .5f,.5f, .5f, //near z LL LR UL UR
238-.5f,-.5f,-.5f, .5f,-.5f,-.5f, -.5f,.5f,-.5f, .5f,.5f,-.5f, //far z
239};
240//ccw tris
241int boxtriindccw [48] = {
2420, 1, 3, -1, //near z
2433, 2, 0, -1,
2441, 5, 7, -1, //right
2457, 3, 1, -1,
2465, 4, 6, -1, //back z
2476, 7, 5, -1,
2484, 0, 2, -1, //left
2492, 6, 4, -1,
2502, 3, 7, -1, //top y
2517, 6, 2, -1,
2524, 5, 1, -1, //bottom y
2531, 0, 4, -1,
254};
255int boxtriindcw [48] = {
2560, 3, 1, -1, //near z
2573, 0, 2, -1,
2581, 7, 5, -1, //right
2597, 1, 3, -1,
2605, 6, 4, -1, //back z
2616, 5, 7, -1,
2624, 2, 0, -1, //left
2632, 4, 6, -1,
2642, 7, 3, -1, //top y
2657, 2, 6, -1,
2664, 1, 5, -1, //bottom y
2671, 4, 0, -1,
268};
269void compile_VolumeData(struct X3D_VolumeData *node){
270 int i,j,itri, ind, jvert;
271 float *boxtris;
272
273 ConsoleMessage("compile_volumedata\n");
274 if(node->_boxtris == NULL){
275 node->_boxtris = MALLOC(void *,108 * sizeof(float));
276 }
277 boxtris = (float*)node->_boxtris;
278 if(0)
279 for(i=0;i<36;i++){
280 for(j=0;j<3;j++)
281 boxtris[i*3 + j] = .5f * node->dimensions.c[j] * box[i*3 + j]; //raw triangles are -1 to 1, dimensions are absolute
282
283 }
284 if(1)
285 for(itri=0;itri<12;itri++){
286 for(jvert=0;jvert<3;jvert++) {
287 float *vert;
288 ind = boxtriindccw[itri*4 + jvert];
289 vert = &boxvert[ind*3];
290 for(j=0;j<3;j++){
291 boxtris[(itri*3 +jvert)*3 + j] = node->dimensions.c[j]*vert[j];
292 }
293 }
294 }
295 //for(i=0;i<36;i++)
296 // printf("%f %f %f\n",boxtris[i*3 +0],boxtris[i*3 +1],boxtris[i*3 +2]);
297 MARK_NODE_COMPILED
298}
299void pushnset_framebuffer(int ibuffer);
300void popnset_framebuffer();
301
302
303#ifdef OLDCODE
304#ifdef GL_DEPTH_COMPONENT32
305#define FW_GL_DEPTH_COMPONENT GL_DEPTH_COMPONENT32
306#else
307#define FW_GL_DEPTH_COMPONENT GL_DEPTH_COMPONENT16
308#endif
309#endif //OLDCODE
310
311
312void __gluMultMatricesd(const GLDOUBLE a[16], const GLDOUBLE b[16], GLDOUBLE r[16]);
313int __gluInvertMatrixd(const GLDOUBLE m[16], GLDOUBLE invOut[16]);
314ivec4 get_current_viewport();
315
316unsigned int prep_volumestyle(struct X3D_Node *vstyle, unsigned int volflags){
317 struct X3D_OpacityMapVolumeStyle *style0 = (struct X3D_OpacityMapVolumeStyle*)vstyle;
318 if(style0->enabled){
319 switch(vstyle->_nodeType){
320 case NODE_OpacityMapVolumeStyle:
321 volflags = volflags << 4;
322 volflags |= SHADERFLAGS_VOLUME_STYLE_OPACITY;
323 break;
324 case NODE_BlendedVolumeStyle:
325 //volflags = volflags << 4;
326 //volflags |= SHADERFLAGS_VOLUME_STYLE_BLENDED;
327 //do nothing, so parent renders as default, or gets a style via composed
328 break;
329 case NODE_BoundaryEnhancementVolumeStyle:
330 volflags = volflags << 4;
331 volflags |= SHADERFLAGS_VOLUME_STYLE_BOUNDARY;
332 break;
333 case NODE_CartoonVolumeStyle:
334 volflags = volflags << 4;
335 volflags |= SHADERFLAGS_VOLUME_STYLE_CARTOON;
336 break;
337 case NODE_ComposedVolumeStyle:
338 {
339 int i;
340 struct X3D_ComposedVolumeStyle *style = (struct X3D_ComposedVolumeStyle*)vstyle;
341 //volflags = volflags << 4;
342 //volflags |= SHADERFLAGS_VOLUME_STYLE_COMPOSED;
343 // I 'unroll' composed here, into a bit-shifted list with 4 bits per entry
344 for(i=0;i<style->renderStyle.n;i++){
345 volflags = prep_volumestyle(style->renderStyle.p[i], volflags);
346 }
347 }
348 break;
349 case NODE_EdgeEnhancementVolumeStyle:
350 volflags = volflags << 4;
351 volflags |= SHADERFLAGS_VOLUME_STYLE_EDGE;
352 break;
353 case NODE_ProjectionVolumeStyle:
354 volflags = volflags << 4;
355 volflags |= SHADERFLAGS_VOLUME_STYLE_PROJECTION;
356 break;
357 case NODE_ShadedVolumeStyle:
358 volflags = volflags << 4;
359 volflags |= SHADERFLAGS_VOLUME_STYLE_SHADED;
360 break;
361 case NODE_SilhouetteEnhancementVolumeStyle:
362 volflags = volflags << 4;
363 volflags |= SHADERFLAGS_VOLUME_STYLE_SILHOUETTE;
364 break;
365 case NODE_ToneMappedVolumeStyle:
366 volflags = volflags << 4;
367 volflags |= SHADERFLAGS_VOLUME_STYLE_TONE;
368 break;
369 default:
370 break;
371 }
372 }
373 return volflags;
374}
375void applysurfaceNormalTexture(struct X3D_Node* surfaceNormals, GLint myProg) {
376 GLuint gradtex;
377 int havetexture = 0;
378 if (surfaceNormals) {
379 //load texture
380 struct X3D_Node* tmpN;
381 textureTableIndexStruct_s* tti;
382 ttglobal tg = gglobal();
383 POSSIBLE_PROTO_EXPANSION(struct X3D_Node*, surfaceNormals, tmpN);
384 tg->RenderFuncs.texturenode = (void*)tmpN;
385
386 //problem: I don't want it sending image dimensions to my volume shader,
387 // which could confuse the voxel sampler
388 //render_node(tmpN); //render_node(node->texture);
389 loadTextureNode(tmpN, NULL);
390 tti = getTableTableFromTextureNode(tmpN);
391 if (tti && tti->status >= TEX_LOADED) {
392 glActiveTexture(GL_TEXTURE0 + 3);
393 glBindTexture(GL_TEXTURE_2D, tti->OpenGLTexture);
394 GLuint tu3 = GET_UNIFORM(myProg, "fw_Texture_unit3");
395 glUniform1i(tu3, 3);
396 havetexture = 1; //signal its a |gradient| magnitude
397 if (tti->channels == 3) havetexture = 3; //signal its an xyz gradient
398 }
399 }
400 gradtex = GET_UNIFORM(myProg, "fw_gradTexture");
401 glUniform1i(gradtex, havetexture);
402
403}
404void render_volume_data(struct X3D_Node *renderStyle, struct X3D_Node *voxels, struct X3D_VolumeData *node);
405struct X3D_Material *get_material_oneSided();
406struct X3D_TwoSidedMaterial *get_material_twoSided();
407void pushnset_viewport(float *vpFraction);
408void popnset_viewport();
409int haveFrameBufferObject();
410void initialize_front_and_back_material_params();
411void render_volumestyle(struct X3D_Node *vstyle, GLint myProg){
412 struct X3D_OpacityMapVolumeStyle *style0 = (struct X3D_OpacityMapVolumeStyle*)vstyle;
413 if(style0->enabled){
414 switch(vstyle->_nodeType){
415 case NODE_OpacityMapVolumeStyle:
416 {
417 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#OpacityMapVolumeStyle
418 // Q. how do the transfer function on GPU? its defined like its on the CPU ie
419 // with integers. On GPU the .a will be 0.0 to 1.0. I guess that can be used as 1D texture coordinate.
420 int havetexture;
421 GLint iopactex;
422 struct X3D_OpacityMapVolumeStyle *style = (struct X3D_OpacityMapVolumeStyle*)vstyle;
423 havetexture = 0;
424 if(style->transferFunction){
425 //load texture
426 struct X3D_Node *tmpN;
427 textureTableIndexStruct_s *tti;
428 ttglobal tg = gglobal();
429
430 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, style->transferFunction,tmpN);
431 tg->RenderFuncs.texturenode = (void*)tmpN;
432
433 //problem: I don't want it sending image dimensions to my volume shader,
434 // which could confuse the voxel sampler
435 //render_node(tmpN); //render_node(node->texture);
436 loadTextureNode(tmpN,NULL);
437 tti = getTableTableFromTextureNode(tmpN);
438 if(tti && tti->status >= TEX_LOADED){
439 glActiveTexture(GL_TEXTURE0+3);
440 glBindTexture(GL_TEXTURE_2D,tti->OpenGLTexture);
441 havetexture = 1;
442 }
443 }
444 iopactex = GET_UNIFORM(myProg,"fw_opacTexture");
445 glUniform1i(iopactex,havetexture);
446
447 }
448 break;
449 case NODE_BlendedVolumeStyle:
450 {
451 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#BlendedVolumeStyle
452 struct X3D_BlendedVolumeStyle *style = (struct X3D_BlendedVolumeStyle*)vstyle;
453 //FBO blending
454 //a) render the parent volumeData to fbo:
455 // - in prep Blended push fbo
456 // - render main to fbo
457 // - in fin Blended: read pixels or save renderbuffer texture 0
458 //b) in fin Blended: render blended (voxels,stye) as VolumeData to fbo
459 // - read pixels or same renderbuffer texture 1
460 //c) pop fbo
461 //d) set 2 pixelsets as textures
462 // and render via a special little shader that blends 2 textures and sends to GL_BACK.
463 #define BLENDED 1
464 #ifdef BLENDED
465 int *fbohandles = style->_fbohandles.p;
466 GLint iviewport[4];
467 float vp[4] = {0.0f,1.0f,0.0f,1.0f}; //arbitrary
468
469 glGetIntegerv(GL_VIEWPORT, iviewport); //xmin,ymin,w,h
470 if(haveFrameBufferObject()){
471 if(fbohandles[0] == 0){
472 GLuint depthrenderbuffer;
473 // https://www.opengl.org/wiki/Framebuffer_Object
474 glGenFramebuffers(1, (GLuint *) &fbohandles[0]);
475 pushnset_framebuffer(fbohandles[0]); //binds framebuffer. we push here, in case higher up we are already rendering the whole scene to an fbo
476
477 // The depth buffer - optional
478 glGenRenderbuffers(1, &depthrenderbuffer);
479 glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer);
480 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, iviewport[2],iviewport[3]);
481 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer);
482
483
484 glGenTextures(1,(GLuint *) &fbohandles[1]);
485 glBindTexture(GL_TEXTURE_2D, fbohandles[1]);
486 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iviewport[2], iviewport[3], 0, GL_RGBA , GL_UNSIGNED_BYTE, 0);
487 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
488 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
489
490 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbohandles[1], 0);
491
492
493 glGenTextures(1,(GLuint *)&fbohandles[2]);
494 glBindTexture(GL_TEXTURE_2D, fbohandles[2]);
495 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iviewport[2], iviewport[3], 0, GL_RGBA , GL_UNSIGNED_BYTE, 0);
496 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
497 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
498
499 //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+1, GL_TEXTURE_2D, fbohandles[2], 0);
500 //--dont assign the second texture till after the parent VolumeData has drawn itself
501 //glDrawBuffers(1,&fbohandles[1]);
502 if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
503 printf("ouch framebuffer not complete\n");
504 //popnset_framebuffer(); //pop after drawing
505 }else{
506 pushnset_framebuffer(fbohandles[0]);
507 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbohandles[1], 0);
508 }
509 }
510 pushnset_viewport(vp); //something to push so we can pop-and-set below, so any mainloop GL_BACK viewport is restored
511 glViewport(0,0,iviewport[2],iviewport[3]); //viewport we want
512 glClearColor(0.0f,0.0f,0.0f,0.0f); //red, for diagnostics during debugging
513 FW_GL_CLEAR(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
514
515 #endif //BLENDED
516 }
517 break;
518 case NODE_BoundaryEnhancementVolumeStyle:
519 {
520 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#BoundaryEnhancementVolumeStyle
522 //SFFloat [in,out] boundaryOpacity 0.9 [0,1]
523 //SFFloat [in,out] opacityFactor 2 [0,?)
524 //SFFloat [in,out] retainedOpacity 0.2 [0,1]
525 //SFNode [in,out] surfaceNormals NULL [X3DTexture3DNode]
526 GLint ibebound, iberetain, ibefactor;
527 ibebound = GET_UNIFORM(myProg,"fw_boundaryOpacity");
528 glUniform1f(ibebound,style->boundaryOpacity);
529 iberetain = GET_UNIFORM(myProg,"fw_retainedOpacity");
530 glUniform1f(iberetain,style->retainedOpacity);
531 ibefactor = GET_UNIFORM(myProg,"fw_opacityFactor");
532 glUniform1f(ibefactor,style->opacityFactor);
533 applysurfaceNormalTexture(style->surfaceNormals,myProg);
534 }
535 break;
536 case NODE_CartoonVolumeStyle:
537 {
538 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#CartoonVolumeStyle
539 struct X3D_CartoonVolumeStyle *style = (struct X3D_CartoonVolumeStyle*)vstyle;
540 //SFInt32 [in,out] colorSteps 4 [1,64]
541 //SFColorRGBA [in,out] orthogonalColor 1 1 1 1 [0,1]
542 //SFColorRGBA [in,out] parallelColor 0 0 0 1 [0,1]
543 //SFNode [in,out] surfaceNormals NULL [X3DTexture3DNode]
544 GLint itoonsteps, itoonortho, itoonparallel;
545 itoonsteps = GET_UNIFORM(myProg,"fw_colorSteps");
546 glUniform1i(itoonsteps,style->colorSteps);
547 itoonortho = GET_UNIFORM(myProg,"fw_orthoColor");
548 glUniform4fv(itoonortho,1,style->orthogonalColor.c);
549 itoonparallel = GET_UNIFORM(myProg,"fw_paraColor");
550 glUniform4fv(itoonparallel,1,style->parallelColor.c);
551 applysurfaceNormalTexture(style->surfaceNormals, myProg);
552
553 }
554 break;
555 case NODE_ComposedVolumeStyle:
556 {
557 int i;
558 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#ComposedVolumeStyle
559 struct X3D_ComposedVolumeStyle *style = (struct X3D_ComposedVolumeStyle*)vstyle;
560 for(i=0;i<style->renderStyle.n;i++){
561 render_volumestyle(style->renderStyle.p[i], myProg);
562 }
563 }
564 break;
565 case NODE_EdgeEnhancementVolumeStyle:
566 {
567 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#EdgeEnhancementVolumeStyle
568 //SFColorRGBA [in,out] edgeColor 0 0 0 1 [0,1]
569 //SFBool [in,out] enabled TRUE
570 //SFFloat [in,out] gradientThreshold 0.4 [0,PI]
571 //SFNode [in,out] metadata NULL [X3DMetadataObject]
572 //SFNode [in,out] surfaceNormals NULL [X3DTexture3DNode]
574 GLint iedgeColor, igradientThreshold;
575 float *rgba;
576 rgba = style->edgeColor.c;
577 iedgeColor = GET_UNIFORM(myProg,"fw_edgeColor");
578 glUniform4fv(iedgeColor,1,rgba);
579 igradientThreshold = GET_UNIFORM(myProg,"fw_cosGradientThreshold");
580 glUniform1f(igradientThreshold,cosf(style->gradientThreshold));
581 //printf("edge uniforms color %d gradthresh %d\n",iedgeColor,igradientThreshold);
582 applysurfaceNormalTexture(style->surfaceNormals,myProg);
583 }
584 break;
585 case NODE_ProjectionVolumeStyle:
586 {
587 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#ProjectionVolumeStyle
588 struct X3D_ProjectionVolumeStyle *style = (struct X3D_ProjectionVolumeStyle*)vstyle;
589 //SFFloat [in,out] intensityThreshold 0 [0,1]
590 //SFString [in,put] type "MAX" ["MAX", "MIN", "AVERAGE"]
591 GLint iintensity, itype;
592 int ktype = 1; // initialize this to something that makes sense
593 char *ctype;
594 iintensity = GET_UNIFORM(myProg,"fw_intensityThreshold");
595 glUniform1f(iintensity,style->intensityThreshold);
596 itype = GET_UNIFORM(myProg,"fw_projType");
597 if(style->_type == 0){
598 ctype = style->type->strptr;
599 if(!strcmp(ctype,"MIN"))
600 ktype = 1;
601 else if(!strcmp(ctype,"MAX"))
602 ktype = 2;
603 else if(!strcmp(ctype,"AVERAGE"))
604 ktype = 3;
605 style->_type = ktype;
606 }
607 glUniform1i(itype,style->_type);
608 }
609 break;
610 case NODE_ShadedVolumeStyle:
611 {
612 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#ShadedVolumeStyle
613 GLint iphase, ilite, ishadow;
614 struct X3D_ShadedVolumeStyle *style = (struct X3D_ShadedVolumeStyle*)vstyle;
615 //SFBool [in,out] lighting FALSE
616 //SFNode [in,out] material NULL [X3DMaterialNode]
617 //SFBool [in,out] shadows FALSE
618 //SFNode [in,out] surfaceNormals NULL [X3DTexture3DNode]
619 //SFString [] phaseFunction "Henyey-Greenstein" ["Henyey-Greenstein","NONE",...]
620 //MATERIAL
621 if(style->material){
622
623 struct X3D_Material *matone;
624 struct X3D_TwoSidedMaterial *mattwo;
625 struct fw_MaterialParameters *fw_FrontMaterial;
626 struct fw_MaterialParameters *fw_BackMaterial;
627 GLint myMaterialDiffuse;
628 GLint myMaterialEmissive;
629 GLint myMaterialSpecular;
630 GLint myMaterialAmbient;
631 GLint myMaterialShininess;
632 GLint myMaterialOcclusion;
633 GLint myMaterialNormalScale;
634 GLint myMaterialTransparency;
635
636 GLint myMaterialBackDiffuse;
637 GLint myMaterialBackEmissive;
638 GLint myMaterialBackSpecular;
639 GLint myMaterialBackShininess;
640 GLint myMaterialBackOcclusion;
641 GLint myMaterialBackNormalScale;
642 GLint myMaterialBackAmbient;
643 GLint myMaterialBackTransparency;
644 struct matpropstruct *myap = getAppearanceProperties();
645
646 void initialize_front_and_back_material_params();
647 RENDER_MATERIAL_SUBNODES(style->material);
648 //struct matpropstruct matprop;
649 //s_shader_capabilities_t mysp;
650 //sendFogToShader(mysp);
651 //matone = get_material_oneSided();
652 //mattwo = get_material_twoSided();
654 //if (matone != NULL) {
655 // memcpy (&myap->fw_FrontMaterial, matone->_verifiedColor.p, sizeof (struct fw_MaterialParameters));
656 // memcpy (&myap->fw_BackMaterial, matone->_verifiedColor.p, sizeof (struct fw_MaterialParameters));
657 // /* copy the emissive colour over for lines and points */
658 // //memcpy(&myap->emissionColour,matone->_verifiedColor.p, 3*sizeof(float));
659
660 //} else if (mattwo != NULL) {
661 // memcpy (&myap->fw_FrontMaterial, mattwo->_verifiedFrontColor.p, sizeof (struct fw_MaterialParameters));
662 // memcpy (&myap->fw_BackMaterial, mattwo->_verifiedBackColor.p, sizeof (struct fw_MaterialParameters));
663 // /* copy the emissive colour over for lines and points */
664 // //memcpy(&myap->emissionColour,mattwo->_verifiedFrontColor.p, 3*sizeof(float));
665 //} else {
666 // /* no materials selected.... */
667 //}
668
669
670
671 if (!myap) return;
672 fw_FrontMaterial = &myap->fw_FrontMaterial;
673 fw_BackMaterial = &myap->fw_BackMaterial;
674
675
676 PRINT_GL_ERROR_IF_ANY("BEGIN sendMaterialsToShader");
677
678 /* eventually do this with code blocks in glsl */
679
680
681 myMaterialDiffuse = GET_UNIFORM(myProg,"fw_FrontMaterial.diffuse");
682 myMaterialEmissive = GET_UNIFORM(myProg,"fw_FrontMaterial.emissive");
683 myMaterialSpecular = GET_UNIFORM(myProg,"fw_FrontMaterial.specular");
684 myMaterialAmbient = GET_UNIFORM(myProg,"fw_FrontMaterial.ambient");
685 myMaterialShininess = GET_UNIFORM(myProg,"fw_FrontMaterial.shininess");
686 myMaterialOcclusion = GET_UNIFORM(myProg, "fw_FrontMaterial.occlusion");
687 myMaterialNormalScale = GET_UNIFORM(myProg, "fw_FrontMaterial.normalScale");
688 myMaterialTransparency = GET_UNIFORM(myProg,"fw_FrontMaterial.transparency");
689
690 myMaterialBackDiffuse = GET_UNIFORM(myProg,"fw_BackMaterial.diffuse");
691 myMaterialBackEmissive = GET_UNIFORM(myProg,"fw_BackMaterial.emissive");
692 myMaterialBackSpecular = GET_UNIFORM(myProg,"fw_BackMaterial.specular");
693 myMaterialBackAmbient = GET_UNIFORM(myProg,"fw_BackMaterial.ambient");
694 myMaterialBackShininess = GET_UNIFORM(myProg,"fw_BackMaterial.shininess");
695 myMaterialBackOcclusion = GET_UNIFORM(myProg, "fw_BackMaterial.occlusion");
696 myMaterialBackNormalScale = GET_UNIFORM(myProg, "fw_BackMaterial.normalScale");
697 myMaterialBackTransparency = GET_UNIFORM(myProg,"fw_BackMaterial.transparency");
698
699
700 profile_start("sendvec");
701 GLUNIFORM3FV(myMaterialDiffuse,1,fw_FrontMaterial->diffuse);
702 GLUNIFORM3FV(myMaterialEmissive,1,fw_FrontMaterial->emissive);
703 GLUNIFORM3FV(myMaterialSpecular,1,fw_FrontMaterial->specular);
704 GLUNIFORM1F(myMaterialAmbient,fw_FrontMaterial->ambient);
705 GLUNIFORM1F(myMaterialShininess,fw_FrontMaterial->shininess);
706 GLUNIFORM1F(myMaterialOcclusion, fw_FrontMaterial->occlusion);
707 GLUNIFORM1F(myMaterialNormalScale, fw_FrontMaterial->normalScale);
708 GLUNIFORM1F(myMaterialTransparency,fw_FrontMaterial->transparency);
709
710 GLUNIFORM3FV(myMaterialBackDiffuse,1,fw_BackMaterial->diffuse);
711 GLUNIFORM3FV(myMaterialBackSpecular,1,fw_BackMaterial->specular);
712 GLUNIFORM3FV(myMaterialBackEmissive,1,fw_BackMaterial->emissive);
713 GLUNIFORM1F(myMaterialBackAmbient,fw_BackMaterial->ambient);
714 GLUNIFORM1F(myMaterialBackShininess,fw_BackMaterial->shininess);
715 GLUNIFORM1F(myMaterialBackOcclusion, fw_BackMaterial->occlusion);
716 GLUNIFORM1F(myMaterialBackNormalScale, fw_BackMaterial->normalScale);
717 GLUNIFORM1F(myMaterialBackTransparency,fw_BackMaterial->transparency);
718 profile_end("sendvec");
719
720
721 }
722 if(style->lighting){
723 //LIGHT
724 //FOG
725 //-these are from the scenegraph above the voldata node, and -like clipplane- can/should be
726 //set generically
727 }
728
729 //phasefunc
730 if(style->_phaseFunction == 0){
731 if(!strcmp(style->phaseFunction->strptr,"NONE"))
732 style->_phaseFunction = 1;
733 else if(!strcmp(style->phaseFunction->strptr,"Henyey-Greenstein"))
734 style->_phaseFunction = 2;
735 }
736 iphase = GET_UNIFORM(myProg,"fw_phase");
737 glUniform1i(iphase,style->_phaseFunction);
738 ilite = GET_UNIFORM(myProg,"fw_lighting");
739 glUniform1i(ilite,style->lighting);
740 ishadow = GET_UNIFORM(myProg,"fw_shadows");
741 glUniform1i(ishadow,style->shadows);
742 applysurfaceNormalTexture(style->surfaceNormals, myProg);
743
744 }
745 break;
746 case NODE_SilhouetteEnhancementVolumeStyle:
747 {
748 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#SilhouetteEnhancementVolumeStyle
750 //SFFloat [in,out] silhouetteBoundaryOpacity 0 [0,1]
751 //SFFloat [in,out] silhouetteRetainedOpacity 1 [0,1]
752 //SFFloat [in,out] silhouetteSharpness 0.5 [0,8)
753 GLint isilbound, isilretain, isilsharp;
754 isilbound = GET_UNIFORM(myProg,"fw_BoundaryOpacity");
755 glUniform1f(isilbound,style->silhouetteBoundaryOpacity);
756 isilretain = GET_UNIFORM(myProg,"fw_RetainedOpacity");
757 glUniform1f(isilretain,style->silhouetteRetainedOpacity);
758 isilsharp = GET_UNIFORM(myProg,"fw_Sharpness");
759 glUniform1f(isilsharp,style->silhouetteSharpness);
760 applysurfaceNormalTexture(style->surfaceNormals, myProg);
761
762 }
763 break;
764 case NODE_ToneMappedVolumeStyle:
765 {
766 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#ToneMappedVolumeStyle
767 //SFColorRGBA [in,out] coolColor 0 0 1 0 [0,1]
768 //SFColorRGBA [in,out] warmColor 1 1 0 0 [0,1]
769 //SFNode [in,out] surfaceNormals NULL [X3DTexture3DNode]
770 struct X3D_ToneMappedVolumeStyle *style = (struct X3D_ToneMappedVolumeStyle*)vstyle;
771 //send warm, cool to shader
772 GLint icool, iwarm;
773 icool = GET_UNIFORM(myProg,"fw_coolColor");
774 glUniform4fv(icool,1,style->coolColor.c);
775 iwarm = GET_UNIFORM(myProg,"fw_warmColor");
776 glUniform4fv(iwarm,1,style->warmColor.c);
777 applysurfaceNormalTexture(style->surfaceNormals, myProg);
778
779 }
780 break;
781 default:
782 break;
783 }
784 }
785}
786static struct {
787const char *ctype;
788int itype;
789} blendfuncs [] = {
790{"CONSTANT",1},
791{"ALPHA1",2},
792{"ALPHA2",3},
793{"TABLE",4},
794{"ONE_MINUS_ALPHA1",5},
795{"ONE_MINUS_ALPHA2",6},
796{NULL,0},
797};
798int lookup_blendfunc(const char *funcname){
799 int iret, i;
800 i = 0;
801 iret = 0;
802 do{
803 if(!strcmp(blendfuncs[i].ctype,funcname)){
804 iret = blendfuncs[i].itype;
805 break;
806 }
807 i++;
808 }while(blendfuncs[i].ctype);
809 return iret;
810}
811
812void sendExplicitMatriciesToShader (GLint ModelViewMatrix, GLint ProjectionMatrix, GLint NormalMatrix, GLint *TextureMatrix, GLint ModelViewInverseMatrix);
813void render_GENERIC_volume_data(s_shader_capabilities_t *caps, struct X3D_Node **renderStyle, int nstyle, struct X3D_Node *voxels, struct X3D_VolumeData *node );
814s_shader_capabilities_t * getVolumeProgram(struct X3D_Node **renderStyle, int nstyle, int VOLUME_DATA_FLAG);
815void saveImage_web3dit(struct textureTableIndexStruct *tti, char *fname);
816
817void fin_volumestyle(struct X3D_Node *vstyle, struct X3D_VolumeData *dataParent){
818 struct X3D_OpacityMapVolumeStyle *style0 = (struct X3D_OpacityMapVolumeStyle*)vstyle;
819 if(style0->enabled){
820 switch(vstyle->_nodeType){
821 case NODE_OpacityMapVolumeStyle:
822 {
823 ttglobal tg = gglobal();
824 //do I need to do this?
825 tg->RenderFuncs.textureStackTop = 0;
826 tg->RenderFuncs.texturenode = NULL;
827 }
828 break;
829 case NODE_BlendedVolumeStyle:
830 {
831 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#BlendedVolumeStyle
832 struct X3D_BlendedVolumeStyle *style = (struct X3D_BlendedVolumeStyle*)vstyle;
833 //FBO blending
834 //a) render the parent volumeData to fbo:
835 // - in prep Blended push fbo
836 // - render main to fbo
837 // - in fin Blended: read pixels or save renderbuffer texture 0
838 //b) in fin Blended: render blended (voxels,stye) as VolumeData to fbo
839 // - read pixels or same renderbuffer texture 1
840 //c) pop fbo
841 //d) set 2 pixelsets as textures
842 // and render via a special little shader that blends 2 textures and sends to GL_BACK.
843 #ifdef BLENDED
844 GLuint pixelType = GL_RGBA;
845 int *fbohandles = style->_fbohandles.p;
846 if(fbohandles[0] > 0){
847 //readpixels from parent volumedata render
848 static int iframe = 0;
849 s_shader_capabilities_t *caps;
850 int nsubstyle;
851 //GLuint myProg;
852 int method_draw_cube, method_draw_quad;
853
854 iframe++;
855 //FW_GL_READPIXELS (0,0,isize,isize,pixelType,GL_UNSIGNED_BYTE, ttip->texdata);
856 if(0) if(iframe==500){
857 //write out whats in the framebuffer, and use as texture in test scene, to see fbo rendered OK
858 GLint iviewport[4];
859 char namebuf[100];
860 textureTableIndexStruct_s ttipp, *ttip;
861 ttip = &ttipp;
862 glGetIntegerv(GL_VIEWPORT, iviewport); //xmin,ymin,w,h
863
864 ttip->texdata = MALLOC (GLvoid *, 4*iviewport[2]*iviewport[3]);
865
866 /* grab the data */
867 //FW_GL_PIXELSTOREI (GL_UNPACK_ALIGNMENT, 1);
868 //FW_GL_PIXELSTOREI (GL_PACK_ALIGNMENT, 1);
869
870 // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glReadPixels.xml
871 FW_GL_READPIXELS (iviewport[0],iviewport[1],iviewport[2],iviewport[3],pixelType,GL_UNSIGNED_BYTE, ttip->texdata);
872 ttip->x = iviewport[2];
873 ttip->y = iviewport[3];
874 ttip->z = 1;
875 ttip->hasAlpha = 1;
876 ttip->channels = 4;
877 //write out tti as web3dit image files for diagnostic viewing, can use for BackGround node
878 //void saveImage_web3dit(struct textureTableIndexStruct *tti, char *fname)
879 sprintf(namebuf,"%s%d.web3dit","blended_fbo_",0);
880 saveImage_web3dit(ttip, namebuf);
881 FREE_IF_NZ(ttip->texdata);
882 }
883
884 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbohandles[2], 0);
885 //glDrawBuffers(1,&fbohandles[2]);
886
887 glClearColor(0.0f,0.0f,0.0f,0.0f); //red, for diagnostics during debugging
888 FW_GL_CLEAR(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
889
890 //render blended as volumedata to fbo
891 //render_volume_data(style->renderStyle,style->voxels,dataParent);
892 nsubstyle = style->renderStyle ? 1 : 0;
893 caps = getVolumeProgram(&style->renderStyle,nsubstyle, SHADERFLAGS_VOLUME_DATA_BASIC);
894 //render generic volume
895 render_GENERIC_volume_data(caps,&style->renderStyle,nsubstyle,style->voxels,(struct X3D_VolumeData*)dataParent );
896 //render_GENERIC_volume_data(caps,style->renderStyle,1,style->voxels,(struct X3D_VolumeData*)dataParent );
897
898 //glDrawBuffers(0,NULL);
899
900 //read blended from fbo
901 //FW_GL_READPIXELS (0,0,isize,isize,pixelType,GL_UNSIGNED_BYTE, ttip->texdata);
902 if(0) if(iframe==500){
903 //write out whats in the framebuffer, and use as texture in test scene, to see fbo rendered OK
904 GLint iviewport[4];
905 char namebuf[100];
906 textureTableIndexStruct_s ttipp, *ttip;
907 ttip = &ttipp;
908 glGetIntegerv(GL_VIEWPORT, iviewport); //xmin,ymin,w,h
909
910 ttip->texdata = MALLOC (GLvoid *, 4*iviewport[2]*iviewport[3]);
911
912 /* grab the data */
913 //FW_GL_PIXELSTOREI (GL_UNPACK_ALIGNMENT, 1);
914 //FW_GL_PIXELSTOREI (GL_PACK_ALIGNMENT, 1);
915 // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glReadPixels.xml
916 FW_GL_READPIXELS (iviewport[0],iviewport[1],iviewport[2],iviewport[3],pixelType,GL_UNSIGNED_BYTE, ttip->texdata);
917 ttip->x = iviewport[2];
918 ttip->y = iviewport[3];
919 ttip->z = 1;
920 ttip->hasAlpha = 1;
921 ttip->channels = 4;
922 //write out tti as web3dit image files for diagnostic viewing, can use for BackGround node
923 //void saveImage_web3dit(struct textureTableIndexStruct *tti, char *fname)
924 sprintf(namebuf,"%s%d.web3dit","blended_fbo_",1);
925 saveImage_web3dit(ttip, namebuf);
926 FREE_IF_NZ(ttip->texdata);
927 printf("wrote blended_fbo_.web3dit \n");
928 }
929 popnset_framebuffer();
930 popnset_viewport();
931 //we're now back to rendering to the screen
932 //we should have 2 textures
933
934 //render 2 textures as blended multitexture, or in special shader for blending,
935 //2 textures are fbohandles[0] (parent voldata), fbohandles[1] (blend voldata)
936 //over window-filling quad
937 //Options:
938 //1) draw our cube again, to get the depth (and skip unneeded pixels)
939 // but use gl_fragCoords as texture interpolator
940 //2) draw quad in ortho mode (but where depth buffer?)
941 method_draw_cube = method_draw_quad = 0;
942 method_draw_cube = 1;
943 if(method_draw_cube){
944 GLint myProg;
945 GLint iwtc1, iwtc2, iwtf1, iwtf2;
946 GLint TextureUnit;
947 int havetextures;
948 GLint iopactex, vp;
949 GLint iviewport[4];
950 float viewport[4];
951 shaderflagsstruct shader_requirements; //shaderflags,
952 s_shader_capabilities_t *caps;
953 GLint Vertices, mvm, proj;
954 double modelviewMatrix[16], projMatrix[16]; //, mvp[16]; // mvpinverse[16]; //mvmInverse[16],
955
956
957 memset(&shader_requirements,0,sizeof(shaderflagsstruct));
958 shader_requirements.volume = SHADERFLAGS_VOLUME_STYLE_BLENDED << 4; //send the following through the volume ubershader
959 // by default we'll mash it in: shader_requirements.volume |= TEX3D_SHADER;
960 caps = getMyShaders(shader_requirements);
961 enableGlobalShader(caps);
962 myProg = caps->myShaderProgram;
963
964 //send the usual matrices - same vertex shader as volumedata
965 //but simpler frag shader that uses gl_fragCoords, and does blend
966
967 //set shader flags
968 //build or get shader program
969 //set attributes
970 //SFFloat [in,out] weightConstant1 0.5 [0,1]
971 //SFFloat [in,out] weightConstant2 0.5 [0,1]
972 //BRUTZMAN: ALPHA0,1 here should be ALPHA1,2 to match table 14.1
973 //SFString [in,out] weightFunction1 "CONSTANT" ["CONSTANT", "ALPHA0", "ALPHA1", "TABLE",
974 // "ONE_MINUS_ALPHA0", "ONE_MINUS_ALPHA1" ]
975 //SFString [in,out] weightFunction2 "CONSTANT" ["CONSTANT", "ALPHA0", "ALPHA1", "TABLE",
976 // "ONE_MINUS_ALPHA0", "ONE_MINUS_ALPHA1" ]
977 //SFNode [in,out] weightTransferFunction1 NULL [X3DTexture2DNode]
978 //SFNode [in,out] weightTransferFunction2 NULL [X3DTexture2DNode]
979
980 iwtc1 = GET_UNIFORM(myProg,"fw_iwtc1");
981 iwtc2 = GET_UNIFORM(myProg,"fw_iwtc2");
982 iwtf1 = GET_UNIFORM(myProg,"fw_iwtf1");
983 iwtf2 = GET_UNIFORM(myProg,"fw_iwtf2");
984 glUniform1f(iwtc1,style->weightConstant1);
985 glUniform1f(iwtc2,style->weightConstant2);
986 if(style->_weightFunction1 == 0)
987 style->_weightFunction1 = lookup_blendfunc(style->weightFunction1->strptr);
988 if(style->_weightFunction2 == 0)
989 style->_weightFunction2 = lookup_blendfunc(style->weightFunction2->strptr);
990 glUniform1i(iwtf1,style->_weightFunction1);
991 glUniform1i(iwtf2,style->_weightFunction2);
992
993 //set the 2 textures from the fbo rendering
994 glActiveTexture ( GL_TEXTURE0 );
995 glBindTexture(GL_TEXTURE_2D,style->_fbohandles.p[1]);
996 FW_GL_TEXPARAMETERI( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //don't interpolate integer segment IDs
997
998 glActiveTexture ( GL_TEXTURE0+1 );
999 glBindTexture(GL_TEXTURE_2D,style->_fbohandles.p[2]);
1000 FW_GL_TEXPARAMETERI( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //don't interpolate integer segment IDs
1001
1002 TextureUnit= GET_UNIFORM(myProg,"fw_Texture_unit0");
1003 glUniform1i(TextureUnit,0);
1004 TextureUnit= GET_UNIFORM(myProg,"fw_Texture_unit1");
1005 glUniform1i(TextureUnit,1);
1006
1007 //set the 2 transfer function textures
1008 havetextures = 0;
1009 if(style->weightTransferFunction1){
1010 //load texture
1011 struct X3D_Node *tmpN;
1012 textureTableIndexStruct_s *tti;
1013 ttglobal tg = gglobal();
1014
1015 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, style->weightTransferFunction1,tmpN);
1016 tg->RenderFuncs.texturenode = (void*)tmpN;
1017
1018 //problem: I don't want it sending image dimensions to my volume shader,
1019 // which could confuse the voxel sampler
1020 //render_node(tmpN); //render_node(node->texture);
1021 loadTextureNode(tmpN,NULL);
1022 tti = getTableTableFromTextureNode(tmpN);
1023 if(tti && tti->status >= TEX_LOADED){
1024 glActiveTexture(GL_TEXTURE0+2);
1025 glBindTexture(GL_TEXTURE_2D,tti->OpenGLTexture);
1026 havetextures |= 1;
1027 }
1028 }
1029 if(style->weightTransferFunction2){
1030 //load texture
1031 struct X3D_Node *tmpN;
1032 textureTableIndexStruct_s *tti;
1033 ttglobal tg = gglobal();
1034
1035 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, style->weightTransferFunction2,tmpN);
1036 tg->RenderFuncs.texturenode = (void*)tmpN;
1037
1038 //problem: I don't want it sending image dimensions to my volume shader,
1039 // which could confuse the voxel sampler
1040 //render_node(tmpN); //render_node(node->texture);
1041 loadTextureNode(tmpN,NULL);
1042 tti = getTableTableFromTextureNode(tmpN);
1043 if(tti && tti->status >= TEX_LOADED){
1044 glActiveTexture(GL_TEXTURE0+3);
1045 glBindTexture(GL_TEXTURE_2D,tti->OpenGLTexture);
1046 havetextures |= 2;
1047 }
1048 }
1049 iopactex = GET_UNIFORM(myProg,"fw_haveTransfers");
1050 glUniform1i(iopactex,havetextures);
1051
1052
1053 glGetIntegerv(GL_VIEWPORT, iviewport); //xmin,ymin,w,h
1054
1055 vp = GET_UNIFORM(myProg,"fw_viewport");
1056 viewport[0] = (float)iviewport[0]; //xmin
1057 viewport[1] = (float)iviewport[1]; //ymin
1058 viewport[2] = (float)iviewport[2]; //width
1059 viewport[3] = (float)iviewport[3]; //height
1060 GLUNIFORM4F(vp,viewport[0],viewport[1],viewport[2],viewport[3]);
1061
1062 //draw the box
1063
1064 Vertices = GET_ATTRIB(myProg,"fw_Vertex");
1065 mvm = GET_UNIFORM(myProg,"fw_ModelViewMatrix"); //fw_ModelViewMatrix
1066 proj = GET_UNIFORM(myProg,"fw_ProjectionMatrix"); //fw_ProjectionMatrix
1067 sendExplicitMatriciesToShader(mvm,proj,-1,NULL,-1);
1068 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewMatrix);
1069 FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, projMatrix);
1070
1071 glEnableVertexAttribArray(Vertices);
1072
1073 glVertexAttribPointer(Vertices, 3, GL_FLOAT, GL_FALSE, 0, dataParent->_boxtris);
1074
1075
1076 glEnable(GL_CULL_FACE);
1077 glFrontFace(GL_CW);
1078 glDrawArrays(GL_TRIANGLES,0,36);
1079 glDisable(GL_CULL_FACE);
1080
1081 }else if(method_draw_quad){
1083 //GLint Vertices = GET_ATTRIB(myProg,"fw_Vertex");
1084 //glEnableVertexAttribArray(Vertices);
1085 //glVertexAttribPointer(Vertices, 3, GL_FLOAT, GL_FALSE, 0, box);
1086 //glDrawArrays(GL_TRIANGLES,0,6); //6 vertices for quad
1087 }
1088
1089 }
1090 #endif //BLENDED
1091 }
1092 case NODE_ComposedVolumeStyle:
1093 {
1094 int i;
1095 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#ComposedVolumeStyle
1096 struct X3D_ComposedVolumeStyle *style = (struct X3D_ComposedVolumeStyle*)vstyle;
1097 for(i=0;i<style->renderStyle.n;i++){
1098 fin_volumestyle(style->renderStyle.p[i],dataParent);
1099 }
1100 }
1101 break;
1102
1103 default:
1104 break;
1105 }
1106 }
1107}
1108int volstyle_needs_normal(struct X3D_Node *vstyle){
1109 //IDEA: compute image gradient and store in RGB, if a style requests it
1110 // then surfaceNormal = normalize(gradient)
1111 //SFNode [in,out] surfaceNormals NULL [X3DTexture3DNode
1112 // Cartoon
1113 // Edge
1114 // Shaded
1115 // SilhouetteEnhancement
1116 // ToneMappedVolumeStyle
1117 //
1118 //SFNode [in,out] gradients NULL [X3DTexture3DNode]
1119 // IsoSurfaceVolumeData
1120 //
1121 //SFNode [in,out] segmentIdentifiers NULL [X3DTexture3DNode]
1122 // SegmentedVolumeData
1123 int need_normal;
1124 struct X3D_OpacityMapVolumeStyle *style0 = (struct X3D_OpacityMapVolumeStyle*)vstyle;
1125 need_normal = FALSE;
1126 if(style0->enabled){
1127 switch(vstyle->_nodeType){
1128 case NODE_ComposedVolumeStyle:
1129 {
1130 int i;
1131 struct X3D_ComposedVolumeStyle *style = (struct X3D_ComposedVolumeStyle*)vstyle;
1132 for(i=0;i<style->renderStyle.n;i++){
1133 need_normal = need_normal || volstyle_needs_normal(style->renderStyle.p[i]);
1134 }
1135 }
1136 break;
1137 case NODE_CartoonVolumeStyle:
1138 case NODE_EdgeEnhancementVolumeStyle:
1139 case NODE_ShadedVolumeStyle:
1140 case NODE_SilhouetteEnhancementVolumeStyle:
1141 case NODE_ToneMappedVolumeStyle:
1142 {
1143 //in perl structs, for these nodes its all the 3rd field after enabled, metadata, surfacenormals
1144 struct X3D_ToneMappedVolumeStyle *style = (struct X3D_ToneMappedVolumeStyle*)vstyle;
1145 need_normal = need_normal || (style->surfaceNormals == NULL);
1146 }
1147 break;
1148 default:
1149 break;
1150 }
1151 }
1152 return need_normal;
1153}
1154
1155void compile_IsoSurfaceVolumeData(struct X3D_IsoSurfaceVolumeData *node){
1156 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#IsoSurfaceVolumeData
1157 // VolumeData + 4 fields:
1158 //SFFloat [in,out] contourStepSize 0 (-INF,INF)
1159 //SFNode [in,out] gradients NULL [X3DTexture3DNode]
1160 //SFFloat [in,out] surfaceTolerance 0 [0,INF)
1161 //MFFloat [in,out] surfaceValues [] (-INF,INF)
1162 printf("compile_isosurfacevolumedata not implemented\n");
1163 compile_VolumeData((struct X3D_VolumeData *)node);
1164}
1165
1166
1167
1168void compile_SegmentedVolumeData(struct X3D_SegmentedVolumeData *node){
1169 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#SegmentedVolumeData
1170 // VolumeData + 2 fields:
1171 //MFBool [in,out] segmentEnabled []
1172 //SFNode [in,out] segmentIdentifiers NULL [X3DTexture3DNode]
1173 printf("compile_segmentedvolumedata \n");
1174 compile_VolumeData((struct X3D_VolumeData *)node);
1175}
1176s_shader_capabilities_t * getVolumeProgram(struct X3D_Node **renderStyle, int nstyle, int VOLUME_DATA_FLAG){
1177 static int once = 0;
1178 unsigned int volflags;
1179 int i;
1180 s_shader_capabilities_t *caps;
1181
1182 if(!once)
1183 ConsoleMessage("getVolumeProgram\n");
1184 volflags = 0;
1185 if(nstyle){
1186 for(i=0;i<nstyle;i++){
1187 struct X3D_OpacityMapVolumeStyle *style0 = (struct X3D_OpacityMapVolumeStyle*)renderStyle[i];
1188 if(style0->enabled){
1189 volflags = prep_volumestyle(renderStyle[i], volflags); //get shader flags
1190 }
1191 }
1192 }else{
1193 volflags = SHADERFLAGS_VOLUME_STYLE_DEFAULT;
1194 }
1195
1196 if(!once){
1197 printf("volflags= ");
1198 for(i=0;i<8;i++)
1199 printf("%d ",((volflags >> (8-i-1)*4) & 0xF)); //show 4 int
1200 printf("\n");
1201 }
1202
1203 //render
1204 //Step 1: set the 3D texture
1205 //if(node->voxels)
1206 // render_node(node->voxels);
1207 //Step 2: get rays to cast: start point and direction vector for each ray to cast
1208
1209 //method: use cpu math to compute a few uniforms so frag shader can do box intersections
1210 //http://prideout.net/blog/?p=64
1211 //- one step raycasting using gl_fragCoord
1212 //- we modified this general method to use gluUnproject math instead of focallength
1213
1214 //Step 3: accumulate along rays and render opacity fragment in one step
1215 //GPU VERSION
1216 {
1217 shaderflagsstruct shader_requirements; //shaderflags,
1218 // OLDCODE GLint myProg;
1219
1220 memset(&shader_requirements,0,sizeof(shaderflagsstruct));
1221 //shaderflags = getShaderFlags();
1222 shader_requirements.volume = VOLUME_DATA_FLAG; //SHADERFLAGS_VOLUME_DATA_BASIC; //send the following through the volume ubershader
1223 shader_requirements.volume |= (volflags << 4); //SHADERFLAGS_VOLUME_STYLE_OPACITY;
1224 //CLIPPLANES ?
1225 shader_requirements.base |= getShaderFlags().base & CLIPPLANE_SHADER;
1226 // by default we'll mash it in: shader_requirements.volume |= TEX3D_SHADER;
1227 caps = getMyShaders(shader_requirements);
1228 enableGlobalShader(caps);
1229 // OLDCODE myProg = caps->myShaderProgram;
1230 }
1231 //Step 1: set the 3D texture
1232 once = 1;
1233 //return myProg;
1234 return caps;
1235}
1236
1237void render_SEGMENTED_volume_data(s_shader_capabilities_t *caps, struct X3D_Node *segmentIDs, int itexture, struct X3D_SegmentedVolumeData *node) {
1238 int myProg;
1239 GLint inids, ienable;
1240
1241 int *enabledIDs = node->segmentEnabled.p;
1242 int nIDs = node->segmentEnabled.n;
1243 myProg = caps->myShaderProgram;
1244 if(segmentIDs){
1245 struct X3D_Node *tmpN;
1246 textureTableIndexStruct_s *tti;
1247 ttglobal tg = gglobal();
1248
1249 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, segmentIDs,tmpN);
1250 tg->RenderFuncs.texturenode = (void*)tmpN;
1251
1252 render_node(tmpN); //render_node(node->voxels);
1253
1254 tti = getTableTableFromTextureNode(tmpN);
1255 if(tti && tti->status >= TEX_LOADED){
1256 GLint TextureUnit;
1257 if(0){
1258 //in theory these will be set by the main voxel texture but don't match
1259 //here we want NEAREST not LINEAR
1260 GLint tex3dUseVertex, ttiles, repeatSTR, magFilter;
1261 ttiles = GET_UNIFORM(myProg,"tex3dTiles");
1262 GLUNIFORM1IV(ttiles,3,tti->tiles);
1263
1264 //me->tex3dUseVertex = GET_UNIFORM(myProg,"tex3dUseVertex");
1265 tex3dUseVertex = GET_UNIFORM(myProg,"tex3dUseVertex");
1266 glUniform1i(tex3dUseVertex,0);
1267 repeatSTR = GET_UNIFORM(myProg,"repeatSTR");
1268 glUniform1iv(repeatSTR,3,tti->repeatSTR);
1269 magFilter = GET_UNIFORM(myProg,"magFilter");
1270 glUniform1i(magFilter,0); //tti->magFilter); //NEAREST
1271 }
1272 TextureUnit= GET_UNIFORM(myProg,"fw_Texture_unit1");
1273 glUniform1i(TextureUnit,itexture);
1274 glActiveTexture(GL_TEXTURE0+itexture);
1275 glBindTexture(GL_TEXTURE_2D,tti->OpenGLTexture);
1276 FW_GL_TEXPARAMETERI( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //don't interpolate integer segment IDs
1277 }
1278 }
1279 inids = GET_UNIFORM(myProg,"fw_nIDs");
1280 glUniform1i(inids,nIDs);
1281 ienable = GET_UNIFORM(myProg,"fw_enableIDs");
1282 glUniform1iv(ienable,nIDs,enabledIDs);
1283
1284 //similar to ISO, there are multiple rendering styles
1285 if(node->renderStyle.n){
1286 int i, *styleflags,instyles;
1287 GLint istyles;
1288
1289 styleflags = MALLOC(int*,sizeof(int)*node->renderStyle.n);
1290 for(i=0;i<node->renderStyle.n;i++){
1291 styleflags[i] = prep_volumestyle(node->renderStyle.p[i],0);
1292 }
1293 //printf("%d %d\n",styleflags[0],styleflags[1]);
1294 istyles = GET_UNIFORM(myProg,"fw_surfaceStyles");
1295 glUniform1iv(istyles,node->renderStyle.n,styleflags);
1296 instyles = GET_UNIFORM(myProg,"fw_nStyles");
1297 glUniform1i(instyles,node->renderStyle.n);
1298 }
1299
1300
1301
1302}
1303
1304float *getTransformedClipPlanes();
1305int getClipPlaneCount();
1306void sendFogToShader(s_shader_capabilities_t *me);
1307void sendLightInfo2(s_shader_capabilities_t* me);
1308int peek_group_visible();
1309void render_GENERIC_volume_data(s_shader_capabilities_t *caps, struct X3D_Node **renderStyle, int nstyle, struct X3D_Node *voxels, struct X3D_VolumeData *node ) {
1310 static int once = 0;
1311 int myProg;
1312 //unsigned int volflags;
1313 GLint Vertices, mvm, proj, mvpi;
1314 double modelviewMatrix[16],projMatrix[16], mvp[16], mvpinverse[16]; // mvmInverse[16],
1315 float spmat[16];
1316 int nsend;
1317 GLint iclipplanes, inclipplanes;
1318 float *clipplanes;
1319 GLint iviewport[4];
1320 float viewport[4];
1321 GLint vp, dim;
1322 float *dimensions;
1323
1324 ttglobal tg = gglobal();
1325
1326 myProg = caps->myShaderProgram;
1327
1328 if(voxels){
1329 struct X3D_Node *tmpN;
1330 textureTableIndexStruct_s *tti;
1331 POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, voxels,tmpN);
1332 tg->RenderFuncs.texturenode = (void*)tmpN;
1333
1334 //gradient > Oct 2016 we compute in textures.c if channels==1 and z>1 and put in rgb
1335 // - saves mallocing another RGBA
1336 // - for scalar images RGB is unused or just 111 anyway
1337 // - takes 1 second on desktop CPU for 17 Mpixel image
1338 //if(node->renderStyle){
1339 // if(volstyle_needs_normal(node->renderStyle)){
1340 // switch(tmpN->_nodeType){
1341 // case NODE_PixelTexture3D:
1342 // ((struct X3D_PixelTexture3D*)tmpN)->_needs_gradient = TRUE; break;
1343 // case NODE_ImageTexture3D:
1344 // ((struct X3D_ImageTexture3D*)tmpN)->_needs_gradient = TRUE; break;
1345 // }
1346 // }
1347 //}
1348 //render_node(voxels) should keep pulling the texture through all stages of loading and opengl
1349 render_node(tmpN); //render_node(node->voxels);
1350
1351 tti = getTableTableFromTextureNode(tmpN);
1352 if(tti && tti->status >= TEX_LOADED){
1353 GLint ttiles, tex3dUseVertex,repeatSTR,magFilter;
1354 ttiles = GET_UNIFORM(myProg,"tex3dTiles");
1355 GLUNIFORM1IV(ttiles,3,tti->tiles);
1356
1357 //me->tex3dUseVertex = GET_UNIFORM(myProg,"tex3dUseVertex");
1358 tex3dUseVertex = GET_UNIFORM(myProg,"tex3dUseVertex");
1359 glUniform1i(tex3dUseVertex,0);
1360 repeatSTR = GET_UNIFORM(myProg,"repeatSTR");
1361 glUniform1iv(repeatSTR,3,tti->repeatSTR);
1362 magFilter = GET_UNIFORM(myProg,"magFilter");
1363 glUniform1i(magFilter,1); //need LINEAR //tti->magFilter);
1364
1365 glActiveTexture(GL_TEXTURE0);
1366 glBindTexture(GL_TEXTURE_2D,tti->OpenGLTexture);
1367 FW_GL_TEXPARAMETERI( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1368
1369 }
1370 }
1371 if(nstyle){
1372 int i;
1373 for(i=0;i<nstyle;i++){
1374 struct X3D_OpacityMapVolumeStyle *style0 = (struct X3D_OpacityMapVolumeStyle*)renderStyle[i];
1375 if(style0->enabled){
1376 render_volumestyle(renderStyle[i],myProg); //send uniforms
1377 // if style uses a texture, it should be the next texture ie GL_TEXTURE0+1,2..
1378 }
1379 }
1380 }
1381 //3.1 set uniforms: dimensions, focal length, fov (field of view), window size, modelview matrix
1382 // set attributes vertices of triangles of bounding box
1383 // set box with vol.dimensions with triangles
1384 Vertices = GET_ATTRIB(myProg,"fw_Vertex");
1385 mvm = GET_UNIFORM(myProg,"fw_ModelViewMatrix"); //fw_ModelViewMatrix
1386 proj = GET_UNIFORM(myProg,"fw_ProjectionMatrix"); //fw_ProjectionMatrix
1387 if(!once)
1388 ConsoleMessage("vertices %d mvm %d proj %d\n",Vertices,mvm,proj);
1389 sendExplicitMatriciesToShader(mvm,proj,-1,NULL,-1);
1390 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewMatrix);
1391 FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, projMatrix);
1392 if(1){
1393 //see gluUnproject in Opengl_Utils.c
1394 __gluMultMatricesd(modelviewMatrix, projMatrix, mvp);
1395 if (!__gluInvertMatrixd(mvp, mvpinverse)) return;
1396 }else{
1397 matmultiplyFULL(mvp,modelviewMatrix,projMatrix);
1398 //matmultiplyFULL(mvp,projMatrix,modelviewMatrix);
1399 //if (!__gluInvertMatrixd(mvp, mvpinverse)) return;
1400 matinverseFULL(mvpinverse,mvp); //seems different than glu's. H0: just wrong H1: transopose H2: full inverse vs factorized
1401 }
1402 matdouble2float4(spmat,mvpinverse);
1403
1404 mvpi = GET_UNIFORM(myProg,"fw_ModelViewProjInverse");
1405 GLUNIFORMMATRIX4FV(mvpi,1,GL_FALSE,spmat);
1406
1407
1408//SEND CLIPPLANES?
1409 //sendClipplanesToShader(mysp);
1410 clipplanes = getTransformedClipPlanes();
1411
1412 nsend = getClipPlaneCount();
1413 iclipplanes = GET_UNIFORM(myProg,"fw_clipplanes");
1414 inclipplanes = GET_UNIFORM(myProg,"fw_nclipplanes");
1415
1416 GLUNIFORM4FV(iclipplanes,nsend,clipplanes);
1417 GLUNIFORM1I(inclipplanes,nsend);
1418
1419//SEND LIGHTS IF WE HAVE A SHADER STYLE
1420 //int haveShaderStyle = FALSE;
1421 //if(nstyle){
1422 // for(int i=0;i<nstyle;i++){
1423 // haveShaderStyle = haveShaderStyle || (renderStyle[i]->_nodeType == NODE_ShadedVolumeStyle);
1424 // }
1425 //}
1426 //if(haveShaderStyle){
1427 //send lights
1428 if (caps->haveLightInShader) {
1429 sendLightInfo2(caps);
1430 sendFogToShader(caps);
1431 }
1432 //}
1433
1434
1435
1436 //get the current viewport
1437 glGetIntegerv(GL_VIEWPORT, iviewport); //xmin,ymin,w,h
1438 vp = GET_UNIFORM(myProg,"fw_viewport");
1439 viewport[0] = (float)iviewport[0]; //xmin
1440 viewport[1] = (float)iviewport[1]; //ymin
1441 viewport[2] = (float)iviewport[2]; //width
1442 viewport[3] = (float)iviewport[3]; //height
1443 GLUNIFORM4F(vp,viewport[0],viewport[1],viewport[2],viewport[3]);
1444 dim = GET_UNIFORM(myProg,"fw_dimensions");
1445 dimensions = node->dimensions.c;
1446 GLUNIFORM3F(dim,dimensions[0],dimensions[1],dimensions[2]);
1447 float center[3];
1448 bbox2extent6f(vecset3f(center,0.0f,0.0f,0.0f),dimensions,node->_extent);
1449 extent6f_union_extent6f(peek_group_extent(),node->_extent);
1450 if(!once) ConsoleMessage("dim %d vp %d \n",dim,vp );
1451
1452 //3.2 draw with shader
1453 glEnableVertexAttribArray(Vertices);
1454 glVertexAttribPointer(Vertices, 3, GL_FLOAT, GL_FALSE, 0, node->_boxtris);
1455 // https://www.opengl.org/wiki/Face_Culling
1456 glEnable(GL_CULL_FACE);
1457 //we want to draw only either back/far or front/near triangles, not both
1458 //so that we comput a ray only once.
1459 //and because we want to use clipplane (or frustum near side) to slice into
1460 //volumes, we want to make sure we are still getting ray fragments when slicing
1461 //so instead of drawing the front faces (which would slice away fragments/rays)
1462 //we want to draw only the far/back triangles so even when slicing, we'll get
1463 //fragment shader calls, and can compute rays.
1464 //assuming our triangles are defined CCW (normal)
1465 //setting front-face to GL_CW should ensure only the far/back triangles are rendered
1466 glFrontFace(GL_CW);
1467 if(peek_group_visible())
1468 glDrawArrays(GL_TRIANGLES,0,36);
1469 glDisable(GL_CULL_FACE);
1470 if(voxels){
1471 tg->RenderFuncs.textureStackTop = 0;
1472 tg->RenderFuncs.texturenode = NULL;
1473 }
1474 if(nstyle){
1475 int i;
1476 for(i=0;i<nstyle;i++)
1477 fin_volumestyle(renderStyle[i],node);
1478 }
1479 once = 1;
1480
1481}
1482
1483void child_SegmentedVolumeData(struct X3D_SegmentedVolumeData *node){
1484 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#SegmentedVolumeData
1485 // VolumeData + 2 fields:
1486 //MFBool [in,out] segmentEnabled []
1487 //SFNode [in,out] segmentIdentifiers NULL [X3DTexture3DNode]
1488 s_shader_capabilities_t *caps;
1489 static int once = 0;
1490 COMPILE_IF_REQUIRED
1491
1492 if (renderstate()->render_blend == (node->_renderFlags & VF_Blend)) {
1493 int itexture = 1; //voxels=0,segmentIDs=1
1494
1495 prep_BBox((struct BBoxFields*)&node->bboxCenter);
1496
1497 if(!once)
1498 printf("child segmentedvolumedata \n");
1499 //int nstyles = 0;
1500 //if(node->renderStyle) nstyles = 1;
1501
1502 caps = getVolumeProgram(node->renderStyle.p,node->renderStyle.n, SHADERFLAGS_VOLUME_DATA_SEGMENT);
1503 //get and set segment-specific uniforms
1504 itexture = 1; //voxels=0,segmentIDs=1
1505 render_SEGMENTED_volume_data(caps,node->segmentIdentifiers,itexture,node);
1506 //render generic volume
1507 render_GENERIC_volume_data(caps,node->renderStyle.p,node->renderStyle.n,node->voxels,(struct X3D_VolumeData*)node );
1508
1509 fin_BBox((struct X3D_Node*)node,(struct BBoxFields*)&node->bboxCenter,FALSE);
1510
1511 once = 1;
1512 } //if VF_Blend
1513
1514}
1515void render_ISO_volume_data(s_shader_capabilities_t *caps,struct X3D_IsoSurfaceVolumeData *node){
1516 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#IsoSurfaceVolumeData
1517 // VolumeData + 4 fields, minus 1 field
1518 //SFFloat [in,out] contourStepSize 0 (-INF,INF)
1519 //SFNode [in,out] gradients NULL [X3DTexture3DNode]
1520 //SFFloat [in,out] surfaceTolerance 0 [0,INF)
1521 //MFFloat [in,out] surfaceValues [] (-INF,INF)
1522 //MFNode [in,out] renderStyle [] [X3DVolumeRenderStyleNode]
1523 //minus SFNode renderStyle
1524 int myProg;
1525 GLint istep, itol,ivals,invals;
1526 myProg= caps->myShaderProgram;
1527 istep = GET_UNIFORM(myProg,"fw_stepSize");
1528 glUniform1f(istep,node->contourStepSize);
1529 itol = GET_UNIFORM(myProg,"fw_tolerance");
1530 glUniform1f(itol,node->surfaceTolerance);
1531
1532 ivals = GET_UNIFORM(myProg,"fw_surfaceVals");
1533 glUniform1fv(ivals,node->surfaceValues.n,node->surfaceValues.p);
1534 invals = GET_UNIFORM(myProg,"fw_nVals");
1535 glUniform1i(invals,node->surfaceValues.n);
1536 applysurfaceNormalTexture(node->gradients, myProg);
1537
1538 if(node->renderStyle.n){
1539 int i;
1540 // OLDCODE GLint istyles;
1541 GLint instyles;
1542 int *styleflags = MALLOC(int*,sizeof(int)*node->renderStyle.n);
1543 for(i=0;i<node->renderStyle.n;i++){
1544 styleflags[i] = prep_volumestyle(node->renderStyle.p[i],0);
1545 }
1546 // OLDCODE istyles = GET_UNIFORM(myProg,"fw_surfaceStyles");
1547 glUniform1iv(ivals,node->renderStyle.n,styleflags);
1548 instyles = GET_UNIFORM(myProg,"fw_nStyles");
1549 glUniform1i(instyles,node->renderStyle.n);
1550 }
1551
1552 //renderstyle handling?
1553 //Options:
1554 // a) include all renderstyles in the shader
1555 // b) go through the list and |= (multiple times should show up as once?)
1556 // then make a special shader to (equivalent to switch-case) on each voxel/gradient after iso value has been computed
1557}
1558
1559void child_IsoSurfaceVolumeData(struct X3D_IsoSurfaceVolumeData *node){
1560 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#IsoSurfaceVolumeData
1561 // VolumeData + 4 fields:
1562 //SFFloat [in,out] contourStepSize 0 (-INF,INF)
1563 //SFNode [in,out] gradients NULL [X3DTexture3DNode]
1564 //SFFloat [in,out] surfaceTolerance 0 [0,INF)
1565 //MFFloat [in,out] surfaceValues [] (-INF,INF)
1566 static int once = 0;
1567 COMPILE_IF_REQUIRED
1568 if (renderstate()->render_blend == (node->_renderFlags & VF_Blend)) {
1569 unsigned int voldataflags;
1570 s_shader_capabilities_t *caps;
1571 int MODE;
1572
1573 prep_BBox((struct BBoxFields*)&node->bboxCenter);
1574
1575 if(!once)
1576 printf("child segmentedvolumedata \n");
1577 voldataflags = SHADERFLAGS_VOLUME_DATA_ISO;
1578
1579 MODE = node->surfaceValues.n == 1 ? 1 : 3;
1580 MODE = node->contourStepSize != 0.0f && MODE == 1 ? 2 : 1;
1581 if(MODE == 3)
1582 voldataflags |= SHADERFLAGS_VOLUME_DATA_ISO_MODE3;
1583 caps = getVolumeProgram(node->renderStyle.p,node->renderStyle.n, voldataflags);
1584 //get and set ISO-specific uniforms
1585
1586
1587 render_ISO_volume_data(caps,node);
1588 //render generic volume
1589 render_GENERIC_volume_data(caps,node->renderStyle.p,node->renderStyle.n,node->voxels,(struct X3D_VolumeData*)node );
1590
1591 fin_BBox((struct X3D_Node*)node,(struct BBoxFields*)&node->bboxCenter,FALSE);
1592
1593 once = 1;
1594 } //if VF_Blend
1595}
1596
1597void child_VolumeData(struct X3D_VolumeData *node){
1598 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#VolumeData
1599 // VolumeData
1600 s_shader_capabilities_t *caps;
1601 static int once = 0;
1602 COMPILE_IF_REQUIRED
1603
1604 if (renderstate()->render_blend == (node->_renderFlags & VF_Blend)) {
1605 int nstyles = 0;
1606 if(!once)
1607 printf("child volumedata \n");
1608 if(node->renderStyle) nstyles = 1;
1609
1610 prep_BBox((struct BBoxFields*)&node->bboxCenter);
1611
1612 caps = getVolumeProgram(&node->renderStyle,nstyles, SHADERFLAGS_VOLUME_DATA_BASIC);
1613 //render generic volume
1614 render_GENERIC_volume_data(caps,&node->renderStyle,nstyles,node->voxels,(struct X3D_VolumeData*)node );
1615
1616 fin_BBox((struct X3D_Node*)node,(struct BBoxFields*)&node->bboxCenter,FALSE);
1617
1618 once = 1;
1619 } //if VF_Blend
1620
1621}