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