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