OSDN Git Service

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