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
;
39 static int newModel
= 1;
41 static int repeat
= 1;
44 int linearFiltering
= 1;
46 static GLfloat constant
[3] = { .2, 0.0, 0.0 };
47 static GLfloat linear
[3] = { .0, .1, 0.0 };
48 static GLfloat theQuad
[3] = { .005, 0.1, 1/600.0 };
50 #define MAX_POINTS 2000
52 static int numPoints
= 200;
54 static GLfloat pointList
[MAX_POINTS
][3];
55 static GLfloat pointTime
[MAX_POINTS
];
56 static GLfloat pointVelocity
[MAX_POINTS
][2];
57 static GLfloat pointDirection
[MAX_POINTS
][2];
58 static int colorList
[MAX_POINTS
];
59 static int animate
= 1, motion
= 0, org
= 0, sprite
= 1, smooth
= 1;
61 static GLfloat colorSet
[][4] = {
63 { 0.7, 0.2, 0.4, 0.5 },
64 { 0.8, 0.0, 0.7, 0.5 },
65 { 1.0, 0.0, 0.0, 0.5 },
66 { 0.9, 0.3, 0.6, 0.5 },
67 { 1.0, 0.4, 0.0, 0.5 },
68 { 1.0, 0.0, 0.5, 0.5 },
71 #define NUM_COLORS (sizeof(colorSet)/sizeof(colorSet[0]))
73 #define DEAD (NUM_COLORS+1)
77 static GLint spritePattern
[16][16] = {
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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
81 { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 },
82 { 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0 },
83 { 0, 0, 1, 1, 0, 0, 1, 1, 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, 0, 0, 0, 0, 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, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0 },
88 { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0 },
89 { 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0 },
90 { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 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 },
93 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
99 #if 0 /* drand48 might be better on Unix machines */
100 #define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * drand48())
102 static float float_rand(void) { return rand() / (float) RAND_MAX
; }
103 #define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * float_rand())
106 #define MEAN_VELOCITY 3.0
108 #define TIME_DELTA 0.025 /* The speed of time. */
110 /* Modeling units of ground extent in each X and Z direction. */
116 float angle
, velocity
, direction
;
120 for (i
=0; i
<numPoints
; i
++) {
121 pointList
[i
][0] = 0.0;
122 pointList
[i
][1] = 0.0;
123 pointList
[i
][2] = 0.0;
125 angle
= (RANDOM_RANGE(60.0, 70.0)) * M_PI
/180.0;
126 direction
= RANDOM_RANGE(0.0, 360.0) * M_PI
/180.0;
127 pointDirection
[i
][0] = cos(direction
);
128 pointDirection
[i
][1] = sin(direction
);
129 velocity
= MEAN_VELOCITY
+ RANDOM_RANGE(-0.8, 1.0);
130 pointVelocity
[i
][0] = velocity
* cos(angle
);
131 pointVelocity
[i
][1] = velocity
* sin(angle
);
132 colorList
[i
] = rand() % NUM_COLORS
;
138 updatePointList(void)
144 for (i
=0; i
<numPoints
; i
++) {
145 distance
= pointVelocity
[i
][0] * theTime
;
148 pointList
[i
][0] = pointDirection
[i
][0] * distance
;
149 pointList
[i
][2] = pointDirection
[i
][1] * distance
;
153 (pointVelocity
[i
][1] - 0.5 * GRAVITY
* pointTime
[i
])*pointTime
[i
];
155 /* If we hit the ground, bounce the point upward again. */
156 if (pointList
[i
][1] <= 0.0) {
157 if (distance
> EDGE
) {
158 /* Particle has hit ground past the distance duration of
159 the particles. Mark particle as dead. */
160 colorList
[i
] = NUM_COLORS
; /* Not moving. */
164 pointVelocity
[i
][1] *= 0.8; /* 80% of previous up velocity. */
165 pointTime
[i
] = 0.0; /* Reset the particles sense of up time. */
168 pointTime
[i
] += TIME_DELTA
;
170 theTime
+= TIME_DELTA
;
171 if (!motion
&& !spin
) {
194 if (vis
== GLUT_VISIBLE
) {
195 if (animate
&& (motion
|| spin
)) {
204 recalcModelView(void)
208 glRotatef(angle
, 0.0, 1.0, 0.0);
217 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
221 glDepthMask(GL_FALSE
);
223 /* Draw the floor. */
224 /* glEnable(GL_TEXTURE_2D);*/
225 glColor3f(0.1, 0.5, 1.0);
227 glTexCoord2f(0.0, 0.0);
228 glVertex3f(-EDGE
, -0.05, -EDGE
);
229 glTexCoord2f(20.0, 0.0);
230 glVertex3f(EDGE
, -0.05, -EDGE
);
231 glTexCoord2f(20.0, 20.0);
232 glVertex3f(EDGE
, -0.05, EDGE
);
233 glTexCoord2f(0.0, 20.0);
234 glVertex3f(-EDGE
, -0.05, EDGE
);
237 /* Allow particles to blend with each other. */
238 glDepthMask(GL_TRUE
);
244 glEnable(GL_TEXTURE_2D
);
245 #ifdef GL_ARB_point_sprite
246 glEnable(GL_POINT_SPRITE_ARB
);
252 for (i
=0; i
<numPoints
; i
++) {
253 /* Draw alive particles. */
254 if (colorList
[i
] != DEAD
) {
255 if (!sprite
) glColor4fv(colorSet
[colorList
[i
]]);
256 glVertex3fv(pointList
[i
]);
261 glDisable(GL_TEXTURE_2D
);
262 #ifdef GL_ARB_point_sprite
263 glDisable(GL_POINT_SPRITE_ARB
);
272 mouse(int button
, int state
, int x
, int y
)
274 /* Scene can be spun around Y axis using left
275 mouse button movement. */
276 if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_DOWN
) {
280 if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_UP
) {
287 mouseMotion(int x
, int y
)
290 angle
= angle
+ (x
- begin
);
304 #if GL_ARB_point_parameters
306 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, constant
);
309 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, linear
);
312 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, theQuad
);
321 #if GL_ARB_point_parameters
323 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB
, 1.0);
326 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB
, 10.0);
330 glEnable(GL_POINT_SMOOTH
);
334 glDisable(GL_POINT_SMOOTH
);
348 if (animate
&& (spin
|| motion
)) {
374 key(unsigned char c
, int x
, int y
)
378 animate
= 1 - animate
; /* toggle. */
379 if (animate
&& (motion
|| spin
)) {
394 #if GL_ARB_point_parameters
395 glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN
,
396 org
? GL_LOWER_LEFT
: GL_UPPER_LEFT
);
408 (smooth
^= 1) ? glEnable(GL_POINT_SMOOTH
) : glDisable(GL_POINT_SMOOTH
);
441 GLubyte texture
[16][16][4];
444 if (!glutExtensionSupported("GL_ARB_point_sprite")) {
445 printf("Sorry, this demo requires GL_ARB_point_sprite.\n");
448 if (!glutExtensionSupported("GL_ARB_point_parameters")) {
449 printf("Sorry, this demo requires GL_ARB_point_parameters.\n");
453 for (i
= 0; i
< 16; i
++) {
454 for (j
= 0; j
< 16; j
++) {
455 if (spritePattern
[i
][j
]) {
456 texture
[i
][j
][0] = 255;
457 texture
[i
][j
][1] = 255;
458 texture
[i
][j
][2] = 255;
459 texture
[i
][j
][3] = 255;
462 texture
[i
][j
][0] = 255;
463 texture
[i
][j
][1] = 0;
464 texture
[i
][j
][2] = 0;
465 texture
[i
][j
][3] = 0;
470 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, 16, 16, 0, GL_RGBA
, GL_UNSIGNED_BYTE
,
472 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
473 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
474 #ifdef GL_ARB_point_sprite
475 glTexEnvi(GL_POINT_SPRITE_ARB
, GL_COORD_REPLACE_ARB
, GL_TRUE
);
481 reshape(int width
, int height
)
483 GLfloat h
= (GLfloat
) height
/ (GLfloat
) width
;
485 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
486 glMatrixMode(GL_PROJECTION
);
488 glFrustum(-1.0, 1.0, -h
, h
, 2.0, 20.0);
489 glMatrixMode(GL_MODELVIEW
);
491 glTranslatef(0.0, 0.0, -60.0);
495 main(int argc
, char **argv
)
498 glutInit(&argc
, argv
);
499 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
| GLUT_MULTISAMPLE
);
501 for (i
=1; i
<argc
; i
++) {
502 if(!strcmp("-noms", argv
[i
])) {
503 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
504 printf("forcing no multisampling\n");
505 } else if(!strcmp("-nomipmaps", argv
[i
])) {
507 } else if(!strcmp("-nearest", argv
[i
])) {
511 glutInitWindowPosition(0, 0);
512 glutInitWindowSize(600,300);
513 glutCreateWindow("sprite blast");
514 glutReshapeFunc(reshape
);
515 glutDisplayFunc(redraw
);
516 glutMouseFunc(mouse
);
517 glutMotionFunc(mouseMotion
);
518 glutVisibilityFunc(visible
);
519 glutKeyboardFunc(key
);
520 glutCreateMenu(menu
);
521 glutAddMenuEntry("Reset time", 0);
522 glutAddMenuEntry("Constant", 1);
523 glutAddMenuEntry("Linear", 2);
524 glutAddMenuEntry("Quadratic", 3);
525 glutAddMenuEntry("Blend on", 4);
526 glutAddMenuEntry("Blend off", 5);
527 glutAddMenuEntry("Threshold 1", 6);
528 glutAddMenuEntry("Threshold 10", 7);
529 glutAddMenuEntry("Point smooth on", 8);
530 glutAddMenuEntry("Point smooth off", 9);
531 glutAddMenuEntry("Point size 4", 10);
532 glutAddMenuEntry("Point size 8", 11);
533 glutAddMenuEntry("Point size 16", 12);
534 glutAddMenuEntry("Toggle spin", 13);
535 glutAddMenuEntry("200 points ", 14);
536 glutAddMenuEntry("500 points ", 15);
537 glutAddMenuEntry("1000 points ", 16);
538 glutAddMenuEntry("2000 points ", 17);
539 glutAddMenuEntry("Quit", 666);
540 glutAttachMenu(GLUT_RIGHT_BUTTON
);
542 glShadeModel(GL_FLAT
);
543 glEnable(GL_DEPTH_TEST
);
544 glEnable(GL_POINT_SMOOTH
);
545 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
547 #if GL_ARB_point_parameters
548 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB
, theQuad
);
550 glMatrixMode(GL_PROJECTION
);
551 gluPerspective( /* field of view in degree */ 40.0,
552 /* aspect ratio */ 1.0,
553 /* Z near */ 0.5, /* Z far */ 40.0);
554 glMatrixMode(GL_MODELVIEW
);
555 gluLookAt(0.0, 1.0, 8.0, /* eye location */
556 0.0, 1.0, 0.0, /* center is at (0,0,0) */
557 0.0, 1.0, 0.); /* up is in postivie Y direction */
558 glPushMatrix(); /* dummy push so we can pop on model
565 return 0; /* ANSI C requires main to return int. */