rayzor

annotate src/main.cc @ 9:70e332156d02

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