aboutsummaryrefslogtreecommitdiff
path: root/progs/demos/pointblast.c
diff options
context:
space:
mode:
Diffstat (limited to 'progs/demos/pointblast.c')
-rw-r--r--progs/demos/pointblast.c498
1 files changed, 498 insertions, 0 deletions
diff --git a/progs/demos/pointblast.c b/progs/demos/pointblast.c
new file mode 100644
index 000000000..715813f17
--- /dev/null
+++ b/progs/demos/pointblast.c
@@ -0,0 +1,498 @@
+
+/* Copyright (c) Mark J. Kilgard, 1997. */
+
+/* This program is freely distributable without licensing fees
+ and is provided without guarantee or warrantee expressed or
+ implied. This program is -not- in the public domain. */
+
+/* This example demonstrates how to render particle effects
+ with OpenGL. A cloud of pinkish/orange particles explodes with the
+ particles bouncing off the ground. When the EXT_point_parameters
+ is present , the particle size is attenuated based on eye distance. */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h> /* for cos(), sin(), and sqrt() */
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+/* Some <math.h> files do not define M_PI... */
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
+#if 0 /* For debugging. */
+#undef GL_EXT_point_parameters
+#endif
+
+static GLfloat angle = -150; /* in degrees */
+static int spin = 0;
+static int moving, begin;
+static int newModel = 1;
+static float theTime;
+static int repeat = 1;
+static int blend = 1;
+int useMipmaps = 1;
+int linearFiltering = 1;
+
+static GLfloat constant[3] = { 1/5.0, 0.0, 0.0 };
+static GLfloat linear[3] = { 0.0, 1/5.0, 0.0 };
+static GLfloat theQuad[3] = { 0.25, 0.0, 1/60.0 };
+
+#define MAX_POINTS 2000
+
+static int numPoints = 200;
+
+static GLfloat pointList[MAX_POINTS][3];
+static GLfloat pointTime[MAX_POINTS];
+static GLfloat pointVelocity[MAX_POINTS][2];
+static GLfloat pointDirection[MAX_POINTS][2];
+static int colorList[MAX_POINTS];
+static int animate = 1, motion = 0;
+
+static GLfloat colorSet[][4] = {
+ /* Shades of red. */
+ { 0.7, 0.2, 0.4, 0.5 },
+ { 0.8, 0.0, 0.7, 0.5 },
+ { 1.0, 0.0, 0.0, 0.5 },
+ { 0.9, 0.3, 0.6, 0.5 },
+ { 1.0, 0.4, 0.0, 0.5 },
+ { 1.0, 0.0, 0.5, 0.5 },
+};
+
+#define NUM_COLORS (sizeof(colorSet)/sizeof(colorSet[0]))
+
+#define DEAD (NUM_COLORS+1)
+
+
+#if 0 /* drand48 might be better on Unix machines */
+#define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * drand48())
+#else
+static float float_rand(void) { return rand() / (float) RAND_MAX; }
+#define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * float_rand())
+#endif
+
+#define MEAN_VELOCITY 3.0
+#define GRAVITY 2.0
+
+/* Modeling units of ground extent in each X and Z direction. */
+#define EDGE 12
+
+static void
+makePointList(void)
+{
+ float angle, velocity, direction;
+ int i;
+
+ motion = 1;
+ for (i=0; i<numPoints; i++) {
+ pointList[i][0] = 0.0;
+ pointList[i][1] = 0.0;
+ pointList[i][2] = 0.0;
+ pointTime[i] = 0.0;
+ angle = (RANDOM_RANGE(60.0, 70.0)) * M_PI/180.0;
+ direction = RANDOM_RANGE(0.0, 360.0) * M_PI/180.0;
+ pointDirection[i][0] = cos(direction);
+ pointDirection[i][1] = sin(direction);
+ velocity = MEAN_VELOCITY + RANDOM_RANGE(-0.8, 1.0);
+ pointVelocity[i][0] = velocity * cos(angle);
+ pointVelocity[i][1] = velocity * sin(angle);
+ colorList[i] = rand() % NUM_COLORS;
+ }
+ theTime = 0.0;
+}
+
+static void
+updatePointList(void)
+{
+ float distance;
+ int i;
+
+ static double t0 = -1.;
+ double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
+ if (t0 < 0.0)
+ t0 = t;
+ dt = t - t0;
+ t0 = t;
+
+ motion = 0;
+ for (i=0; i<numPoints; i++) {
+ distance = pointVelocity[i][0] * theTime;
+
+ /* X and Z */
+ pointList[i][0] = pointDirection[i][0] * distance;
+ pointList[i][2] = pointDirection[i][1] * distance;
+
+ /* Z */
+ pointList[i][1] =
+ (pointVelocity[i][1] - 0.5 * GRAVITY * pointTime[i])*pointTime[i];
+
+ /* If we hit the ground, bounce the point upward again. */
+ if (pointList[i][1] <= 0.0) {
+ if (distance > EDGE) {
+ /* Particle has hit ground past the distance duration of
+ the particles. Mark particle as dead. */
+ colorList[i] = NUM_COLORS; /* Not moving. */
+ continue;
+ }
+
+ pointVelocity[i][1] *= 0.8; /* 80% of previous up velocity. */
+ pointTime[i] = 0.0; /* Reset the particles sense of up time. */
+ }
+ motion = 1;
+ pointTime[i] += dt;
+ }
+ theTime += dt;
+ if (!motion && !spin) {
+ if (repeat) {
+ makePointList();
+ } else {
+ glutIdleFunc(NULL);
+ }
+ }
+}
+
+static void
+idle(void)
+{
+ updatePointList();
+ if (spin) {
+ angle += 0.3;
+ newModel = 1;
+ }
+ glutPostRedisplay();
+}
+
+static void
+visible(int vis)
+{
+ if (vis == GLUT_VISIBLE) {
+ if (animate && (motion || spin)) {
+ glutIdleFunc(idle);
+ }
+ } else {
+ glutIdleFunc(NULL);
+ }
+}
+
+static void
+recalcModelView(void)
+{
+ glPopMatrix();
+ glPushMatrix();
+ glRotatef(angle, 0.0, 1.0, 0.0);
+ newModel = 0;
+}
+
+static void
+redraw(void)
+{
+ int i;
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ if (newModel)
+ recalcModelView();
+
+ glDepthMask(GL_FALSE);
+
+ /* Draw the floor. */
+/* glEnable(GL_TEXTURE_2D);*/
+ glColor3f(0.5, 1.0, 0.5);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0, 0.0);
+ glVertex3f(-EDGE, -0.05, -EDGE);
+ glTexCoord2f(20.0, 0.0);
+ glVertex3f(EDGE, -0.05, -EDGE);
+ glTexCoord2f(20.0, 20.0);
+ glVertex3f(EDGE, -0.05, EDGE);
+ glTexCoord2f(0.0, 20.0);
+ glVertex3f(-EDGE, -0.05, EDGE);
+ glEnd();
+
+ /* Allow particles to blend with each other. */
+ glDepthMask(GL_TRUE);
+
+ if (blend)
+ glEnable(GL_BLEND);
+
+ glDisable(GL_TEXTURE_2D);
+ glBegin(GL_POINTS);
+ for (i=0; i<numPoints; i++) {
+ /* Draw alive particles. */
+ if (colorList[i] != DEAD) {
+ glColor4fv(colorSet[colorList[i]]);
+ glVertex3fv(pointList[i]);
+ }
+ }
+ glEnd();
+
+ glDisable(GL_BLEND);
+
+ glutSwapBuffers();
+}
+
+/* ARGSUSED2 */
+static void
+mouse(int button, int state, int x, int y)
+{
+ /* Scene can be spun around Y axis using left
+ mouse button movement. */
+ if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
+ moving = 1;
+ begin = x;
+ }
+ if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
+ moving = 0;
+ }
+}
+
+/* ARGSUSED1 */
+static void
+mouseMotion(int x, int y)
+{
+ if (moving) {
+ angle = angle + (x - begin);
+ begin = x;
+ newModel = 1;
+ glutPostRedisplay();
+ }
+}
+
+static void
+menu(int option)
+{
+ switch (option) {
+ case 0:
+ makePointList();
+ break;
+#ifdef GL_ARB_point_parameters
+ case 1:
+ glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, constant);
+ break;
+ case 2:
+ glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, linear);
+ break;
+ case 3:
+ glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
+ break;
+#endif
+ case 4:
+ blend = 1;
+ break;
+ case 5:
+ blend = 0;
+ break;
+#ifdef GL_ARB_point_parameters
+ case 6:
+ glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1.0);
+ break;
+ case 7:
+ glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 10.0);
+ break;
+#endif
+ case 8:
+ glEnable(GL_POINT_SMOOTH);
+ break;
+ case 9:
+ glDisable(GL_POINT_SMOOTH);
+ break;
+ case 10:
+ glPointSize(2.0);
+ break;
+ case 11:
+ glPointSize(4.0);
+ break;
+ case 12:
+ glPointSize(8.0);
+ break;
+ case 13:
+ spin = 1 - spin;
+ if (animate && (spin || motion)) {
+ glutIdleFunc(idle);
+ } else {
+ glutIdleFunc(NULL);
+ }
+ break;
+ case 14:
+ numPoints = 200;
+ break;
+ case 15:
+ numPoints = 500;
+ break;
+ case 16:
+ numPoints = 1000;
+ break;
+ case 17:
+ numPoints = 2000;
+ break;
+ case 666:
+ exit(0);
+ }
+ glutPostRedisplay();
+}
+
+/* ARGSUSED1 */
+static void
+key(unsigned char c, int x, int y)
+{
+ switch (c) {
+ case 13:
+ animate = 1 - animate; /* toggle. */
+ if (animate && (motion || spin)) {
+ glutIdleFunc(idle);
+ } else {
+ glutIdleFunc(NULL);
+ }
+ break;
+ case ' ':
+ animate = 1;
+ makePointList();
+ glutIdleFunc(idle);
+ break;
+ case 27:
+ exit(0);
+ }
+}
+
+/* Nice floor texture tiling pattern. */
+static char *circles[] = {
+ "....xxxx........",
+ "..xxxxxxxx......",
+ ".xxxxxxxxxx.....",
+ ".xxx....xxx.....",
+ "xxx......xxx....",
+ "xxx......xxx....",
+ "xxx......xxx....",
+ "xxx......xxx....",
+ ".xxx....xxx.....",
+ ".xxxxxxxxxx.....",
+ "..xxxxxxxx......",
+ "....xxxx........",
+ "................",
+ "................",
+ "................",
+ "................",
+};
+
+static void
+makeFloorTexture(void)
+{
+ GLubyte floorTexture[16][16][3];
+ GLubyte *loc;
+ int s, t;
+
+ /* Setup RGB image for the texture. */
+ loc = (GLubyte*) floorTexture;
+ for (t = 0; t < 16; t++) {
+ for (s = 0; s < 16; s++) {
+ if (circles[t][s] == 'x') {
+ /* Nice blue. */
+ loc[0] = 0x1f;
+ loc[1] = 0x1f;
+ loc[2] = 0x8f;
+ } else {
+ /* Light gray. */
+ loc[0] = 0xca;
+ loc[1] = 0xca;
+ loc[2] = 0xca;
+ }
+ loc += 3;
+ }
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ if (useMipmaps) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+ gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 16, 16,
+ GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
+ } else {
+ if (linearFiltering) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+ glTexImage2D(GL_TEXTURE_2D, 0, 3, 16, 16, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ glutInit(&argc, argv);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(300, 300);
+
+ for (i=1; i<argc; i++) {
+ if(!strcmp("-noms", argv[i])) {
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+ printf("forcing no multisampling\n");
+ } else if(!strcmp("-nomipmaps", argv[i])) {
+ useMipmaps = 0;
+ } else if(!strcmp("-nearest", argv[i])) {
+ linearFiltering = 0;
+ }
+ }
+
+ glutCreateWindow("point burst");
+ glutDisplayFunc(redraw);
+ glutMouseFunc(mouse);
+ glutMotionFunc(mouseMotion);
+ glutVisibilityFunc(visible);
+ glutKeyboardFunc(key);
+ glutCreateMenu(menu);
+ glutAddMenuEntry("Reset time", 0);
+ glutAddMenuEntry("Constant", 1);
+ glutAddMenuEntry("Linear", 2);
+ glutAddMenuEntry("Quadratic", 3);
+ glutAddMenuEntry("Blend on", 4);
+ glutAddMenuEntry("Blend off", 5);
+ glutAddMenuEntry("Threshold 1", 6);
+ glutAddMenuEntry("Threshold 10", 7);
+ glutAddMenuEntry("Point smooth on", 8);
+ glutAddMenuEntry("Point smooth off", 9);
+ glutAddMenuEntry("Point size 2", 10);
+ glutAddMenuEntry("Point size 4", 11);
+ glutAddMenuEntry("Point size 8", 12);
+ glutAddMenuEntry("Toggle spin", 13);
+ glutAddMenuEntry("200 points ", 14);
+ glutAddMenuEntry("500 points ", 15);
+ glutAddMenuEntry("1000 points ", 16);
+ glutAddMenuEntry("2000 points ", 17);
+ glutAddMenuEntry("Quit", 666);
+ glutAttachMenu(GLUT_RIGHT_BUTTON);
+
+ glShadeModel(GL_FLAT);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_POINT_SMOOTH);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glPointSize(8.0);
+#if GL_ARB_point_parameters
+ glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
+#endif
+ glMatrixMode(GL_PROJECTION);
+ gluPerspective( /* field of view in degree */ 40.0,
+ /* aspect ratio */ 1.0,
+ /* Z near */ 0.5, /* Z far */ 40.0);
+ glMatrixMode(GL_MODELVIEW);
+ gluLookAt(0.0, 1.0, 8.0, /* eye location */
+ 0.0, 1.0, 0.0, /* center is at (0,0,0) */
+ 0.0, 1.0, 0.); /* up is in postivie Y direction */
+ glPushMatrix(); /* dummy push so we can pop on model
+ recalc */
+
+ makePointList();
+ makeFloorTexture();
+
+ glutMainLoop();
+ return 0; /* ANSI C requires main to return int. */
+}