blob: 63dc7d12bb8a56c677f15743c65fcb46e3f3c6a1 [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;
Brian Paul1a899782003-09-24 20:41:53 +000039static float theTime;
40static int repeat = 1;
41static int blend = 1;
42int useMipmaps = 1;
43int linearFiltering = 1;
44
45static GLfloat constant[3] = { .2, 0.0, 0.0 };
46static GLfloat linear[3] = { .0, .1, 0.0 };
47static GLfloat theQuad[3] = { .005, 0.1, 1/600.0 };
48
49#define MAX_POINTS 2000
50
51static int numPoints = 200;
52
53static GLfloat pointList[MAX_POINTS][3];
54static GLfloat pointTime[MAX_POINTS];
55static GLfloat pointVelocity[MAX_POINTS][2];
56static GLfloat pointDirection[MAX_POINTS][2];
57static int colorList[MAX_POINTS];
Daniel Borcaa9ea1622004-09-13 08:47:01 +000058static int animate = 1, motion = 0, org = 0, sprite = 1, smooth = 1;
Brian Paul1a899782003-09-24 20:41:53 +000059
60static GLfloat colorSet[][4] = {
61 /* Shades of red. */
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 },
68};
69
70#define NUM_COLORS (sizeof(colorSet)/sizeof(colorSet[0]))
71
72#define DEAD (NUM_COLORS+1)
73
74
75/* GL */
76static 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 }
93};
94
95
96
97
98#if 0 /* drand48 might be better on Unix machines */
99#define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * drand48())
100#else
101static float float_rand(void) { return rand() / (float) RAND_MAX; }
102#define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * float_rand())
103#endif
104
105#define MEAN_VELOCITY 3.0
106#define GRAVITY 2.0
107#define TIME_DELTA 0.025 /* The speed of time. */
108
109/* Modeling units of ground extent in each X and Z direction. */
110#define EDGE 12
111
112static void
113makePointList(void)
114{
115 float angle, velocity, direction;
116 int i;
117
118 motion = 1;
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;
123 pointTime[i] = 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;
132 }
133 theTime = 0.0;
134}
135
136static void
137updatePointList(void)
138{
139 float distance;
140 int i;
141
142 motion = 0;
143 for (i=0; i<numPoints; i++) {
144 distance = pointVelocity[i][0] * theTime;
145
146 /* X and Z */
147 pointList[i][0] = pointDirection[i][0] * distance;
148 pointList[i][2] = pointDirection[i][1] * distance;
149
150 /* Z */
151 pointList[i][1] =
152 (pointVelocity[i][1] - 0.5 * GRAVITY * pointTime[i])*pointTime[i];
153
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. */
160 continue;
161 }
162
163 pointVelocity[i][1] *= 0.8; /* 80% of previous up velocity. */
164 pointTime[i] = 0.0; /* Reset the particles sense of up time. */
165 }
166 motion = 1;
167 pointTime[i] += TIME_DELTA;
168 }
169 theTime += TIME_DELTA;
170 if (!motion && !spin) {
171 if (repeat) {
172 makePointList();
173 } else {
174 glutIdleFunc(NULL);
175 }
176 }
177}
178
179static void
180idle(void)
181{
182 updatePointList();
183 if (spin) {
184 angle += 0.3;
Brian Paul1a899782003-09-24 20:41:53 +0000185 }
186 glutPostRedisplay();
187}
188
189static void
190visible(int vis)
191{
192 if (vis == GLUT_VISIBLE) {
193 if (animate && (motion || spin)) {
194 glutIdleFunc(idle);
195 }
196 } else {
197 glutIdleFunc(NULL);
198 }
199}
200
201static void
Brian Paul1a899782003-09-24 20:41:53 +0000202redraw(void)
203{
204 int i;
205
206 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Brian Paul6fedd4e2004-09-16 19:32:49 +0000207
208 glPushMatrix();
209 glRotatef(15.0, 1.0, 0.0, 0.0);
210 glRotatef(angle, 0.0, 1.0, 0.0);
Brian Paul1a899782003-09-24 20:41:53 +0000211
212 glDepthMask(GL_FALSE);
213
214 /* Draw the floor. */
215/* glEnable(GL_TEXTURE_2D);*/
216 glColor3f(0.1, 0.5, 1.0);
217 glBegin(GL_QUADS);
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);
226 glEnd();
227
228 /* Allow particles to blend with each other. */
229 glDepthMask(GL_TRUE);
230
231 if (blend)
232 glEnable(GL_BLEND);
233
Daniel Borcaa9ea1622004-09-13 08:47:01 +0000234 if (sprite) {
235 glEnable(GL_TEXTURE_2D);
Brian Paul1a899782003-09-24 20:41:53 +0000236#ifdef GL_ARB_point_sprite
Daniel Borcaa9ea1622004-09-13 08:47:01 +0000237 glEnable(GL_POINT_SPRITE_ARB);
Brian Paul1a899782003-09-24 20:41:53 +0000238#endif
Daniel Borcaa9ea1622004-09-13 08:47:01 +0000239 }
Brian Paul1a899782003-09-24 20:41:53 +0000240
241 glColor3f(1,1,1);
242 glBegin(GL_POINTS);
243 for (i=0; i<numPoints; i++) {
244 /* Draw alive particles. */
245 if (colorList[i] != DEAD) {
Daniel Borcaa9ea1622004-09-13 08:47:01 +0000246 if (!sprite) glColor4fv(colorSet[colorList[i]]);
Brian Paul1a899782003-09-24 20:41:53 +0000247 glVertex3fv(pointList[i]);
248 }
249 }
250 glEnd();
251
252 glDisable(GL_TEXTURE_2D);
253#ifdef GL_ARB_point_sprite
254 glDisable(GL_POINT_SPRITE_ARB);
255#endif
256 glDisable(GL_BLEND);
257
Brian Paul6fedd4e2004-09-16 19:32:49 +0000258 glPopMatrix();
259
Brian Paul1a899782003-09-24 20:41:53 +0000260 glutSwapBuffers();
261}
262
263/* ARGSUSED2 */
264static void
265mouse(int button, int state, int x, int y)
266{
267 /* Scene can be spun around Y axis using left
268 mouse button movement. */
269 if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
270 moving = 1;
271 begin = x;
272 }
273 if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
274 moving = 0;
275 }
276}
277
278/* ARGSUSED1 */
279static void
280mouseMotion(int x, int y)
281{
282 if (moving) {
283 angle = angle + (x - begin);
284 begin = x;
Brian Paul1a899782003-09-24 20:41:53 +0000285 glutPostRedisplay();
286 }
287}
288
289static void
290menu(int option)
291{
292 switch (option) {
293 case 0:
294 makePointList();
295 break;
Brian Paul6fedd4e2004-09-16 19:32:49 +0000296#ifdef GL_ARB_point_parameters
Brian Paul1a899782003-09-24 20:41:53 +0000297 case 1:
298 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, constant);
299 break;
300 case 2:
301 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, linear);
302 break;
303 case 3:
304 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
305 break;
306#endif
307 case 4:
308 blend = 1;
309 break;
310 case 5:
311 blend = 0;
312 break;
Brian Paul6fedd4e2004-09-16 19:32:49 +0000313#ifdef GL_ARB_point_parameters
Brian Paul1a899782003-09-24 20:41:53 +0000314 case 6:
315 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1.0);
316 break;
317 case 7:
318 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 10.0);
319 break;
320#endif
321 case 8:
322 glEnable(GL_POINT_SMOOTH);
Daniel Borcaa9ea1622004-09-13 08:47:01 +0000323 smooth = 1;
Brian Paul1a899782003-09-24 20:41:53 +0000324 break;
325 case 9:
326 glDisable(GL_POINT_SMOOTH);
Daniel Borcaa9ea1622004-09-13 08:47:01 +0000327 smooth = 0;
Brian Paul1a899782003-09-24 20:41:53 +0000328 break;
329 case 10:
330 glPointSize(4.0);
331 break;
332 case 11:
333 glPointSize(8.0);
334 break;
335 case 12:
336 glPointSize(16.0);
337 break;
338 case 13:
339 spin = 1 - spin;
340 if (animate && (spin || motion)) {
341 glutIdleFunc(idle);
342 } else {
343 glutIdleFunc(NULL);
344 }
345 break;
346 case 14:
347 numPoints = 200;
348 break;
349 case 15:
350 numPoints = 500;
351 break;
352 case 16:
353 numPoints = 1000;
354 break;
355 case 17:
356 numPoints = 2000;
357 break;
358 case 666:
359 exit(0);
360 }
361 glutPostRedisplay();
362}
363
364/* ARGSUSED1 */
365static void
366key(unsigned char c, int x, int y)
367{
368 switch (c) {
369 case 13:
370 animate = 1 - animate; /* toggle. */
371 if (animate && (motion || spin)) {
372 glutIdleFunc(idle);
373 } else {
374 glutIdleFunc(NULL);
375 }
376 break;
377 case ' ':
378 animate = 1;
379 makePointList();
380 glutIdleFunc(idle);
381 break;
Daniel Borcaa9ea1622004-09-13 08:47:01 +0000382 case 'o':
383 case 'O':
384 org ^= 1;
Brian Paul6fedd4e2004-09-16 19:32:49 +0000385#ifdef GL_VERSION_2_0
386#ifdef GL_ARB_point_parameters
Daniel Borcaa9ea1622004-09-13 08:47:01 +0000387 glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN,
388 org ? GL_LOWER_LEFT : GL_UPPER_LEFT);
389#endif
390#endif
391 glutPostRedisplay();
392 break;
393 case 't':
394 case 'T':
395 sprite ^= 1;
396 glutPostRedisplay();
397 break;
398 case 's':
399 case 'S':
400 (smooth ^= 1) ? glEnable(GL_POINT_SMOOTH) : glDisable(GL_POINT_SMOOTH);
401 glutPostRedisplay();
402 break;
403 case '0':
404 glPointSize(1.0);
405 glutPostRedisplay();
406 break;
407 case '1':
408 glPointSize(2.0);
409 glutPostRedisplay();
410 break;
411 case '2':
412 glPointSize(4.0);
413 glutPostRedisplay();
414 break;
415 case '3':
416 glPointSize(8.0);
417 glutPostRedisplay();
418 break;
419 case '4':
420 glPointSize(16.0);
421 glutPostRedisplay();
422 break;
Brian Paul1a899782003-09-24 20:41:53 +0000423 case 27:
424 exit(0);
425 }
426}
427
428
429
430static void
431makeSprite(void)
432{
433 GLubyte texture[16][16][4];
434 int i, j;
435
436 if (!glutExtensionSupported("GL_ARB_point_sprite")) {
437 printf("Sorry, this demo requires GL_ARB_point_sprite.\n");
438 exit(0);
439 }
440 if (!glutExtensionSupported("GL_ARB_point_parameters")) {
441 printf("Sorry, this demo requires GL_ARB_point_parameters.\n");
442 exit(0);
443 }
444
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;
452 }
453 else {
454 texture[i][j][0] = 255;
455 texture[i][j][1] = 0;
456 texture[i][j][2] = 0;
457 texture[i][j][3] = 0;
458 }
459 }
460 }
461
462 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
463 texture);
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);
468#endif
469}
470
471
472static void
473reshape(int width, int height)
474{
475 GLfloat h = (GLfloat) height / (GLfloat) width;
476
477 glViewport(0, 0, (GLint) width, (GLint) height);
478 glMatrixMode(GL_PROJECTION);
479 glLoadIdentity();
Brian Paul6fedd4e2004-09-16 19:32:49 +0000480 glFrustum(-1.0, 1.0, -h, h, 2.0, 30.0);
Brian Paul1a899782003-09-24 20:41:53 +0000481 glMatrixMode(GL_MODELVIEW);
482 glLoadIdentity();
Brian Paul6fedd4e2004-09-16 19:32:49 +0000483 glTranslatef(0.0, 0.0, -10.0);
Brian Paul1a899782003-09-24 20:41:53 +0000484}
485
486int
487main(int argc, char **argv)
488{
489 int i;
490 glutInit(&argc, argv);
491 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
492
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])) {
498 useMipmaps = 0;
499 } else if(!strcmp("-nearest", argv[i])) {
500 linearFiltering = 0;
501 }
502 }
Keith Whitwelleabe7be2004-01-28 10:09:59 +0000503 glutInitWindowPosition(0, 0);
Brian Paul1a899782003-09-24 20:41:53 +0000504 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);
533
534 glShadeModel(GL_FLAT);
535 glEnable(GL_DEPTH_TEST);
536 glEnable(GL_POINT_SMOOTH);
537 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
538 glPointSize(16.0);
Brian Paul6fedd4e2004-09-16 19:32:49 +0000539#ifdef GL_ARB_point_parameters
Brian Paul1a899782003-09-24 20:41:53 +0000540 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
541#endif
Brian Paul1a899782003-09-24 20:41:53 +0000542
543 makePointList();
544 makeSprite();
545
546 glutMainLoop();
547 return 0; /* ANSI C requires main to return int. */
548}