home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / Mesa-3.0 / DEMOS / pointblast.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-07-26  |  11.2 KB  |  504 lines

  1.  
  2. /* Copyright (c) Mark J. Kilgard, 1997.  */
  3.  
  4. /* This program is freely distributable without licensing fees 
  5.    and is provided without guarantee or warrantee expressed or 
  6.    implied. This program is -not- in the public domain. */
  7.  
  8. /* This example demonstrates how to render particle effects
  9.    with OpenGL.  A cloud of pinkish/orange particles explodes with the
  10.    particles bouncing off the ground.  When the EXT_point_parameters
  11.    is present , the particle size is attenuated based on eye distance. */
  12.  
  13.  
  14. /*
  15.  * $Log: pointblast.c,v $
  16.  * Revision 3.3  1998/07/26 01:24:27  brianp
  17.  * removed include of gl.h
  18.  *
  19.  * Revision 3.2  1998/02/14 18:51:46  brianp
  20.  * fixed a small compiler warning
  21.  *
  22.  * Revision 3.1  1998/02/14 18:45:25  brianp
  23.  * optimized to use flat shading, don't blend ground polygon
  24.  *
  25.  * Revision 3.0  1998/02/14 18:42:29  brianp
  26.  * initial rev
  27.  *
  28.  */
  29.  
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <math.h>       /* for cos(), sin(), and sqrt() */
  35. #include <GL/glut.h>
  36.  
  37. /* Some <math.h> files do not define M_PI... */
  38. #ifndef M_PI
  39. #define M_PI 3.14159265
  40. #endif
  41.  
  42. #if 0  /* For debugging. */
  43. #undef GL_EXT_point_parameters
  44. #endif
  45.  
  46. static GLfloat angle = -150;   /* in degrees */
  47. static int spin = 0;
  48. static int moving, begin;
  49. static int newModel = 1;
  50. static float theTime;
  51. static int repeat = 1;
  52. static int blend = 1;
  53. int useMipmaps = 1;
  54. int linearFiltering = 1;
  55.  
  56. static GLfloat constant[3] = { 1/5.0, 0.0, 0.0 };
  57. static GLfloat linear[3] = { 0.0, 1/5.0, 0.0 };
  58. static GLfloat theQuad[3] = { 0.25, 0.0, 1/60.0 };
  59.  
  60. #define MAX_POINTS 2000
  61.  
  62. static int numPoints = 200;
  63.  
  64. static GLfloat pointList[MAX_POINTS][3];
  65. static GLfloat pointTime[MAX_POINTS];
  66. static GLfloat pointVelocity[MAX_POINTS][2];
  67. static GLfloat pointDirection[MAX_POINTS][2];
  68. static int colorList[MAX_POINTS];
  69. static int animate = 1, motion = 0;
  70.  
  71. static GLfloat colorSet[][4] = {
  72.   /* Shades of red. */
  73.   { 0.7, 0.2, 0.4, 0.5 },
  74.   { 0.8, 0.0, 0.7, 0.5 },
  75.   { 1.0, 0.0, 0.0, 0.5 },
  76.   { 0.9, 0.3, 0.6, 0.5 },
  77.   { 1.0, 0.4, 0.0, 0.5 },
  78.   { 1.0, 0.0, 0.5, 0.5 },
  79. };
  80.  
  81. #define NUM_COLORS (sizeof(colorSet)/sizeof(colorSet[0]))
  82.  
  83. #define DEAD (NUM_COLORS+1)
  84.  
  85.  
  86. #if 0  /* drand48 might be better on Unix machines */
  87. #define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * drand48())
  88. #else
  89. static float float_rand(void) { return rand() / (float) RAND_MAX; }
  90. #define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * float_rand())
  91. #endif
  92.  
  93. #define MEAN_VELOCITY 3.0
  94. #define GRAVITY 2.0
  95. #define TIME_DELTA 0.025  /* The speed of time. */
  96.  
  97. /* Modeling units of ground extent in each X and Z direction. */
  98. #define EDGE 12
  99.  
  100. void
  101. makePointList(void)
  102. {
  103.   float angle, velocity, direction;
  104.   int i;
  105.  
  106.   motion = 1;
  107.   for (i=0; i<numPoints; i++) {
  108.     pointList[i][0] = 0.0;
  109.     pointList[i][1] = 0.0;
  110.     pointList[i][2] = 0.0;
  111.     pointTime[i] = 0.0;
  112.     angle = (RANDOM_RANGE(60.0, 70.0)) * M_PI/180.0;
  113.     direction = RANDOM_RANGE(0.0, 360.0) * M_PI/180.0;
  114.     pointDirection[i][0] = cos(direction);
  115.     pointDirection[i][1] = sin(direction);
  116.     velocity = MEAN_VELOCITY + RANDOM_RANGE(-0.8, 1.0);
  117.     pointVelocity[i][0] = velocity * cos(angle);
  118.     pointVelocity[i][1] = velocity * sin(angle);
  119.     colorList[i] = rand() % NUM_COLORS;
  120.   }
  121.   theTime = 0.0;
  122. }
  123.  
  124. void
  125. updatePointList(void)
  126. {
  127.   float distance;
  128.   int i;
  129.  
  130.   motion = 0;
  131.   for (i=0; i<numPoints; i++) {
  132.     distance = pointVelocity[i][0] * theTime;
  133.  
  134.     /* X and Z */
  135.     pointList[i][0] = pointDirection[i][0] * distance;
  136.     pointList[i][2] = pointDirection[i][1] * distance;
  137.  
  138.     /* Z */
  139.     pointList[i][1] =
  140.       (pointVelocity[i][1] - 0.5 * GRAVITY * pointTime[i])*pointTime[i];
  141.  
  142.     /* If we hit the ground, bounce the point upward again. */
  143.     if (pointList[i][1] <= 0.0) {
  144.       if (distance > EDGE) {
  145.         /* Particle has hit ground past the distance duration of
  146.           the particles.  Mark particle as dead. */
  147.        colorList[i] = NUM_COLORS;  /* Not moving. */
  148.        continue;
  149.       }
  150.  
  151.       pointVelocity[i][1] *= 0.8;  /* 80% of previous up velocity. */
  152.       pointTime[i] = 0.0;  /* Reset the particles sense of up time. */
  153.     }
  154.     motion = 1;
  155.     pointTime[i] += TIME_DELTA;
  156.   }
  157.   theTime += TIME_DELTA;
  158.   if (!motion && !spin) {
  159.     if (repeat) {
  160.       makePointList();
  161.     } else {
  162.       glutIdleFunc(NULL);
  163.     }
  164.   }
  165. }
  166.  
  167. void
  168. idle(void)
  169. {
  170.   updatePointList();
  171.   if (spin) {
  172.     angle += 0.3;
  173.     newModel = 1;
  174.   }
  175.   glutPostRedisplay();
  176. }
  177.  
  178. void
  179. visible(int vis)
  180. {
  181.   if (vis == GLUT_VISIBLE) {
  182.     if (animate && (motion || spin)) {
  183.       glutIdleFunc(idle);
  184.     }
  185.   } else {
  186.     glutIdleFunc(NULL);
  187.   }
  188. }
  189.  
  190. void
  191. recalcModelView(void)
  192. {
  193.   glPopMatrix();
  194.   glPushMatrix();
  195.   glRotatef(angle, 0.0, 1.0, 0.0);
  196.   newModel = 0;
  197. }
  198.  
  199. void
  200. redraw(void)
  201. {
  202.   int i;
  203.  
  204.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  205.   if (newModel)
  206.     recalcModelView();
  207.  
  208.   glDepthMask(GL_FALSE);
  209.  
  210.   /* Draw the floor. */
  211. /*  glEnable(GL_TEXTURE_2D);*/
  212.   glColor3f(0.5, 1.0, 0.5);
  213.   glBegin(GL_QUADS);
  214.     glTexCoord2f(0.0, 0.0);
  215.     glVertex3f(-EDGE, -0.05, -EDGE);
  216.     glTexCoord2f(20.0, 0.0);
  217.     glVertex3f(EDGE, -0.05, -EDGE);
  218.     glTexCoord2f(20.0, 20.0);
  219.     glVertex3f(EDGE, -0.05, EDGE);
  220.     glTexCoord2f(0.0, 20.0);
  221.     glVertex3f(-EDGE, -0.05, EDGE);
  222.   glEnd();
  223.  
  224.   /* Allow particles to blend with each other. */
  225.   glDepthMask(GL_TRUE);
  226.  
  227.   if (blend)
  228.      glEnable(GL_BLEND);
  229.  
  230.   glDisable(GL_TEXTURE_2D);
  231.   glBegin(GL_POINTS);
  232.     for (i=0; i<numPoints; i++) {
  233.       /* Draw alive particles. */
  234.       if (colorList[i] != DEAD) {
  235.         glColor4fv(colorSet[colorList[i]]);
  236.         glVertex3fv(pointList[i]);
  237.       }
  238.     }
  239.   glEnd();
  240.  
  241.   glDisable(GL_BLEND);
  242.  
  243.   glutSwapBuffers();
  244. }
  245.  
  246. /* ARGSUSED2 */
  247. void
  248. mouse(int button, int state, int x, int y)
  249. {
  250.   /* Scene can be spun around Y axis using left
  251.      mouse button movement. */
  252.   if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
  253.     moving = 1;
  254.     begin = x;
  255.   }
  256.   if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
  257.     moving = 0;
  258.   }
  259. }
  260.  
  261. /* ARGSUSED1 */
  262. void
  263. mouseMotion(int x, int y)
  264. {
  265.   if (moving) {
  266.     angle = angle + (x - begin);
  267.     begin = x;
  268.     newModel = 1;
  269.     glutPostRedisplay();
  270.   }
  271. }
  272.  
  273. void
  274. menu(int option)
  275. {
  276.   switch (option) {
  277.   case 0:
  278.     makePointList();
  279.     break;
  280. #if GL_EXT_point_parameters
  281.   case 1:
  282.     glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, constant);
  283.     break;
  284.   case 2:
  285.     glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, linear);
  286.     break;
  287.   case 3:
  288.     glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, theQuad);
  289.     break;
  290. #endif
  291.   case 4:
  292.     blend = 1;
  293.     break;
  294.   case 5:
  295.     blend = 0;
  296.     break;
  297. #if GL_EXT_point_parameters
  298.   case 6:
  299.     glPointParameterfEXT(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 1.0);
  300.     break;
  301.   case 7:
  302.     glPointParameterfEXT(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 10.0);
  303.     break;
  304. #endif
  305.   case 8:
  306.     glEnable(GL_POINT_SMOOTH);
  307.     break;
  308.   case 9:
  309.     glDisable(GL_POINT_SMOOTH);
  310.     break;
  311.   case 10:
  312.     glPointSize(2.0);
  313.     break;
  314.   case 11:
  315.     glPointSize(4.0);
  316.     break;
  317.   case 12:
  318.     glPointSize(8.0);
  319.     break;
  320.   case 13:
  321.     spin = 1 - spin;
  322.     if (animate && (spin || motion)) {
  323.       glutIdleFunc(idle);
  324.     } else {
  325.       glutIdleFunc(NULL);
  326.     }
  327.     break;
  328.   case 14:
  329.     numPoints = 200;
  330.     break;
  331.   case 15:
  332.     numPoints = 500;
  333.     break;
  334.   case 16:
  335.     numPoints = 1000;
  336.     break;
  337.   case 17:
  338.     numPoints = 2000;
  339.     break;
  340.   case 666:
  341.     exit(0);
  342.   }
  343.   glutPostRedisplay();
  344. }
  345.  
  346. /* ARGSUSED1 */
  347. void
  348. key(unsigned char c, int x, int y)
  349. {
  350.   switch (c) {
  351.   case 13:
  352.     animate = 1 - animate;  /* toggle. */
  353.     if (animate && (motion || spin)) {
  354.       glutIdleFunc(idle);
  355.     } else {
  356.       glutIdleFunc(NULL);
  357.     }
  358.     break;
  359.   case ' ':
  360.     animate = 1;
  361.     makePointList();
  362.     glutIdleFunc(idle);
  363.     break;
  364.   case 27:
  365.     exit(0);
  366.   }
  367. }
  368.  
  369. /* Nice floor texture tiling pattern. */
  370. static char *circles[] = {
  371.   "....xxxx........",
  372.   "..xxxxxxxx......",
  373.   ".xxxxxxxxxx.....",
  374.   ".xxx....xxx.....",
  375.   "xxx......xxx....",
  376.   "xxx......xxx....",
  377.   "xxx......xxx....",
  378.   "xxx......xxx....",
  379.   ".xxx....xxx.....",
  380.   ".xxxxxxxxxx.....",
  381.   "..xxxxxxxx......",
  382.   "....xxxx........",
  383.   "................",
  384.   "................",
  385.   "................",
  386.   "................",
  387. };
  388.  
  389. static void
  390. makeFloorTexture(void)
  391. {
  392.   GLubyte floorTexture[16][16][3];
  393.   GLubyte *loc;
  394.   int s, t;
  395.  
  396.   /* Setup RGB image for the texture. */
  397.   loc = (GLubyte*) floorTexture;
  398.   for (t = 0; t < 16; t++) {
  399.     for (s = 0; s < 16; s++) {
  400.       if (circles[t][s] == 'x') {
  401.         /* Nice blue. */
  402.         loc[0] = 0x1f;
  403.         loc[1] = 0x1f;
  404.         loc[2] = 0x8f;
  405.       } else {
  406.         /* Light gray. */
  407.         loc[0] = 0xca;
  408.         loc[1] = 0xca;
  409.         loc[2] = 0xca;
  410.       }
  411.       loc += 3;
  412.     }
  413.   }
  414.  
  415.   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  416.  
  417.   if (useMipmaps) {
  418.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  419.       GL_LINEAR_MIPMAP_LINEAR);
  420.     gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 16, 16,
  421.       GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
  422.   } else {
  423.     if (linearFiltering) {
  424.       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  425.     } else {
  426.       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  427.     }
  428.     glTexImage2D(GL_TEXTURE_2D, 0, 3, 16, 16, 0,
  429.       GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
  430.   }
  431. }
  432.  
  433. int
  434. main(int argc, char **argv)
  435. {
  436.   int i;
  437.   glutInit(&argc, argv);
  438.   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
  439.  
  440.   for (i=1; i<argc; i++) {
  441.     if(!strcmp("-noms", argv[i])) {
  442.       glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  443.       printf("forcing no multisampling\n");
  444.     } else if(!strcmp("-nomipmaps", argv[i])) {
  445.       useMipmaps = 0;
  446.     } else if(!strcmp("-nearest", argv[i])) {
  447.       linearFiltering = 0;
  448.     }
  449.   }
  450.  
  451.   glutCreateWindow("point burst");
  452.   glutDisplayFunc(redraw);
  453.   glutMouseFunc(mouse);
  454.   glutMotionFunc(mouseMotion);
  455.   glutVisibilityFunc(visible);
  456.   glutKeyboardFunc(key);
  457.   glutCreateMenu(menu);
  458.   glutAddMenuEntry("Reset time", 0);
  459.   glutAddMenuEntry("Constant", 1);
  460.   glutAddMenuEntry("Linear", 2);
  461.   glutAddMenuEntry("Quadratic", 3);
  462.   glutAddMenuEntry("Blend on", 4);
  463.   glutAddMenuEntry("Blend off", 5);
  464.   glutAddMenuEntry("Threshold 1", 6);
  465.   glutAddMenuEntry("Threshold 10", 7);
  466.   glutAddMenuEntry("Point smooth on", 8);
  467.   glutAddMenuEntry("Point smooth off", 9);
  468.   glutAddMenuEntry("Point size 2", 10);
  469.   glutAddMenuEntry("Point size 4", 11);
  470.   glutAddMenuEntry("Point size 8", 12);
  471.   glutAddMenuEntry("Toggle spin", 13);
  472.   glutAddMenuEntry("200 points ", 14);
  473.   glutAddMenuEntry("500 points ", 15);
  474.   glutAddMenuEntry("1000 points ", 16);
  475.   glutAddMenuEntry("2000 points ", 17);
  476.   glutAddMenuEntry("Quit", 666);
  477.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  478.  
  479.   glShadeModel(GL_FLAT);
  480.   glEnable(GL_DEPTH_TEST);
  481.   glEnable(GL_POINT_SMOOTH);
  482.   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  483.   glPointSize(8.0);
  484. #if GL_EXT_point_parameters
  485.   glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, theQuad);
  486. #endif
  487.   glMatrixMode(GL_PROJECTION);
  488.   gluPerspective( /* field of view in degree */ 40.0,
  489.   /* aspect ratio */ 1.0,
  490.     /* Z near */ 0.5, /* Z far */ 40.0);
  491.   glMatrixMode(GL_MODELVIEW);
  492.   gluLookAt(0.0, 1.0, 8.0, /* eye location */
  493.     0.0, 1.0, 0.0,      /* center is at (0,0,0) */
  494.     0.0, 1.0, 0.);      /* up is in postivie Y direction */
  495.   glPushMatrix();       /* dummy push so we can pop on model
  496.                            recalc */
  497.  
  498.   makePointList();
  499.   makeFloorTexture();
  500.  
  501.   glutMainLoop();
  502.   return 0;             /* ANSI C requires main to return int. */
  503. }
  504.