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