1 /*-----------------------------
2 * stex3d.c GL example of the mesa 3d-texture extention to simulate procedural
3 * texturing, it uses a perlin noise and turbulence functions.
5 * Author: Daniel Barrero
7 * dbarrero@pegasus.uniandes.edu.co
9 * Converted to GLUT by brianp on 1/1/98
10 * Massive clean-up on 2002/10/23 by brianp
13 * cc stex3d.c -o stex3d -lglut -lMesaGLU -lMesaGL -lX11 -lXext -lm
15 *---------------------------- */
22 #include "glut_wrap.h"
26 #define M_PI 3.14159265358979323846
29 #define NOISE_TEXTURE 1
30 #define GRADIENT_TEXTURE 2
35 static int tex_width
=64, tex_height
=64, tex_depth
=64;
36 static float angx
=0, angy
=0, angz
=0;
37 static int texgen
= 2, animate
= 1, smooth
= 1, wireframe
= 0;
38 static int CurTexture
= NOISE_TEXTURE
, CurObject
= TORUS
;
39 static GLenum Filter
= GL_LINEAR
;
46 float theta1
, phi1
, theta2
, phi2
, rings
, sides
;
47 float v0
[03], v1
[3], v2
[3], v3
[3];
48 float t0
[03], t1
[3], t2
[3], t3
[3];
49 float n0
[3], n1
[3], n2
[3], n3
[3];
50 float innerRadius
= 0.25;
51 float outerRadius
= 0.5;
56 scalFac
= 1 / (outerRadius
* 2);
58 glNewList(TORUS
, GL_COMPILE
);
59 for (i
= 0; i
< rings
; i
++) {
60 theta1
= (float) i
*2.0 * M_PI
/ rings
;
61 theta2
= (float) (i
+ 1) * 2.0 * M_PI
/ rings
;
62 for (j
= 0; j
< sides
; j
++) {
63 phi1
= (float) j
*2.0 * M_PI
/ sides
;
64 phi2
= (float) (j
+ 1) * 2.0 * M_PI
/ sides
;
66 v0
[0] = cos(theta1
) * (outerRadius
+ innerRadius
* cos(phi1
));
67 v0
[1] = -sin(theta1
) * (outerRadius
+ innerRadius
* cos(phi1
));
68 v0
[2] = innerRadius
* sin(phi1
);
70 v1
[0] = cos(theta2
) * (outerRadius
+ innerRadius
* cos(phi1
));
71 v1
[1] = -sin(theta2
) * (outerRadius
+ innerRadius
* cos(phi1
));
72 v1
[2] = innerRadius
* sin(phi1
);
73 v2
[0] = cos(theta2
) * (outerRadius
+ innerRadius
* cos(phi2
));
74 v2
[1] = -sin(theta2
) * (outerRadius
+ innerRadius
* cos(phi2
));
75 v2
[2] = innerRadius
* sin(phi2
);
77 v3
[0] = cos(theta1
) * (outerRadius
+ innerRadius
* cos(phi2
));
78 v3
[1] = -sin(theta1
) * (outerRadius
+ innerRadius
* cos(phi2
));
79 v3
[2] = innerRadius
* sin(phi2
);
81 n0
[0] = cos(theta1
) * (cos(phi1
));
82 n0
[1] = -sin(theta1
) * (cos(phi1
));
85 n1
[0] = cos(theta2
) * (cos(phi1
));
86 n1
[1] = -sin(theta2
) * (cos(phi1
));
89 n2
[0] = cos(theta2
) * (cos(phi2
));
90 n2
[1] = -sin(theta2
) * (cos(phi2
));
93 n3
[0] = cos(theta1
) * (cos(phi2
));
94 n3
[1] = -sin(theta1
) * (cos(phi2
));
97 t0
[0] = v0
[0] * scalFac
+ 0.5;
98 t0
[1] = v0
[1] * scalFac
+ 0.5;
99 t0
[2] = v0
[2] * scalFac
+ 0.5;
101 t1
[0] = v1
[0] * scalFac
+ 0.5;
102 t1
[1] = v1
[1] * scalFac
+ 0.5;
103 t1
[2] = v1
[2] * scalFac
+ 0.5;
105 t2
[0] = v2
[0] * scalFac
+ 0.5;
106 t2
[1] = v2
[1] * scalFac
+ 0.5;
107 t2
[2] = v2
[2] * scalFac
+ 0.5;
109 t3
[0] = v3
[0] * scalFac
+ 0.5;
110 t3
[1] = v3
[1] * scalFac
+ 0.5;
111 t3
[2] = v3
[2] * scalFac
+ 0.5;
133 /*--------------------------------------------------------------------
134 noise function over R3 - implemented by a pseudorandom tricubic spline
135 EXCERPTED FROM SIGGRAPH 92, COURSE 23
139 ----------------------------------------------------------------------*/
142 #define DOT(a,b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])
144 static int p
[B
+ B
+ 2];
145 static float g
[B
+ B
+ 2][3];
146 #define setup(i,b0,b1,r0,r1) \
147 t = vec[i] + 10000.; \
148 b0 = ((int)t) & (B-1); \
149 b1 = (b0+1) & (B-1); \
156 int bx0
, bx1
, by0
, by1
, bz0
, bz1
, b00
, b10
, b01
, b11
;
157 float rx0
, rx1
, ry0
, ry1
, rz0
, rz1
, *q
, sx
, sy
, sz
, a
, b
, c
, d
, t
, u
, v
;
160 setup(0, bx0
, bx1
, rx0
, rx1
);
161 setup(1, by0
, by1
, ry0
, ry1
);
162 setup(2, bz0
, bz1
, rz0
, rz1
);
172 #define at(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] )
173 #define surve(t) ( t * t * (3. - 2. * t) )
174 #define lerp(t, a, b) ( a + t * (b - a) )
181 u
= at(rx0
, ry0
, rz0
);
183 v
= at(rx1
, ry0
, rz0
);
187 u
= at(rx0
, ry1
, rz0
);
189 v
= at(rx1
, ry1
, rz0
);
192 c
= lerp(sy
, a
, b
); /* interpolate in y at lo x */
195 u
= at(rx0
, ry0
, rz1
);
197 v
= at(rx1
, ry0
, rz1
);
201 u
= at(rx0
, ry1
, rz1
);
203 v
= at(rx1
, ry1
, rz1
);
206 d
= lerp(sy
, a
, b
); /* interpolate in y at hi x */
208 return 1.5 * lerp(sz
, c
, d
); /* interpolate in z */
218 /* Create an array of random gradient vectors uniformly on the unit sphere */
221 for (i
= 0; i
< B
; i
++) {
222 do { /* Choose uniformly in a cube */
223 for (j
= 0; j
< 3; j
++)
224 v
[j
] = (float) ((rand() % (B
+ B
)) - B
) / B
;
226 } while (s
> 1.0); /* If not in sphere try again */
228 for (j
= 0; j
< 3; j
++) /* Else normalize */
232 /* Create a pseudorandom permutation of [1..B] */
233 for (i
= 0; i
< B
; i
++)
235 for (i
= B
; i
> 0; i
-= 2) {
237 p
[i
] = p
[j
= rand() % B
];
241 /* Extend g and p arrays to allow for faster indexing */
242 for (i
= 0; i
< B
+ 2; i
++) {
244 for (j
= 0; j
< 3; j
++)
245 g
[B
+ i
][j
] = g
[i
][j
];
251 turbulence(float point
[3], float lofreq
, float hifreq
)
255 p
[0] = point
[0] + 123.456;
260 for (freq
= lofreq
; freq
< hifreq
; freq
*= 2.) {
261 t
+= fabs(noise3(p
)) / freq
;
266 return t
- 0.3; /* readjust to make mean value = 0.0 */
271 create3Dtexture(void)
273 unsigned char *voxels
= NULL
;
279 printf("creating 3d textures...\n");
282 malloc((size_t) (4 * tex_width
* tex_height
* tex_depth
));
284 for (i
= 0; i
< tex_width
; i
++) {
286 for (j
= 0; j
< tex_height
; j
++) {
288 for (k
= 0; k
< tex_depth
; k
++) {
290 tmp
= (sin(k
* i
* j
+ turbulence(vec
, 0.01, 1)) + 1) * 127.5;
299 printf("setting up 3d texture...\n");
301 glBindTexture(GL_TEXTURE_3D
, NOISE_TEXTURE
);
302 glTexParameteri(GL_TEXTURE_3D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
303 glTexParameteri(GL_TEXTURE_3D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
304 glTexParameteri(GL_TEXTURE_3D
, GL_TEXTURE_WRAP_R
, GL_REPEAT
);
305 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_DECAL
);
307 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
308 glTexImage3D(GL_TEXTURE_3D
, 0, GL_RGBA
,
309 tex_width
, tex_height
, tex_depth
,
310 0, GL_RGBA
, GL_UNSIGNED_BYTE
, voxels
);
311 if (glGetError() == GL_OUT_OF_MEMORY
)
312 printf("stex3d: Out of memory allocating %d x %d x %d RGBA texture",
313 tex_width
, tex_height
, tex_depth
);
317 printf("finished setting up 3d texture image.\n");
324 printf("\nUsage: stex3d <cmd line options>\n");
325 printf(" cmd line options:\n");
326 printf(" -wxxx Width of the texture (Default=64)\n");
327 printf(" -hxxx Height of the texture (Default=64)\n");
328 printf(" -dxxx Depth of the texture (Default=64)\n");
329 printf(" Keyboard Options:\n");
330 printf(" up/down rotate around X\n");
331 printf(" left/right rotate around Y\n");
332 printf(" z/Z rotate around Z\n");
333 printf(" a toggle animation\n");
334 printf(" s toggle smooth shading\n");
335 printf(" t toggle texgen mode\n");
336 printf(" o toggle object: torus/sphere\n");
337 printf(" i toggle texture image: noise/gradient\n");
338 printf(" f toggle linear/nearest filtering\n");
343 parseCmdLine(int argc
, char **argv
)
347 for (i
= 1; i
< argc
; i
++) {
348 if (strcmp(argv
[i
], "-help") == 0) {
352 else if (strstr(argv
[i
], "-w") != NULL
) {
353 tex_width
= atoi((argv
[i
]) + 2);
355 else if (strstr(argv
[i
], "-h") != NULL
) {
356 tex_height
= atoi((argv
[i
]) + 2);
358 else if (strstr(argv
[i
], "-d") != NULL
) {
359 tex_depth
= atoi((argv
[i
]) + 2);
362 printf("%s (Bad option).\n", argv
[i
]);
367 if (tex_width
== 0 || tex_height
== 0 || tex_depth
== 0) {
368 printf("%s (Bad option).\n", "size parameters can't be 0");
379 static const GLfloat sPlane
[4] = { 0.5, 0, 0, -.5 };
380 static const GLfloat tPlane
[4] = { 0, 0.5, 0, -.5 };
381 static const GLfloat rPlane
[4] = { 0, 0, 0.5, -.5 };
383 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
386 glTexGenfv(GL_S
, GL_EYE_PLANE
, sPlane
);
387 glTexGenfv(GL_T
, GL_EYE_PLANE
, tPlane
);
388 glTexGenfv(GL_R
, GL_EYE_PLANE
, rPlane
);
391 glRotatef(angx
, 1.0, 0.0, 0.0);
392 glRotatef(angy
, 0.0, 1.0, 0.0);
393 glRotatef(angz
, 0.0, 0.0, 1.0);
396 glTexGenfv(GL_S
, GL_EYE_PLANE
, sPlane
);
397 glTexGenfv(GL_T
, GL_EYE_PLANE
, tPlane
);
398 glTexGenfv(GL_R
, GL_EYE_PLANE
, rPlane
);
402 glEnable(GL_TEXTURE_GEN_S
);
403 glEnable(GL_TEXTURE_GEN_T
);
404 glEnable(GL_TEXTURE_GEN_R
);
407 glDisable(GL_TEXTURE_GEN_S
);
408 glDisable(GL_TEXTURE_GEN_T
);
409 glDisable(GL_TEXTURE_GEN_R
);
412 glTexParameteri(GL_TEXTURE_3D
, GL_TEXTURE_MIN_FILTER
, Filter
);
413 glTexParameteri(GL_TEXTURE_3D
, GL_TEXTURE_MAG_FILTER
, Filter
);
415 glCallList(CurObject
);
425 float ar
= (float) w
/ (float) h
;
428 glViewport(0, 0, (GLint
) w
, (GLint
) h
);
429 glMatrixMode(GL_PROJECTION
);
431 glFrustum(-ax
, ax
, -ay
, ay
, 2, 20);
432 /*glOrtho(-2, 2, -2, 2, -10, 10);*/
433 glMatrixMode(GL_MODELVIEW
);
435 glTranslatef(0, 0, -4);
442 float t
= glutGet(GLUT_ELAPSED_TIME
);
451 SpecialKey(int k
, int x
, int y
)
474 KeyHandler(unsigned char key
, int x
, int y
)
476 static const char *mode
[] = {
477 "glTexCoord3f (no texgen)",
478 "texgen fixed to object coords",
479 "texgen fixed to eye coords"
486 case 'Q': /* quit game. */
498 glShadeModel(GL_SMOOTH
);
500 glShadeModel(GL_FLAT
);
506 printf("Texgen: %s\n", mode
[texgen
]);
509 if (CurObject
== TORUS
)
515 if (Filter
== GL_LINEAR
)
521 if (CurTexture
== NOISE_TEXTURE
)
522 CurTexture
= GRADIENT_TEXTURE
;
524 CurTexture
= NOISE_TEXTURE
;
525 glBindTexture(GL_TEXTURE_3D
, CurTexture
);
536 wireframe
= !wireframe
;
538 glPolygonMode(GL_FRONT_AND_BACK
, GL_LINE
);
540 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
550 create3Dgradient(void)
554 unsigned char *voxels
= NULL
;
556 voxels
= (unsigned char *) malloc(4 * tex_width
* tex_height
* tex_depth
);
559 for (i
= 0; i
< tex_depth
; i
++) {
560 for (j
= 0; j
< tex_height
; j
++) {
561 for (k
= 0; k
< tex_width
; k
++) {
562 GLint r
= (255 * i
) / (tex_depth
- 1);
563 GLint g
= (255 * j
) / (tex_height
- 1);
564 GLint b
= (255 * k
) / (tex_width
- 1);
574 glBindTexture(GL_TEXTURE_3D
, GRADIENT_TEXTURE
);
575 glTexParameteri(GL_TEXTURE_3D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
576 glTexParameteri(GL_TEXTURE_3D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
577 glTexParameteri(GL_TEXTURE_3D
, GL_TEXTURE_WRAP_R
, GL_REPEAT
);
578 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_DECAL
);
580 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
581 glTexImage3D(GL_TEXTURE_3D
, 0, GL_RGBA
,
582 tex_width
, tex_height
, tex_depth
,
583 0, GL_RGBA
, GL_UNSIGNED_BYTE
, voxels
);
584 if (glGetError() == GL_OUT_OF_MEMORY
)
585 printf("stex3d: Out of memory allocating %d x %d x %d RGBA texture",
586 tex_width
, tex_height
, tex_depth
);
596 static const GLfloat mat_specular
[] = { 1.0, 1.0, 1.0, 1.0 };
597 static const GLfloat mat_shininess
[] = { 25.0 };
598 static const GLfloat gray
[] = { 0.6, 0.6, 0.6, 0.0 };
599 static const GLfloat white
[] = { 1.0, 1.0, 1.0, 0.0 };
600 static const GLfloat light_position
[] = { 0.0, 1.0, 1.0, 0.0 };
604 /* see if we have OpenGL 1.2 or later, for 3D texturing */
606 const char *version
= (const char *) glGetString(GL_VERSION
);
607 if (strncmp(version
, "1.0", 3) == 0 || strncmp(version
, "1.1", 3) == 0) {
608 printf("Sorry, OpenGL 1.2 or later is required\n");
612 printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER
));
613 glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE
, &max
);
614 printf("GL_MAX_3D_TEXTURE_SIZE: %d\n", max
);
615 printf("Current 3D texture size: %d x %d x %d\n",
616 tex_width
, tex_height
, tex_depth
);
619 glMaterialfv(GL_FRONT
, GL_SPECULAR
, mat_specular
);
620 glMaterialfv(GL_FRONT
, GL_SHININESS
, mat_shininess
);
621 glLightfv(GL_LIGHT1
, GL_POSITION
, light_position
);
622 glLightfv(GL_LIGHT1
, GL_AMBIENT
, gray
);
623 glLightfv(GL_LIGHT1
, GL_DIFFUSE
, white
);
624 glLightfv(GL_LIGHT1
, GL_SPECULAR
, white
);
625 glColorMaterial(GL_FRONT
, GL_DIFFUSE
);
626 glEnable(GL_COLOR_MATERIAL
);
627 glEnable(GL_LIGHTING
);
630 glClearColor(.5, .5, .5, 0);
635 gluQuadricTexture( q
, GL_TRUE
);
636 glNewList(SPHERE
, GL_COMPILE
);
637 gluSphere( q
, 0.95, 30, 15 );
650 glEnable(GL_TEXTURE_3D
);
653 glBlendFunc(GL_SRC_COLOR, GL_SRC_ALPHA);
656 glEnable(GL_DEPTH_TEST
);
658 glColor3f(0.6, 0.7, 0.8);
663 main(int argc
, char **argv
)
665 glutInit(&argc
, argv
);
667 if (parseCmdLine(argc
, argv
) == GL_FALSE
) {
671 glutInitWindowPosition(0, 0);
672 glutInitWindowSize(400, 400);
673 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
675 if (glutCreateWindow("stex3d") <= 0) {
685 glutReshapeFunc(resize
);
686 glutKeyboardFunc(KeyHandler
);
687 glutSpecialFunc(SpecialKey
);
688 glutDisplayFunc(drawScene
);