blob: 2fe1df3a0714da1d6cbc12cdf4caecb56a1b8e50 [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 * based on a Mikael SkiZoWalker's (MoDEL) / France (Skizo@Hol.Fr) demo
9 */
10
11#include <stdio.h>
12#include <math.h>
13#include <stdlib.h>
14#include <time.h>
15
16#ifdef WIN32
17#include <windows.h>
18#endif
19
20#include <GL/glut.h>
21
22#ifdef XMESA
23#include "GL/xmesa.h"
24static int fullscreen = 1;
25#endif
26
27#ifndef M_PI
28#define M_PI 3.14159265
29#endif
30
31#define heightMnt 450
32#define lenghtXmnt 62
33#define lenghtYmnt 62
34
35#define stepXmnt 96.0
36#define stepYmnt 96.0
37
38#define WIDTH 640
39#define HEIGHT 480
40
Brian Pauld49b34a2000-09-12 18:44:45 +000041static GLint T0 = 0;
42static GLint Frames = 0;
Brian Paul5b0a7f32000-06-27 16:52:38 +000043
Brian Pauld49b34a2000-09-12 18:44:45 +000044#define TSCALE 4
Brian Paul5b0a7f32000-06-27 16:52:38 +000045
46#define FOV 85
47
48static GLfloat terrain[256 * 256];
49static GLfloat terraincolor[256 * 256][3];
50
51static int win = 0;
52
53static int fog = 1;
54static int bfcull = 1;
55static int usetex = 1;
56static int poutline = 0;
57static int help = 1;
58static int joyavailable = 0;
59static int joyactive = 0;
60static float ModZMnt;
61static long GlobalMnt = 0;
62
63static int scrwidth = WIDTH;
64static int scrheight = HEIGHT;
65
66#define OBSSTARTX 992.0
67#define OBSSTARTY 103.0
68
69static float obs[3] = { OBSSTARTX, heightMnt * 1.3, OBSSTARTY };
70static float dir[3], v1[2], v2[2];
71static float v = 15.0;
72static float alpha = 75.0;
73static float beta = 90.0;
74
Brian Paul5b0a7f32000-06-27 16:52:38 +000075static void
76calcposobs(void)
77{
78 float alpha1, alpha2;
79
80 dir[0] = sin(alpha * M_PI / 180.0);
81 dir[2] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0);
82 dir[1] = cos(beta * M_PI / 180.0);
83
84 alpha1 = alpha + FOV / 2.0;
85 v1[0] = sin(alpha1 * M_PI / 180.0);
86 v1[1] = cos(alpha1 * M_PI / 180.0);
87
88 alpha2 = alpha - FOV / 2.0;
89 v2[0] = sin(alpha2 * M_PI / 180.0);
90 v2[1] = cos(alpha2 * M_PI / 180.0);
91
92 obs[0] += v * dir[0];
93 obs[1] += v * dir[1];
94 obs[2] += v * dir[2];
95
96 if (obs[1] < 0.0)
97 obs[1] = 0.0;
98}
99
100static void
101reshape(int width, int height)
102{
103 scrwidth = width;
104 scrheight = height;
105 glViewport(0, 0, (GLint) width, (GLint) height);
106 glMatrixMode(GL_PROJECTION);
107 glLoadIdentity();
108 gluPerspective(50.0, ((GLfloat) width / (GLfloat) height),
109 lenghtXmnt * stepYmnt * 0.01, lenghtXmnt * stepYmnt * 0.7);
110 glMatrixMode(GL_MODELVIEW);
111 glLoadIdentity();
112}
113
Brian Paul02e8a032000-06-27 17:04:43 +0000114static int
Brian Paul5b0a7f32000-06-27 16:52:38 +0000115clipstrip(float y, float *start, float *end)
116{
117 float x1, x2, t1, t2, tmp;
118
119 if (v1[1] == 0.0) {
120 t1 = 0.0;
121 x1 = -HUGE_VAL;
122 }
123 else {
124 t1 = y / v1[1];
125 x1 = t1 * v1[0];
126 }
127
128 if (v2[1] == 0.0) {
129 t2 = 0.0;
130 x2 = HUGE_VAL;
131 }
132 else {
133 t2 = y / v2[1];
134 x2 = t2 * v2[0];
135 }
136
137 if (((x1 < -(lenghtXmnt * stepXmnt) / 2) && (t2 <= 0.0)) ||
138 ((t1 <= 0.0) && (x2 > (lenghtXmnt * stepXmnt) / 2)) ||
139 ((t1 < 0.0) && (t2 < 0.0)))
140 return 0;
141
142 if ((t1 == 0.0) && (t2 == 0.0)) {
143 if ((v1[0] < 0.0) && (v1[1] > 0.0) && (v2[0] < 0.0) && (v2[1] < 0.0)) {
144 *start = -(lenghtXmnt * stepXmnt) / 2;
145 *end = stepXmnt;
146 return 1;
147 }
148 else {
149 if ((v1[0] > 0.0) && (v1[1] < 0.0) && (v2[0] > 0.0) && (v2[1] > 0.0)) {
150 *start = -stepXmnt;
151 *end = (lenghtXmnt * stepXmnt) / 2;
152 return 1;
153 }
154 else
155 return 0;
156 }
157 }
158 else {
159 if (t2 < 0.0) {
160 if (x1 < 0.0)
161 x2 = -(lenghtXmnt * stepXmnt) / 2;
162 else
163 x2 = (lenghtXmnt * stepXmnt) / 2;
164 }
165
166 if (t1 < 0.0) {
167 if (x2 < 0.0)
168 x1 = -(lenghtXmnt * stepXmnt) / 2;
169 else
170 x1 = (lenghtXmnt * stepXmnt) / 2;
171 }
172 }
173
174 if (x1 > x2) {
175 tmp = x1;
176 x1 = x2;
177 x2 = tmp;
178 }
179
180 x1 -= stepXmnt;
181 if (x1 < -(lenghtXmnt * stepXmnt) / 2)
182 x1 = -(lenghtXmnt * stepXmnt) / 2;
183
184 x2 += stepXmnt;
185 if (x2 > (lenghtXmnt * stepXmnt) / 2)
186 x2 = (lenghtXmnt * stepXmnt) / 2;
187
188 *start = ((int) (x1 / stepXmnt)) * stepXmnt;
189 *end = ((int) (x2 / stepXmnt)) * stepXmnt;
190
191 return 1;
192}
193
194static void
195printstring(void *font, char *string)
196{
197 int len, i;
198
199 len = (int) strlen(string);
200 for (i = 0; i < len; i++)
201 glutBitmapCharacter(font, string[i]);
202}
203
204static void
205printhelp(void)
206{
207 glEnable(GL_BLEND);
208 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
209 glColor4f(0.0, 0.0, 0.0, 0.5);
210 glRecti(40, 40, 600, 440);
211 glDisable(GL_BLEND);
212
213 glColor3f(1.0, 0.0, 0.0);
214 glRasterPos2i(300, 420);
215 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Help");
216
217 glRasterPos2i(60, 390);
218 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "h - Togle Help");
219 glRasterPos2i(60, 360);
220 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "t - Togle Textures");
221 glRasterPos2i(60, 330);
222 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "f - Togle Fog");
223 glRasterPos2i(60, 300);
224 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "p - Wire frame");
225 glRasterPos2i(60, 270);
226 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "b - Togle Back face culling");
227 glRasterPos2i(60, 240);
228 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Arrow Keys - Rotate");
229 glRasterPos2i(60, 210);
230 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "a - Increase velocity");
231 glRasterPos2i(60, 180);
232 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "z - Decrease velocity");
233
234 glRasterPos2i(60, 150);
235 if (joyavailable)
236 printstring(GLUT_BITMAP_TIMES_ROMAN_24,
237 "j - Togle jostick control (Joystick control available)");
238 else
239 printstring(GLUT_BITMAP_TIMES_ROMAN_24,
240 "(No Joystick control available)");
241}
242
Brian Paul02e8a032000-06-27 17:04:43 +0000243static void
Brian Paul5b0a7f32000-06-27 16:52:38 +0000244drawterrain(void)
245{
246 int h, i, idx, ox, oy;
247 float j, k, start, end;
248
249 ox = (int) (obs[0] / stepXmnt);
250 oy = (int) (obs[2] / stepYmnt);
251 GlobalMnt = ((ox * TSCALE) & 255) + ((oy * TSCALE) & 255) * 256;
252
253 glPushMatrix();
254 glTranslatef((float) ox * stepXmnt, 0, (float) oy * stepYmnt);
255
256 for (h = 0, k = -(lenghtYmnt * stepYmnt) / 2; h < lenghtYmnt;
257 k += stepYmnt, h++) {
258 if (!clipstrip(k, &start, &end))
259 continue;
260
261 glBegin(GL_TRIANGLE_STRIP); /* I hope that the optimizer will be able to improve this code */
262 for (i = (int) (lenghtXmnt / 2 + start / stepXmnt), j = start; j <= end;
263 j += stepXmnt, i++) {
264 idx = (i * TSCALE + h * 256 * TSCALE + GlobalMnt) & 65535;
265 glColor3fv(terraincolor[idx]);
266 glTexCoord2f((ox + i) / 8.0, (oy + h) / 8.0);
267 glVertex3f(j, terrain[idx], k);
268
269 idx =
270 (i * TSCALE + h * 256 * TSCALE + 256 * TSCALE +
271 GlobalMnt) & 65535;
272 glColor3fv(terraincolor[idx]);
273 glTexCoord2f((ox + i) / 8.0, (oy + h + 1) / 8.0);
274 glVertex3f(j, terrain[idx], k + stepYmnt);
275 }
276 glEnd();
277 }
278
279 glDisable(GL_CULL_FACE);
280 glDisable(GL_TEXTURE_2D);
281 glEnable(GL_BLEND);
282 glBegin(GL_QUADS);
283 glColor4f(0.1, 0.7, 1.0, 0.4);
284 glVertex3f(-(lenghtXmnt * stepXmnt) / 2.0, heightMnt * 0.6,
285 -(lenghtYmnt * stepYmnt) / 2.0);
286 glVertex3f(-(lenghtXmnt * stepXmnt) / 2.0, heightMnt * 0.6,
287 (lenghtYmnt * stepYmnt) / 2.0);
288 glVertex3f((lenghtXmnt * stepXmnt) / 2.0, heightMnt * 0.6,
289 (lenghtYmnt * stepYmnt) / 2.0);
290 glVertex3f((lenghtXmnt * stepXmnt) / 2.0, heightMnt * 0.6,
291 -(lenghtYmnt * stepYmnt) / 2.0);
292 glEnd();
293 glDisable(GL_BLEND);
294 if (bfcull)
295 glEnable(GL_CULL_FACE);
296 glEnable(GL_TEXTURE_2D);
297
298 glPopMatrix();
299
300}
301
302static void
303dojoy(void)
304{
305#ifdef WIN32
306 static UINT max[2] = { 0, 0 };
307 static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2];
308 MMRESULT res;
309 JOYINFO joy;
310
311 res = joyGetPos(JOYSTICKID1, &joy);
312
313 if (res == JOYERR_NOERROR) {
314 joyavailable = 1;
315
316 if (max[0] < joy.wXpos)
317 max[0] = joy.wXpos;
318 if (min[0] > joy.wXpos)
319 min[0] = joy.wXpos;
320 center[0] = (max[0] + min[0]) / 2;
321
322 if (max[1] < joy.wYpos)
323 max[1] = joy.wYpos;
324 if (min[1] > joy.wYpos)
325 min[1] = joy.wYpos;
326 center[1] = (max[1] + min[1]) / 2;
327
328 if (joyactive) {
329 if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0]))
330 alpha +=
331 2.5 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]);
332 if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1]))
333 beta += 2.5 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]);
334
335 if (joy.wButtons & JOY_BUTTON1)
336 v += 0.5;
337 if (joy.wButtons & JOY_BUTTON2)
338 v -= 0.5;
339 }
340 }
341 else
342 joyavailable = 0;
343#endif
344}
345
Brian Paul02e8a032000-06-27 17:04:43 +0000346static void
Brian Paul5b0a7f32000-06-27 16:52:38 +0000347drawscene(void)
348{
Brian Pauld49b34a2000-09-12 18:44:45 +0000349 static char frbuf[80] = "";
Brian Paul5b0a7f32000-06-27 16:52:38 +0000350
351 dojoy();
352
353 glShadeModel(GL_SMOOTH);
354 glEnable(GL_DEPTH_TEST);
355
356 if (usetex)
357 glEnable(GL_TEXTURE_2D);
358 else
359 glDisable(GL_TEXTURE_2D);
360
361 if (fog)
362 glEnable(GL_FOG);
363 else
364 glDisable(GL_FOG);
365
366 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
367
368 glPushMatrix();
369
370 calcposobs();
371 gluLookAt(obs[0], obs[1], obs[2],
372 obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2],
373 0.0, 1.0, 0.0);
374
375 drawterrain();
376 glPopMatrix();
377
Brian Paul5b0a7f32000-06-27 16:52:38 +0000378 glDisable(GL_TEXTURE_2D);
379 glDisable(GL_DEPTH_TEST);
380 glDisable(GL_FOG);
381 glShadeModel(GL_FLAT);
382
383 glMatrixMode(GL_PROJECTION);
384 glLoadIdentity();
385 glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
386 glMatrixMode(GL_MODELVIEW);
387 glLoadIdentity();
388
389 glColor3f(1.0, 0.0, 0.0);
390 glRasterPos2i(10, 10);
391 printstring(GLUT_BITMAP_HELVETICA_18, frbuf);
392 glRasterPos2i(350, 470);
393 printstring(GLUT_BITMAP_HELVETICA_10,
394 "Terrain V1.2 Written by David Bucciarelli (tech.hmw@plus.it)");
395 glRasterPos2i(434, 457);
396 printstring(GLUT_BITMAP_HELVETICA_10,
397 "Based on a Mickael's demo (Skizo@Hol.Fr)");
398
399 if (help)
400 printhelp();
401
402 reshape(scrwidth, scrheight);
403
404 glutSwapBuffers();
405
Brian Pauld49b34a2000-09-12 18:44:45 +0000406 Frames++;
407 {
408 GLint t = glutGet(GLUT_ELAPSED_TIME);
409 if (t - T0 >= 2000) {
410 GLfloat seconds = (t - T0) / 1000.0;
411 GLfloat fps = Frames / seconds;
412 sprintf(frbuf, "Frame rate: %f", fps);
413 T0 = t;
414 Frames = 0;
415 }
416 }
Brian Paul5b0a7f32000-06-27 16:52:38 +0000417}
418
419static void
420key(unsigned char k, int x, int y)
421{
422 switch (k) {
423 case 27:
424 exit(0);
425 break;
426 case 'a':
427 v += 0.5;
428 break;
429 case 'z':
430 v -= 0.5;
431 break;
432 case 'p':
433 if (poutline) {
434 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
435 poutline = 0;
436 }
437 else {
438 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
439 poutline = 1;
440 }
441 break;
442 case 'j':
443 joyactive = (!joyactive);
444 break;
445 case 'h':
446 help = (!help);
447 break;
448 case 'f':
449 fog = (!fog);
450 break;
451 case 't':
452 usetex = (!usetex);
453 break;
454 case 'b':
455 if (bfcull) {
456 glDisable(GL_CULL_FACE);
457 bfcull = 0;
458 }
459 else {
460 glEnable(GL_CULL_FACE);
461 bfcull = 1;
462 }
463 break;
464#ifdef XMESA
465 case ' ':
466 XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
467 fullscreen = (!fullscreen);
468 break;
469#endif
470 }
471}
472
473static void
474special(int k, int x, int y)
475{
476 switch (k) {
477 case GLUT_KEY_LEFT:
478 alpha += 2.0;
479 break;
480 case GLUT_KEY_RIGHT:
481 alpha -= 2.0;
482 break;
483 case GLUT_KEY_DOWN:
484 beta -= 2.0;
485 break;
486 case GLUT_KEY_UP:
487 beta += 2.0;
488 break;
489 }
490}
491
492static void
493calccolor(GLfloat height, GLfloat c[3])
494{
495 GLfloat color[4][3] = {
496 {1.0, 1.0, 1.0},
497 {0.0, 0.8, 0.0},
498 {1.0, 1.0, 0.3},
499 {0.0, 0.0, 0.8}
500 };
501 GLfloat fact;
502
503 height = height * (1.0 / 255.0);
504
505 if (height >= 0.9) {
506 c[0] = color[0][0];
507 c[1] = color[0][1];
508 c[2] = color[0][2];
509 return;
510 }
511
512 if ((height < 0.9) && (height >= 0.7)) {
513 fact = (height - 0.7) * 5.0;
514 c[0] = fact * color[0][0] + (1.0 - fact) * color[1][0];
515 c[1] = fact * color[0][1] + (1.0 - fact) * color[1][1];
516 c[2] = fact * color[0][2] + (1.0 - fact) * color[1][2];
517 return;
518 }
519
520 if ((height < 0.7) && (height >= 0.6)) {
521 fact = (height - 0.6) * 10.0;
522 c[0] = fact * color[1][0] + (1.0 - fact) * color[2][0];
523 c[1] = fact * color[1][1] + (1.0 - fact) * color[2][1];
524 c[2] = fact * color[1][2] + (1.0 - fact) * color[2][2];
525 return;
526 }
527
528 if ((height < 0.6) && (height >= 0.5)) {
529 fact = (height - 0.5) * 10.0;
530 c[0] = fact * color[2][0] + (1.0 - fact) * color[3][0];
531 c[1] = fact * color[2][1] + (1.0 - fact) * color[3][1];
532 c[2] = fact * color[2][2] + (1.0 - fact) * color[3][2];
533 return;
534 }
535
536 c[0] = color[3][0];
537 c[1] = color[3][1];
538 c[2] = color[3][2];
539}
540
541static void
542loadpic(void)
543{
544 GLubyte bufferter[256 * 256], terrainpic[256 * 256];
545 FILE *FilePic;
546 int i, tmp;
547 GLenum gluerr;
548
549 if ((FilePic = fopen("terrain.dat", "r")) == NULL) {
Brian Pauld49b34a2000-09-12 18:44:45 +0000550 fprintf(stderr, "Error loading terrain.dat\n");
Brian Paul5b0a7f32000-06-27 16:52:38 +0000551 exit(-1);
552 }
553 fread(bufferter, 256 * 256, 1, FilePic);
554 fclose(FilePic);
555
556 for (i = 0; i < (256 * 256); i++) {
557 terrain[i] = (bufferter[i] * (heightMnt / 255.0f));
558 calccolor((GLfloat) bufferter[i], terraincolor[i]);
559 tmp = (((int) bufferter[i]) + 96);
560 terrainpic[i] = (tmp > 255) ? 255 : tmp;
561 }
562
563 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
564 if ((gluerr = gluBuild2DMipmaps(GL_TEXTURE_2D, 1, 256, 256, GL_LUMINANCE,
565 GL_UNSIGNED_BYTE,
566 (GLvoid *) (&terrainpic[0])))) {
567 fprintf(stderr, "GLULib%s\n", gluErrorString(gluerr));
568 exit(-1);
569 }
570
571 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
572 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
573
574 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
575 GL_LINEAR_MIPMAP_LINEAR);
576 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
577
578 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
579 glEnable(GL_TEXTURE_2D);
580}
581
582static void
583init(void)
584{
585 float fogcolor[4] = { 0.6, 0.7, 0.7, 1.0 };
586
587 glClearColor(fogcolor[0], fogcolor[1], fogcolor[2], fogcolor[3]);
588 glClearDepth(1.0);
589 glDepthFunc(GL_LEQUAL);
590 glShadeModel(GL_SMOOTH);
591 glEnable(GL_DEPTH_TEST);
592 glEnable(GL_CULL_FACE);
593
594 glDisable(GL_BLEND);
595 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
596
597 glEnable(GL_FOG);
598 glFogi(GL_FOG_MODE, GL_EXP2);
599 glFogfv(GL_FOG_COLOR, fogcolor);
600 glFogf(GL_FOG_DENSITY, 0.0007);
601#ifdef FX
602 glHint(GL_FOG_HINT, GL_NICEST);
603#endif
604
605 reshape(scrwidth, scrheight);
606}
607
608
609int
610main(int ac, char **av)
611{
612 glutInitWindowPosition(0, 0);
613 glutInitWindowSize(WIDTH, HEIGHT);
614 glutInit(&ac, av);
615
616 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
617
618 if (!(win = glutCreateWindow("Terrain"))) {
619 fprintf(stderr, "Error, couldn't open window\n");
620 return -1;
621 }
622
623 ModZMnt = 0.0f;
624 loadpic();
625
626 init();
627
628#ifndef FX
629 glDisable(GL_TEXTURE_2D);
630 usetex = 0;
631#endif
632
633 glutReshapeFunc(reshape);
634 glutDisplayFunc(drawscene);
635 glutKeyboardFunc(key);
636 glutSpecialFunc(special);
637 glutIdleFunc(drawscene);
638
639 glutMainLoop();
640
641 return 0;
642}