rayzor

view src/main.cc @ 10:235c8b764c0b

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