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