FreeWRL/FreeX3D  3.0.0
Component_CubeMapTexturing.c
1 /*
2 
3 
4 X3D Cubemap Texturing Component
5 
6 */
7 
8 /****************************************************************************
9  This file is part of the FreeWRL/FreeX3D Distribution.
10 
11  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
12 
13  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
14  it under the terms of the GNU Lesser Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  GNU General Public License for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
25 ****************************************************************************/
26 
27 
28 #include <config.h>
29 
30 #include <system.h>
31 #include <display.h>
32 #include <internal.h>
33 
34 #include <libFreeWRL.h>
35 #include "../vrml_parser/Structs.h"
36 #include "../main/headers.h"
37 #include "../opengl/OpenGL_Utils.h"
38 #include "../opengl/Textures.h"
39 #include "../scenegraph/Component_Shape.h"
40 #include "../scenegraph/LinearAlgebra.h"
41 #include "../scenegraph/Component_CubeMapTexturing.h"
42 #include "../input/EAIHelpers.h"
43 #include "../vrml_parser/CParseGeneral.h" /* for union anyVrml */
44 
45 #ifndef HAVE_UINT32
46 # define uint32 uint32_t
47 #endif
48 
49 
50 /*
51 
52 "CUBEMAP STANDARDS"?
53 - left to right is usually obvious - sky usually at top
54 a) for the single image -+-- layout its usually ovbious which way to shoot down and top images:
55  -top of down image is contiguous with bottom of front
56  -bottom of up image is contiguous with top of front
57  https://msdn.microsoft.com/en-us/library/windows/desktop/bb204881(v=vs.85).aspx
58  - direct3D cubic environment mapping
59  - no talk of DDS, but shows +- layout on single uv image (relative to LHS object space axes, Y up)
60  +y
61  -x +z +x -z
62  -y
63 
64 b) for otherwise piecewise cubemaps its a little less obvious, needs standards:
65 
66 http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/env_texture.html#Textureorientation
67 Web3D has texture orientation
68 - Front is on the XY plane, in RHS
69 - Left is on the YZ plane
70 +x == Right
71 -x == Left
72 +y == Top
73 -y == Down
74 +z == Back
75 -z == Front
76 so to match DX ordering:
77 R,L,T,D,B,F
78 x no mention of which way is up on the the top and bottom images
79 
80 http://wiki.simigon.com/wiki/index.php?title=Dds_cubemaps
81 - has instructions for generating via maya -> photoshop -> dds
82 - rotations of images: 4 sides are obvious, top at top
83 x up/down seem rotatated:
84 - Up has Right at top (+x when looking from center)
85 x Down has Left at top (-x when looking from center)
86 file order: F,B,U,D,L,R
87 Assuming F==+x: in LHS system:
88 file order: +x,-x,+y,-y,+z,-z
89 - with top of Top against -z, top of bottom against +z
90 
91 OpenGL Redbook p.441 has no diagram, but hints at the same face ordering as dds.
92 
93 https://docs.unity3d.com/Manual/class-Cubemap.html
94 Unity uses Y up, and (unlike web3d) LHS
95 Right +x
96 Left -x
97 Top +Y
98 Bottom -Y
99 Front +z
100 Back -Z
101 Top of the bottom image is Left -x like simigon says about DDS cubemap
102 Top of the top image is front or back likely +z front
103 
104 http://stackoverflow.com/questions/11685608/convention-of-faces-in-opengl-cubemapping
105 - mentions of renderman
106 - a LHS diagram for figuring opengl cube map
107 http://www.nvidia.com/object/cube_map_ogl_tutorial.html
108 - the refleciton pool architecture model images I'm using are from an nVidia oopengl cubemap tutorial
109 
110 
111 http://developer.amd.com/tools-and-sdks/archive/games-cgi/cubemapgen/
112 CCubeMapProcessor.cpp:
113 // D3D cube map face specification
114 // mapping from 3D x,y,z cube map lookup coordinates
115 // to 2D within face u,v coordinates
116 //
117 // --------------------> U direction
118 // | (within-face texture space)
119 // | _____
120 // | | |
121 // | | +Y |
122 // | _____|_____|_____ _____
123 // | | | | | |
124 // | | -X | +Z | +X | -Z |
125 // | |_____|_____|_____|_____|
126 // | | |
127 // | | -Y |
128 // | |_____|
129 // |
130 // v V direction
131 // (within-face texture space)
132 - that's an LHS (Left-Handed coordinate System)
133 - don't take the U,V as absolute in this diagram, but rather as directional hint
134 - if +Y is top, -Y bottom, +Z front, -Z back, then its saying:
135  top of the Top is against Back, and top of the Bottom is against Front.
136 x doesn't explain the order of faces in .dds file
137 * does harmonize with simigon above, which has (dug9-derived) file face order (LHS Z):
138  _____ _____ _____ _____ _____ _____
139  | | | | | | |
140  | +X | -X | +Y | -Y | +Z | -Z |
141  |_____|_____|_____|_____|_____|_____|
142 
143 
144 SUMMARY OF BEST GUESS OF DDS CUBEMAP LAYOUT:
145 a) LHS: +y is up, xy form RHS 2D axes, +z is LHS relative to xy
146 b) face order in file: (as per simigon derived diagram above):
147  +x (Right), -x (Left), +y (Top), -y(Bottom), +z(Front, in LHS), -z(Back, in LHS)
148 c) uv direction per face (as per CubeMapGen diagram above):
149  - x,z faces (+x/Right,-x/Left,+z/Front,-z/Back): top of image is up;
150  - +y(Top): top of Top is against -z(Back)
151  - -y(Bottom): top of Bottom is against +z(Front)
152 This interpretation matches the 2nd diagram on this page:
153 https://msdn.microsoft.com/en-us/library/windows/desktop/bb204881(v=vs.85).aspx
154 
155 
156 CUBEMAP FORMAT FOR INTERNAL FREEWRL AND .WEB3DIT
157 http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/env_texture.html#Textureorientation
158 Similar to above for DDS summary, except:
159 1. using opengl/web3d RHS: when naming the faces by signed axis:-
160  sign on z is reversed, -z is Front, +z is Back
161 2. order: +x,-x,+y,-y,+z,-z except +z,-z mean something different. So relative to DDS, we swap Front and Back
162  Back is before Front in linear list
163 
164 a) RHS with y-up, -z Front
165 b) face order in linear array:
166  +x (Right), -x (Left), +y (Top), -y(Bottom), +z(Back, in RHS), -z(Front, in RHS)
167 c) uv direction per face - (same as DDS)
168  - x,z faces: top of image is up
169  - +y(Top): top of Top is against +z(Back)
170  - -y(Bottom): top of Bottom is against -z(Front)
171 
172 OPENGL CUBETEXTURE CONVENTION
173 https://www.opengl.org/registry/doc/glspec21.20061201.pdf
174 section 3.8.6, p.170, table 3.19 shows how your 3D texture coordinate
175 is used in the sampler:
176 Major Axis
177 Direction Target sc tc ma
178 +rx TEXTURE CUBE MAP POSITIVE X -rz -ry rx
179 -rx TEXTURE CUBE MAP NEGATIVE X rz -ry rx
180 +ry TEXTURE CUBE MAP POSITIVE Y rx rz ry
181 -ry TEXTURE CUBE MAP NEGATIVE Y rx -rz ry
182 +rz TEXTURE CUBE MAP POSITIVE Z rx -ry rz
183 -rz TEXTURE CUBE MAP NEGATIVE Z -rx -ry rz
184 Take the +rx - the plus x face. If you're in the center of the cube
185 at the origin, looking down the +x axis, in a Y-up RHS system, shouldn't
186 you see +z going to your right, and +y going up, in the 2D texture coordinate
187 system? Opengl has them both negative.
188 
189 Its a bit bizzarre and makes more sense
190 if thinking of texture rows as y-down like images, and xyz as LHS - 2 things
191 that seem un-opengl-like. Someone said its using renderman convention for cubemaps.
192 
193 There's no way to intercept the output of this table before its used in cubeSampler.
194 
195 In freewrl we have been flipping texture rows to be y-down in Textures.c L.1432 in move_texture_to_opengl()
196 - and for ComposedTexture below we exchange left/right and front/back textures
197 - we still need to reflect one axis of our RHS reflection vector to get from our RHS to renderman LHS,
198 x hard to find a way to do that in the shader that works for all cubemap faces
199 
200 http://www.3dcpptutorials.sk/index.php?id=24
201 - this developer shows there's a way to do it without flipping your textures y-down
202 -- 'just' re-arranging textures and rotating around 180
203 -- I tried with composed, and it worked by doing 3 things:
204  a) don't flip y-down in textures.c L.1432
205  if(0){
206  //flip cubemap textures to be y-down following opengl specs table 3-19
207  b) swap faces in pairs so right goes to (our count=1) GL_CUBEMAP_NEGATIVE_X instead of (our count=0) POSITIVE_X
208  case 1: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->right,thistex); break;}
209  c) in vertex shader reflect 2 axes of the reflection vector
210  fw_TexCoord[0].yz = -fw_TexCoord[0].yz;
211 So could be rolled out for Composed, Generated, Image Cubemaps
212 
213 
214 OpenGL has defined constants for cubemap faces:
215 - GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT
216 - in numerical order +X, -X, +Y, -Y, +Z, -Z
217  http://learnopengl.com/#!Advanced-OpenGL/Cubemaps
218 - assume (untested): uv directions are same as FREEWRL/WEB3DIT and DDS:
219  - top of x,z faces: +y/up
220  - top of Top: adjacent to Back
221  - top of Bottom: adjacent to Front
222 
223 SUMMARY OF CUBEMAP
224 I've confirmed my proper creation of dds cubemap with Gimp DDS using ATI's CubeMapGen utility
225 http://developer.amd.com/tools-and-sdks/archive/games-cgi/cubemapgen/
226 - CubeMapGen uses an axis numbering scheme that matches DX/DDS conventions
227 
228 WORKING with DDS cubemap and -+-- tee layout single images Sept 12, 2016
229 Not done:
230 - figure out how/why other browsers (octaga, instantplayer, view3dscene) accept .dds, but show a spiral texture
231 - auto-detect 1x6, 2x3 (6x1, 3x2?) and 1x1 (earth/spherical texture) layouts
232  - InstantReality uses 1x1 spherical image map with single .png
233  x tried 1x6 and 2x3 but other browsers aren't using those layouts either
234 
235 GENERATEDCUBEMAP aka dynamic cubemap
236 a general algorithm: 7 more passes through scenegraph:
237 A search scenegraph for generatedcubemap locations
238 B foreach generatedcubemap location
239  foreach 6 faces
240  render scenegraph to fbo without generatedcubemap consumers
241  convert fbo to cubemap
242 C render scenegraph normally with generatedcubemap consumers
243 
244 Strange conciderations:
245 - if there are 2 generatedcubemap consumers side by side, in theory you should
246  have infinite re-renderings to get all the reflections back and forth between them
247  (we will ignore other generatedcubemap consumers when generating)
248 - if a generatedcubemap is DEF/USED, which location would you use
249  (we will snapshot generatedcubemap locations (node,modelviewmatrix), sort by node,
250  and eliminated node duplicates. So don't DEF/USE in scene - you'll get only one)
251 
252 
253 dynamic cubemap links:
254 http://www.mbroecker.com/project_dynamic_cubemaps.html
255 http://richardssoftware.net/Home/Post/26
256 - DX
257 http://webglsamples.org/dynamic-cubemap/dynamic-cubemap.html
258 - webgl sample
259 http://stackoverflow.com/questions/4775798/rendering-dynamic-cube-maps-in-opengl-with-frame-buffer-objects
260 http://users.csc.calpoly.edu/~ssueda/teaching/CSC471/2016S/demos/khongton/index.html
261 http://math.hws.edu/graphicsbook/source/webgl/cube-camera.html
262 https://www.opengl.org/discussion_boards/showthread.php/156906-Dynamic-cubemap-FBO
263 https://github.com/WebGLSamples/WebGLSamples.github.io/tree/master/dynamic-cubemap
264 
265 
266 */
267 
268 static int lookup_xxyyzz_face_from_count [] = {0,1,2,3,4,5}; // {1,0,2,3,5,4}; //swaps left-right front-back faces
269 
270 
271 #ifndef GL_EXT_texture_cube_map
272 # define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515
273 #endif
274 
275 
276 /****************************************************************************
277  *
278  * ComposedCubeMapTextures
279  *
280  ****************************************************************************/
281 
282 void render_ComposedCubeMapTexture (struct X3D_ComposedCubeMapTexture *node) {
283  int count, iface;
284  struct X3D_Node *thistex = 0;
285 
286  //printf ("render_ComposedCubeMapTexture\n");
287  for (count=0; count<6; count++) {
288 
289  /* set up the appearanceProperties to indicate a CubeMap */
290  getAppearanceProperties()->cubeFace = GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT+count;
291  //printf ("set cubeFace to %d in rcm\n",getAppearanceProperties()->cubeFace);
292  /* go through these, right left, top, bottom, front, back, */
293  // +x, -x, +y, -y, +z, -z //LHS system
294  // -z, +z //RHS system
295  // we appear to be swapping left/right front/back
296  iface = lookup_xxyyzz_face_from_count[count];
297  switch (iface) {
298  case 0: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->right,thistex); break;}
299  case 1: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->left,thistex); break;}
300 
301  case 2: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->top,thistex); break;}
302  case 3: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->bottom,thistex); break;}
303 
304  case 4: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->front,thistex); break;}
305  case 5: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->back,thistex); break;}
306  }
307  //printf ("rcm, thistex %p, type %s\n",thistex,stringNodeType(thistex->_nodeType));
308  if (thistex != NULL) {
309  /* we have an image specified for this face */
310  /* the X3D spec says that a X3DTextureNode has to be one of... */
311  if ((thistex->_nodeType == NODE_ImageTexture) ||
312  (thistex->_nodeType == NODE_PixelTexture) ||
313  (thistex->_nodeType == NODE_MovieTexture) ||
314  (thistex->_nodeType == NODE_MultiTexture)) {
315 
316  gglobal()->RenderFuncs.textureStackTop = 0;
317  /* render the proper texture */
318  render_node((void *)thistex);
319  }
320  }
321  }
322 
323  /* set this back for "normal" textures. */
324  getAppearanceProperties()->cubeFace = 0;
325 }
326 
327 
328 
329 /* is this a DDS file? If so, get it, and subdivide it. Ignore MIPMAPS for now */
330 /* see: http://www.mindcontrol.org/~hplus/graphics/dds-info/MyDDS.cpp */
331 /* see: http://msdn.microsoft.com/en-us/library/bb943991.aspx/ */
332 // 2016: https://msdn.microsoft.com/en-us/library/windows/desktop/bb943982(v=vs.85).aspx
333 
334 /* DDS readstuff */
335 /* DDS loader written by Jon Watte 2002 */
336 /* Permission granted to use freely, as long as Jon Watte */
337 /* is held harmless for all possible damages resulting from */
338 /* your use or failure to use this code. */
339 /* No warranty is expressed or implied. Use at your own risk, */
340 /* or not at all. */
341 
342 #if !defined( mydds_h )
343 
344 // little-endian, of course
345 #define DDS_MAGIC 0x20534444
346 
347 
348 // DDS_header.dwFlags
349  #define DDSD_CAPS 0x00000001
350 // #define DDSD_HEIGHT 0x00000002
351 // #define DDSD_WIDTH 0x00000004
352 // #define DDSD_PITCH 0x00000008
353  #define DDSD_PIXELFORMAT 0x00001000
354 // #define DDSD_MIPMAPCOUNT 0x00020000
355 // #define DDSD_LINEARSIZE 0x00080000
356  #define DDSD_DEPTH 0x00800000
357 
358 // DDS_header.sPixelFormat.dwFlags
359  #define DDPF_ALPHAPIXELS 0x00000001
360  #define DDPF_FOURCC 0x00000004
361  #define DDPF_INDEXED 0x00000020
362  #define DDPF_RGB 0x00000040
363 
364 // DDS_header.sCaps.dwCaps1
365  #define DDSCAPS_COMPLEX 0x00000008
366 // #define DDSCAPS_TEXTURE 0x00001000
367 // #define DDSCAPS_MIPMAP 0x00400000
368 
369 // DDS_header.sCaps.dwCaps2
370  #define DDSCAPS2_CUBEMAP 0x00000200
371  #define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
372  #define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
373  #define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
374  #define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
375  #define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
376  #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
377  #define DDSCAPS2_VOLUME 0x00200000
378 
379 /* old way - use 4-char string and cast later, not a good idea
380  #define D3DFMT_DXT1 "1TXD" // DXT1 compression texture format
381  #define D3DFMT_DXT2 "2TXD" // DXT2 compression texture format
382  #define D3DFMT_DXT3 "3TXD" // DXT3 compression texture format
383  #define D3DFMT_DXT4 "4TXD" // DXT4 compression texture format
384  #define D3DFMT_DXT5 "5TXD" // DXT5 compression texture format
385 */
386 /* new way - use actual four-byte unsigned integer value */
387  #define D3DFMT_DXT1 0x31545844
388 // #define D3DFMT_DXT2 0x32545844
389  #define D3DFMT_DXT3 0x33545844
390 // #define D3DFMT_DXT4 0x34545844
391  #define D3DFMT_DXT5 0x35545844
392 
393 
394 #define PF_IS_DXT1(pf) \
395  ((pf.dwFlags & DDPF_FOURCC) && \
396  (pf.dwFourCC == (unsigned int) D3DFMT_DXT1))
397 
398 #define PF_IS_DXT3(pf) \
399  ((pf.dwFlags & DDPF_FOURCC) && \
400  (pf.dwFourCC == (unsigned int) D3DFMT_DXT3))
401 
402 #define PF_IS_DXT5(pf) \
403  ((pf.dwFlags & DDPF_FOURCC) && \
404  (pf.dwFourCC == (unsigned int) D3DFMT_DXT5))
405 
406 #define PF_IS_BGRA8(pf) \
407  ((pf.dwFlags & DDPF_RGB) && \
408  (pf.dwFlags & DDPF_ALPHAPIXELS) && \
409  (pf.dwRGBBitCount == 32) && \
410  (pf.dwRBitMask == 0xff0000) && \
411  (pf.dwGBitMask == 0xff00) && \
412  (pf.dwBBitMask == 0xff) && \
413  (pf.dwAlphaBitMask == 0xff000000U))
414 
415 #define PF_IS_RGB8(pf) \
416  ((pf.dwFlags & DDPF_RGB) && \
417  !(pf.dwFlags & DDPF_ALPHAPIXELS) && \
418  (pf.dwRGBBitCount == 24) && \
419  (pf.dwRBitMask == 0xff) && \
420  (pf.dwGBitMask == 0xff00) && \
421  (pf.dwBBitMask == 0xff0000))
422 
423 #define PF_IS_BGR8(pf) \
424  ((pf.dwFlags & DDPF_RGB) && \
425  !(pf.dwFlags & DDPF_ALPHAPIXELS) && \
426  (pf.dwRGBBitCount == 24) && \
427  (pf.dwRBitMask == 0xff0000) && \
428  (pf.dwGBitMask == 0xff00) && \
429  (pf.dwBBitMask == 0xff))
430 
431 #define PF_IS_BGR5A1(pf) \
432  ((pf.dwFlags & DDPF_RGB) && \
433  (pf.dwFlags & DDPF_ALPHAPIXELS) && \
434  (pf.dwRGBBitCount == 16) && \
435  (pf.dwRBitMask == 0x00007c00) && \
436  (pf.dwGBitMask == 0x000003e0) && \
437  (pf.dwBBitMask == 0x0000001f) && \
438  (pf.dwAlphaBitMask == 0x00008000))
439 
440 #define PF_IS_BGR565(pf) \
441  ((pf.dwFlags & DDPF_RGB) && \
442  !(pf.dwFlags & DDPF_ALPHAPIXELS) && \
443  (pf.dwRGBBitCount == 16) && \
444  (pf.dwRBitMask == 0x0000f800) && \
445  (pf.dwGBitMask == 0x000007e0) && \
446  (pf.dwBBitMask == 0x0000001f))
447 
448 #define PF_IS_INDEX8(pf) \
449  ((pf.dwFlags & DDPF_INDEXED) && \
450  (pf.dwRGBBitCount == 8))
451 
452 #define PF_IS_VOLUME(pf) \
453  ((pf.dwFlags & DDSD_DEPTH))
454  //&&
455  // (pf.sCaps.dwCaps1 & DDSCAPS_COMPLEX) &&
456  // (pf.sCaps.dwCaps1 & DDSCAPS2_VOLUME))
457 
458 
459 
460 union DDS_header {
461  struct {
462  unsigned int dwMagic;
463  unsigned int dwSize;
464  unsigned int dwFlags;
465  unsigned int dwHeight;
466  unsigned int dwWidth;
467  unsigned int dwPitchOrLinearSize;
468  unsigned int dwDepth;
469  unsigned int dwMipMapCount;
470  unsigned int dwReserved1[ 11 ];
471 
472  // DDPIXELFORMAT
473  struct {
474  unsigned int dwSize;
475  unsigned int dwFlags;
476  unsigned int dwFourCC;
477  unsigned int dwRGBBitCount;
478  unsigned int dwRBitMask;
479  unsigned int dwGBitMask;
480  unsigned int dwBBitMask;
481  unsigned int dwAlphaBitMask;
482  } sPixelFormat;
483 
484  // DDCAPS2
485  struct {
486  unsigned int dwCaps1;
487  unsigned int dwCaps2;
488  unsigned int dwDDSX;
489  unsigned int dwReserved;
490  } sCaps;
491  unsigned int dwReserved2;
492  }; //JASdefStruct; // put "name" in here to get rid of compiler warning
493 char data[ 128 ];
494 };
495 
496 #endif // mydds_h
497 
498 
499 struct DdsLoadInfo {
500  bool compressed;
501  bool swap;
502  bool palette;
503  unsigned int divSize;
504  unsigned int blockBytes;
505  GLenum internalFormat;
506  GLenum externalFormat;
507  GLenum type;
508 };
509 
510 struct DdsLoadInfo loadInfoDXT1 = {
511  true, false, false, 4, 8, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
512 };
513 struct DdsLoadInfo loadInfoDXT3 = {
514  true, false, false, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
515 };
516 struct DdsLoadInfo loadInfoDXT5 = {
517  true, false, false, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
518 };
519 
520 #if defined (GL_BGRA)
521 
522  struct DdsLoadInfo loadInfoBGRA8 = {
523  false, false, false, 1, 4, GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE
524  };
525  struct DdsLoadInfo loadInfoBGR5A1 = {
526  false, true, false, 1, 2, GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV
527  };
528  struct DdsLoadInfo loadInfoIndex8 = {
529  false, false, true, 1, 1, GL_RGB8, GL_BGRA, GL_UNSIGNED_BYTE
530  };
531 #endif //BGRA textures supported
532 
533 struct DdsLoadInfo loadInfoRGB8 = {
534  false, false, false, 1, 3, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE
535 };
536 struct DdsLoadInfo loadInfoBGR8 = {
537  false, false, false, 1, 3, GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE
538 };
539 struct DdsLoadInfo loadInfoBGR565 = {
540  false, true, false, 1, 2, GL_RGB5, GL_RGB, GL_UNSIGNED_SHORT_5_6_5
541 };
542 
543 #ifdef OLDCODE
544 OLDCODE static unsigned int GetLowestBitPos(unsigned int value)
545 OLDCODE {
546 OLDCODE unsigned int pos = 0;
547 OLDCODE assert(value != 0); // handled separately
548 OLDCODE
549 OLDCODE while (!(value & 1))
550 OLDCODE {
551 OLDCODE value >>= 1;
552 OLDCODE ++pos;
553 OLDCODE if(pos == 32) break;
554 OLDCODE }
555 OLDCODE return pos;
556 OLDCODE }
557 #endif //OLDCODE
558 
559 // LoadTextures.c likes to call this one
560 int textureIsDDS(textureTableIndexStruct_s* this_tex, char *filename) {
561  FILE *file;
562  unsigned char *buffer, *bdata; //, *bdata2;
563  char sniffbuf[20];
564  unsigned long fileLen;
565  union DDS_header hdr;
566  unsigned int x = 0;
567  unsigned int y = 0;
568  unsigned int z = 0;
569  //unsigned int rshift[4]; //to go with color bitmask
570  int nchan, idoFrontBackSwap;
571  //unsigned int mipMapCount = 0;
572  unsigned int xSize, ySize,zSize;
573 
574  struct DdsLoadInfo * li;
575  size_t xx;
576 
577  UNUSED(xx); // compiler warning mitigation
578  xSize=ySize=zSize=0;
579  li = NULL;
580 
581  //printf ("textureIsDDS... node %s, file %s\n",
582  // stringNodeType(this_tex->scenegraphNode->_nodeType), filename);
583 
584  /* read in file */
585  file = fopen(filename,"rb");
586  if (!file)
587  return FALSE;
588 
589  //sniff header
590  xx=fread(sniffbuf, 4, 1, file);
591  fclose(file);
592  if(strncmp(sniffbuf,"DDS ",4)){
593  //not DDS file
594  //sniffbuf[5] = '\0';
595  //printf("sniff header = %s\n",sniffbuf);
596  return FALSE;
597  }
598  file = fopen(filename,"rb");
599  /* have file, read in data */
600 
601 
602  /* get file length */
603  fseek(file, 0, SEEK_END);
604  fileLen=ftell(file);
605  fseek(file, 0, SEEK_SET);
606 
607  /* llocate memory */
608  buffer=MALLOC(unsigned char *, fileLen+1);
609  if (!buffer) {
610  fclose(file);
611  return FALSE;
612  }
613 
614  /* read file */
615  xx=fread(buffer, fileLen, 1, file);
616  fclose(file);
617 
618  /* check to see if this could be a valid DDS file */
619  if (fileLen < sizeof(hdr))
620  return FALSE;
621 
622  /* look at the header, see what kind of a DDS file it might be */
623  memcpy( &hdr, buffer, sizeof(hdr));
624 
625  /* does this start off with "DDS " an so on ?? */
626  if ((hdr.dwMagic == DDS_MAGIC) && (hdr.dwSize == 124) &&
627  (hdr.dwFlags & DDSD_PIXELFORMAT) && (hdr.dwFlags & DDSD_CAPS)) {
628  //printf ("matched :DDS :\n");
629 
630 
631  //printf ("dwFlags %x, DDSD_PIXELFORMAT %x, DDSD_CAPS %x\n",hdr.dwFlags, DDSD_PIXELFORMAT, DDSD_CAPS);
632  xSize = hdr.dwWidth;
633  ySize = hdr.dwHeight;
634  //printf ("size %d, %d\n",xSize, ySize);
635 
636 
637  /*
638  assert( !(xSize & (xSize-1)) );
639  assert( !(ySize & (ySize-1)) );
640  */
641 
642  if(0){
643  printf ("looking to see what it is...\n");
644  printf ("DDPF_FOURCC dwFlags %x mask %x, final %x\n",hdr.sPixelFormat.dwFlags,DDPF_FOURCC,hdr.sPixelFormat.dwFlags & DDPF_FOURCC);
645 
646  printf ("if it is a dwFourCC, %x and %x\n", hdr.sPixelFormat.dwFourCC ,D3DFMT_DXT1);
647 
648  printf ("dwFlags %x\n",hdr.sPixelFormat.dwFlags);
649  printf ("dwRGBBitCount %d\n",hdr.sPixelFormat.dwRGBBitCount); //24 for normal RGB
650  printf ("dwRBitMask %x\n",hdr.sPixelFormat.dwRBitMask);
651  printf ("dwGBitMask %x\n",hdr.sPixelFormat.dwGBitMask);
652  printf ("dwBBitMask %x\n",hdr.sPixelFormat.dwBBitMask);
653  printf ("dwAlphaBitMask %x\n",hdr.sPixelFormat.dwAlphaBitMask);
654  printf ("dwFlags and DDPF_ALPHAPIXELS... %x\n",DDPF_ALPHAPIXELS & hdr.sPixelFormat.dwFlags);
655  printf ("dwflags & DDPF_RGB %x\n,",hdr.sPixelFormat.dwFlags & DDPF_RGB);
656 
657  printf ("dwFlags and DEPTH %x\n",hdr.dwFlags & DDSD_DEPTH);
658  printf ("dwCaps1 and complex %x\n", (hdr.sCaps.dwCaps1 & DDSCAPS_COMPLEX));
659  printf ("dwCaps1 and VOLUME %x\n", (hdr.sCaps.dwCaps1 & DDSCAPS2_VOLUME));
660  }
661  //rshift[0] = GetLowestBitPos(hdr.sPixelFormat.dwRBitMask);
662  //rshift[1] = GetLowestBitPos(hdr.sPixelFormat.dwGBitMask);
663  //rshift[2] = GetLowestBitPos(hdr.sPixelFormat.dwBBitMask);
664  //rshift[3] = GetLowestBitPos(hdr.sPixelFormat.dwAlphaBitMask);
665  bdata = NULL;
666  if(hdr.sPixelFormat.dwFlags & DDPF_FOURCC){
667  if( PF_IS_DXT1( hdr.sPixelFormat ) ) {
668  li = &loadInfoDXT1;
669  }
670  else if( PF_IS_DXT3( hdr.sPixelFormat ) ) {
671  li = &loadInfoDXT3;
672  }
673  else if( PF_IS_DXT5( hdr.sPixelFormat ) ) {
674  li = &loadInfoDXT5;
675  }
676 
677  #if defined (GL_BGRA)
678  else if( PF_IS_BGRA8( hdr.sPixelFormat ) ) {
679  li = &loadInfoBGRA8;
680  }
681  else if( PF_IS_BGR5A1( hdr.sPixelFormat ) ) {
682  li = &loadInfoBGR5A1;
683  }
684  else if( PF_IS_INDEX8( hdr.sPixelFormat ) ) {
685  li = &loadInfoIndex8;
686  }
687  #endif
688 
689  else if( PF_IS_RGB8( hdr.sPixelFormat ) ) {
690  li = &loadInfoRGB8;
691  }
692  else if( PF_IS_BGR8( hdr.sPixelFormat ) ) {
693  li = &loadInfoBGR8;
694  }
695  else if( PF_IS_BGR565( hdr.sPixelFormat ) ) {
696  li = &loadInfoBGR565;
697  }
698  //else {
699  // ConsoleMessage("CubeMap li failure\n");
700  // return FALSE;
701  //}
702  }else{
703  //no FOURCC
704  bdata = &buffer[sizeof(union DDS_header)];
705  //bdata = &hdr.data[0];
706  }
707  //fixme: do cube maps later
708  //fixme: do 3d later
709  x = xSize = hdr.dwWidth;
710  y = ySize = hdr.dwHeight;
711  z = zSize = 1;
712  idoFrontBackSwap = 0;
713  if( PF_IS_VOLUME(hdr) )
714  z = zSize = hdr.dwDepth;
715  if( hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP){
716  int facecount = 0;
717  if(hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP_POSITIVEX) facecount++;
718  if(hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) facecount++;
719  if(hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP_POSITIVEY) facecount++;
720  if(hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) facecount++;
721  if(hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) facecount++;
722  if(hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) facecount++;
723  z = zSize = facecount;
724  if(z==6)
725  idoFrontBackSwap = 1;
726  }
727  nchan = 3;
728  if(DDPF_ALPHAPIXELS & hdr.sPixelFormat.dwFlags) nchan = 4;
729  //if(li == NULL)
730  // return FALSE;
731  //if(!hdr.dwFlags & DDSD_MIPMAPCOUNT){
732  if(bdata){
733  //simple, convert to rgba and set tti
734  int ipix,jpix,bpp, ir, ig, ib;
735  unsigned int i,j,k;
736  unsigned char * rgbablob = malloc(x*y*z *4);
737  bpp = hdr.sPixelFormat.dwRGBBitCount / 8;
738  ir = 0; ig = 1; ib = 2; //if incoming is BGR order
739  if(hdr.sPixelFormat.dwRBitMask > hdr.sPixelFormat.dwBBitMask){
740  //if incoming is RGB order
741  ir = 2;
742  ib = 0;
743  //printf("BGR\n");
744  }
745  //printf("bitmasks R %d G %d B %d\n",hdr.sPixelFormat.dwRBitMask,hdr.sPixelFormat.dwGBitMask,hdr.sPixelFormat.dwBBitMask);
746  //printf("bpp=%d x %d y %d z %d\n",bpp, x,y,z);
747  for(i=0;i<z;i++){
748  for(j=0;j<y;j++){
749  for(k=0;k<x;k++){
750  unsigned char *pixel,*rgba;
751  int ii;
752  ii = idoFrontBackSwap && i == 4? 5 : i; //swap Front and Back faces for opengl order
753  ii = idoFrontBackSwap && i == 5? 4 : i;
754  ii = i;
755  ipix = (i*y +j)*x +k; //top down, for input image
756  jpix = (ii*y +(y-1-j))*x + k; //bottom up, for ouput texture
757  pixel = &bdata[ipix * bpp];
758  rgba = &rgbablob[jpix *4];
759  //freewrl target format: RGBA
760  //swizzle if incoming is BGRA
761  rgba[3] = 255;
762  rgba[0] = pixel[ir];
763  rgba[1] = pixel[ig];
764  rgba[2] = pixel[ib];
765  if(nchan == 4)
766  rgba[3] = pixel[3];
767  if(0){
768  static int once = 0;
769  if(!once){
770  printf("pixel R=%x G=%x B=%x A=%x\n",rgba[0],rgba[1],rgba[2],rgba[3]);
771  //once = 1;
772  }
773  }
774 
775  }
776  }
777  }
778  this_tex->channels = nchan;
779  this_tex->x = x;
780  this_tex->y = y;
781  this_tex->z = z;
782  this_tex->texdata = rgbablob;
783  return TRUE;
784  }else{
785  return FALSE;
786  }
787 
788  //mipMapCount = (hdr.dwFlags & DDSD_MIPMAPCOUNT) ? hdr.dwMipMapCount : 1;
789  //printf ("mipMapCount %d\n",mipMapCount);
790 
791  if( li->compressed ) {
792  //printf ("compressed\n");
793  /*
794  size_t size = max( li->divSize, x )/li->divSize * max( li->divSize, y )/li->divSize * li->blockBytes;
795  assert( size == hdr.dwPitchOrLinearSize );
796  assert( hdr.dwFlags & DDSD_LINEARSIZE );
797  unsigned char * data = (unsigned char *)malloc( size );
798  if( !data ) {
799  goto failure;
800  }
801  format = cFormat = li->internalFormat;
802  for( unsigned int ix = 0; ix < mipMapCount; ++ix ) {
803  fread( data, 1, size, f );
804  glCompressedTexImage2D( GL_TEXTURE_2D, ix, li->internalFormat, x, y, 0, size, data );
805  gl->updateError();
806  x = (x+1)>>1;
807  y = (y+1)>>1;
808  size = max( li->divSize, x )/li->divSize * max( li->divSize, y )/li->divSize * li->blockBytes;
809  }
810  free( data );
811  */
812  } else if( li->palette ) {
813  //printf ("palette\n");
814  /*
815  // currently, we unpack palette into BGRA
816  // I'm not sure we always get pitch...
817  assert( hdr.dwFlags & DDSD_PITCH );
818  assert( hdr.sPixelFormat.dwRGBBitCount == 8 );
819  size_t size = hdr.dwPitchOrLinearSize * ySize;
820  // And I'm even less sure we don't get padding on the smaller MIP levels...
821  assert( size == x * y * li->blockBytes );
822  format = li->externalFormat;
823  cFormat = li->internalFormat;
824  unsigned char * data = (unsigned char *)malloc( size );
825  unsigned int palette[ 256 ];
826  unsigned int * unpacked = (unsigned int *)malloc( size*sizeof( unsigned int ) );
827  fread( palette, 4, 256, f );
828  for( unsigned int ix = 0; ix < mipMapCount; ++ix ) {
829  fread( data, 1, size, f );
830  for( unsigned int zz = 0; zz < size; ++zz ) {
831  unpacked[ zz ] = palette[ data[ zz ] ];
832  }
833  glPixelStorei( GL_UNPACK_ROW_LENGTH, y );
834  glTexImage2D( GL_TEXTURE_2D, ix, li->internalFormat, x, y, 0, li->externalFormat, li->type, unpacked );
835  gl->updateError();
836  x = (x+1)>>1;
837  y = (y+1)>>1;
838  size = x * y * li->blockBytes;
839  }
840  free( data );
841  free( unpacked );
842  */
843  } else {
844  //int size;
845 
846  if( li->swap ) {
847  //printf ("swap\n");
848 
849  /*
850  glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_TRUE );
851  */
852  }
853  //size = x * y * li->blockBytes;
854 
855  //printf ("size is %d\n",size);
856  /*
857  format = li->externalFormat;
858  cFormat = li->internalFormat;
859  unsigned char * data = (unsigned char *)malloc( size );
860  //fixme: how are MIP maps stored for 24-bit if pitch != ySize*3 ?
861  for( unsigned int ix = 0; ix < mipMapCount; ++ix ) {
862  fread( data, 1, size, f );
863  glPixelStorei( GL_UNPACK_ROW_LENGTH, y );
864  glTexImage2D( GL_TEXTURE_2D, ix, li->internalFormat, x, y, 0, li->externalFormat, li->type, data );
865  gl->updateError();
866  x = (x+1)>>1;
867  y = (y+1)>>1;
868  size = x * y * li->blockBytes;
869  }
870  free( data );
871  glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE );
872  gl->updateError();
873  */
874  }
875  /*
876  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipMapCount-1 );
877  gl->updateError();
878 
879  return true;
880 
881  failure:
882  return false;
883  }
884  */
885 
886  }
887  // else {
888  // //printf ("put in the dummy file here, and call it quits\n");
889  //}
890  FREE_IF_NZ(buffer);
891  return FALSE;
892 }
893 
894 
895 
896 /****************************************************************************
897  *
898  * ImageCubeMapTextures
899  * notes - we make 6 PixelTextures, and actually put the data for each face
900  * into these pixelTextures.
901  *
902  * yes, maybe there is a better way; this way mimics the ComposedCubeMap
903  * method, and makes rendering both ImageCubeMap and ComposedCubeMapTextures
904  * the same, in terms of scene-graph traversal.
905  *
906  * look carefully at the call to unpackImageCubeMap...
907  *
908  ****************************************************************************/
909  void add_node_to_broto_context(struct X3D_Proto *currentContext,struct X3D_Node *node);
910 
911 void compile_ImageCubeMapTexture (struct X3D_ImageCubeMapTexture *node) {
912  if (node->__subTextures.n == 0) {
913  int i;
914 
915  /* printf ("changed_ImageCubeMapTexture - creating sub-textures\n"); */
916  FREE_IF_NZ(node->__subTextures.p); /* should be NULL, checking */
917  node->__subTextures.p = MALLOC(struct X3D_Node **, 6 * sizeof (struct X3D_PixelTexture *));
918  for (i=0; i<6; i++) {
919  struct X3D_PixelTexture *pt;
920  //struct textureTableIndexStruct *tti;
921  pt = (struct X3D_PixelTexture *)createNewX3DNode(NODE_PixelTexture);
922  node->__subTextures.p[i] = X3D_NODE(pt);
923  if(node->_executionContext)
924  add_node_to_broto_context(X3D_PROTO(node->_executionContext),X3D_NODE(node->__subTextures.p[i]));
925  //tti = getTableIndex(pt->__textureTableIndex);
926  //tti->status = TEX_NEEDSBINDING; //I found I didn't need - yet
927  }
928  node->__subTextures.n=6;
929  }
930 
931  /* tell the whole system to re-create the data for these sub-children */
932  node->__regenSubTextures = TRUE;
933  MARK_NODE_COMPILED
934 }
935 
936 
937 void render_ImageCubeMapTexture (struct X3D_ImageCubeMapTexture *node) {
938  int count, iface;
939 
940  COMPILE_IF_REQUIRED
941 
942  /* do we have to split this CubeMap raw data apart? */
943  if (node->__regenSubTextures) {
944  /* Yes! Get the image data from the file, and split it apart */
945  loadTextureNode(X3D_NODE(node),NULL);
946  } else {
947  /* we have the 6 faces from the image, just go through and render them as a cube */
948  if (node->__subTextures.n == 0) return; /* not generated yet - see changed_ImageCubeMapTexture */
949 
950  for (count=0; count<6; count++) {
951 
952  /* set up the appearanceProperties to indicate a CubeMap */
953  getAppearanceProperties()->cubeFace = GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT+count;
954 
955  /* go through these, back, front, top, bottom, right left */
956  iface = lookup_xxyyzz_face_from_count[count];
957  render_node(node->__subTextures.p[iface]);
958  }
959  }
960  /* Finished rendering CubeMap, set it back for normal textures */
961  getAppearanceProperties()->cubeFace = 0;
962 
963 }
964 
965 
966 /* textures - we have got a png (jpeg, etc) file with a cubemap in it; eg, see:
967  http://en.wikipedia.org/wiki/Cube_mapping
968 */
969 /* images are stored in an image as 3 "rows", 4 "columns", we pick the data out of these columns */
970 static int offsets[]={
971  /*y,x, with y-up */
972  1,2, /* right */
973  1,0, /* left */
974  2,1, /* top */
975  0,1, /* bottom */
976  1,1, /* front */
977  1,3}; /* back */
978 //if assuming the offsets order represents +x,-x,+y,-y,+z,-z then this is LHS (left handed system)
979 /* or:
980  ---- Top -- --
981  Left Front Right Back
982  ---- Down -- --
983 */
984 
985 /* fill in the 6 PixelTextures from the data in the texture
986  this is for when you have a single .png image with 6 sub-patches
987 */
988 
989 
990 // Textures.c loves to call this one.
991 void unpackImageCubeMap (textureTableIndexStruct_s* me) {
992  int size;
993  int count;
994 
995  struct X3D_ImageCubeMapTexture *node = (struct X3D_ImageCubeMapTexture *)me->scenegraphNode;
996 
997  if (node == NULL) {
998  ERROR_MSG("problem unpacking single image ImageCubeMap\n");
999  return;
1000  }
1001 
1002  if (node->_nodeType != NODE_ImageCubeMapTexture) {
1003  ERROR_MSG("internal error - expected ImageCubeMapTexture here");
1004  return;
1005  }
1006 
1007  /* expect the cube map to be in a 4:3 ratio */
1008  /* printf ("size %dx%d, data %p\n",me->x, me->y, me->texdata); */
1009  if ((me->x * 3) != (me->y*4)) {
1010  ERROR_MSG ("expect an ImageCubeMap to be in a 4:3 ratio");
1011  return;
1012  }
1013 
1014  /* ok, we have, probably, a cube map in the image data. Extract the data and go nuts */
1015  size = me->x / 4;
1016 
1017 
1018  if (node->__subTextures.n != 6) {
1019  ERROR_MSG("unpackImageCubeMap, there should be 6 PixelTexture nodes here\n");
1020  return;
1021  }
1022  /* go through each face, and send the data to the relevant PixelTexture */
1023  /* order: right left, top, bottom, back, front */
1024  for (count=0; count <6; count++) {
1025  int x,y;
1026  uint32 val;
1027  uint32 *tex = (uint32 *) me->texdata;
1028  struct X3D_PixelTexture *pt = X3D_PIXELTEXTURE(node->__subTextures.p[count]);
1029  int xSubIndex, ySubIndex;
1030  int index;
1031 
1032  ySubIndex=offsets[count*2]*size; xSubIndex=offsets[count*2+1]*size;
1033 
1034  /* create the MFInt32 array for this face in the PixelTexture */
1035  FREE_IF_NZ(pt->image.p);
1036  pt->image.n = size*size+3;
1037  pt->image.p = MALLOC(int *, pt->image.n * sizeof (int));
1038  pt->image.p[0] = size;
1039  pt->image.p[1] = size;
1040  pt->image.p[2] = 4; /* this last one is for RGBA nchannels/components = 4 */
1041  index = 3;
1042 
1043  for (y=ySubIndex; y<ySubIndex+size; y++) {
1044  for (x=xSubIndex; x<xSubIndex+size; x++) {
1045  int ipix;
1046  unsigned char *rgba;
1047  ipix = y*me->x + x; //pixel in big image
1048  if(0){
1049  /* remember, this will be in ARGB format, make into RGBA */
1050  val = tex[ipix];
1051  pt->image.p[index] = ((val & 0xffffff) << 8) | ((val & 0xff000000) >> 24);
1052  }else{
1053  rgba = (unsigned char *)&tex[ipix];
1054  //convert to host-endian red-high int
1055  pt->image.p[index] = (rgba[0] << 24) + (rgba[1] << 16) + (rgba[2] << 8) + (rgba[3] << 0);
1056  }
1057  /* printf ("was %x, now %x\n",tex[x*me->x+y], pt->image.p[index]); */
1058  index ++;
1059  }
1060 
1061  }
1062  }
1063 
1064  /* we are now locked-n-loaded */
1065  node->__regenSubTextures = FALSE;
1066 
1067  /* get rid of the original texture data now */
1068  FREE_IF_NZ(me->texdata);
1069 }
1070 
1071 // Textures.c references this baby.
1072 void unpackImageCubeMap6 (textureTableIndexStruct_s* me) {
1073  //for .DDS and .web3dit that are in cubemap format ie 6 contiguous images in tti->teximage
1074  // incoming order of images: +x,-x,+y,-y,+z,-z (or R,L,F,B,T,D ?) */
1075  //int size;
1076  int count;
1077 
1078  struct X3D_ImageCubeMapTexture *node = (struct X3D_ImageCubeMapTexture *)me->scenegraphNode;
1079 
1080  if (node == NULL) {
1081  ERROR_MSG("problem unpacking single image ImageCubeMap\n");
1082  return;
1083  }
1084 
1085  if (node->_nodeType != NODE_ImageCubeMapTexture) {
1086  ERROR_MSG("internal error - expected ImageCubeMapTexture here");
1087  return;
1088  }
1089 
1090 
1091  if (node->__subTextures.n != 6) {
1092  ERROR_MSG("unpackImageCubeMap, there should be 6 PixelTexture nodes here\n");
1093  return;
1094  }
1095  /* go through each face, and send the data to the relevant PixelTexture */
1096  /* (jas declared target) order: right left, top, bottom, back, front */
1097  // (dug9 incoming order from dds/.web3dit cubemap texture, RHS: +x,-x,+y,-y,+z,-z
1098  // this should be same as opengl/web3d order
1099  {
1100  uint32 imlookup[] = {0,1,2,3,4,5}; //dug9 lookup order that experimentally seems to work
1101  for (count=0; count <6; count++) {
1102  int i,j; //,k; //x,y,
1103  uint32 ioff; //val,
1104  uint32 *tex;
1105  struct X3D_PixelTexture *pt = X3D_PIXELTEXTURE(node->__subTextures.p[count]);
1106 
1107  /* create the MFInt32 array for this face in the PixelTexture */
1108  FREE_IF_NZ(pt->image.p);
1109  pt->image.n = me->x*me->y+3;
1110  pt->image.p = MALLOC(int *, pt->image.n * sizeof (uint32));
1111  pt->image.p[0] = me->x;
1112  pt->image.p[1] = me->y;
1113  pt->image.p[2] = 4; /* this last one is for RGBA */
1114  ioff = imlookup[count] * me->x * me->y;
1115  //we are in char rgba order, but we need to convert to endian-specific uint32
1116  // which is what texture_load_from_pixelTexture() will be expecting
1117  //in imageIsDDS() image reader, we already flipped from top-down image to bottom-up texture order
1118  // which pixeltexture is expecting
1119  tex = (uint32 *) me->texdata;
1120  tex = &tex[ioff];
1121  for(j=0;j<me->y;j++){
1122  for(i=0;i<me->x;i++){
1123  int ipix; //,jpix;
1124  uint32 pixint;
1125  unsigned char* rgba;
1126 
1127  ipix = j*me->x + i; //image row same as image row out
1128  //jpix = (me->y-1 -j)*me->x + i; //flip image vertically - no, pixeltexture is bottom-up like incoming
1129  rgba = (unsigned char*)&tex[ipix];
1130  pixint = (rgba[0] << 24) + (rgba[1] << 16) + (rgba[2] << 8) + rgba[3];
1131  pt->image.p[ipix+3] = pixint;
1132  }
1133  }
1134  }
1135  }
1136 
1137  /* we are now locked-n-loaded */
1138  node->__regenSubTextures = FALSE;
1139 
1140  /* get rid of the original texture data now */
1141  FREE_IF_NZ(me->texdata);
1142 }
1143 
1144 
1145 
1146 /****************************************************************************
1147  *
1148  * GeneratedCubeMapTextures
1149  *
1150  ****************************************************************************/
1151  #include "RenderFuncs.h"
1153  Stack * gencube_stack;
1155 
1156 static void *Component_CubeMapTexturing_constructor(){
1157  void *v = MALLOCV(sizeof(struct pComponent_CubeMapTexturing));
1158  memset(v,0,sizeof(struct pComponent_CubeMapTexturing));
1159  return v;
1160 }
1161 
1162 // iglobal.c loves to call this one.
1163 void Component_CubeMapTexturing_init(struct tComponent_CubeMapTexturing *t){
1164  //public
1165  //private
1166  t->prv = Component_CubeMapTexturing_constructor();
1167  {
1169  p->gencube_stack = newStack(usehit);
1170  }
1171 }
1172 
1173 // iglobal.c loves to call this one.
1174 void Component_CubeMapTexturing_clear(struct tComponent_CubeMapTexturing *t){
1175  //public
1176  //private
1177  {
1179  deleteVector(usehit,p->gencube_stack);
1180  }
1181 }
1182 
1183 //ppComponent_CubeMapTexturing p = (ppComponent_CubeMapTexturing)gglobal()->Component_CubeMapTexturing.prv;
1184 
1185  // uni_string update ["NONE"|"NEXT_FRAME_ONLY"|"ALWAYS"]
1186  // int size
1187 
1188 void pushnset_framebuffer(int ibuffer);
1189 void popnset_framebuffer();
1190 
1191 #ifdef GL_DEPTH_COMPONENT32
1192 #define FW_GL_DEPTH_COMPONENT GL_DEPTH_COMPONENT32
1193 #else
1194 #define FW_GL_DEPTH_COMPONENT GL_DEPTH_COMPONENT16
1195 #endif
1196 int haveFrameBufferObject();
1197 
1198 // called from the scene traversal, linked in GeneratedCode.c
1199 void compile_GeneratedCubeMapTexture (struct X3D_GeneratedCubeMapTexture *node) {
1200  if (node->__subTextures.n == 0) {
1201  int i;
1202  struct textureTableIndexStruct *tti;
1203 
1204  /* printf ("changed_ImageCubeMapTexture - creating sub-textures\n"); */
1205  FREE_IF_NZ(node->__subTextures.p); /* should be NULL, checking */
1206  node->__subTextures.p = MALLOC(struct X3D_Node **, 6 * sizeof (struct X3D_PixelTexture *));
1207  for (i=0; i<6; i++) {
1208  struct X3D_PixelTexture *pt;
1209  pt = (struct X3D_PixelTexture *)createNewX3DNode(NODE_PixelTexture);
1210  node->__subTextures.p[i] = X3D_NODE(pt);
1211  if(node->_executionContext)
1212  add_node_to_broto_context(X3D_PROTO(node->_executionContext),X3D_NODE(node->__subTextures.p[i]));
1213  //tti = getTableIndex(pt->__textureTableIndex);
1214  //tti->status = TEX_NEEDSBINDING; //I found I didn't need - yet
1215  //tti->z = 6;
1216 
1217  }
1218  node->__subTextures.n=6;
1219  tti = getTableIndex(node->__textureTableIndex);
1220  tti->status = TEX_NEEDSBINDING; //I found I didn't need - yet
1221  tti->x = tti->y = node->size;
1222  //tti->z = 6;
1223  loadTextureNode(X3D_NODE(node),NULL);
1224  if(tti->ifbobuffer == 0 && haveFrameBufferObject() ){
1225  int j, isize;
1226  isize = node->size; //node->size is initializeOnly, we will ignore any change during run
1227  tti->x = isize; //by storing and retrieving initial size from here
1228  // https://www.opengl.org/wiki/Framebuffer_Object
1229  glGenFramebuffers(1, &tti->ifbobuffer);
1230  pushnset_framebuffer(tti->ifbobuffer); //binds framebuffer. we push here, in case higher up we are already rendering the whole scene to an fbo
1231 
1232  glGenRenderbuffers(1, &tti->idepthbuffer);
1233  glBindRenderbuffer(GL_RENDERBUFFER, tti->idepthbuffer);
1234  glRenderbufferStorage(GL_RENDERBUFFER, FW_GL_DEPTH_COMPONENT, isize,isize);
1235  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, tti->idepthbuffer);
1236 
1237  for(j=0;j<node->__subTextures.n;j++){ //should be 6
1238  //textureTableIndexStruct_s* ttip;
1239  //struct X3D_PixelTexture * nodep;
1240  //nodep = (struct X3D_PixelTexture *)node->__subTextures.p[j];
1241  //ttip = getTableIndex(nodep->__textureTableIndex);
1242  //glGenTextures(1,&ttip->OpenGLTexture);
1243  //glBindTexture(GL_TEXTURE_2D, ttip->OpenGLTexture);
1244 
1245  //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, isize, isize, 0, GL_RGBA , GL_UNSIGNED_BYTE, 0);
1246  //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+j, GL_TEXTURE_2D, ttip->OpenGLTexture, 0);
1247  }
1248  glGenTextures(1,&tti->OpenGLTexture);
1249  glBindTexture(GL_TEXTURE_2D, tti->OpenGLTexture);
1250 
1251  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, isize, isize, 0, GL_RGBA , GL_UNSIGNED_BYTE, 0);
1252  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tti->OpenGLTexture, 0);
1253 
1254  popnset_framebuffer(); //tti->ifbobuffer);
1255  }
1256 
1257  }
1258 
1259  /* tell the whole system to re-create the data for these sub-children */
1260  //node->__regenSubTextures = TRUE;
1261 
1262  MARK_NODE_COMPILED
1263  //we leave it up to shape nodes to detect if they have generatedcubemaptexture
1264  // and if so not draw themselves on VF_Cube pass
1265 }
1266 
1267 //double *get_view_matrixd();
1268 void get_view_matrix(double *savePosOri, double *saveView);
1269 void freeASCIIString(struct Uni_String *us);
1270 
1271 // called from the scene traversal, linked in GeneratedCode.c
1272 void render_GeneratedCubeMapTexture (struct X3D_GeneratedCubeMapTexture *node) {
1273  int count, iface;
1274 
1275  COMPILE_IF_REQUIRED
1276 
1277  if(!strcmp(node->update->strptr,"ALWAYS") || !strcmp(node->update->strptr,"NEXT_FRAME_ONLY")){
1278  ttrenderstate rs;
1279  rs = renderstate();
1280  if(rs->render_geom && !rs->render_cube){
1281  //add (node,modelviewmatrix) for next frame
1282  //programmer: please clear the gencube stack once per frame
1283  int i, isAdded;
1284  usehit uhit;
1285  ppComponent_CubeMapTexturing p = (ppComponent_CubeMapTexturing)gglobal()->Component_CubeMapTexturing.prv;
1286  //check if already added, only add once for simplification
1287  isAdded = FALSE;
1288  for(i=0;i<vectorSize(p->gencube_stack);i++){
1289  uhit = vector_get(usehit,p->gencube_stack,i);
1290  if(uhit.node == X3D_NODE(node)){
1291  isAdded = TRUE;
1292  break;
1293  }
1294  }
1295  if(!isAdded){
1296  double modelviewMatrix[16], mvmInverse[16];
1297  double worldmatrix[16], viewmatrix[16], saveView[16], savePosOri[16]; //bothinverse[16],
1298  usehit uhit;
1299  //GL_GET_MODELVIEWMATRIX
1300  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewMatrix);
1301  get_view_matrix(savePosOri,saveView);
1302  matmultiplyAFFINE(viewmatrix,saveView,savePosOri);
1303  //matinverseAFFINE(bothinverse,viewmatrix);
1304  matinverseAFFINE(mvmInverse,modelviewMatrix);
1305 
1306  //matmultiplyAFFINE(worldmatrix,bothinverse,modelviewMatrix);
1307  //matmultiplyAFFINE(worldmatrix,modelviewMatrix,bothinverse);
1308 
1309  matmultiplyAFFINE(worldmatrix,viewmatrix,mvmInverse);
1310 
1311  //strip viewmatrix - will happen when we invert one of the USEUSE pair, and multiply
1312  uhit.node = X3D_NODE(node);
1313  //memcpy(uhit.mvm,modelviewMatrix,16*sizeof(double)); //deep copy
1314  memcpy(uhit.mvm,worldmatrix,16*sizeof(double)); //deep copy
1315  vector_pushBack(usehit,p->gencube_stack,uhit); //fat elements do another deep copy
1316  if(!strcmp(node->update->strptr,"NEXT_FRAME_ONLY")){
1317  //set back to NONE
1318  freeASCIIString(node->update);
1319  node->update = newASCIIString("NONE");
1320  //not sure why, but I don't seem to need to mark event
1321  //MARK_EVENT (X3D_NODE(node),offsetof (struct X3D_GeneratedCubeMapTexture, update));
1322  //printf("MARK_EVENT\n");
1323  }
1324  }
1325 
1326  }
1327  }
1328  //render what we have now
1329 
1330  /* do we have to split this CubeMap raw data apart? */
1331  //if (node->__regenSubTextures) {
1332  // loadTextureNode(X3D_NODE(node),NULL);
1333  //}
1334  //else
1335  {
1336  /* we have the 6 faces from the image, just go through and render them as a cube */
1337  if (node->__subTextures.n == 0) return; /* not generated yet - see changed_ImageCubeMapTexture */
1338 
1339  for (count=0; count<6; count++) {
1340 
1341  /* set up the appearanceProperties to indicate a CubeMap */
1342  getAppearanceProperties()->cubeFace = GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT+count;
1343 
1344  /* go through these, back, front, top, bottom, right left */
1345  iface = lookup_xxyyzz_face_from_count[count];
1346  render_node(node->__subTextures.p[iface]);
1347  }
1348  }
1349  /* Finished rendering CubeMap, set it back for normal textures */
1350  getAppearanceProperties()->cubeFace = 0;
1351 }
1352 
1353 //Stack *getGenCubeList(){
1354 // ppComponent_CubeMapTexturing p = (ppComponent_CubeMapTexturing)gglobal()->Component_CubeMapTexturing.prv;
1355 // return p->gencube_stack;
1356 //}
1357 
1358 
1359 //we'll do a different matrix rotation for each face, using sideangle struct:
1360 static struct {
1361 double angle;
1362 double x;
1363 double y;
1364 double z;
1365 } sideangle[6] = {
1366 { 90.0,0.0,1.0,0.0}, //+x
1367 {-90.0,0.0,1.0,0.0}, //-x
1368 {-90.0,1.0,0.0,0.0}, //+y weird but works
1369 { 90.0,1.0,0.0,0.0}, //-y "
1370 { 0.0,0.0,1.0,0.0}, //+z (lhs)
1371 {180.0,0.0,1.0,0.0}, //-z
1372 };
1373 
1374 void saveImage_web3dit(struct textureTableIndexStruct *tti, char *fname);
1375 void fw_gluPerspective_2(GLDOUBLE xcenter, GLDOUBLE fovy, GLDOUBLE aspect, GLDOUBLE zNear, GLDOUBLE zFar);
1376 void pushnset_viewport(float *vpFraction);
1377 void popnset_viewport();
1378 
1379 // called from MainLoop.c
1380 
1381 void generate_GeneratedCubeMapTextures(){
1382  //call from mainloop once per frame:
1383  //foreach cubemaptexture location in cubgen list
1384  // foreach 6 sides
1385  // set viewpoint pose
1386  // render scene to fbo
1387  // convert fbo to regular cubemap texture
1388  //clear cubegen list
1389  Stack *gencube_stack;
1390  ttglobal tg = gglobal();
1391  ppComponent_CubeMapTexturing p = (ppComponent_CubeMapTexturing)tg->Component_CubeMapTexturing.prv;
1392  static int iframe = 0;
1393 
1394  iframe++;
1395  gencube_stack = p->gencube_stack;
1396  if(vectorSize(gencube_stack)){
1397  int i, j, n;
1398 
1399  n = vectorSize(gencube_stack);
1400  for(i=0;i<n;i++){
1401  usehit uhit;
1402  int isize;
1403  double modelviewmatrix[16];
1405  float vp[4] = {0.0f,1.0f,0.0f,1.0f}; //arbitrary
1406  struct X3D_GeneratedCubeMapTexture * node;
1407 
1408  uhit = vector_get(usehit,gencube_stack,i);
1409  node = (struct X3D_GeneratedCubeMapTexture*)uhit.node;
1410  memcpy(modelviewmatrix,uhit.mvm,16*sizeof(double));
1411 
1412  //compile_generatedcubemap - creates framebufferobject fbo
1413  tti = getTableIndex(node->__textureTableIndex);
1414 
1415  isize = tti->x; //set in compile_
1416  pushnset_framebuffer(tti->ifbobuffer); //binds framebuffer. we push here, in case higher up we are already rendering the whole scene to an fbo
1417  //GLuint attachments [1] = {GL_COLOR_ATTACHMENT0};
1418  //glDrawBuffers(1,attachments); //'draw' is implied in GL_RENDERBUFFER above
1419  //glReadBuffer(GL_COLOR_ATTACHMENT0); //'read' is implied in GL_RENDERBUFFER
1420  pushnset_viewport(vp); //something to push so we can pop-and-set below, so any mainloop GL_BACK viewport is restored
1421  glViewport(0,0,isize,isize); //viewport we want
1422 
1423  //create fbo or fbo tiles collection for generatedcubemap
1424  //method: we draw each face to a single framebuffer texture,
1425  // and readpixels back into 6 PixelTexture tti->texdata, so its a bit like ImageCubeMap except
1426  // we skip the steps of creating and reading back PixelTexture->image.p into texdata
1427  for(j=0;j<node->__subTextures.n;j++){ //should be 6
1429  struct X3D_PixelTexture * nodep;
1430  GLuint pixelType;
1431  int bytesPerPixel;
1432 
1433  nodep = (struct X3D_PixelTexture *)node->__subTextures.p[j];
1434  ttip = getTableIndex(nodep->__textureTableIndex);
1435  //we won't directly generate cubemap textures here, but looks interesting as possible
1436  // shotcut to skip readpixels below
1437  //glBindTexture(GL_TEXTURE_2D, ttip->OpenGLTexture);
1438  //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+j, GL_TEXTURE_2D, ttip->OpenGLTexture, 0);
1439  glClearColor(1.0f,0.0f,0.0f,1.0f); //red, for diagnostics during debugging
1440  FW_GL_CLEAR(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1441 
1442  //set viewpoint matrix for side
1443  //setup_projection();
1444  FW_GL_MATRIX_MODE(GL_PROJECTION);
1445  FW_GL_LOAD_IDENTITY();
1446  //fw_gluPerspective(90.0, 1.0, .1,10000.0);
1447  fw_gluPerspective_2(0.0,90.0, 1.0, .1,10000.0);
1448 
1449  FW_GL_MATRIX_MODE(GL_MODELVIEW);
1450  FW_GL_LOAD_IDENTITY();
1451  fw_glSetDoublev(GL_MODELVIEW_MATRIX, modelviewmatrix);
1452  fw_glRotated(sideangle[j].angle,sideangle[j].x,sideangle[j].y,sideangle[j].z);
1453 
1454 
1455  clearLightTable();//turns all lights off- will turn them on for VF_globalLight and scope-wise for non-global in VF_geom
1456 
1457  /* turn light #0 off only if it is not a headlight.*/
1458  if (!fwl_get_headlight()) {
1459  setLightState(HEADLIGHT_LIGHT,FALSE);
1460  setLightType(HEADLIGHT_LIGHT,2); // DirectionalLight
1461  }
1462 
1463  /* Other lights*/
1464  PRINT_GL_ERROR_IF_ANY("XEvents::render, before render_hier");
1465 
1466  render_hier(rootNode(), VF_globalLight );
1467  PRINT_GL_ERROR_IF_ANY("XEvents::render, render_hier(VF_globalLight)");
1468  render_hier(rootNode(), VF_Other );
1469 
1470  /* 4. Nodes (not the blended ones)*/
1471  profile_start("hier_geom");
1472  render_hier(rootNode(), VF_Geom | VF_Cube);
1473  profile_end("hier_geom");
1474  PRINT_GL_ERROR_IF_ANY("XEvents::render, render_hier(VF_Geom)");
1475 
1476  /* 5. Blended Nodes*/
1477  if (tg->RenderFuncs.have_transparency) {
1478  /* render the blended nodes*/
1479  render_hier(rootNode(), VF_Geom | VF_Blend | VF_Cube);
1480  PRINT_GL_ERROR_IF_ANY("XEvents::render, render_hier(VF_Geom)");
1481  }
1482 
1483  //if you can figure out how to use regular texture in cubemap, then there may be a shortcut
1484  //for now, we'll pull the fbo pixels back into cpu space and put them in pixeltexture
1485  pixelType = GL_RGBA;
1486  bytesPerPixel = 4;
1487  if(!ttip->texdata || ttip->x != isize){
1488  FREE_IF_NZ(ttip->texdata);
1489  ttip->texdata = MALLOC (GLvoid *, bytesPerPixel*isize*isize);
1490  }
1491 
1492  /* grab the data */
1493  //FW_GL_PIXELSTOREI (GL_UNPACK_ALIGNMENT, 1);
1494  //FW_GL_PIXELSTOREI (GL_PACK_ALIGNMENT, 1);
1495 
1496  FW_GL_READPIXELS (0,0,isize,isize,pixelType,GL_UNSIGNED_BYTE, ttip->texdata);
1497  ttip->x = isize;
1498  ttip->y = isize;
1499  ttip->z = 1;
1500  ttip->hasAlpha = 1;
1501  ttip->channels = 4;
1502  ttip->status = TEX_NEEDSBINDING;
1503  if(0){
1504  //write out tti as web3dit image files for diagnostic viewing, can use for BackGround node
1505  //void saveImage_web3dit(struct textureTableIndexStruct *tti, char *fname)
1506  if(iframe == 50){
1507  char namebuf[100];
1508  sprintf(namebuf,"%s%d.web3dit","cubemapface_",j);
1509  saveImage_web3dit(ttip, namebuf);
1510  }
1511  }
1512  }
1513  popnset_viewport();
1514  popnset_framebuffer();
1515  //compile_generatedcubemaptexture // convert to opengl
1516  }
1517  //clear cubegen list
1518  gencube_stack->n = 0;
1519  }
1520 }
Definition: Vector.h:36