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() */
24 #define GL_GLEXT_PROTOTYPES
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
107 #define TIME_DELTA 0.025 /* The speed of time. */
109 /* Modeling units of ground extent in each X and Z direction. */
115 float angle
, velocity
, direction
;
119 for (i
=0; i
<numPoints
; i
++) {
120 pointList
[i
][0] = 0.0;
121 pointList
[i
][1] = 0.0;
122 pointList
[i
][2] = 0.0;
124 angle
= (RANDOM_RANGE(60.0, 70.0)) * M_PI
/180.0;
125 direction
= RANDOM_RANGE(0.0, 360.0) * M_PI
/180.0;
126 pointDirection
[i
][0] = cos(direction
);
127 pointDirection
[i
][1] = sin(direction
);
128 velocity
= MEAN_VELOCITY
+ RANDOM_RANGE(-0.8, 1.0);
129 pointVelocity
[i
][0] = velocity
* cos(angle
);
130 pointVelocity
[i
][1] = velocity
* sin(angle
);
131 colorList
[i
] = rand() % NUM_COLORS
;
137 updatePointList(void)
143 for (i
=0; i
<numPoints
; i
++) {
144 distance
= pointVelocity
[i
][0] * theTime
;
147 pointList
[i
][0] = pointDirection
[i
][0] * distance
;
148 pointList
[i
][2] = pointDirection
[i
][1] * distance
;
152 (pointVelocity
[i
][1] - 0.5 * GRAVITY
* pointTime
[i
])*pointTime
[i
];
154 /* If we hit the ground, bounce the point upward again. */
155 if (pointList
[i
][1] <= 0.0) {
156 if (distance
> EDGE
) {
157 /* Particle has hit ground past the distance duration of
158 the particles. Mark particle as dead. */
159 colorList
[i
] = NUM_COLORS
; /* Not moving. */
163 pointVelocity
[i
][1] *= 0.8; /* 80% of previous up velocity. */
164 pointTime
[i
] = 0.0; /* Reset the particles sense of up time. */
167 pointTime
[i
] += TIME_DELTA
;
169 theTime
+= TIME_DELTA
;
170 if (!motion
&& !spin
) {
192 if (vis
== GLUT_VISIBLE
) {
193 if (animate
&& (motion
|| spin
)) {
206 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
209 glRotatef(15.0, 1.0, 0.0, 0.0);
210 glRotatef(angle
, 0.0, 1.0, 0.0);
212 glDepthMask(GL_FALSE
);
214 /* Draw the floor. */
215 /* glEnable(GL_TEXTURE_2D);*/
216 glColor3f(0.1, 0.5, 1.0);
218 glTexCoord2f(0.0, 0.0);
219 glVertex3f(-EDGE
, -0.05, -EDGE
);
220 glTexCoord2f(20.0, 0.0);
221 glVertex3f(EDGE
, -0.05, -EDGE
);
222 glTexCoord2f(20.0, 20.0);
223 glVertex3f(EDGE
, -0.05, EDGE
);
224 glTexCoord2f(0.0, 20.0);
225 glVertex3f(-EDGE
, -0.05, EDGE
);
228 /* Allow particles to blend with each other. */
229 glDepthMask(GL_TRUE
);
235 glEnable(GL_TEXTURE_2D
);
236 #ifdef GL_ARB_point_sprite
237 glEnable(GL_POINT_SPRITE_ARB
);
243 for (i
=0; i
<numPoints
; i
++) {
244 /* Draw alive particles. */
245 if (colorList
[i
] != DEAD
) {
246 if (!sprite
) glColor4fv(colorSet
[colorList
[i
]]);
247 glVertex3fv(pointList
[i
]);
252 glDisable(GL_TEXTURE_2D
);
253 #ifdef GL_ARB_point_sprite
254 glDisable(GL_POINT_SPRITE_ARB
);
265 mouse(int button
, int state
, int x
, int y
)
267 /* Scene can be spun around Y axis using left
268 mouse button movement. */
269 if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_DOWN
) {
273 if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_UP
) {
280 mouseMotion(int x
, int y
)
283 angle
= angle
+ (x
- begin
);
296 #ifdef GL_ARB_point_parameters
298 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, constant
);
301 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, linear
);
304 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, theQuad
);
313 #ifdef GL_ARB_point_parameters
315 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB
, 1.0);
318 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB
, 10.0);
322 glEnable(GL_POINT_SMOOTH
);
326 glDisable(GL_POINT_SMOOTH
);
340 if (animate
&& (spin
|| motion
)) {
366 key(unsigned char c
, int x
, int y
)
370 animate
= 1 - animate
; /* toggle. */
371 if (animate
&& (motion
|| spin
)) {
385 #ifdef GL_VERSION_2_0
386 #ifdef GL_ARB_point_parameters
387 glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN
,
388 org
? GL_LOWER_LEFT
: GL_UPPER_LEFT
);
400 (smooth
^= 1) ? glEnable(GL_POINT_SMOOTH
) : glDisable(GL_POINT_SMOOTH
);
433 GLubyte texture
[16][16][4];
436 if (!glutExtensionSupported("GL_ARB_point_sprite")) {
437 printf("Sorry, this demo requires GL_ARB_point_sprite.\n");
440 if (!glutExtensionSupported("GL_ARB_point_parameters")) {
441 printf("Sorry, this demo requires GL_ARB_point_parameters.\n");
445 for (i
= 0; i
< 16; i
++) {
446 for (j
= 0; j
< 16; j
++) {
447 if (spritePattern
[i
][j
]) {
448 texture
[i
][j
][0] = 255;
449 texture
[i
][j
][1] = 255;
450 texture
[i
][j
][2] = 255;
451 texture
[i
][j
][3] = 255;
454 texture
[i
][j
][0] = 255;
455 texture
[i
][j
][1] = 0;
456 texture
[i
][j
][2] = 0;
457 texture
[i
][j
][3] = 0;
462 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, 16, 16, 0, GL_RGBA
, GL_UNSIGNED_BYTE
,
464 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
465 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
466 #ifdef GL_ARB_point_sprite
467 glTexEnvi(GL_POINT_SPRITE_ARB
, GL_COORD_REPLACE_ARB
, GL_TRUE
);
473 reshape(int width
, int height
)
475 GLfloat h
= (GLfloat
) height
/ (GLfloat
) width
;
477 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
478 glMatrixMode(GL_PROJECTION
);
480 glFrustum(-1.0, 1.0, -h
, h
, 2.0, 30.0);
481 glMatrixMode(GL_MODELVIEW
);
483 glTranslatef(0.0, 0.0, -10.0);
487 main(int argc
, char **argv
)
490 glutInit(&argc
, argv
);
491 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
| GLUT_MULTISAMPLE
);
493 for (i
=1; i
<argc
; i
++) {
494 if(!strcmp("-noms", argv
[i
])) {
495 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
496 printf("forcing no multisampling\n");
497 } else if(!strcmp("-nomipmaps", argv
[i
])) {
499 } else if(!strcmp("-nearest", argv
[i
])) {
503 glutInitWindowPosition(0, 0);
504 glutInitWindowSize(600,300);
505 glutCreateWindow("sprite blast");
506 glutReshapeFunc(reshape
);
507 glutDisplayFunc(redraw
);
508 glutMouseFunc(mouse
);
509 glutMotionFunc(mouseMotion
);
510 glutVisibilityFunc(visible
);
511 glutKeyboardFunc(key
);
512 glutCreateMenu(menu
);
513 glutAddMenuEntry("Reset time", 0);
514 glutAddMenuEntry("Constant", 1);
515 glutAddMenuEntry("Linear", 2);
516 glutAddMenuEntry("Quadratic", 3);
517 glutAddMenuEntry("Blend on", 4);
518 glutAddMenuEntry("Blend off", 5);
519 glutAddMenuEntry("Threshold 1", 6);
520 glutAddMenuEntry("Threshold 10", 7);
521 glutAddMenuEntry("Point smooth on", 8);
522 glutAddMenuEntry("Point smooth off", 9);
523 glutAddMenuEntry("Point size 4", 10);
524 glutAddMenuEntry("Point size 8", 11);
525 glutAddMenuEntry("Point size 16", 12);
526 glutAddMenuEntry("Toggle spin", 13);
527 glutAddMenuEntry("200 points ", 14);
528 glutAddMenuEntry("500 points ", 15);
529 glutAddMenuEntry("1000 points ", 16);
530 glutAddMenuEntry("2000 points ", 17);
531 glutAddMenuEntry("Quit", 666);
532 glutAttachMenu(GLUT_RIGHT_BUTTON
);
534 glShadeModel(GL_FLAT
);
535 glEnable(GL_DEPTH_TEST
);
536 glEnable(GL_POINT_SMOOTH
);
537 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
539 #ifdef GL_ARB_point_parameters
540 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, theQuad
);
547 return 0; /* ANSI C requires main to return int. */