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