finished the tile generator
[megadrive_tetris] / tools / tilegen / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <assert.h>
6 #include <GL/glut.h>
7
8 struct vec3 {
9         float x, y, z;
10 };
11
12 void disp(void);
13 void draw_scene(int eye);
14 void draw_field(int xcells, int ycells);
15 void draw_tile(int col, int row, int xcells, int ycells);
16 void set_view_matrix(int eye, float ipd);
17 void set_proj_matrix(int eye, float ipd);
18 void reshape(int x, int y);
19 void keyb(unsigned char key, int x, int y);
20 void save_tiles(void);
21 int save_tile(const char *fname, unsigned char *pixptr, int xsz, int ysz, int pitch);
22 void draw_grid(void);
23
24 void draw_shaft(void);
25
26 static int win_width = 1280;
27 static int win_height = 960;
28 static int grid_cols = 10;
29 static int grid_rows = 20;
30 static float aspect;
31 static int view = 0;
32 static float eye_dist_well = 0.5;
33 static float eye_dist_tiles = 1.3;
34
35 static int show_blocks = 0;
36 static int show_stereo = 0;
37 static int show_grid = 1;
38
39 int main(int argc, char **argv)
40 {
41         printf("press 't' to toggle block tiles\n");
42         printf("press 's' to toggle stereo\n");
43         printf("press 'g' to toggle guide grid\n");
44         printf("press space to resize to 8x8 tiles\n");
45
46         glutInit(&argc, argv);
47         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
48         glutInitWindowSize(win_width, win_height);
49         glutCreateWindow("tilegen");
50
51         glutDisplayFunc(disp);
52         glutReshapeFunc(reshape);
53         glutKeyboardFunc(keyb);
54
55         glClearColor(0.05, 0.05, 0.05, 1);
56         glEnable(GL_CULL_FACE);
57         glShadeModel(GL_FLAT);
58
59         glutMainLoop();
60         return 0;
61 }
62
63 void disp(void)
64 {
65         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
66
67         if(show_stereo) {
68                 glColorMask(1, 0, 0, 0);
69                 draw_scene(-1);
70
71                 glColorMask(0, 1, 1, 0);
72                 draw_scene(1);
73
74                 glColorMask(1, 1, 1, 1);
75         } else {
76                 draw_scene(0);
77         }
78
79         if(show_grid) {
80                 draw_grid();
81         }
82
83         glutSwapBuffers();
84         assert(glGetError() == GL_NO_ERROR);
85 }
86
87 void draw_scene(int eye)
88 {
89         set_proj_matrix(eye, eye_dist_well);
90         set_view_matrix(eye, eye_dist_well);
91         glTranslatef(0, 0, -1);
92         draw_shaft();
93
94         set_proj_matrix(eye, eye_dist_tiles);
95         set_view_matrix(eye, eye_dist_tiles);
96         glTranslatef(0, 0, -1);
97         draw_field(grid_cols, grid_rows);
98 }
99
100 void draw_field(int xcells, int ycells)
101 {
102         int i, j;
103
104         if(show_blocks) {
105                 for(i=0; i<ycells; i++) {
106                         for(j=0; j<xcells; j++) {
107                                 draw_tile(j, i, xcells, ycells);
108                         }
109                 }
110         }
111 }
112
113 #define DX      0.75
114 #define DZ      0.45
115
116 static struct vec3 tileverts[] = {
117         {-1, -1, 0}, {1, -1, 0}, {1, 1, 0}, {-1, 1, 0},
118         {-1 + DX, -1 + DX, DZ}, {1 - DX, -1 + DX, DZ},
119         {1 - DX, 1 - DX, DZ}, {-1 + DX, 1 - DX, DZ}
120 };
121 static struct vec3 tilecol[] = {
122         {0.5, 0.5, 0.5},        /* left */
123         {0.2, 0.2, 0.2},        /* bottom */
124         {0.5, 0.5, 0.5},        /* right */
125         {0.8, 0.8, 0.8},        /* top */
126         {0.65, 0.65, 0.65},     /* front */
127         {0, 0, 0}, {0, 0, 0}, {0, 0, 0}
128 };
129 static uint16_t tileidx[] = { /* 3 +---------+ 2 */
130         4, 7, 3, 0,               /*   |\ 7   6 /|   */
131         5, 4, 0, 1,               /*   | +-----+ |   */
132         6, 5, 1, 2,               /*   | |     | |   */
133         7, 6, 2, 3,               /*   | +-----+ |   */
134         5, 6, 7, 4                /*   |/ 4   5 \|   */
135 };                            /* 0 +---------+ 1 */
136
137 void draw_tile(int col, int row, int xcells, int ycells)
138 {
139         int ncells = xcells > ycells ? xcells : ycells;
140         float cellsz = 2.0 / ncells;
141
142         glPushMatrix();
143         glTranslatef((col - xcells / 2.0 + 0.5) * cellsz, (row - ycells / 2.0 + 0.5) * cellsz, 0);
144         glScalef(cellsz * 0.5, cellsz * 0.5, cellsz * 0.5);
145
146         glEnableClientState(GL_VERTEX_ARRAY);
147         glEnableClientState(GL_COLOR_ARRAY);
148         glVertexPointer(3, GL_FLOAT, 0, tileverts);
149         glColorPointer(3, GL_FLOAT, 0, tilecol);
150         glDrawElements(GL_QUADS, 20, GL_UNSIGNED_SHORT, tileidx);
151         glDisableClientState(GL_VERTEX_ARRAY);
152         glDisableClientState(GL_COLOR_ARRAY);
153
154         glPopMatrix();
155 }
156
157 void set_view_matrix(int eye, float ipd)
158 {
159         const float offs[] = {0.5, 0.0, -0.5};
160
161         glMatrixMode(GL_MODELVIEW);
162         glLoadIdentity();
163         glTranslatef(offs[eye + 1] * ipd, 0, 0);
164 }
165
166 void set_proj_matrix(int eye, float ipd)
167 {
168         const float offs[] = {1.0, 0.0, -1.0};
169         float vpsz = 0.5 / (2.0 / 3.0);
170
171         float right = aspect * vpsz;
172         float top = vpsz;
173         float shift = offs[eye + 1] * ipd * 0.25; /* 0.25 -> 0.5 * znear */
174
175         glMatrixMode(GL_PROJECTION);
176         glLoadIdentity();
177         glFrustum(-right + shift, right + shift, -top, top, 0.5, 500.0);
178 }
179
180 void reshape(int x, int y)
181 {
182         win_width = x;
183         win_height = y;
184         aspect = (float)win_width / (float)win_height;
185         glViewport(0, 0, x, y);
186 }
187
188 void keyb(unsigned char key, int x, int y)
189 {
190         switch(key) {
191         case 27:
192                 exit(0);
193
194         case '1':
195         case '2':
196         case '3':
197                 view = key - '2';
198                 glutPostRedisplay();
199                 break;
200
201         case 's':
202                 show_stereo = !show_stereo;
203                 glutPostRedisplay();
204                 break;
205
206         case ' ':
207                 if(win_height > 160) {
208                         glutReshapeWindow(win_width / 4, win_height / 4);
209                 } else {
210                         glutReshapeWindow(win_width * 4, win_height * 4);
211                 }
212                 glutPostRedisplay();
213                 break;
214
215         case 't':
216                 show_blocks = !show_blocks;
217                 glutPostRedisplay();
218                 break;
219
220         case 'g':
221                 show_grid = !show_grid;
222                 glutPostRedisplay();
223                 break;
224         }
225 }
226
227
228 void save_tiles(void)
229 {
230         unsigned char *pixels, *tilepix;
231         int i, j, tilesz = win_height / grid_rows;
232         char fname[256];
233
234         if(!(pixels = malloc(win_width * win_height * 3))) {
235                 fprintf(stderr, "failed to allocate pixel buffer\n");
236                 return;
237         }
238         glReadPixels(0, 0, win_width, win_height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
239
240         for(i=0; i<grid_rows; i++) {
241                 for(j=0; j<grid_cols; j++) {
242                         tilepix = pixels + (i * win_width + j) * tilesz * 3;
243
244                         sprintf(fname, "tile-%02d%02d.ppm", j, i);
245                         save_tile(fname, tilepix, tilesz, tilesz, win_width * 3);
246                 }
247         }
248 }
249
250 int save_tile(const char *fname, unsigned char *pixptr, int xsz, int ysz, int pitch)
251 {
252         int i, j;
253         FILE *fp;
254
255         printf("saving tile: %s\n", fname);
256
257         if(!(fp = fopen(fname, "wb"))) {
258                 fprintf(stderr, "failed to open %s for writing: %s\n", fname, strerror(errno));
259                 return -1;
260         }
261
262         pixptr += ysz * pitch;
263         fprintf(fp, "P6\n%d %d\n255\n", xsz, ysz);
264         for(i=0; i<ysz; i++) {
265                 pixptr -= pitch;
266                 for(j=0; j<xsz; j++) {
267                         int r = pixptr[j * 3];
268                         int g = pixptr[j * 3 + 1];
269                         int b = pixptr[j * 3 + 2];
270                         fputc(r, fp);
271                         fputc(g, fp);
272                         fputc(b, fp);
273                 }
274         }
275
276         fclose(fp);
277         return 0;
278 }
279
280 void draw_grid(void)
281 {
282         int x, y;
283
284         glMatrixMode(GL_PROJECTION);
285         glPushMatrix();
286         glLoadIdentity();
287         glOrtho(0, win_width, 0, win_height, -1, 1);
288
289         glMatrixMode(GL_MODELVIEW);
290         glPushMatrix();
291         glLoadIdentity();
292
293         glBegin(GL_LINES);
294         glColor3f(0.5, 0.2, 0.1);
295         for(y=0; y<win_height; y += 32) {
296                 glVertex2f(0, y);
297                 glVertex2f(win_width, y);
298         }
299         for(x=0; x<win_width; x += 32) {
300                 glVertex2f(x, 0);
301                 glVertex2f(x, win_height);
302         }
303         glEnd();
304
305         glMatrixMode(GL_PROJECTION);
306         glPopMatrix();
307         glMatrixMode(GL_MODELVIEW);
308         glPopMatrix();
309 }