rev |
line source |
nuclear@1
|
1 #include <stdio.h>
|
nuclear@1
|
2 #include <stdlib.h>
|
nuclear@1
|
3 #include <string.h>
|
nuclear@1
|
4 #include <math.h>
|
nuclear@7
|
5 #include <signal.h>
|
nuclear@1
|
6 #include "inttypes.h"
|
nuclear@1
|
7 #include "gfx.h"
|
nuclear@1
|
8 #include "keyb.h"
|
nuclear@1
|
9 #include "mouse.h"
|
nuclear@1
|
10 #include "logger.h"
|
nuclear@6
|
11 #include "min3d.h"
|
nuclear@6
|
12 #include "scene.h"
|
nuclear@1
|
13
|
nuclear@6
|
14 static bool init();
|
nuclear@6
|
15 static void cleanup();
|
nuclear@1
|
16 static void display();
|
nuclear@1
|
17 static void swap_buffers();
|
nuclear@7
|
18 static void draw_cursor(unsigned char *buf, int mx, int my);
|
nuclear@1
|
19 static void handle_keyboard();
|
nuclear@1
|
20 static void handle_mouse();
|
nuclear@7
|
21 static void mouse_button(int bn, int x, int y);
|
nuclear@7
|
22 static void mouse_motion(int x, int y);
|
nuclear@1
|
23 static bool parse_args(int argc, char **argv);
|
nuclear@7
|
24 static void sig(int s);
|
nuclear@1
|
25
|
nuclear@6
|
26 static int xsz = 640;
|
nuclear@6
|
27 static int ysz = 480;
|
nuclear@7
|
28 static int bpp = 24;
|
nuclear@1
|
29 static int bytespp;
|
nuclear@6
|
30 static bool novideo;
|
nuclear@1
|
31 static unsigned char *fb;
|
nuclear@1
|
32 static unsigned char *backbuf;
|
nuclear@1
|
33 static int rbits, gbits, bbits;
|
nuclear@1
|
34 static int rshift, gshift, bshift;
|
nuclear@1
|
35 static unsigned int rmask, gmask, bmask;
|
nuclear@1
|
36
|
nuclear@7
|
37 static int mx, my; // mouse cursor
|
nuclear@7
|
38 static float cam_theta, cam_phi = 25, cam_dist = 8;
|
nuclear@7
|
39
|
nuclear@7
|
40 static bool use_mouse;
|
nuclear@1
|
41 static bool quit;
|
nuclear@1
|
42
|
nuclear@6
|
43 struct m3d_image rbuf;
|
nuclear@6
|
44 static Scene *scn;
|
nuclear@6
|
45
|
nuclear@1
|
46 int main(int argc, char **argv)
|
nuclear@1
|
47 {
|
nuclear@1
|
48 if(!parse_args(argc, argv)) {
|
nuclear@1
|
49 return 1;
|
nuclear@1
|
50 }
|
nuclear@6
|
51 if(!init()) {
|
nuclear@1
|
52 return 1;
|
nuclear@1
|
53 }
|
nuclear@1
|
54
|
nuclear@1
|
55 // main loop
|
nuclear@1
|
56 for(;;) {
|
nuclear@1
|
57 handle_keyboard();
|
nuclear@1
|
58 handle_mouse();
|
nuclear@1
|
59 if(quit) break;
|
nuclear@1
|
60
|
nuclear@1
|
61 display();
|
nuclear@6
|
62
|
nuclear@6
|
63 if(novideo) break;
|
nuclear@1
|
64 }
|
nuclear@1
|
65
|
nuclear@6
|
66 cleanup();
|
nuclear@1
|
67 printf("Thank you for using Rayzor!\n");
|
nuclear@1
|
68 return 0;
|
nuclear@1
|
69 }
|
nuclear@1
|
70
|
nuclear@6
|
71 static bool init()
|
nuclear@6
|
72 {
|
nuclear@7
|
73 signal(SIGINT, sig);
|
nuclear@7
|
74 signal(SIGSEGV, sig);
|
nuclear@7
|
75 signal(SIGILL, sig);
|
nuclear@7
|
76 signal(SIGFPE, sig);
|
nuclear@7
|
77
|
nuclear@6
|
78 if(!novideo) {
|
nuclear@6
|
79 if(kb_init(32) == -1) {
|
nuclear@6
|
80 fprintf(stderr, "failed to initialize keyboard driver\n");
|
nuclear@6
|
81 return false;
|
nuclear@6
|
82 }
|
nuclear@6
|
83
|
nuclear@6
|
84 if(!(fb = (unsigned char*)set_video_mode(xsz, ysz, bpp))) {
|
nuclear@6
|
85 set_text_mode();
|
nuclear@6
|
86 fprintf(stderr, "failed to set video mode: %dx%d %dbpp\n", xsz, ysz, bpp);
|
nuclear@6
|
87 return false;
|
nuclear@6
|
88 }
|
nuclear@6
|
89 bpp = get_color_depth();
|
nuclear@6
|
90 get_color_bits(&rbits, &gbits, &bbits);
|
nuclear@6
|
91 get_color_shift(&rshift, &gshift, &bshift);
|
nuclear@6
|
92 get_color_mask(&rmask, &gmask, &bmask);
|
nuclear@6
|
93 bytespp = (int)ceil(bpp / 8.0);
|
nuclear@6
|
94
|
nuclear@6
|
95 printlog("bpp: %d (%d %d %d)\n", bpp, rbits, gbits, bbits);
|
nuclear@6
|
96 printlog("shift: %d %d %d\n", rshift, gshift, bshift);
|
nuclear@6
|
97 printlog("mask: %x %x %x\n", rmask, gmask, bmask);
|
nuclear@7
|
98
|
nuclear@7
|
99 if(have_mouse()) {
|
nuclear@7
|
100 use_mouse = true;
|
nuclear@7
|
101 set_mouse_limits(0, 0, xsz - 1, ysz - 1);
|
nuclear@7
|
102 }
|
nuclear@6
|
103 } else {
|
nuclear@6
|
104 logger_output(stdout);
|
nuclear@6
|
105 printlog("novideo (debug) mode\n");
|
nuclear@6
|
106 bpp = 24;
|
nuclear@6
|
107 rbits = gbits = bbits = 8;
|
nuclear@6
|
108 bytespp = 3;
|
nuclear@6
|
109 }
|
nuclear@6
|
110
|
nuclear@6
|
111 backbuf = new unsigned char[xsz * ysz * 3];
|
nuclear@6
|
112 if(!backbuf) {
|
nuclear@6
|
113 return false;
|
nuclear@6
|
114 }
|
nuclear@6
|
115
|
nuclear@6
|
116 m3d_init();
|
nuclear@6
|
117 rbuf.pixels = backbuf;
|
nuclear@6
|
118 rbuf.xsz = xsz;
|
nuclear@6
|
119 rbuf.ysz = ysz;
|
nuclear@6
|
120 m3d_set_buffers(&rbuf, 0);
|
nuclear@6
|
121
|
nuclear@6
|
122 m3d_matrix_mode(M3D_PROJECTION);
|
nuclear@6
|
123 m3d_load_identity();
|
nuclear@6
|
124 m3d_perspective(50.0, (float)xsz / (float)ysz, 0.5, 500.0);
|
nuclear@6
|
125
|
nuclear@6
|
126 scn = new Scene;
|
nuclear@6
|
127
|
nuclear@6
|
128 Sphere *sph = new Sphere;
|
nuclear@6
|
129 scn->add_object(sph);
|
nuclear@6
|
130
|
nuclear@6
|
131 return true;
|
nuclear@6
|
132 }
|
nuclear@6
|
133
|
nuclear@6
|
134 static void cleanup()
|
nuclear@6
|
135 {
|
nuclear@6
|
136 delete scn;
|
nuclear@6
|
137
|
nuclear@6
|
138 m3d_shutdown();
|
nuclear@6
|
139 delete [] backbuf;
|
nuclear@6
|
140
|
nuclear@6
|
141 if(!novideo) {
|
nuclear@6
|
142 set_text_mode();
|
nuclear@6
|
143 kb_shutdown();
|
nuclear@6
|
144 }
|
nuclear@6
|
145 }
|
nuclear@6
|
146
|
nuclear@6
|
147
|
nuclear@1
|
148 static void display()
|
nuclear@1
|
149 {
|
nuclear@6
|
150 m3d_clear(M3D_COLOR_BUFFER_BIT);
|
nuclear@1
|
151
|
nuclear@6
|
152 m3d_matrix_mode(M3D_MODELVIEW);
|
nuclear@6
|
153 m3d_load_identity();
|
nuclear@7
|
154 m3d_translate(0, 0, -cam_dist);
|
nuclear@7
|
155 m3d_rotate(cam_phi, 1, 0, 0);
|
nuclear@7
|
156 m3d_rotate(cam_theta, 0, 1, 0);
|
nuclear@6
|
157
|
nuclear@6
|
158 scn->draw();
|
nuclear@6
|
159
|
nuclear@7
|
160 // draw the mouse cursor
|
nuclear@7
|
161 if(use_mouse) {
|
nuclear@7
|
162 draw_cursor(backbuf, mx, my);
|
nuclear@7
|
163 }
|
nuclear@7
|
164
|
nuclear@6
|
165 if(!novideo) {
|
nuclear@6
|
166 swap_buffers();
|
nuclear@6
|
167 wait_vsync();
|
nuclear@1
|
168 }
|
nuclear@1
|
169 }
|
nuclear@1
|
170
|
nuclear@1
|
171 #define PACK_RGB(r, g, b) \
|
nuclear@1
|
172 ((((r) << rshift) & rmask) | \
|
nuclear@1
|
173 (((g) << gshift) & gmask) | \
|
nuclear@1
|
174 (((b) << bshift) & bmask))
|
nuclear@1
|
175
|
nuclear@1
|
176 static void swap_buffers()
|
nuclear@1
|
177 {
|
nuclear@1
|
178 unsigned char *src = backbuf;
|
nuclear@1
|
179 int num_pixels = xsz * ysz;
|
nuclear@1
|
180
|
nuclear@1
|
181 switch(bpp) {
|
nuclear@1
|
182 case 32:
|
nuclear@1
|
183 {
|
nuclear@1
|
184 uint32_t *dest = (uint32_t*)fb;
|
nuclear@1
|
185 for(int i=0; i<num_pixels; i++) {
|
nuclear@1
|
186 *dest++ = PACK_RGB(src[0], src[1], src[2]);
|
nuclear@1
|
187 src += 3;
|
nuclear@1
|
188 }
|
nuclear@1
|
189 }
|
nuclear@1
|
190 break;
|
nuclear@1
|
191
|
nuclear@1
|
192 case 24:
|
nuclear@1
|
193 memcpy(fb, backbuf, num_pixels * 3);
|
nuclear@1
|
194 break;
|
nuclear@1
|
195
|
nuclear@1
|
196 case 16:
|
nuclear@1
|
197 case 15:
|
nuclear@1
|
198 {
|
nuclear@1
|
199 int srs = 8 - rbits;
|
nuclear@1
|
200 int sgs = 8 - gbits;
|
nuclear@1
|
201 int sbs = 8 - bbits;
|
nuclear@1
|
202 uint16_t *dest = (uint16_t*)fb;
|
nuclear@1
|
203 for(int i=0; i<num_pixels; i++) {
|
nuclear@1
|
204 *dest++ = PACK_RGB(src[0] >> srs, src[1] >> sgs, src[2] >> sbs);
|
nuclear@1
|
205 src += 3;
|
nuclear@1
|
206 }
|
nuclear@1
|
207 }
|
nuclear@1
|
208 break;
|
nuclear@1
|
209
|
nuclear@1
|
210 default:
|
nuclear@1
|
211 break;
|
nuclear@1
|
212 }
|
nuclear@1
|
213 }
|
nuclear@1
|
214
|
nuclear@7
|
215 static void draw_cursor(unsigned char *buf, int mx, int my)
|
nuclear@7
|
216 {
|
nuclear@7
|
217 unsigned char *cptr = buf + (my * xsz + mx) * 3;
|
nuclear@7
|
218 int i, cw[2] = {4, 4}, ch[2] = {4, 4};
|
nuclear@7
|
219
|
nuclear@7
|
220 if(mx < cw[0]) cw[0] = mx;
|
nuclear@7
|
221 if(my < ch[0]) ch[0] = my;
|
nuclear@7
|
222 if(xsz - mx < cw[1]) cw[1] = xsz - mx - 1;
|
nuclear@7
|
223 if(ysz - my < ch[1]) ch[1] = ysz - my - 1;
|
nuclear@7
|
224
|
nuclear@7
|
225 for(i=1; i<cw[0]; i++) {
|
nuclear@7
|
226 int idx = -i * 3;
|
nuclear@7
|
227 cptr[idx] = 255;
|
nuclear@7
|
228 cptr[idx + 1] = 255;
|
nuclear@7
|
229 cptr[idx + 2] = 255;
|
nuclear@7
|
230 }
|
nuclear@7
|
231 for(i=1; i<cw[1]; i++) {
|
nuclear@7
|
232 int idx = i * 3;
|
nuclear@7
|
233 cptr[idx] = 255;
|
nuclear@7
|
234 cptr[idx + 1] = 255;
|
nuclear@7
|
235 cptr[idx + 2] = 255;
|
nuclear@7
|
236 }
|
nuclear@7
|
237 for(i=1; i<ch[0]; i++) {
|
nuclear@7
|
238 int idx = -i * xsz * 3;
|
nuclear@7
|
239 cptr[idx] = 255;
|
nuclear@7
|
240 cptr[idx + 1] = 255;
|
nuclear@7
|
241 cptr[idx + 2] = 255;
|
nuclear@7
|
242 }
|
nuclear@7
|
243 for(i=1; i<ch[1]; i++) {
|
nuclear@7
|
244 int idx = i * xsz * 3;
|
nuclear@7
|
245 cptr[idx] = 255;
|
nuclear@7
|
246 cptr[idx + 1] = 255;
|
nuclear@7
|
247 cptr[idx + 2] = 255;
|
nuclear@7
|
248 }
|
nuclear@7
|
249 }
|
nuclear@7
|
250
|
nuclear@1
|
251 static void handle_keyboard()
|
nuclear@1
|
252 {
|
nuclear@5
|
253 int key;
|
nuclear@1
|
254
|
nuclear@6
|
255 if(novideo) return;
|
nuclear@6
|
256
|
nuclear@5
|
257 while((key = kb_getkey()) != -1) {
|
nuclear@5
|
258 switch(key) {
|
nuclear@5
|
259 case 27:
|
nuclear@5
|
260 quit = true;
|
nuclear@5
|
261 return;
|
nuclear@5
|
262 }
|
nuclear@1
|
263 }
|
nuclear@1
|
264 }
|
nuclear@1
|
265
|
nuclear@1
|
266 static void handle_mouse()
|
nuclear@1
|
267 {
|
nuclear@7
|
268 static int prev_mx, prev_my, prev_bnmask;
|
nuclear@7
|
269 int /*mx, my,*/ bnmask;
|
nuclear@7
|
270
|
nuclear@7
|
271 if(!use_mouse || novideo) return;
|
nuclear@7
|
272
|
nuclear@7
|
273 bnmask = read_mouse(&mx, &my);
|
nuclear@7
|
274 if(bnmask != prev_bnmask) {
|
nuclear@7
|
275 mouse_button(bnmask, mx, my);
|
nuclear@7
|
276 prev_bnmask = bnmask;
|
nuclear@7
|
277 }
|
nuclear@7
|
278 if(mx != prev_mx || my != prev_my) {
|
nuclear@7
|
279 mouse_motion(mx, my);
|
nuclear@7
|
280 prev_mx = mx;
|
nuclear@7
|
281 prev_my = my;
|
nuclear@7
|
282 }
|
nuclear@7
|
283 }
|
nuclear@7
|
284
|
nuclear@7
|
285 static int bnstate;
|
nuclear@7
|
286 static int prev_x = -1, prev_y;
|
nuclear@7
|
287 static void mouse_button(int bn, int x, int y)
|
nuclear@7
|
288 {
|
nuclear@7
|
289 bnstate = bn;
|
nuclear@7
|
290 prev_x = x;
|
nuclear@7
|
291 prev_y = y;
|
nuclear@7
|
292 }
|
nuclear@7
|
293
|
nuclear@7
|
294 static void mouse_motion(int x, int y)
|
nuclear@7
|
295 {
|
nuclear@7
|
296 int dx = x - prev_x;
|
nuclear@7
|
297 int dy = y - prev_y;
|
nuclear@7
|
298 prev_x = x;
|
nuclear@7
|
299 prev_y = y;
|
nuclear@7
|
300
|
nuclear@7
|
301 if(bnstate & 1) {
|
nuclear@7
|
302 cam_theta += dx * 0.5;
|
nuclear@7
|
303 cam_phi += dy * 0.5;
|
nuclear@7
|
304
|
nuclear@7
|
305 if(cam_phi < -90) cam_phi = -90;
|
nuclear@7
|
306 if(cam_phi > 90) cam_phi = 90;
|
nuclear@7
|
307 }
|
nuclear@7
|
308 if(bnstate & 2) {
|
nuclear@7
|
309 cam_dist += dy * 0.1;
|
nuclear@7
|
310 if(cam_dist < 0) cam_dist = 0;
|
nuclear@7
|
311 }
|
nuclear@1
|
312 }
|
nuclear@1
|
313
|
nuclear@1
|
314 static struct {
|
nuclear@1
|
315 int opt;
|
nuclear@1
|
316 const char *lopt;
|
nuclear@1
|
317 const char *desc;
|
nuclear@1
|
318 } options[] = {
|
nuclear@1
|
319 {'s', "size", "resolution <xres>x<yres>[:bpp]"},
|
nuclear@6
|
320 {'n', "novid", "don't switch video mode (for debugging)"},
|
nuclear@1
|
321 {'h', "help", "print usage information and exit"},
|
nuclear@1
|
322 {-1, 0, 0}
|
nuclear@1
|
323 };
|
nuclear@1
|
324
|
nuclear@1
|
325 static void print_usage(const char *argv0)
|
nuclear@1
|
326 {
|
nuclear@1
|
327 printf("%s usage\n", argv0);
|
nuclear@1
|
328 for(int i=0; options[i].opt != -1; i++) {
|
nuclear@1
|
329 printf(" -%c, -%s: %s\n", options[i].opt, options[i].lopt, options[i].desc);
|
nuclear@1
|
330 }
|
nuclear@1
|
331 exit(0);
|
nuclear@1
|
332 }
|
nuclear@1
|
333
|
nuclear@1
|
334 static bool parse_args(int argc, char **argv)
|
nuclear@1
|
335 {
|
nuclear@1
|
336 for(int i=1; i<argc; i++) {
|
nuclear@1
|
337 if(argv[i][0] == '-') {
|
nuclear@1
|
338 int opt = -1;
|
nuclear@1
|
339
|
nuclear@1
|
340 for(int j=0; options[j].opt != -1; j++) {
|
nuclear@1
|
341 if(argv[i][2] == 0) {
|
nuclear@1
|
342 if(argv[i][1] == options[j].opt) {
|
nuclear@1
|
343 opt = options[j].opt;
|
nuclear@1
|
344 break;
|
nuclear@1
|
345 }
|
nuclear@1
|
346 } else {
|
nuclear@1
|
347 if(strcmp(argv[i] + 1, options[j].lopt) == 0) {
|
nuclear@1
|
348 opt = options[j].opt;
|
nuclear@1
|
349 break;
|
nuclear@1
|
350 }
|
nuclear@1
|
351 }
|
nuclear@1
|
352 }
|
nuclear@1
|
353
|
nuclear@1
|
354 switch(opt) {
|
nuclear@1
|
355 case 's':
|
nuclear@1
|
356 if(sscanf(argv[++i], "%dx%d:%d", &xsz, &ysz, &bpp) < 2) {
|
nuclear@1
|
357 fprintf(stderr, "%s must be followed by a resolution: WxH\n", argv[i - 1]);
|
nuclear@1
|
358 return false;
|
nuclear@1
|
359 }
|
nuclear@1
|
360 break;
|
nuclear@1
|
361
|
nuclear@6
|
362 case 'n':
|
nuclear@6
|
363 novideo = true;
|
nuclear@6
|
364 break;
|
nuclear@6
|
365
|
nuclear@1
|
366 case 'h':
|
nuclear@1
|
367 print_usage(argv[0]); // doesn't return
|
nuclear@1
|
368 break;
|
nuclear@1
|
369
|
nuclear@1
|
370 default:
|
nuclear@1
|
371 fprintf(stderr, "unknown option: %s\n", argv[i]);
|
nuclear@1
|
372 return false;
|
nuclear@1
|
373 }
|
nuclear@1
|
374 } else {
|
nuclear@1
|
375 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
|
nuclear@1
|
376 return false;
|
nuclear@1
|
377 }
|
nuclear@1
|
378 }
|
nuclear@1
|
379 return true;
|
nuclear@1
|
380 }
|
nuclear@7
|
381
|
nuclear@7
|
382 static void sig(int s)
|
nuclear@7
|
383 {
|
nuclear@7
|
384 cleanup();
|
nuclear@7
|
385 fprintf(stderr, "signal caught: %d\n", s);
|
nuclear@7
|
386 }
|