2 /* Copyright (c) Mark J. Kilgard, 1997. */
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. */
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. */
17 #include <math.h> /* for cos(), sin(), and sqrt() */
22 #include "glut_wrap.h"
24 /* Some <math.h> files do not define M_PI... */
26 #define M_PI 3.14159265
29 #if 0 /* For debugging. */
30 #undef GL_EXT_point_parameters
33 static GLfloat angle
= -150; /* in degrees */
35 static int moving
, begin
;
36 static int newModel
= 1;
38 static int repeat
= 1;
41 int linearFiltering
= 1;
43 static GLfloat constant
[3] = { 1/5.0, 0.0, 0.0 };
44 static GLfloat linear
[3] = { 0.0, 1/5.0, 0.0 };
45 static GLfloat theQuad
[3] = { 0.25, 0.0, 1/60.0 };
47 #define MAX_POINTS 2000
49 static int numPoints
= 200;
51 static GLfloat pointList
[MAX_POINTS
][3];
52 static GLfloat pointTime
[MAX_POINTS
];
53 static GLfloat pointVelocity
[MAX_POINTS
][2];
54 static GLfloat pointDirection
[MAX_POINTS
][2];
55 static int colorList
[MAX_POINTS
];
56 static int animate
= 1, motion
= 0;
58 static GLfloat colorSet
[][4] = {
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 },
68 #define NUM_COLORS (sizeof(colorSet)/sizeof(colorSet[0]))
70 #define DEAD (NUM_COLORS+1)
73 #if 0 /* drand48 might be better on Unix machines */
74 #define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * drand48())
76 static float float_rand(void) { return rand() / (float) RAND_MAX
; }
77 #define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * float_rand())
80 #define MEAN_VELOCITY 3.0
83 /* Modeling units of ground extent in each X and Z direction. */
89 float angle
, velocity
, direction
;
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;
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
;
111 updatePointList(void)
116 static double t0
= -1.;
117 double dt
, t
= glutGet(GLUT_ELAPSED_TIME
) / 1000.0;
124 for (i
=0; i
<numPoints
; i
++) {
125 distance
= pointVelocity
[i
][0] * theTime
;
128 pointList
[i
][0] = pointDirection
[i
][0] * distance
;
129 pointList
[i
][2] = pointDirection
[i
][1] * distance
;
133 (pointVelocity
[i
][1] - 0.5 * GRAVITY
* pointTime
[i
])*pointTime
[i
];
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. */
144 pointVelocity
[i
][1] *= 0.8; /* 80% of previous up velocity. */
145 pointTime
[i
] = 0.0; /* Reset the particles sense of up time. */
151 if (!motion
&& !spin
) {
174 if (vis
== GLUT_VISIBLE
) {
175 if (animate
&& (motion
|| spin
)) {
184 recalcModelView(void)
188 glRotatef(angle
, 0.0, 1.0, 0.0);
197 glDepthMask(GL_TRUE
);
198 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
203 /* Draw the floor. */
204 /* glEnable(GL_TEXTURE_2D);*/
205 glColor3f(0.5, 1.0, 0.5);
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
);
217 /* Allow particles to blend with each other. */
218 glDepthMask(GL_FALSE
);
223 glDisable(GL_TEXTURE_2D
);
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
]);
241 mouse(int button
, int state
, int x
, int y
)
243 /* Scene can be spun around Y axis using left
244 mouse button movement. */
245 if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_DOWN
) {
249 if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_UP
) {
256 mouseMotion(int x
, int y
)
259 angle
= angle
+ (x
- begin
);
273 #ifdef GL_ARB_point_parameters
275 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, constant
);
278 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, linear
);
281 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, theQuad
);
290 #ifdef GL_ARB_point_parameters
292 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB
, 1.0);
295 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB
, 10.0);
299 glEnable(GL_POINT_SMOOTH
);
302 glDisable(GL_POINT_SMOOTH
);
315 if (animate
&& (spin
|| motion
)) {
341 key(unsigned char c
, int x
, int y
)
345 animate
= 1 - animate
; /* toggle. */
346 if (animate
&& (motion
|| spin
)) {
362 /* Nice floor texture tiling pattern. */
363 static char *circles
[] = {
383 makeFloorTexture(void)
385 GLubyte floorTexture
[16][16][3];
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') {
408 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
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
);
416 if (linearFiltering
) {
417 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
419 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
421 glTexImage2D(GL_TEXTURE_2D
, 0, 3, 16, 16, 0,
422 GL_RGB
, GL_UNSIGNED_BYTE
, floorTexture
);
427 main(int argc
, char **argv
)
431 glutInitWindowSize(300, 300);
432 glutInit(&argc
, argv
);
433 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
| GLUT_MULTISAMPLE
);
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
])) {
441 } else if(!strcmp("-nearest", argv
[i
])) {
446 glutCreateWindow("point burst");
448 glutDisplayFunc(redraw
);
449 glutMouseFunc(mouse
);
450 glutMotionFunc(mouseMotion
);
451 glutVisibilityFunc(visible
);
452 glutKeyboardFunc(key
);
453 glutCreateMenu(menu
);
454 glutAddMenuEntry("Reset time", 0);
455 glutAddMenuEntry("Constant", 1);
456 glutAddMenuEntry("Linear", 2);
457 glutAddMenuEntry("Quadratic", 3);
458 glutAddMenuEntry("Blend on", 4);
459 glutAddMenuEntry("Blend off", 5);
460 glutAddMenuEntry("Threshold 1", 6);
461 glutAddMenuEntry("Threshold 10", 7);
462 glutAddMenuEntry("Point smooth on", 8);
463 glutAddMenuEntry("Point smooth off", 9);
464 glutAddMenuEntry("Point size 2", 10);
465 glutAddMenuEntry("Point size 4", 11);
466 glutAddMenuEntry("Point size 8", 12);
467 glutAddMenuEntry("Toggle spin", 13);
468 glutAddMenuEntry("200 points ", 14);
469 glutAddMenuEntry("500 points ", 15);
470 glutAddMenuEntry("1000 points ", 16);
471 glutAddMenuEntry("2000 points ", 17);
472 glutAddMenuEntry("Quit", 666);
473 glutAttachMenu(GLUT_RIGHT_BUTTON
);
475 if (!glutExtensionSupported("GL_ARB_point_parameters")) {
476 fprintf(stderr
, "Sorry, GL_ARB_point_parameters is not supported.\n");
480 glShadeModel(GL_FLAT
);
481 glEnable(GL_DEPTH_TEST
);
482 glEnable(GL_POINT_SMOOTH
);
483 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
485 #if GL_ARB_point_parameters
486 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, theQuad
);
488 glMatrixMode(GL_PROJECTION
);
489 gluPerspective( /* field of view in degree */ 40.0,
490 /* aspect ratio */ 1.0,
491 /* Z near */ 0.5, /* Z far */ 40.0);
492 glMatrixMode(GL_MODELVIEW
);
493 gluLookAt(0.0, 1.0, 8.0, /* eye location */
494 0.0, 1.0, 0.0, /* center is at (0,0,0) */
495 0.0, 1.0, 0.); /* up is in postivie Y direction */
496 glPushMatrix(); /* dummy push so we can pop on model
503 return 0; /* ANSI C requires main to return int. */