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