/* Copyright (c) Mark J. Kilgard, 1997, 1998. */ /* 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 SGIS_point_parameters is present (supported on SGI's InfiniteReality hardware), the particle size is attenuated based on eye distance. */ /* Now pointburst.c is extended to support the multi-vendor EXT_point_parameters extension that has the same interface as the SGIS extension (modulo the SGIS suffix/prefix). NVidia's Release 2 OpenGL ICD driver supports the EXT_point_parameters extension. */ #include #include #include #include /* for cos(), sin(), and sqrt() */ #ifdef _WIN32 #include /* for wglGetProcAddress */ #endif #include /* Some files do not define M_PI... */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #if 0 /* For debugging. */ #undef GL_SGIS_point_parameters #endif #if defined(GL_SGIS_point_parameters) && !defined(GL_EXT_point_parameters) /* Use the EXT point parameters interface for the SGIS implementation. */ #define GL_POINT_SIZE_MIN_EXT GL_POINT_SIZE_MIN_SGIS #define GL_POINT_SIZE_MAX_EXT GL_POINT_SIZE_MAX_SGIS #define GL_POINT_FADE_THRESHOLD_SIZE_EXT GL_POINT_FADE_THRESHOLD_SIZE_SGIS #define GL_DISTANCE_ATTENUATION_EXT GL_DISTANCE_ATTENUATION_SGIS #define glPointParameterfEXT glPointParameterfSGIS #define glPointParameterfvEXT glPointParameterfvSGIS #define GL_EXT_point_parameters 1 #endif #if !defined(GL_EXT_point_parameters) #define GL_POINT_SIZE_MIN_EXT 0x8126 #define GL_POINT_SIZE_MAX_EXT 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 #define GL_DISTANCE_ATTENUATION_EXT 0x8129 #ifdef _WIN32 /* Curse Microsoft for the insanity of wglGetProcAddress. */ typedef void (APIENTRY * PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param); typedef void (APIENTRY * PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params); #define GL_EXT_point_parameters 1 #endif #endif #ifdef _WIN32 PFNGLPOINTPARAMETERFEXTPROC glPointParameterfEXT; PFNGLPOINTPARAMETERFVEXTPROC glPointParameterfvEXT; #endif int hasPointParameters; static GLfloat angle = -150; /* in degrees */ static int spin = 0; static int moving, begin; static int newModel = 1; static float time; static int repeat = 1; int useMipmaps = 1; int linearFiltering = 1; int useTexture = 1; #if GL_EXT_point_parameters static GLfloat constant[3] = { 1/5.0, 0.0, 0.0 }; static GLfloat linear[3] = { 0.0, 1/5.0, 0.0 }; static GLfloat quadratic[3] = { 0.25, 0.0, 1/60.0 }; #endif #define MAX_POINTS 2000 static int numPoints = 500; 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 #define TIME_DELTA 0.025 /* The speed of time. */ /* Modeling units of ground extent in each X and Z direction. */ #define EDGE 12 void makePointList(void) { float angle, velocity, direction; int i; motion = 1; for (i=0; i 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] += TIME_DELTA; } time += TIME_DELTA; if (!motion && !spin) { if (repeat) { makePointList(); } else { glutIdleFunc(NULL); } } } void idle(void) { updatePointList(); if (spin) { angle += 0.3; newModel = 1; } glutPostRedisplay(); } void visible(int vis) { if (vis == GLUT_VISIBLE) { if (animate && (motion || spin)) { glutIdleFunc(idle); } } else { glutIdleFunc(NULL); } } void recalcModelView(void) { glPopMatrix(); glPushMatrix(); glRotatef(angle, 0.0, 1.0, 0.0); newModel = 0; } void redraw(void) { int i; glDepthMask(GL_TRUE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (newModel) recalcModelView(); /* Draw the floor. */ if (useTexture) { 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_FALSE); if (useTexture) { glDisable(GL_TEXTURE_2D); } glBegin(GL_POINTS); for (i=0; i