blob: dbbe2f35a28f80c9ee0fbff4e60a5e01def4ed81 [file] [log] [blame]
jtgafb833d1999-08-19 00:55:39 +00001
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
jtgafb833d1999-08-19 00:55:39 +000014#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <math.h> /* for cos(), sin(), and sqrt() */
Karl Schultz164ce122002-01-16 00:48:43 +000018#ifdef _WIN32
19#include <windows.h>
20#endif
Brian Paul66fa33e2002-12-03 03:13:17 +000021#define GL_GLEXT_PROTOTYPES
jtgafb833d1999-08-19 00:55:39 +000022#include <GL/glut.h>
23
24/* Some <math.h> files do not define M_PI... */
25#ifndef M_PI
26#define M_PI 3.14159265
27#endif
28
29#if 0 /* For debugging. */
30#undef GL_EXT_point_parameters
31#endif
32
33static GLfloat angle = -150; /* in degrees */
34static int spin = 0;
35static int moving, begin;
36static int newModel = 1;
37static float theTime;
38static int repeat = 1;
39static int blend = 1;
40int useMipmaps = 1;
41int linearFiltering = 1;
42
43static GLfloat constant[3] = { 1/5.0, 0.0, 0.0 };
44static GLfloat linear[3] = { 0.0, 1/5.0, 0.0 };
45static GLfloat theQuad[3] = { 0.25, 0.0, 1/60.0 };
46
47#define MAX_POINTS 2000
48
49static int numPoints = 200;
50
51static GLfloat pointList[MAX_POINTS][3];
52static GLfloat pointTime[MAX_POINTS];
53static GLfloat pointVelocity[MAX_POINTS][2];
54static GLfloat pointDirection[MAX_POINTS][2];
55static int colorList[MAX_POINTS];
56static int animate = 1, motion = 0;
57
58static GLfloat colorSet[][4] = {
59 /* Shades of red. */
60 { 0.7, 0.2, 0.4, 0.5 },
61 { 0.8, 0.0, 0.7, 0.5 },
62 { 1.0, 0.0, 0.0, 0.5 },
63 { 0.9, 0.3, 0.6, 0.5 },
64 { 1.0, 0.4, 0.0, 0.5 },
65 { 1.0, 0.0, 0.5, 0.5 },
66};
67
68#define NUM_COLORS (sizeof(colorSet)/sizeof(colorSet[0]))
69
70#define DEAD (NUM_COLORS+1)
71
72
73#if 0 /* drand48 might be better on Unix machines */
74#define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * drand48())
75#else
76static float float_rand(void) { return rand() / (float) RAND_MAX; }
77#define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * float_rand())
78#endif
79
80#define MEAN_VELOCITY 3.0
81#define GRAVITY 2.0
jtgafb833d1999-08-19 00:55:39 +000082
83/* Modeling units of ground extent in each X and Z direction. */
84#define EDGE 12
85
Brian Paul02e8a032000-06-27 17:04:43 +000086static void
jtgafb833d1999-08-19 00:55:39 +000087makePointList(void)
88{
89 float angle, velocity, direction;
90 int i;
91
92 motion = 1;
93 for (i=0; i<numPoints; i++) {
94 pointList[i][0] = 0.0;
95 pointList[i][1] = 0.0;
96 pointList[i][2] = 0.0;
97 pointTime[i] = 0.0;
98 angle = (RANDOM_RANGE(60.0, 70.0)) * M_PI/180.0;
99 direction = RANDOM_RANGE(0.0, 360.0) * M_PI/180.0;
100 pointDirection[i][0] = cos(direction);
101 pointDirection[i][1] = sin(direction);
102 velocity = MEAN_VELOCITY + RANDOM_RANGE(-0.8, 1.0);
103 pointVelocity[i][0] = velocity * cos(angle);
104 pointVelocity[i][1] = velocity * sin(angle);
105 colorList[i] = rand() % NUM_COLORS;
106 }
107 theTime = 0.0;
108}
109
Brian Paul02e8a032000-06-27 17:04:43 +0000110static void
jtgafb833d1999-08-19 00:55:39 +0000111updatePointList(void)
112{
113 float distance;
114 int i;
115
Brian Paul92eddb02005-01-09 17:37:50 +0000116 static double t0 = -1.;
117 double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
118 if (t0 < 0.0)
119 t0 = t;
120 dt = t - t0;
121 t0 = t;
122
jtgafb833d1999-08-19 00:55:39 +0000123 motion = 0;
124 for (i=0; i<numPoints; i++) {
125 distance = pointVelocity[i][0] * theTime;
126
127 /* X and Z */
128 pointList[i][0] = pointDirection[i][0] * distance;
129 pointList[i][2] = pointDirection[i][1] * distance;
130
131 /* Z */
132 pointList[i][1] =
133 (pointVelocity[i][1] - 0.5 * GRAVITY * pointTime[i])*pointTime[i];
134
135 /* If we hit the ground, bounce the point upward again. */
136 if (pointList[i][1] <= 0.0) {
137 if (distance > EDGE) {
138 /* Particle has hit ground past the distance duration of
139 the particles. Mark particle as dead. */
140 colorList[i] = NUM_COLORS; /* Not moving. */
141 continue;
142 }
143
144 pointVelocity[i][1] *= 0.8; /* 80% of previous up velocity. */
145 pointTime[i] = 0.0; /* Reset the particles sense of up time. */
146 }
147 motion = 1;
Brian Paul92eddb02005-01-09 17:37:50 +0000148 pointTime[i] += dt;
jtgafb833d1999-08-19 00:55:39 +0000149 }
Brian Paul92eddb02005-01-09 17:37:50 +0000150 theTime += dt;
jtgafb833d1999-08-19 00:55:39 +0000151 if (!motion && !spin) {
152 if (repeat) {
153 makePointList();
154 } else {
155 glutIdleFunc(NULL);
156 }
157 }
158}
159
Brian Paul02e8a032000-06-27 17:04:43 +0000160static void
jtgafb833d1999-08-19 00:55:39 +0000161idle(void)
162{
163 updatePointList();
164 if (spin) {
165 angle += 0.3;
166 newModel = 1;
167 }
168 glutPostRedisplay();
169}
170
Brian Paul02e8a032000-06-27 17:04:43 +0000171static void
jtgafb833d1999-08-19 00:55:39 +0000172visible(int vis)
173{
174 if (vis == GLUT_VISIBLE) {
175 if (animate && (motion || spin)) {
176 glutIdleFunc(idle);
177 }
178 } else {
179 glutIdleFunc(NULL);
180 }
181}
182
Brian Paul02e8a032000-06-27 17:04:43 +0000183static void
jtgafb833d1999-08-19 00:55:39 +0000184recalcModelView(void)
185{
186 glPopMatrix();
187 glPushMatrix();
188 glRotatef(angle, 0.0, 1.0, 0.0);
189 newModel = 0;
190}
191
Brian Paul02e8a032000-06-27 17:04:43 +0000192static void
jtgafb833d1999-08-19 00:55:39 +0000193redraw(void)
194{
195 int i;
196
197 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
198 if (newModel)
199 recalcModelView();
200
201 glDepthMask(GL_FALSE);
202
203 /* Draw the floor. */
204/* glEnable(GL_TEXTURE_2D);*/
205 glColor3f(0.5, 1.0, 0.5);
206 glBegin(GL_QUADS);
207 glTexCoord2f(0.0, 0.0);
208 glVertex3f(-EDGE, -0.05, -EDGE);
209 glTexCoord2f(20.0, 0.0);
210 glVertex3f(EDGE, -0.05, -EDGE);
211 glTexCoord2f(20.0, 20.0);
212 glVertex3f(EDGE, -0.05, EDGE);
213 glTexCoord2f(0.0, 20.0);
214 glVertex3f(-EDGE, -0.05, EDGE);
215 glEnd();
216
217 /* Allow particles to blend with each other. */
218 glDepthMask(GL_TRUE);
219
220 if (blend)
221 glEnable(GL_BLEND);
222
223 glDisable(GL_TEXTURE_2D);
224 glBegin(GL_POINTS);
225 for (i=0; i<numPoints; i++) {
226 /* Draw alive particles. */
227 if (colorList[i] != DEAD) {
228 glColor4fv(colorSet[colorList[i]]);
229 glVertex3fv(pointList[i]);
230 }
231 }
232 glEnd();
233
234 glDisable(GL_BLEND);
235
236 glutSwapBuffers();
237}
238
239/* ARGSUSED2 */
Brian Paul02e8a032000-06-27 17:04:43 +0000240static void
jtgafb833d1999-08-19 00:55:39 +0000241mouse(int button, int state, int x, int y)
242{
243 /* Scene can be spun around Y axis using left
244 mouse button movement. */
245 if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
246 moving = 1;
247 begin = x;
248 }
249 if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
250 moving = 0;
251 }
252}
253
254/* ARGSUSED1 */
Brian Paul02e8a032000-06-27 17:04:43 +0000255static void
jtgafb833d1999-08-19 00:55:39 +0000256mouseMotion(int x, int y)
257{
258 if (moving) {
259 angle = angle + (x - begin);
260 begin = x;
261 newModel = 1;
262 glutPostRedisplay();
263 }
264}
265
Brian Paul02e8a032000-06-27 17:04:43 +0000266static void
jtgafb833d1999-08-19 00:55:39 +0000267menu(int option)
268{
269 switch (option) {
270 case 0:
271 makePointList();
272 break;
Brian Paul92eddb02005-01-09 17:37:50 +0000273#ifdef GL_ARB_point_parameters
jtgafb833d1999-08-19 00:55:39 +0000274 case 1:
Brian Paul66fa33e2002-12-03 03:13:17 +0000275 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, constant);
jtgafb833d1999-08-19 00:55:39 +0000276 break;
277 case 2:
Brian Paul66fa33e2002-12-03 03:13:17 +0000278 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, linear);
jtgafb833d1999-08-19 00:55:39 +0000279 break;
280 case 3:
Brian Paul66fa33e2002-12-03 03:13:17 +0000281 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
jtgafb833d1999-08-19 00:55:39 +0000282 break;
283#endif
284 case 4:
285 blend = 1;
286 break;
287 case 5:
288 blend = 0;
289 break;
Brian Paul92eddb02005-01-09 17:37:50 +0000290#ifdef GL_ARB_point_parameters
jtgafb833d1999-08-19 00:55:39 +0000291 case 6:
Brian Paul66fa33e2002-12-03 03:13:17 +0000292 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1.0);
jtgafb833d1999-08-19 00:55:39 +0000293 break;
294 case 7:
Brian Paul66fa33e2002-12-03 03:13:17 +0000295 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 10.0);
jtgafb833d1999-08-19 00:55:39 +0000296 break;
297#endif
298 case 8:
299 glEnable(GL_POINT_SMOOTH);
300 break;
301 case 9:
302 glDisable(GL_POINT_SMOOTH);
303 break;
304 case 10:
305 glPointSize(2.0);
306 break;
307 case 11:
308 glPointSize(4.0);
309 break;
310 case 12:
311 glPointSize(8.0);
312 break;
313 case 13:
314 spin = 1 - spin;
315 if (animate && (spin || motion)) {
316 glutIdleFunc(idle);
317 } else {
318 glutIdleFunc(NULL);
319 }
320 break;
321 case 14:
322 numPoints = 200;
323 break;
324 case 15:
325 numPoints = 500;
326 break;
327 case 16:
328 numPoints = 1000;
329 break;
330 case 17:
331 numPoints = 2000;
332 break;
333 case 666:
334 exit(0);
335 }
336 glutPostRedisplay();
337}
338
339/* ARGSUSED1 */
Brian Paul02e8a032000-06-27 17:04:43 +0000340static void
jtgafb833d1999-08-19 00:55:39 +0000341key(unsigned char c, int x, int y)
342{
343 switch (c) {
344 case 13:
345 animate = 1 - animate; /* toggle. */
346 if (animate && (motion || spin)) {
347 glutIdleFunc(idle);
348 } else {
349 glutIdleFunc(NULL);
350 }
351 break;
352 case ' ':
353 animate = 1;
354 makePointList();
355 glutIdleFunc(idle);
356 break;
357 case 27:
358 exit(0);
359 }
360}
361
362/* Nice floor texture tiling pattern. */
363static char *circles[] = {
364 "....xxxx........",
365 "..xxxxxxxx......",
366 ".xxxxxxxxxx.....",
367 ".xxx....xxx.....",
368 "xxx......xxx....",
369 "xxx......xxx....",
370 "xxx......xxx....",
371 "xxx......xxx....",
372 ".xxx....xxx.....",
373 ".xxxxxxxxxx.....",
374 "..xxxxxxxx......",
375 "....xxxx........",
376 "................",
377 "................",
378 "................",
379 "................",
380};
381
382static void
383makeFloorTexture(void)
384{
385 GLubyte floorTexture[16][16][3];
386 GLubyte *loc;
387 int s, t;
388
389 /* Setup RGB image for the texture. */
390 loc = (GLubyte*) floorTexture;
391 for (t = 0; t < 16; t++) {
392 for (s = 0; s < 16; s++) {
393 if (circles[t][s] == 'x') {
394 /* Nice blue. */
395 loc[0] = 0x1f;
396 loc[1] = 0x1f;
397 loc[2] = 0x8f;
398 } else {
399 /* Light gray. */
400 loc[0] = 0xca;
401 loc[1] = 0xca;
402 loc[2] = 0xca;
403 }
404 loc += 3;
405 }
406 }
407
408 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
409
410 if (useMipmaps) {
411 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
412 GL_LINEAR_MIPMAP_LINEAR);
413 gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 16, 16,
414 GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
415 } else {
416 if (linearFiltering) {
417 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
418 } else {
419 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
420 }
421 glTexImage2D(GL_TEXTURE_2D, 0, 3, 16, 16, 0,
422 GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
423 }
424}
425
426int
427main(int argc, char **argv)
428{
429 int i;
430 glutInit(&argc, argv);
431 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
Keith Whitwell7b5199e2004-02-16 14:45:56 +0000432 glutInitWindowPosition(0, 0);
433 glutInitWindowSize(300, 300);
jtgafb833d1999-08-19 00:55:39 +0000434
435 for (i=1; i<argc; i++) {
436 if(!strcmp("-noms", argv[i])) {
437 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
438 printf("forcing no multisampling\n");
439 } else if(!strcmp("-nomipmaps", argv[i])) {
440 useMipmaps = 0;
441 } else if(!strcmp("-nearest", argv[i])) {
442 linearFiltering = 0;
443 }
444 }
445
446 glutCreateWindow("point burst");
447 glutDisplayFunc(redraw);
448 glutMouseFunc(mouse);
449 glutMotionFunc(mouseMotion);
450 glutVisibilityFunc(visible);
451 glutKeyboardFunc(key);
452 glutCreateMenu(menu);
453 glutAddMenuEntry("Reset time", 0);
454 glutAddMenuEntry("Constant", 1);
455 glutAddMenuEntry("Linear", 2);
456 glutAddMenuEntry("Quadratic", 3);
457 glutAddMenuEntry("Blend on", 4);
458 glutAddMenuEntry("Blend off", 5);
459 glutAddMenuEntry("Threshold 1", 6);
460 glutAddMenuEntry("Threshold 10", 7);
461 glutAddMenuEntry("Point smooth on", 8);
462 glutAddMenuEntry("Point smooth off", 9);
463 glutAddMenuEntry("Point size 2", 10);
464 glutAddMenuEntry("Point size 4", 11);
465 glutAddMenuEntry("Point size 8", 12);
466 glutAddMenuEntry("Toggle spin", 13);
467 glutAddMenuEntry("200 points ", 14);
468 glutAddMenuEntry("500 points ", 15);
469 glutAddMenuEntry("1000 points ", 16);
470 glutAddMenuEntry("2000 points ", 17);
471 glutAddMenuEntry("Quit", 666);
472 glutAttachMenu(GLUT_RIGHT_BUTTON);
473
Brian Paula394f542006-08-28 14:20:19 +0000474 if (!glutExtensionSupported("GL_ARB_point_parameters")) {
475 fprintf(stderr, "Sorry, GL_ARB_point_parameters is not supported.\n");
476 return -1;
477 }
478
jtgafb833d1999-08-19 00:55:39 +0000479 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);
Brian Paul66fa33e2002-12-03 03:13:17 +0000484#if GL_ARB_point_parameters
485 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
jtgafb833d1999-08-19 00:55:39 +0000486#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}