clean-up the hokey transformation code so that window resizes actually work
[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 #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
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 #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
112 static void
113 makePointList(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
136 static void
137 updatePointList(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
179 static void
180 idle(void)
181 {
182 updatePointList();
183 if (spin) {
184 angle += 0.3;
185 }
186 glutPostRedisplay();
187 }
188
189 static void
190 visible(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
201 static void
202 redraw(void)
203 {
204 int i;
205
206 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
207
208 glPushMatrix();
209 glRotatef(15.0, 1.0, 0.0, 0.0);
210 glRotatef(angle, 0.0, 1.0, 0.0);
211
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
234 if (sprite) {
235 glEnable(GL_TEXTURE_2D);
236 #ifdef GL_ARB_point_sprite
237 glEnable(GL_POINT_SPRITE_ARB);
238 #endif
239 }
240
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) {
246 if (!sprite) glColor4fv(colorSet[colorList[i]]);
247 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
258 glPopMatrix();
259
260 glutSwapBuffers();
261 }
262
263 /* ARGSUSED2 */
264 static void
265 mouse(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 */
279 static void
280 mouseMotion(int x, int y)
281 {
282 if (moving) {
283 angle = angle + (x - begin);
284 begin = x;
285 glutPostRedisplay();
286 }
287 }
288
289 static void
290 menu(int option)
291 {
292 switch (option) {
293 case 0:
294 makePointList();
295 break;
296 #ifdef GL_ARB_point_parameters
297 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;
313 #ifdef GL_ARB_point_parameters
314 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);
323 smooth = 1;
324 break;
325 case 9:
326 glDisable(GL_POINT_SMOOTH);
327 smooth = 0;
328 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 */
365 static void
366 key(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;
382 case 'o':
383 case 'O':
384 org ^= 1;
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);
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;
423 case 27:
424 exit(0);
425 }
426 }
427
428
429
430 static void
431 makeSprite(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
472 static void
473 reshape(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();
480 glFrustum(-1.0, 1.0, -h, h, 2.0, 30.0);
481 glMatrixMode(GL_MODELVIEW);
482 glLoadIdentity();
483 glTranslatef(0.0, 0.0, -10.0);
484 }
485
486 int
487 main(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 }
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);
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);
539 #ifdef GL_ARB_point_parameters
540 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
541 #endif
542
543 makePointList();
544 makeSprite();
545
546 glutMainLoop();
547 return 0; /* ANSI C requires main to return int. */
548 }