rayzor

annotate src/main.cc @ 7:75bc89c2abc4

fixed the mouse handling problem
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 07 Apr 2014 08:05:06 +0300
parents a68dbf80d547
children 70e332156d02
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 }