summaryrefslogtreecommitdiff
path: root/progs/demos/terrain.c
diff options
context:
space:
mode:
Diffstat (limited to 'progs/demos/terrain.c')
-rw-r--r--progs/demos/terrain.c653
1 files changed, 653 insertions, 0 deletions
diff --git a/progs/demos/terrain.c b/progs/demos/terrain.c
new file mode 100644
index 0000000000..b708ff826d
--- /dev/null
+++ b/progs/demos/terrain.c
@@ -0,0 +1,653 @@
+/*
+ * This program is under the GNU GPL.
+ * Use at your own risk.
+ *
+ * written by David Bucciarelli (tech.hmw@plus.it)
+ * Humanware s.r.l.
+ *
+ * based on a Mikael SkiZoWalker's (MoDEL) / France (Skizo@Hol.Fr) demo
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <time.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <GL/glut.h>
+
+#ifdef XMESA
+#include "GL/xmesa.h"
+static int fullscreen = 1;
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
+#define heightMnt 450
+#define lenghtXmnt 62
+#define lenghtYmnt 62
+
+#define stepXmnt 96.0
+#define stepYmnt 96.0
+
+#define WIDTH 640
+#define HEIGHT 480
+
+#define TSCALE 4
+
+#define FRAME 50
+
+#define FOV 85
+
+static GLfloat terrain[256 * 256];
+static GLfloat terraincolor[256 * 256][3];
+
+static int win = 0;
+
+static int fog = 1;
+static int bfcull = 1;
+static int usetex = 1;
+static int poutline = 0;
+static int help = 1;
+static int joyavailable = 0;
+static int joyactive = 0;
+static float ModZMnt;
+static long GlobalMnt = 0;
+
+static int scrwidth = WIDTH;
+static int scrheight = HEIGHT;
+
+#define OBSSTARTX 992.0
+#define OBSSTARTY 103.0
+
+static float obs[3] = { OBSSTARTX, heightMnt * 1.3, OBSSTARTY };
+static float dir[3], v1[2], v2[2];
+static float v = 15.0;
+static float alpha = 75.0;
+static float beta = 90.0;
+
+static float
+gettime(void)
+{
+ static clock_t told = 0;
+ clock_t tnew, ris;
+
+ tnew = clock();
+
+ ris = tnew - told;
+
+ told = tnew;
+
+ return (ris / (float) CLOCKS_PER_SEC);
+}
+
+static void
+calcposobs(void)
+{
+ float alpha1, alpha2;
+
+ dir[0] = sin(alpha * M_PI / 180.0);
+ dir[2] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0);
+ dir[1] = cos(beta * M_PI / 180.0);
+
+ alpha1 = alpha + FOV / 2.0;
+ v1[0] = sin(alpha1 * M_PI / 180.0);
+ v1[1] = cos(alpha1 * M_PI / 180.0);
+
+ alpha2 = alpha - FOV / 2.0;
+ v2[0] = sin(alpha2 * M_PI / 180.0);
+ v2[1] = cos(alpha2 * M_PI / 180.0);
+
+ obs[0] += v * dir[0];
+ obs[1] += v * dir[1];
+ obs[2] += v * dir[2];
+
+ if (obs[1] < 0.0)
+ obs[1] = 0.0;
+}
+
+static void
+reshape(int width, int height)
+{
+ scrwidth = width;
+ scrheight = height;
+ glViewport(0, 0, (GLint) width, (GLint) height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluPerspective(50.0, ((GLfloat) width / (GLfloat) height),
+ lenghtXmnt * stepYmnt * 0.01, lenghtXmnt * stepYmnt * 0.7);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+int
+clipstrip(float y, float *start, float *end)
+{
+ float x1, x2, t1, t2, tmp;
+
+ if (v1[1] == 0.0) {
+ t1 = 0.0;
+ x1 = -HUGE_VAL;
+ }
+ else {
+ t1 = y / v1[1];
+ x1 = t1 * v1[0];
+ }
+
+ if (v2[1] == 0.0) {
+ t2 = 0.0;
+ x2 = HUGE_VAL;
+ }
+ else {
+ t2 = y / v2[1];
+ x2 = t2 * v2[0];
+ }
+
+ if (((x1 < -(lenghtXmnt * stepXmnt) / 2) && (t2 <= 0.0)) ||
+ ((t1 <= 0.0) && (x2 > (lenghtXmnt * stepXmnt) / 2)) ||
+ ((t1 < 0.0) && (t2 < 0.0)))
+ return 0;
+
+ if ((t1 == 0.0) && (t2 == 0.0)) {
+ if ((v1[0] < 0.0) && (v1[1] > 0.0) && (v2[0] < 0.0) && (v2[1] < 0.0)) {
+ *start = -(lenghtXmnt * stepXmnt) / 2;
+ *end = stepXmnt;
+ return 1;
+ }
+ else {
+ if ((v1[0] > 0.0) && (v1[1] < 0.0) && (v2[0] > 0.0) && (v2[1] > 0.0)) {
+ *start = -stepXmnt;
+ *end = (lenghtXmnt * stepXmnt) / 2;
+ return 1;
+ }
+ else
+ return 0;
+ }
+ }
+ else {
+ if (t2 < 0.0) {
+ if (x1 < 0.0)
+ x2 = -(lenghtXmnt * stepXmnt) / 2;
+ else
+ x2 = (lenghtXmnt * stepXmnt) / 2;
+ }
+
+ if (t1 < 0.0) {
+ if (x2 < 0.0)
+ x1 = -(lenghtXmnt * stepXmnt) / 2;
+ else
+ x1 = (lenghtXmnt * stepXmnt) / 2;
+ }
+ }
+
+ if (x1 > x2) {
+ tmp = x1;
+ x1 = x2;
+ x2 = tmp;
+ }
+
+ x1 -= stepXmnt;
+ if (x1 < -(lenghtXmnt * stepXmnt) / 2)
+ x1 = -(lenghtXmnt * stepXmnt) / 2;
+
+ x2 += stepXmnt;
+ if (x2 > (lenghtXmnt * stepXmnt) / 2)
+ x2 = (lenghtXmnt * stepXmnt) / 2;
+
+ *start = ((int) (x1 / stepXmnt)) * stepXmnt;
+ *end = ((int) (x2 / stepXmnt)) * stepXmnt;
+
+ return 1;
+}
+
+static void
+printstring(void *font, char *string)
+{
+ int len, i;
+
+ len = (int) strlen(string);
+ for (i = 0; i < len; i++)
+ glutBitmapCharacter(font, string[i]);
+}
+
+static void
+printhelp(void)
+{
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4f(0.0, 0.0, 0.0, 0.5);
+ glRecti(40, 40, 600, 440);
+ glDisable(GL_BLEND);
+
+ glColor3f(1.0, 0.0, 0.0);
+ glRasterPos2i(300, 420);
+ printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Help");
+
+ glRasterPos2i(60, 390);
+ printstring(GLUT_BITMAP_TIMES_ROMAN_24, "h - Togle Help");
+ glRasterPos2i(60, 360);
+ printstring(GLUT_BITMAP_TIMES_ROMAN_24, "t - Togle Textures");
+ glRasterPos2i(60, 330);
+ printstring(GLUT_BITMAP_TIMES_ROMAN_24, "f - Togle Fog");
+ glRasterPos2i(60, 300);
+ printstring(GLUT_BITMAP_TIMES_ROMAN_24, "p - Wire frame");
+ glRasterPos2i(60, 270);
+ printstring(GLUT_BITMAP_TIMES_ROMAN_24, "b - Togle Back face culling");
+ glRasterPos2i(60, 240);
+ printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Arrow Keys - Rotate");
+ glRasterPos2i(60, 210);
+ printstring(GLUT_BITMAP_TIMES_ROMAN_24, "a - Increase velocity");
+ glRasterPos2i(60, 180);
+ printstring(GLUT_BITMAP_TIMES_ROMAN_24, "z - Decrease velocity");
+
+ glRasterPos2i(60, 150);
+ if (joyavailable)
+ printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+ "j - Togle jostick control (Joystick control available)");
+ else
+ printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+ "(No Joystick control available)");
+}
+
+void
+drawterrain(void)
+{
+ int h, i, idx, ox, oy;
+ float j, k, start, end;
+
+ ox = (int) (obs[0] / stepXmnt);
+ oy = (int) (obs[2] / stepYmnt);
+ GlobalMnt = ((ox * TSCALE) & 255) + ((oy * TSCALE) & 255) * 256;
+
+ glPushMatrix();
+ glTranslatef((float) ox * stepXmnt, 0, (float) oy * stepYmnt);
+
+ for (h = 0, k = -(lenghtYmnt * stepYmnt) / 2; h < lenghtYmnt;
+ k += stepYmnt, h++) {
+ if (!clipstrip(k, &start, &end))
+ continue;
+
+ glBegin(GL_TRIANGLE_STRIP); /* I hope that the optimizer will be able to improve this code */
+ for (i = (int) (lenghtXmnt / 2 + start / stepXmnt), j = start; j <= end;
+ j += stepXmnt, i++) {
+ idx = (i * TSCALE + h * 256 * TSCALE + GlobalMnt) & 65535;
+ glColor3fv(terraincolor[idx]);
+ glTexCoord2f((ox + i) / 8.0, (oy + h) / 8.0);
+ glVertex3f(j, terrain[idx], k);
+
+ idx =
+ (i * TSCALE + h * 256 * TSCALE + 256 * TSCALE +
+ GlobalMnt) & 65535;
+ glColor3fv(terraincolor[idx]);
+ glTexCoord2f((ox + i) / 8.0, (oy + h + 1) / 8.0);
+ glVertex3f(j, terrain[idx], k + stepYmnt);
+ }
+ glEnd();
+ }
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBegin(GL_QUADS);
+ glColor4f(0.1, 0.7, 1.0, 0.4);
+ glVertex3f(-(lenghtXmnt * stepXmnt) / 2.0, heightMnt * 0.6,
+ -(lenghtYmnt * stepYmnt) / 2.0);
+ glVertex3f(-(lenghtXmnt * stepXmnt) / 2.0, heightMnt * 0.6,
+ (lenghtYmnt * stepYmnt) / 2.0);
+ glVertex3f((lenghtXmnt * stepXmnt) / 2.0, heightMnt * 0.6,
+ (lenghtYmnt * stepYmnt) / 2.0);
+ glVertex3f((lenghtXmnt * stepXmnt) / 2.0, heightMnt * 0.6,
+ -(lenghtYmnt * stepYmnt) / 2.0);
+ glEnd();
+ glDisable(GL_BLEND);
+ if (bfcull)
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_TEXTURE_2D);
+
+ glPopMatrix();
+
+}
+
+static void
+dojoy(void)
+{
+#ifdef WIN32
+ static UINT max[2] = { 0, 0 };
+ static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2];
+ MMRESULT res;
+ JOYINFO joy;
+
+ res = joyGetPos(JOYSTICKID1, &joy);
+
+ if (res == JOYERR_NOERROR) {
+ joyavailable = 1;
+
+ if (max[0] < joy.wXpos)
+ max[0] = joy.wXpos;
+ if (min[0] > joy.wXpos)
+ min[0] = joy.wXpos;
+ center[0] = (max[0] + min[0]) / 2;
+
+ if (max[1] < joy.wYpos)
+ max[1] = joy.wYpos;
+ if (min[1] > joy.wYpos)
+ min[1] = joy.wYpos;
+ center[1] = (max[1] + min[1]) / 2;
+
+ if (joyactive) {
+ if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0]))
+ alpha +=
+ 2.5 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]);
+ if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1]))
+ beta += 2.5 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]);
+
+ if (joy.wButtons & JOY_BUTTON1)
+ v += 0.5;
+ if (joy.wButtons & JOY_BUTTON2)
+ v -= 0.5;
+ }
+ }
+ else
+ joyavailable = 0;
+#endif
+}
+
+void
+drawscene(void)
+{
+ static int count = 0;
+ static char frbuf[80];
+ float fr;
+
+ dojoy();
+
+ glShadeModel(GL_SMOOTH);
+ glEnable(GL_DEPTH_TEST);
+
+ if (usetex)
+ glEnable(GL_TEXTURE_2D);
+ else
+ glDisable(GL_TEXTURE_2D);
+
+ if (fog)
+ glEnable(GL_FOG);
+ else
+ glDisable(GL_FOG);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+
+ calcposobs();
+ gluLookAt(obs[0], obs[1], obs[2],
+ obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2],
+ 0.0, 1.0, 0.0);
+
+ drawterrain();
+ glPopMatrix();
+
+ if ((count % FRAME) == 0) {
+ fr = gettime();
+ sprintf(frbuf, "Frame rate: %.3f", FRAME / fr);
+ }
+
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_FOG);
+ glShadeModel(GL_FLAT);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glColor3f(1.0, 0.0, 0.0);
+ glRasterPos2i(10, 10);
+ printstring(GLUT_BITMAP_HELVETICA_18, frbuf);
+ glRasterPos2i(350, 470);
+ printstring(GLUT_BITMAP_HELVETICA_10,
+ "Terrain V1.2 Written by David Bucciarelli (tech.hmw@plus.it)");
+ glRasterPos2i(434, 457);
+ printstring(GLUT_BITMAP_HELVETICA_10,
+ "Based on a Mickael's demo (Skizo@Hol.Fr)");
+
+ if (help)
+ printhelp();
+
+ reshape(scrwidth, scrheight);
+
+ glutSwapBuffers();
+
+ count++;
+}
+
+static void
+key(unsigned char k, int x, int y)
+{
+ switch (k) {
+ case 27:
+ exit(0);
+ break;
+ case 'a':
+ v += 0.5;
+ break;
+ case 'z':
+ v -= 0.5;
+ break;
+ case 'p':
+ if (poutline) {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ poutline = 0;
+ }
+ else {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ poutline = 1;
+ }
+ break;
+ case 'j':
+ joyactive = (!joyactive);
+ break;
+ case 'h':
+ help = (!help);
+ break;
+ case 'f':
+ fog = (!fog);
+ break;
+ case 't':
+ usetex = (!usetex);
+ break;
+ case 'b':
+ if (bfcull) {
+ glDisable(GL_CULL_FACE);
+ bfcull = 0;
+ }
+ else {
+ glEnable(GL_CULL_FACE);
+ bfcull = 1;
+ }
+ break;
+#ifdef XMESA
+ case ' ':
+ XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
+ fullscreen = (!fullscreen);
+ break;
+#endif
+ }
+}
+
+static void
+special(int k, int x, int y)
+{
+ switch (k) {
+ case GLUT_KEY_LEFT:
+ alpha += 2.0;
+ break;
+ case GLUT_KEY_RIGHT:
+ alpha -= 2.0;
+ break;
+ case GLUT_KEY_DOWN:
+ beta -= 2.0;
+ break;
+ case GLUT_KEY_UP:
+ beta += 2.0;
+ break;
+ }
+}
+
+static void
+calccolor(GLfloat height, GLfloat c[3])
+{
+ GLfloat color[4][3] = {
+ {1.0, 1.0, 1.0},
+ {0.0, 0.8, 0.0},
+ {1.0, 1.0, 0.3},
+ {0.0, 0.0, 0.8}
+ };
+ GLfloat fact;
+
+ height = height * (1.0 / 255.0);
+
+ if (height >= 0.9) {
+ c[0] = color[0][0];
+ c[1] = color[0][1];
+ c[2] = color[0][2];
+ return;
+ }
+
+ if ((height < 0.9) && (height >= 0.7)) {
+ fact = (height - 0.7) * 5.0;
+ c[0] = fact * color[0][0] + (1.0 - fact) * color[1][0];
+ c[1] = fact * color[0][1] + (1.0 - fact) * color[1][1];
+ c[2] = fact * color[0][2] + (1.0 - fact) * color[1][2];
+ return;
+ }
+
+ if ((height < 0.7) && (height >= 0.6)) {
+ fact = (height - 0.6) * 10.0;
+ c[0] = fact * color[1][0] + (1.0 - fact) * color[2][0];
+ c[1] = fact * color[1][1] + (1.0 - fact) * color[2][1];
+ c[2] = fact * color[1][2] + (1.0 - fact) * color[2][2];
+ return;
+ }
+
+ if ((height < 0.6) && (height >= 0.5)) {
+ fact = (height - 0.5) * 10.0;
+ c[0] = fact * color[2][0] + (1.0 - fact) * color[3][0];
+ c[1] = fact * color[2][1] + (1.0 - fact) * color[3][1];
+ c[2] = fact * color[2][2] + (1.0 - fact) * color[3][2];
+ return;
+ }
+
+ c[0] = color[3][0];
+ c[1] = color[3][1];
+ c[2] = color[3][2];
+}
+
+static void
+loadpic(void)
+{
+ GLubyte bufferter[256 * 256], terrainpic[256 * 256];
+ FILE *FilePic;
+ int i, tmp;
+ GLenum gluerr;
+
+ if ((FilePic = fopen("terrain.dat", "r")) == NULL) {
+ fprintf(stderr, "Error loading Mnt.bin\n");
+ exit(-1);
+ }
+ fread(bufferter, 256 * 256, 1, FilePic);
+ fclose(FilePic);
+
+ for (i = 0; i < (256 * 256); i++) {
+ terrain[i] = (bufferter[i] * (heightMnt / 255.0f));
+ calccolor((GLfloat) bufferter[i], terraincolor[i]);
+ tmp = (((int) bufferter[i]) + 96);
+ terrainpic[i] = (tmp > 255) ? 255 : tmp;
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ if ((gluerr = gluBuild2DMipmaps(GL_TEXTURE_2D, 1, 256, 256, GL_LUMINANCE,
+ GL_UNSIGNED_BYTE,
+ (GLvoid *) (&terrainpic[0])))) {
+ fprintf(stderr, "GLULib%s\n", gluErrorString(gluerr));
+ exit(-1);
+ }
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glEnable(GL_TEXTURE_2D);
+}
+
+static void
+init(void)
+{
+ float fogcolor[4] = { 0.6, 0.7, 0.7, 1.0 };
+
+ glClearColor(fogcolor[0], fogcolor[1], fogcolor[2], fogcolor[3]);
+ glClearDepth(1.0);
+ glDepthFunc(GL_LEQUAL);
+ glShadeModel(GL_SMOOTH);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+
+ glDisable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glEnable(GL_FOG);
+ glFogi(GL_FOG_MODE, GL_EXP2);
+ glFogfv(GL_FOG_COLOR, fogcolor);
+ glFogf(GL_FOG_DENSITY, 0.0007);
+#ifdef FX
+ glHint(GL_FOG_HINT, GL_NICEST);
+#endif
+
+ reshape(scrwidth, scrheight);
+}
+
+
+int
+main(int ac, char **av)
+{
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(WIDTH, HEIGHT);
+ glutInit(&ac, av);
+
+ glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
+
+ if (!(win = glutCreateWindow("Terrain"))) {
+ fprintf(stderr, "Error, couldn't open window\n");
+ return -1;
+ }
+
+ ModZMnt = 0.0f;
+ loadpic();
+
+ init();
+
+#ifndef FX
+ glDisable(GL_TEXTURE_2D);
+ usetex = 0;
+#endif
+
+ glutReshapeFunc(reshape);
+ glutDisplayFunc(drawscene);
+ glutKeyboardFunc(key);
+ glutSpecialFunc(special);
+ glutIdleFunc(drawscene);
+
+ glutMainLoop();
+
+ return 0;
+}