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