nuclear@5: /* This file implements all calls made to dos-specific code using SDL */ nuclear@5: #include nuclear@5: #include nuclear@5: #include nuclear@5: #ifdef DOSEMU_CAPTURE nuclear@5: #include nuclear@5: #endif nuclear@5: #include "gfx.h" nuclear@5: #include "mouse.h" nuclear@5: #include "keyb.h" nuclear@5: #include "timer.h" nuclear@5: nuclear@9: static void cleanup(void); nuclear@5: static void proc_events(void); nuclear@12: static int translate_sdlkey(int sym); nuclear@12: static void update_modkeys(void); nuclear@5: static void capture_frame(unsigned char *frame); nuclear@5: nuclear@9: static void init_sdl(void) nuclear@5: { nuclear@5: const SDL_version *ver; nuclear@5: nuclear@5: if(!SDL_WasInit(SDL_INIT_EVERYTHING)) { nuclear@5: SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); nuclear@5: nuclear@5: if((ver = SDL_Linked_Version())) { nuclear@5: printf("SDL %d.%d.%d initialized\n", ver->major, ver->minor, ver->patch); nuclear@5: } nuclear@9: atexit(cleanup); nuclear@5: } nuclear@5: } nuclear@5: nuclear@9: static void cleanup(void) nuclear@9: { nuclear@9: SDL_Quit(); nuclear@9: } nuclear@9: nuclear@5: /* ----- graphics (gfx.c (vbe) implementation) ----- */ nuclear@5: static SDL_Surface *fbsurf; nuclear@5: static int scale = 1; nuclear@5: static int frames_to_capture; nuclear@5: nuclear@5: static struct { nuclear@5: unsigned char r, g, b; nuclear@5: } palette[256]; nuclear@5: nuclear@5: nuclear@5: void *set_video_mode(int xsz, int ysz, int bpp) nuclear@5: { nuclear@5: unsigned int sdl_flags = bpp <= 8 ? SDL_HWPALETTE : 0; nuclear@5: char *env; nuclear@5: nuclear@5: if(getenv("DOSEMU_DOUBLESIZE")) { nuclear@5: scale = 2; nuclear@5: } nuclear@5: nuclear@5: if((env = getenv("DOSEMU_SCALE"))) { nuclear@5: int n = atoi(env); nuclear@5: if(n > 0) { nuclear@5: scale = n; nuclear@5: } nuclear@5: } nuclear@5: xsz *= scale; nuclear@5: ysz *= scale; nuclear@5: nuclear@5: if(getenv("DOSEMU_FULLSCREEN")) { nuclear@5: sdl_flags |= SDL_FULLSCREEN; nuclear@5: } nuclear@5: nuclear@5: init_sdl(); nuclear@5: nuclear@5: if(!(fbsurf = SDL_SetVideoMode(xsz, ysz, bpp, sdl_flags))) { nuclear@5: fprintf(stderr, "failed to set video mode\n"); nuclear@5: abort(); nuclear@5: } nuclear@5: SDL_WM_SetCaption("Rayzor", 0); nuclear@5: /*SDL_ShowCursor(0);*/ nuclear@5: nuclear@5: return fbsurf->pixels; nuclear@5: } nuclear@5: nuclear@5: int set_text_mode(void) nuclear@5: { nuclear@5: SDL_ShowCursor(1); nuclear@5: SDL_EnableKeyRepeat(0, 0); nuclear@5: return 0; nuclear@5: } nuclear@5: nuclear@5: int get_color_depth(void) nuclear@5: { nuclear@5: return fbsurf->format->BitsPerPixel; nuclear@5: } nuclear@5: nuclear@5: static int count_bits(unsigned int x) nuclear@5: { nuclear@5: int i, count = 0; nuclear@5: for(i=0; i<32; i++) { nuclear@5: if(x & 1) { nuclear@5: count++; nuclear@5: } nuclear@5: x >>= 1; nuclear@5: } nuclear@5: return count; nuclear@5: } nuclear@5: nuclear@5: int get_color_bits(int *rbits, int *gbits, int *bbits) nuclear@5: { nuclear@5: *rbits = count_bits(fbsurf->format->Rmask); nuclear@5: *gbits = count_bits(fbsurf->format->Gmask); nuclear@5: *bbits = count_bits(fbsurf->format->Bmask); nuclear@5: return *rbits + *gbits + *bbits; nuclear@5: } nuclear@5: nuclear@5: int get_color_shift(int *rshift, int *gshift, int *bshift) nuclear@5: { nuclear@5: *rshift = fbsurf->format->Rshift; nuclear@5: *gshift = fbsurf->format->Gshift; nuclear@5: *bshift = fbsurf->format->Bshift; nuclear@5: return 0; nuclear@5: } nuclear@5: nuclear@5: int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask) nuclear@5: { nuclear@5: *rmask = fbsurf->format->Rmask; nuclear@5: *gmask = fbsurf->format->Gmask; nuclear@5: *bmask = fbsurf->format->Bmask; nuclear@5: return 0; nuclear@5: } nuclear@5: nuclear@5: nuclear@5: void set_palette(int idx, int r, int g, int b) nuclear@5: { nuclear@5: SDL_Color col; nuclear@5: col.r = r; nuclear@5: col.g = g; nuclear@5: col.b = b; nuclear@5: nuclear@5: if(SDL_SetPalette(fbsurf, SDL_LOGPAL | SDL_PHYSPAL, &col, idx, 1) != 1) { nuclear@5: fprintf(stderr, "set_palette failed to set the required color\n"); nuclear@5: } nuclear@5: nuclear@5: palette[idx].r = r; nuclear@5: palette[idx].g = g; nuclear@5: palette[idx].b = b; nuclear@5: } nuclear@5: nuclear@5: static int copy_frame_called; nuclear@5: nuclear@5: void copy_frame(void *pixels) nuclear@5: { nuclear@5: unsigned char *frame = (unsigned char*)pixels; nuclear@5: copy_frame_called = 1; nuclear@5: nuclear@5: if(SDL_MUSTLOCK(fbsurf)) { nuclear@5: SDL_LockSurface(fbsurf); nuclear@5: } nuclear@5: nuclear@5: if(pixels) { nuclear@5: if(scale > 1) { nuclear@5: int i, j, xsz, ysz; nuclear@5: unsigned char *dest = fbsurf->pixels; nuclear@5: nuclear@5: xsz = fbsurf->w * scale; nuclear@5: ysz = fbsurf->h * scale; nuclear@5: nuclear@5: for(i=0; iw + (j / scale)]; nuclear@5: } nuclear@5: } nuclear@5: } else { nuclear@5: int num_pixels = fbsurf->w * fbsurf->h; nuclear@5: memcpy(fbsurf->pixels, frame, num_pixels * fbsurf->format->BytesPerPixel); nuclear@5: } nuclear@5: } nuclear@5: nuclear@5: if(SDL_MUSTLOCK(fbsurf)) { nuclear@5: SDL_UnlockSurface(fbsurf); nuclear@5: } nuclear@5: nuclear@5: SDL_Flip(fbsurf); nuclear@5: nuclear@5: if(frames_to_capture > 0) { nuclear@5: capture_frame(pixels); nuclear@5: --frames_to_capture; nuclear@5: } nuclear@5: nuclear@5: /* also print fps every second ... */ nuclear@9: /*{ nuclear@5: static long prev_fps, num_frames; nuclear@5: long msec, dt; nuclear@5: nuclear@5: msec = get_msec(); nuclear@5: dt = msec - prev_fps; nuclear@5: if(dt >= 1000) { nuclear@5: float fps = (float)num_frames / ((float)dt / 1000.0f); nuclear@5: printf("framerate: %.1f \r", fps); nuclear@5: fflush(stdout); nuclear@5: num_frames = 0; nuclear@5: prev_fps = msec; nuclear@5: } else { nuclear@5: num_frames++; nuclear@5: } nuclear@9: }*/ nuclear@5: } nuclear@5: nuclear@5: #define spin_delay(ms) \ nuclear@5: do { \ nuclear@5: unsigned int end = SDL_GetTicks() + ms; \ nuclear@5: while((prev_msec = SDL_GetTicks()) < end); \ nuclear@5: } while(0) nuclear@5: nuclear@5: #define FRAME_INTERVAL (1000/70) nuclear@5: nuclear@5: void wait_vsync(void) nuclear@5: { nuclear@9: /*static int prev_msec; nuclear@9: int msec, dt, tleft;*/ nuclear@5: nuclear@5: if(!copy_frame_called) { nuclear@5: copy_frame(0); nuclear@5: copy_frame_called = 0; nuclear@5: } nuclear@5: nuclear@9: /* nuclear@5: msec = SDL_GetTicks(); nuclear@5: nuclear@5: dt = msec - prev_msec; nuclear@5: nuclear@5: tleft = FRAME_INTERVAL - dt; nuclear@5: if(tleft > 0) { nuclear@5: int coarse = tleft & 0xfffffff8; nuclear@5: tleft = tleft & 7; nuclear@5: nuclear@5: if(coarse) { nuclear@5: SDL_Delay(coarse); nuclear@5: } nuclear@5: if(tleft) { nuclear@5: spin_delay(tleft); nuclear@5: } else { nuclear@5: prev_msec = SDL_GetTicks(); nuclear@5: } nuclear@5: } else { nuclear@5: prev_msec = msec; nuclear@5: } nuclear@9: */ nuclear@5: } nuclear@5: nuclear@5: static int cap_count = 0; nuclear@5: void begin_capture(int frames) nuclear@5: { nuclear@5: frames_to_capture = frames; nuclear@5: } nuclear@5: nuclear@5: void end_capture(void) nuclear@5: { nuclear@5: cap_count = 0; nuclear@5: frames_to_capture = 0; nuclear@5: } nuclear@5: nuclear@5: #define NUMPIX (fbsurf->w * fbsurf->h) nuclear@5: static void capture_frame(unsigned char *frame) nuclear@5: { nuclear@5: #ifdef DOSEMU_CAPTURE nuclear@5: static unsigned char rgbpix[NUMPIX * 4]; nuclear@5: char fname[32]; nuclear@5: int i; nuclear@5: unsigned char *src, *dest; nuclear@5: nuclear@5: sprintf(fname, "frame%04d.png", cap_count++); nuclear@5: nuclear@5: src = frame; nuclear@5: dest = rgbpix; nuclear@5: nuclear@5: for(i=0; iw, fbsurf->h, IMG_FMT_RGBA32); nuclear@5: #endif nuclear@5: } nuclear@5: nuclear@5: nuclear@5: /* ----- event handling (conio.h) ----- */ nuclear@5: static SDL_Event *keybev; nuclear@5: static int mousex, mousey, bnmask; nuclear@5: nuclear@5: static int keystate[256]; nuclear@5: static int num_pressed; nuclear@5: nuclear@5: int kbhit(void) nuclear@5: { nuclear@5: if(!keybev) { nuclear@5: proc_events(); nuclear@5: } nuclear@5: return keybev != 0; nuclear@5: } nuclear@5: nuclear@5: int getch(void) nuclear@5: { nuclear@5: int res; nuclear@5: nuclear@5: while(!keybev) { nuclear@5: SDL_Event ev; nuclear@5: SDL_WaitEvent(&ev); nuclear@5: SDL_PushEvent(&ev); nuclear@5: proc_events(); nuclear@5: } nuclear@5: res = keybev->key.keysym.sym; nuclear@5: keybev = 0; nuclear@5: return res; nuclear@5: } nuclear@5: nuclear@5: /* ----- improved event handling (keyb.h) ---- */ nuclear@12: static char sdlkey_tbl[SDLK_LAST]; nuclear@5: nuclear@5: int kb_init(int bufsz) nuclear@5: { nuclear@12: int i; nuclear@5: init_sdl(); nuclear@5: nuclear@12: /* construct the SDL key translation table */ nuclear@12: for(i=0; i<256; i++) { nuclear@12: sdlkey_tbl[i] = i; /* start from an identity mapping for the first 256 */ nuclear@12: } nuclear@12: /* then change the special keys */ nuclear@12: sdlkey_tbl[SDLK_LALT] = KB_LALT; nuclear@12: sdlkey_tbl[SDLK_RALT] = KB_RALT; nuclear@12: sdlkey_tbl[SDLK_LCTRL] = KB_LCTRL; nuclear@12: sdlkey_tbl[SDLK_RCTRL] = KB_RCTRL; nuclear@12: sdlkey_tbl[SDLK_LSHIFT] = KB_LSHIFT; nuclear@12: for(i=0; i<12; i++) { nuclear@12: sdlkey_tbl[SDLK_F1 + i] = KB_F1 + i; nuclear@12: } nuclear@12: sdlkey_tbl[SDLK_CAPSLOCK] = KB_CAPSLK; nuclear@12: sdlkey_tbl[SDLK_NUMLOCK] = KB_NUMLK; nuclear@12: sdlkey_tbl[SDLK_SCROLLOCK] = KB_SCRLK; nuclear@12: sdlkey_tbl[SDLK_SYSREQ] = KB_SYSRQ; nuclear@12: sdlkey_tbl[SDLK_ESCAPE] = KB_ESC; nuclear@12: sdlkey_tbl[SDLK_INSERT] = KB_INSERT; nuclear@12: sdlkey_tbl[SDLK_DELETE] = KB_DEL; nuclear@12: sdlkey_tbl[SDLK_HOME] = KB_HOME; nuclear@12: sdlkey_tbl[SDLK_END] = KB_END; nuclear@12: sdlkey_tbl[SDLK_PAGEUP] = KB_PGUP; nuclear@12: sdlkey_tbl[SDLK_PAGEDOWN] = KB_PGDN; nuclear@12: sdlkey_tbl[SDLK_LEFT] = KB_LEFT; nuclear@12: sdlkey_tbl[SDLK_RIGHT] = KB_RIGHT; nuclear@12: sdlkey_tbl[SDLK_UP] = KB_UP; nuclear@12: sdlkey_tbl[SDLK_DOWN] = KB_DOWN; nuclear@12: sdlkey_tbl[SDLK_KP_PERIOD] = KB_NUM_DOT; nuclear@12: sdlkey_tbl[SDLK_KP_ENTER] = KB_NUM_ENTER; nuclear@12: sdlkey_tbl[SDLK_KP_PLUS] = KB_NUM_PLUS; nuclear@12: sdlkey_tbl[SDLK_KP_MINUS] = KB_NUM_MINUS; nuclear@12: sdlkey_tbl[SDLK_KP_MULTIPLY] = KB_NUM_MUL; nuclear@12: sdlkey_tbl[SDLK_KP_DIVIDE] = KB_NUM_DIV; nuclear@12: /* TODO missing numeric keypad numbers */ nuclear@12: sdlkey_tbl[SDLK_BACKSPACE] = KB_BACKSP; nuclear@12: nuclear@12: nuclear@5: return 0; nuclear@5: } nuclear@5: nuclear@5: void kb_shutdown(void) nuclear@5: { nuclear@5: } nuclear@5: nuclear@5: int kb_getkey(void) nuclear@5: { nuclear@5: int res = -1; nuclear@5: nuclear@5: proc_events(); nuclear@5: if(keybev) { nuclear@12: res = translate_sdlkey(keybev->key.keysym.sym); nuclear@5: keybev = 0; nuclear@5: } nuclear@5: return res; nuclear@5: } nuclear@5: nuclear@5: int kb_isdown(int key) nuclear@5: { nuclear@12: switch(key) { nuclear@12: case KB_ANY: nuclear@5: return num_pressed; nuclear@12: nuclear@12: case KB_ALT: nuclear@12: return keystate[KB_LALT] + keystate[KB_RALT]; nuclear@12: nuclear@12: case KB_CTRL: nuclear@12: return keystate[KB_LCTRL] + keystate[KB_RCTRL]; nuclear@5: } nuclear@5: return keystate[key]; nuclear@5: } nuclear@5: nuclear@5: /* mouse handling (mouse.c implementation) */ nuclear@5: static unsigned long last_mouse_hide_time; nuclear@5: nuclear@5: int have_mouse(void) nuclear@5: { nuclear@5: return 1; nuclear@5: } nuclear@5: nuclear@8: void set_mouse_limits(int xmin, int ymin, int xmax, int ymax) nuclear@8: { nuclear@8: } nuclear@8: nuclear@5: void set_mouse(int x, int y) nuclear@5: { nuclear@5: SDL_ShowCursor(0); nuclear@5: last_mouse_hide_time = get_msec(); nuclear@5: nuclear@5: SDL_WarpMouse(x * scale, y * scale); nuclear@5: mousex = x; nuclear@5: mousey = y; nuclear@5: } nuclear@5: nuclear@5: int read_mouse(int *xp, int *yp) nuclear@5: { nuclear@5: if(xp) *xp = mousex; nuclear@5: if(yp) *yp = mousey; nuclear@5: return bnmask; nuclear@5: } nuclear@5: nuclear@5: static void proc_events(void) nuclear@5: { nuclear@5: static SDL_Event ev; nuclear@5: nuclear@5: if(last_mouse_hide_time > 0 && get_msec() - last_mouse_hide_time > 3000) { nuclear@5: last_mouse_hide_time = 0; nuclear@5: SDL_ShowCursor(1); nuclear@5: } nuclear@5: nuclear@5: while(SDL_PollEvent(&ev)) { nuclear@5: switch(ev.type) { nuclear@5: case SDL_KEYDOWN: nuclear@5: { nuclear@12: int key = translate_sdlkey(ev.key.keysym.sym); nuclear@5: nuclear@5: if(!keybev) { nuclear@5: keybev = &ev; nuclear@5: } nuclear@5: nuclear@5: if(!keystate[key]) { nuclear@5: keystate[key] = 1; nuclear@5: num_pressed++; nuclear@5: } nuclear@12: nuclear@12: update_modkeys(); nuclear@5: } nuclear@5: break; nuclear@5: nuclear@5: case SDL_KEYUP: nuclear@5: { nuclear@12: int key = translate_sdlkey(ev.key.keysym.sym); nuclear@5: nuclear@5: if(keystate[key]) { nuclear@5: keystate[key] = 0; nuclear@5: if(--num_pressed < 0) { nuclear@5: num_pressed = 0; nuclear@5: } nuclear@5: } nuclear@12: nuclear@12: update_modkeys(); nuclear@5: } nuclear@5: break; nuclear@5: nuclear@5: case SDL_MOUSEMOTION: nuclear@5: mousex = ev.motion.x / scale; nuclear@5: mousey = ev.motion.y / scale; nuclear@5: break; nuclear@5: nuclear@5: case SDL_MOUSEBUTTONDOWN: nuclear@5: case SDL_MOUSEBUTTONUP: nuclear@5: { nuclear@5: int mask = 0; nuclear@5: switch(ev.button.button) { nuclear@5: case SDL_BUTTON_LEFT: nuclear@5: mask = MOUSE_LEFT; nuclear@5: break; nuclear@5: case SDL_BUTTON_MIDDLE: nuclear@5: mask = MOUSE_MIDDLE; nuclear@5: break; nuclear@5: case SDL_BUTTON_RIGHT: nuclear@5: mask = MOUSE_RIGHT; nuclear@5: default: nuclear@5: break; nuclear@5: } nuclear@5: if(!mask) { nuclear@5: break; nuclear@5: } nuclear@5: nuclear@5: if(ev.button.state == SDL_PRESSED) { nuclear@5: bnmask |= mask; nuclear@5: } else { nuclear@5: bnmask &= ~mask; nuclear@5: } nuclear@5: } nuclear@5: break; nuclear@5: nuclear@5: default: nuclear@5: break; nuclear@5: } nuclear@5: } nuclear@5: } nuclear@5: nuclear@12: static int translate_sdlkey(int sym) nuclear@12: { nuclear@12: if(sym >= 0 && sym < 256) { nuclear@12: return sdlkey_tbl[sym]; nuclear@12: } nuclear@12: return sym; nuclear@12: } nuclear@12: nuclear@12: static void update_modkeys(void) nuclear@12: { nuclear@12: unsigned int mod = SDL_GetModState(); nuclear@12: nuclear@12: keystate[KB_LALT] = mod & KMOD_LALT; nuclear@12: keystate[KB_RALT] = mod & KMOD_RALT; nuclear@12: keystate[KB_LCTRL] = mod & KMOD_LCTRL; nuclear@12: keystate[KB_RCTRL] = mod & KMOD_RCTRL; nuclear@12: keystate[KB_LSHIFT] = mod & KMOD_LSHIFT; nuclear@12: keystate[KB_RSHIFT] = mod & KMOD_RSHIFT; nuclear@12: } nuclear@12: nuclear@5: /* ---- timer.c implementation ---- */ nuclear@5: static Uint32 start_time; nuclear@5: nuclear@5: void init_timer(int res_hz) nuclear@5: { nuclear@5: init_sdl(); nuclear@5: reset_timer(); nuclear@5: } nuclear@5: nuclear@5: void reset_timer(void) nuclear@5: { nuclear@5: start_time = SDL_GetTicks(); nuclear@5: printf("resetting timer: %u, %lu\n", start_time, get_msec()); nuclear@5: } nuclear@5: nuclear@5: unsigned long get_msec(void) nuclear@5: { nuclear@5: Uint32 ticks = SDL_GetTicks(); nuclear@5: return (unsigned long)(ticks - start_time); nuclear@5: }