blob: c604536ab38bb42b5cb6284151c7eb5a542297ea [file] [log] [blame]
Brian Paul1a899782003-09-24 20:41:53 +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
14/* Modified by Brian Paul to test GL_ARB_point_sprite */
15
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <math.h> /* for cos(), sin(), and sqrt() */
21#ifdef _WIN32
22#include <windows.h>
23#endif
24#define GL_GLEXT_PROTOTYPES
25#include <GL/glut.h>
26
27/* Some <math.h> files do not define M_PI... */
28#ifndef M_PI
29#define M_PI 3.14159265
30#endif
31
32#if 0 /* For debugging. */
33#undef GL_EXT_point_parameters
34#endif
35
36static GLfloat angle = -150; /* in degrees */
37static int spin = 0;
38static int moving, begin;
39static int newModel = 1;
40static float theTime;
41static int repeat = 1;
42static int blend = 1;
43int useMipmaps = 1;
44int linearFiltering = 1;
45
46static GLfloat constant[3] = { .2, 0.0, 0.0 };
47static GLfloat linear[3] = { .0, .1, 0.0 };
48static GLfloat theQuad[3] = { .005, 0.1, 1/600.0 };
49
50#define MAX_POINTS 2000
51
52static int numPoints = 200;
53
54static GLfloat pointList[MAX_POINTS][3];
55static GLfloat pointTime[MAX_POINTS];
56static GLfloat pointVelocity[MAX_POINTS][2];
57static GLfloat pointDirection[MAX_POINTS][2];
58static int colorList[MAX_POINTS];
59static int animate = 1, motion = 0;
60
61static GLfloat colorSet[][4] = {
62 /* Shades of red. */
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 },
69};
70
71#define NUM_COLORS (sizeof(colorSet)/sizeof(colorSet[0]))
72
73#define DEAD (NUM_COLORS+1)
74
75
76/* GL */
77static 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 }
94};
95
96
97
98
99#if 0 /* drand48 might be better on Unix machines */
100#define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * drand48())
101#else
102static float float_rand(void) { return rand() / (float) RAND_MAX; }
103#define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * float_rand())
104#endif
105
106#define MEAN_VELOCITY 3.0
107#define GRAVITY 2.0
108#define TIME_DELTA 0.025 /* The speed of time. */
109
110/* Modeling units of ground extent in each X and Z direction. */
111#define EDGE 12
112
113static void
114makePointList(void)
115{
116 float angle, velocity, direction;
117 int i;
118
119 motion = 1;
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;
124 pointTime[i] = 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;
133 }
134 theTime = 0.0;
135}
136
137static void
138updatePointList(void)
139{
140 float distance;
141 int i;
142
143 motion = 0;
144 for (i=0; i<numPoints; i++) {
145 distance = pointVelocity[i][0] * theTime;
146
147 /* X and Z */
148 pointList[i][0] = pointDirection[i][0] * distance;
149 pointList[i][2] = pointDirection[i][1] * distance;
150
151 /* Z */
152 pointList[i][1] =
153 (pointVelocity[i][1] - 0.5 * GRAVITY * pointTime[i])*pointTime[i];
154
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. */
161 continue;
162 }
163
164 pointVelocity[i][1] *= 0.8; /* 80% of previous up velocity. */
165 pointTime[i] = 0.0; /* Reset the particles sense of up time. */
166 }
167 motion = 1;
168 pointTime[i] += TIME_DELTA;
169 }
170 theTime += TIME_DELTA;
171 if (!motion && !spin) {
172 if (repeat) {
173 makePointList();
174 } else {
175 glutIdleFunc(NULL);
176 }
177 }
178}
179
180static void
181idle(void)
182{
183 updatePointList();
184 if (spin) {
185 angle += 0.3;
186 newModel = 1;
187 }
188 glutPostRedisplay();
189}
190
191static void
192visible(int vis)
193{
194 if (vis == GLUT_VISIBLE) {
195 if (animate && (motion || spin)) {
196 glutIdleFunc(idle);
197 }
198 } else {
199 glutIdleFunc(NULL);
200 }
201}
202
203static void
204recalcModelView(void)
205{
206 glPopMatrix();
207 glPushMatrix();
208 glRotatef(angle, 0.0, 1.0, 0.0);
209 newModel = 0;
210}
211
212static void
213redraw(void)
214{
215 int i;
216
217 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
218 if (newModel)
219 recalcModelView();
220
221 glDepthMask(GL_FALSE);
222
223 /* Draw the floor. */
224/* glEnable(GL_TEXTURE_2D);*/
225 glColor3f(0.1, 0.5, 1.0);
226 glBegin(GL_QUADS);
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);
235 glEnd();
236
237 /* Allow particles to blend with each other. */
238 glDepthMask(GL_TRUE);
239
240 if (blend)
241 glEnable(GL_BLEND);
242
243 glEnable(GL_TEXTURE_2D);
244#ifdef GL_ARB_point_sprite
245 glEnable(GL_POINT_SPRITE_ARB);
246#endif
247
248 glColor3f(1,1,1);
249 glBegin(GL_POINTS);
250 for (i=0; i<numPoints; i++) {
251 /* Draw alive particles. */
252 if (colorList[i] != DEAD) {
253 /*glColor4fv(colorSet[colorList[i]]);*/
254 glVertex3fv(pointList[i]);
255 }
256 }
257 glEnd();
258
259 glDisable(GL_TEXTURE_2D);
260#ifdef GL_ARB_point_sprite
261 glDisable(GL_POINT_SPRITE_ARB);
262#endif
263 glDisable(GL_BLEND);
264
265 glutSwapBuffers();
266}
267
268/* ARGSUSED2 */
269static void
270mouse(int button, int state, int x, int y)
271{
272 /* Scene can be spun around Y axis using left
273 mouse button movement. */
274 if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
275 moving = 1;
276 begin = x;
277 }
278 if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
279 moving = 0;
280 }
281}
282
283/* ARGSUSED1 */
284static void
285mouseMotion(int x, int y)
286{
287 if (moving) {
288 angle = angle + (x - begin);
289 begin = x;
290 newModel = 1;
291 glutPostRedisplay();
292 }
293}
294
295static void
296menu(int option)
297{
298 switch (option) {
299 case 0:
300 makePointList();
301 break;
302#if GL_ARB_point_parameters
303 case 1:
304 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, constant);
305 break;
306 case 2:
307 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, linear);
308 break;
309 case 3:
310 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
311 break;
312#endif
313 case 4:
314 blend = 1;
315 break;
316 case 5:
317 blend = 0;
318 break;
319#if GL_ARB_point_parameters
320 case 6:
321 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1.0);
322 break;
323 case 7:
324 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 10.0);
325 break;
326#endif
327 case 8:
328 glEnable(GL_POINT_SMOOTH);
329 break;
330 case 9:
331 glDisable(GL_POINT_SMOOTH);
332 break;
333 case 10:
334 glPointSize(4.0);
335 break;
336 case 11:
337 glPointSize(8.0);
338 break;
339 case 12:
340 glPointSize(16.0);
341 break;
342 case 13:
343 spin = 1 - spin;
344 if (animate && (spin || motion)) {
345 glutIdleFunc(idle);
346 } else {
347 glutIdleFunc(NULL);
348 }
349 break;
350 case 14:
351 numPoints = 200;
352 break;
353 case 15:
354 numPoints = 500;
355 break;
356 case 16:
357 numPoints = 1000;
358 break;
359 case 17:
360 numPoints = 2000;
361 break;
362 case 666:
363 exit(0);
364 }
365 glutPostRedisplay();
366}
367
368/* ARGSUSED1 */
369static void
370key(unsigned char c, int x, int y)
371{
372 switch (c) {
373 case 13:
374 animate = 1 - animate; /* toggle. */
375 if (animate && (motion || spin)) {
376 glutIdleFunc(idle);
377 } else {
378 glutIdleFunc(NULL);
379 }
380 break;
381 case ' ':
382 animate = 1;
383 makePointList();
384 glutIdleFunc(idle);
385 break;
386 case 27:
387 exit(0);
388 }
389}
390
391
392
393static void
394makeSprite(void)
395{
396 GLubyte texture[16][16][4];
397 int i, j;
398
399 if (!glutExtensionSupported("GL_ARB_point_sprite")) {
400 printf("Sorry, this demo requires GL_ARB_point_sprite.\n");
401 exit(0);
402 }
403 if (!glutExtensionSupported("GL_ARB_point_parameters")) {
404 printf("Sorry, this demo requires GL_ARB_point_parameters.\n");
405 exit(0);
406 }
407
408 for (i = 0; i < 16; i++) {
409 for (j = 0; j < 16; j++) {
410 if (spritePattern[i][j]) {
411 texture[i][j][0] = 255;
412 texture[i][j][1] = 255;
413 texture[i][j][2] = 255;
414 texture[i][j][3] = 255;
415 }
416 else {
417 texture[i][j][0] = 255;
418 texture[i][j][1] = 0;
419 texture[i][j][2] = 0;
420 texture[i][j][3] = 0;
421 }
422 }
423 }
424
425 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
426 texture);
427 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
428 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
429#ifdef GL_ARB_point_sprite
430 glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
431#endif
432}
433
434
435static void
436reshape(int width, int height)
437{
438 GLfloat h = (GLfloat) height / (GLfloat) width;
439
440 glViewport(0, 0, (GLint) width, (GLint) height);
441 glMatrixMode(GL_PROJECTION);
442 glLoadIdentity();
443 glFrustum(-1.0, 1.0, -h, h, 2.0, 20.0);
444 glMatrixMode(GL_MODELVIEW);
445 glLoadIdentity();
446 glTranslatef(0.0, 0.0, -60.0);
447}
448
449int
450main(int argc, char **argv)
451{
452 int i;
453 glutInit(&argc, argv);
454 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
455
456 for (i=1; i<argc; i++) {
457 if(!strcmp("-noms", argv[i])) {
458 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
459 printf("forcing no multisampling\n");
460 } else if(!strcmp("-nomipmaps", argv[i])) {
461 useMipmaps = 0;
462 } else if(!strcmp("-nearest", argv[i])) {
463 linearFiltering = 0;
464 }
465 }
466 glutInitWindowSize(600,300);
467 glutCreateWindow("sprite blast");
468 glutReshapeFunc(reshape);
469 glutDisplayFunc(redraw);
470 glutMouseFunc(mouse);
471 glutMotionFunc(mouseMotion);
472 glutVisibilityFunc(visible);
473 glutKeyboardFunc(key);
474 glutCreateMenu(menu);
475 glutAddMenuEntry("Reset time", 0);
476 glutAddMenuEntry("Constant", 1);
477 glutAddMenuEntry("Linear", 2);
478 glutAddMenuEntry("Quadratic", 3);
479 glutAddMenuEntry("Blend on", 4);
480 glutAddMenuEntry("Blend off", 5);
481 glutAddMenuEntry("Threshold 1", 6);
482 glutAddMenuEntry("Threshold 10", 7);
483 glutAddMenuEntry("Point smooth on", 8);
484 glutAddMenuEntry("Point smooth off", 9);
485 glutAddMenuEntry("Point size 4", 10);
486 glutAddMenuEntry("Point size 8", 11);
487 glutAddMenuEntry("Point size 16", 12);
488 glutAddMenuEntry("Toggle spin", 13);
489 glutAddMenuEntry("200 points ", 14);
490 glutAddMenuEntry("500 points ", 15);
491 glutAddMenuEntry("1000 points ", 16);
492 glutAddMenuEntry("2000 points ", 17);
493 glutAddMenuEntry("Quit", 666);
494 glutAttachMenu(GLUT_RIGHT_BUTTON);
495
496 glShadeModel(GL_FLAT);
497 glEnable(GL_DEPTH_TEST);
498 glEnable(GL_POINT_SMOOTH);
499 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
500 glPointSize(16.0);
501#if GL_ARB_point_parameters
502 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
503#endif
504 glMatrixMode(GL_PROJECTION);
505 gluPerspective( /* field of view in degree */ 40.0,
506 /* aspect ratio */ 1.0,
507 /* Z near */ 0.5, /* Z far */ 40.0);
508 glMatrixMode(GL_MODELVIEW);
509 gluLookAt(0.0, 1.0, 8.0, /* eye location */
510 0.0, 1.0, 0.0, /* center is at (0,0,0) */
511 0.0, 1.0, 0.); /* up is in postivie Y direction */
512 glPushMatrix(); /* dummy push so we can pop on model
513 recalc */
514
515 makePointList();
516 makeSprite();
517
518 glutMainLoop();
519 return 0; /* ANSI C requires main to return int. */
520}