1 #ifdef __WIN32__
2 #include <windows.h>
3 #else
4 #define MessageBox(owner, text, caption, type) printf("%s: %s\n", caption, text)
5 #endif
6 
7 #include "SDL.h"
8 #include "SDL_thread.h"
9 
10 #include "shared.h"
11 #include "sms_ntsc.h"
12 #include "md_ntsc.h"
13 
14 #define SOUND_FREQUENCY 48000
15 #define SOUND_SAMPLES_SIZE  2048
16 
17 #define VIDEO_WIDTH  320
18 #define VIDEO_HEIGHT 240
19 
20 int joynum = 0;
21 
22 int log_error   = 0;
23 int debug_on    = 0;
24 int turbo_mode  = 0;
25 int use_sound   = 1;
26 int fullscreen  = 0; /* SDL_FULLSCREEN */
27 
28 /* sound */
29 
30 struct {
31   char* current_pos;
32   char* buffer;
33   int current_emulated_samples;
34 } sdl_sound;
35 
36 
37 static uint8 brm_format[0x40] =
38 {
39   0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x00,0x00,0x00,0x00,0x40,
40   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
41   0x53,0x45,0x47,0x41,0x5f,0x43,0x44,0x5f,0x52,0x4f,0x4d,0x00,0x01,0x00,0x00,0x00,
42   0x52,0x41,0x4d,0x5f,0x43,0x41,0x52,0x54,0x52,0x49,0x44,0x47,0x45,0x5f,0x5f,0x5f
43 };
44 
45 
46 static short soundframe[SOUND_SAMPLES_SIZE];
47 
sdl_sound_callback(void * userdata,Uint8 * stream,int len)48 static void sdl_sound_callback(void *userdata, Uint8 *stream, int len)
49 {
50   if(sdl_sound.current_emulated_samples < len) {
51     memset(stream, 0, len);
52   }
53   else {
54     memcpy(stream, sdl_sound.buffer, len);
55     /* loop to compensate desync */
56     do {
57       sdl_sound.current_emulated_samples -= len;
58     } while(sdl_sound.current_emulated_samples > 2 * len);
59     memcpy(sdl_sound.buffer,
60            sdl_sound.current_pos - sdl_sound.current_emulated_samples,
61            sdl_sound.current_emulated_samples);
62     sdl_sound.current_pos = sdl_sound.buffer + sdl_sound.current_emulated_samples;
63   }
64 }
65 
sdl_sound_init()66 static int sdl_sound_init()
67 {
68   int n;
69   SDL_AudioSpec as_desired;
70 
71   if(SDL_Init(SDL_INIT_AUDIO) < 0) {
72     MessageBox(NULL, "SDL Audio initialization failed", "Error", 0);
73     return 0;
74   }
75 
76   as_desired.freq     = SOUND_FREQUENCY;
77   as_desired.format   = AUDIO_S16LSB;
78   as_desired.channels = 2;
79   as_desired.samples  = SOUND_SAMPLES_SIZE;
80   as_desired.callback = sdl_sound_callback;
81 
82   if(SDL_OpenAudio(&as_desired, NULL) == -1) {
83     MessageBox(NULL, "SDL Audio open failed", "Error", 0);
84     return 0;
85   }
86 
87   sdl_sound.current_emulated_samples = 0;
88   n = SOUND_SAMPLES_SIZE * 2 * sizeof(short) * 20;
89   sdl_sound.buffer = (char*)malloc(n);
90   if(!sdl_sound.buffer) {
91     MessageBox(NULL, "Can't allocate audio buffer", "Error", 0);
92     return 0;
93   }
94   memset(sdl_sound.buffer, 0, n);
95   sdl_sound.current_pos = sdl_sound.buffer;
96   return 1;
97 }
98 
sdl_sound_update(int enabled)99 static void sdl_sound_update(int enabled)
100 {
101   int size = audio_update(soundframe) * 2;
102 
103   if (enabled)
104   {
105     int i;
106     short *out;
107 
108     SDL_LockAudio();
109     out = (short*)sdl_sound.current_pos;
110     for(i = 0; i < size; i++)
111     {
112       *out++ = soundframe[i];
113     }
114     sdl_sound.current_pos = (char*)out;
115     sdl_sound.current_emulated_samples += size * sizeof(short);
116     SDL_UnlockAudio();
117   }
118 }
119 
sdl_sound_close()120 static void sdl_sound_close()
121 {
122   SDL_PauseAudio(1);
123   SDL_CloseAudio();
124   if (sdl_sound.buffer)
125     free(sdl_sound.buffer);
126 }
127 
128 /* video */
129 md_ntsc_t *md_ntsc;
130 sms_ntsc_t *sms_ntsc;
131 
132 struct {
133   SDL_Surface* surf_screen;
134   SDL_Surface* surf_bitmap;
135   SDL_Rect srect;
136   SDL_Rect drect;
137   Uint32 frames_rendered;
138 } sdl_video;
139 
sdl_video_init()140 static int sdl_video_init()
141 {
142   if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
143     MessageBox(NULL, "SDL Video initialization failed", "Error", 0);
144     return 0;
145   }
146   sdl_video.surf_screen  = SDL_SetVideoMode(VIDEO_WIDTH, VIDEO_HEIGHT, 16, SDL_SWSURFACE | fullscreen);
147   sdl_video.surf_bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, 720, 576, 16, 0, 0, 0, 0);
148   sdl_video.frames_rendered = 0;
149   SDL_ShowCursor(0);
150   return 1;
151 }
152 
sdl_video_update()153 static void sdl_video_update()
154 {
155   if (system_hw == SYSTEM_MCD)
156   {
157     system_frame_scd(0);
158   }
159   else if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
160   {
161     system_frame_gen(0);
162   }
163   else
164   {
165     system_frame_sms(0);
166   }
167 
168   /* viewport size changed */
169   if(bitmap.viewport.changed & 1)
170   {
171     bitmap.viewport.changed &= ~1;
172 
173     /* source bitmap */
174     sdl_video.srect.w = bitmap.viewport.w+2*bitmap.viewport.x;
175     sdl_video.srect.h = bitmap.viewport.h+2*bitmap.viewport.y;
176     sdl_video.srect.x = 0;
177     sdl_video.srect.y = 0;
178     if (sdl_video.srect.w > VIDEO_WIDTH)
179     {
180       sdl_video.srect.x = (sdl_video.srect.w - VIDEO_WIDTH) / 2;
181       sdl_video.srect.w = VIDEO_WIDTH;
182     }
183     if (sdl_video.srect.h > VIDEO_HEIGHT)
184     {
185       sdl_video.srect.y = (sdl_video.srect.h - VIDEO_HEIGHT) / 2;
186       sdl_video.srect.h = VIDEO_HEIGHT;
187     }
188 
189     /* destination bitmap */
190     sdl_video.drect.w = sdl_video.srect.w;
191     sdl_video.drect.h = sdl_video.srect.h;
192     sdl_video.drect.x = (VIDEO_WIDTH - sdl_video.drect.w) / 2;
193     sdl_video.drect.y = (VIDEO_HEIGHT - sdl_video.drect.h) / 2;
194 
195     /* clear destination surface */
196     SDL_FillRect(sdl_video.surf_screen, 0, 0);
197 
198 #if 0
199     if (config.render && (interlaced || config.ntsc))  rect.h *= 2;
200     if (config.ntsc) rect.w = (reg[12]&1) ? MD_NTSC_OUT_WIDTH(rect.w) : SMS_NTSC_OUT_WIDTH(rect.w);
201     if (config.ntsc)
202     {
203       sms_ntsc = (sms_ntsc_t *)malloc(sizeof(sms_ntsc_t));
204       md_ntsc = (md_ntsc_t *)malloc(sizeof(md_ntsc_t));
205 
206       switch (config.ntsc)
207       {
208         case 1:
209           sms_ntsc_init(sms_ntsc, &sms_ntsc_composite);
210           md_ntsc_init(md_ntsc, &md_ntsc_composite);
211           break;
212         case 2:
213           sms_ntsc_init(sms_ntsc, &sms_ntsc_svideo);
214           md_ntsc_init(md_ntsc, &md_ntsc_svideo);
215           break;
216         case 3:
217           sms_ntsc_init(sms_ntsc, &sms_ntsc_rgb);
218           md_ntsc_init(md_ntsc, &md_ntsc_rgb);
219           break;
220       }
221     }
222     else
223     {
224       if (sms_ntsc)
225       {
226         free(sms_ntsc);
227         sms_ntsc = NULL;
228       }
229 
230       if (md_ntsc)
231       {
232         free(md_ntsc);
233         md_ntsc = NULL;
234       }
235     }
236 #endif
237   }
238 
239   SDL_BlitSurface(sdl_video.surf_bitmap, &sdl_video.srect, sdl_video.surf_screen, &sdl_video.drect);
240   SDL_UpdateRect(sdl_video.surf_screen, 0, 0, 0, 0);
241 
242   ++sdl_video.frames_rendered;
243 }
244 
sdl_video_close()245 static void sdl_video_close()
246 {
247   SDL_FreeSurface(sdl_video.surf_bitmap);
248 }
249 
250 /* Timer Sync */
251 
252 struct {
253   SDL_sem* sem_sync;
254   unsigned ticks;
255 } sdl_sync;
256 
sdl_sync_timer_callback(Uint32 interval)257 static Uint32 sdl_sync_timer_callback(Uint32 interval)
258 {
259   SDL_SemPost(sdl_sync.sem_sync);
260   sdl_sync.ticks++;
261   if (sdl_sync.ticks == (vdp_pal ? 50 : 20))
262   {
263     SDL_Event event;
264     SDL_UserEvent userevent;
265 
266     userevent.type = SDL_USEREVENT;
267     userevent.code = vdp_pal ? (sdl_video.frames_rendered / 3) : sdl_video.frames_rendered;
268     userevent.data1 = NULL;
269     userevent.data2 = NULL;
270     sdl_sync.ticks = sdl_video.frames_rendered = 0;
271 
272     event.type = SDL_USEREVENT;
273     event.user = userevent;
274 
275     SDL_PushEvent(&event);
276   }
277   return interval;
278 }
279 
sdl_sync_init()280 static int sdl_sync_init()
281 {
282   if(SDL_InitSubSystem(SDL_INIT_TIMER|SDL_INIT_EVENTTHREAD) < 0)
283   {
284     MessageBox(NULL, "SDL Timer initialization failed", "Error", 0);
285     return 0;
286   }
287 
288   sdl_sync.sem_sync = SDL_CreateSemaphore(0);
289   sdl_sync.ticks = 0;
290   return 1;
291 }
292 
sdl_sync_close()293 static void sdl_sync_close()
294 {
295   if(sdl_sync.sem_sync)
296     SDL_DestroySemaphore(sdl_sync.sem_sync);
297 }
298 
299 static const uint16 vc_table[4][2] =
300 {
301   /* NTSC, PAL */
302   {0xDA , 0xF2},  /* Mode 4 (192 lines) */
303   {0xEA , 0x102}, /* Mode 5 (224 lines) */
304   {0xDA , 0xF2},  /* Mode 4 (192 lines) */
305   {0x106, 0x10A}  /* Mode 5 (240 lines) */
306 };
307 
sdl_control_update(SDLKey keystate)308 static int sdl_control_update(SDLKey keystate)
309 {
310     switch (keystate)
311     {
312       case SDLK_TAB:
313       {
314         system_reset();
315         break;
316       }
317 
318       case SDLK_F1:
319       {
320         if (SDL_ShowCursor(-1)) SDL_ShowCursor(0);
321         else SDL_ShowCursor(1);
322         break;
323       }
324 
325       case SDLK_F2:
326       {
327         fullscreen = (fullscreen ? 0 : SDL_FULLSCREEN);
328         sdl_video.surf_screen = SDL_SetVideoMode(VIDEO_WIDTH, VIDEO_HEIGHT, 16,  SDL_SWSURFACE | fullscreen);
329         break;
330       }
331 
332       case SDLK_F3:
333       {
334         if (config.bios == 0) config.bios = 3;
335         else if (config.bios == 3) config.bios = 1;
336         break;
337       }
338 
339       case SDLK_F4:
340       {
341         if (!turbo_mode) use_sound ^= 1;
342         break;
343       }
344 
345       case SDLK_F5:
346       {
347         log_error ^= 1;
348         break;
349       }
350 
351       case SDLK_F6:
352       {
353         if (!use_sound)
354         {
355           turbo_mode ^=1;
356           sdl_sync.ticks = 0;
357         }
358         break;
359       }
360 
361       case SDLK_F7:
362       {
363         FILE *f = fopen("game.gp0","rb");
364         if (f)
365         {
366           uint8 buf[STATE_SIZE];
367           fread(&buf, STATE_SIZE, 1, f);
368           state_load(buf);
369           fclose(f);
370         }
371         break;
372       }
373 
374       case SDLK_F8:
375       {
376         FILE *f = fopen("game.gp0","wb");
377         if (f)
378         {
379           uint8 buf[STATE_SIZE];
380           int len = state_save(buf);
381           fwrite(&buf, len, 1, f);
382           fclose(f);
383         }
384         break;
385       }
386 
387       case SDLK_F9:
388       {
389         config.region_detect = (config.region_detect + 1) % 5;
390         get_region(0);
391 
392         /* framerate has changed, reinitialize audio timings */
393         audio_init(snd.sample_rate, 0);
394 
395         /* system with region BIOS should be reinitialized */
396         if ((system_hw == SYSTEM_MCD) || ((system_hw & SYSTEM_SMS) && (config.bios & 1)))
397         {
398           system_init();
399           system_reset();
400         }
401         else
402         {
403           /* reinitialize I/O region register */
404           if (system_hw == SYSTEM_MD)
405           {
406             io_reg[0x00] = 0x20 | region_code | (config.bios & 1);
407           }
408           else
409           {
410             io_reg[0x00] = 0x80 | (region_code >> 1);
411           }
412 
413           /* reinitialize VDP */
414           if (vdp_pal)
415           {
416             status |= 1;
417             lines_per_frame = 313;
418           }
419           else
420           {
421             status &= ~1;
422             lines_per_frame = 262;
423           }
424 
425           /* reinitialize VC max value */
426           switch (bitmap.viewport.h)
427           {
428             case 192:
429               vc_max = vc_table[0][vdp_pal];
430               break;
431             case 224:
432               vc_max = vc_table[1][vdp_pal];
433               break;
434             case 240:
435               vc_max = vc_table[3][vdp_pal];
436               break;
437           }
438         }
439         break;
440       }
441 
442       case SDLK_F10:
443       {
444         gen_reset(0);
445         break;
446       }
447 
448       case SDLK_F11:
449       {
450         config.overscan =  (config.overscan + 1) & 3;
451         if ((system_hw == SYSTEM_GG) && !config.gg_extra)
452         {
453           bitmap.viewport.x = (config.overscan & 2) ? 14 : -48;
454         }
455         else
456         {
457           bitmap.viewport.x = (config.overscan & 2) * 7;
458         }
459         bitmap.viewport.changed = 3;
460         break;
461       }
462 
463       case SDLK_F12:
464       {
465         joynum = (joynum + 1) % MAX_DEVICES;
466         while (input.dev[joynum] == NO_DEVICE)
467         {
468           joynum = (joynum + 1) % MAX_DEVICES;
469         }
470         break;
471       }
472 
473       case SDLK_ESCAPE:
474       {
475         return 0;
476       }
477 
478       default:
479         break;
480     }
481 
482    return 1;
483 }
484 
sdl_input_update(void)485 int sdl_input_update(void)
486 {
487   uint8 *keystate = SDL_GetKeyState(NULL);
488 
489   /* reset input */
490   input.pad[joynum] = 0;
491 
492   switch (input.dev[joynum])
493   {
494     case DEVICE_LIGHTGUN:
495     {
496       /* get mouse coordinates (absolute values) */
497       int x,y;
498       int state = SDL_GetMouseState(&x,&y);
499 
500       /* X axis */
501       input.analog[joynum][0] =  x - (VIDEO_WIDTH-bitmap.viewport.w)/2;
502 
503       /* Y axis */
504       input.analog[joynum][1] =  y - (VIDEO_HEIGHT-bitmap.viewport.h)/2;
505 
506       /* TRIGGER, B, C (Menacer only), START (Menacer & Justifier only) */
507       if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_A;
508       if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_B;
509       if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_C;
510       if(keystate[SDLK_f])  input.pad[joynum] |= INPUT_START;
511       break;
512     }
513 
514     case DEVICE_PADDLE:
515     {
516       /* get mouse (absolute values) */
517       int x;
518       int state = SDL_GetMouseState(&x, NULL);
519 
520       /* Range is [0;256], 128 being middle position */
521       input.analog[joynum][0] = x * 256 /VIDEO_WIDTH;
522 
523       /* Button I -> 0 0 0 0 0 0 0 I*/
524       if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B;
525 
526       break;
527     }
528 
529     case DEVICE_SPORTSPAD:
530     {
531       /* get mouse (relative values) */
532       int x,y;
533       int state = SDL_GetRelativeMouseState(&x,&y);
534 
535       /* Range is [0;256] */
536       input.analog[joynum][0] = (unsigned char)(-x & 0xFF);
537       input.analog[joynum][1] = (unsigned char)(-y & 0xFF);
538 
539       /* Buttons I & II -> 0 0 0 0 0 0 II I*/
540       if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B;
541       if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_C;
542 
543       break;
544     }
545 
546     case DEVICE_MOUSE:
547     {
548       /* get mouse (relative values) */
549       int x,y;
550       int state = SDL_GetRelativeMouseState(&x,&y);
551 
552       /* Sega Mouse range is [-256;+256] */
553       input.analog[joynum][0] = x * 2;
554       input.analog[joynum][1] = y * 2;
555 
556       /* Vertical movement is upsidedown */
557       if (!config.invert_mouse)
558         input.analog[joynum][1] = 0 - input.analog[joynum][1];
559 
560       /* Start,Left,Right,Middle buttons -> 0 0 0 0 START MIDDLE RIGHT LEFT */
561       if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B;
562       if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_C;
563       if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_A;
564       if(keystate[SDLK_f])  input.pad[joynum] |= INPUT_START;
565 
566       break;
567     }
568 
569     case DEVICE_XE_1AP:
570     {
571       /* A,B,C,D,Select,START,E1,E2 buttons -> E1(?) E2(?) START SELECT(?) A B C D */
572       if(keystate[SDLK_a])  input.pad[joynum] |= INPUT_START;
573       if(keystate[SDLK_s])  input.pad[joynum] |= INPUT_A;
574       if(keystate[SDLK_d])  input.pad[joynum] |= INPUT_C;
575       if(keystate[SDLK_f])  input.pad[joynum] |= INPUT_Y;
576       if(keystate[SDLK_z])  input.pad[joynum] |= INPUT_B;
577       if(keystate[SDLK_x])  input.pad[joynum] |= INPUT_X;
578       if(keystate[SDLK_c])  input.pad[joynum] |= INPUT_MODE;
579       if(keystate[SDLK_v])  input.pad[joynum] |= INPUT_Z;
580 
581       /* Left Analog Stick (bidirectional) */
582       if(keystate[SDLK_UP])     input.analog[joynum][1]-=2;
583       else if(keystate[SDLK_DOWN])   input.analog[joynum][1]+=2;
584       else input.analog[joynum][1] = 128;
585       if(keystate[SDLK_LEFT])   input.analog[joynum][0]-=2;
586       else if(keystate[SDLK_RIGHT])  input.analog[joynum][0]+=2;
587       else input.analog[joynum][0] = 128;
588 
589       /* Right Analog Stick (unidirectional) */
590       if(keystate[SDLK_KP8])    input.analog[joynum+1][0]-=2;
591       else if(keystate[SDLK_KP2])   input.analog[joynum+1][0]+=2;
592       else if(keystate[SDLK_KP4])   input.analog[joynum+1][0]-=2;
593       else if(keystate[SDLK_KP6])  input.analog[joynum+1][0]+=2;
594       else input.analog[joynum+1][0] = 128;
595 
596       /* Limiters */
597       if (input.analog[joynum][0] > 0xFF) input.analog[joynum][0] = 0xFF;
598       else if (input.analog[joynum][0] < 0) input.analog[joynum][0] = 0;
599       if (input.analog[joynum][1] > 0xFF) input.analog[joynum][1] = 0xFF;
600       else if (input.analog[joynum][1] < 0) input.analog[joynum][1] = 0;
601       if (input.analog[joynum+1][0] > 0xFF) input.analog[joynum+1][0] = 0xFF;
602       else if (input.analog[joynum+1][0] < 0) input.analog[joynum+1][0] = 0;
603       if (input.analog[joynum+1][1] > 0xFF) input.analog[joynum+1][1] = 0xFF;
604       else if (input.analog[joynum+1][1] < 0) input.analog[joynum+1][1] = 0;
605 
606       break;
607     }
608 
609     case DEVICE_PICO:
610     {
611       /* get mouse (absolute values) */
612       int x,y;
613       int state = SDL_GetMouseState(&x,&y);
614 
615       /* Calculate X Y axis values */
616       input.analog[0][0] = 0x3c  + (x * (0x17c-0x03c+1)) / VIDEO_WIDTH;
617       input.analog[0][1] = 0x1fc + (y * (0x2f7-0x1fc+1)) / VIDEO_HEIGHT;
618 
619       /* Map mouse buttons to player #1 inputs */
620       if(state & SDL_BUTTON_MMASK) pico_current = (pico_current + 1) & 7;
621       if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_PICO_RED;
622       if(state & SDL_BUTTON_LMASK) input.pad[0] |= INPUT_PICO_PEN;
623 
624       break;
625     }
626 
627     case DEVICE_TEREBI:
628     {
629       /* get mouse (absolute values) */
630       int x,y;
631       int state = SDL_GetMouseState(&x,&y);
632 
633       /* Calculate X Y axis values */
634       input.analog[0][0] = (x * 250) / VIDEO_WIDTH;
635       input.analog[0][1] = (y * 250) / VIDEO_HEIGHT;
636 
637       /* Map mouse buttons to player #1 inputs */
638       if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_B;
639 
640       break;
641     }
642 
643     case DEVICE_GRAPHIC_BOARD:
644     {
645       /* get mouse (absolute values) */
646       int x,y;
647       int state = SDL_GetMouseState(&x,&y);
648 
649       /* Calculate X Y axis values */
650       input.analog[0][0] = (x * 255) / VIDEO_WIDTH;
651       input.analog[0][1] = (y * 255) / VIDEO_HEIGHT;
652 
653       /* Map mouse buttons to player #1 inputs */
654       if(state & SDL_BUTTON_LMASK) input.pad[0] |= INPUT_GRAPHIC_PEN;
655       if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_GRAPHIC_MENU;
656       if(state & SDL_BUTTON_MMASK) input.pad[0] |= INPUT_GRAPHIC_DO;
657 
658       break;
659     }
660 
661     case DEVICE_ACTIVATOR:
662     {
663       if(keystate[SDLK_g])  input.pad[joynum] |= INPUT_ACTIVATOR_7L;
664       if(keystate[SDLK_h])  input.pad[joynum] |= INPUT_ACTIVATOR_7U;
665       if(keystate[SDLK_j])  input.pad[joynum] |= INPUT_ACTIVATOR_8L;
666       if(keystate[SDLK_k])  input.pad[joynum] |= INPUT_ACTIVATOR_8U;
667     }
668 
669     default:
670     {
671       if(keystate[SDLK_a])  input.pad[joynum] |= INPUT_A;
672       if(keystate[SDLK_s])  input.pad[joynum] |= INPUT_B;
673       if(keystate[SDLK_d])  input.pad[joynum] |= INPUT_C;
674       if(keystate[SDLK_f])  input.pad[joynum] |= INPUT_START;
675       if(keystate[SDLK_z])  input.pad[joynum] |= INPUT_X;
676       if(keystate[SDLK_x])  input.pad[joynum] |= INPUT_Y;
677       if(keystate[SDLK_c])  input.pad[joynum] |= INPUT_Z;
678       if(keystate[SDLK_v])  input.pad[joynum] |= INPUT_MODE;
679 
680       if(keystate[SDLK_UP]) input.pad[joynum] |= INPUT_UP;
681       else
682       if(keystate[SDLK_DOWN]) input.pad[joynum] |= INPUT_DOWN;
683       if(keystate[SDLK_LEFT]) input.pad[joynum] |= INPUT_LEFT;
684       else
685       if(keystate[SDLK_RIGHT]) input.pad[joynum] |= INPUT_RIGHT;
686 
687       break;
688     }
689   }
690   return 1;
691 }
692 
693 
main(int argc,char ** argv)694 int main (int argc, char **argv)
695 {
696   FILE *fp;
697   int running = 1;
698 
699   /* Print help if no game specified */
700   if(argc < 2)
701   {
702     char caption[256];
703     sprintf(caption, "Genesis Plus GX\\SDL\nusage: %s gamename\n", argv[0]);
704     MessageBox(NULL, caption, "Information", 0);
705     return 1;
706   }
707 
708   /* set default config */
709   error_init();
710   set_config_defaults();
711 
712   /* mark all BIOS as unloaded */
713   system_bios = 0;
714 
715   /* Genesis BOOT ROM support (2KB max) */
716   memset(boot_rom, 0xFF, 0x800);
717   fp = fopen(MD_BIOS, "rb");
718   if (fp != NULL)
719   {
720     int i;
721 
722     /* read BOOT ROM */
723     fread(boot_rom, 1, 0x800, fp);
724     fclose(fp);
725 
726     /* check BOOT ROM */
727     if (!memcmp((char *)(boot_rom + 0x120),"GENESIS OS", 10))
728     {
729       /* mark Genesis BIOS as loaded */
730       system_bios = SYSTEM_MD;
731     }
732 
733     /* Byteswap ROM */
734     for (i=0; i<0x800; i+=2)
735     {
736       uint8 temp = boot_rom[i];
737       boot_rom[i] = boot_rom[i+1];
738       boot_rom[i+1] = temp;
739     }
740   }
741 
742   /* initialize SDL */
743   if(SDL_Init(0) < 0)
744   {
745     MessageBox(NULL, "SDL initialization failed", "Error", 0);
746     return 1;
747   }
748   sdl_video_init();
749   if (use_sound) sdl_sound_init();
750   sdl_sync_init();
751 
752   /* initialize Genesis virtual system */
753   SDL_LockSurface(sdl_video.surf_bitmap);
754   memset(&bitmap, 0, sizeof(t_bitmap));
755   bitmap.width        = 720;
756   bitmap.height       = 576;
757 #if defined(USE_8BPP_RENDERING)
758   bitmap.pitch        = (bitmap.width * 1);
759 #elif defined(USE_15BPP_RENDERING)
760   bitmap.pitch        = (bitmap.width * 2);
761 #elif defined(USE_16BPP_RENDERING)
762   bitmap.pitch        = (bitmap.width * 2);
763 #elif defined(USE_32BPP_RENDERING)
764   bitmap.pitch        = (bitmap.width * 4);
765 #endif
766   bitmap.data         = sdl_video.surf_bitmap->pixels;
767   SDL_UnlockSurface(sdl_video.surf_bitmap);
768   bitmap.viewport.changed = 3;
769 
770   /* Load game file */
771   if(!load_rom(argv[1]))
772   {
773     char caption[256];
774     sprintf(caption, "Error loading file `%s'.", argv[1]);
775     MessageBox(NULL, caption, "Error", 0);
776     return 1;
777   }
778 
779   /* initialize system hardware */
780   audio_init(SOUND_FREQUENCY, 0);
781   system_init();
782 
783   /* Mega CD specific */
784   if (system_hw == SYSTEM_MCD)
785   {
786     /* load internal backup RAM */
787     fp = fopen("./scd.brm", "rb");
788     if (fp!=NULL)
789     {
790       fread(scd.bram, 0x2000, 1, fp);
791       fclose(fp);
792     }
793 
794     /* check if internal backup RAM is formatted */
795     if (memcmp(scd.bram + 0x2000 - 0x20, brm_format + 0x20, 0x20))
796     {
797       /* clear internal backup RAM */
798       memset(scd.bram, 0x00, 0x200);
799 
800       /* Internal Backup RAM size fields */
801       brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = 0x00;
802       brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (sizeof(scd.bram) / 64) - 3;
803 
804       /* format internal backup RAM */
805       memcpy(scd.bram + 0x2000 - 0x40, brm_format, 0x40);
806     }
807 
808     /* load cartridge backup RAM */
809     if (scd.cartridge.id)
810     {
811       fp = fopen("./cart.brm", "rb");
812       if (fp!=NULL)
813       {
814         fread(scd.cartridge.area, scd.cartridge.mask + 1, 1, fp);
815         fclose(fp);
816       }
817 
818       /* check if cartridge backup RAM is formatted */
819       if (memcmp(scd.cartridge.area + scd.cartridge.mask + 1 - 0x20, brm_format + 0x20, 0x20))
820       {
821         /* clear cartridge backup RAM */
822         memset(scd.cartridge.area, 0x00, scd.cartridge.mask + 1);
823 
824         /* Cartridge Backup RAM size fields */
825         brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = (((scd.cartridge.mask + 1) / 64) - 3) >> 8;
826         brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (((scd.cartridge.mask + 1) / 64) - 3) & 0xff;
827 
828         /* format cartridge backup RAM */
829         memcpy(scd.cartridge.area + scd.cartridge.mask + 1 - sizeof(brm_format), brm_format, sizeof(brm_format));
830       }
831     }
832   }
833 
834   if (sram.on)
835   {
836     /* load SRAM */
837     fp = fopen("./game.srm", "rb");
838     if (fp!=NULL)
839     {
840       fread(sram.sram,0x10000,1, fp);
841       fclose(fp);
842     }
843   }
844 
845   /* reset system hardware */
846   system_reset();
847 
848   if(use_sound) SDL_PauseAudio(0);
849 
850   /* 3 frames = 50 ms (60hz) or 60 ms (50hz) */
851   if(sdl_sync.sem_sync)
852     SDL_SetTimer(vdp_pal ? 60 : 50, sdl_sync_timer_callback);
853 
854   /* emulation loop */
855   while(running)
856   {
857     SDL_Event event;
858     if (SDL_PollEvent(&event))
859     {
860       switch(event.type)
861       {
862         case SDL_USEREVENT:
863         {
864           char caption[100];
865           sprintf(caption,"Genesis Plus GX - %d fps - %s", event.user.code, (rominfo.international[0] != 0x20) ? rominfo.international : rominfo.domestic);
866           SDL_WM_SetCaption(caption, NULL);
867           break;
868         }
869 
870         case SDL_QUIT:
871         {
872           running = 0;
873           break;
874         }
875 
876         case SDL_KEYDOWN:
877         {
878           running = sdl_control_update(event.key.keysym.sym);
879           break;
880         }
881       }
882     }
883 
884     sdl_video_update();
885     sdl_sound_update(use_sound);
886 
887     if(!turbo_mode && sdl_sync.sem_sync && sdl_video.frames_rendered % 3 == 0)
888     {
889       SDL_SemWait(sdl_sync.sem_sync);
890     }
891   }
892 
893   if (system_hw == SYSTEM_MCD)
894   {
895     /* save internal backup RAM (if formatted) */
896     if (!memcmp(scd.bram + 0x2000 - 0x20, brm_format + 0x20, 0x20))
897     {
898       fp = fopen("./scd.brm", "wb");
899       if (fp!=NULL)
900       {
901         fwrite(scd.bram, 0x2000, 1, fp);
902         fclose(fp);
903       }
904     }
905 
906     /* save cartridge backup RAM (if formatted) */
907     if (scd.cartridge.id)
908     {
909       if (!memcmp(scd.cartridge.area + scd.cartridge.mask + 1 - 0x20, brm_format + 0x20, 0x20))
910       {
911         fp = fopen("./cart.brm", "wb");
912         if (fp!=NULL)
913         {
914           fwrite(scd.cartridge.area, scd.cartridge.mask + 1, 1, fp);
915           fclose(fp);
916         }
917       }
918     }
919   }
920 
921   if (sram.on)
922   {
923     /* save SRAM */
924     fp = fopen("./game.srm", "wb");
925     if (fp!=NULL)
926     {
927       fwrite(sram.sram,0x10000,1, fp);
928       fclose(fp);
929     }
930   }
931 
932   audio_shutdown();
933   error_shutdown();
934 
935   sdl_video_close();
936   sdl_sound_close();
937   sdl_sync_close();
938   SDL_Quit();
939 
940   return 0;
941 }
942