Merge commit 'origin/gallium-0.1'
[mesa.git] / progs / demos / spriteblast.c
1
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 #include <GL/glew.h>
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
36 static GLfloat angle = -150; /* in degrees */
37 static int spin = 0;
38 static int moving, begin;
39 static float theTime;
40 static int repeat = 1;
41 static int blend = 1;
42 int useMipmaps = 1;
43 int linearFiltering = 1;
44
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 };
48
49 #define MAX_POINTS 2000
50
51 static int numPoints = 200;
52
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;
59
60 static 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 */
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 }
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
101 static 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
108 /* Modeling units of ground extent in each X and Z direction. */
109 #define EDGE 12
110
111 static void
112 makePointList(void)
113 {
114 float angle, velocity, direction;
115 int i;
116
117 motion = 1;
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;
122 pointTime[i] = 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;
131 }
132 theTime = 0.0;
133 }
134
135 static void
136 updatePointList(void)
137 {
138 float distance;
139 int i;
140
141 static double t0 = -1.;
142 double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
143 if (t0 < 0.0)
144 t0 = t;
145 dt = t - t0;
146 t0 = t;
147
148 motion = 0;
149 for (i=0; i<numPoints; i++) {
150 distance = pointVelocity[i][0] * theTime;
151
152 /* X and Z */
153 pointList[i][0] = pointDirection[i][0] * distance;
154 pointList[i][2] = pointDirection[i][1] * distance;
155
156 /* Z */
157 pointList[i][1] =
158 (pointVelocity[i][1] - 0.5 * GRAVITY * pointTime[i])*pointTime[i];
159
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. */
166 continue;
167 }
168
169 pointVelocity[i][1] *= 0.8; /* 80% of previous up velocity. */
170 pointTime[i] = 0.0; /* Reset the particles sense of up time. */
171 }
172 motion = 1;
173 pointTime[i] += dt;
174 }
175 theTime += dt;
176 if (!motion && !spin) {
177 if (repeat) {
178 makePointList();
179 } else {
180 glutIdleFunc(NULL);
181 }
182 }
183 }
184
185 static void
186 idle(void)
187 {
188 updatePointList();
189 if (spin) {
190 angle += 0.3;
191 }
192 glutPostRedisplay();
193 }
194
195 static void
196 visible(int vis)
197 {
198 if (vis == GLUT_VISIBLE) {
199 if (animate && (motion || spin)) {
200 glutIdleFunc(idle);
201 }
202 } else {
203 glutIdleFunc(NULL);
204 }
205 }
206
207 static void
208 redraw(void)
209 {
210 int i;
211
212 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
213
214 glPushMatrix();
215 glRotatef(15.0, 1.0, 0.0, 0.0);
216 glRotatef(angle, 0.0, 1.0, 0.0);
217
218 glDepthMask(GL_FALSE);
219
220 /* Draw the floor. */
221 /* glEnable(GL_TEXTURE_2D);*/
222 glColor3f(0.1, 0.5, 1.0);
223 glBegin(GL_QUADS);
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);
232 glEnd();
233
234 /* Allow particles to blend with each other. */
235 glDepthMask(GL_TRUE);
236
237 if (blend)
238 glEnable(GL_BLEND);
239
240 if (sprite) {
241 glEnable(GL_TEXTURE_2D);
242 #ifdef GL_ARB_point_sprite
243 glEnable(GL_POINT_SPRITE_ARB);
244 #endif
245 }
246
247 glColor3f(1,1,1);
248 glBegin(GL_POINTS);
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]);
254 }
255 }
256 glEnd();
257
258 glDisable(GL_TEXTURE_2D);
259 #ifdef GL_ARB_point_sprite
260 glDisable(GL_POINT_SPRITE_ARB);
261 #endif
262 glDisable(GL_BLEND);
263
264 glPopMatrix();
265
266 glutSwapBuffers();
267 }
268
269 /* ARGSUSED2 */
270 static void
271 mouse(int button, int state, int x, int y)
272 {
273 /* Scene can be spun around Y axis using left
274 mouse button movement. */
275 if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
276 moving = 1;
277 begin = x;
278 }
279 if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
280 moving = 0;
281 }
282 }
283
284 /* ARGSUSED1 */
285 static void
286 mouseMotion(int x, int y)
287 {
288 if (moving) {
289 angle = angle + (x - begin);
290 begin = x;
291 glutPostRedisplay();
292 }
293 }
294
295 static void
296 menu(int option)
297 {
298 switch (option) {
299 case 0:
300 makePointList();
301 break;
302 #ifdef 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 #ifdef 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 smooth = 1;
330 break;
331 case 9:
332 glDisable(GL_POINT_SMOOTH);
333 smooth = 0;
334 break;
335 case 10:
336 glPointSize(16.0);
337 break;
338 case 11:
339 glPointSize(32.0);
340 break;
341 case 12:
342 glPointSize(64.0);
343 break;
344 case 13:
345 spin = 1 - spin;
346 if (animate && (spin || motion)) {
347 glutIdleFunc(idle);
348 } else {
349 glutIdleFunc(NULL);
350 }
351 break;
352 case 14:
353 numPoints = 200;
354 break;
355 case 15:
356 numPoints = 500;
357 break;
358 case 16:
359 numPoints = 1000;
360 break;
361 case 17:
362 numPoints = 2000;
363 break;
364 case 666:
365 exit(0);
366 }
367 glutPostRedisplay();
368 }
369
370 /* ARGSUSED1 */
371 static void
372 key(unsigned char c, int x, int y)
373 {
374 switch (c) {
375 case 13:
376 animate = 1 - animate; /* toggle. */
377 if (animate && (motion || spin)) {
378 glutIdleFunc(idle);
379 } else {
380 glutIdleFunc(NULL);
381 }
382 break;
383 case ' ':
384 animate = 1;
385 makePointList();
386 glutIdleFunc(idle);
387 break;
388 case 'o':
389 case 'O':
390 org ^= 1;
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);
395 #endif
396 #endif
397 glutPostRedisplay();
398 break;
399 case 't':
400 case 'T':
401 sprite ^= 1;
402 glutPostRedisplay();
403 break;
404 case 's':
405 case 'S':
406 (smooth ^= 1) ? glEnable(GL_POINT_SMOOTH) : glDisable(GL_POINT_SMOOTH);
407 glutPostRedisplay();
408 break;
409 case '0':
410 glPointSize(1.0);
411 glutPostRedisplay();
412 break;
413 case '1':
414 glPointSize(16.0);
415 glutPostRedisplay();
416 break;
417 case '2':
418 glPointSize(32.0);
419 glutPostRedisplay();
420 break;
421 case '3':
422 glPointSize(64.0);
423 glutPostRedisplay();
424 break;
425 case '4':
426 glPointSize(128.0);
427 glutPostRedisplay();
428 break;
429 case 27:
430 exit(0);
431 }
432 }
433
434
435
436 static void
437 makeSprite(void)
438 {
439 GLubyte texture[16][16][4];
440 int i, j;
441
442 if (!glutExtensionSupported("GL_ARB_point_sprite")) {
443 printf("Sorry, this demo requires GL_ARB_point_sprite.\n");
444 exit(0);
445 }
446 if (!glutExtensionSupported("GL_ARB_point_parameters")) {
447 printf("Sorry, this demo requires GL_ARB_point_parameters.\n");
448 exit(0);
449 }
450
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;
458 }
459 else {
460 texture[i][j][0] = 255;
461 texture[i][j][1] = 0;
462 texture[i][j][2] = 0;
463 texture[i][j][3] = 0;
464 }
465 }
466 }
467
468 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
469 texture);
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);
474 #endif
475 }
476
477
478 static void
479 reshape(int width, int height)
480 {
481 GLfloat h = (GLfloat) height / (GLfloat) width;
482
483 glViewport(0, 0, (GLint) width, (GLint) height);
484 glMatrixMode(GL_PROJECTION);
485 glLoadIdentity();
486 glFrustum(-1.0, 1.0, -h, h, 2.0, 30.0);
487 glMatrixMode(GL_MODELVIEW);
488 glLoadIdentity();
489 glTranslatef(0.0, 0.0, -10.0);
490 }
491
492 int
493 main(int argc, char **argv)
494 {
495 int i;
496 glutInit(&argc, argv);
497 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
498
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])) {
504 useMipmaps = 0;
505 } else if(!strcmp("-nearest", argv[i])) {
506 linearFiltering = 0;
507 }
508 }
509 glutInitWindowPosition(0, 0);
510 glutInitWindowSize(600,300);
511 glutCreateWindow("sprite blast");
512 glewInit();
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);
540
541 makePointList();
542 makeSprite();
543
544 glShadeModel(GL_FLAT);
545 glEnable(GL_DEPTH_TEST);
546 glEnable(GL_POINT_SMOOTH);
547 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
548 glPointSize(32.0);
549 #ifdef GL_ARB_point_parameters
550 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
551 #endif
552
553 glutMainLoop();
554 return 0; /* ANSI C requires main to return int. */
555 }