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