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