1 #ifndef _MSC_VER
2 #include <stdbool.h>
3 #endif
4 #include <stddef.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/stat.h>
9 
10 #ifdef _MSC_VER
11 #define snprintf _snprintf
12 #pragma pack(1)
13 #endif
14 
15 #include "libretro.h"
16 
17 #include "audio.h"
18 #include "config.h"
19 #include "cpu.h"
20 #include "crc32.h"
21 #include "debug.h"
22 #include "keyboard.h"
23 #include "score.h"
24 #include "vdc.h"
25 #include "vmachine.h"
26 #include "voice.h"
27 #include "vpp.h"
28 #include "vkeyb/vkeyb.h"
29 
30 #include "wrapalleg.h"
31 
32 static retro_log_printf_t log_cb;
33 static retro_video_refresh_t video_cb;
34 static retro_input_poll_t input_poll_cb;
35 static retro_input_state_t input_state_cb;
36 static retro_environment_t environ_cb;
37 static retro_audio_sample_t audio_cb;
38 static retro_audio_sample_batch_t audio_batch_cb;
39 
retro_set_video_refresh(retro_video_refresh_t cb)40 void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; }
retro_set_audio_sample(retro_audio_sample_t cb)41 void retro_set_audio_sample(retro_audio_sample_t cb) { audio_cb = cb; }
retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)42 void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { audio_batch_cb = cb; }
retro_set_input_poll(retro_input_poll_t cb)43 void retro_set_input_poll(retro_input_poll_t cb) { input_poll_cb = cb; }
retro_set_input_state(retro_input_state_t cb)44 void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; }
45 
46 void retro_destroybmp(void);
47 
48 unsigned short int mbmp[TEX_WIDTH * TEX_HEIGHT];
49 uint8_t soundBuffer[1056];
50 int SND;
51 int RLOOP=0;
52 int joystick_data[2][5]={{0,0,0,0,0},{0,0,0,0,0}};
53 
54 int contax, o2flag, g74flag, c52flag, jopflag, helpflag;
55 
56 unsigned long crcx = ~0;
57 
58 static char scshot[MAXC],
59 odyssey2[MAXC],
60 file_v[MAXC],scorefile[MAXC], statefile[MAXC];
61 
62 extern uint8_t intRAM[];
63 
64 // True if the virtual keyboard must be showed
65 static bool vkb_show = false;
66 
67 struct ButtonsState
68 {
69   bool up, down, right, left;
70   bool select, start;
71   bool b, y;
72 };
73 // Last state of the buttons for joypad 1
74 struct ButtonsState last_btn_state = { false, false, false, false,
75                                        false, false,
76                                        false, false };
77 
78 static const struct retro_variable prefs[] = {
79     { "o2em_vkb_transparency", "Virtual keyboard transparency; 0%|10%|20%|30%|40%|50%|60%|70%|80%|90%" },
80     { NULL, NULL }
81 };
82 
retro_set_environment(retro_environment_t cb)83 void retro_set_environment(retro_environment_t cb)
84 {
85   // Emulator's preferences
86   cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *) prefs);
87 
88   environ_cb = cb;
89 }
90 
does_file_exist(const char * filename)91 static int does_file_exist(const char *filename)
92 {
93    struct stat st;
94    int result = stat(filename, &st);
95    return result == 0;
96 }
97 
filesize(FILE * stream)98 static long filesize(FILE *stream)
99 {
100    long curpos, length;
101    curpos = ftell(stream);
102    fseek(stream, 0L, SEEK_END);
103    length = ftell(stream);
104    fseek(stream, curpos, SEEK_SET);
105    return length;
106 }
107 
load_bios(const char * biosname)108 static bool load_bios(const char *biosname)
109 {
110    FILE *fn;
111    static char s[MAXC+10];
112    unsigned long crc;
113    int i;
114 
115    if ((biosname[strlen(biosname)-1]=='/') || (biosname[strlen(biosname)-1]=='\\') || (biosname[strlen(biosname)-1]==':'))
116    {
117       strcpy(s,biosname);
118       strcat(s,odyssey2);
119       fn = fopen(s,"rb");
120 
121       if (!fn)
122       {
123          strcpy(s,biosname);
124          strcat(s,odyssey2);
125          fn = fopen(s,"rb");
126       }
127    }
128    else
129    {
130       strcpy(s,biosname);
131       fn = fopen(biosname,"rb");
132    }
133 
134    if (!fn)
135    {
136       fprintf(stderr,"Error loading bios ROM (%s)\n",s);
137       return false;
138    }
139 
140    if (fread(rom_table[0],1024,1,fn) != 1)
141    {
142       fclose(fn);
143       fprintf(stderr,"Error loading bios ROM %s\n",odyssey2);
144       return false;
145    }
146 
147    fclose(fn);
148 
149    strcpy(s,biosname);
150    fn = fopen(biosname,"rb");
151 
152    if (!fn)
153    {
154       fprintf(stderr,"Error loading bios ROM (%s)\n",s);
155       return false;
156    }
157 
158    if (fread(rom_table[0],1024,1,fn) != 1)
159    {
160       fclose(fn);
161       fprintf(stderr,"Error loading bios ROM %s\n",odyssey2);
162       return false;
163    }
164 
165    fclose(fn);
166 
167    for (i=1; i<8; i++)
168       memcpy(rom_table[i],rom_table[0],1024);
169 
170    crc = crc32_buf(rom_table[0],1024);
171 
172    if (crc==0x8016A315) {
173       printf("Magnavox Odyssey2 BIOS ROM loaded (G7000 model)\n");
174       app_data.vpp = 0;
175       app_data.bios = ROM_O2;
176    } else if (crc==0xE20A9F41) {
177       printf("Philips Videopac+ European BIOS ROM loaded (G7400 model)\n");
178       app_data.vpp = 1;
179       app_data.bios = ROM_G7400;
180    } else if (crc==0xA318E8D6) {
181       if (!((!o2flag)&&(c52flag))) printf("Philips Videopac+ French BIOS ROM loaded (G7000 model)\n"); else printf("Ok\n");
182       app_data.vpp = 0;
183       app_data.bios = ROM_C52;
184    } else if (crc==0x11647CA5) {
185       if (g74flag) printf("Philips Videopac+ French BIOS ROM loaded (G7400 model)\n"); else printf(" Ok\n");
186       app_data.vpp = 1;
187       app_data.bios = ROM_JOPAC;
188    } else {
189       printf("Bios ROM loaded (unknown version)\n");
190       app_data.vpp = 0;
191       app_data.bios = ROM_UNKNOWN;
192    }
193 
194    return true;
195 }
196 
load_cart(const char * file)197 static bool load_cart(const char *file)
198 {
199    FILE *fn;
200    long l;
201    int i, nb;
202 
203    app_data.crc = crc32_file(file);
204    if (app_data.crc == 0xAFB23F89)
205       app_data.exrom = 1;  /* Musician */
206    if (app_data.crc == 0x3BFEF56B)
207       app_data.exrom = 1;  /* Four in 1 Row! */
208    if (app_data.crc == 0x9B5E9356)
209       app_data.exrom = 1;  /* Four in 1 Row! (french) */
210 
211    if (((app_data.crc == 0x975AB8DA) || (app_data.crc == 0xE246A812)) && (!app_data.debug))
212    {
213       fprintf(stderr,"Error: file %s is an incomplete ROM dump\n",file_v);
214       return false;
215    }
216 
217    fn=fopen(file,"rb");
218    if (!fn) {
219       fprintf(stderr,"Error loading %s\n",file_v);
220       return false;
221    }
222    printf("Loading: \"%s\"  Size: ",file_v);
223    l = filesize(fn);
224 
225    if ((l % 1024) != 0) {
226       fprintf(stderr,"Error: file %s is an invalid ROM dump\n",file_v);
227       return false;
228    }
229 
230    /* special MegaCART design by Soeren Gust */
231    if ((l == 32768) || (l == 65536) || (l == 131072) || (l == 262144) || (l == 524288) || (l == 1048576))
232    {
233       app_data.megaxrom = 1;
234       app_data.bank = 1;
235       megarom = malloc(1048576);
236 
237       if (megarom == NULL)
238       {
239          fprintf(stderr, "Out of memory loading %s\n", file);
240          return false;
241       }
242       if (fread(megarom, l, 1, fn) != 1)
243       {
244          fprintf(stderr,"Error loading %s\n",file);
245          return false;
246       }
247 
248       /* mirror shorter files into full megabyte */
249       if (l < 65536)
250          memcpy(megarom+32768,megarom,32768);
251       if (l < 131072)
252          memcpy(megarom+65536,megarom,65536);
253       if (l < 262144)
254          memcpy(megarom+131072,megarom,131072);
255       if (l < 524288)
256          memcpy(megarom+262144,megarom,262144);
257       if (l < 1048576)
258          memcpy(megarom+524288,megarom,524288);
259       /* start in bank 0xff */
260       memcpy(&rom_table[0][1024], megarom + 4096*255 + 1024, 3072);
261       printf("MegaCart %ldK", l / 1024);
262       nb = 1;
263    }
264    else if (((l % 3072) == 0))
265    {
266       app_data.three_k = 1;
267       nb = l/3072;
268 
269       for (i=nb-1; i>=0; i--)
270       {
271          if (fread(&rom_table[i][1024],3072,1,fn) != 1)
272          {
273             fprintf(stderr,"Error loading %s\n",file);
274             return false;
275          }
276       }
277       printf("%dK",nb*3);
278 
279    } else {
280 
281       nb = l/2048;
282 
283       if ((nb == 2) && (app_data.exrom))
284       {
285 
286          if (fread(&extROM[0], 1024,1,fn) != 1)
287          {
288             fprintf(stderr,"Error loading %s\n",file);
289             return false;
290          }
291          if (fread(&rom_table[0][1024],3072,1,fn) != 1)
292          {
293             fprintf(stderr,"Error loading %s\n",file);
294             return false;
295          }
296          printf("3K EXROM");
297 
298       }
299       else
300       {
301          for (i=nb-1; i>=0; i--)
302          {
303             if (fread(&rom_table[i][1024],2048,1,fn) != 1)
304             {
305                fprintf(stderr,"Error loading %s\n",file);
306                return false;
307             }
308             memcpy(&rom_table[i][3072],&rom_table[i][2048],1024); /* simulate missing A10 */
309          }
310          printf("%dK",nb*2);
311       }
312    }
313    fclose(fn);
314    rom = rom_table[0];
315    if (nb==1)
316       app_data.bank = 1;
317    else if (nb==2)
318       app_data.bank = app_data.exrom ? 1 : 2;
319    else if (nb==4)
320       app_data.bank = 3;
321    else
322       app_data.bank = 4;
323 
324    if ((rom_table[nb-1][1024+12]=='O') && (rom_table[nb-1][1024+13]=='P') && (rom_table[nb-1][1024+14]=='N') && (rom_table[nb-1][1024+15]=='B'))
325       app_data.openb=1;
326 
327    printf("  CRC: %08lX\n",app_data.crc);
328 
329    return true;
330 }
331 
update_joy(void)332 void update_joy(void)
333 {
334 }
335 
pointerToScreenCoordinates(int * x,int * y)336 static void pointerToScreenCoordinates(int *x, int *y)
337 {
338   *x = (*x + 0x7FFF) * EMUWIDTH / 0xFFFF;
339   *y = (*y + 0x7FFF) * EMUHEIGHT / 0xFFFF;
340 }
341 
update_input_virtual_keyboard()342 static void update_input_virtual_keyboard()
343 {
344   bool select, start;
345   bool b, y;
346   bool left, right, up, down;
347   bool click;
348 
349   select = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT);
350   start = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START);
351   y = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y);
352   up = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP);
353   down = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN);
354   left = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT);
355   right = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT);
356   b = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B);
357   click = input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED);
358 
359   // Show the virtual keyboard?
360   if (select && !last_btn_state.select)
361   {
362     vkb_show = !vkb_show;
363     // Release current key when virtual keyboard hidden
364     if (!vkb_show)
365     {
366       key[vkb_get_current_key_scancode()] = false;
367     }
368   }
369 
370   if (vkb_show)
371   {
372     // Move keyboard
373     if (y && !last_btn_state.y)
374     {
375       vkb_set_virtual_keyboard_position((vkb_get_virtual_keyboard_position() + 1) % 2);
376     }
377     // Direct click on the keyboard (touch screen)
378     if (click)
379     {
380       int xpointer, ypointer;
381       xpointer = input_state_cb(2, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
382       ypointer = input_state_cb(2, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
383       pointerToScreenCoordinates(&xpointer, &ypointer);
384       if (vkb_move_at(xpointer, ypointer))
385       {
386         // A key was touched: act as if the "Action" button was pushed
387         b = true;
388       }
389     }
390     // Press key
391     if ((b && !last_btn_state.b) || (!b && last_btn_state.b))
392     {
393       key[vkb_get_current_key_scancode()] = b;
394     }
395     if (!b)
396     {
397       // Move current key
398       if (right && !last_btn_state.right)
399       {
400         vkb_move_key(VKB_MOVE_RIGHT);
401       }
402       else if (left && !last_btn_state.left)
403       {
404         vkb_move_key(VKB_MOVE_LEFT);
405       }
406       else if (down && !last_btn_state.down)
407       {
408         vkb_move_key(VKB_MOVE_DOWN);
409       }
410       else if (up && !last_btn_state.up)
411       {
412         vkb_move_key(VKB_MOVE_UP);
413       }
414       // If start is pressed than press the Enter key
415       if ((start && !last_btn_state.start) || (!start && last_btn_state.start))
416       {
417         key[RETROK_RETURN] = start;
418       }
419     }
420   }
421 
422   last_btn_state.select = select;
423   last_btn_state.start = start;
424   last_btn_state.y = y;
425   last_btn_state.b = b;
426   last_btn_state.left = left;
427   last_btn_state.right = right;
428   last_btn_state.up = up;
429   last_btn_state.down = down;
430 }
431 
update_input(void)432 static void update_input(void)
433 {
434    if (!input_poll_cb)
435       return;
436 
437    input_poll_cb();
438 
439    if (!vkb_show)
440    {
441      // Joystick
442      // Player 1
443      joystick_data[0][0]= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP);
444      joystick_data[0][1]= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN);
445      joystick_data[0][2]= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT);
446      joystick_data[0][3]= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT);
447      joystick_data[0][4]= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B); // "Action" button on the joystick
448      // Player 2
449      joystick_data[1][0]= input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP);
450      joystick_data[1][1]= input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN);
451      joystick_data[1][2]= input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT);
452      joystick_data[1][3]= input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT);
453      joystick_data[1][4]= input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B); // "Action" button on the joystick
454 
455      // Numeric and Alpha
456      key[RETROK_0] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_0);
457      key[RETROK_1] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_1);
458      key[RETROK_2] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_2);
459      key[RETROK_3] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_3);
460      key[RETROK_4] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_4);
461      key[RETROK_5] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_5);
462      key[RETROK_6] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_6);
463      key[RETROK_7] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_7);
464      key[RETROK_8] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_8);
465      key[RETROK_9] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_9);
466      key[RETROK_a] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_a);
467      key[RETROK_b] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_b);
468      key[RETROK_c] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_c);
469      key[RETROK_d] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_d);
470      key[RETROK_e] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_e);
471      key[RETROK_f] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_f);
472      key[RETROK_g] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_g);
473      key[RETROK_h] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_h);
474      key[RETROK_i] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_i);
475      key[RETROK_j] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_j);
476      key[RETROK_k] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_k);
477      key[RETROK_l] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_l);
478      key[RETROK_m] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_m);
479      key[RETROK_n] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_n);
480      key[RETROK_o] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_o);
481      key[RETROK_p] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_p);
482      key[RETROK_q] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_q);
483      key[RETROK_r] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_r);
484      key[RETROK_s] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_s);
485      key[RETROK_t] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_t);
486      key[RETROK_u] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_u);
487      key[RETROK_v] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_v);
488      key[RETROK_w] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_w);
489      key[RETROK_x] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_x);
490      key[RETROK_y] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_y);
491      key[RETROK_z] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_z);
492      key[RETROK_SPACE] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_SPACE);       // Space
493      key[RETROK_QUESTION] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_QUESTION); // ?
494      key[RETROK_PERIOD] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_PERIOD);     // .
495      key[RETROK_END] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_END);           // "Clear"
496      key[RETROK_RETURN] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_RETURN);     // "Enter"
497      key[RETROK_MINUS] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_MINUS);       // -
498      key[RETROK_ASTERISK] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_ASTERISK); // Multiply sign
499      key[RETROK_SLASH] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_SLASH);       // Divide sign
500      key[RETROK_EQUALS] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_EQUALS);     // =
501      key[RETROK_PLUS] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_PLUS);         // +
502    }
503 
504    // Virtual keyboard management
505    update_input_virtual_keyboard();
506 }
507 
508 /************************************
509  * libretro implementation
510  ************************************/
511 
retro_get_system_info(struct retro_system_info * info)512 void retro_get_system_info(struct retro_system_info *info)
513 {
514    memset(info, 0, sizeof(*info));
515 	info->library_name = "O2EM";
516 #ifndef GIT_VERSION
517 #define GIT_VERSION ""
518 #endif
519 	info->library_version = "1.18" GIT_VERSION;
520 	info->need_fullpath = true;
521 	info->valid_extensions = "bin";
522 }
523 
retro_get_system_av_info(struct retro_system_av_info * info)524 void retro_get_system_av_info(struct retro_system_av_info *info)
525 {
526    memset(info, 0, sizeof(*info));
527 
528    info->timing.fps            = (evblclk == EVBLCLK_NTSC) ? 60 : 50;
529    info->timing.sample_rate    = 44100;
530    info->geometry.base_width   = EMUWIDTH;
531    info->geometry.base_height  = EMUHEIGHT;
532    info->geometry.max_width    = EMUWIDTH;
533    info->geometry.max_height   = EMUHEIGHT;
534    info->geometry.aspect_ratio = 4.0 / 3.0;
535 }
536 
retro_set_controller_port_device(unsigned port,unsigned device)537 void retro_set_controller_port_device(unsigned port, unsigned device)
538 {
539    (void)port;
540    (void)device;
541 }
542 
retro_serialize_size(void)543 size_t retro_serialize_size(void)
544 {
545 	return STATE_SIZE;
546 }
547 
retro_serialize(void * data,size_t size)548 bool retro_serialize(void *data, size_t size)
549 {
550    savestate_to_mem((uint8_t *)data);
551    return true;
552 }
553 
retro_unserialize(const void * data,size_t size)554 bool retro_unserialize(const void *data, size_t size)
555 {
556    loadstate_from_mem((uint8_t *)data);
557    return true;
558 }
559 
retro_cheat_reset(void)560 void retro_cheat_reset(void)
561 {}
562 
retro_cheat_set(unsigned index,bool enabled,const char * code)563 void retro_cheat_set(unsigned index, bool enabled, const char *code)
564 {
565    (void)index;
566    (void)enabled;
567    (void)code;
568 }
569 
retro_load_game(const struct retro_game_info * info)570 bool retro_load_game(const struct retro_game_info *info)
571 {
572     char bios_file_path[256];
573     const char *full_path, *system_directory_c;
574     enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
575     struct retro_input_descriptor desc[] = {
576        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "Left" },
577        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "Up" },
578        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "Down" },
579        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right" },
580        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "Action" },
581        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Move Virtual Keyboard" },
582        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,"Show/Hide Virtual Keyboard" },
583 
584        { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "Left" },
585        { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "Up" },
586        { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "Down" },
587        { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right" },
588        { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "Action" },
589 
590        { 2, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X, "Virtual Keyboard: Pointer X" },
591        { 2, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y, "Virtual Keyboard: Pointer Y" },
592        { 2, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED, "Virtual Keyboard: Pointer Pressed" },
593 
594        { 0 }
595     };
596 
597     if (!info)
598        return false;
599 
600     if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
601     {
602         if (log_cb)
603             log_cb(RETRO_LOG_INFO, "[O2EM]: RGB565 is not supported.\n");
604         return false;
605     }
606 
607    environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
608 
609     full_path = info->path;
610     system_directory_c = NULL;
611 
612     // BIOS is required
613     environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_directory_c);
614     if (!system_directory_c)
615     {
616        if (log_cb)
617           log_cb(RETRO_LOG_WARN, "[O2EM]: no system directory defined, unable to look for o2rom.bin\n");
618        return false;
619     }
620     else
621     {
622 #ifdef _WIN32
623       char slash = '\\';
624 #else
625       char slash = '/';
626 #endif
627 
628        snprintf(bios_file_path, sizeof(bios_file_path), "%s%c%s", system_directory_c, slash, "o2rom.bin");
629 
630        if (!does_file_exist(bios_file_path))
631        {
632           if (log_cb)
633              log_cb(RETRO_LOG_WARN, "[O2EM]: o2rom.bin not found, cannot load BIOS\n");
634           return false;
635        }
636     }
637 
638     app_data.debug = 0;
639     app_data.stick[0] = app_data.stick[1] = 1;
640     app_data.sticknumber[0] = app_data.sticknumber[1] = 0;
641     set_defjoykeys(0,0);
642     set_defjoykeys(1,1);
643     set_defsystemkeys();
644     app_data.bank = 0;
645     app_data.limit = 1;
646     app_data.sound_en = 1;
647     app_data.speed = 100;
648     app_data.wsize = 2;
649     app_data.fullscreen = 0;
650     app_data.scanlines = 0;
651     app_data.voice = 1;
652     app_data.window_title = "O2EM v" O2EM_VERSION;
653     app_data.svolume = 100;
654     app_data.vvolume = 100;
655     app_data.filter = 0;
656     app_data.exrom = 0;
657     app_data.three_k = 0;
658     app_data.crc = 0;
659     app_data.scshot = scshot;
660     app_data.statefile = statefile;
661     app_data.euro = 0;
662     app_data.openb = 0;
663     app_data.vpp = 0;
664     app_data.bios = 0;
665     app_data.scoretype = 0;
666     app_data.scoreaddress = 0;
667     app_data.default_highscore = 0;
668     app_data.breakpoint = 65535;
669     app_data.megaxrom = 0;
670     strcpy(scorefile,"highscore.txt");
671     //read_default_config();
672 
673     init_audio();
674 
675     app_data.crc = crc32_file(full_path);
676 
677     //suck_bios();
678     o2flag = 1;
679 
680     crcx = app_data.crc;
681     //suck_roms();
682 
683     if (!load_bios(bios_file_path))
684        return false;
685 
686     if (!load_cart(full_path))
687        return false;
688 
689     //if (app_data.voice) load_voice_samples(path2);
690 
691     init_display();
692 
693     init_cpu();
694 
695     init_system();
696 
697     set_score(app_data.scoretype, app_data.scoreaddress, app_data.default_highscore);
698 
699     return true;
700 }
701 
retro_load_game_special(unsigned game_type,const struct retro_game_info * info,size_t num_info)702 bool retro_load_game_special(unsigned game_type, const struct retro_game_info *info, size_t num_info)
703 {
704    (void)game_type;
705    (void)info;
706    (void)num_info;
707    return false;
708 }
709 
retro_unload_game(void)710 void retro_unload_game(void)
711 {
712 }
713 
retro_get_region(void)714 unsigned retro_get_region(void)
715 {
716     return evblclk == EVBLCLK_NTSC ? RETRO_REGION_NTSC : RETRO_REGION_PAL;
717 }
718 
retro_api_version(void)719 unsigned retro_api_version(void)
720 {
721     return RETRO_API_VERSION;
722 }
723 
retro_get_memory_data(unsigned id)724 void *retro_get_memory_data(unsigned id)
725 {
726     if ( id == RETRO_MEMORY_SYSTEM_RAM )
727         return intRAM;
728     return NULL;
729 }
730 
retro_get_memory_size(unsigned id)731 size_t retro_get_memory_size(unsigned id)
732 {
733     if ( id == RETRO_MEMORY_SYSTEM_RAM )
734         return 64;
735     return 0;
736 }
737 
check_variables(void)738 static void check_variables(void)
739 {
740   struct retro_variable var = {0, 0};
741   var.key = "o2em_vkb_transparency";
742   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
743   {
744     int alpha = 255 - (255 * atoi(var.value) / 100);
745     vkb_set_virtual_keyboard_transparency(alpha);
746   }
747 }
748 
retro_init(void)749 void retro_init(void)
750 {
751    struct retro_log_callback log;
752    unsigned level = 5;
753 
754    if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
755       log_cb = log.log;
756    else
757       log_cb = NULL;
758 
759    environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
760 
761    memset(mbmp, 0, sizeof(mbmp));
762    vkb_configure_virtual_keyboard(mbmp, EMUWIDTH, EMUHEIGHT, TEX_WIDTH);
763    check_variables();
764    RLOOP=1;
765 }
766 
retro_deinit(void)767 void retro_deinit(void)
768 {
769    close_audio();
770    close_voice();
771    close_display();
772    retro_destroybmp();
773 }
774 
retro_reset(void)775 void retro_reset(void)
776 {
777    init_cpu();
778    init_roms();
779    init_vpp();
780    clearscr();
781 }
782 
retro_run(void)783 void retro_run(void)
784 {
785    int i, length;
786    bool var_updated;
787 
788    update_input();
789 
790    cpu_exec();
791    RLOOP=1;
792 
793    if (vkb_show)
794    {
795      vkb_show_virtual_keyboard();
796    }
797    video_cb(mbmp, EMUWIDTH, EMUHEIGHT, TEX_WIDTH << 1);
798 
799    length = (evblclk == EVBLCLK_NTSC) ? 44100 / 60 : 44100 / 50;
800 
801    /* Convert 8u to 16s */
802    for(i = 0; i < length; i++)
803    {
804       int16_t sample16 = (soundBuffer[i]-128) << 8;
805       audio_cb(sample16, sample16);
806    }
807 
808    var_updated = false;
809    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &var_updated) && var_updated)
810    {
811      check_variables();
812    }
813 }
814