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
268
269
270
271
272int generate_color_cubemap_gl_texture(int size) {
273 //if size > 0, reserves blank space for each side, otherwise just the basics
274 int tex;
275 glGenTextures(1, &tex);
276 glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
277 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
278 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
279 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
280 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
281 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
282 // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexParameter.xhtml
283 if (size > 0) {
284 for (size_t i = 0; i < 6; ++i) {
285 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
286 }
287 }
288 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
289 return tex;
290}
291
292
293
294/****************************************************************************
295 *
296 * ComposedCubeMapTextures
297 *
298 ****************************************************************************/
299
300static int cubetextureID = 0;
301
302void texture_flipy(int width, int height, int bytesperpixel, unsigned char* data){
303 //flips image data in place
304 int ipixi, ipixo, ibytei, ibyteo;
305 unsigned char* row = malloc(width * bytesperpixel);
306 for (int y = 0; y < height/2; y++) {
307 int y2 = height - 1 - y;
308 ipixo = y2 * width;
309 ibyteo = ipixo * bytesperpixel;
310 ipixi = y * width;
311 ibytei = ipixi * bytesperpixel;
312 memcpy(row, &data[ibyteo], width * bytesperpixel);
313 memcpy(&data[ibyteo], &data[ibytei], width * bytesperpixel);
314 memcpy(&data[ibytei], row, width * bytesperpixel);
315 }
316}
317
318// new way
319void render_ComposedCubeMapTexture(struct X3D_ComposedCubeMapTexture* node) {
320 //step 1 create a cubemap texture
321 //step 2 iterate over textures, and any that are loaded, apply to cubemap
322 //step 3 when all loaded, flag cubemap as loaded, otherwise keep checking
323 textureTableIndexStruct_s* tti;
324 tti = getTableTableFromTextureNode(X3D_NODE(node));
325 if (tti && tti->status != TEX_LOADED)
326 {
327 if (tti->status == TEX_NOTLOADED) {
328 tti->OpenGLTexture = generate_color_cubemap_gl_texture(0);
329 glBindTexture(GL_TEXTURE_CUBE_MAP, tti->OpenGLTexture);
330 tti->status = TEX_LOADING;
331 }
332 if (tti->status == TEX_LOADING) {
333 int loaded_faces = 0;
334 textureTableIndexStruct_s* ttiface;
335 struct X3D_Node* texface;
336 for (int iface = 0; iface < 6; iface++) {
337
338 // right left, top, bottom, front, back,
339 // +x, -x, +y, -y, +z, -z //LHS system
340 // -z, +z //RHS system
341 switch (iface) {
342 case 0: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node*, node->right, texface); break; }
343 case 1: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node*, node->left, texface); break; }
344
345 case 2: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node*, node->top, texface); break; }
346 case 3: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node*, node->bottom, texface); break; }
347
348 case 4: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node*, node->front, texface); break; }
349 case 5: {POSSIBLE_PROTO_EXPANSION(struct X3D_Node*, node->back, texface); break; }
350 }
351 //printf ("rcm, thistex %p, type %s\n",thistex,stringNodeType(thistex->_nodeType));
352 if (texface != NULL) {
353 /* we have an image specified for this face */
354 /* the X3D spec says that a X3DTextureNode has to be one of... */
355 if ((texface->_nodeType == NODE_ImageTexture) ||
356 (texface->_nodeType == NODE_PixelTexture) ||
357 (texface->_nodeType == NODE_MovieTexture) ||
358 (texface->_nodeType == NODE_MultiTexture)) {
359
360 ttiface = getTableTableFromTextureNode(X3D_NODE(texface));
361 if (ttiface->status == TEX_LOADED) {
362 glBindTexture(GL_TEXTURE_2D, ttiface->OpenGLTexture);
363 unsigned char* texdata = malloc(ttiface->x * ttiface->y * 4);
364 // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetTexImage.xhtml
365 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, texdata);
366 texture_flipy(ttiface->x, ttiface->y, 4, texdata);
367 glBindTexture(GL_TEXTURE_2D, 0);
368 glBindTexture(GL_TEXTURE_CUBE_MAP, tti->OpenGLTexture);
369 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + iface, 0, GL_RGBA, ttiface->x, ttiface->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, texdata);
370 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
371 free(texdata);
372 loaded_faces++;
373 }
374 else {
375 gglobal()->RenderFuncs.textureStackTop = 0;
376 /* render the proper texture */
377 render_node(X3D_NODE(texface));
378 gglobal()->RenderFuncs.textureStackTop = 0;
379 }
380 }
381 }
382 }
383 if (loaded_faces > 0 && loaded_faces < 6)
384 tti->status = TEX_LOADING;
385 else if (loaded_faces == 6) {
386 tti->status = TEX_LOADED;
387 //appearance likes to know if there's alpha
388 struct X3D_Node* p[6];
389 p[0] = node->left;
390 p[1] = node->right;
391 p[2] = node->top;
392 p[3] = node->bottom;
393 p[4] = node->front;
394 p[5] = node->back;
395 int channels = 0;
396 int imgalpha = 0;
397 for (int iface = 0; iface < 6; iface++) {
398 textureTableIndexStruct_s* ttiface = getTableTableFromTextureNode(p[iface]);
399 //new Aug 6, 2016, check LoadTextures.c for your platform channel counting
400 //NoImage=0, Luminance=1, LuminanceAlpha=2, RGB=3, RGBA=4
401 //PROBLEM: if tti isn't loaded -with #channels, alpha set-, we don't want to compile child
402 channels = max(channels, ttiface->channels);
403 imgalpha = max(ttiface->hasAlpha, imgalpha);
404 }
405 textureTableIndexStruct_s* tti = getTableTableFromTextureNode(X3D_NODE(node));
406 tti->channels = channels;
407 tti->hasAlpha = imgalpha;
408 }
409 }
410 }
411 if (tti && tti->status >= TEX_LOADING) {
412 gglobal()->RenderFuncs.textureStackTop = 1;
413 gglobal()->RenderFuncs.texturenode = node;
414 }
415 else {
416 gglobal()->RenderFuncs.textureStackTop = 0;
417 }
418}
419
420
421
422/* is this a DDS file? If so, get it, and subdivide it. Ignore MIPMAPS for now */
423/* see: http://www.mindcontrol.org/~hplus/graphics/dds-info/MyDDS.cpp */
424/* see: http://msdn.microsoft.com/en-us/library/bb943991.aspx/ */
425// 2016: https://msdn.microsoft.com/en-us/library/windows/desktop/bb943982(v=vs.85).aspx
426
427/* DDS readstuff */
428/* DDS loader written by Jon Watte 2002 */
429/* Permission granted to use freely, as long as Jon Watte */
430/* is held harmless for all possible damages resulting from */
431/* your use or failure to use this code. */
432/* No warranty is expressed or implied. Use at your own risk, */
433/* or not at all. */
434
435#if !defined( mydds_h )
436
437// little-endian, of course
438#define DDS_MAGIC 0x20534444
439
440
441// DDS_header.dwFlags
442 #define DDSD_CAPS 0x00000001
443// #define DDSD_HEIGHT 0x00000002
444// #define DDSD_WIDTH 0x00000004
445// #define DDSD_PITCH 0x00000008
446 #define DDSD_PIXELFORMAT 0x00001000
447// #define DDSD_MIPMAPCOUNT 0x00020000
448// #define DDSD_LINEARSIZE 0x00080000
449 #define DDSD_DEPTH 0x00800000
450
451// DDS_header.sPixelFormat.dwFlags
452 #define DDPF_ALPHAPIXELS 0x00000001
453 #define DDPF_FOURCC 0x00000004
454 #define DDPF_INDEXED 0x00000020
455 #define DDPF_RGB 0x00000040
456
457// DDS_header.sCaps.dwCaps1
458 #define DDSCAPS_COMPLEX 0x00000008
459// #define DDSCAPS_TEXTURE 0x00001000
460// #define DDSCAPS_MIPMAP 0x00400000
461
462// DDS_header.sCaps.dwCaps2
463 #define DDSCAPS2_CUBEMAP 0x00000200
464 #define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
465 #define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
466 #define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
467 #define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
468 #define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
469 #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
470 #define DDSCAPS2_VOLUME 0x00200000
471
472/* old way - use 4-char string and cast later, not a good idea
473 #define D3DFMT_DXT1 "1TXD" // DXT1 compression texture format
474 #define D3DFMT_DXT2 "2TXD" // DXT2 compression texture format
475 #define D3DFMT_DXT3 "3TXD" // DXT3 compression texture format
476 #define D3DFMT_DXT4 "4TXD" // DXT4 compression texture format
477 #define D3DFMT_DXT5 "5TXD" // DXT5 compression texture format
478*/
479/* new way - use actual four-byte unsigned integer value */
480 #define D3DFMT_DXT1 0x31545844
481// #define D3DFMT_DXT2 0x32545844
482 #define D3DFMT_DXT3 0x33545844
483// #define D3DFMT_DXT4 0x34545844
484 #define D3DFMT_DXT5 0x35545844
485
486
487#define PF_IS_DXT1(pf) \
488 ((pf.dwFlags & DDPF_FOURCC) && \
489 (pf.dwFourCC == (unsigned int) D3DFMT_DXT1))
490
491#define PF_IS_DXT3(pf) \
492 ((pf.dwFlags & DDPF_FOURCC) && \
493 (pf.dwFourCC == (unsigned int) D3DFMT_DXT3))
494
495#define PF_IS_DXT5(pf) \
496 ((pf.dwFlags & DDPF_FOURCC) && \
497 (pf.dwFourCC == (unsigned int) D3DFMT_DXT5))
498
499#define PF_IS_BGRA8(pf) \
500 ((pf.dwFlags & DDPF_RGB) && \
501 (pf.dwFlags & DDPF_ALPHAPIXELS) && \
502 (pf.dwRGBBitCount == 32) && \
503 (pf.dwRBitMask == 0xff0000) && \
504 (pf.dwGBitMask == 0xff00) && \
505 (pf.dwBBitMask == 0xff) && \
506 (pf.dwAlphaBitMask == 0xff000000U))
507
508#define PF_IS_RGB8(pf) \
509 ((pf.dwFlags & DDPF_RGB) && \
510 !(pf.dwFlags & DDPF_ALPHAPIXELS) && \
511 (pf.dwRGBBitCount == 24) && \
512 (pf.dwRBitMask == 0xff) && \
513 (pf.dwGBitMask == 0xff00) && \
514 (pf.dwBBitMask == 0xff0000))
515
516#define PF_IS_BGR8(pf) \
517 ((pf.dwFlags & DDPF_RGB) && \
518 !(pf.dwFlags & DDPF_ALPHAPIXELS) && \
519 (pf.dwRGBBitCount == 24) && \
520 (pf.dwRBitMask == 0xff0000) && \
521 (pf.dwGBitMask == 0xff00) && \
522 (pf.dwBBitMask == 0xff))
523
524#define PF_IS_BGR5A1(pf) \
525 ((pf.dwFlags & DDPF_RGB) && \
526 (pf.dwFlags & DDPF_ALPHAPIXELS) && \
527 (pf.dwRGBBitCount == 16) && \
528 (pf.dwRBitMask == 0x00007c00) && \
529 (pf.dwGBitMask == 0x000003e0) && \
530 (pf.dwBBitMask == 0x0000001f) && \
531 (pf.dwAlphaBitMask == 0x00008000))
532
533#define PF_IS_BGR565(pf) \
534 ((pf.dwFlags & DDPF_RGB) && \
535 !(pf.dwFlags & DDPF_ALPHAPIXELS) && \
536 (pf.dwRGBBitCount == 16) && \
537 (pf.dwRBitMask == 0x0000f800) && \
538 (pf.dwGBitMask == 0x000007e0) && \
539 (pf.dwBBitMask == 0x0000001f))
540
541#define PF_IS_INDEX8(pf) \
542 ((pf.dwFlags & DDPF_INDEXED) && \
543 (pf.dwRGBBitCount == 8))
544
545#define PF_IS_VOLUME(pf) \
546 ((pf.dwFlags & DDSD_DEPTH))
547 //&&
548 // (pf.sCaps.dwCaps1 & DDSCAPS_COMPLEX) &&
549 // (pf.sCaps.dwCaps1 & DDSCAPS2_VOLUME))
550
551
552
554 struct {
555 unsigned int dwMagic;
556 unsigned int dwSize;
557 unsigned int dwFlags;
558 unsigned int dwHeight;
559 unsigned int dwWidth;
560 unsigned int dwPitchOrLinearSize;
561 unsigned int dwDepth;
562 unsigned int dwMipMapCount;
563 unsigned int dwReserved1[ 11 ];
564
565 // DDPIXELFORMAT
566 struct {
567 unsigned int dwSize;
568 unsigned int dwFlags;
569 unsigned int dwFourCC;
570 unsigned int dwRGBBitCount;
571 unsigned int dwRBitMask;
572 unsigned int dwGBitMask;
573 unsigned int dwBBitMask;
574 unsigned int dwAlphaBitMask;
575 } sPixelFormat;
576
577 // DDCAPS2
578 struct {
579 unsigned int dwCaps1;
580 unsigned int dwCaps2;
581 unsigned int dwDDSX;
582 unsigned int dwReserved;
583 } sCaps;
584 unsigned int dwReserved2;
585 }; //JASdefStruct; // put "name" in here to get rid of compiler warning
586char data[ 128 ];
587};
588
589#endif // mydds_h
590
591
593 bool compressed;
594 bool swap;
595 bool palette;
596 unsigned int divSize;
597 unsigned int blockBytes;
598 GLenum internalFormat;
599 GLenum externalFormat;
600 GLenum type;
601};
602
603struct DdsLoadInfo loadInfoDXT1 = {
604 true, false, false, 4, 8, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
605};
606struct DdsLoadInfo loadInfoDXT3 = {
607 true, false, false, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
608};
609struct DdsLoadInfo loadInfoDXT5 = {
610 true, false, false, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
611};
612
613#if defined (GL_BGRA)
614
615 struct DdsLoadInfo loadInfoBGRA8 = {
616 false, false, false, 1, 4, GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE
617 };
618 struct DdsLoadInfo loadInfoBGR5A1 = {
619 false, true, false, 1, 2, GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV
620 };
621 struct DdsLoadInfo loadInfoIndex8 = {
622 false, false, true, 1, 1, GL_RGB8, GL_BGRA, GL_UNSIGNED_BYTE
623 };
624#endif //BGRA textures supported
625
626struct DdsLoadInfo loadInfoRGB8 = {
627 false, false, false, 1, 3, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE
628};
629struct DdsLoadInfo loadInfoBGR8 = {
630 false, false, false, 1, 3, GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE
631};
632struct DdsLoadInfo loadInfoBGR565 = {
633 false, true, false, 1, 2, GL_RGB5, GL_RGB, GL_UNSIGNED_SHORT_5_6_5
634};
635
636// LoadTextures.c likes to call this one
637int textureIsDDS(textureTableIndexStruct_s* this_tex, char *filename) {
638 FILE *file;
639 unsigned char *buffer, *bdata; //, *bdata2;
640 char sniffbuf[20];
641 unsigned long fileLen;
642 union DDS_header hdr;
643 unsigned int x = 0;
644 unsigned int y = 0;
645 unsigned int z = 0;
646 //unsigned int rshift[4]; //to go with color bitmask
647 int nchan, idoFrontBackSwap;
648 //unsigned int mipMapCount = 0;
649 unsigned int xSize, ySize,zSize;
650
651 struct DdsLoadInfo * li;
652 size_t xx;
653
654 UNUSED(xx); // compiler warning mitigation
655 xSize=ySize=zSize=0;
656 li = NULL;
657
658 //printf ("textureIsDDS... node %s, file %s\n",
659 // stringNodeType(this_tex->scenegraphNode->_nodeType), filename);
660
661 /* read in file */
662 file = fopen(filename,"rb");
663 if (!file)
664 return FALSE;
665
666 //sniff header
667 xx=fread(sniffbuf, 4, 1, file);
668 fclose(file);
669 if(strncmp(sniffbuf,"DDS ",4)){
670 //not DDS file
671 //sniffbuf[5] = '\0';
672 //printf("sniff header = %s\n",sniffbuf);
673 return FALSE;
674 }
675 file = fopen(filename,"rb");
676 /* have file, read in data */
677
678
679 /* get file length */
680 fseek(file, 0, SEEK_END);
681 fileLen=ftell(file);
682 fseek(file, 0, SEEK_SET);
683
684 /* llocate memory */
685 buffer=MALLOC(unsigned char *, fileLen+1);
686 if (!buffer) {
687 fclose(file);
688 return FALSE;
689 }
690
691 /* read file */
692 xx=fread(buffer, fileLen, 1, file);
693 fclose(file);
694
695 /* check to see if this could be a valid DDS file */
696 if (fileLen < sizeof(hdr))
697 return FALSE;
698
699 /* look at the header, see what kind of a DDS file it might be */
700 memcpy( &hdr, buffer, sizeof(hdr));
701
702 /* does this start off with "DDS " an so on ?? */
703 if ((hdr.dwMagic == DDS_MAGIC) && (hdr.dwSize == 124) &&
704 (hdr.dwFlags & DDSD_PIXELFORMAT) && (hdr.dwFlags & DDSD_CAPS)) {
705 //printf ("matched :DDS :\n");
706
707
708 //printf ("dwFlags %x, DDSD_PIXELFORMAT %x, DDSD_CAPS %x\n",hdr.dwFlags, DDSD_PIXELFORMAT, DDSD_CAPS);
709 xSize = hdr.dwWidth;
710 ySize = hdr.dwHeight;
711 //printf ("size %d, %d\n",xSize, ySize);
712
713
714 /*
715 assert( !(xSize & (xSize-1)) );
716 assert( !(ySize & (ySize-1)) );
717 */
718
719 if(0){
720 printf ("looking to see what it is...\n");
721 printf ("DDPF_FOURCC dwFlags %x mask %x, final %x\n",hdr.sPixelFormat.dwFlags,DDPF_FOURCC,hdr.sPixelFormat.dwFlags & DDPF_FOURCC);
722
723 printf ("if it is a dwFourCC, %x and %x\n", hdr.sPixelFormat.dwFourCC ,D3DFMT_DXT1);
724
725 printf ("dwFlags %x\n",hdr.sPixelFormat.dwFlags);
726 printf ("dwRGBBitCount %d\n",hdr.sPixelFormat.dwRGBBitCount); //24 for normal RGB
727 printf ("dwRBitMask %x\n",hdr.sPixelFormat.dwRBitMask);
728 printf ("dwGBitMask %x\n",hdr.sPixelFormat.dwGBitMask);
729 printf ("dwBBitMask %x\n",hdr.sPixelFormat.dwBBitMask);
730 printf ("dwAlphaBitMask %x\n",hdr.sPixelFormat.dwAlphaBitMask);
731 printf ("dwFlags and DDPF_ALPHAPIXELS... %x\n",DDPF_ALPHAPIXELS & hdr.sPixelFormat.dwFlags);
732 printf ("dwflags & DDPF_RGB %x\n,",hdr.sPixelFormat.dwFlags & DDPF_RGB);
733
734 printf ("dwFlags and DEPTH %x\n",hdr.dwFlags & DDSD_DEPTH);
735 printf ("dwCaps1 and complex %x\n", (hdr.sCaps.dwCaps1 & DDSCAPS_COMPLEX));
736 printf ("dwCaps1 and VOLUME %x\n", (hdr.sCaps.dwCaps1 & DDSCAPS2_VOLUME));
737 }
738 //rshift[0] = GetLowestBitPos(hdr.sPixelFormat.dwRBitMask);
739 //rshift[1] = GetLowestBitPos(hdr.sPixelFormat.dwGBitMask);
740 //rshift[2] = GetLowestBitPos(hdr.sPixelFormat.dwBBitMask);
741 //rshift[3] = GetLowestBitPos(hdr.sPixelFormat.dwAlphaBitMask);
742 bdata = NULL;
743 if(hdr.sPixelFormat.dwFlags & DDPF_FOURCC){
744 if( PF_IS_DXT1( hdr.sPixelFormat ) ) {
745 li = &loadInfoDXT1;
746 }
747 else if( PF_IS_DXT3( hdr.sPixelFormat ) ) {
748 li = &loadInfoDXT3;
749 }
750 else if( PF_IS_DXT5( hdr.sPixelFormat ) ) {
751 li = &loadInfoDXT5;
752 }
753
754 #if defined (GL_BGRA)
755 else if( PF_IS_BGRA8( hdr.sPixelFormat ) ) {
756 li = &loadInfoBGRA8;
757 }
758 else if( PF_IS_BGR5A1( hdr.sPixelFormat ) ) {
759 li = &loadInfoBGR5A1;
760 }
761 else if( PF_IS_INDEX8( hdr.sPixelFormat ) ) {
762 li = &loadInfoIndex8;
763 }
764 #endif
765
766 else if( PF_IS_RGB8( hdr.sPixelFormat ) ) {
767 li = &loadInfoRGB8;
768 }
769 else if( PF_IS_BGR8( hdr.sPixelFormat ) ) {
770 li = &loadInfoBGR8;
771 }
772 else if( PF_IS_BGR565( hdr.sPixelFormat ) ) {
773 li = &loadInfoBGR565;
774 }
775 //else {
776 // ConsoleMessage("CubeMap li failure\n");
777 // return FALSE;
778 //}
779 }else{
780 //no FOURCC
781 bdata = &buffer[sizeof(union DDS_header)];
782 //bdata = &hdr.data[0];
783 }
784 //fixme: do cube maps later
785 //fixme: do 3d later
786 x = xSize = hdr.dwWidth;
787 y = ySize = hdr.dwHeight;
788 z = zSize = 1;
789 idoFrontBackSwap = 0;
790 if( PF_IS_VOLUME(hdr) )
791 z = zSize = hdr.dwDepth;
792 if( hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP){
793 int facecount = 0;
794 if(hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP_POSITIVEX) facecount++;
795 if(hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) facecount++;
796 if(hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP_POSITIVEY) facecount++;
797 if(hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) facecount++;
798 if(hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) facecount++;
799 if(hdr.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) facecount++;
800 z = zSize = facecount;
801 if(z==6)
802 idoFrontBackSwap = 1;
803 }
804 nchan = 3;
805 if(DDPF_ALPHAPIXELS & hdr.sPixelFormat.dwFlags) nchan = 4;
806 //if(li == NULL)
807 // return FALSE;
808 //if(!hdr.dwFlags & DDSD_MIPMAPCOUNT){
809 if(bdata){
810 //simple, convert to rgba and set tti
811 int ipix,jpix,bpp, ir, ig, ib;
812 unsigned int i,j,k;
813 unsigned char * rgbablob = malloc(x*y*z *4);
814 bpp = hdr.sPixelFormat.dwRGBBitCount / 8;
815 ir = 0; ig = 1; ib = 2; //if incoming is BGR order
816 if(hdr.sPixelFormat.dwRBitMask > hdr.sPixelFormat.dwBBitMask){
817 //if incoming is RGB order
818 ir = 2;
819 ib = 0;
820 //printf("BGR\n");
821 }
822 //printf("bitmasks R %d G %d B %d\n",hdr.sPixelFormat.dwRBitMask,hdr.sPixelFormat.dwGBitMask,hdr.sPixelFormat.dwBBitMask);
823 //printf("bpp=%d x %d y %d z %d\n",bpp, x,y,z);
824 for(i=0;i<z;i++){
825 for(j=0;j<y;j++){
826 for(k=0;k<x;k++){
827 unsigned char *pixel,*rgba;
828 int ii;
829 ii = idoFrontBackSwap && i == 4? 5 : i; //swap Front and Back faces for opengl order
830 ii = idoFrontBackSwap && i == 5? 4 : i;
831 ii = i;
832 ipix = (i*y +j)*x +k; //top down, for input image
833 jpix = (ii*y +(y-1-j))*x + k; //bottom up, for ouput texture
834 pixel = &bdata[ipix * bpp];
835 rgba = &rgbablob[jpix *4];
836 //freewrl target format: RGBA
837 //swizzle if incoming is BGRA
838 rgba[3] = 255;
839 rgba[0] = pixel[ir];
840 rgba[1] = pixel[ig];
841 rgba[2] = pixel[ib];
842 if(nchan == 4)
843 rgba[3] = pixel[3];
844 if(0){
845 static int once = 0;
846 if(!once){
847 printf("pixel R=%x G=%x B=%x A=%x\n",rgba[0],rgba[1],rgba[2],rgba[3]);
848 //once = 1;
849 }
850 }
851
852 }
853 }
854 }
855 this_tex->channels = nchan;
856 this_tex->x = x;
857 this_tex->y = y;
858 this_tex->z = z;
859 this_tex->texdata = rgbablob;
860 return TRUE;
861 }else{
862 return FALSE;
863 }
864
865 //mipMapCount = (hdr.dwFlags & DDSD_MIPMAPCOUNT) ? hdr.dwMipMapCount : 1;
866 //printf ("mipMapCount %d\n",mipMapCount);
867
868 if( li->compressed ) {
869 //printf ("compressed\n");
870 /*
871 size_t size = max( li->divSize, x )/li->divSize * max( li->divSize, y )/li->divSize * li->blockBytes;
872 assert( size == hdr.dwPitchOrLinearSize );
873 assert( hdr.dwFlags & DDSD_LINEARSIZE );
874 unsigned char * data = (unsigned char *)malloc( size );
875 if( !data ) {
876 goto failure;
877 }
878 format = cFormat = li->internalFormat;
879 for( unsigned int ix = 0; ix < mipMapCount; ++ix ) {
880 fread( data, 1, size, f );
881 glCompressedTexImage2D( GL_TEXTURE_2D, ix, li->internalFormat, x, y, 0, size, data );
882 gl->updateError();
883 x = (x+1)>>1;
884 y = (y+1)>>1;
885 size = max( li->divSize, x )/li->divSize * max( li->divSize, y )/li->divSize * li->blockBytes;
886 }
887 free( data );
888 */
889 } else if( li->palette ) {
890 //printf ("palette\n");
891 /*
892 // currently, we unpack palette into BGRA
893 // I'm not sure we always get pitch...
894 assert( hdr.dwFlags & DDSD_PITCH );
895 assert( hdr.sPixelFormat.dwRGBBitCount == 8 );
896 size_t size = hdr.dwPitchOrLinearSize * ySize;
897 // And I'm even less sure we don't get padding on the smaller MIP levels...
898 assert( size == x * y * li->blockBytes );
899 format = li->externalFormat;
900 cFormat = li->internalFormat;
901 unsigned char * data = (unsigned char *)malloc( size );
902 unsigned int palette[ 256 ];
903 unsigned int * unpacked = (unsigned int *)malloc( size*sizeof( unsigned int ) );
904 fread( palette, 4, 256, f );
905 for( unsigned int ix = 0; ix < mipMapCount; ++ix ) {
906 fread( data, 1, size, f );
907 for( unsigned int zz = 0; zz < size; ++zz ) {
908 unpacked[ zz ] = palette[ data[ zz ] ];
909 }
910 glPixelStorei( GL_UNPACK_ROW_LENGTH, y );
911 glTexImage2D( GL_TEXTURE_2D, ix, li->internalFormat, x, y, 0, li->externalFormat, li->type, unpacked );
912 gl->updateError();
913 x = (x+1)>>1;
914 y = (y+1)>>1;
915 size = x * y * li->blockBytes;
916 }
917 free( data );
918 free( unpacked );
919 */
920 } else {
921 //int size;
922
923 if( li->swap ) {
924 printf ("swap\n");
925
926 /*
927 glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_TRUE );
928 */
929 }
930 //size = x * y * li->blockBytes;
931
932 //printf ("size is %d\n",size);
933 /*
934 format = li->externalFormat;
935 cFormat = li->internalFormat;
936 unsigned char * data = (unsigned char *)malloc( size );
937 //fixme: how are MIP maps stored for 24-bit if pitch != ySize*3 ?
938 for( unsigned int ix = 0; ix < mipMapCount; ++ix ) {
939 fread( data, 1, size, f );
940 glPixelStorei( GL_UNPACK_ROW_LENGTH, y );
941 glTexImage2D( GL_TEXTURE_2D, ix, li->internalFormat, x, y, 0, li->externalFormat, li->type, data );
942 gl->updateError();
943 x = (x+1)>>1;
944 y = (y+1)>>1;
945 size = x * y * li->blockBytes;
946 }
947 free( data );
948 glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE );
949 gl->updateError();
950 */
951 }
952 /*
953 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipMapCount-1 );
954 gl->updateError();
955
956 return true;
957
958 failure:
959 return false;
960 }
961 */
962
963 }
964 // else {
965 // //printf ("put in the dummy file here, and call it quits\n");
966 //}
967 FREE_IF_NZ(buffer);
968 return FALSE;
969}
970
971
972
973/****************************************************************************
974 *
975 * ImageCubeMapTextures
976 * notes - we make 6 PixelTextures, and actually put the data for each face
977 * into these pixelTextures.
978 *
979 * yes, maybe there is a better way; this way mimics the ComposedCubeMap
980 * method, and makes rendering both ImageCubeMap and ComposedCubeMapTextures
981 * the same, in terms of scene-graph traversal.
982 *
983 * look carefully at the call to unpackImageCubeMap...
984 *
985 ****************************************************************************/
986 void add_node_to_broto_context(struct X3D_Proto *currentContext,struct X3D_Node *node);
987
988
989
990/* textures - we have got a png (jpeg, etc) file with a cubemap in it; eg, see:
991 http://en.wikipedia.org/wiki/Cube_mapping
992*/
993/* images are stored in an image as 3 "rows", 4 "columns", we pick the data out of these columns */
994static int offsets[]={
995 /*y,x, with y-up */
996 1,2, /* right */
997 1,0, /* left */
998 2,1, /* top */
999 0,1, /* bottom */
1000 1,1, /* front */
1001 1,3}; /* back */
1002//if assuming the offsets order represents +x,-x,+y,-y,+z,-z then this is LHS (left handed system)
1003/* or:
1004 ---- Top -- --
1005 Left Front Right Back
1006 ---- Down -- --
1007*/
1008
1009/* fill in the 6 PixelTextures from the data in the texture
1010 this is for when you have a single .png image with 6 sub-patches
1011*/
1012
1013
1014// Textures.c loves to call this one.
1015void unpackImageCubeMap (textureTableIndexStruct_s* me) {
1016 int size;
1017 int count;
1018
1019 struct X3D_ImageCubeMapTexture *node = (struct X3D_ImageCubeMapTexture *)me->scenegraphNode;
1020
1021 if (node == NULL) {
1022 ERROR_MSG("problem unpacking single image ImageCubeMap\n");
1023 return;
1024 }
1025
1026 if (node->_nodeType != NODE_ImageCubeMapTexture) {
1027 ERROR_MSG("internal error - expected ImageCubeMapTexture here");
1028 return;
1029 }
1030
1031 /* expect the cube map to be in a 4:3 ratio */
1032 /* printf ("size %dx%d, data %p\n",me->x, me->y, me->texdata); */
1033 if ((me->x * 3) != (me->y*4)) {
1034 ERROR_MSG ("expect an ImageCubeMap to be in a 4:3 ratio");
1035 return;
1036 }
1037
1038 /* ok, we have, probably, a cube map in the image data. Extract the data and go nuts */
1039 size = me->x / 4;
1040
1041
1042 if (node->__subTextures.n != 6) {
1043 ERROR_MSG("unpackImageCubeMap, there should be 6 PixelTexture nodes here\n");
1044 return;
1045 }
1046 /* go through each face, and send the data to the relevant PixelTexture */
1047 /* order: right left, top, bottom, back, front */
1048 for (count=0; count <6; count++) {
1049 int x,y;
1050 uint32 val;
1051 uint32 *tex = (uint32 *) me->texdata;
1052 struct X3D_PixelTexture *pt = X3D_PIXELTEXTURE(node->__subTextures.p[count]);
1053 int xSubIndex, ySubIndex;
1054 int index;
1055
1056 ySubIndex=offsets[count*2]*size; xSubIndex=offsets[count*2+1]*size;
1057
1058 /* create the MFInt32 array for this face in the PixelTexture */
1059 FREE_IF_NZ(pt->image.arr.p);
1060 pt->image.arr.n = size*size;
1061 pt->image.arr.p = MALLOC(int *, pt->image.arr.n * sizeof (int));
1062 pt->image.whc[0] = size;
1063 pt->image.whc[1] = size;
1064 pt->image.whc[2] = 4; /* this last one is for RGBA nchannels/components = 4 */
1065 index = 0;
1066
1067 for (y=ySubIndex; y<ySubIndex+size; y++) {
1068 for (x=xSubIndex; x<xSubIndex+size; x++) {
1069 int ipix;
1070 unsigned char *rgba;
1071 ipix = y*me->x + x; //pixel in big image
1072 if(0){
1073 /* remember, this will be in ARGB format, make into RGBA */
1074 val = tex[ipix];
1075 pt->image.arr.p[index] = ((val & 0xffffff) << 8) | ((val & 0xff000000) >> 24);
1076 }else{
1077 rgba = (unsigned char *)&tex[ipix];
1078 //convert to host-endian red-high int
1079 pt->image.arr.p[index] = (rgba[0] << 24) + (rgba[1] << 16) + (rgba[2] << 8) + (rgba[3] << 0);
1080 }
1081 /* printf ("was %x, now %x\n",tex[x*me->x+y], pt->image.p[index]); */
1082 index ++;
1083 }
1084
1085 }
1086 }
1087
1088 /* we are now locked-n-loaded */
1089 node->__regenSubTextures = FALSE;
1090
1091 /* get rid of the original texture data now */
1092 FREE_IF_NZ(me->texdata);
1093}
1094
1095// Textures.c references this baby.
1096void unpackImageCubeMap6 (textureTableIndexStruct_s* me) {
1097 //for .DDS and .web3dit that are in cubemap format ie 6 contiguous images in tti->teximage
1098 // incoming order of images: +x,-x,+y,-y,+z,-z (or R,L,F,B,T,D ?) */
1099 //int size;
1100 int count;
1101
1102 struct X3D_ImageCubeMapTexture *node = (struct X3D_ImageCubeMapTexture *)me->scenegraphNode;
1103
1104 if (node == NULL) {
1105 ERROR_MSG("problem unpacking single image ImageCubeMap\n");
1106 return;
1107 }
1108
1109 if (node->_nodeType != NODE_ImageCubeMapTexture) {
1110 ERROR_MSG("internal error - expected ImageCubeMapTexture here");
1111 return;
1112 }
1113
1114
1115 if (node->__subTextures.n != 6) {
1116 ERROR_MSG("unpackImageCubeMap, there should be 6 PixelTexture nodes here\n");
1117 return;
1118 }
1119 /* go through each face, and send the data to the relevant PixelTexture */
1120 /* (jas declared target) order: right left, top, bottom, back, front */
1121 // (dug9 incoming order from dds/.web3dit cubemap texture, RHS: +x,-x,+y,-y,+z,-z
1122 // this should be same as opengl/web3d order
1123 {
1124 uint32 imlookup[] = {0,1,2,3,4,5}; //dug9 lookup order that experimentally seems to work
1125 for (count=0; count <6; count++) {
1126 int i,j; //,k; //x,y,
1127 uint32 ioff; //val,
1128 uint32 *tex;
1129 struct X3D_PixelTexture *pt = X3D_PIXELTEXTURE(node->__subTextures.p[count]);
1130
1131 /* create the MFInt32 array for this face in the PixelTexture */
1132 FREE_IF_NZ(pt->image.arr.p);
1133 pt->image.arr.n = me->x*me->y;
1134 pt->image.arr.p = MALLOC(int *, pt->image.arr.n * sizeof (uint32));
1135 pt->image.whc[0] = me->x;
1136 pt->image.whc[1] = me->y;
1137 pt->image.whc[2] = 4; /* this last one is for RGBA */
1138 ioff = imlookup[count] * me->x * me->y;
1139 //we are in char rgba order, but we need to convert to endian-specific uint32
1140 // which is what texture_load_from_pixelTexture() will be expecting
1141 //in imageIsDDS() image reader, we already flipped from top-down image to bottom-up texture order
1142 // which pixeltexture is expecting
1143 tex = (uint32 *) me->texdata;
1144 tex = &tex[ioff];
1145 for(j=0;j<me->y;j++){
1146 for(i=0;i<me->x;i++){
1147 int ipix; //,jpix;
1148 uint32 pixint;
1149 unsigned char* rgba;
1150
1151 ipix = j*me->x + i; //image row same as image row out
1152 //jpix = (me->y-1 -j)*me->x + i; //flip image vertically - no, pixeltexture is bottom-up like incoming
1153 rgba = (unsigned char*)&tex[ipix];
1154 pixint = (rgba[0] << 24) + (rgba[1] << 16) + (rgba[2] << 8) + rgba[3];
1155 pt->image.arr.p[ipix] = pixint;
1156 }
1157 }
1158 }
1159 }
1160
1161 /* we are now locked-n-loaded */
1162 node->__regenSubTextures = FALSE;
1163
1164 /* get rid of the original texture data now */
1165 FREE_IF_NZ(me->texdata);
1166}
1167
1168enum {
1169 ICM_UNK = -1,
1170 ICM_DDS = 0, //detected by file type
1171 ICM_T = 1, //+- 4x3
1172 ICM_3X2 = 2,
1173 ICM_2X3 = 3,
1174 ICM_6X1 = 4,
1175 ICM_1X6 = 5,
1176 ICM_3X4 = 6, //like ICM_T
1177};
1178int unpackImageCubeMapB(textureTableIndexStruct_s* tti, int pattern, unsigned char** facetextures) {
1179 //offsets x,y,flipx,flipy(0=renderman 1=no renderman flip)
1180 int isize = 0;
1181 int* offs = NULL;
1182 if (pattern == ICM_DDS) {
1183 isize = tti->x;
1184 int oo0[] = { 0,0,0,0, 1,0,0,0, 2,0,0,0, 3,0,0,0, 4,0,0,0, 5,0,0,0 };
1185 offs = oo0;
1186 } else if (pattern == ICM_T) {
1187 //+- format
1188 isize = tti->x / 4;
1189 /*y,x, with y-up */
1190 int oo0[] = {
1191 1, 2, 0,0, /* right */
1192 1, 0, 0,0, /* left */
1193 2, 1, 0,0, /* top */
1194 0, 1, 0,0, /* bottom */
1195 1, 1, 0,0, /* front */
1196 1, 3, 0,0, /* back */
1197 };
1198 offs = oo0; //defined above in y,x,y,x sequence
1199 } else if (pattern == ICM_3X4) {
1200 //+ format
1201 //|
1202 isize = tti->x / 3;
1203 int oo0[] = {
1204 2,2,0,0, /* right */
1205 2,0,0,0, /* left */
1206 3,1,0,0, /* top */
1207 1,1,0,0, /* bottom */
1208 2,1,0,0, /* front */
1209 0,1,1,1, /* back */
1210 };
1211 offs = oo0; //defined above in y,x,y,x sequence
1212 }
1213 else {
1214 //packed
1215 int nx, ny;
1216 //June 2022 - never seen this pattern in practice, but made a few tests for it
1217 // if you have a real case then change the following to work
1218 switch (pattern) {
1219 case ICM_1X6: //nx = 1; ny = 6;
1220 isize = tti->x;
1221 int oo1[] = { 5,0,0,0, 4,0,0,0, 3,0,0,0, 2,0,0,0, 1,0,0,0, 0,0,0,0, };
1222 offs = oo1;
1223 break;
1224 case ICM_6X1: //nx = 6; ny = 1;
1225 isize = tti->y;
1226 int oo2[] = { 0,0,0,0, 0,1,0,0, 0,2,0,0, 0,3,0,0, 0,4,0,0, 0,5,0,0, };
1227 offs = oo2;
1228 break;
1229 case ICM_2X3: //nx = 2; ny = 3;
1230 isize = tti->x/2;
1231 int oo3[] = { 2,0,0,0, 2,1,0,0, 1,0,0,0, 1,1,0,0, 0,0,0,0, 0,1,0,0, };
1232 offs = oo3;
1233 break;
1234 case ICM_3X2: //nx = 3; ny = 2;
1235 isize = tti->x/3;
1236 int oo4[] = { 0,0,0,0, 0,1,0,0, 0,2,0,0, 1,0,0,0, 1,2,0,0, 1,2,0,0, };
1237 offs = oo4;
1238 break;
1239 default: nx = 0; ny = 0; isize = 0;
1240 }
1241
1242 }
1243 if(isize > 0){
1244 /* go through each face, and send the data to the relevant PixelTexture */
1245 /* order: right left, top, bottom, back, front */
1246 for (int iface = 0; iface < 6; iface++) {
1247 int x, y, xx,ix, yy, iy, index;
1248 unsigned char* tex = tti->texdata;
1249 unsigned char rgba[4];
1250 unsigned char c;
1251 int xSubIndex, ySubIndex, iflipx, inoflipy;
1252
1253 int nci = 4; // tti->channels;
1254 int nco = 4;
1255 if (tti->hasAlpha && nci == 3) nci = 4;
1256 ySubIndex = offs[iface * 4] * isize; xSubIndex = offs[iface * 4 + 1] * isize;
1257 iflipx = offs[iface * 4 + 2] * isize; inoflipy = offs[iface * 4 + 3] * isize;
1258
1259 /* create the MFInt32 array for this face in the PixelTexture */
1260 FREE_IF_NZ(facetextures[iface]);
1261 facetextures[iface] = malloc(isize * isize * nco);
1262 index = 0; //byte in face image
1263 for (yy = ySubIndex, iy=0; yy < ySubIndex+isize; yy++,iy++) {
1264 //flip cubemap textures to be y-down following opengl specs table 3-19
1265 //'renderman' convention
1266 y = (ySubIndex + isize - 1) - iy; //flip y for
1267 if (inoflipy) y = yy;
1268 for (xx = xSubIndex,ix=0; xx < xSubIndex + isize; xx++,ix++) {
1269 int ipix, ibyte;
1270 x = xx;
1271 if(iflipx)
1272 x = (xSubIndex + isize - 1) - ix; //flip y for
1273 ipix = y * tti->x + x; //pixel in big image
1274 ibyte = ipix * nci;
1275 memset(rgba, 255, 4);
1276 memcpy(rgba, &tex[ibyte], nci);
1277 memcpy(&facetextures[iface][index], rgba,nco);
1278 index += nco;
1279 }
1280 }
1281 }
1282 }
1283 return isize;
1284
1285}
1286
1287int unpack_image_2D_into_cube_faces(textureTableIndexStruct_s* tti, unsigned char** facetextures) {
1288 int isize = 0;
1289 if (tti->z == 1) {
1290 /* if we have an single 2D image, ImageCubeMap, we have most likely got a png map;
1291 ________
1292 | T | - Top
1293 |L F R B| - Left, Front, Right, Back
1294 |__D____| - Down(bottom)
1295 let the render_ImageCubeMapTexture code unpack the maps from this one png */
1296 /* this is ok - what is happening is that we have one image, that needs to be
1297 split up into each face */
1298 /* this should print if we are actually working ok
1299 if (me->status != TEX_LOADED) {
1300 printf ("have ImageCubeMapTexture, but status != TEX_LOADED\n");
1301 }
1302 */
1303 int pattern = tti->x * 3 == tti->y * 4 ? ICM_T : tti->x * 4 == tti->y * 3 ? ICM_3X4 : tti->x * 3 == tti->y * 2 ? ICM_2X3 : tti->x * 2 == tti->y * 3 ? ICM_3X2 : tti->x * 6 == tti->y ? ICM_1X6 : tti->x == tti->y * 6 ? ICM_6X1 : ICM_UNK;
1304 isize = unpackImageCubeMapB(tti,pattern,facetextures);
1305 }
1306 else if (tti->z == 6) {
1307 //likely a .DDS (MS invention) or web3dit (dug9 invention)
1308 //order of images: +x,-x,+y,-y,+z,-z (or R,L,F,B,T,D)
1309 isize = unpackImageCubeMapB(tti,ICM_DDS,facetextures);
1310 }
1311
1312 return isize;
1313}
1314void compile_ImageCubeMapTexture(struct X3D_ImageCubeMapTexture* node) {
1315
1316 MARK_NODE_COMPILED
1317}
1318
1319void set_debug_quad(int which_debug_shader, int textureID);
1320
1321void render_ImageCubeMapTexture(struct X3D_ImageCubeMapTexture* node) {
1322 COMPILE_IF_REQUIRED
1323 if(node->load)
1324 {
1325 int refresh = FALSE;
1326 //step 1 load the texture as a 2D image texture
1327 //step 2 use size hint from image texture to generate cubemap of approximate same size sides
1328 //step 3 cut chunks out of 2D image texture and paste into cubemap sides
1329 if (node->autoRefresh > 0.0) {
1330 double dtime = TickTime();
1331 double elapsedTime = dtime - node->__lasttime;
1332 double runtime = dtime - BrowserStartTime();
1333 if (elapsedTime > node->autoRefresh && runtime < node->autoRefreshTimeLimit ) {
1334 node->__lasttime = dtime;
1335 refresh = TRUE;
1336 }
1337 }
1338 textureTableIndexStruct_s * tti;
1339 tti = getTableTableFromTextureNode(X3D_NODE(node));
1340 if (refresh) tti->status = TEX_NOTLOADED;
1341 if (tti && tti->status != TEX_LOADED)
1342 {
1343 //step 1 load the texture as a 2D image texture
1344 // a compile once section
1345 if (node->__subTextures.n == 0) {
1346 tti->OpenGLTexture = generate_color_cubemap_gl_texture(0);
1347 node->__subTextures.p = malloc(sizeof(struct X3D_Node*));
1348 node->__subTextures.n = 1;
1349 struct X3D_ImageTexture* tex2d = createNewX3DNode(NODE_ImageTexture);
1350 tex2d->url.p = malloc(sizeof(struct Uni_String*) * node->url.n);
1351 for (int i = 0; i < node->url.n; i++) {
1352 tex2d->url.p[i] = newASCIIString(node->url.p[i]->strptr);
1353 }
1354 tex2d->url.n = node->url.n;
1355 tex2d->_parentResource = node->_parentResource;
1356 tex2d->load = TRUE;
1357 if (node->_executionContext)
1358 add_node_to_broto_context(X3D_PROTO(node->_executionContext), X3D_NODE(tex2d));
1359
1360 textureTableIndexStruct_s* tti2d = getTableTableFromTextureNode(X3D_NODE(tex2d));
1361 tti2d->scenegraphNode = X3D_NODE(tex2d);
1362 tti2d->no_gl = TRUE; //skip move_texture_to_opengl to preserve texdata
1363 node->__subTextures.p[0] = X3D_NODE(tex2d);
1364 node->_ichange = node->_change;
1365 render_node(X3D_NODE(tex2d));
1366 //printf("tti2d->no_gl=%d after first render_node\n", tti2d->no_gl);
1367 }
1368 else {
1369 struct X3D_ImageTexture* tex2d = (struct X3D_ImageTexture*)node->__subTextures.p[0];
1370 textureTableIndexStruct_s* tti2d = getTableTableFromTextureNode(X3D_NODE(tex2d));
1371 if (refresh) tti2d->status = TEX_NOTLOADED;
1372 if (tti2d->status < TEX_NEEDSBINDING) { // TEX_LOADED) {
1373 render_node(X3D_NODE(tex2d));
1374
1375 }
1376 else {
1377 //step 2 use size hint from image texture to generate cubemap of approximate same size sides
1378 //step 3 cut chunks out of 2D image texture and paste into cubemap sides
1379 // weakness: assumes image file has square, equal side sizes
1380 //alternate method not attempted: node.size field, and
1381 // a) render to sides using fbo + ortho, or
1382 // b) use x,y interpolation loops
1383 unsigned char* facetextures[6];
1384 memset(facetextures, 0, 6 * sizeof(unsigned char*));
1385 //pattern = ICM_T, ICM_3X2,or ICM_DDS: detects by file type (DDS) or rectangularity
1386 //width = 3/2 * height? ICM_3X2 : width = 4/3 * height? ICM_T
1387 int isize = unpack_image_2D_into_cube_faces(tti2d,facetextures);
1388 glBindTexture(GL_TEXTURE_CUBE_MAP, tti->OpenGLTexture);
1389 for (int iface = 0; iface < 6; iface++)
1390 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + iface, 0, GL_RGBA, isize, isize, 0, GL_RGBA, GL_UNSIGNED_BYTE, facetextures[iface]);
1391 tti->status = TEX_LOADED;
1392 for (int iface = 0; iface < 6; iface++)
1393 FREE_IF_NZ(facetextures[iface]);
1394 tti->channels = tti2d->channels;
1395 tti->hasAlpha = tti2d->hasAlpha;
1396 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
1397
1398 }
1399 }
1400
1401 }
1402 if (tti && tti->status == TEX_LOADED) {
1403 gglobal()->RenderFuncs.textureStackTop = 1;
1404 gglobal()->RenderFuncs.texturenode = node;
1405 }
1406 else {
1407 gglobal()->RenderFuncs.textureStackTop = 0;
1408 }
1409 if (0) {
1410 set_debug_quad(5, tti->OpenGLTexture);
1411 }
1412
1413 }
1414}
1415
1416/****************************************************************************
1417 *
1418 * GeneratedCubeMapTextures
1419 *
1420 ****************************************************************************/
1421 #include "RenderFuncs.h"
1423 Stack * gencube_stack;
1424}* ppComponent_CubeMapTexturing;
1425
1426static void *Component_CubeMapTexturing_constructor(){
1427 void *v = MALLOCV(sizeof(struct pComponent_CubeMapTexturing));
1428 memset(v,0,sizeof(struct pComponent_CubeMapTexturing));
1429 return v;
1430}
1431
1432// iglobal.c loves to call this one.
1433void Component_CubeMapTexturing_init(struct tComponent_CubeMapTexturing *t){
1434 //public
1435 //private
1436 t->prv = Component_CubeMapTexturing_constructor();
1437 {
1438 ppComponent_CubeMapTexturing p = (ppComponent_CubeMapTexturing)t->prv;
1439 p->gencube_stack = newStack(usehit);
1440 }
1441}
1442
1443// iglobal.c loves to call this one.
1444void Component_CubeMapTexturing_clear(struct tComponent_CubeMapTexturing *t){
1445 //public
1446 //private
1447 {
1448 ppComponent_CubeMapTexturing p = (ppComponent_CubeMapTexturing)t->prv;
1449 deleteVector(usehit,p->gencube_stack);
1450 }
1451}
1452
1453//ppComponent_CubeMapTexturing p = (ppComponent_CubeMapTexturing)gglobal()->Component_CubeMapTexturing.prv;
1454
1455 // uni_string update ["NONE"|"NEXT_FRAME_ONLY"|"ALWAYS"]
1456 // int size
1457
1458void pushnset_framebuffer(int ibuffer);
1459void popnset_framebuffer();
1460
1461#ifdef GL_DEPTH_COMPONENT32
1462#define FW_GL_DEPTH_COMPONENT GL_DEPTH_COMPONENT32
1463#else
1464#define FW_GL_DEPTH_COMPONENT GL_DEPTH_COMPONENT16
1465#endif
1466int haveFrameBufferObject();
1467void printFramebufferStatusIfNotComplete(int status) {
1468 // https://www.khronos.org/opengl/wiki/Framebuffer_Object#Framebuffer_Completeness
1469 // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glCheckFramebufferStatus.xhtml
1470 if (status != GL_FRAMEBUFFER_COMPLETE) {
1471 printf("make_depth_buffer_cube: framebuffer not complete\n");
1472 switch (status) {
1473 case GL_FRAMEBUFFER_UNDEFINED:
1474 printf("GL_FRAMEBUFFER_UNDEFINED\n"); break;
1475 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
1476 printf("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT\n"); break;
1477 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
1478 printf("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT\n"); break;
1479 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
1480 printf("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER\n"); break;
1481 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
1482 printf("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER\n"); break;
1483 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
1484 printf("GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE\n"); break;
1485 case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
1486 printf("GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS\n"); break;
1487 case GL_FRAMEBUFFER_UNSUPPORTED:
1488 printf("GL_FRAMEBUFFER_UNSUPPORTED\n"); break;
1489 default:
1490 printf("unknown GL error %u\n", (unsigned int)status); break;
1491 }
1492 }
1493}
1494// called from the scene traversal, linked in GeneratedCode.c
1495void compile_GeneratedCubeMapTexture (struct X3D_GeneratedCubeMapTexture *node) {
1496
1497 //GL 4+ way
1498 struct textureTableIndexStruct* tti;
1499 tti = getTableIndex(node->__textureTableIndex);
1500 if (tti->OpenGLTexture == 0) {
1501 tti->x = tti->y = node->size;
1502 tti->status = TEX_LOADED;
1503 glGenTextures(1, &tti->OpenGLTexture);
1504 glBindTexture(GL_TEXTURE_CUBE_MAP, tti->OpenGLTexture);
1505 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1506 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1507 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1508 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1509 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
1510 tti->channels = 3; //assumes GL-RGBA
1511 tti->hasAlpha = TRUE; //assumes glClearColor(,,,0.0f) in generate_..()
1512 // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexParameter.xhtml
1513 for (size_t i = 0; i < 6; ++i) {
1514 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, tti->x, tti->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
1515 }
1516 glGenFramebuffers(1, &tti->ifbobuffer);
1517 pushnset_framebuffer(tti->ifbobuffer); //binds framebuffer. we push here, in case higher up we are already rendering the whole scene to an fbo
1518 PRINT_GL_ERROR_IF_ANY("make_depth_buffer_cube 1");
1519 //glDrawBuffer(GL_NONE);
1520 //glReadBuffer(GL_NONE);
1521 glViewport(0, 0, tti->x, tti->y);
1522
1523 //bind one tex now for fun, and to check FBO completeness, but will bind in iteration loop during depth rendering generate_shadowmap_cube
1524 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + 0, tti->OpenGLTexture, 0);
1525 int status = glCheckNamedFramebufferStatus(tti->ifbobuffer, GL_FRAMEBUFFER);
1526 printFramebufferStatusIfNotComplete(status);
1527 popnset_framebuffer(); //tti->ifbobuffer);
1528 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
1529 }
1530
1531
1532
1533 MARK_NODE_COMPILED
1534 //we leave it up to shape nodes to detect if they have generatedcubemaptexture
1535 // and if so not draw themselves on VF_Cube pass
1536}
1537
1538//double *get_view_matrixd();
1539void get_view_matrix(double *savePosOri, double *saveView);
1540void freeASCIIString(struct Uni_String *us);
1541
1542// called from the scene traversal, linked in GeneratedCode.c
1543void render_GeneratedCubeMapTexture (struct X3D_GeneratedCubeMapTexture *node) {
1544 int count, iface;
1545
1546 COMPILE_IF_REQUIRED
1547
1548 if(!strcmp(node->update->strptr,"ALWAYS") || !strcmp(node->update->strptr,"NEXT_FRAME_ONLY")){
1549 ttrenderstate rs;
1550 rs = renderstate();
1551 if(rs->render_geom && !rs->render_cube){
1552 //add (node,modelviewmatrix) for next frame
1553 //programmer: please clear the gencube stack once per frame
1554 int i, isAdded;
1555 usehit uhit;
1556 ppComponent_CubeMapTexturing p = (ppComponent_CubeMapTexturing)gglobal()->Component_CubeMapTexturing.prv;
1557 //check if already added, only add once for simplification
1558 isAdded = FALSE;
1559 for(i=0;i<vectorSize(p->gencube_stack);i++){
1560 uhit = vector_get(usehit,p->gencube_stack,i);
1561 if(uhit.node == X3D_NODE(node)){
1562 isAdded = TRUE;
1563 break;
1564 }
1565 }
1566 if(!isAdded){
1567 double modelviewMatrix[16], mvmInverse[16];
1568 double worldmatrix[16], viewmatrix[16], saveView[16], savePosOri[16]; //bothinverse[16],
1569 usehit uhit;
1570 //GL_GET_MODELVIEWMATRIX
1571 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewMatrix);
1572 get_view_matrix(savePosOri,saveView);
1573 matmultiplyAFFINE(viewmatrix,saveView,savePosOri);
1574 //matinverseAFFINE(bothinverse,viewmatrix);
1575 matinverseAFFINE(mvmInverse,modelviewMatrix);
1576
1577 //matmultiplyAFFINE(worldmatrix,bothinverse,modelviewMatrix);
1578 //matmultiplyAFFINE(worldmatrix,modelviewMatrix,bothinverse);
1579
1580 matmultiplyAFFINE(worldmatrix,viewmatrix,mvmInverse);
1581
1582 //strip viewmatrix - will happen when we invert one of the USEUSE pair, and multiply
1583 uhit.node = X3D_NODE(node);
1584 //memcpy(uhit.mvm,modelviewMatrix,16*sizeof(double)); //deep copy
1585 memcpy(uhit.mvm,worldmatrix,16*sizeof(double)); //deep copy
1586 vector_pushBack(usehit,p->gencube_stack,uhit); //fat elements do another deep copy
1587 if(!strcmp(node->update->strptr,"NEXT_FRAME_ONLY")){
1588 //set back to NONE
1589 freeASCIIString(node->update);
1590 node->update = newASCIIString("NONE");
1591 //not sure why, but I don't seem to need to mark event
1592 //MARK_EVENT (X3D_NODE(node),offsetof (struct X3D_GeneratedCubeMapTexture, update));
1593 //printf("MARK_EVENT\n");
1594 }
1595 }
1596
1597 }
1598 }
1599 //render what we have now
1600 gglobal()->RenderFuncs.textureStackTop = 1;
1601 gglobal()->RenderFuncs.texturenode = node;
1602
1603}
1604
1605//Stack *getGenCubeList(){
1606// ppComponent_CubeMapTexturing p = (ppComponent_CubeMapTexturing)gglobal()->Component_CubeMapTexturing.prv;
1607// return p->gencube_stack;
1608//}
1609
1610
1611//we'll do a different matrix rotation for each face, using sideangle struct:
1612static struct {
1613double angle;
1614double x;
1615double y;
1616double z;
1617} sideangle[6] = {
1618{ 90.0,0.0,1.0,0.0}, //+x
1619{-90.0,0.0,1.0,0.0}, //-x
1620{ 90.0,1.0,0.0,0.0}, //+y weird but works
1621{-90.0,1.0,0.0,0.0}, //-y "
1622{ 0.0,0.0,1.0,0.0}, //+z (lhs)
1623{180.0,0.0,1.0,0.0}, //-z
1624};
1625
1626void saveImage_web3dit(struct textureTableIndexStruct *tti, char *fname);
1627void fw_gluPerspective_2(GLDOUBLE xcenter, GLDOUBLE fovy, GLDOUBLE aspect, GLDOUBLE zNear, GLDOUBLE zFar);
1628void pushnset_viewport(float *vpFraction);
1629void popnset_viewport();
1630void render_bound_background();
1631void lightTable_clear();
1632
1633// called from MainLoop.c
1634#include "../x3d_parser/Bindable.h"
1635
1636void generate_GeneratedCubeMapTextures(){
1637 //call from mainloop once per frame:
1638 //foreach cubemaptexture location in cubgen list
1639 // foreach 6 sides
1640 // set viewpoint pose
1641 // render scene to fbo
1642 // convert fbo to regular cubemap texture
1643 //clear cubegen list
1644 double savebackmat[16];
1645 Stack *gencube_stack;
1646 ttglobal tg = gglobal();
1647 ppComponent_CubeMapTexturing p = (ppComponent_CubeMapTexturing)tg->Component_CubeMapTexturing.prv;
1648 static int iframe = 0;
1649 bindablestack *bstack;
1650 bstack = getActiveBindableStacks(tg);
1651
1652 //set_viewmatrix();
1653 //this function tampers with the normal background matrix, which has already been prepped for the mainloop rendering
1654 //so save it, and restore after gencubemap loop of 6
1655 memcpy(savebackmat,bstack->backgroundmatrix,16*sizeof(double));
1656 iframe++;
1657 gencube_stack = p->gencube_stack;
1658 if(vectorSize(gencube_stack)){
1659 int i, j, n;
1660
1661 n = vectorSize(gencube_stack);
1662 for(i=0;i<n;i++){
1663 usehit uhit;
1664 int isize;
1665 double modelviewmatrix[16];
1666 textureTableIndexStruct_s* tti;
1667 float vp[4] = {0.0f,1.0f,0.0f,1.0f}; //arbitrary
1668 struct X3D_GeneratedCubeMapTexture * node;
1669
1670 uhit = vector_get(usehit,gencube_stack,i);
1671 node = (struct X3D_GeneratedCubeMapTexture*)uhit.node;
1672 memcpy(modelviewmatrix,uhit.mvm,16*sizeof(double));
1673
1674 //compile_generatedcubemap - creates framebufferobject fbo
1675 tti = getTableIndex(node->__textureTableIndex);
1676
1677 isize = tti->x; //set in compile_
1678 pushnset_framebuffer(tti->ifbobuffer); //binds framebuffer. we push here, in case higher up we are already rendering the whole scene to an fbo
1679 pushnset_viewport(vp); //something to push so we can pop-and-set below, so any mainloop GL_BACK viewport is restored
1680 glViewport(0,0,isize,isize); //viewport we want
1681 glEnable(GL_TEXTURE_GEN_S);
1682 glEnable(GL_TEXTURE_GEN_T);
1683 glEnable(GL_TEXTURE_GEN_R);
1684
1685 //create fbo or fbo tiles collection for generatedcubemap
1686 //method: we draw each face to a single framebuffer texture,
1687 for(j=0;j<6;j++){
1688 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, tti->OpenGLTexture, 0);
1689 // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glFramebufferTexture.xhtml
1690
1691 //glClearColor(1.0f,0.0f,0.0f,1.0f); //red, for diagnostics during debugging
1692 glClearColor(1.0f, 0.0f, 0.0f, 0.0f); //transparent, so results can be blended
1693 FW_GL_CLEAR(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1694
1695 //set viewpoint matrix for side
1696 //setup_projection();
1697 FW_GL_MATRIX_MODE(GL_PROJECTION);
1698 FW_GL_LOAD_IDENTITY();
1699 //fw_gluPerspective(90.0, 1.0, .1,10000.0);
1700 fw_gluPerspective_2(0.0,90.0, 1.0, .1,10000.0);
1701
1702 FW_GL_MATRIX_MODE(GL_MODELVIEW);
1703 FW_GL_LOAD_IDENTITY();
1704 fw_glSetDoublev(GL_MODELVIEW_MATRIX, modelviewmatrix);
1705 fw_glRotated(sideangle[j].angle,sideangle[j].x,sideangle[j].y,sideangle[j].z);
1706 fw_glScaled(1.0, -1.0, 1.0);
1707 fw_glGetDoublev(GL_MODELVIEW_MATRIX, bstack->viewmatrix);
1708
1709 lightTable_clear();
1710
1711 render_bound_background();
1712
1713 /* Other lights*/
1714 PRINT_GL_ERROR_IF_ANY("XEvents::render, before render_hier");
1715
1716 render_hier(rootNode(), VF_globalLight );
1717 PRINT_GL_ERROR_IF_ANY("XEvents::render, render_hier(VF_globalLight)");
1718 render_hier(rootNode(), VF_Other );
1719
1720 /* 4. Nodes (not the blended ones)*/
1721 profile_start("hier_geom");
1722 render_hier(rootNode(), VF_Geom | VF_Cube);
1723 profile_end("hier_geom");
1724 PRINT_GL_ERROR_IF_ANY("XEvents::render, render_hier(VF_Geom)");
1725
1726 /* 5. Blended Nodes*/
1727 if (tg->RenderFuncs.have_transparency) {
1728 /* render the blended nodes*/
1729 render_hier(rootNode(), VF_Geom | VF_Blend | VF_Cube);
1730 PRINT_GL_ERROR_IF_ANY("XEvents::render, render_hier(VF_Geom)");
1731 }
1732
1733 }
1734 popnset_viewport();
1735 int status = glCheckNamedFramebufferStatus(tti->ifbobuffer, GL_FRAMEBUFFER);
1736 printFramebufferStatusIfNotComplete(status);
1737 popnset_framebuffer();
1738 if (0) {
1739 set_debug_quad(5, tti->OpenGLTexture);
1740 }
1741 }
1742
1743 //clear cubegen list
1744 gencube_stack->n = 0;
1745 memcpy(bstack->backgroundmatrix,savebackmat,16*sizeof(double));
1746
1747 }
1748}