blob: 56ec49ca62a80263a779a7f4a910dd21f289828e [file] [log] [blame]
Brian Paulfdd631a2002-04-22 16:03:37 +00001/* $Id: stex3d.c,v 1.6 2002/04/22 16:03:37 brianp Exp $ */
jtgafb833d1999-08-19 00:55:39 +00002
3/*-----------------------------
4 * stex3d.c GL example of the mesa 3d-texture extention to simulate procedural
5 * texturing, it uses a perlin noise and turbulence functions.
6 *
7 * Author: Daniel Barrero
8 * barrero@irit.fr
9 * dbarrero@pegasus.uniandes.edu.co
10 *
11 * Converted to GLUT by brianp on 1/1/98
12 *
13 *
14 * cc stex3d.c -o stex3d -lglut -lMesaGLU -lMesaGL -lX11 -lXext -lm
15 *
16 *---------------------------- */
17
jtgafb833d1999-08-19 00:55:39 +000018#include <string.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <math.h>
22#include <GL/gl.h>
23#include <GL/glut.h>
24/* function declarations */
25#ifndef M_PI
26#define M_PI 3.14159265358979323846
27#endif
28
29void init(void),
30 printHelp(void),
31 create3Dtexture(void),
32 setDefaults(void),
33 drawScene(void),
34 resize(int w, int h),
35 buildFigure(void),
36 initNoise(void);
37float turbulence(float point[3], float lofreq, float hifreq);
38
jtgafb833d1999-08-19 00:55:39 +000039void KeyHandler( unsigned char key, int x, int y );
40GLenum parseCmdLine(int argc, char **argv);
41float noise3(float vec[3]);
42
43/* global variables */
44GLenum rgb, doubleBuffer, directRender, windType; /* visualization state*/
45float tex_width,tex_height,tex_depth; /* texture volume dimensions */
46unsigned char *voxels; /* texture data ptr */
47int angx,angy,angz;
48GLuint figure;
49
50/*function definitions */
51int main(int argc, char **argv)
52{
53
54 if (parseCmdLine(argc, argv) == GL_FALSE) {
55 exit(0);
56 }
57
58 glutInitWindowPosition(0, 0);
59 glutInitWindowSize(400, 400);
60 windType = (rgb) ? GLUT_RGB : GLUT_INDEX;
61 windType |= (doubleBuffer) ? GLUT_DOUBLE : GLUT_SINGLE;
62 windType |= GLUT_DEPTH;
63 glutInitDisplayMode(windType);
64
65 if (glutCreateWindow("stex3d") <= 0) {
66 exit(0);
67 }
68 /* init all */
69 init();
70
71 glutReshapeFunc(resize);
72 glutKeyboardFunc(KeyHandler);
73 glutDisplayFunc(drawScene);
74 glutMainLoop();
75 return 0;
76}
77
78void init()
79{
80 /* init light */
81 GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
82 GLfloat mat_shininess[] = { 25.0 };
83 GLfloat gray[] = { 0.6, 0.6, 0.6, 0.0 };
84 GLfloat white[] = { 1.0, 1.0, 1.0, 0.0 };
85 GLfloat light_position[] = { 0.0, 1.0, 1.0, 0.0 };
86
87 glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
88 glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
89 glLightfv(GL_LIGHT1, GL_POSITION, light_position);
90 glLightfv(GL_LIGHT1, GL_AMBIENT, gray);
91 glLightfv(GL_LIGHT1, GL_DIFFUSE, white);
92 glLightfv(GL_LIGHT1, GL_SPECULAR, white);
93 glColorMaterial(GL_FRONT, GL_DIFFUSE);
94 glEnable(GL_COLOR_MATERIAL);
95 glEnable(GL_LIGHTING);
96 glEnable(GL_LIGHT1);
97
98 /* create torus for texturing */
99 figure=glGenLists(1);
100 buildFigure();
101/* tkSolidTorus(figure,0.3,1.2);*/
102
103 /* start the noise function variables */
104 initNoise();
105
Brian Paul49dcae82000-03-22 19:48:57 +0000106 /* see if we have OpenGL 1.2 or later, for 3D texturing */
107 {
108 const char *version = (const char *) glGetString(GL_VERSION);
109 if (strncmp(version, "1.0", 3) == 0 ||
110 strncmp(version, "1.1", 3) == 0) {
111 printf("Sorry, OpenGL 1.2 or later is required\n");
112 exit(1);
113 }
jtgafb833d1999-08-19 00:55:39 +0000114 }
115
116 /* if texture is supported then generate the texture */
117 create3Dtexture();
118
Brian Paul49dcae82000-03-22 19:48:57 +0000119 glEnable(GL_TEXTURE_3D);
jtgafb833d1999-08-19 00:55:39 +0000120 /*
121 glBlendFunc(GL_SRC_COLOR, GL_SRC_ALPHA);
122 glEnable(GL_BLEND);
123 */
124 glEnable(GL_DEPTH_TEST);
125
126 glShadeModel(GL_FLAT);
127 glColor3f(0.6,0.7,0.8);
128}
129
130void buildFigure(void)
131{ GLint i, j;
132 float theta1, phi1, theta2, phi2, rings, sides;
133 float v0[03], v1[3], v2[3], v3[3];
134 float t0[03], t1[3], t2[3], t3[3];
135 float n0[3], n1[3], n2[3], n3[3];
136 float innerRadius=0.4;
137 float outerRadius=0.8;
138 float scalFac;
139
140 rings = 8;
141 sides = 10;
142 scalFac=1/(outerRadius*2);
143
144 glNewList(figure, GL_COMPILE);
145 for (i = 0; i < rings; i++) {
146 theta1 = (float)i * 2.0 * M_PI / rings;
147 theta2 = (float)(i + 1) * 2.0 * M_PI / rings;
148 for (j = 0; j < sides; j++) {
149 phi1 = (float)j * 2.0 * M_PI / sides;
150 phi2 = (float)(j + 1) * 2.0 * M_PI / sides;
151
152 v0[0] = cos(theta1) * (outerRadius + innerRadius * cos(phi1));
153 v0[1] = -sin(theta1) * (outerRadius + innerRadius * cos(phi1));
154 v0[2] = innerRadius * sin(phi1);
155
156 v1[0] = cos(theta2) * (outerRadius + innerRadius * cos(phi1));
157 v1[1] = -sin(theta2) * (outerRadius + innerRadius * cos(phi1));
158 v1[2] = innerRadius * sin(phi1);
159 v2[0] = cos(theta2) * (outerRadius + innerRadius * cos(phi2));
160 v2[1] = -sin(theta2) * (outerRadius + innerRadius * cos(phi2));
161 v2[2] = innerRadius * sin(phi2);
162
163 v3[0] = cos(theta1) * (outerRadius + innerRadius * cos(phi2));
164 v3[1] = -sin(theta1) * (outerRadius + innerRadius * cos(phi2));
165 v3[2] = innerRadius * sin(phi2);
166
167 n0[0] = cos(theta1) * (cos(phi1));
168 n0[1] = -sin(theta1) * (cos(phi1));
169 n0[2] = sin(phi1);
170
171 n1[0] = cos(theta2) * (cos(phi1));
172 n1[1] = -sin(theta2) * (cos(phi1));
173 n1[2] = sin(phi1);
174
175 n2[0] = cos(theta2) * (cos(phi2));
176 n2[1] = -sin(theta2) * (cos(phi2));
177 n2[2] = sin(phi2);
178
179 n3[0] = cos(theta1) * (cos(phi2));
180 n3[1] = -sin(theta1) * (cos(phi2));
181 n3[2] = sin(phi2);
182
183 t0[0] = v0[0]*scalFac + 0.5;
184 t0[1] = v0[1]*scalFac + 0.5;
185 t0[2] = v0[2]*scalFac + 0.5;
186
187 t1[0] = v1[0]*scalFac + 0.5;
188 t1[1] = v1[1]*scalFac + 0.5;
189 t1[2] = v1[2]*scalFac + 0.5;
190
191 t2[0] = v2[0]*scalFac + 0.5;
192 t2[1] = v2[1]*scalFac + 0.5;
193 t2[2] = v2[2]*scalFac + 0.5;
194
195 t3[0] = v3[0]*scalFac + 0.5;
196 t3[1] = v3[1]*scalFac + 0.5;
197 t3[2] = v3[2]*scalFac + 0.5;
198
199 glBegin(GL_POLYGON);
200 glNormal3fv(n3); glTexCoord3fv(t3); glVertex3fv(v3);
201 glNormal3fv(n2); glTexCoord3fv(t2); glVertex3fv(v2);
202 glNormal3fv(n1); glTexCoord3fv(t1); glVertex3fv(v1);
203 glNormal3fv(n0); glTexCoord3fv(t0); glVertex3fv(v0);
204 glEnd();
205 }
206 }
207 glEndList();
208}
209
210void create3Dtexture()
211{
212 int i,j,k;
213 unsigned char *vp;
214 float vec[3];
215 int tmp;
216
217 printf("creating 3d textures...\n");
Brian Paulc02db131999-12-16 08:54:22 +0000218 voxels = (unsigned char *) malloc((size_t)(4*tex_width*tex_height*tex_depth));
jtgafb833d1999-08-19 00:55:39 +0000219 vp=voxels;
220 for (i=0;i<tex_width;i++){
221 vec[0]=i;
222 for (j=0;j<tex_height;j++) {
223 vec[1]=j;
224 for (k=0;k<tex_depth;k++) {
225 vec[2]=k;
226 tmp=(sin(k*i*j+turbulence(vec,0.01,1))+1)*127.5;
227 *vp++=0;
228 *vp++=0;
229 *vp++=tmp;
230 *vp++=tmp+128;
231 }
232 }
233 }
234
235 printf("setting up 3d texture...\n");
236 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
Brian Paul49dcae82000-03-22 19:48:57 +0000237 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
238 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
239 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
240 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
241 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
jtgafb833d1999-08-19 00:55:39 +0000242 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
243
Brian Paul49dcae82000-03-22 19:48:57 +0000244 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA,
245 tex_width, tex_height, tex_depth,
246 0, GL_RGBA, GL_UNSIGNED_BYTE, voxels);
jtgafb833d1999-08-19 00:55:39 +0000247
248 printf("finished setting up 3d texture image...\n");
249}
250
jtgafb833d1999-08-19 00:55:39 +0000251void printHelp()
252{
253 printf("\nUsage: stex3d <cmd line options>\n");
254 printf(" cmd line options:\n");
255 printf(" -help print this help!\n");
256 printf(" -rgb RGBA mode. (Default)\n");
257 printf(" -ci Color index mode.\n");
258 printf(" -sb Single buffer mode. (Default)\n");
259 printf(" -db Double buffer mode. \n");
260 printf(" -dr Direct render mode.\n");
261 printf(" -ir Indirect render mode. (Default)\n");
262 printf(" -wxxx Width of the texture (Default=64)\n");
263 printf(" -hxxx Height of the texture (Default=64)\n");
264 printf(" -dxxx Depth of the texture (Default=64)\n");
265 printf(" Keyboard Options:\n");
266 printf(" 1 Object Texture coordinates (Default)\n");
267 printf(" 2 Eye Texture coordinates \n");
268 printf(" x rotate around x clockwise\n");
269 printf(" X rotate around x counter clockwise\n");
270 printf(" y rotate around y clockwise\n");
271 printf(" Y rotate around y counter clockwise\n");
272 printf(" z rotate around z clockwise\n");
273 printf(" Z rotate around z counter clockwise\n");
274 printf(" t enable 3-D texuring (Default)\n");
275 printf(" T disable 3-D texuring\n");
276 printf(" s smooth shading \n");
277 printf(" S flat shading (Default)\n");
278}
279
280void setDefaults()
281{
282 /* visualization defaults */
283 rgb = GL_TRUE;
284 doubleBuffer = GL_FALSE;
285 directRender = GL_TRUE;
286 angx=130;
287 angy=30;
288 angz=0;
289 /* texture values */
290 tex_width=64;
291 tex_height=64;
292 tex_depth=64;
293}
294
295GLenum parseCmdLine(int argc, char **argv)
296{
297 GLint i;
298
299 setDefaults();
300
301 for (i = 1; i < argc; i++) {
302 if (strcmp(argv[i], "-ci") == 0) {
303 rgb = GL_FALSE;
304 } else if (strcmp(argv[i], "-rgb") == 0) {
305 rgb = GL_TRUE;
306 } else if (strcmp(argv[i], "-sb") == 0) {
307 doubleBuffer = GL_FALSE;
308 } else if (strcmp(argv[i], "-db") == 0) {
309 doubleBuffer = GL_TRUE;
310 } else if (strcmp(argv[i], "-dr") == 0) {
311 directRender = GL_TRUE;
312 } else if (strcmp(argv[i], "-ir") == 0) {
313 directRender = GL_FALSE;
314 } else if (strstr(argv[i], "-w") == 0) {
315 tex_width=atoi((argv[i])+2);
316 } else if (strstr(argv[i], "-h") == 0) {
317 tex_height=atoi((argv[i])+2);
318 } else if (strstr(argv[i], "-d") == 0) {
319 tex_depth=atoi((argv[i])+2);
320 } else if (strcmp(argv[i], "-help") == 0) {
321 printHelp();
322 return GL_FALSE;
323 } else {
324 printf("%s (Bad option).\n", argv[i]);
325 printHelp();
326 return GL_FALSE;
327 }
328 }
329 if(tex_width==0 || tex_height==0 || tex_depth==0) {
330 printf("%s (Bad option).\n", "size parameters can't be 0");
331 printHelp();
332 return GL_FALSE;
333 }
334 return GL_TRUE;
335}
336
337void drawScene()
338{
339 /* clear background, z buffer etc */
340 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
341 glPushMatrix();
342 glRotatef(angx,1.0,0.0,0.0);
343 glRotatef(angy,0.0,1.0,0.0);
344 glRotatef(angz,0.0,0.0,1.0);
345
346 glCallList(figure);
347 glPopMatrix();
348 glFlush();
349 if(doubleBuffer)
350 glutSwapBuffers();
351 ;
352}
353
354void resize(int w, int h)
355{
356 glViewport(0, 0, (GLint)w, (GLint)h);
357 glMatrixMode(GL_PROJECTION);
358 glLoadIdentity();
359 glOrtho(-2,2,-2,2,-5,10);
360 glMatrixMode(GL_MODELVIEW);
361 glLoadIdentity();
362 glTranslatef(0,0,-5);
363}
364
Brian Paul02e8a032000-06-27 17:04:43 +0000365static void cleanEverything(void)
jtgafb833d1999-08-19 00:55:39 +0000366{
367/* free(voxels); */
368}
369
370
371void KeyHandler( unsigned char key, int x, int y )
372{
Brian Paulecaf1a01999-09-17 12:27:01 +0000373 (void) x;
374 (void) y;
jtgafb833d1999-08-19 00:55:39 +0000375 switch(key) {
376 case 27:
377 case 'q':
378 case 'Q': /* quit game. */
379 cleanEverything();
380 exit(0);
381 break;
382 case 'x':
383 angx+=10;
384 break;
385 case 'X':
386 angx-=10;
387 break;
388 case 'y':
389 angy+=10;
390 break;
391 case 'Y':
392 angy-=10;
393 break;
394 case 'z':
395 angz+=10;
396 break;
397 case 'Z':
398 angz-=10;
399 break;
400 case 't':
Brian Paul49dcae82000-03-22 19:48:57 +0000401 glEnable(GL_TEXTURE_3D);
jtgafb833d1999-08-19 00:55:39 +0000402 break;
403 case 'T':
Brian Paul49dcae82000-03-22 19:48:57 +0000404 glDisable(GL_TEXTURE_3D);
jtgafb833d1999-08-19 00:55:39 +0000405 break;
406 case 's':
407 glShadeModel(GL_SMOOTH);
408 break;
409 case 'S':
410 glShadeModel(GL_FLAT);
411 break;
412 case '1':
413 glDisable(GL_TEXTURE_GEN_S);
414 glDisable(GL_TEXTURE_GEN_T);
415 glDisable(GL_TEXTURE_GEN_R);
416 break;
417 case '2':
418 glEnable(GL_TEXTURE_GEN_S);
419 glEnable(GL_TEXTURE_GEN_T);
420 glEnable(GL_TEXTURE_GEN_R);
421 break;
422 default:
423 break;
424 }
425 glutPostRedisplay();
426}
427
428/*--------------------------------------------------------------------
429 noise function over R3 - implemented by a pseudorandom tricubic spline
430 EXCERPTED FROM SIGGRAPH 92, COURSE 23
431 PROCEDURAL MODELING
432 Ken Perlin
433 New York University
434----------------------------------------------------------------------*/
435
436
437#define DOT(a,b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])
438#define B 256
439static int p[B + B + 2];
440static float g[B + B + 2][3];
441#define setup(i,b0,b1,r0,r1) \
442 t = vec[i] + 10000.; \
443 b0 = ((int)t) & (B-1); \
444 b1 = (b0+1) & (B-1); \
445 r0 = t - (int)t; \
446 r1 = r0 - 1.;
447
448float noise3(float vec[3])
449{
450 int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
451 float rx0, rx1, ry0, ry1, rz0, rz1, *q, sx, sy, sz, a, b, c, d, t, u, v;
452 register int i, j;
453
454 setup(0, bx0,bx1, rx0,rx1);
455 setup(1, by0,by1, ry0,ry1);
456 setup(2, bz0,bz1, rz0,rz1);
457
458 i = p[ bx0 ];
459 j = p[ bx1 ];
460
461 b00 = p[ i + by0 ];
462 b10 = p[ j + by0 ];
463 b01 = p[ i + by1 ];
464 b11 = p[ j + by1 ];
465
466#define at(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] )
467#define surve(t) ( t * t * (3. - 2. * t) )
468#define lerp(t, a, b) ( a + t * (b - a) )
469
470 sx = surve(rx0);
471 sy = surve(ry0);
472 sz = surve(rz0);
473
474 q = g[ b00 + bz0 ] ; u = at(rx0,ry0,rz0);
475 q = g[ b10 + bz0 ] ; v = at(rx1,ry0,rz0);
476 a = lerp(sx, u, v);
477
478 q = g[ b01 + bz0 ] ; u = at(rx0,ry1,rz0);
479 q = g[ b11 + bz0 ] ; v = at(rx1,ry1,rz0);
480 b = lerp(sx, u, v);
481
482 c = lerp(sy, a, b); /* interpolate in y at lo x */
483
484 q = g[ b00 + bz1 ] ; u = at(rx0,ry0,rz1);
485 q = g[ b10 + bz1 ] ; v = at(rx1,ry0,rz1);
486 a = lerp(sx, u, v);
487
488 q = g[ b01 + bz1 ] ; u = at(rx0,ry1,rz1);
489 q = g[ b11 + bz1 ] ; v = at(rx1,ry1,rz1);
490 b = lerp(sx, u, v);
491
492 d = lerp(sy, a, b); /* interpolate in y at hi x */
493
494 return 1.5 * lerp(sz, c, d); /* interpolate in z */
495}
496
497void initNoise()
498{
499 /*long random();*/
500 int i, j, k;
501 float v[3], s;
502
503/* Create an array of random gradient vectors uniformly on the unit sphere */
504 /*srandom(1);*/
505 srand(1);
506 for (i = 0 ; i < B ; i++) {
507 do { /* Choose uniformly in a cube */ for (j=0 ; j<3 ; j++)
508 v[j] = (float)((rand() % (B + B)) - B) / B;
509 s = DOT(v,v);
510 } while (s > 1.0); /* If not in sphere try again */ s = sqrt(s);
511 for (j = 0 ; j < 3 ; j++) /* Else normalize */
512 g[i][j] = v[j] / s;
513 }
514
515/* Create a pseudorandom permutation of [1..B] */
516 for (i = 0 ; i < B ; i++)
517 p[i] = i;
518 for (i = B ; i > 0 ; i -= 2) {
519 k = p[i];
520 p[i] = p[j = rand() % B];
521 p[j] = k;
522 }
523
524/* Extend g and p arrays to allow for faster indexing */
525 for (i = 0 ; i < B + 2 ; i++) {
526 p[B + i] = p[i];
527 for (j = 0 ; j < 3 ; j++)
528 g[B + i][j] = g[i][j];
529 }
530}
531
532float turbulence(float point[3], float lofreq, float hifreq)
533{
534 float freq, t, p[3];
535
536 p[0] = point[0] + 123.456;
537 p[1] = point[1];
538 p[2] = point[2];
539
540 t = 0;
541 for (freq = lofreq ; freq < hifreq ; freq *= 2.) {
542 t += fabs(noise3(p)) / freq;
543 p[0] *= 2.;
544 p[1] *= 2.;
545 p[2] *= 2.;
546 }
547 return t - 0.3; /* readjust to make mean value = 0.0 */
548}
549