Merge commit 'origin/gallium-master-merge'
[mesa.git] / progs / demos / fbo_firecube.c
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 <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
47 static 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
66 static 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
85 static 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
151 static GLint WinWidth = 800, WinHeight = 800;
152 static GLint TexWidth, TexHeight;
153 static GLuint TexObj;
154 static GLuint MyFB;
155 static GLuint DepthRB;
156 static GLboolean WireFrame = GL_FALSE;
157 static GLboolean Anim = GL_TRUE;
158 static GLint texType = 0;
159
160 static GLint T0 = 0;
161 static GLint Frames = 0;
162 static GLint Win = 0;
163
164 static GLfloat ViewRotX = 20.0, ViewRotY = 30.0, ViewRotZ = 0.0;
165 static GLfloat CubeRot = 0.0;
166
167
168 static void
169 idle(void);
170
171
172 static void
173 CheckError(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
183 static void
184 cleanup(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
193 static 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
206 typedef struct
207 {
208 int age;
209 float p[3][3];
210 float v[3];
211 float c[3][4];
212 }
213 part;
214
215 static float treepos[NUMTREE][3];
216
217 static float black[3] = { 0.0, 0.0, 0.0 };
218 static float blu[3] = { 1.0, 0.2, 0.0 };
219 static float blu2[3] = { 1.0, 1.0, 0.0 };
220
221 static float fogcolor[4] = { 1.0, 1.0, 1.0, 1.0 };
222
223 static 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
230 static float qt[4][2] = {
231 {-DIMTP, -DIMTP},
232 {DIMTP, -DIMTP},
233 {DIMTP, DIMTP},
234 {-DIMTP, DIMTP}
235 };
236
237 static int np;
238 static float eject_r, dt, maxage, eject_vy, eject_vl;
239 static short shadows;
240 static float ridtri;
241 static int fog = 0;
242 static int help = 1;
243
244 static part *p;
245
246 static GLuint groundid;
247 static GLuint treeid;
248
249 static float obs[3] = { 2.0, 1.0, 0.0 };
250 static float dir[3];
251 static float v = 0.0;
252 static float alpha = -84.0;
253 static float beta = 90.0;
254
255 static float
256 vrnd(void)
257 {
258 return (((float) rand()) / RAND_MAX);
259 }
260
261 static void
262 setnewpart(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
294 static void
295 setpart(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
333 static void
334 drawtree(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
366 static void
367 calcposobs(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
385 static void
386 printstring(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
396 static void
397 printhelp(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
434 static void
435 drawfire(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 T0 = t;
588 Frames = 0;
589 }
590 }
591
592 }
593
594 static void
595 regen_texImage(void)
596 {
597 glBindTexture(GL_TEXTURE_2D, TexObj);
598 glTexImage2D(GL_TEXTURE_2D, 0, TEXINTFORMAT, TexWidth, TexHeight, 0,
599 texFormats[texType], texTypes[texType], NULL);
600 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB);
601 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
602 GL_TEXTURE_2D, TexObj, 0);
603 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
604 }
605
606 static void
607 key(unsigned char key, int x, int y)
608 {
609 switch (key) {
610 case 27:
611 cleanup();
612 exit(0);
613 break;
614 case ' ':
615 Anim = !Anim;
616 glutIdleFunc(Anim ? idle : NULL);
617 break;
618 case 'a':
619 v += 0.0005;
620 break;
621 case 'z':
622 v -= 0.0005;
623 break;
624 case 'h':
625 help = (!help);
626 break;
627 case 'f':
628 fog = (!fog);
629 break;
630 case 's':
631 shadows = !shadows;
632 break;
633 case 'R':
634 eject_r -= 0.03;
635 break;
636 case 'r':
637 eject_r += 0.03;
638 break;
639 case 't':
640 ridtri += 0.005;
641 break;
642 case 'T':
643 ridtri -= 0.005;
644 break;
645 case 'v':
646 ViewRotZ += 5.0;
647 break;
648 case 'V':
649 ViewRotZ -= 5.0;
650 break;
651 case 'w':
652 WireFrame = !WireFrame;
653 break;
654 case 'q':
655 if (++texType > 16)
656 texType = 0;
657 regen_texImage();
658 break;
659 case 'n':
660 NiceFog = !NiceFog;
661 printf("NiceFog %d\n", NiceFog);
662 break;
663 }
664 glutPostRedisplay();
665 }
666
667 static void
668 inittextures(void)
669 {
670 GLenum gluerr;
671 GLubyte tex[128][128][4];
672
673 glGenTextures(1, &groundid);
674 glBindTexture(GL_TEXTURE_2D, groundid);
675
676 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
677 if (!LoadRGBMipmaps("../images/s128.rgb", GL_RGB)) {
678 fprintf(stderr, "Error reading a texture.\n");
679 exit(-1);
680 }
681
682 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
683 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
684
685 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
686 GL_LINEAR_MIPMAP_LINEAR);
687 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
688
689 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
690
691 glGenTextures(1, &treeid);
692 glBindTexture(GL_TEXTURE_2D, treeid);
693
694 if (1)
695 {
696 int w, h;
697 GLenum format;
698 int x, y;
699 GLubyte *image = LoadRGBImage("../images/tree3.rgb", &w, &h, &format);
700
701 if (!image) {
702 fprintf(stderr, "Error reading a texture.\n");
703 exit(-1);
704 }
705
706 for (y = 0; y < 128; y++)
707 for (x = 0; x < 128; x++) {
708 tex[x][y][0] = image[(y + x * 128) * 3];
709 tex[x][y][1] = image[(y + x * 128) * 3 + 1];
710 tex[x][y][2] = image[(y + x * 128) * 3 + 2];
711 if ((tex[x][y][0] == tex[x][y][1]) &&
712 (tex[x][y][1] == tex[x][y][2]) && (tex[x][y][2] == 255))
713 tex[x][y][3] = 0;
714 else
715 tex[x][y][3] = 255;
716 }
717
718 if ((gluerr = gluBuild2DMipmaps(GL_TEXTURE_2D, 4, 128, 128, GL_RGBA,
719 GL_UNSIGNED_BYTE, (GLvoid *) (tex)))) {
720 fprintf(stderr, "GLULib%s\n", (char *) gluErrorString(gluerr));
721 exit(-1);
722 }
723 }
724 else {
725 if (!LoadRGBMipmaps("../images/tree2.rgba", GL_RGBA)) {
726 fprintf(stderr, "Error reading a texture.\n");
727 exit(-1);
728 }
729 }
730
731 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
732 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
733
734 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
735 GL_LINEAR_MIPMAP_LINEAR);
736 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
737
738 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
739 }
740
741 static void
742 inittree(void)
743 {
744 int i;
745 float dist;
746
747 for (i = 0; i < NUMTREE; i++)
748 do {
749 treepos[i][0] = vrnd() * TREEOUTR * 2.0 - TREEOUTR;
750 treepos[i][1] = 0.0;
751 treepos[i][2] = vrnd() * TREEOUTR * 2.0 - TREEOUTR;
752 dist =
753 sqrt(treepos[i][0] * treepos[i][0] +
754 treepos[i][2] * treepos[i][2]);
755 } while ((dist < TREEINR) || (dist > TREEOUTR));
756 }
757
758 static int
759 init_fire(int ac, char *av[])
760 {
761 int i;
762
763 np = 800;
764 eject_r = -0.65;
765 dt = 0.015;
766 eject_vy = 4;
767 eject_vl = 1;
768 shadows = 1;
769 ridtri = 0.25;
770
771 maxage = 1.0 / dt;
772
773 if (ac == 2)
774 np = atoi(av[1]);
775
776
777 inittextures();
778
779 p = (part *) malloc(sizeof(part) * np);
780
781 for (i = 0; i < np; i++)
782 setnewpart(&p[i]);
783
784 inittree();
785
786 return (0);
787 }
788
789
790
791
792
793
794 static void
795 DrawCube(void)
796 {
797 static const GLfloat texcoords[4][2] = {
798 { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 }
799 };
800 static const GLfloat vertices[4][2] = {
801 { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 }
802 };
803 static const GLfloat xforms[6][4] = {
804 { 0, 0, 1, 0 },
805 { 90, 0, 1, 0 },
806 { 180, 0, 1, 0 },
807 { 270, 0, 1, 0 },
808 { 90, 1, 0, 0 },
809 { -90, 1, 0, 0 }
810 };
811 static const GLfloat mat[4] = { 1.0, 1.0, 0.5, 1.0 };
812 GLint i, j;
813
814 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat);
815 glEnable(GL_TEXTURE_2D);
816
817 glPushMatrix();
818 glRotatef(ViewRotX, 1.0, 0.0, 0.0);
819 glRotatef(15, 1, 0, 0);
820 glRotatef(CubeRot, 0, 1, 0);
821 glScalef(4, 4, 4);
822
823 for (i = 0; i < 6; i++) {
824 glPushMatrix();
825 glRotatef(xforms[i][0], xforms[i][1], xforms[i][2], xforms[i][3]);
826 glTranslatef(0, 0, 1.1);
827 glBegin(GL_POLYGON);
828 glNormal3f(0, 0, 1);
829 for (j = 0; j < 4; j++) {
830 glTexCoord2fv(texcoords[j]);
831 glVertex2fv(vertices[j]);
832 }
833 glEnd();
834 glPopMatrix();
835 }
836 glPopMatrix();
837
838 glDisable(GL_TEXTURE_2D);
839 }
840
841
842 static void
843 draw(void)
844 {
845 float ar;
846 static GLfloat pos[4] = {5.0, 5.0, 10.0, 0.0};
847
848 drawfire();
849
850 glLightfv(GL_LIGHT0, GL_POSITION, pos);
851 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,
852 GL_SEPARATE_SPECULAR_COLOR);
853
854 glEnable(GL_LIGHTING);
855 glEnable(GL_LIGHT0);
856 glEnable(GL_DEPTH_TEST);
857 glEnable(GL_NORMALIZE);
858 glDisable(GL_BLEND);
859 glDisable(GL_FOG);
860
861 glMatrixMode(GL_MODELVIEW);
862 glLoadIdentity();
863 glTranslatef(0.0, 0.0, -40.0);
864
865 glClear(GL_DEPTH_BUFFER_BIT);
866
867 /* draw textured cube */
868
869 glViewport(0, 0, WinWidth, WinHeight);
870 glClearColor(0.5, 0.5, 0.8, 0.0);
871 glClear(GL_COLOR_BUFFER_BIT);
872
873 ar = (float) (WinWidth) / WinHeight;
874 glMatrixMode(GL_PROJECTION);
875 glLoadIdentity();
876 glFrustum(-ar, ar, -1.0, 1.0, 5.0, 60.0);
877 glMatrixMode(GL_MODELVIEW);
878 glBindTexture(GL_TEXTURE_2D, TexObj);
879
880 DrawCube();
881
882 /* finish up */
883 glutSwapBuffers();
884 }
885
886
887 static void
888 idle(void)
889 {
890 static double t0 = -1.;
891 double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
892 if (t0 < 0.0)
893 t0 = t;
894 dt = t - t0;
895 t0 = t;
896
897 CubeRot = fmod(CubeRot + 15.0 * dt, 360.0); /* 15 deg/sec */
898
899 glutPostRedisplay();
900 }
901
902
903 /* change view angle */
904 static void
905 special(int k, int x, int y)
906 {
907 (void) x;
908 (void) y;
909 switch (k) {
910 case GLUT_KEY_UP:
911 ViewRotX += 5.0;
912 break;
913 case GLUT_KEY_DOWN:
914 ViewRotX -= 5.0;
915 break;
916 case GLUT_KEY_LEFT:
917 ViewRotY += 5.0;
918 break;
919 case GLUT_KEY_RIGHT:
920 ViewRotY -= 5.0;
921 break;
922 default:
923 return;
924 }
925 glutPostRedisplay();
926 }
927
928
929 /* new window size or exposure */
930 static void
931 reshape(int width, int height)
932 {
933 WinWidth = width;
934 WinHeight = height;
935 }
936
937
938 static void
939 init_fbotexture()
940 {
941 GLint i;
942
943 /* gen framebuffer id, delete it, do some assertions, just for testing */
944 glGenFramebuffersEXT(1, &MyFB);
945 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB);
946 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &i);
947
948 /* Make texture object/image */
949 glGenTextures(1, &TexObj);
950 glBindTexture(GL_TEXTURE_2D, TexObj);
951 /* make one image level. */
952 glTexImage2D(GL_TEXTURE_2D, 0, TEXINTFORMAT, TexWidth, TexHeight, 0,
953 texFormats[texType], texTypes[texType], NULL);
954
955 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
956 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
957 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
958 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
959 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
960
961 CheckError(__LINE__);
962
963 /* Render color to texture */
964 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
965 GL_TEXTURE_2D, TexObj, 0);
966 CheckError(__LINE__);
967
968
969 /* make depth renderbuffer */
970 glGenRenderbuffersEXT(1, &DepthRB);
971 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, DepthRB);
972 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16,
973 TexWidth, TexHeight);
974 CheckError(__LINE__);
975 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT,
976 GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
977 CheckError(__LINE__);
978 printf("Depth renderbuffer size = %d bits\n", i);
979
980 /* attach DepthRB to MyFB */
981 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
982 GL_RENDERBUFFER_EXT, DepthRB);
983 CheckError(__LINE__);
984 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
985
986 /*
987 * Check for completeness.
988 */
989
990 }
991
992
993 static void
994 init(int argc, char *argv[])
995 {
996 GLint i;
997
998 if (!glutExtensionSupported("GL_EXT_framebuffer_object")) {
999 fprintf(stderr, "Sorry, GL_EXT_framebuffer_object is required!\n");
1000 exit(1);
1001 }
1002
1003 TexWidth = 512;
1004 TexHeight = 512;
1005
1006 init_fbotexture();
1007 init_fire(argc, argv);
1008
1009
1010 for ( i=1; i<argc; i++ ) {
1011 if (strcmp(argv[i], "-info")==0) {
1012 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
1013 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
1014 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
1015 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
1016 }
1017 }
1018 }
1019
1020
1021 static void
1022 visible(int vis)
1023 {
1024 if (vis == GLUT_VISIBLE)
1025 glutIdleFunc(Anim ? idle : NULL);
1026 else
1027 glutIdleFunc(NULL);
1028 }
1029
1030
1031 int
1032 main(int argc, char *argv[])
1033 {
1034 glutInit(&argc, argv);
1035
1036 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
1037
1038 glutInitWindowSize(WinWidth, WinHeight);
1039 Win = glutCreateWindow("fbo_firecube");
1040 glewInit();
1041 init(argc, argv);
1042
1043 glutDisplayFunc(draw);
1044 glutReshapeFunc(reshape);
1045 glutKeyboardFunc(key);
1046 glutSpecialFunc(special);
1047 glutVisibilityFunc(visible);
1048
1049 glutMainLoop();
1050 return 0; /* ANSI C requires main to return int. */
1051 }