fbo_firecube.c revision 7ec3b29a
1/* 2 * Draw the "fire" test program on the six faces of a cube using 3 * fbo render-to-texture. 4 * 5 * Much of the code comes from David Bucciarelli's "fire" 6 * test program. The rest basically from Brian Paul's "gearbox" and 7 * fbotexture programs. 8 * 9 * By pressing the 'q' key, you can make the driver choose different 10 * internal texture RGBA formats by giving it different "format" and "type" 11 * arguments to the glTexImage2D function that creates the texture 12 * image being rendered to. If the driver doesn't support a texture image 13 * format as a render target, it will usually fall back to software when 14 * drawing the "fire" image, and frame-rate should drop considerably. 15 * 16 * Performance: 17 * The rendering speed of this program is usually dictated by fill rate 18 * and the fact that software fallbacks for glBitMap makes the driver 19 * operate synchronously. Low-end UMA hardware will probably see around 20 * 35 fps with the help screen disabled and 32bpp window- and user 21 * frame-buffers (2008). 22 * 23 * This program is released under GPL, following the "fire" licensing. 24 * 25 * Authors: 26 * David Bucciarelli ("fire") 27 * Brian Paul ("gearbox", "fbotexture") 28 * Thomas Hellstrom (Putting it together) 29 * 30 */ 31 32#include <math.h> 33#include <stdlib.h> 34#include <stdio.h> 35#include <string.h> 36#include <GL/glew.h> 37#include "glut_wrap.h" 38#include "readtex.h" 39 40 41/* 42 * Format of texture we render to. 43 */ 44 45#define TEXINTFORMAT GL_RGBA 46 47static GLuint texTypes[] = 48 {GL_UNSIGNED_BYTE, 49 GL_UNSIGNED_INT_8_8_8_8_REV, 50 GL_UNSIGNED_SHORT_1_5_5_5_REV, 51 GL_UNSIGNED_SHORT_4_4_4_4_REV, 52 GL_UNSIGNED_INT_8_8_8_8, 53 GL_UNSIGNED_SHORT_5_5_5_1, 54 GL_UNSIGNED_SHORT_4_4_4_4, 55 GL_UNSIGNED_INT_8_8_8_8_REV, 56 GL_UNSIGNED_SHORT_1_5_5_5_REV, 57 GL_UNSIGNED_SHORT_4_4_4_4_REV, 58 GL_UNSIGNED_INT_8_8_8_8, 59 GL_UNSIGNED_SHORT_5_5_5_1, 60 GL_UNSIGNED_SHORT_4_4_4_4, 61 GL_UNSIGNED_SHORT_5_6_5, 62 GL_UNSIGNED_SHORT_5_6_5_REV, 63 GL_UNSIGNED_SHORT_5_6_5, 64 GL_UNSIGNED_SHORT_5_6_5_REV}; 65 66static GLuint texFormats[] = 67 {GL_RGBA, 68 GL_RGBA, 69 GL_RGBA, 70 GL_RGBA, 71 GL_RGBA, 72 GL_RGBA, 73 GL_RGBA, 74 GL_BGRA, 75 GL_BGRA, 76 GL_BGRA, 77 GL_BGRA, 78 GL_BGRA, 79 GL_BGRA, 80 GL_RGB, 81 GL_RGB, 82 GL_BGR, 83 GL_BGR}; 84 85static const char *texNames[] = 86 {"GL_RGBA GL_UNSIGNED_BYTE", 87 "GL_RGBA GL_UNSIGNED_INT_8_8_8_8_REV", 88 "GL_RGBA GL_UNSIGNED_SHORT_1_5_5_5_REV", 89 "GL_RGBA GL_UNSIGNED_SHORT_4_4_4_4_REV", 90 "GL_RGBA GL_UNSIGNED_INT_8_8_8_8", 91 "GL_RGBA GL_UNSIGNED_INT_5_5_5_1", 92 "GL_RGBA GL_UNSIGNED_INT_4_4_4_4", 93 "GL_BGRA GL_UNSIGNED_INT_8_8_8_8_REV", 94 "GL_BGRA GL_UNSIGNED_SHORT_1_5_5_5_REV", 95 "GL_BGRA GL_UNSIGNED_SHORT_4_4_4_4_REV", 96 "GL_BGRA GL_UNSIGNED_INT_8_8_8_8", 97 "GL_BGRA GL_UNSIGNED_INT_5_5_5_1", 98 "GL_BGRA GL_UNSIGNED_INT_4_4_4_4", 99 "GL_RGB GL_UNSIGNED_INT_5_6_5", 100 "GL_RGB GL_UNSIGNED_INT_5_6_5_REV", 101 "GL_BGR GL_UNSIGNED_INT_5_6_5", 102 "GL_BGR GL_UNSIGNED_INT_5_6_5_REV"}; 103 104 105 106 107#ifndef M_PI 108#define M_PI 3.1415926535 109#endif 110 111#define vinit(a,i,j,k) { \ 112 (a)[0]=i; \ 113 (a)[1]=j; \ 114 (a)[2]=k; \ 115 } 116 117#define vinit4(a,i,j,k,w) { \ 118 (a)[0]=i; \ 119 (a)[1]=j; \ 120 (a)[2]=k; \ 121 (a)[3]=w; \ 122 } 123 124 125#define vadds(a,dt,b) { \ 126 (a)[0]+=(dt)*(b)[0]; \ 127 (a)[1]+=(dt)*(b)[1]; \ 128 (a)[2]+=(dt)*(b)[2]; \ 129 } 130 131#define vequ(a,b) { \ 132 (a)[0]=(b)[0]; \ 133 (a)[1]=(b)[1]; \ 134 (a)[2]=(b)[2]; \ 135 } 136 137#define vinter(a,dt,b,c) { \ 138 (a)[0]=(dt)*(b)[0]+(1.0-dt)*(c)[0]; \ 139 (a)[1]=(dt)*(b)[1]+(1.0-dt)*(c)[1]; \ 140 (a)[2]=(dt)*(b)[2]+(1.0-dt)*(c)[2]; \ 141 } 142 143#define clamp(a) ((a) < 0.0 ? 0.0 : ((a) < 1.0 ? (a) : 1.0)) 144 145#define vclamp(v) { \ 146 (v)[0]=clamp((v)[0]); \ 147 (v)[1]=clamp((v)[1]); \ 148 (v)[2]=clamp((v)[2]); \ 149 } 150 151static GLint WinWidth = 800, WinHeight = 800; 152static GLint TexWidth, TexHeight; 153static GLuint TexObj; 154static GLuint MyFB; 155static GLuint DepthRB; 156static GLboolean WireFrame = GL_FALSE; 157static GLboolean Anim = GL_TRUE; 158static GLint texType = 0; 159 160static GLint T0 = 0; 161static GLint Frames = 0; 162static GLint Win = 0; 163 164static GLfloat ViewRotX = 20.0, ViewRotY = 30.0, ViewRotZ = 0.0; 165static GLfloat CubeRot = 0.0; 166 167 168static void 169idle(void); 170 171 172static void 173CheckError(int line) 174{ 175 GLenum err = glGetError(); 176 if (err) { 177 printf("GL Error 0x%x at line %d\n", (int) err, line); 178 exit(1); 179 } 180} 181 182 183static void 184cleanup(void) 185{ 186 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 187 glDeleteFramebuffersEXT(1, &MyFB); 188 glDeleteRenderbuffersEXT(1, &DepthRB); 189 glDeleteTextures(1, &TexObj); 190 glutDestroyWindow(Win); 191} 192 193static GLint NiceFog = 1; 194 195#define DIMP 20.0 196#define DIMTP 16.0 197 198#define RIDCOL 0.4 199 200#define NUMTREE 50 201#define TREEINR 2.5 202#define TREEOUTR 8.0 203 204#define AGRAV -9.8 205 206typedef struct 207{ 208 int age; 209 float p[3][3]; 210 float v[3]; 211 float c[3][4]; 212} 213 part; 214 215static float treepos[NUMTREE][3]; 216 217static float black[3] = { 0.0, 0.0, 0.0 }; 218static float blu[3] = { 1.0, 0.2, 0.0 }; 219static float blu2[3] = { 1.0, 1.0, 0.0 }; 220 221static float fogcolor[4] = { 1.0, 1.0, 1.0, 1.0 }; 222 223static float q[4][3] = { 224 {-DIMP, 0.0, -DIMP}, 225 {DIMP, 0.0, -DIMP}, 226 {DIMP, 0.0, DIMP}, 227 {-DIMP, 0.0, DIMP} 228}; 229 230static float qt[4][2] = { 231 {-DIMTP, -DIMTP}, 232 {DIMTP, -DIMTP}, 233 {DIMTP, DIMTP}, 234 {-DIMTP, DIMTP} 235}; 236 237static int np; 238static float eject_r, dt, maxage, eject_vy, eject_vl; 239static short shadows; 240static float ridtri; 241static int fog = 0; 242static int help = 1; 243 244static part *p; 245 246static GLuint groundid; 247static GLuint treeid; 248 249static float obs[3] = { 2.0, 1.0, 0.0 }; 250static float dir[3]; 251static float v = 0.0; 252static float alpha = -84.0; 253static float beta = 90.0; 254 255static float 256vrnd(void) 257{ 258 return (((float) rand()) / RAND_MAX); 259} 260 261static void 262setnewpart(part * p) 263{ 264 float a, v[3], *c; 265 266 p->age = 0; 267 268 a = vrnd() * 3.14159265359 * 2.0; 269 270 vinit(v, sin(a) * eject_r * vrnd(), 0.15, cos(a) * eject_r * vrnd()); 271 vinit(p->p[0], v[0] + vrnd() * ridtri, v[1] + vrnd() * ridtri, 272 v[2] + vrnd() * ridtri); 273 vinit(p->p[1], v[0] + vrnd() * ridtri, v[1] + vrnd() * ridtri, 274 v[2] + vrnd() * ridtri); 275 vinit(p->p[2], v[0] + vrnd() * ridtri, v[1] + vrnd() * ridtri, 276 v[2] + vrnd() * ridtri); 277 278 vinit(p->v, v[0] * eject_vl / (eject_r / 2), 279 vrnd() * eject_vy + eject_vy / 2, v[2] * eject_vl / (eject_r / 2)); 280 281 c = blu; 282 283 vinit4(p->c[0], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 284 c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 285 c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0); 286 vinit4(p->c[1], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 287 c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 288 c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0); 289 vinit4(p->c[2], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 290 c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 291 c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0); 292} 293 294static void 295setpart(part * p) 296{ 297 float fact; 298 299 if (p->p[0][1] < 0.1) { 300 setnewpart(p); 301 return; 302 } 303 304 p->v[1] += AGRAV * dt; 305 306 vadds(p->p[0], dt, p->v); 307 vadds(p->p[1], dt, p->v); 308 vadds(p->p[2], dt, p->v); 309 310 p->age++; 311 312 if ((p->age) > maxage) { 313 vequ(p->c[0], blu2); 314 vequ(p->c[1], blu2); 315 vequ(p->c[2], blu2); 316 } 317 else { 318 fact = 1.0 / maxage; 319 vadds(p->c[0], fact, blu2); 320 vclamp(p->c[0]); 321 p->c[0][3] = fact * (maxage - p->age); 322 323 vadds(p->c[1], fact, blu2); 324 vclamp(p->c[1]); 325 p->c[1][3] = fact * (maxage - p->age); 326 327 vadds(p->c[2], fact, blu2); 328 vclamp(p->c[2]); 329 p->c[2][3] = fact * (maxage - p->age); 330 } 331} 332 333static void 334drawtree(float x, float y, float z) 335{ 336 glBegin(GL_QUADS); 337 glTexCoord2f(0.0, 0.0); 338 glVertex3f(x - 1.5, y + 0.0, z); 339 340 glTexCoord2f(1.0, 0.0); 341 glVertex3f(x + 1.5, y + 0.0, z); 342 343 glTexCoord2f(1.0, 1.0); 344 glVertex3f(x + 1.5, y + 3.0, z); 345 346 glTexCoord2f(0.0, 1.0); 347 glVertex3f(x - 1.5, y + 3.0, z); 348 349 350 glTexCoord2f(0.0, 0.0); 351 glVertex3f(x, y + 0.0, z - 1.5); 352 353 glTexCoord2f(1.0, 0.0); 354 glVertex3f(x, y + 0.0, z + 1.5); 355 356 glTexCoord2f(1.0, 1.0); 357 glVertex3f(x, y + 3.0, z + 1.5); 358 359 glTexCoord2f(0.0, 1.0); 360 glVertex3f(x, y + 3.0, z - 1.5); 361 362 glEnd(); 363 364} 365 366static void 367calcposobs(void) 368{ 369 dir[0] = sin(alpha * M_PI / 180.0); 370 dir[2] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0); 371 dir[1] = cos(beta * M_PI / 180.0); 372 373 if (dir[0] < 1.0e-5 && dir[0] > -1.0e-5) 374 dir[0] = 0; 375 if (dir[1] < 1.0e-5 && dir[1] > -1.0e-5) 376 dir[1] = 0; 377 if (dir[2] < 1.0e-5 && dir[2] > -1.0e-5) 378 dir[2] = 0; 379 380 obs[0] += v * dir[0]; 381 obs[1] += v * dir[1]; 382 obs[2] += v * dir[2]; 383} 384 385static void 386printstring(void *font, const char *string) 387{ 388 int len, i; 389 390 len = (int) strlen(string); 391 for (i = 0; i < len; i++) 392 glutBitmapCharacter(font, string[i]); 393} 394 395 396static void 397printhelp(void) 398{ 399 glColor4f(0.0, 0.0, 0.0, 0.5); 400 glRecti(40, 40, 600, 440); 401 402 glColor3f(1.0, 0.0, 0.0); 403 glRasterPos2i(300, 420); 404 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Help"); 405 406 glRasterPos2i(60, 390); 407 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "h - Toggle Help"); 408 409 glRasterPos2i(60, 360); 410 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "t - Increase particle size"); 411 glRasterPos2i(60, 330); 412 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "T - Decrease particle size"); 413 414 glRasterPos2i(60, 300); 415 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "r - Increase emission radius"); 416 glRasterPos2i(60, 270); 417 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "R - Decrease emission radius"); 418 419 glRasterPos2i(60, 240); 420 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "f - Toggle Fog"); 421 glRasterPos2i(60, 210); 422 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "s - Toggle shadows"); 423 glRasterPos2i(60, 180); 424 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "q - Toggle texture format & type"); 425 glRasterPos2i(60, 150); 426 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "a - Increase velocity"); 427 glRasterPos2i(60, 120); 428 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "z - Decrease velocity"); 429 glRasterPos2i(60, 90); 430 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Arrow Keys - Rotate"); 431} 432 433 434static void 435drawfire(void) 436{ 437 static char frbuf[80] = ""; 438 int j; 439 static double t0 = -1.; 440 double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; 441 if (t0 < 0.0) 442 t0 = t; 443 dt = (t - t0) * 1.0; 444 t0 = t; 445 446 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB); 447 448 glDisable(GL_LIGHTING); 449 450 glShadeModel(GL_FLAT); 451 452 glEnable(GL_BLEND); 453 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 454 455 glEnable(GL_FOG); 456 glFogi(GL_FOG_MODE, GL_EXP); 457 glFogfv(GL_FOG_COLOR, fogcolor); 458 glFogf(GL_FOG_DENSITY, 0.1); 459 460 461 glViewport(0, 0, (GLint) TexWidth, (GLint) TexHeight); 462 glMatrixMode(GL_PROJECTION); 463 glLoadIdentity(); 464 gluPerspective(70.0, TexWidth/ (float) TexHeight, 0.1, 30.0); 465 466 glMatrixMode(GL_MODELVIEW); 467 glLoadIdentity(); 468 469 if (NiceFog) 470 glHint(GL_FOG_HINT, GL_NICEST); 471 else 472 glHint(GL_FOG_HINT, GL_DONT_CARE); 473 474 glEnable(GL_DEPTH_TEST); 475 476 if (fog) 477 glEnable(GL_FOG); 478 else 479 glDisable(GL_FOG); 480 481 glDepthMask(GL_TRUE); 482 glClearColor(1.0, 1.0, 1.0, 1.0); 483 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 484 485 486 glPushMatrix(); 487 calcposobs(); 488 gluLookAt(obs[0], obs[1], obs[2], 489 obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2], 490 0.0, 1.0, 0.0); 491 492 glColor4f(1.0, 1.0, 1.0, 1.0); 493 494 glEnable(GL_TEXTURE_2D); 495 496 glBindTexture(GL_TEXTURE_2D, groundid); 497 glBegin(GL_QUADS); 498 glTexCoord2fv(qt[0]); 499 glVertex3fv(q[0]); 500 glTexCoord2fv(qt[1]); 501 glVertex3fv(q[1]); 502 glTexCoord2fv(qt[2]); 503 glVertex3fv(q[2]); 504 glTexCoord2fv(qt[3]); 505 glVertex3fv(q[3]); 506 glEnd(); 507 508 glEnable(GL_ALPHA_TEST); 509 glAlphaFunc(GL_GEQUAL, 0.9); 510 511 glBindTexture(GL_TEXTURE_2D, treeid); 512 for (j = 0; j < NUMTREE; j++) 513 drawtree(treepos[j][0], treepos[j][1], treepos[j][2]); 514 515 glDisable(GL_TEXTURE_2D); 516 glDepthMask(GL_FALSE); 517 glDisable(GL_ALPHA_TEST); 518 519 if (shadows) { 520 glBegin(GL_TRIANGLES); 521 for (j = 0; j < np; j++) { 522 glColor4f(black[0], black[1], black[2], p[j].c[0][3]); 523 glVertex3f(p[j].p[0][0], 0.1, p[j].p[0][2]); 524 525 glColor4f(black[0], black[1], black[2], p[j].c[1][3]); 526 glVertex3f(p[j].p[1][0], 0.1, p[j].p[1][2]); 527 528 glColor4f(black[0], black[1], black[2], p[j].c[2][3]); 529 glVertex3f(p[j].p[2][0], 0.1, p[j].p[2][2]); 530 } 531 glEnd(); 532 } 533 534 glBegin(GL_TRIANGLES); 535 for (j = 0; j < np; j++) { 536 glColor4fv(p[j].c[0]); 537 glVertex3fv(p[j].p[0]); 538 539 glColor4fv(p[j].c[1]); 540 glVertex3fv(p[j].p[1]); 541 542 glColor4fv(p[j].c[2]); 543 glVertex3fv(p[j].p[2]); 544 545 setpart(&p[j]); 546 } 547 glEnd(); 548 549 550 glDisable(GL_TEXTURE_2D); 551 glDisable(GL_ALPHA_TEST); 552 glDisable(GL_DEPTH_TEST); 553 glDisable(GL_FOG); 554 555 glMatrixMode(GL_PROJECTION); 556 glLoadIdentity(); 557 glOrtho(-0.5, 639.5, -0.5, 479.5 558 , -1.0, 1.0); 559 glMatrixMode(GL_MODELVIEW); 560 glLoadIdentity(); 561 562 glColor3f(1.0, 0.0, 0.0); 563 glRasterPos2i(10, 10); 564 printstring(GLUT_BITMAP_HELVETICA_18, frbuf); 565 glColor3f(0.0, 0.0, 1.0); 566 glRasterPos2i(10, 450); 567 printstring(GLUT_BITMAP_HELVETICA_18, texNames[texType]); 568 glColor3f(1.0, 0.0, 0.0); 569 glRasterPos2i(10, 470); 570 printstring(GLUT_BITMAP_HELVETICA_10, 571 "Fire V1.5 Written by David Bucciarelli (tech.hmw@plus.it)"); 572 573 if (help) 574 printhelp(); 575 576 glPopMatrix(); 577 glDepthMask(GL_TRUE); 578 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 579 Frames++; 580 581 { 582 GLint t = glutGet(GLUT_ELAPSED_TIME); 583 if (t - T0 >= 2000) { 584 GLfloat seconds = (t - T0) / 1000.0; 585 GLfloat fps = Frames / seconds; 586 sprintf(frbuf, "Frame rate: %f", fps); 587 printf("%s\n", frbuf); 588 fflush(stdout); 589 T0 = t; 590 Frames = 0; 591 } 592 } 593 594} 595 596static void 597regen_texImage(void) 598{ 599 glBindTexture(GL_TEXTURE_2D, TexObj); 600 glTexImage2D(GL_TEXTURE_2D, 0, TEXINTFORMAT, TexWidth, TexHeight, 0, 601 texFormats[texType], texTypes[texType], NULL); 602 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB); 603 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 604 GL_TEXTURE_2D, TexObj, 0); 605 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 606} 607 608static void 609key(unsigned char key, int x, int y) 610{ 611 switch (key) { 612 case 27: 613 cleanup(); 614 exit(0); 615 break; 616 case ' ': 617 Anim = !Anim; 618 glutIdleFunc(Anim ? idle : NULL); 619 break; 620 case 'a': 621 v += 0.0005; 622 break; 623 case 'z': 624 v -= 0.0005; 625 break; 626 case 'h': 627 help = (!help); 628 break; 629 case 'f': 630 fog = (!fog); 631 break; 632 case 's': 633 shadows = !shadows; 634 break; 635 case 'R': 636 eject_r -= 0.03; 637 break; 638 case 'r': 639 eject_r += 0.03; 640 break; 641 case 't': 642 ridtri += 0.005; 643 break; 644 case 'T': 645 ridtri -= 0.005; 646 break; 647 case 'v': 648 ViewRotZ += 5.0; 649 break; 650 case 'V': 651 ViewRotZ -= 5.0; 652 break; 653 case 'w': 654 WireFrame = !WireFrame; 655 break; 656 case 'q': 657 if (++texType > 16) 658 texType = 0; 659 regen_texImage(); 660 break; 661 case 'n': 662 NiceFog = !NiceFog; 663 printf("NiceFog %d\n", NiceFog); 664 break; 665 } 666 glutPostRedisplay(); 667} 668 669static void 670inittextures(void) 671{ 672 GLenum gluerr; 673 GLubyte tex[128][128][4]; 674 675 glGenTextures(1, &groundid); 676 glBindTexture(GL_TEXTURE_2D, groundid); 677 678 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 679 if (!LoadRGBMipmaps(DEMOS_DATA_DIR "s128.rgb", GL_RGB)) { 680 fprintf(stderr, "Error reading a texture.\n"); 681 exit(-1); 682 } 683 684 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 685 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 686 687 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 688 GL_LINEAR_MIPMAP_LINEAR); 689 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 690 691 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); 692 693 glGenTextures(1, &treeid); 694 glBindTexture(GL_TEXTURE_2D, treeid); 695 696 if (1) 697 { 698 int w, h; 699 GLenum format; 700 int x, y; 701 GLubyte *image = LoadRGBImage(DEMOS_DATA_DIR "tree3.rgb", 702 &w, &h, &format); 703 704 if (!image) { 705 fprintf(stderr, "Error reading a texture.\n"); 706 exit(-1); 707 } 708 709 for (y = 0; y < 128; y++) 710 for (x = 0; x < 128; x++) { 711 tex[x][y][0] = image[(y + x * 128) * 3]; 712 tex[x][y][1] = image[(y + x * 128) * 3 + 1]; 713 tex[x][y][2] = image[(y + x * 128) * 3 + 2]; 714 if ((tex[x][y][0] == tex[x][y][1]) && 715 (tex[x][y][1] == tex[x][y][2]) && (tex[x][y][2] == 255)) 716 tex[x][y][3] = 0; 717 else 718 tex[x][y][3] = 255; 719 } 720 721 if ((gluerr = gluBuild2DMipmaps(GL_TEXTURE_2D, 4, 128, 128, GL_RGBA, 722 GL_UNSIGNED_BYTE, (GLvoid *) (tex)))) { 723 fprintf(stderr, "GLULib%s\n", (char *) gluErrorString(gluerr)); 724 exit(-1); 725 } 726 } 727 else { 728 if (!LoadRGBMipmaps(DEMOS_DATA_DIR "tree2.rgba", GL_RGBA)) { 729 fprintf(stderr, "Error reading a texture.\n"); 730 exit(-1); 731 } 732 } 733 734 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 735 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 736 737 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 738 GL_LINEAR_MIPMAP_LINEAR); 739 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 740 741 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 742} 743 744static void 745inittree(void) 746{ 747 int i; 748 float dist; 749 750 for (i = 0; i < NUMTREE; i++) 751 do { 752 treepos[i][0] = vrnd() * TREEOUTR * 2.0 - TREEOUTR; 753 treepos[i][1] = 0.0; 754 treepos[i][2] = vrnd() * TREEOUTR * 2.0 - TREEOUTR; 755 dist = 756 sqrt(treepos[i][0] * treepos[i][0] + 757 treepos[i][2] * treepos[i][2]); 758 } while ((dist < TREEINR) || (dist > TREEOUTR)); 759} 760 761static int 762init_fire(int ac, char *av[]) 763{ 764 int i; 765 766 np = 800; 767 eject_r = -0.65; 768 dt = 0.015; 769 eject_vy = 4; 770 eject_vl = 1; 771 shadows = 1; 772 ridtri = 0.25; 773 774 maxage = 1.0 / dt; 775 776 if (ac == 2) 777 np = atoi(av[1]); 778 779 780 inittextures(); 781 782 p = (part *) malloc(sizeof(part) * np); 783 784 for (i = 0; i < np; i++) 785 setnewpart(&p[i]); 786 787 inittree(); 788 789 return (0); 790} 791 792 793 794 795 796 797static void 798DrawCube(void) 799{ 800 static const GLfloat texcoords[4][2] = { 801 { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 } 802 }; 803 static const GLfloat vertices[4][2] = { 804 { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } 805 }; 806 static const GLfloat xforms[6][4] = { 807 { 0, 0, 1, 0 }, 808 { 90, 0, 1, 0 }, 809 { 180, 0, 1, 0 }, 810 { 270, 0, 1, 0 }, 811 { 90, 1, 0, 0 }, 812 { -90, 1, 0, 0 } 813 }; 814 static const GLfloat mat[4] = { 1.0, 1.0, 0.5, 1.0 }; 815 GLint i, j; 816 817 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat); 818 glEnable(GL_TEXTURE_2D); 819 820 glPushMatrix(); 821 glRotatef(ViewRotX, 1.0, 0.0, 0.0); 822 glRotatef(15, 1, 0, 0); 823 glRotatef(CubeRot, 0, 1, 0); 824 glScalef(4, 4, 4); 825 826 for (i = 0; i < 6; i++) { 827 glPushMatrix(); 828 glRotatef(xforms[i][0], xforms[i][1], xforms[i][2], xforms[i][3]); 829 glTranslatef(0, 0, 1.1); 830 glBegin(GL_POLYGON); 831 glNormal3f(0, 0, 1); 832 for (j = 0; j < 4; j++) { 833 glTexCoord2fv(texcoords[j]); 834 glVertex2fv(vertices[j]); 835 } 836 glEnd(); 837 glPopMatrix(); 838 } 839 glPopMatrix(); 840 841 glDisable(GL_TEXTURE_2D); 842} 843 844 845static void 846draw(void) 847{ 848 float ar; 849 static GLfloat pos[4] = {5.0, 5.0, 10.0, 0.0}; 850 851 drawfire(); 852 853 glLightfv(GL_LIGHT0, GL_POSITION, pos); 854 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, 855 GL_SEPARATE_SPECULAR_COLOR); 856 857 glEnable(GL_LIGHTING); 858 glEnable(GL_LIGHT0); 859 glEnable(GL_DEPTH_TEST); 860 glEnable(GL_NORMALIZE); 861 glDisable(GL_BLEND); 862 glDisable(GL_FOG); 863 864 glMatrixMode(GL_MODELVIEW); 865 glLoadIdentity(); 866 glTranslatef(0.0, 0.0, -40.0); 867 868 glClear(GL_DEPTH_BUFFER_BIT); 869 870 /* draw textured cube */ 871 872 glViewport(0, 0, WinWidth, WinHeight); 873 glClearColor(0.5, 0.5, 0.8, 0.0); 874 glClear(GL_COLOR_BUFFER_BIT); 875 876 ar = (float) (WinWidth) / WinHeight; 877 glMatrixMode(GL_PROJECTION); 878 glLoadIdentity(); 879 glFrustum(-ar, ar, -1.0, 1.0, 5.0, 60.0); 880 glMatrixMode(GL_MODELVIEW); 881 glBindTexture(GL_TEXTURE_2D, TexObj); 882 883 DrawCube(); 884 885 /* finish up */ 886 glutSwapBuffers(); 887} 888 889 890static void 891idle(void) 892{ 893 static double t0 = -1.; 894 double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; 895 if (t0 < 0.0) 896 t0 = t; 897 dt = t - t0; 898 t0 = t; 899 900 CubeRot = fmod(CubeRot + 15.0 * dt, 360.0); /* 15 deg/sec */ 901 902 glutPostRedisplay(); 903} 904 905 906/* change view angle */ 907static void 908special(int k, int x, int y) 909{ 910 (void) x; 911 (void) y; 912 switch (k) { 913 case GLUT_KEY_UP: 914 ViewRotX += 5.0; 915 break; 916 case GLUT_KEY_DOWN: 917 ViewRotX -= 5.0; 918 break; 919 case GLUT_KEY_LEFT: 920 ViewRotY += 5.0; 921 break; 922 case GLUT_KEY_RIGHT: 923 ViewRotY -= 5.0; 924 break; 925 default: 926 return; 927 } 928 glutPostRedisplay(); 929} 930 931 932/* new window size or exposure */ 933static void 934reshape(int width, int height) 935{ 936 WinWidth = width; 937 WinHeight = height; 938} 939 940 941static void 942init_fbotexture(void) 943{ 944 static const GLenum depthFormats[] = { 945 GL_DEPTH_COMPONENT, 946 GL_DEPTH_COMPONENT16, 947 GL_DEPTH_COMPONENT32 948 }; 949 static int numDepthFormats = sizeof(depthFormats) / sizeof(depthFormats[0]); 950 GLint i; 951 GLenum stat; 952 953 /* gen framebuffer id, delete it, do some assertions, just for testing */ 954 glGenFramebuffersEXT(1, &MyFB); 955 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB); 956 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &i); 957 958 /* Make texture object/image */ 959 glGenTextures(1, &TexObj); 960 glBindTexture(GL_TEXTURE_2D, TexObj); 961 /* make one image level. */ 962 glTexImage2D(GL_TEXTURE_2D, 0, TEXINTFORMAT, TexWidth, TexHeight, 0, 963 texFormats[texType], texTypes[texType], NULL); 964 965 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 966 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 967 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 968 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); 969 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); 970 971 CheckError(__LINE__); 972 973 /* Render color to texture */ 974 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 975 GL_TEXTURE_2D, TexObj, 0); 976 CheckError(__LINE__); 977 978 979 /* make depth renderbuffer */ 980 glGenRenderbuffersEXT(1, &DepthRB); 981 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, DepthRB); 982 /* we may have to try several formats */ 983 for (i = 0; i < numDepthFormats; i++) { 984 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, depthFormats[i], 985 TexWidth, TexHeight); 986 CheckError(__LINE__); 987 988 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 989 GL_RENDERBUFFER_EXT, DepthRB); 990 CheckError(__LINE__); 991 stat = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 992 if (stat == GL_FRAMEBUFFER_COMPLETE_EXT) { 993 break; 994 } 995 } 996 997 if (stat != GL_FRAMEBUFFER_COMPLETE_EXT) { 998 fprintf(stderr, "Error: unable to get usable FBO combination!\n"); 999 exit(1); 1000 } 1001 1002 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, 1003 GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i); 1004 CheckError(__LINE__); 1005 printf("Depth renderbuffer size = %d bits\n", i); 1006 1007 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 1008 1009 /* 1010 * Check for completeness. 1011 */ 1012 1013} 1014 1015 1016static void 1017init(int argc, char *argv[]) 1018{ 1019 GLint i; 1020 1021 if (!glutExtensionSupported("GL_EXT_framebuffer_object")) { 1022 fprintf(stderr, "Sorry, GL_EXT_framebuffer_object is required!\n"); 1023 exit(1); 1024 } 1025 1026 TexWidth = 512; 1027 TexHeight = 512; 1028 1029 init_fbotexture(); 1030 init_fire(argc, argv); 1031 1032 1033 for ( i=1; i<argc; i++ ) { 1034 if (strcmp(argv[i], "-info")==0) { 1035 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); 1036 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION)); 1037 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR)); 1038 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS)); 1039 } 1040 } 1041} 1042 1043 1044static void 1045visible(int vis) 1046{ 1047 if (vis == GLUT_VISIBLE) 1048 glutIdleFunc(Anim ? idle : NULL); 1049 else 1050 glutIdleFunc(NULL); 1051} 1052 1053 1054int 1055main(int argc, char *argv[]) 1056{ 1057 glutInitWindowSize(WinWidth, WinHeight); 1058 glutInit(&argc, argv); 1059 1060 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 1061 1062 Win = glutCreateWindow("fbo_firecube"); 1063 glewInit(); 1064 init(argc, argv); 1065 1066 glutDisplayFunc(draw); 1067 glutReshapeFunc(reshape); 1068 glutKeyboardFunc(key); 1069 glutSpecialFunc(special); 1070 glutVisibilityFunc(visible); 1071 1072 glutMainLoop(); 1073 return 0; /* ANSI C requires main to return int. */ 1074} 1075