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. */
14 /* Modified by Brian Paul to test GL_ARB_point_sprite */
20 #include <math.h> /* for cos(), sin(), and sqrt() */
27 /* Some <math.h> files do not define M_PI... */
29 #define M_PI 3.14159265
32 #if 0 /* For debugging. */
33 #undef GL_EXT_point_parameters
36 static GLfloat angle
= -150; /* in degrees */
38 static int moving
, begin
;
40 static int repeat
= 1;
43 int linearFiltering
= 1;
45 static GLfloat constant
[3] = { .2, 0.0, 0.0 };
46 static GLfloat linear
[3] = { .0, .1, 0.0 };
47 static GLfloat theQuad
[3] = { .005, 0.1, 1/600.0 };
49 #define MAX_POINTS 2000
51 static int numPoints
= 200;
53 static GLfloat pointList
[MAX_POINTS
][3];
54 static GLfloat pointTime
[MAX_POINTS
];
55 static GLfloat pointVelocity
[MAX_POINTS
][2];
56 static GLfloat pointDirection
[MAX_POINTS
][2];
57 static int colorList
[MAX_POINTS
];
58 static int animate
= 1, motion
= 0, org
= 0, sprite
= 1, smooth
= 1;
60 static GLfloat colorSet
[][4] = {
62 { 0.7, 0.2, 0.4, 0.5 },
63 { 0.8, 0.0, 0.7, 0.5 },
64 { 1.0, 0.0, 0.0, 0.5 },
65 { 0.9, 0.3, 0.6, 0.5 },
66 { 1.0, 0.4, 0.0, 0.5 },
67 { 1.0, 0.0, 0.5, 0.5 },
70 #define NUM_COLORS (sizeof(colorSet)/sizeof(colorSet[0]))
72 #define DEAD (NUM_COLORS+1)
76 static GLint spritePattern
[16][16] = {
77 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
78 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
79 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
80 { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 },
81 { 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0 },
82 { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0 },
83 { 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 },
84 { 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 },
85 { 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0 },
86 { 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0 },
87 { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0 },
88 { 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0 },
89 { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0 },
90 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
91 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
92 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
98 #if 0 /* drand48 might be better on Unix machines */
99 #define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * drand48())
101 static float float_rand(void) { return rand() / (float) RAND_MAX
; }
102 #define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * float_rand())
105 #define MEAN_VELOCITY 3.0
108 /* Modeling units of ground extent in each X and Z direction. */
114 float angle
, velocity
, direction
;
118 for (i
=0; i
<numPoints
; i
++) {
119 pointList
[i
][0] = 0.0;
120 pointList
[i
][1] = 0.0;
121 pointList
[i
][2] = 0.0;
123 angle
= (RANDOM_RANGE(60.0, 70.0)) * M_PI
/180.0;
124 direction
= RANDOM_RANGE(0.0, 360.0) * M_PI
/180.0;
125 pointDirection
[i
][0] = cos(direction
);
126 pointDirection
[i
][1] = sin(direction
);
127 velocity
= MEAN_VELOCITY
+ RANDOM_RANGE(-0.8, 1.0);
128 pointVelocity
[i
][0] = velocity
* cos(angle
);
129 pointVelocity
[i
][1] = velocity
* sin(angle
);
130 colorList
[i
] = rand() % NUM_COLORS
;
136 updatePointList(void)
141 static double t0
= -1.;
142 double dt
, t
= glutGet(GLUT_ELAPSED_TIME
) / 1000.0;
149 for (i
=0; i
<numPoints
; i
++) {
150 distance
= pointVelocity
[i
][0] * theTime
;
153 pointList
[i
][0] = pointDirection
[i
][0] * distance
;
154 pointList
[i
][2] = pointDirection
[i
][1] * distance
;
158 (pointVelocity
[i
][1] - 0.5 * GRAVITY
* pointTime
[i
])*pointTime
[i
];
160 /* If we hit the ground, bounce the point upward again. */
161 if (pointList
[i
][1] <= 0.0) {
162 if (distance
> EDGE
) {
163 /* Particle has hit ground past the distance duration of
164 the particles. Mark particle as dead. */
165 colorList
[i
] = NUM_COLORS
; /* Not moving. */
169 pointVelocity
[i
][1] *= 0.8; /* 80% of previous up velocity. */
170 pointTime
[i
] = 0.0; /* Reset the particles sense of up time. */
176 if (!motion
&& !spin
) {
198 if (vis
== GLUT_VISIBLE
) {
199 if (animate
&& (motion
|| spin
)) {
212 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
215 glRotatef(15.0, 1.0, 0.0, 0.0);
216 glRotatef(angle
, 0.0, 1.0, 0.0);
218 glDepthMask(GL_FALSE
);
220 /* Draw the floor. */
221 /* glEnable(GL_TEXTURE_2D);*/
222 glColor3f(0.1, 0.5, 1.0);
224 glTexCoord2f(0.0, 0.0);
225 glVertex3f(-EDGE
, -0.05, -EDGE
);
226 glTexCoord2f(20.0, 0.0);
227 glVertex3f(EDGE
, -0.05, -EDGE
);
228 glTexCoord2f(20.0, 20.0);
229 glVertex3f(EDGE
, -0.05, EDGE
);
230 glTexCoord2f(0.0, 20.0);
231 glVertex3f(-EDGE
, -0.05, EDGE
);
234 /* Allow particles to blend with each other. */
235 glDepthMask(GL_TRUE
);
241 glEnable(GL_TEXTURE_2D
);
242 #ifdef GL_ARB_point_sprite
243 glEnable(GL_POINT_SPRITE_ARB
);
249 for (i
=0; i
<numPoints
; i
++) {
250 /* Draw alive particles. */
251 if (colorList
[i
] != DEAD
) {
252 if (!sprite
) glColor4fv(colorSet
[colorList
[i
]]);
253 glVertex3fv(pointList
[i
]);
258 glDisable(GL_TEXTURE_2D
);
259 #ifdef GL_ARB_point_sprite
260 glDisable(GL_POINT_SPRITE_ARB
);
271 mouse(int button
, int state
, int x
, int y
)
273 /* Scene can be spun around Y axis using left
274 mouse button movement. */
275 if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_DOWN
) {
279 if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_UP
) {
286 mouseMotion(int x
, int y
)
289 angle
= angle
+ (x
- begin
);
302 #ifdef GL_ARB_point_parameters
304 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, constant
);
307 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, linear
);
310 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, theQuad
);
319 #ifdef GL_ARB_point_parameters
321 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB
, 1.0);
324 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB
, 10.0);
328 glEnable(GL_POINT_SMOOTH
);
332 glDisable(GL_POINT_SMOOTH
);
346 if (animate
&& (spin
|| motion
)) {
372 key(unsigned char c
, int x
, int y
)
376 animate
= 1 - animate
; /* toggle. */
377 if (animate
&& (motion
|| spin
)) {
391 #ifdef GL_VERSION_2_0
392 #ifdef GL_ARB_point_parameters
393 glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN
,
394 org
? GL_LOWER_LEFT
: GL_UPPER_LEFT
);
406 (smooth
^= 1) ? glEnable(GL_POINT_SMOOTH
) : glDisable(GL_POINT_SMOOTH
);
439 GLubyte texture
[16][16][4];
442 if (!glutExtensionSupported("GL_ARB_point_sprite")) {
443 printf("Sorry, this demo requires GL_ARB_point_sprite.\n");
446 if (!glutExtensionSupported("GL_ARB_point_parameters")) {
447 printf("Sorry, this demo requires GL_ARB_point_parameters.\n");
451 for (i
= 0; i
< 16; i
++) {
452 for (j
= 0; j
< 16; j
++) {
453 if (spritePattern
[i
][j
]) {
454 texture
[i
][j
][0] = 255;
455 texture
[i
][j
][1] = 255;
456 texture
[i
][j
][2] = 255;
457 texture
[i
][j
][3] = 255;
460 texture
[i
][j
][0] = 255;
461 texture
[i
][j
][1] = 0;
462 texture
[i
][j
][2] = 0;
463 texture
[i
][j
][3] = 0;
468 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, 16, 16, 0, GL_RGBA
, GL_UNSIGNED_BYTE
,
470 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
471 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
472 #ifdef GL_ARB_point_sprite
473 glTexEnvi(GL_POINT_SPRITE_ARB
, GL_COORD_REPLACE_ARB
, GL_TRUE
);
479 reshape(int width
, int height
)
481 GLfloat h
= (GLfloat
) height
/ (GLfloat
) width
;
483 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
484 glMatrixMode(GL_PROJECTION
);
486 glFrustum(-1.0, 1.0, -h
, h
, 2.0, 30.0);
487 glMatrixMode(GL_MODELVIEW
);
489 glTranslatef(0.0, 0.0, -10.0);
493 main(int argc
, char **argv
)
496 glutInit(&argc
, argv
);
497 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
| GLUT_MULTISAMPLE
);
499 for (i
=1; i
<argc
; i
++) {
500 if(!strcmp("-noms", argv
[i
])) {
501 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
502 printf("forcing no multisampling\n");
503 } else if(!strcmp("-nomipmaps", argv
[i
])) {
505 } else if(!strcmp("-nearest", argv
[i
])) {
509 glutInitWindowPosition(0, 0);
510 glutInitWindowSize(600,300);
511 glutCreateWindow("sprite blast");
513 glutReshapeFunc(reshape
);
514 glutDisplayFunc(redraw
);
515 glutMouseFunc(mouse
);
516 glutMotionFunc(mouseMotion
);
517 glutVisibilityFunc(visible
);
518 glutKeyboardFunc(key
);
519 glutCreateMenu(menu
);
520 glutAddMenuEntry("Reset time", 0);
521 glutAddMenuEntry("Constant", 1);
522 glutAddMenuEntry("Linear", 2);
523 glutAddMenuEntry("Quadratic", 3);
524 glutAddMenuEntry("Blend on", 4);
525 glutAddMenuEntry("Blend off", 5);
526 glutAddMenuEntry("Threshold 1", 6);
527 glutAddMenuEntry("Threshold 10", 7);
528 glutAddMenuEntry("Point smooth on", 8);
529 glutAddMenuEntry("Point smooth off", 9);
530 glutAddMenuEntry("Point size 16", 10);
531 glutAddMenuEntry("Point size 32", 11);
532 glutAddMenuEntry("Point size 64", 12);
533 glutAddMenuEntry("Toggle spin", 13);
534 glutAddMenuEntry("200 points ", 14);
535 glutAddMenuEntry("500 points ", 15);
536 glutAddMenuEntry("1000 points ", 16);
537 glutAddMenuEntry("2000 points ", 17);
538 glutAddMenuEntry("Quit", 666);
539 glutAttachMenu(GLUT_RIGHT_BUTTON
);
544 glShadeModel(GL_FLAT
);
545 glEnable(GL_DEPTH_TEST
);
546 glEnable(GL_POINT_SMOOTH
);
547 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
549 #ifdef GL_ARB_point_parameters
550 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, theQuad
);
554 return 0; /* ANSI C requires main to return int. */