adjust fov on aspect change
[voxscape] / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <assert.h>
6 #include <GL/glut.h>
7 #include "glfb.h"
8 #include "voxscape.h"
9 #include "lut.h"
10
11 enum {
12         INP_FWD         = 0x01,
13         INP_BACK        = 0x02,
14         INP_LEFT        = 0x04,
15         INP_RIGHT       = 0x08,
16         INP_LTURN       = 0x10,
17         INP_RTURN       = 0x20
18 };
19
20 int init(void);
21 void cleanup(void);
22 void display(void);
23 void idle(void);
24 void reshape(int x, int y);
25 void keyb(unsigned char key, int x, int y);
26 void keyb_up(unsigned char key, int x, int y);
27 void mouse(int bn, int st, int x, int y);
28 void motion(int x, int y);
29
30 int win_width, win_height;
31
32 #define FB_W    640
33 #define FB_H    480
34 unsigned int fb[FB_W * FB_H];
35
36 int mouse_x, mouse_y, mwarp, mbstate[3];
37 int hfilt = VOX_LINEAR, cfilt = VOX_LINEAR;
38
39 unsigned int input;
40 int32_t pos[2], theta, phi;
41 int horizon;
42
43 struct voxscape *vox;
44
45 #define COLOR_HORIZON   0xcc77ff
46 #define COLOR_ZENITH    0x5588cc
47
48
49 int main(int argc, char **argv)
50 {
51         glutInit(&argc, argv);
52         glutInitWindowSize(1280, 960);
53         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
54         glutCreateWindow("voxel landscape test");
55
56         glutDisplayFunc(display);
57         glutIdleFunc(idle);
58         glutReshapeFunc(reshape);
59         glutKeyboardFunc(keyb);
60         glutKeyboardUpFunc(keyb_up);
61         glutMouseFunc(mouse);
62         glutMotionFunc(motion);
63
64         if(init() == -1) {
65                 return 1;
66         }
67         atexit(cleanup);
68
69         glutMainLoop();
70         return 0;
71 }
72
73
74 int init(void)
75 {
76         init_lut();
77
78         pos[0] = 512 << 16;
79         pos[1] = 512 << 16;
80
81         if(!(vox = vox_open("data/height.png", "data/color.png"))) {
82                 return -1;
83         }
84         vox_framebuf(vox, FB_W, FB_H, fb);
85         vox_fog(vox, 260, COLOR_HORIZON);
86         vox_filter(vox, hfilt, cfilt);
87
88         glfb_setup(FB_W, FB_H, GLFB_RGBA32, FB_W * 4);
89         return 0;
90 }
91
92 void cleanup(void)
93 {
94         vox_free(vox);
95 }
96
97 #define WALK_SPEED      0x40000
98 #define TURN_SPEED      0x100
99
100 void update(void)
101 {
102         int32_t fwd[2], right[2];
103
104         if(input & INP_LTURN) theta += TURN_SPEED;
105         if(input & INP_RTURN) theta -= TURN_SPEED;
106
107         fwd[0] = -SIN(theta);
108         fwd[1] = COS(theta);
109         right[0] = fwd[1];
110         right[1] = -fwd[0];
111
112         if(input & INP_FWD) {
113                 pos[0] += fwd[0];
114                 pos[1] += fwd[1];
115         }
116         if(input & INP_BACK) {
117                 pos[0] -= fwd[0];
118                 pos[1] -= fwd[1];
119         }
120         if(input & INP_RIGHT) {
121                 pos[0] += right[0];
122                 pos[1] += right[1];
123         }
124         if(input & INP_LEFT) {
125                 pos[0] -= right[0];
126                 pos[1] -= right[1];
127         }
128
129         vox_view(vox, pos[0], pos[1], -30, theta, phi);
130 }
131
132 void display(void)
133 {
134         update();
135
136         vox_render(vox);
137         vox_sky_grad(vox, COLOR_HORIZON, COLOR_ZENITH);
138
139         glfb_update(fb);
140         glfb_display();
141
142         glutSwapBuffers();
143         assert(glGetError() == GL_NO_ERROR);
144
145         if(mbstate[0]) {
146                 mwarp = 1;
147                 glutWarpPointer(win_width / 2, win_height / 2);
148         }
149 }
150
151 void idle(void)
152 {
153         glutPostRedisplay();
154 }
155
156 void reshape(int x, int y)
157 {
158         float aspect = (float)x / y;
159
160         vox_proj(vox, 140, 40 * aspect, 1, 300);
161
162         glViewport(0, 0, x, y);
163
164         win_width = x;
165         win_height = y;
166 }
167
168 void keyb(unsigned char key, int x, int y)
169 {
170         switch(key) {
171         case 27:
172                 exit(0);
173
174         case 'w':
175                 input |= INP_FWD;
176                 break;
177         case 's':
178                 input |= INP_BACK;
179                 break;
180         case 'a':
181                 input |= INP_LEFT;
182                 break;
183         case 'd':
184                 input |= INP_RIGHT;
185                 break;
186         case 'q':
187                 input |= INP_LTURN;
188                 break;
189         case 'e':
190                 input |= INP_RTURN;
191                 break;
192
193         case 'h':
194                 hfilt ^= 1;
195                 printf("filtering: height(%s) color(%s)\n", hfilt ? "linear" : "nearest",
196                                 cfilt ? "linear" : "nearest");
197                 vox_filter(vox, hfilt, cfilt);
198                 break;
199
200         case 'c':
201                 cfilt ^= 1;
202                 vox_filter(vox, hfilt, cfilt);
203                 printf("filtering: height(%s) color(%s)\n", hfilt ? "linear" : "nearest",
204                                 cfilt ? "linear" : "nearest");
205                 break;
206
207         default:
208                 break;
209         }
210 }
211
212 void keyb_up(unsigned char key, int x, int y)
213 {
214         switch(key) {
215         case 'w':
216                 input &= ~INP_FWD;
217                 break;
218         case 's':
219                 input &= ~INP_BACK;
220                 break;
221         case 'a':
222                 input &= ~INP_LEFT;
223                 break;
224         case 'd':
225                 input &= ~INP_RIGHT;
226                 break;
227         case 'q':
228                 input &= ~INP_LTURN;
229                 break;
230         case 'e':
231                 input &= ~INP_RTURN;
232                 break;
233
234         default:
235                 break;
236         }
237 }
238
239 void mouse(int bn, int st, int x, int y)
240 {
241         int bidx = bn - GLUT_LEFT_BUTTON;
242
243         if(bidx < 3) {
244                 mbstate[bidx] = st == GLUT_DOWN;
245         }
246         mouse_x = x;
247         mouse_y = y;
248
249         if(st == GLUT_DOWN) {
250                 glutSetCursor(GLUT_CURSOR_NONE);
251         } else {
252                 glutSetCursor(GLUT_CURSOR_LEFT_ARROW);
253         }
254 }
255
256 void motion(int x, int y)
257 {
258         int dx = x - mouse_x;
259         int dy = y - mouse_y;
260         mouse_x = x;
261         mouse_y = y;
262
263         if(mwarp) {
264                 mwarp = 0;
265                 return;
266         }
267         if(!(dx | dy)) return;
268
269         if(mbstate[0]) {
270                 theta -= dx << 6;
271                 phi += dy << 8;
272                 if(phi < -0x18000) phi = -0x18000;
273                 if(phi > 0x18000) phi = 0x18000;
274         }
275 }