1/* 2 * This program is under the GNU GPL. 3 * Use at your own risk. 4 * 5 * written by David Bucciarelli (tech.hmw@plus.it) 6 * Humanware s.r.l. 7 */ 8 9#include <assert.h> 10#include <stdio.h> 11#include <stdlib.h> 12#include <math.h> 13#include <time.h> 14#include <string.h> 15 16#ifdef WIN32 17#include <windows.h> 18#include <mmsystem.h> 19#endif 20 21#include "glut_wrap.h" 22#include "readtex.h" 23 24#ifdef XMESA 25#include "GL/xmesa.h" 26static int fullscreen = 1; 27#endif 28 29#ifndef M_PI 30#define M_PI 3.1415926535 31#endif 32 33#define vinit(a,i,j,k) {\ 34 (a)[0]=i;\ 35 (a)[1]=j;\ 36 (a)[2]=k;\ 37} 38 39#define vinit4(a,i,j,k,w) {\ 40 (a)[0]=i;\ 41 (a)[1]=j;\ 42 (a)[2]=k;\ 43 (a)[3]=w;\ 44} 45 46 47#define vadds(a,dt,b) {\ 48 (a)[0]+=(dt)*(b)[0];\ 49 (a)[1]+=(dt)*(b)[1];\ 50 (a)[2]+=(dt)*(b)[2];\ 51} 52 53#define vequ(a,b) {\ 54 (a)[0]=(b)[0];\ 55 (a)[1]=(b)[1];\ 56 (a)[2]=(b)[2];\ 57} 58 59#define vinter(a,dt,b,c) {\ 60 (a)[0]=(dt)*(b)[0]+(1.0-dt)*(c)[0];\ 61 (a)[1]=(dt)*(b)[1]+(1.0-dt)*(c)[1];\ 62 (a)[2]=(dt)*(b)[2]+(1.0-dt)*(c)[2];\ 63} 64 65#define clamp(a) ((a) < 0.0 ? 0.0 : ((a) < 1.0 ? (a) : 1.0)) 66 67#define vclamp(v) {\ 68 (v)[0]=clamp((v)[0]);\ 69 (v)[1]=clamp((v)[1]);\ 70 (v)[2]=clamp((v)[2]);\ 71} 72 73static int WIDTH = 640; 74static int HEIGHT = 480; 75 76static GLint T0 = 0; 77static GLint Frames = 0; 78static GLint NiceFog = 1; 79 80#define DIMP 20.0 81#define DIMTP 16.0 82 83#define RIDCOL 0.4 84 85#define NUMTREE 50 86#define TREEINR 2.5 87#define TREEOUTR 8.0 88 89#define AGRAV -9.8 90 91typedef struct 92{ 93 int age; 94 float p[3][3]; 95 float v[3]; 96 float c[3][4]; 97} 98part; 99 100static float treepos[NUMTREE][3]; 101 102static float black[3] = { 0.0, 0.0, 0.0 }; 103static float blu[3] = { 1.0, 0.2, 0.0 }; 104static float blu2[3] = { 1.0, 1.0, 0.0 }; 105 106static float fogcolor[4] = { 1.0, 1.0, 1.0, 1.0 }; 107 108static float q[4][3] = { 109 {-DIMP, 0.0, -DIMP}, 110 {DIMP, 0.0, -DIMP}, 111 {DIMP, 0.0, DIMP}, 112 {-DIMP, 0.0, DIMP} 113}; 114 115static float qt[4][2] = { 116 {-DIMTP, -DIMTP}, 117 {DIMTP, -DIMTP}, 118 {DIMTP, DIMTP}, 119 {-DIMTP, DIMTP} 120}; 121 122static int win = 0; 123 124static int np; 125static float eject_r, dt, maxage, eject_vy, eject_vl; 126static short shadows; 127static float ridtri; 128static int fog = 1; 129static int help = 1; 130static int joyavailable = 0; 131static int joyactive = 0; 132 133static part *p; 134 135static GLuint groundid; 136static GLuint treeid; 137 138static float obs[3] = { 2.0, 1.0, 0.0 }; 139static float dir[3]; 140static float v = 0.0; 141static float alpha = -84.0; 142static float beta = 90.0; 143 144static float 145vrnd(void) 146{ 147 return (((float) rand()) / RAND_MAX); 148} 149 150static void 151setnewpart(part * p) 152{ 153 float a, v[3], *c; 154 155 p->age = 0; 156 157 a = vrnd() * 3.14159265359 * 2.0; 158 159 vinit(v, sin(a) * eject_r * vrnd(), 0.15, cos(a) * eject_r * vrnd()); 160 vinit(p->p[0], v[0] + vrnd() * ridtri, v[1] + vrnd() * ridtri, 161 v[2] + vrnd() * ridtri); 162 vinit(p->p[1], v[0] + vrnd() * ridtri, v[1] + vrnd() * ridtri, 163 v[2] + vrnd() * ridtri); 164 vinit(p->p[2], v[0] + vrnd() * ridtri, v[1] + vrnd() * ridtri, 165 v[2] + vrnd() * ridtri); 166 167 vinit(p->v, v[0] * eject_vl / (eject_r / 2), 168 vrnd() * eject_vy + eject_vy / 2, v[2] * eject_vl / (eject_r / 2)); 169 170 c = blu; 171 172 vinit4(p->c[0], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 173 c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 174 c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0); 175 vinit4(p->c[1], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 176 c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 177 c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0); 178 vinit4(p->c[2], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 179 c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 180 c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0); 181} 182 183static void 184setpart(part * p) 185{ 186 float fact; 187 188 if (p->p[0][1] < 0.1) { 189 setnewpart(p); 190 return; 191 } 192 193 p->v[1] += AGRAV * dt; 194 195 vadds(p->p[0], dt, p->v); 196 vadds(p->p[1], dt, p->v); 197 vadds(p->p[2], dt, p->v); 198 199 p->age++; 200 201 if ((p->age) > maxage) { 202 vequ(p->c[0], blu2); 203 vequ(p->c[1], blu2); 204 vequ(p->c[2], blu2); 205 } 206 else { 207 fact = 1.0 / maxage; 208 vadds(p->c[0], fact, blu2); 209 vclamp(p->c[0]); 210 p->c[0][3] = fact * (maxage - p->age); 211 212 vadds(p->c[1], fact, blu2); 213 vclamp(p->c[1]); 214 p->c[1][3] = fact * (maxage - p->age); 215 216 vadds(p->c[2], fact, blu2); 217 vclamp(p->c[2]); 218 p->c[2][3] = fact * (maxage - p->age); 219 } 220} 221 222static void 223drawtree(float x, float y, float z) 224{ 225 glBegin(GL_QUADS); 226 glTexCoord2f(0.0, 0.0); 227 glVertex3f(x - 1.5, y + 0.0, z); 228 229 glTexCoord2f(1.0, 0.0); 230 glVertex3f(x + 1.5, y + 0.0, z); 231 232 glTexCoord2f(1.0, 1.0); 233 glVertex3f(x + 1.5, y + 3.0, z); 234 235 glTexCoord2f(0.0, 1.0); 236 glVertex3f(x - 1.5, y + 3.0, z); 237 238 239 glTexCoord2f(0.0, 0.0); 240 glVertex3f(x, y + 0.0, z - 1.5); 241 242 glTexCoord2f(1.0, 0.0); 243 glVertex3f(x, y + 0.0, z + 1.5); 244 245 glTexCoord2f(1.0, 1.0); 246 glVertex3f(x, y + 3.0, z + 1.5); 247 248 glTexCoord2f(0.0, 1.0); 249 glVertex3f(x, y + 3.0, z - 1.5); 250 251 glEnd(); 252 253} 254 255static void 256calcposobs(void) 257{ 258 dir[0] = sin(alpha * M_PI / 180.0); 259 dir[2] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0); 260 dir[1] = cos(beta * M_PI / 180.0); 261 262 if (dir[0] < 1.0e-5 && dir[0] > -1.0e-5) 263 dir[0] = 0; 264 if (dir[1] < 1.0e-5 && dir[1] > -1.0e-5) 265 dir[1] = 0; 266 if (dir[2] < 1.0e-5 && dir[2] > -1.0e-5) 267 dir[2] = 0; 268 269 obs[0] += v * dir[0]; 270 obs[1] += v * dir[1]; 271 obs[2] += v * dir[2]; 272} 273 274static void 275printstring(void *font, char *string) 276{ 277 int len, i; 278 279 len = (int) strlen(string); 280 for (i = 0; i < len; i++) 281 glutBitmapCharacter(font, string[i]); 282} 283 284static void 285reshape(int width, int height) 286{ 287 WIDTH = width; 288 HEIGHT = height; 289 glViewport(0, 0, (GLint) width, (GLint) height); 290 glMatrixMode(GL_PROJECTION); 291 glLoadIdentity(); 292 gluPerspective(70.0, width / (float) height, 0.1, 30.0); 293 294 glMatrixMode(GL_MODELVIEW); 295} 296 297static void 298printhelp(void) 299{ 300 glColor4f(0.0, 0.0, 0.0, 0.5); 301 glRecti(40, 40, 600, 440); 302 303 glColor3f(1.0, 0.0, 0.0); 304 glRasterPos2i(300, 420); 305 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Help"); 306 307 glRasterPos2i(60, 390); 308 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "h - Toggle Help"); 309 310 glRasterPos2i(60, 360); 311 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "t - Increase particle size"); 312 glRasterPos2i(60, 330); 313 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "T - Decrease particle size"); 314 315 glRasterPos2i(60, 300); 316 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "r - Increase emission radius"); 317 glRasterPos2i(60, 270); 318 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "R - Decrease emission radius"); 319 320 glRasterPos2i(60, 240); 321 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "f - Toggle Fog"); 322 glRasterPos2i(60, 210); 323 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "s - Toggle shadows"); 324 glRasterPos2i(60, 180); 325 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Arrow Keys - Rotate"); 326 glRasterPos2i(60, 150); 327 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "a - Increase velocity"); 328 glRasterPos2i(60, 120); 329 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "z - Decrease velocity"); 330 331 glRasterPos2i(60, 90); 332 if (joyavailable) 333 printstring(GLUT_BITMAP_TIMES_ROMAN_24, 334 "j - Toggle jostick control (Joystick control available)"); 335 else 336 printstring(GLUT_BITMAP_TIMES_ROMAN_24, 337 "(No Joystick control available)"); 338} 339 340static void 341dojoy(void) 342{ 343#ifdef WIN32 344 static UINT max[2] = { 0, 0 }; 345 static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2]; 346 MMRESULT res; 347 JOYINFO joy; 348 349 res = joyGetPos(JOYSTICKID1, &joy); 350 351 if (res == JOYERR_NOERROR) { 352 joyavailable = 1; 353 354 if (max[0] < joy.wXpos) 355 max[0] = joy.wXpos; 356 if (min[0] > joy.wXpos) 357 min[0] = joy.wXpos; 358 center[0] = (max[0] + min[0]) / 2; 359 360 if (max[1] < joy.wYpos) 361 max[1] = joy.wYpos; 362 if (min[1] > joy.wYpos) 363 min[1] = joy.wYpos; 364 center[1] = (max[1] + min[1]) / 2; 365 366 if (joyactive) { 367 if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0])) 368 alpha += 369 2.5 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]); 370 if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1])) 371 beta += 2.5 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]); 372 373 if (joy.wButtons & JOY_BUTTON1) 374 v += 0.01; 375 if (joy.wButtons & JOY_BUTTON2) 376 v -= 0.01; 377 } 378 } 379 else 380 joyavailable = 0; 381#endif 382} 383 384static void 385drawfire(void) 386{ 387 static char frbuf[80] = ""; 388 int j; 389 static double t0 = -1.; 390 double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; 391 if (t0 < 0.0) 392 t0 = t; 393 dt = (t - t0) * 1.0; 394 t0 = t; 395 396 dojoy(); 397 398 if (NiceFog) 399 glHint(GL_FOG_HINT, GL_NICEST); 400 else 401 glHint(GL_FOG_HINT, GL_DONT_CARE); 402 403 glEnable(GL_DEPTH_TEST); 404 405 if (fog) 406 glEnable(GL_FOG); 407 else 408 glDisable(GL_FOG); 409 410 glDepthMask(GL_TRUE); 411 glClearColor(1.0, 1.0, 1.0, 1.0); 412 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 413 414 glPushMatrix(); 415 calcposobs(); 416 gluLookAt(obs[0], obs[1], obs[2], 417 obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2], 418 0.0, 1.0, 0.0); 419 420 glColor4f(1.0, 1.0, 1.0, 1.0); 421 422 glEnable(GL_TEXTURE_2D); 423 424 glBindTexture(GL_TEXTURE_2D, groundid); 425#if 1 426 glBegin(GL_QUADS); 427 glTexCoord2fv(qt[0]); 428 glVertex3fv(q[0]); 429 glTexCoord2fv(qt[1]); 430 glVertex3fv(q[1]); 431 glTexCoord2fv(qt[2]); 432 glVertex3fv(q[2]); 433 glTexCoord2fv(qt[3]); 434 glVertex3fv(q[3]); 435 glEnd(); 436#else 437 /* Subdivide the ground into a bunch of quads. This improves fog 438 * if GL_FOG_HINT != GL_NICEST 439 */ 440 { 441 float x, y; 442 float dx = 1.0, dy = 1.0; 443 glBegin(GL_QUADS); 444 for (y = -DIMP; y < DIMP; y += 1.0) { 445 for (x = -DIMP; x < DIMP; x += 1.0) { 446 glTexCoord2f(0, 0); glVertex3f(x, 0, y); 447 glTexCoord2f(1, 0); glVertex3f(x+dx, 0, y); 448 glTexCoord2f(1, 1); glVertex3f(x+dx, 0, y+dy); 449 glTexCoord2f(0, 1); glVertex3f(x, 0, y+dy); 450 } 451 } 452 glEnd(); 453 } 454#endif 455 456 457 glEnable(GL_ALPHA_TEST); 458 glAlphaFunc(GL_GEQUAL, 0.9); 459 460 glBindTexture(GL_TEXTURE_2D, treeid); 461 for (j = 0; j < NUMTREE; j++) 462 drawtree(treepos[j][0], treepos[j][1], treepos[j][2]); 463 464 glDisable(GL_TEXTURE_2D); 465 glDepthMask(GL_FALSE); 466 glDisable(GL_ALPHA_TEST); 467 468 if (shadows) { 469 glBegin(GL_TRIANGLES); 470 for (j = 0; j < np; j++) { 471 glColor4f(black[0], black[1], black[2], p[j].c[0][3]); 472 glVertex3f(p[j].p[0][0], 0.1, p[j].p[0][2]); 473 474 glColor4f(black[0], black[1], black[2], p[j].c[1][3]); 475 glVertex3f(p[j].p[1][0], 0.1, p[j].p[1][2]); 476 477 glColor4f(black[0], black[1], black[2], p[j].c[2][3]); 478 glVertex3f(p[j].p[2][0], 0.1, p[j].p[2][2]); 479 } 480 glEnd(); 481 } 482 483 glBegin(GL_TRIANGLES); 484 for (j = 0; j < np; j++) { 485 glColor4fv(p[j].c[0]); 486 glVertex3fv(p[j].p[0]); 487 488 glColor4fv(p[j].c[1]); 489 glVertex3fv(p[j].p[1]); 490 491 glColor4fv(p[j].c[2]); 492 glVertex3fv(p[j].p[2]); 493 494 setpart(&p[j]); 495 } 496 glEnd(); 497 498 glDisable(GL_TEXTURE_2D); 499 glDisable(GL_ALPHA_TEST); 500 glDisable(GL_DEPTH_TEST); 501 glDisable(GL_FOG); 502 503 glMatrixMode(GL_PROJECTION); 504 glLoadIdentity(); 505 glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0); 506 glMatrixMode(GL_MODELVIEW); 507 glLoadIdentity(); 508 509 glColor3f(1.0, 0.0, 0.0); 510 glRasterPos2i(10, 10); 511 printstring(GLUT_BITMAP_HELVETICA_18, frbuf); 512 glRasterPos2i(370, 470); 513 printstring(GLUT_BITMAP_HELVETICA_10, 514 "Fire V1.5 Written by David Bucciarelli (tech.hmw@plus.it)"); 515 516 if (help) 517 printhelp(); 518 519 reshape(WIDTH, HEIGHT); 520 glPopMatrix(); 521 522 glutSwapBuffers(); 523 524 Frames++; 525 { 526 GLint t = glutGet(GLUT_ELAPSED_TIME); 527 if (t - T0 >= 2000) { 528 GLfloat seconds = (t - T0) / 1000.0; 529 GLfloat fps = Frames / seconds; 530 sprintf(frbuf, "Frame rate: %f", fps); 531 printf("%s\n", frbuf); 532 fflush(stdout); 533 T0 = t; 534 Frames = 0; 535 } 536 } 537} 538 539 540static void 541idle(void) 542{ 543 glutPostRedisplay(); 544} 545 546 547static void 548special(int key, int x, int y) 549{ 550 switch (key) { 551 case GLUT_KEY_LEFT: 552 alpha += 2.0; 553 break; 554 case GLUT_KEY_RIGHT: 555 alpha -= 2.0; 556 break; 557 case GLUT_KEY_DOWN: 558 beta -= 2.0; 559 break; 560 case GLUT_KEY_UP: 561 beta += 2.0; 562 break; 563 } 564 glutPostRedisplay(); 565} 566 567static void 568key(unsigned char key, int x, int y) 569{ 570 switch (key) { 571 case 27: 572 glutDestroyWindow(win); 573 exit(0); 574 break; 575 576 case 'a': 577 v += 0.0005; 578 break; 579 case 'z': 580 v -= 0.0005; 581 break; 582 583 case 'j': 584 joyactive = (!joyactive); 585 break; 586 case 'h': 587 help = (!help); 588 break; 589 case 'f': 590 fog = (!fog); 591 break; 592 case 's': 593 shadows = !shadows; 594 break; 595 case 'R': 596 eject_r -= 0.03; 597 break; 598 case 'r': 599 eject_r += 0.03; 600 break; 601 case 't': 602 ridtri += 0.005; 603 break; 604 case 'T': 605 ridtri -= 0.005; 606 break; 607#ifdef XMESA 608 case ' ': 609 XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW); 610 fullscreen = (!fullscreen); 611 break; 612#endif 613 case 'n': 614 NiceFog = !NiceFog; 615 printf("NiceFog %d\n", NiceFog); 616 break; 617 } 618 glutPostRedisplay(); 619} 620 621static void 622inittextures(void) 623{ 624 GLenum gluerr; 625 GLubyte tex[128][128][4]; 626 627 glGenTextures(1, &groundid); 628 glBindTexture(GL_TEXTURE_2D, groundid); 629 630 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 631 if (!LoadRGBMipmaps(DEMOS_DATA_DIR "s128.rgb", GL_RGB)) { 632 fprintf(stderr, "Error reading a texture.\n"); 633 exit(-1); 634 } 635 636 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 637 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 638 639 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 640 GL_LINEAR_MIPMAP_LINEAR); 641 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 642 643 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); 644 645 glGenTextures(1, &treeid); 646 glBindTexture(GL_TEXTURE_2D, treeid); 647 648 if (1) 649 { 650 int w, h; 651 GLenum format; 652 int x, y; 653 GLubyte *image = LoadRGBImage(DEMOS_DATA_DIR "tree3.rgb", 654 &w, &h, &format); 655 656 if (!image) { 657 fprintf(stderr, "Error reading a texture.\n"); 658 exit(-1); 659 } 660 661 for (y = 0; y < 128; y++) 662 for (x = 0; x < 128; x++) { 663 tex[x][y][0] = image[(y + x * 128) * 3]; 664 tex[x][y][1] = image[(y + x * 128) * 3 + 1]; 665 tex[x][y][2] = image[(y + x * 128) * 3 + 2]; 666 if ((tex[x][y][0] == tex[x][y][1]) && 667 (tex[x][y][1] == tex[x][y][2]) && (tex[x][y][2] == 255)) 668 tex[x][y][3] = 0; 669 else 670 tex[x][y][3] = 255; 671 } 672 673 if ((gluerr = gluBuild2DMipmaps(GL_TEXTURE_2D, 4, 128, 128, GL_RGBA, 674 GL_UNSIGNED_BYTE, (GLvoid *) (tex)))) { 675 fprintf(stderr, "GLULib%s\n", (char *) gluErrorString(gluerr)); 676 exit(-1); 677 } 678 } 679 else { 680 if (!LoadRGBMipmaps(DEMOS_DATA_DIR "tree2.rgba", GL_RGBA)) { 681 fprintf(stderr, "Error reading a texture.\n"); 682 exit(-1); 683 } 684 } 685 686 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 687 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 688 689 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 690 GL_LINEAR_MIPMAP_LINEAR); 691 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 692 693 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 694} 695 696static void 697inittree(void) 698{ 699 int i; 700 float dist; 701 702 for (i = 0; i < NUMTREE; i++) 703 do { 704 treepos[i][0] = vrnd() * TREEOUTR * 2.0 - TREEOUTR; 705 treepos[i][1] = 0.0; 706 treepos[i][2] = vrnd() * TREEOUTR * 2.0 - TREEOUTR; 707 dist = 708 sqrt(treepos[i][0] * treepos[i][0] + 709 treepos[i][2] * treepos[i][2]); 710 } while ((dist < TREEINR) || (dist > TREEOUTR)); 711} 712 713int 714main(int ac, char **av) 715{ 716 int i; 717 718 fprintf(stderr, 719 "Fire V1.5\nWritten by David Bucciarelli (tech.hmw@plus.it)\n"); 720 721 /* Default settings */ 722 723 np = 800; 724 eject_r = -0.65; 725 dt = 0.015; 726 eject_vy = 4; 727 eject_vl = 1; 728 shadows = 1; 729 ridtri = 0.25; 730 731 maxage = 1.0 / dt; 732 733 if (ac == 2) { 734 np = atoi(av[1]); 735 if (np <= 0 || np > 1000000) { 736 fprintf(stderr, "Invalid input.\n"); 737 exit(-1); 738 } 739 } 740 741 if (ac == 4) { 742 WIDTH = atoi(av[2]); 743 HEIGHT = atoi(av[3]); 744 } 745 746 glutInitWindowSize(WIDTH, HEIGHT); 747 glutInit(&ac, av); 748 749 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 750 751 if (!(win = glutCreateWindow("Fire"))) { 752 fprintf(stderr, "Error opening a window.\n"); 753 exit(-1); 754 } 755 756 reshape(WIDTH, HEIGHT); 757 758 inittextures(); 759 760 glShadeModel(GL_FLAT); 761 glEnable(GL_DEPTH_TEST); 762 763 glEnable(GL_BLEND); 764 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 765 766 glEnable(GL_FOG); 767 glFogi(GL_FOG_MODE, GL_EXP); 768 glFogfv(GL_FOG_COLOR, fogcolor); 769 glFogf(GL_FOG_DENSITY, 0.1); 770 771 assert(np > 0); 772 p = (part *) malloc(sizeof(part) * np); 773 assert(p); 774 775 for (i = 0; i < np; i++) 776 setnewpart(&p[i]); 777 778 inittree(); 779 780 glutKeyboardFunc(key); 781 glutSpecialFunc(special); 782 glutDisplayFunc(drawfire); 783 glutIdleFunc(idle); 784 glutReshapeFunc(reshape); 785 glutMainLoop(); 786 787 return (0); 788} 789