deepstone

annotate src/dosemu/dosemu.c @ 38:17a5107b6fa4

- added perspective correct interpolation - added recording functionality - added video capture functionality
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 10 Mar 2014 17:24:42 +0200
parents e234f2a4b6fa
children
rev   line source
nuclear@0 1 /* This file implements all calls made to dos-specific code using SDL
nuclear@0 2 * Don't ask why ...
nuclear@0 3 */
nuclear@0 4
nuclear@0 5 #include <stdlib.h>
nuclear@0 6 #include <assert.h>
nuclear@0 7 #include <SDL.h>
nuclear@38 8 #include <imago2.h>
nuclear@24 9 #include "wvga.h"
nuclear@0 10 #include "conio.h"
nuclear@0 11 #include "mouse.h"
nuclear@34 12 #include "keyb.h"
nuclear@0 13 #include "timer.h"
nuclear@0 14
nuclear@0 15 static void proc_events(void);
nuclear@38 16 static void capture_frame(unsigned char *frame);
nuclear@0 17
nuclear@34 18 static void init_sdl()
nuclear@34 19 {
nuclear@35 20 const SDL_version *ver;
nuclear@35 21
nuclear@34 22 if(!SDL_WasInit(SDL_INIT_EVERYTHING)) {
nuclear@34 23 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
nuclear@35 24
nuclear@35 25 if((ver = SDL_Linked_Version())) {
nuclear@35 26 printf("SDL %d.%d.%d initialized\n", ver->major, ver->minor, ver->patch);
nuclear@35 27 }
nuclear@34 28 }
nuclear@34 29 }
nuclear@34 30
nuclear@24 31 /* ----- graphics (wvga.c implementation) ----- */
nuclear@0 32 static SDL_Surface *fbsurf;
nuclear@35 33 static int scale = 3;
nuclear@38 34 static int frames_to_capture;
nuclear@38 35
nuclear@38 36 static struct {
nuclear@38 37 unsigned char r, g, b;
nuclear@38 38 } palette[256];
nuclear@38 39
nuclear@0 40
nuclear@24 41 int set_video_mode(int mode)
nuclear@0 42 {
nuclear@0 43 int resx = 320, resy = 200;
nuclear@9 44 unsigned int sdl_flags = SDL_HWPALETTE;
nuclear@28 45 char *env;
nuclear@0 46
nuclear@0 47 if(getenv("DOSEMU_DOUBLESIZE")) {
nuclear@28 48 scale = 2;
nuclear@0 49 }
nuclear@0 50
nuclear@28 51 if((env = getenv("DOSEMU_SCALE"))) {
nuclear@28 52 int n = atoi(env);
nuclear@28 53 if(n > 0) {
nuclear@28 54 scale = n;
nuclear@28 55 }
nuclear@28 56 }
nuclear@28 57 resx *= scale;
nuclear@28 58 resy *= scale;
nuclear@28 59
nuclear@9 60 if(getenv("DOSEMU_FULLSCREEN")) {
nuclear@9 61 sdl_flags |= SDL_FULLSCREEN;
nuclear@9 62 }
nuclear@9 63
nuclear@34 64 init_sdl();
nuclear@34 65
nuclear@0 66 switch(mode) {
nuclear@0 67 case 0x13:
nuclear@9 68 if(!(fbsurf = SDL_SetVideoMode(resx, resy, 8, sdl_flags))) {
nuclear@0 69 fprintf(stderr, "failed to set video mode\n");
nuclear@0 70 abort();
nuclear@0 71 }
nuclear@25 72 SDL_WM_SetCaption("Deepstone", 0);
nuclear@28 73 /*SDL_ShowCursor(0);*/
nuclear@34 74 /*SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);*/
nuclear@0 75 break;
nuclear@0 76
nuclear@0 77 case 3:
nuclear@0 78 SDL_ShowCursor(1);
nuclear@11 79 SDL_EnableKeyRepeat(0, 0);
nuclear@0 80 SDL_Quit();
nuclear@0 81 break;
nuclear@0 82
nuclear@0 83 default:
nuclear@0 84 break;
nuclear@0 85 }
nuclear@24 86
nuclear@24 87 return 0;
nuclear@0 88 }
nuclear@0 89
nuclear@24 90 void set_palette(int idx, int *col, int count)
nuclear@24 91 {
nuclear@24 92 int i;
nuclear@24 93
nuclear@24 94 for(i=0; i<count; i++) {
nuclear@24 95 set_pal_entry(idx + i, col[0], col[1], col[2]);
nuclear@24 96 col += 3;
nuclear@24 97 }
nuclear@24 98 }
nuclear@24 99
nuclear@24 100 void set_pal_entry(int idx, int r, int g, int b)
nuclear@0 101 {
nuclear@0 102 SDL_Color col;
nuclear@0 103 col.r = r;
nuclear@0 104 col.g = g;
nuclear@0 105 col.b = b;
nuclear@0 106
nuclear@24 107 if(SDL_SetPalette(fbsurf, SDL_LOGPAL | SDL_PHYSPAL, &col, idx, 1) != 1) {
nuclear@0 108 fprintf(stderr, "set_palette failed to set the required color\n");
nuclear@0 109 }
nuclear@38 110
nuclear@38 111 palette[idx].r = r;
nuclear@38 112 palette[idx].g = g;
nuclear@38 113 palette[idx].b = b;
nuclear@0 114 }
nuclear@0 115
nuclear@24 116 void copy_frame(void *pixels)
nuclear@0 117 {
nuclear@24 118 unsigned char *frame = (unsigned char*)pixels;
nuclear@24 119
nuclear@0 120 if(SDL_MUSTLOCK(fbsurf)) {
nuclear@0 121 SDL_LockSurface(fbsurf);
nuclear@0 122 }
nuclear@0 123
nuclear@28 124 if(scale > 1) {
nuclear@28 125 int i, j, xsz, ysz;
nuclear@28 126 unsigned char *dest = fbsurf->pixels;
nuclear@0 127
nuclear@28 128 xsz = 320 * scale;
nuclear@28 129 ysz = 200 * scale;
nuclear@28 130
nuclear@28 131 for(i=0; i<ysz; i++) {
nuclear@28 132 for(j=0; j<xsz; j++) {
nuclear@28 133 *dest++ = frame[(i / scale) * 320 + (j / scale)];
nuclear@0 134 }
nuclear@0 135 }
nuclear@0 136 } else {
nuclear@0 137 memcpy(fbsurf->pixels, frame, 64000);
nuclear@0 138 }
nuclear@0 139
nuclear@0 140 if(SDL_MUSTLOCK(fbsurf)) {
nuclear@0 141 SDL_UnlockSurface(fbsurf);
nuclear@0 142 }
nuclear@0 143 SDL_Flip(fbsurf);
nuclear@34 144
nuclear@38 145 if(frames_to_capture > 0) {
nuclear@38 146 capture_frame(pixels);
nuclear@38 147 --frames_to_capture;
nuclear@38 148 }
nuclear@34 149
nuclear@34 150 /* also print fps every second ... */
nuclear@34 151 {
nuclear@34 152 static long prev_fps, num_frames;
nuclear@34 153 long msec, dt;
nuclear@34 154
nuclear@34 155 msec = get_msec();
nuclear@34 156 dt = msec - prev_fps;
nuclear@34 157 if(dt >= 1000) {
nuclear@34 158 float fps = (float)num_frames / ((float)dt / 1000.0f);
nuclear@34 159 printf("framerate: %.1f \r", fps);
nuclear@34 160 fflush(stdout);
nuclear@34 161 num_frames = 0;
nuclear@34 162 prev_fps = msec;
nuclear@34 163 } else {
nuclear@34 164 num_frames++;
nuclear@34 165 }
nuclear@34 166 }
nuclear@0 167 }
nuclear@0 168
nuclear@38 169 #define spin_delay(ms) \
nuclear@38 170 do { \
nuclear@38 171 unsigned int end = SDL_GetTicks() + ms; \
nuclear@38 172 while((prev_msec = SDL_GetTicks()) < end); \
nuclear@38 173 } while(0)
nuclear@38 174
nuclear@38 175 #define FRAME_INTERVAL (1000/70)
nuclear@0 176 void wait_vsync(void)
nuclear@0 177 {
nuclear@38 178 static int prev_msec;
nuclear@38 179 int msec, dt, tleft;
nuclear@38 180
nuclear@38 181 msec = SDL_GetTicks();
nuclear@38 182
nuclear@38 183 dt = msec - prev_msec;
nuclear@38 184
nuclear@38 185 tleft = FRAME_INTERVAL - dt;
nuclear@38 186 if(tleft > 0) {
nuclear@38 187 int coarse = tleft & 0xfffffff8;
nuclear@38 188 tleft = tleft & 7;
nuclear@38 189
nuclear@38 190 if(coarse) {
nuclear@38 191 SDL_Delay(coarse);
nuclear@38 192 }
nuclear@38 193 if(tleft) {
nuclear@38 194 spin_delay(tleft);
nuclear@38 195 } else {
nuclear@38 196 prev_msec = SDL_GetTicks();
nuclear@38 197 }
nuclear@38 198 } else {
nuclear@38 199 prev_msec = msec;
nuclear@38 200 }
nuclear@0 201 }
nuclear@0 202
nuclear@38 203 static int cap_count = 0;
nuclear@38 204 void begin_capture(int frames)
nuclear@38 205 {
nuclear@38 206 frames_to_capture = frames;
nuclear@38 207 }
nuclear@38 208
nuclear@38 209 void end_capture(void)
nuclear@38 210 {
nuclear@38 211 cap_count = 0;
nuclear@38 212 frames_to_capture = 0;
nuclear@38 213 }
nuclear@38 214
nuclear@38 215 #define NUMPIX (320 * 200)
nuclear@38 216 static void capture_frame(unsigned char *frame)
nuclear@38 217 {
nuclear@38 218 static unsigned char rgbpix[NUMPIX * 4];
nuclear@38 219 char fname[32];
nuclear@38 220 int i;
nuclear@38 221 unsigned char *src, *dest;
nuclear@38 222
nuclear@38 223 sprintf(fname, "frame%04d.png", cap_count++);
nuclear@38 224
nuclear@38 225 src = frame;
nuclear@38 226 dest = rgbpix;
nuclear@38 227
nuclear@38 228 for(i=0; i<NUMPIX; i++) {
nuclear@38 229 unsigned char c = *src++;
nuclear@38 230 *dest++ = palette[c].r;
nuclear@38 231 *dest++ = palette[c].g;
nuclear@38 232 *dest++ = palette[c].b;
nuclear@38 233 *dest++ = 255;
nuclear@38 234 }
nuclear@38 235
nuclear@38 236 img_save_pixels(fname, rgbpix, 320, 200, IMG_FMT_RGBA32);
nuclear@38 237 }
nuclear@38 238
nuclear@38 239
nuclear@0 240 /* ----- event handling (conio.h) ----- */
nuclear@0 241 static SDL_Event *keybev;
nuclear@0 242 static int mousex, mousey, bnmask;
nuclear@0 243
nuclear@34 244 static int keystate[256];
nuclear@34 245 static int num_pressed;
nuclear@34 246
nuclear@0 247 int kbhit(void)
nuclear@0 248 {
nuclear@0 249 if(!keybev) {
nuclear@0 250 proc_events();
nuclear@0 251 }
nuclear@0 252 return keybev != 0;
nuclear@0 253 }
nuclear@0 254
nuclear@9 255 int getch(void)
nuclear@0 256 {
nuclear@9 257 int res;
nuclear@0 258
nuclear@0 259 while(!keybev) {
nuclear@0 260 SDL_Event ev;
nuclear@0 261 SDL_WaitEvent(&ev);
nuclear@0 262 SDL_PushEvent(&ev);
nuclear@0 263 proc_events();
nuclear@0 264 }
nuclear@0 265 res = keybev->key.keysym.sym;
nuclear@0 266 keybev = 0;
nuclear@0 267 return res;
nuclear@0 268 }
nuclear@0 269
nuclear@34 270 /* ----- improved event handling (keyb.h) ---- */
nuclear@34 271
nuclear@34 272 int kb_init(int bufsz)
nuclear@34 273 {
nuclear@34 274 init_sdl();
nuclear@34 275
nuclear@34 276 return 0;
nuclear@34 277 }
nuclear@34 278
nuclear@34 279 void kb_shutdown(void)
nuclear@34 280 {
nuclear@34 281 }
nuclear@34 282
nuclear@34 283 int kb_getkey(void)
nuclear@34 284 {
nuclear@34 285 int res = -1;
nuclear@34 286
nuclear@34 287 proc_events();
nuclear@34 288 if(keybev) {
nuclear@34 289 res = keybev->key.keysym.sym;
nuclear@34 290 keybev = 0;
nuclear@34 291 }
nuclear@34 292 return res;
nuclear@34 293 }
nuclear@34 294
nuclear@34 295 int kb_isdown(int key)
nuclear@34 296 {
nuclear@34 297 if(key == KB_ANY) {
nuclear@34 298 return num_pressed;
nuclear@34 299 }
nuclear@34 300 return keystate[key];
nuclear@34 301 }
nuclear@34 302
nuclear@0 303 /* mouse handling (mouse.c implementation) */
nuclear@34 304 static unsigned long last_mouse_hide_time;
nuclear@34 305
nuclear@0 306 int have_mouse(void)
nuclear@0 307 {
nuclear@0 308 return 1;
nuclear@0 309 }
nuclear@0 310
nuclear@34 311 void set_mouse(int x, int y)
nuclear@34 312 {
nuclear@36 313 SDL_ShowCursor(0);
nuclear@36 314 last_mouse_hide_time = get_msec();
nuclear@34 315
nuclear@34 316 SDL_WarpMouse(x * scale, y * scale);
nuclear@34 317 mousex = x;
nuclear@34 318 mousey = y;
nuclear@34 319 }
nuclear@34 320
nuclear@0 321 int read_mouse(int *xp, int *yp)
nuclear@0 322 {
nuclear@0 323 if(xp) *xp = mousex;
nuclear@0 324 if(yp) *yp = mousey;
nuclear@0 325 return bnmask;
nuclear@0 326 }
nuclear@0 327
nuclear@0 328 static void proc_events(void)
nuclear@0 329 {
nuclear@0 330 static SDL_Event ev;
nuclear@0 331
nuclear@34 332 if(last_mouse_hide_time > 0 && get_msec() - last_mouse_hide_time > 3000) {
nuclear@34 333 last_mouse_hide_time = 0;
nuclear@34 334 SDL_ShowCursor(1);
nuclear@34 335 }
nuclear@34 336
nuclear@0 337 while(SDL_PollEvent(&ev)) {
nuclear@0 338 switch(ev.type) {
nuclear@0 339 case SDL_KEYDOWN:
nuclear@34 340 {
nuclear@34 341 int key = ev.key.keysym.sym;
nuclear@34 342
nuclear@34 343 if(!keybev) {
nuclear@34 344 keybev = &ev;
nuclear@34 345 }
nuclear@34 346
nuclear@34 347 if(!keystate[key]) {
nuclear@34 348 keystate[key] = 1;
nuclear@34 349 num_pressed++;
nuclear@34 350 }
nuclear@34 351 }
nuclear@34 352 break;
nuclear@34 353
nuclear@34 354 case SDL_KEYUP:
nuclear@34 355 {
nuclear@34 356 int key = ev.key.keysym.sym;
nuclear@34 357
nuclear@34 358 if(keystate[key]) {
nuclear@34 359 keystate[key] = 0;
nuclear@34 360 if(--num_pressed < 0) {
nuclear@34 361 num_pressed = 0;
nuclear@34 362 }
nuclear@34 363 }
nuclear@34 364 }
nuclear@34 365 break;
nuclear@0 366
nuclear@0 367 case SDL_MOUSEMOTION:
nuclear@28 368 mousex = ev.motion.x / scale;
nuclear@28 369 mousey = ev.motion.y / scale;
nuclear@0 370 break;
nuclear@0 371
nuclear@0 372 case SDL_MOUSEBUTTONDOWN:
nuclear@0 373 case SDL_MOUSEBUTTONUP:
nuclear@0 374 {
nuclear@0 375 int mask = 0;
nuclear@0 376 switch(ev.button.button) {
nuclear@0 377 case SDL_BUTTON_LEFT:
nuclear@0 378 mask = MOUSE_LEFT;
nuclear@0 379 break;
nuclear@0 380 case SDL_BUTTON_MIDDLE:
nuclear@0 381 mask = MOUSE_MIDDLE;
nuclear@0 382 break;
nuclear@0 383 case SDL_BUTTON_RIGHT:
nuclear@0 384 mask = MOUSE_RIGHT;
nuclear@0 385 default:
nuclear@0 386 break;
nuclear@0 387 }
nuclear@0 388 if(!mask) {
nuclear@0 389 break;
nuclear@0 390 }
nuclear@0 391
nuclear@0 392 if(ev.button.state == SDL_PRESSED) {
nuclear@0 393 bnmask |= mask;
nuclear@0 394 } else {
nuclear@0 395 bnmask &= ~mask;
nuclear@0 396 }
nuclear@0 397 }
nuclear@0 398 break;
nuclear@0 399
nuclear@0 400 default:
nuclear@0 401 break;
nuclear@0 402 }
nuclear@0 403 }
nuclear@0 404 }
nuclear@0 405
nuclear@0 406 /* ---- timer.c implementation ---- */
nuclear@0 407 static Uint32 start_time;
nuclear@0 408
nuclear@0 409 void init_timer(int res_hz)
nuclear@0 410 {
nuclear@34 411 init_sdl();
nuclear@0 412 reset_timer();
nuclear@0 413 }
nuclear@0 414
nuclear@0 415 void reset_timer(void)
nuclear@0 416 {
nuclear@0 417 start_time = SDL_GetTicks();
nuclear@34 418 printf("resetting timer: %u, %lu\n", start_time, get_msec());
nuclear@0 419 }
nuclear@0 420
nuclear@0 421 unsigned long get_msec(void)
nuclear@0 422 {
nuclear@34 423 Uint32 ticks = SDL_GetTicks();
nuclear@34 424 return (unsigned long)(ticks - start_time);
nuclear@0 425 }