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@5: static void proc_events(void); nuclear@5: static void capture_frame(unsigned char *frame); nuclear@5: nuclear@5: static void init_sdl() 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@5: } nuclear@5: } nuclear@5: 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: SDL_Quit(); 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@5: { 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@5: } 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@5: static int prev_msec; nuclear@5: 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@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@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@5: nuclear@5: int kb_init(int bufsz) nuclear@5: { nuclear@5: init_sdl(); nuclear@5: 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@5: res = 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@5: if(key == KB_ANY) { nuclear@5: return num_pressed; 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@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@5: int key = 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@5: } nuclear@5: break; nuclear@5: nuclear@5: case SDL_KEYUP: nuclear@5: { nuclear@5: int key = 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@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@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: }