stex3d.c revision 32001f49
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. 4 * 5 * Author: Daniel Barrero 6 * barrero@irit.fr 7 * dbarrero@pegasus.uniandes.edu.co 8 * 9 * Converted to GLUT by brianp on 1/1/98 10 * Massive clean-up on 2002/10/23 by brianp 11 * 12 * 13 * cc stex3d.c -o stex3d -lglut -lMesaGLU -lMesaGL -lX11 -lXext -lm 14 * 15 *---------------------------- */ 16 17#include <string.h> 18#include <stdio.h> 19#include <stdlib.h> 20#include <math.h> 21#include <GL/glew.h> 22#include "glut_wrap.h" 23 24 25#ifndef M_PI 26#define M_PI 3.14159265358979323846 27#endif 28 29#define NOISE_TEXTURE 1 30#define GRADIENT_TEXTURE 2 31 32#define TORUS 1 33#define SPHERE 2 34 35static int tex_width=64, tex_height=64, tex_depth=64; 36static float angx=0, angy=0, angz=0; 37static int texgen = 2, animate = 1, smooth = 1, wireframe = 0; 38static int CurTexture = NOISE_TEXTURE, CurObject = TORUS; 39static GLenum Filter = GL_LINEAR; 40 41 42static void 43BuildTorus(void) 44{ 45 GLint i, j; 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; 52 float scalFac; 53 54 rings = 16; 55 sides = 12; 56 scalFac = 1 / (outerRadius * 2); 57 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; 65 66 v0[0] = cos(theta1) * (outerRadius + innerRadius * cos(phi1)); 67 v0[1] = -sin(theta1) * (outerRadius + innerRadius * cos(phi1)); 68 v0[2] = innerRadius * sin(phi1); 69 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); 76 77 v3[0] = cos(theta1) * (outerRadius + innerRadius * cos(phi2)); 78 v3[1] = -sin(theta1) * (outerRadius + innerRadius * cos(phi2)); 79 v3[2] = innerRadius * sin(phi2); 80 81 n0[0] = cos(theta1) * (cos(phi1)); 82 n0[1] = -sin(theta1) * (cos(phi1)); 83 n0[2] = sin(phi1); 84 85 n1[0] = cos(theta2) * (cos(phi1)); 86 n1[1] = -sin(theta2) * (cos(phi1)); 87 n1[2] = sin(phi1); 88 89 n2[0] = cos(theta2) * (cos(phi2)); 90 n2[1] = -sin(theta2) * (cos(phi2)); 91 n2[2] = sin(phi2); 92 93 n3[0] = cos(theta1) * (cos(phi2)); 94 n3[1] = -sin(theta1) * (cos(phi2)); 95 n3[2] = sin(phi2); 96 97 t0[0] = v0[0] * scalFac + 0.5; 98 t0[1] = v0[1] * scalFac + 0.5; 99 t0[2] = v0[2] * scalFac + 0.5; 100 101 t1[0] = v1[0] * scalFac + 0.5; 102 t1[1] = v1[1] * scalFac + 0.5; 103 t1[2] = v1[2] * scalFac + 0.5; 104 105 t2[0] = v2[0] * scalFac + 0.5; 106 t2[1] = v2[1] * scalFac + 0.5; 107 t2[2] = v2[2] * scalFac + 0.5; 108 109 t3[0] = v3[0] * scalFac + 0.5; 110 t3[1] = v3[1] * scalFac + 0.5; 111 t3[2] = v3[2] * scalFac + 0.5; 112 113 glBegin(GL_POLYGON); 114 glNormal3fv(n3); 115 glTexCoord3fv(t3); 116 glVertex3fv(v3); 117 glNormal3fv(n2); 118 glTexCoord3fv(t2); 119 glVertex3fv(v2); 120 glNormal3fv(n1); 121 glTexCoord3fv(t1); 122 glVertex3fv(v1); 123 glNormal3fv(n0); 124 glTexCoord3fv(t0); 125 glVertex3fv(v0); 126 glEnd(); 127 } 128 } 129 glEndList(); 130} 131 132 133/*-------------------------------------------------------------------- 134 noise function over R3 - implemented by a pseudorandom tricubic spline 135 EXCERPTED FROM SIGGRAPH 92, COURSE 23 136 PROCEDURAL MODELING 137 Ken Perlin 138 New York University 139----------------------------------------------------------------------*/ 140 141 142#define DOT(a,b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]) 143#define B 128 144static int p[B + B + 2]; 145static 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); \ 150 r0 = t - (int)t; \ 151 r1 = r0 - 1.; 152 153static float 154noise3(float vec[3]) 155{ 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; 158 register int i, j; 159 160 setup(0, bx0, bx1, rx0, rx1); 161 setup(1, by0, by1, ry0, ry1); 162 setup(2, bz0, bz1, rz0, rz1); 163 164 i = p[bx0]; 165 j = p[bx1]; 166 167 b00 = p[i + by0]; 168 b10 = p[j + by0]; 169 b01 = p[i + by1]; 170 b11 = p[j + by1]; 171 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) ) 175 176 sx = surve(rx0); 177 sy = surve(ry0); 178 sz = surve(rz0); 179 180 q = g[b00 + bz0]; 181 u = at(rx0, ry0, rz0); 182 q = g[b10 + bz0]; 183 v = at(rx1, ry0, rz0); 184 a = lerp(sx, u, v); 185 186 q = g[b01 + bz0]; 187 u = at(rx0, ry1, rz0); 188 q = g[b11 + bz0]; 189 v = at(rx1, ry1, rz0); 190 b = lerp(sx, u, v); 191 192 c = lerp(sy, a, b); /* interpolate in y at lo x */ 193 194 q = g[b00 + bz1]; 195 u = at(rx0, ry0, rz1); 196 q = g[b10 + bz1]; 197 v = at(rx1, ry0, rz1); 198 a = lerp(sx, u, v); 199 200 q = g[b01 + bz1]; 201 u = at(rx0, ry1, rz1); 202 q = g[b11 + bz1]; 203 v = at(rx1, ry1, rz1); 204 b = lerp(sx, u, v); 205 206 d = lerp(sy, a, b); /* interpolate in y at hi x */ 207 208 return 1.5 * lerp(sz, c, d); /* interpolate in z */ 209} 210 211static void 212initNoise(void) 213{ 214 /*long random(); */ 215 int i, j, k; 216 float v[3], s; 217 218 /* Create an array of random gradient vectors uniformly on the unit sphere */ 219 /*srandom(1); */ 220 srand(1); 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; 225 s = DOT(v, v); 226 } while (s > 1.0); /* If not in sphere try again */ 227 s = sqrt(s); 228 for (j = 0; j < 3; j++) /* Else normalize */ 229 g[i][j] = v[j] / s; 230 } 231 232 /* Create a pseudorandom permutation of [1..B] */ 233 for (i = 0; i < B; i++) 234 p[i] = i; 235 for (i = B; i > 0; i -= 2) { 236 k = p[i]; 237 p[i] = p[j = rand() % B]; 238 p[j] = k; 239 } 240 241 /* Extend g and p arrays to allow for faster indexing */ 242 for (i = 0; i < B + 2; i++) { 243 p[B + i] = p[i]; 244 for (j = 0; j < 3; j++) 245 g[B + i][j] = g[i][j]; 246 } 247} 248 249 250static float 251turbulence(float point[3], float lofreq, float hifreq) 252{ 253 float freq, t, p[3]; 254 255 p[0] = point[0] + 123.456; 256 p[1] = point[1]; 257 p[2] = point[2]; 258 259 t = 0; 260 for (freq = lofreq; freq < hifreq; freq *= 2.) { 261 t += fabs(noise3(p)) / freq; 262 p[0] *= 2.; 263 p[1] *= 2.; 264 p[2] *= 2.; 265 } 266 return t - 0.3; /* readjust to make mean value = 0.0 */ 267} 268 269 270static void 271create3Dtexture(void) 272{ 273 unsigned char *voxels = NULL; 274 int i, j, k; 275 unsigned char *vp; 276 float vec[3]; 277 int tmp; 278 279 printf("creating 3d textures...\n"); 280 voxels = 281 (unsigned char *) 282 malloc((size_t) (4 * tex_width * tex_height * tex_depth)); 283 vp = voxels; 284 for (i = 0; i < tex_width; i++) { 285 vec[0] = i; 286 for (j = 0; j < tex_height; j++) { 287 vec[1] = j; 288 for (k = 0; k < tex_depth; k++) { 289 vec[2] = k; 290 tmp = (sin(k * i * j + turbulence(vec, 0.01, 1)) + 1) * 127.5; 291 *vp++ = 0; 292 *vp++ = 0; 293 *vp++ = tmp; 294 *vp++ = tmp + 128; 295 } 296 } 297 } 298 299 printf("setting up 3d texture...\n"); 300 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); 306 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); 314 315 free(voxels); 316 317 printf("finished setting up 3d texture image.\n"); 318} 319 320 321static void 322printHelp(void) 323{ 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"); 339} 340 341 342static GLenum 343parseCmdLine(int argc, char **argv) 344{ 345 GLint i; 346 347 for (i = 1; i < argc; i++) { 348 if (strcmp(argv[i], "-help") == 0) { 349 printHelp(); 350 return GL_FALSE; 351 } 352 else if (strstr(argv[i], "-w") != NULL) { 353 tex_width = atoi((argv[i]) + 2); 354 } 355 else if (strstr(argv[i], "-h") != NULL) { 356 tex_height = atoi((argv[i]) + 2); 357 } 358 else if (strstr(argv[i], "-d") != NULL) { 359 tex_depth = atoi((argv[i]) + 2); 360 } 361 else { 362 printf("%s (Bad option).\n", argv[i]); 363 printHelp(); 364 return GL_FALSE; 365 } 366 } 367 if (tex_width == 0 || tex_height == 0 || tex_depth == 0) { 368 printf("%s (Bad option).\n", "size parameters can't be 0"); 369 printHelp(); 370 return GL_FALSE; 371 } 372 return GL_TRUE; 373} 374 375 376static void 377drawScene(void) 378{ 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 }; 382 383 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 384 glPushMatrix(); 385 if (texgen == 2) { 386 glTexGenfv(GL_S, GL_EYE_PLANE, sPlane); 387 glTexGenfv(GL_T, GL_EYE_PLANE, tPlane); 388 glTexGenfv(GL_R, GL_EYE_PLANE, rPlane); 389 } 390 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); 394 395 if (texgen == 1) { 396 glTexGenfv(GL_S, GL_EYE_PLANE, sPlane); 397 glTexGenfv(GL_T, GL_EYE_PLANE, tPlane); 398 glTexGenfv(GL_R, GL_EYE_PLANE, rPlane); 399 } 400 401 if (texgen) { 402 glEnable(GL_TEXTURE_GEN_S); 403 glEnable(GL_TEXTURE_GEN_T); 404 glEnable(GL_TEXTURE_GEN_R); 405 } 406 else { 407 glDisable(GL_TEXTURE_GEN_S); 408 glDisable(GL_TEXTURE_GEN_T); 409 glDisable(GL_TEXTURE_GEN_R); 410 } 411 412 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, Filter); 413 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, Filter); 414 415 glCallList(CurObject); 416 glPopMatrix(); 417 418 glutSwapBuffers(); 419} 420 421 422static void 423resize(int w, int h) 424{ 425 float ar = (float) w / (float) h; 426 float ax = 0.6 * ar; 427 float ay = 0.6; 428 glViewport(0, 0, (GLint) w, (GLint) h); 429 glMatrixMode(GL_PROJECTION); 430 glLoadIdentity(); 431 glFrustum(-ax, ax, -ay, ay, 2, 20); 432 /*glOrtho(-2, 2, -2, 2, -10, 10);*/ 433 glMatrixMode(GL_MODELVIEW); 434 glLoadIdentity(); 435 glTranslatef(0, 0, -4); 436} 437 438 439static void 440Idle(void) 441{ 442 float t = glutGet(GLUT_ELAPSED_TIME); 443 angx = 0.01 * t; 444 angy = 0.03 * t; 445 angz += 0; 446 glutPostRedisplay(); 447} 448 449 450static void 451SpecialKey(int k, int x, int y) 452{ 453 switch (k) { 454 case GLUT_KEY_UP: 455 angx += 5.0; 456 break; 457 case GLUT_KEY_DOWN: 458 angx -= 5.0; 459 break; 460 case GLUT_KEY_LEFT: 461 angy += 5.0; 462 break; 463 case GLUT_KEY_RIGHT: 464 angy -= 5.0; 465 break; 466 default: 467 return; 468 } 469 glutPostRedisplay(); 470} 471 472 473static void 474KeyHandler(unsigned char key, int x, int y) 475{ 476 static const char *mode[] = { 477 "glTexCoord3f (no texgen)", 478 "texgen fixed to object coords", 479 "texgen fixed to eye coords" 480 }; 481 (void) x; 482 (void) y; 483 switch (key) { 484 case 27: 485 case 'q': 486 case 'Q': /* quit game. */ 487 exit(0); 488 break; 489 case 'z': 490 angz += 10; 491 break; 492 case 'Z': 493 angz -= 10; 494 break; 495 case 's': 496 smooth = !smooth; 497 if (smooth) 498 glShadeModel(GL_SMOOTH); 499 else 500 glShadeModel(GL_FLAT); 501 break; 502 case 't': 503 texgen++; 504 if (texgen > 2) 505 texgen = 0; 506 printf("Texgen: %s\n", mode[texgen]); 507 break; 508 case 'o': 509 if (CurObject == TORUS) 510 CurObject = SPHERE; 511 else 512 CurObject = TORUS; 513 break; 514 case 'f': 515 if (Filter == GL_LINEAR) 516 Filter = GL_NEAREST; 517 else 518 Filter = GL_LINEAR; 519 break; 520 case 'i': 521 if (CurTexture == NOISE_TEXTURE) 522 CurTexture = GRADIENT_TEXTURE; 523 else 524 CurTexture = NOISE_TEXTURE; 525 glBindTexture(GL_TEXTURE_3D, CurTexture); 526 break; 527 case 'a': 528 case ' ': 529 animate = !animate; 530 if (animate) 531 glutIdleFunc(Idle); 532 else 533 glutIdleFunc(NULL); 534 break; 535 case 'w': 536 wireframe = !wireframe; 537 if (wireframe) 538 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 539 else 540 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 541 break; 542 default: 543 break; 544 } 545 glutPostRedisplay(); 546} 547 548 549static void 550create3Dgradient(void) 551{ 552 unsigned char *v; 553 int i, j, k; 554 unsigned char *voxels = NULL; 555 556 voxels = (unsigned char *) malloc(4 * tex_width * tex_height * tex_depth); 557 v = voxels; 558 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); 565 *v++ = r; 566 *v++ = g; 567 *v++ = b; 568 *v++ = 255; 569 } 570 } 571 } 572 573 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); 579 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); 587 588 free(voxels); 589} 590 591 592 593static void 594init(void) 595{ 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 }; 601 602 int max; 603 604 /* see if we have OpenGL 1.2 or later, for 3D texturing */ 605 { 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"); 609 exit(1); 610 } 611 } 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); 617 618 /* init light */ 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); 628 glEnable(GL_LIGHT1); 629 630 glClearColor(.5, .5, .5, 0); 631 632 { 633 GLUquadricObj *q; 634 q = gluNewQuadric(); 635 gluQuadricTexture( q, GL_TRUE ); 636 glNewList(SPHERE, GL_COMPILE); 637 gluSphere( q, 0.95, 30, 15 ); 638 glEndList(); 639 gluDeleteQuadric(q); 640 } 641 642 BuildTorus(); 643 644 645 create3Dgradient(); 646 647 initNoise(); 648 create3Dtexture(); 649 650 glEnable(GL_TEXTURE_3D); 651 652 /* 653 glBlendFunc(GL_SRC_COLOR, GL_SRC_ALPHA); 654 glEnable(GL_BLEND); 655 */ 656 glEnable(GL_DEPTH_TEST); 657 658 glColor3f(0.6, 0.7, 0.8); 659} 660 661 662int 663main(int argc, char **argv) 664{ 665 glutInit(&argc, argv); 666 667 if (parseCmdLine(argc, argv) == GL_FALSE) { 668 exit(0); 669 } 670 671 glutInitWindowPosition(0, 0); 672 glutInitWindowSize(400, 400); 673 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); 674 675 if (glutCreateWindow("stex3d") <= 0) { 676 exit(0); 677 } 678 679 glewInit(); 680 681 init(); 682 683 printHelp(); 684 685 glutReshapeFunc(resize); 686 glutKeyboardFunc(KeyHandler); 687 glutSpecialFunc(SpecialKey); 688 glutDisplayFunc(drawScene); 689 if (animate) 690 glutIdleFunc(Idle); 691 glutMainLoop(); 692 return 0; 693} 694 695