FreeWRL / FreeX3D 4.3.0
Component_CubeMapTexturing.c
1/*
2
3
4X3D 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
54a) 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
64b) for otherwise piecewise cubemaps its a little less obvious, needs standards:
65
66http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/env_texture.html#Textureorientation
67Web3D 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
76so to match DX ordering:
77R,L,T,D,B,F
78x no mention of which way is up on the the top and bottom images
79
80http://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
83x up/down seem rotatated:
84- Up has Right at top (+x when looking from center)
85x Down has Left at top (-x when looking from center)
86file order: F,B,U,D,L,R
87Assuming F==+x: in LHS system:
88file order: +x,-x,+y,-y,+z,-z
89- with top of Top against -z, top of bottom against +z
90
91OpenGL Redbook p.441 has no diagram, but hints at the same face ordering as dds.
92
93https://docs.unity3d.com/Manual/class-Cubemap.html
94Unity uses Y up, and (unlike web3d) LHS
95Right +x
96Left -x
97Top +Y
98Bottom -Y
99Front +z
100Back -Z
101Top of the bottom image is Left -x like simigon says about DDS cubemap
102Top of the top image is front or back likely +z front
103
104http://stackoverflow.com/questions/11685608/convention-of-faces-in-opengl-cubemapping
105- mentions of renderman
106- a LHS diagram for figuring opengl cube map
107http://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
111http://developer.amd.com/tools-and-sdks/archive/games-cgi/cubemapgen/
112CCubeMapProcessor.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.
136x 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
144SUMMARY OF BEST GUESS OF DDS CUBEMAP LAYOUT:
145a) LHS: +y is up, xy form RHS 2D axes, +z is LHS relative to xy
146b) 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)
148c) 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)
152This interpretation matches the 2nd diagram on this page:
153https://msdn.microsoft.com/en-us/library/windows/desktop/bb204881(v=vs.85).aspx
154
155
156CUBEMAP FORMAT FOR INTERNAL FREEWRL AND .WEB3DIT
157http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/env_texture.html#Textureorientation
158Similar to above for DDS summary, except:
1591. using opengl/web3d RHS: when naming the faces by signed axis:-
160 sign on z is reversed, -z is Front, +z is Back
1612. 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
164a) RHS with y-up, -z Front
165b) face order in linear array:
166 +x (Right), -x (Left), +y (Top), -y(Bottom), +z(Back, in RHS), -z(Front, in RHS)
167c) 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
172OPENGL CUBETEXTURE CONVENTION
173https://www.opengl.org/registry/doc/glspec21.20061201.pdf
174section 3.8.6, p.170, table 3.19 shows how your 3D texture coordinate
175is used in the sampler:
176Major Axis
177Direction 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
184Take the +rx - the plus x face. If you're in the center of the cube
185at the origin, looking down the +x axis, in a Y-up RHS system, shouldn't
186you see +z going to your right, and +y going up, in the 2D texture coordinate
187system? Opengl has them both negative.
188
189Its a bit bizzarre and makes more sense
190if thinking of texture rows as y-down like images, and xyz as LHS - 2 things
191that seem un-opengl-like. Someone said its using renderman convention for cubemaps.
192
193There's no way to intercept the output of this table before its used in cubeSampler.
194
195In 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,
198x hard to find a way to do that in the shader that works for all cubemap faces
199
200http://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;
211So could be rolled out for Composed, Generated, Image Cubemaps
212
213
214OpenGL 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
223SUMMARY OF CUBEMAP
224I've confirmed my proper creation of dds cubemap with Gimp DDS using ATI's CubeMapGen utility
225http://developer.amd.com/tools-and-sdks/archive/games-cgi/cubemapgen/
226- CubeMapGen uses an axis numbering scheme that matches DX/DDS conventions
227
228WORKING with DDS cubemap and -+-- tee layout single images Sept 12, 2016
229Not 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
235GENERATEDCUBEMAP aka dynamic cubemap
236a general algorithm: 7 more passes through scenegraph:
237A search scenegraph for generatedcubemap locations
238B foreach generatedcubemap location
239 foreach 6 faces
240 render scenegraph to fbo without generatedcubemap consumers
241 convert fbo to cubemap
242C render scenegraph normally with generatedcubemap consumers
243
244Strange 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
253dynamic cubemap links:
254http://www.mbroecker.com/project_dynamic_cubemaps.html
255http://richardssoftware.net/Home/Post/26
256- DX
257http://webglsamples.org/dynamic-cubemap/dynamic-cubemap.html
258- webgl sample
259http://stackoverflow.com/questions/4775798/rendering-dynamic-cube-maps-in-opengl-with-frame-buffer-objects
260http://users.csc.calpoly.edu/~ssueda/teaching/CSC471/2016S/demos/khongton/index.html
261http://math.hws.edu/graphicsbook/source/webgl/cube-camera.html
262https://www.opengl.org/discussion_boards/showthread.php/156906-Dynamic-cubemap-FBO
263https://github.com/WebGLSamples/WebGLSamples.github.io/tree/master/dynamic-cubemap
264
265
266*/
267
268static 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
282void 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
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
493char data[ 128 ];
494};
495
496#endif // mydds_h
497
498
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
510struct DdsLoadInfo loadInfoDXT1 = {
511 true, false, false, 4, 8, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
512};
513struct DdsLoadInfo loadInfoDXT3 = {
514 true, false, false, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
515};
516struct 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
533struct DdsLoadInfo loadInfoRGB8 = {
534 false, false, false, 1, 3, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE
535};
536struct DdsLoadInfo loadInfoBGR8 = {
537 false, false, false, 1, 3, GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE
538};
539struct DdsLoadInfo loadInfoBGR565 = {
540 false, true, false, 1, 2, GL_RGB5, GL_RGB, GL_UNSIGNED_SHORT_5_6_5
541};
542
543#ifdef OLDCODE
544OLDCODE static unsigned int GetLowestBitPos(unsigned int value)
545OLDCODE {
546OLDCODE unsigned int pos = 0;
547OLDCODE assert(value != 0); // handled separately
548OLDCODE
549OLDCODE while (!(value & 1))
550OLDCODE {
551OLDCODE value >>= 1;
552OLDCODE ++pos;
553OLDCODE if(pos == 32) break;
554OLDCODE }
555OLDCODE return pos;
556OLDCODE }
557#endif //OLDCODE
558
559// LoadTextures.c likes to call this one
560int 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
911void 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
937void 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 */
970static 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.
991void 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.
1072void 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
1156static 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.
1163void 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.
1174void 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
1188void pushnset_framebuffer(int ibuffer);
1189void 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
1196int haveFrameBufferObject();
1197
1198// called from the scene traversal, linked in GeneratedCode.c
1199void 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();
1268void get_view_matrix(double *savePosOri, double *saveView);
1269void freeASCIIString(struct Uni_String *us);
1270
1271// called from the scene traversal, linked in GeneratedCode.c
1272void 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:
1360static struct {
1361double angle;
1362double x;
1363double y;
1364double 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
1374void saveImage_web3dit(struct textureTableIndexStruct *tti, char *fname);
1375void fw_gluPerspective_2(GLDOUBLE xcenter, GLDOUBLE fovy, GLDOUBLE aspect, GLDOUBLE zNear, GLDOUBLE zFar);
1376void pushnset_viewport(float *vpFraction);
1377void popnset_viewport();
1378void render_bound_background();
1379
1380// called from MainLoop.c
1381
1382void generate_GeneratedCubeMapTextures(){
1383 //call from mainloop once per frame:
1384 //foreach cubemaptexture location in cubgen list
1385 // foreach 6 sides
1386 // set viewpoint pose
1387 // render scene to fbo
1388 // convert fbo to regular cubemap texture
1389 //clear cubegen list
1390 Stack *gencube_stack;
1391 ttglobal tg = gglobal();
1392 ppComponent_CubeMapTexturing p = (ppComponent_CubeMapTexturing)tg->Component_CubeMapTexturing.prv;
1393 static int iframe = 0;
1394
1395 iframe++;
1396 gencube_stack = p->gencube_stack;
1397 if(vectorSize(gencube_stack)){
1398 int i, j, n;
1399
1400 n = vectorSize(gencube_stack);
1401 for(i=0;i<n;i++){
1402 usehit uhit;
1403 int isize;
1404 double modelviewmatrix[16];
1406 float vp[4] = {0.0f,1.0f,0.0f,1.0f}; //arbitrary
1407 struct X3D_GeneratedCubeMapTexture * node;
1408
1409 uhit = vector_get(usehit,gencube_stack,i);
1410 node = (struct X3D_GeneratedCubeMapTexture*)uhit.node;
1411 memcpy(modelviewmatrix,uhit.mvm,16*sizeof(double));
1412
1413 //compile_generatedcubemap - creates framebufferobject fbo
1414 tti = getTableIndex(node->__textureTableIndex);
1415
1416 isize = tti->x; //set in compile_
1417 pushnset_framebuffer(tti->ifbobuffer); //binds framebuffer. we push here, in case higher up we are already rendering the whole scene to an fbo
1418 //GLuint attachments [1] = {GL_COLOR_ATTACHMENT0};
1419 //glDrawBuffers(1,attachments); //'draw' is implied in GL_RENDERBUFFER above
1420 //glReadBuffer(GL_COLOR_ATTACHMENT0); //'read' is implied in GL_RENDERBUFFER
1421 pushnset_viewport(vp); //something to push so we can pop-and-set below, so any mainloop GL_BACK viewport is restored
1422 glViewport(0,0,isize,isize); //viewport we want
1423
1424 //create fbo or fbo tiles collection for generatedcubemap
1425 //method: we draw each face to a single framebuffer texture,
1426 // and readpixels back into 6 PixelTexture tti->texdata, so its a bit like ImageCubeMap except
1427 // we skip the steps of creating and reading back PixelTexture->image.p into texdata
1428 for(j=0;j<node->__subTextures.n;j++){ //should be 6
1430 struct X3D_PixelTexture * nodep;
1431 GLuint pixelType;
1432 int bytesPerPixel;
1433
1434 nodep = (struct X3D_PixelTexture *)node->__subTextures.p[j];
1435 ttip = getTableIndex(nodep->__textureTableIndex);
1436 //we won't directly generate cubemap textures here, but looks interesting as possible
1437 // shotcut to skip readpixels below
1438 //glBindTexture(GL_TEXTURE_2D, ttip->OpenGLTexture);
1439 //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+j, GL_TEXTURE_2D, ttip->OpenGLTexture, 0);
1440 glClearColor(1.0f,0.0f,0.0f,1.0f); //red, for diagnostics during debugging
1441 FW_GL_CLEAR(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1442
1443 //set viewpoint matrix for side
1444 //setup_projection();
1445 FW_GL_MATRIX_MODE(GL_PROJECTION);
1446 FW_GL_LOAD_IDENTITY();
1447 //fw_gluPerspective(90.0, 1.0, .1,10000.0);
1448 fw_gluPerspective_2(0.0,90.0, 1.0, .1,10000.0);
1449
1450 FW_GL_MATRIX_MODE(GL_MODELVIEW);
1451 FW_GL_LOAD_IDENTITY();
1452 fw_glSetDoublev(GL_MODELVIEW_MATRIX, modelviewmatrix);
1453 fw_glRotated(sideangle[j].angle,sideangle[j].x,sideangle[j].y,sideangle[j].z);
1454
1455
1456 clearLightTable();//turns all lights off- will turn them on for VF_globalLight and scope-wise for non-global in VF_geom
1457
1458 render_bound_background();
1459
1460 /* turn light #0 off only if it is not a headlight.*/
1461 if (!fwl_get_headlight()) {
1462 setLightState(HEADLIGHT_LIGHT,FALSE);
1463 setLightType(HEADLIGHT_LIGHT,2); // DirectionalLight
1464 }
1465
1466 /* Other lights*/
1467 PRINT_GL_ERROR_IF_ANY("XEvents::render, before render_hier");
1468
1469 render_hier(rootNode(), VF_globalLight );
1470 PRINT_GL_ERROR_IF_ANY("XEvents::render, render_hier(VF_globalLight)");
1471 render_hier(rootNode(), VF_Other );
1472
1473 /* 4. Nodes (not the blended ones)*/
1474 profile_start("hier_geom");
1475 render_hier(rootNode(), VF_Geom | VF_Cube);
1476 profile_end("hier_geom");
1477 PRINT_GL_ERROR_IF_ANY("XEvents::render, render_hier(VF_Geom)");
1478
1479 /* 5. Blended Nodes*/
1480 if (tg->RenderFuncs.have_transparency) {
1481 /* render the blended nodes*/
1482 render_hier(rootNode(), VF_Geom | VF_Blend | VF_Cube);
1483 PRINT_GL_ERROR_IF_ANY("XEvents::render, render_hier(VF_Geom)");
1484 }
1485
1486 //if you can figure out how to use regular texture in cubemap, then there may be a shortcut
1487 //for now, we'll pull the fbo pixels back into cpu space and put them in pixeltexture
1488 pixelType = GL_RGBA;
1489 bytesPerPixel = 4;
1490 if(!ttip->texdata || ttip->x != isize){
1491 FREE_IF_NZ(ttip->texdata);
1492 ttip->texdata = MALLOC (GLvoid *, bytesPerPixel*isize*isize);
1493 }
1494
1495 /* grab the data */
1496 //FW_GL_PIXELSTOREI (GL_UNPACK_ALIGNMENT, 1);
1497 //FW_GL_PIXELSTOREI (GL_PACK_ALIGNMENT, 1);
1498
1499 FW_GL_READPIXELS (0,0,isize,isize,pixelType,GL_UNSIGNED_BYTE, ttip->texdata);
1500 ttip->x = isize;
1501 ttip->y = isize;
1502 ttip->z = 1;
1503 ttip->hasAlpha = 1;
1504 ttip->channels = 4;
1505 ttip->status = TEX_NEEDSBINDING;
1506 if(0){
1507 //write out tti as web3dit image files for diagnostic viewing, can use for BackGround node
1508 //void saveImage_web3dit(struct textureTableIndexStruct *tti, char *fname)
1509 if(iframe == 50){
1510 char namebuf[100];
1511 sprintf(namebuf,"%s%d.web3dit","cubemapface_",j);
1512 saveImage_web3dit(ttip, namebuf);
1513 }
1514 }
1515 }
1516 popnset_viewport();
1517 popnset_framebuffer();
1518 //compile_generatedcubemaptexture // convert to opengl
1519 }
1520 //clear cubegen list
1521 gencube_stack->n = 0;
1522 }
1523}