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