changes towards GL_ARB_point_sprite (two-zero)
[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 int newModel = 1;
40 static float theTime;
41 static int repeat = 1;
42 static int blend = 1;
43 int useMipmaps = 1;
44 int linearFiltering = 1;
45
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 };
49
50 #define MAX_POINTS 2000
51
52 static int numPoints = 200;
53
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;
60
61 static 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 */
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 }
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
102 static 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
113 static void
114 makePointList(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
137 static void
138 updatePointList(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
180 static void
181 idle(void)
182 {
183 updatePointList();
184 if (spin) {
185 angle += 0.3;
186 newModel = 1;
187 }
188 glutPostRedisplay();
189 }
190
191 static void
192 visible(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
203 static void
204 recalcModelView(void)
205 {
206 glPopMatrix();
207 glPushMatrix();
208 glRotatef(angle, 0.0, 1.0, 0.0);
209 newModel = 0;
210 }
211
212 static void
213 redraw(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 if (sprite) {
244 glEnable(GL_TEXTURE_2D);
245 #ifdef GL_ARB_point_sprite
246 glEnable(GL_POINT_SPRITE_ARB);
247 #endif
248 }
249
250 glColor3f(1,1,1);
251 glBegin(GL_POINTS);
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]);
257 }
258 }
259 glEnd();
260
261 glDisable(GL_TEXTURE_2D);
262 #ifdef GL_ARB_point_sprite
263 glDisable(GL_POINT_SPRITE_ARB);
264 #endif
265 glDisable(GL_BLEND);
266
267 glutSwapBuffers();
268 }
269
270 /* ARGSUSED2 */
271 static void
272 mouse(int button, int state, int x, int y)
273 {
274 /* Scene can be spun around Y axis using left
275 mouse button movement. */
276 if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
277 moving = 1;
278 begin = x;
279 }
280 if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
281 moving = 0;
282 }
283 }
284
285 /* ARGSUSED1 */
286 static void
287 mouseMotion(int x, int y)
288 {
289 if (moving) {
290 angle = angle + (x - begin);
291 begin = x;
292 newModel = 1;
293 glutPostRedisplay();
294 }
295 }
296
297 static void
298 menu(int option)
299 {
300 switch (option) {
301 case 0:
302 makePointList();
303 break;
304 #if GL_ARB_point_parameters
305 case 1:
306 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, constant);
307 break;
308 case 2:
309 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, linear);
310 break;
311 case 3:
312 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
313 break;
314 #endif
315 case 4:
316 blend = 1;
317 break;
318 case 5:
319 blend = 0;
320 break;
321 #if GL_ARB_point_parameters
322 case 6:
323 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1.0);
324 break;
325 case 7:
326 glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 10.0);
327 break;
328 #endif
329 case 8:
330 glEnable(GL_POINT_SMOOTH);
331 smooth = 1;
332 break;
333 case 9:
334 glDisable(GL_POINT_SMOOTH);
335 smooth = 0;
336 break;
337 case 10:
338 glPointSize(4.0);
339 break;
340 case 11:
341 glPointSize(8.0);
342 break;
343 case 12:
344 glPointSize(16.0);
345 break;
346 case 13:
347 spin = 1 - spin;
348 if (animate && (spin || motion)) {
349 glutIdleFunc(idle);
350 } else {
351 glutIdleFunc(NULL);
352 }
353 break;
354 case 14:
355 numPoints = 200;
356 break;
357 case 15:
358 numPoints = 500;
359 break;
360 case 16:
361 numPoints = 1000;
362 break;
363 case 17:
364 numPoints = 2000;
365 break;
366 case 666:
367 exit(0);
368 }
369 glutPostRedisplay();
370 }
371
372 /* ARGSUSED1 */
373 static void
374 key(unsigned char c, int x, int y)
375 {
376 switch (c) {
377 case 13:
378 animate = 1 - animate; /* toggle. */
379 if (animate && (motion || spin)) {
380 glutIdleFunc(idle);
381 } else {
382 glutIdleFunc(NULL);
383 }
384 break;
385 case ' ':
386 animate = 1;
387 makePointList();
388 glutIdleFunc(idle);
389 break;
390 case 'o':
391 case 'O':
392 org ^= 1;
393 #if GL_VERSION_2_0
394 #if GL_ARB_point_parameters
395 glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN,
396 org ? GL_LOWER_LEFT : GL_UPPER_LEFT);
397 #endif
398 #endif
399 glutPostRedisplay();
400 break;
401 case 't':
402 case 'T':
403 sprite ^= 1;
404 glutPostRedisplay();
405 break;
406 case 's':
407 case 'S':
408 (smooth ^= 1) ? glEnable(GL_POINT_SMOOTH) : glDisable(GL_POINT_SMOOTH);
409 glutPostRedisplay();
410 break;
411 case '0':
412 glPointSize(1.0);
413 glutPostRedisplay();
414 break;
415 case '1':
416 glPointSize(2.0);
417 glutPostRedisplay();
418 break;
419 case '2':
420 glPointSize(4.0);
421 glutPostRedisplay();
422 break;
423 case '3':
424 glPointSize(8.0);
425 glutPostRedisplay();
426 break;
427 case '4':
428 glPointSize(16.0);
429 glutPostRedisplay();
430 break;
431 case 27:
432 exit(0);
433 }
434 }
435
436
437
438 static void
439 makeSprite(void)
440 {
441 GLubyte texture[16][16][4];
442 int i, j;
443
444 if (!glutExtensionSupported("GL_ARB_point_sprite")) {
445 printf("Sorry, this demo requires GL_ARB_point_sprite.\n");
446 exit(0);
447 }
448 if (!glutExtensionSupported("GL_ARB_point_parameters")) {
449 printf("Sorry, this demo requires GL_ARB_point_parameters.\n");
450 exit(0);
451 }
452
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;
460 }
461 else {
462 texture[i][j][0] = 255;
463 texture[i][j][1] = 0;
464 texture[i][j][2] = 0;
465 texture[i][j][3] = 0;
466 }
467 }
468 }
469
470 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
471 texture);
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);
476 #endif
477 }
478
479
480 static void
481 reshape(int width, int height)
482 {
483 GLfloat h = (GLfloat) height / (GLfloat) width;
484
485 glViewport(0, 0, (GLint) width, (GLint) height);
486 glMatrixMode(GL_PROJECTION);
487 glLoadIdentity();
488 glFrustum(-1.0, 1.0, -h, h, 2.0, 20.0);
489 glMatrixMode(GL_MODELVIEW);
490 glLoadIdentity();
491 glTranslatef(0.0, 0.0, -60.0);
492 }
493
494 int
495 main(int argc, char **argv)
496 {
497 int i;
498 glutInit(&argc, argv);
499 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
500
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])) {
506 useMipmaps = 0;
507 } else if(!strcmp("-nearest", argv[i])) {
508 linearFiltering = 0;
509 }
510 }
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);
541
542 glShadeModel(GL_FLAT);
543 glEnable(GL_DEPTH_TEST);
544 glEnable(GL_POINT_SMOOTH);
545 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
546 glPointSize(16.0);
547 #if GL_ARB_point_parameters
548 glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
549 #endif
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
559 recalc */
560
561 makePointList();
562 makeSprite();
563
564 glutMainLoop();
565 return 0; /* ANSI C requires main to return int. */
566 }