s/DP4/DP3/
[mesa.git] / progs / demos / ipers.c
1 /*
2 * This program is under the GNU GPL.
3 * Use at your own risk.
4 *
5 * written by David Bucciarelli (tech.hmw@plus.it)
6 * Humanware s.r.l.
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <math.h>
12 #include <time.h>
13
14 #if defined (WIN32)|| defined(_WIN32)
15 #include <windows.h>
16 #include <mmsystem.h>
17 #endif
18
19 #include <GL/glut.h>
20
21 #include "readtex.c"
22
23 #ifdef XMESA
24 #include "GL/xmesa.h"
25 static int fullscreen = 1;
26 #endif
27
28 static int WIDTH = 640;
29 static int HEIGHT = 480;
30
31 static GLint T0;
32 static GLint Frames;
33
34 #define MAX_LOD 9
35
36 #define TEX_SKY_WIDTH 256
37 #define TEX_SKY_HEIGHT TEX_SKY_WIDTH
38
39 #ifndef M_PI
40 #define M_PI 3.1415926535
41 #endif
42
43 #define FROM_NONE 0
44 #define FROM_DOWN 1
45 #define FROM_UP 2
46 #define FROM_LEFT 3
47 #define FROM_RIGHT 4
48 #define FROM_FRONT 5
49 #define FROM_BACK 6
50
51 static int win = 0;
52
53 static float obs[3] = { 3.8, 0.0, 0.0 };
54 static float dir[3];
55 static float v = 0.0;
56 static float alpha = -90.0;
57 static float beta = 90.0;
58
59 static int fog = 1;
60 static int bfcull = 1;
61 static int usetex = 1;
62 static int help = 1;
63 static int poutline = 0;
64 static int normext = 1;
65 static int joyavailable = 0;
66 static int joyactive = 0;
67 static int LODbias = 3;
68 static int maxdepth = MAX_LOD;
69
70 static unsigned int totpoly = 0;
71
72 static GLuint t1id, t2id;
73 static GLuint skydlist, LODdlist[MAX_LOD], LODnumpoly[MAX_LOD];
74
75 static void
76 initlight(void)
77 {
78 GLfloat lspec[4] = { 1.0, 1.0, 1.0, 1.0 };
79 static GLfloat lightpos[4] = { 30, 15.0, 30.0, 1.0 };
80
81 glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
82 glLightfv(GL_LIGHT0, GL_SPECULAR, lspec);
83
84 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 32.0);
85 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, lspec);
86 }
87
88 static void
89 initdlists(void)
90 {
91 static int slicetable[MAX_LOD][2] = {
92 {21, 10},
93 {18, 9},
94 {15, 8},
95 {12, 7},
96 {9, 6},
97 {7, 5},
98 {5, 4},
99 {4, 3},
100 {3, 2}
101 };
102 GLUquadricObj *obj;
103 int i, xslices, yslices;
104
105 obj = gluNewQuadric();
106
107 skydlist = glGenLists(1);
108 glNewList(skydlist, GL_COMPILE);
109 glBindTexture(GL_TEXTURE_2D, t2id);
110 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
111 glColor3f(1.0f, 1.0f, 1.0f);
112
113 gluQuadricDrawStyle(obj, GLU_FILL);
114 gluQuadricNormals(obj, GLU_NONE);
115 gluQuadricTexture(obj, GL_TRUE);
116 gluQuadricOrientation(obj, GLU_INSIDE);
117 gluSphere(obj, 40.0f, 18, 9);
118
119 glEndList();
120
121 for (i = 0; i < MAX_LOD; i++) {
122 LODdlist[i] = glGenLists(1);
123 glNewList(LODdlist[i], GL_COMPILE);
124
125 gluQuadricDrawStyle(obj, GLU_FILL);
126 gluQuadricNormals(obj, GLU_SMOOTH);
127 gluQuadricTexture(obj, GL_TRUE);
128 gluQuadricOrientation(obj, GLU_OUTSIDE);
129 xslices = slicetable[i][0];
130 yslices = slicetable[i][1];
131 gluSphere(obj, 1.0f, xslices, yslices);
132 LODnumpoly[i] = xslices * (yslices - 2) + 2 * (xslices - 1);
133
134 glEndList();
135 }
136 }
137
138 static void
139 inittextures(void)
140 {
141 GLubyte tsky[TEX_SKY_HEIGHT][TEX_SKY_WIDTH][3];
142 GLuint x, y;
143 GLfloat fact;
144 GLenum gluerr;
145
146 /* Brick */
147
148 glGenTextures(1, &t1id);
149 glBindTexture(GL_TEXTURE_2D, t1id);
150
151 if (!LoadRGBMipmaps("../images/bw.rgb", 3)) {
152 fprintf(stderr, "Error reading a texture.\n");
153 exit(-1);
154 }
155
156 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
157 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
158
159 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
160 GL_LINEAR_MIPMAP_LINEAR);
161 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
162
163 /* Sky */
164
165 glGenTextures(1, &t2id);
166 glBindTexture(GL_TEXTURE_2D, t2id);
167
168 for (y = 0; y < TEX_SKY_HEIGHT; y++)
169 for (x = 0; x < TEX_SKY_WIDTH; x++)
170 if (y < TEX_SKY_HEIGHT / 2) {
171 fact = y / (GLfloat) (TEX_SKY_HEIGHT / 2);
172 tsky[y][x][0] =
173 (GLubyte) (255.0f * (0.1f * fact + 0.3f * (1.0f - fact)));
174 tsky[y][x][1] =
175 (GLubyte) (255.0f * (0.2f * fact + 1.0f * (1.0f - fact)));
176 tsky[y][x][2] = 255;
177 }
178 else {
179 tsky[y][x][0] = tsky[TEX_SKY_HEIGHT - y - 1][x][0];
180 tsky[y][x][1] = tsky[TEX_SKY_HEIGHT - y - 1][x][1];
181 tsky[y][x][2] = 255;
182 }
183
184 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
185 if (
186 (gluerr =
187 gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TEX_SKY_WIDTH, TEX_SKY_HEIGHT,
188 GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *) (tsky)))) {
189 fprintf(stderr, "GLULib%s\n", (char *) gluErrorString(gluerr));
190 exit(-1);
191 }
192
193 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
194 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
195
196 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
197 GL_LINEAR_MIPMAP_LINEAR);
198 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
199 }
200
201 static void
202 calcposobs(void)
203 {
204 dir[0] = sin(alpha * M_PI / 180.0);
205 dir[1] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0);
206 dir[2] = cos(beta * M_PI / 180.0);
207
208 if (dir[0] < 1.0e-5 && dir[0] > -1.0e-5)
209 dir[0] = 0;
210 if (dir[1] < 1.0e-5 && dir[1] > -1.0e-5)
211 dir[1] = 0;
212 if (dir[2] < 1.0e-5 && dir[2] > -1.0e-5)
213 dir[2] = 0;
214
215 obs[0] += v * dir[0];
216 obs[1] += v * dir[1];
217 obs[2] += v * dir[2];
218 }
219
220 static void
221 special(int k, int x, int y)
222 {
223 switch (k) {
224 case GLUT_KEY_LEFT:
225 alpha -= 2.0;
226 break;
227 case GLUT_KEY_RIGHT:
228 alpha += 2.0;
229 break;
230 case GLUT_KEY_DOWN:
231 beta -= 2.0;
232 break;
233 case GLUT_KEY_UP:
234 beta += 2.0;
235 break;
236 }
237 }
238
239 static void
240 key(unsigned char k, int x, int y)
241 {
242 switch (k) {
243 case 27:
244 exit(0);
245 break;
246
247 case 'a':
248 v += 0.01;
249 break;
250 case 'z':
251 v -= 0.01;
252 break;
253
254 #ifdef XMESA
255 case ' ':
256 fullscreen = (!fullscreen);
257 XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
258 break;
259 #endif
260
261 case '+':
262 LODbias--;
263 break;
264 case '-':
265 LODbias++;
266 break;
267 case 'j':
268 joyactive = (!joyactive);
269 break;
270 case 'h':
271 help = (!help);
272 break;
273 case 'f':
274 fog = (!fog);
275 break;
276 case 't':
277 usetex = (!usetex);
278 break;
279 case 'n':
280 normext = (!normext);
281 break;
282 case 'b':
283 if (bfcull) {
284 glDisable(GL_CULL_FACE);
285 bfcull = 0;
286 }
287 else {
288 glEnable(GL_CULL_FACE);
289 bfcull = 1;
290 }
291 break;
292 case 'p':
293 if (poutline) {
294 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
295 poutline = 0;
296 usetex = 1;
297 }
298 else {
299 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
300 poutline = 1;
301 usetex = 0;
302 }
303 break;
304 }
305 }
306
307 static void
308 reshape(int w, int h)
309 {
310 WIDTH = w;
311 HEIGHT = h;
312 glMatrixMode(GL_PROJECTION);
313 glLoadIdentity();
314 gluPerspective(90.0, w / (float) h, 0.8, 100.0);
315 glMatrixMode(GL_MODELVIEW);
316 glLoadIdentity();
317 glViewport(0, 0, w, h);
318 }
319
320 static void
321 printstring(void *font, char *string)
322 {
323 int len, i;
324
325 len = (int) strlen(string);
326 for (i = 0; i < len; i++)
327 glutBitmapCharacter(font, string[i]);
328 }
329
330 static void
331 printhelp(void)
332 {
333 glEnable(GL_BLEND);
334 glColor4f(0.5, 0.5, 0.5, 0.5);
335 glRecti(40, 40, 600, 440);
336 glDisable(GL_BLEND);
337
338 glColor3f(1.0, 0.0, 0.0);
339 glRasterPos2i(300, 420);
340 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Help");
341
342 glRasterPos2i(60, 390);
343 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "h - Toggle Help");
344 glRasterPos2i(60, 360);
345 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "t - Toggle Textures");
346 glRasterPos2i(60, 330);
347 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "f - Toggle Fog");
348 glRasterPos2i(60, 300);
349 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "b - Toggle Back face culling");
350 glRasterPos2i(60, 270);
351 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Arrow Keys - Rotate");
352 glRasterPos2i(60, 240);
353 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "a - Increase velocity");
354 glRasterPos2i(60, 210);
355 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "z - Decrease velocity");
356 glRasterPos2i(60, 180);
357 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "p - Toggle Wire frame");
358 glRasterPos2i(60, 150);
359 printstring(GLUT_BITMAP_TIMES_ROMAN_24,
360 "b - Toggle GL_EXT_rescale_normal extension");
361 glRasterPos2i(60, 120);
362 printstring(GLUT_BITMAP_TIMES_ROMAN_24,
363 "+/- - Increase/decrease the Object maximum LOD");
364
365 glRasterPos2i(60, 90);
366 if (joyavailable)
367 printstring(GLUT_BITMAP_TIMES_ROMAN_24,
368 "j - Toggle jostick control (Joystick control available)");
369 else
370 printstring(GLUT_BITMAP_TIMES_ROMAN_24,
371 "(No Joystick control available)");
372 }
373
374 static void
375 dojoy(void)
376 {
377 #ifdef _WIN32
378 static UINT max[2] = { 0, 0 };
379 static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2];
380 MMRESULT res;
381 JOYINFO joy;
382
383 res = joyGetPos(JOYSTICKID1, &joy);
384
385 if (res == JOYERR_NOERROR) {
386 joyavailable = 1;
387
388 if (max[0] < joy.wXpos)
389 max[0] = joy.wXpos;
390 if (min[0] > joy.wXpos)
391 min[0] = joy.wXpos;
392 center[0] = (max[0] + min[0]) / 2;
393
394 if (max[1] < joy.wYpos)
395 max[1] = joy.wYpos;
396 if (min[1] > joy.wYpos)
397 min[1] = joy.wYpos;
398 center[1] = (max[1] + min[1]) / 2;
399
400 if (joyactive) {
401 if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0]))
402 alpha -=
403 2.0 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]);
404 if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1]))
405 beta += 2.0 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]);
406
407 if (joy.wButtons & JOY_BUTTON1)
408 v += 0.01;
409 if (joy.wButtons & JOY_BUTTON2)
410 v -= 0.01;
411 }
412 }
413 else
414 joyavailable = 0;
415 #endif
416 }
417
418 static void
419 drawipers(int depth, int from)
420 {
421 int lod;
422
423 if (depth == maxdepth)
424 return;
425
426 lod = depth + LODbias;
427 if (lod < 0)
428 lod = 0;
429 if (lod >= MAX_LOD)
430 return;
431
432 switch (from) {
433 case FROM_NONE:
434 glCallList(LODdlist[lod]);
435
436 depth++;
437 drawipers(depth, FROM_DOWN);
438 drawipers(depth, FROM_UP);
439 drawipers(depth, FROM_FRONT);
440 drawipers(depth, FROM_BACK);
441 drawipers(depth, FROM_LEFT);
442 drawipers(depth, FROM_RIGHT);
443 break;
444 case FROM_FRONT:
445 glPushMatrix();
446 glTranslatef(0.0f, -1.5f, 0.0f);
447 glScalef(0.5f, 0.5f, 0.5f);
448
449 glCallList(LODdlist[lod]);
450
451 depth++;
452 drawipers(depth, FROM_DOWN);
453 drawipers(depth, FROM_UP);
454 drawipers(depth, FROM_FRONT);
455 drawipers(depth, FROM_LEFT);
456 drawipers(depth, FROM_RIGHT);
457 glPopMatrix();
458 break;
459 case FROM_BACK:
460 glPushMatrix();
461 glTranslatef(0.0f, 1.5f, 0.0f);
462 glScalef(0.5f, 0.5f, 0.5f);
463
464 glCallList(LODdlist[lod]);
465
466 depth++;
467 drawipers(depth, FROM_DOWN);
468 drawipers(depth, FROM_UP);
469 drawipers(depth, FROM_BACK);
470 drawipers(depth, FROM_LEFT);
471 drawipers(depth, FROM_RIGHT);
472 glPopMatrix();
473 break;
474 case FROM_LEFT:
475 glPushMatrix();
476 glTranslatef(-1.5f, 0.0f, 0.0f);
477 glScalef(0.5f, 0.5f, 0.5f);
478
479 glCallList(LODdlist[lod]);
480
481 depth++;
482 drawipers(depth, FROM_DOWN);
483 drawipers(depth, FROM_UP);
484 drawipers(depth, FROM_FRONT);
485 drawipers(depth, FROM_BACK);
486 drawipers(depth, FROM_LEFT);
487 glPopMatrix();
488 break;
489 case FROM_RIGHT:
490 glPushMatrix();
491 glTranslatef(1.5f, 0.0f, 0.0f);
492 glScalef(0.5f, 0.5f, 0.5f);
493
494 glCallList(LODdlist[lod]);
495
496 depth++;
497 drawipers(depth, FROM_DOWN);
498 drawipers(depth, FROM_UP);
499 drawipers(depth, FROM_FRONT);
500 drawipers(depth, FROM_BACK);
501 drawipers(depth, FROM_RIGHT);
502 glPopMatrix();
503 break;
504 case FROM_DOWN:
505 glPushMatrix();
506 glTranslatef(0.0f, 0.0f, 1.5f);
507 glScalef(0.5f, 0.5f, 0.5f);
508
509 glCallList(LODdlist[lod]);
510
511 depth++;
512 drawipers(depth, FROM_DOWN);
513 drawipers(depth, FROM_FRONT);
514 drawipers(depth, FROM_BACK);
515 drawipers(depth, FROM_LEFT);
516 drawipers(depth, FROM_RIGHT);
517 glPopMatrix();
518 break;
519 case FROM_UP:
520 glPushMatrix();
521 glTranslatef(0.0f, 0.0f, -1.5f);
522 glScalef(0.5f, 0.5f, 0.5f);
523
524 glCallList(LODdlist[lod]);
525
526 depth++;
527 drawipers(depth, FROM_UP);
528 drawipers(depth, FROM_FRONT);
529 drawipers(depth, FROM_BACK);
530 drawipers(depth, FROM_LEFT);
531 drawipers(depth, FROM_RIGHT);
532 glPopMatrix();
533 break;
534 }
535
536 totpoly += LODnumpoly[lod];
537 }
538
539 static void
540 draw(void)
541 {
542 static char frbuf[80] = "";
543 static GLfloat alpha = 0.0f;
544 static GLfloat beta = 0.0f;
545 static float fr = 0.0;
546
547 dojoy();
548
549 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
550
551 if (usetex)
552 glEnable(GL_TEXTURE_2D);
553 else
554 glDisable(GL_TEXTURE_2D);
555
556 if (fog)
557 glEnable(GL_FOG);
558 else
559 glDisable(GL_FOG);
560
561 glPushMatrix();
562 calcposobs();
563 gluLookAt(obs[0], obs[1], obs[2],
564 obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2],
565 0.0, 0.0, 1.0);
566
567 /* Scene */
568 glEnable(GL_DEPTH_TEST);
569
570 glShadeModel(GL_SMOOTH);
571 glBindTexture(GL_TEXTURE_2D, t1id);
572 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
573 glColor3f(1.0f, 1.0f, 1.0f);
574 glEnable(GL_LIGHT0);
575 glEnable(GL_LIGHTING);
576
577 if (normext)
578 glEnable(GL_RESCALE_NORMAL_EXT);
579 else
580 glEnable(GL_NORMALIZE);
581
582 glPushMatrix();
583 glRotatef(alpha, 0.0f, 0.0f, 1.0f);
584 glRotatef(beta, 1.0f, 0.0f, 0.0f);
585 totpoly = 0;
586 drawipers(0, FROM_NONE);
587 glPopMatrix();
588
589 alpha += 0.5f;
590 beta += 0.3f;
591
592 glDisable(GL_LIGHTING);
593 glDisable(GL_LIGHT0);
594 glShadeModel(GL_FLAT);
595
596 if (normext)
597 glDisable(GL_RESCALE_NORMAL_EXT);
598 else
599 glDisable(GL_NORMALIZE);
600
601 glCallList(skydlist);
602
603 glPopMatrix();
604
605 /* Help Screen */
606
607 sprintf(frbuf,
608 "Frame rate: %0.2f LOD: %d Tot. poly.: %d Poly/sec: %.1f",
609 fr, LODbias, totpoly, totpoly * fr);
610
611 glDisable(GL_TEXTURE_2D);
612 glDisable(GL_FOG);
613 glShadeModel(GL_FLAT);
614 glDisable(GL_DEPTH_TEST);
615
616 glMatrixMode(GL_PROJECTION);
617 glPushMatrix();
618 glLoadIdentity();
619 glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
620
621 glMatrixMode(GL_MODELVIEW);
622 glLoadIdentity();
623
624 glColor3f(1.0, 0.0, 0.0);
625 glRasterPos2i(10, 10);
626 printstring(GLUT_BITMAP_HELVETICA_18, frbuf);
627 glRasterPos2i(350, 470);
628 printstring(GLUT_BITMAP_HELVETICA_10,
629 "IperS V1.0 Written by David Bucciarelli (tech.hmw@plus.it)");
630
631 if (help)
632 printhelp();
633
634 glMatrixMode(GL_PROJECTION);
635 glPopMatrix();
636 glMatrixMode(GL_MODELVIEW);
637
638 glutSwapBuffers();
639
640 Frames++;
641 {
642 GLint t = glutGet(GLUT_ELAPSED_TIME);
643 if (t - T0 >= 2000) {
644 GLfloat seconds = (t - T0) / 1000.0;
645 fr = Frames / seconds;
646 T0 = t;
647 Frames = 0;
648 }
649 }
650 }
651
652 int
653 main(int ac, char **av)
654 {
655 float fogcolor[4] = { 0.7, 0.7, 0.7, 1.0 };
656
657 fprintf(stderr,
658 "IperS V1.0\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
659
660 glutInitWindowPosition(0, 0);
661 glutInitWindowSize(WIDTH, HEIGHT);
662 glutInit(&ac, av);
663
664 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
665
666 if (!(win = glutCreateWindow("IperS"))) {
667 fprintf(stderr, "Error, couldn't open window\n");
668 exit(-1);
669 }
670
671 reshape(WIDTH, HEIGHT);
672
673 glShadeModel(GL_SMOOTH);
674 glEnable(GL_DEPTH_TEST);
675 glEnable(GL_CULL_FACE);
676 glEnable(GL_TEXTURE_2D);
677
678 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
679
680 glEnable(GL_FOG);
681 glFogi(GL_FOG_MODE, GL_EXP2);
682 glFogfv(GL_FOG_COLOR, fogcolor);
683
684 glFogf(GL_FOG_DENSITY, 0.006);
685
686 glHint(GL_FOG_HINT, GL_NICEST);
687
688 inittextures();
689 initdlists();
690 initlight();
691
692 glClearColor(fogcolor[0], fogcolor[1], fogcolor[2], fogcolor[3]);
693 glClear(GL_COLOR_BUFFER_BIT);
694
695 calcposobs();
696
697 glutReshapeFunc(reshape);
698 glutDisplayFunc(draw);
699 glutKeyboardFunc(key);
700 glutSpecialFunc(special);
701 glutIdleFunc(draw);
702
703 glutMainLoop();
704
705 return 0;
706 }