--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <GL/glut.h>
+#include <assert.h>
+
+struct vec3 {
+ float x, y, z;
+};
+
+void disp(void);
+void draw_field(int xcells, int ycells);
+void draw_tile(int col, int row, int xcells, int ycells);
+void set_view_matrix(int eye, float ipd);
+void set_proj_matrix(int eye, float ipd);
+void reshape(int x, int y);
+void keyb(unsigned char key, int x, int y);
+
+static int win_width = 320;
+static int win_height = 640;
+static float aspect;
+static int view = 0;
+static float eye_dist = 1.4;
+
+int main(int argc, char **argv)
+{
+ glutInit(&argc, argv);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
+ glutInitWindowSize(win_width, win_height);
+ glutCreateWindow("tilegen");
+
+ glutDisplayFunc(disp);
+ glutReshapeFunc(reshape);
+ glutKeyboardFunc(keyb);
+
+ glClearColor(0.05, 0.05, 0.05, 1);
+ glEnable(GL_CULL_FACE);
+ glShadeModel(GL_FLAT);
+
+ glutMainLoop();
+ return 0;
+}
+
+void disp(void)
+{
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glColorMask(1, 0, 0, 0);
+
+ set_proj_matrix(-1, eye_dist);
+ set_view_matrix(-1, eye_dist);
+ glTranslatef(0, 0, -1);
+
+ draw_field(10, 20);
+
+ glColorMask(0, 1, 1, 0);
+
+ set_proj_matrix(1, eye_dist);
+ set_view_matrix(1, eye_dist);
+ glTranslatef(0, 0, -1);
+
+ draw_field(10, 20);
+
+ glColorMask(1, 1, 1, 1);
+
+ glutSwapBuffers();
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void draw_field(int xcells, int ycells)
+{
+ int i, j;
+
+ for(i=0; i<ycells; i++) {
+ for(j=0; j<xcells; j++) {
+ draw_tile(j, i, xcells, ycells);
+ }
+ }
+
+ /*
+ glBegin(GL_LINES);
+ glColor3f(1, 0, 0);
+ glVertex2f(-100, 0);
+ glVertex2f(100, 0);
+ glColor3f(0, 1, 0);
+ glVertex2f(0, -100);
+ glVertex2f(0, 100);
+ glEnd();
+ */
+}
+
+#define DX 0.4
+#define DZ 0.3
+
+static struct vec3 tileverts[] = {
+ {-1, -1, 0}, {1, -1, 0}, {1, 1, 0}, {-1, 1, 0},
+ {-1 + DX, -1 + DX, DZ}, {1 - DX, -1 + DX, DZ},
+ {1 - DX, 1 - DX, DZ}, {-1 + DX, 1 - DX, DZ}
+};
+static struct vec3 tilecol[] = {
+ {0.8, 0.8, 0.8}, /* left */
+ {0.2, 0.2, 0.2}, /* bottom */
+ {0.4, 0.4, 0.4}, /* right */
+ {1.0, 1.0, 1.0}, /* top */
+ {0.7, 0.7, 0.7}, /* front */
+ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}
+};
+static uint16_t tileidx[] = { /* 3 +---------+ 2 */
+ 4, 7, 3, 0, /* |\ 7 6 /| */
+ 5, 4, 0, 1, /* | +-----+ | */
+ 6, 5, 1, 2, /* | | | | */
+ 7, 6, 2, 3, /* | +-----+ | */
+ 5, 6, 7, 4 /* |/ 4 5 \| */
+}; /* 0 +---------+ 1 */
+
+void draw_tile(int col, int row, int xcells, int ycells)
+{
+ int ncells = xcells > ycells ? xcells : ycells;
+ float cellsz = 2.0 / ncells;
+
+ glPushMatrix();
+ glTranslatef((col - xcells / 2.0 + 0.5) * cellsz, (row - ycells / 2.0 + 0.5) * cellsz, 0);
+ glScalef(cellsz * 0.5, cellsz * 0.5, cellsz * 0.5);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, tileverts);
+ glColorPointer(3, GL_FLOAT, 0, tilecol);
+ glDrawElements(GL_QUADS, 20, GL_UNSIGNED_SHORT, tileidx);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ glPopMatrix();
+}
+
+void set_view_matrix(int eye, float ipd)
+{
+ const float offs[] = {0.5, 0.0, -0.5};
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(offs[eye + 1] * ipd, 0, 0);
+}
+
+void set_proj_matrix(int eye, float ipd)
+{
+ const float offs[] = {1.0, 0.0, -1.0};
+ float vpsz = 0.5;
+
+ float right = aspect * vpsz;
+ float top = vpsz;
+ float shift = offs[eye + 1] * ipd * 0.25; /* 0.25 -> 0.5 * znear */
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-right + shift, right + shift, -top, top, 0.5, 500.0);
+}
+
+void reshape(int x, int y)
+{
+ win_width = x;
+ win_height = y;
+ aspect = (float)win_width / (float)win_height;
+ glViewport(0, 0, x, y);
+}
+
+void keyb(unsigned char key, int x, int y)
+{
+ switch(key) {
+ case 27:
+ exit(0);
+
+ case '1':
+ case '2':
+ case '3':
+ view = key - '2';
+ glutPostRedisplay();
+ break;
+ }
+}