main.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. /*
  2. * meg4/platform/libretro/main.c
  3. *
  4. * Copyright (C) 2023 bzt
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. *
  20. * @brief RetroArch "platform" for the MEG-4
  21. *
  22. */
  23. #define _POSIX_C_SOURCE 199309L /* needed for timespec and nanosleep() */
  24. #include <time.h>
  25. #include "meg4.h"
  26. #include "libretro.h"
  27. static retro_video_refresh_t video_cb;
  28. static retro_audio_sample_t audio_cb;
  29. static retro_audio_sample_batch_t audio_batch_cb;
  30. static retro_environment_t environ_cb = 0;
  31. static retro_input_poll_t input_poll_cb;
  32. static retro_input_state_t input_state_cb;
  33. uint32_t scrbuf32[640 * 400];
  34. uint16_t scrbuf16[640 * 400];
  35. uint8_t *game_buf = NULL;
  36. char game_fn[256] = { 0 };
  37. int game_len = 0;
  38. int use_audio_cb = 0;
  39. int pixel_format = RETRO_PIXEL_FORMAT_XRGB8888;
  40. int main_w = 0, main_h = 0, win_w, win_h, win_f = 0, audio = 0, main_alt = 0, main_keymap[512];
  41. int mx = 160, my = 100, ml = 0, mm = 0, mr = 0;
  42. void main_delay(int msec);
  43. char floppydir_tmp[4096];
  44. #define meg4_showcursor()
  45. #define meg4_hidecursor()
  46. #include "../common.h"
  47. /**
  48. * Exit emulator
  49. */
  50. void main_quit(void)
  51. {
  52. main_log(1, "quitting... ");
  53. meg4_poweroff();
  54. meg4_showcursor();
  55. if(game_buf) { free(game_buf); game_buf = NULL; }
  56. }
  57. /**
  58. * Toggle fullscreen
  59. */
  60. void main_fullscreen(void)
  61. {
  62. /* not supported by libretro */
  63. }
  64. /**
  65. * Make window focused
  66. */
  67. void main_focus(void)
  68. {
  69. /* not supported by libretro */
  70. }
  71. /**
  72. * Get text from clipboard (must be freed by caller)
  73. */
  74. char *main_getclipboard(void)
  75. {
  76. /* not supported by libretro */
  77. return NULL;
  78. }
  79. /**
  80. * Set text to clipboard
  81. */
  82. void main_setclipboard(char *str)
  83. {
  84. /* not supported by libretro */
  85. (void)str;
  86. }
  87. /**
  88. * Show on-screen keyboard
  89. */
  90. void main_osk_show(void)
  91. {
  92. }
  93. /**
  94. * Hide on-screen keyboard
  95. */
  96. void main_osk_hide(void)
  97. {
  98. }
  99. /**
  100. * Delay
  101. */
  102. void main_delay(int msec)
  103. {
  104. struct timespec tv;
  105. tv.tv_sec = 0; tv.tv_nsec = msec * 1000000;
  106. nanosleep(&tv, NULL);
  107. }
  108. /**
  109. * Print program version and copyright
  110. */
  111. void main_hdr(void)
  112. {
  113. printf("\r\nMEG-4 v%s (libretro, build %u) by bzt Copyright (C) 2023 GPLv3+\r\n\r\n", meg4ver, BUILD);
  114. }
  115. /**
  116. * libretro callback; keyboard
  117. */
  118. static void keyboard_cb(bool down, unsigned keycode, uint32_t unicode, uint16_t mod)
  119. {
  120. char s[5];
  121. (void)keycode; (void)mod;
  122. /* for a lot of keys, this simply doesn't work... for example this function is called for 'c', but not for 'x' nor for 'a'. Happy typing! */
  123. /*printf("Down: %s, Code: %d, Char: %u, Mod: %u.\n", down ? "yes" : "no", keycode, unicode, mod);*/
  124. if(!down) return;
  125. /* yeah, normal keypress doesn't work for Esc... */
  126. if(keycode == RETROK_ESCAPE) {
  127. if(main_alt) { retro_deinit(); environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, NULL); } else meg4_pushkey("\x1b\0\0");
  128. } else
  129. if(!main_alt && unicode >= ' ') {
  130. memset(s, 0, sizeof(s));
  131. if(unicode<0x80) { s[0]=unicode; } else
  132. if(unicode<0x800) { s[0]=((unicode>>6)&0x1F)|0xC0; s[1]=(unicode&0x3F)|0x80; } else
  133. if(unicode<0x10000) { s[0]=((unicode>>12)&0x0F)|0xE0; s[1]=((unicode>>6)&0x3F)|0x80; s[2]=(unicode&0x3F)|0x80; }
  134. else { s[0]=((unicode>>18)&0x07)|0xF0; s[1]=((unicode>>12)&0x3F)|0x80; s[2]=((unicode>>6)&0x3F)|0x80; s[3]=(unicode&0x3F)|0x80; }
  135. meg4_pushkey(s);
  136. }
  137. }
  138. /**
  139. * libretro callback; audio
  140. */
  141. static void audio_callback(void)
  142. {
  143. #define AUDIO_BUFSIZ 735 /* 44100 / 60 */
  144. float fbuf[AUDIO_BUFSIZ];
  145. int16_t ibuf[AUDIO_BUFSIZ * 2];
  146. int i, j;
  147. meg4_audiofeed(fbuf, AUDIO_BUFSIZ);
  148. if(!audio) return;
  149. for(i = j = 0; i < AUDIO_BUFSIZ; i++, j += 2)
  150. ibuf[j] = ibuf[j + 1] = fbuf[i] * 32767.0f;
  151. audio_batch_cb(ibuf, AUDIO_BUFSIZ);
  152. }
  153. /**
  154. * libretro callback; audio
  155. */
  156. static void audio_set_state(bool enable)
  157. {
  158. (void)enable;
  159. }
  160. /**
  161. * libretro callback; Global initialization.
  162. */
  163. RETRO_API void retro_init(void)
  164. {
  165. char *lng;
  166. unsigned int l = 0;
  167. sprintf(meg4plat, "libretro %u", RETRO_API_VERSION);
  168. memset(main_keymap, 0, sizeof(main_keymap));
  169. main_keymap[RETROK_SPACE] = MEG4_KEY_SPACE;
  170. main_keymap[RETROK_CARET] = MEG4_KEY_APOSTROPHE;
  171. main_keymap[RETROK_COMMA] = MEG4_KEY_COMMA;
  172. main_keymap[RETROK_MINUS] = MEG4_KEY_MINUS;
  173. main_keymap[RETROK_PERIOD] = MEG4_KEY_PERIOD;
  174. main_keymap[RETROK_SLASH] = MEG4_KEY_SLASH;
  175. main_keymap[RETROK_0] = MEG4_KEY_0;
  176. main_keymap[RETROK_1] = MEG4_KEY_1;
  177. main_keymap[RETROK_2] = MEG4_KEY_2;
  178. main_keymap[RETROK_3] = MEG4_KEY_3;
  179. main_keymap[RETROK_4] = MEG4_KEY_4;
  180. main_keymap[RETROK_5] = MEG4_KEY_5;
  181. main_keymap[RETROK_6] = MEG4_KEY_6;
  182. main_keymap[RETROK_7] = MEG4_KEY_7;
  183. main_keymap[RETROK_8] = MEG4_KEY_8;
  184. main_keymap[RETROK_9] = MEG4_KEY_9;
  185. main_keymap[RETROK_SEMICOLON] = MEG4_KEY_SEMICOLON;
  186. main_keymap[RETROK_EQUALS] = MEG4_KEY_EQUAL;
  187. main_keymap[RETROK_a] = MEG4_KEY_A;
  188. main_keymap[RETROK_b] = MEG4_KEY_B;
  189. main_keymap[RETROK_c] = MEG4_KEY_C;
  190. main_keymap[RETROK_d] = MEG4_KEY_D;
  191. main_keymap[RETROK_e] = MEG4_KEY_E;
  192. main_keymap[RETROK_f] = MEG4_KEY_F;
  193. main_keymap[RETROK_g] = MEG4_KEY_G;
  194. main_keymap[RETROK_h] = MEG4_KEY_H;
  195. main_keymap[RETROK_i] = MEG4_KEY_I;
  196. main_keymap[RETROK_j] = MEG4_KEY_J;
  197. main_keymap[RETROK_k] = MEG4_KEY_K;
  198. main_keymap[RETROK_l] = MEG4_KEY_L;
  199. main_keymap[RETROK_m] = MEG4_KEY_M;
  200. main_keymap[RETROK_n] = MEG4_KEY_N;
  201. main_keymap[RETROK_o] = MEG4_KEY_O;
  202. main_keymap[RETROK_p] = MEG4_KEY_P;
  203. main_keymap[RETROK_q] = MEG4_KEY_Q;
  204. main_keymap[RETROK_r] = MEG4_KEY_R;
  205. main_keymap[RETROK_s] = MEG4_KEY_S;
  206. main_keymap[RETROK_t] = MEG4_KEY_T;
  207. main_keymap[RETROK_u] = MEG4_KEY_U;
  208. main_keymap[RETROK_v] = MEG4_KEY_V;
  209. main_keymap[RETROK_x] = MEG4_KEY_X;
  210. main_keymap[RETROK_y] = MEG4_KEY_Y;
  211. main_keymap[RETROK_z] = MEG4_KEY_Z;
  212. main_keymap[RETROK_LEFTBRACKET] = MEG4_KEY_LBRACKET;
  213. main_keymap[RETROK_BACKSLASH] = MEG4_KEY_BACKSLASH;
  214. main_keymap[RETROK_RIGHTBRACKET] = MEG4_KEY_RBRACKET;
  215. main_keymap[RETROK_RETURN] = MEG4_KEY_ENTER;
  216. main_keymap[RETROK_TAB] = MEG4_KEY_TAB;
  217. main_keymap[RETROK_BACKSPACE] = MEG4_KEY_BACKSPACE;
  218. main_keymap[RETROK_INSERT] = MEG4_KEY_INS;
  219. main_keymap[RETROK_DELETE] = MEG4_KEY_DEL;
  220. main_keymap[RETROK_RIGHT] = MEG4_KEY_RIGHT;
  221. main_keymap[RETROK_LEFT] = MEG4_KEY_LEFT;
  222. main_keymap[RETROK_DOWN] = MEG4_KEY_DOWN;
  223. main_keymap[RETROK_UP] = MEG4_KEY_UP;
  224. main_keymap[RETROK_PAGEUP] = MEG4_KEY_PGUP;
  225. main_keymap[RETROK_PAGEDOWN] = MEG4_KEY_PGDN;
  226. main_keymap[RETROK_HOME] = MEG4_KEY_HOME;
  227. main_keymap[RETROK_END] = MEG4_KEY_END;
  228. main_keymap[RETROK_CAPSLOCK] = MEG4_KEY_CAPSLOCK;
  229. main_keymap[RETROK_SCROLLOCK] = MEG4_KEY_SCRLOCK;
  230. main_keymap[RETROK_NUMLOCK] = MEG4_KEY_NUMLOCK;
  231. main_keymap[RETROK_PRINT] = MEG4_KEY_PRSCR;
  232. main_keymap[RETROK_PAUSE] = MEG4_KEY_PAUSE;
  233. main_keymap[RETROK_F1] = MEG4_KEY_F1;
  234. main_keymap[RETROK_F2] = MEG4_KEY_F2;
  235. main_keymap[RETROK_F3] = MEG4_KEY_F3;
  236. main_keymap[RETROK_F4] = MEG4_KEY_F4;
  237. main_keymap[RETROK_F5] = MEG4_KEY_F5;
  238. main_keymap[RETROK_F6] = MEG4_KEY_F6;
  239. main_keymap[RETROK_F7] = MEG4_KEY_F7;
  240. main_keymap[RETROK_F8] = MEG4_KEY_F8;
  241. main_keymap[RETROK_F9] = MEG4_KEY_F9;
  242. main_keymap[RETROK_F10] = MEG4_KEY_F10;
  243. main_keymap[RETROK_F11] = MEG4_KEY_F11;
  244. main_keymap[RETROK_F12] = MEG4_KEY_F12;
  245. main_keymap[RETROK_KP0] = MEG4_KEY_KP_0;
  246. main_keymap[RETROK_KP1] = MEG4_KEY_KP_1;
  247. main_keymap[RETROK_KP2] = MEG4_KEY_KP_2;
  248. main_keymap[RETROK_KP3] = MEG4_KEY_KP_3;
  249. main_keymap[RETROK_KP4] = MEG4_KEY_KP_4;
  250. main_keymap[RETROK_KP5] = MEG4_KEY_KP_5;
  251. main_keymap[RETROK_KP6] = MEG4_KEY_KP_6;
  252. main_keymap[RETROK_KP7] = MEG4_KEY_KP_7;
  253. main_keymap[RETROK_KP8] = MEG4_KEY_KP_8;
  254. main_keymap[RETROK_KP9] = MEG4_KEY_KP_9;
  255. main_keymap[RETROK_KP_PERIOD] = MEG4_KEY_KP_DEC;
  256. main_keymap[RETROK_KP_DIVIDE] = MEG4_KEY_KP_DIV;
  257. main_keymap[RETROK_KP_MULTIPLY] = MEG4_KEY_KP_MUL;
  258. main_keymap[RETROK_KP_MINUS] = MEG4_KEY_KP_SUB;
  259. main_keymap[RETROK_KP_PLUS] = MEG4_KEY_KP_ADD;
  260. main_keymap[RETROK_KP_ENTER] = MEG4_KEY_KP_ENTER;
  261. main_keymap[RETROK_KP_EQUALS] = MEG4_KEY_KP_EQUAL;
  262. main_keymap[RETROK_LSHIFT] = MEG4_KEY_LSHIFT;
  263. main_keymap[RETROK_LCTRL] = MEG4_KEY_LCTRL;
  264. main_keymap[RETROK_LALT] = MEG4_KEY_LALT;
  265. main_keymap[RETROK_LSUPER] = MEG4_KEY_LSUPER;
  266. main_keymap[RETROK_RSHIFT] = MEG4_KEY_RSHIFT;
  267. main_keymap[RETROK_RCTRL] = MEG4_KEY_RCTRL;
  268. main_keymap[RETROK_RALT] = MEG4_KEY_RALT;
  269. main_keymap[RETROK_RSUPER] = MEG4_KEY_RSUPER;
  270. main_keymap[RETROK_MENU] = MEG4_KEY_MENU;
  271. if(environ_cb) environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &l);
  272. switch(l) {
  273. case RETRO_LANGUAGE_JAPANESE: lng = "ja"; break;
  274. case RETRO_LANGUAGE_FRENCH: lng = "fr"; break;
  275. case RETRO_LANGUAGE_SPANISH: lng = "es"; break;
  276. case RETRO_LANGUAGE_GERMAN: lng = "de"; break;
  277. case RETRO_LANGUAGE_ITALIAN: lng = "it"; break;
  278. case RETRO_LANGUAGE_DUTCH: lng = "nl"; break;
  279. case RETRO_LANGUAGE_PORTUGUESE_BRAZIL:
  280. case RETRO_LANGUAGE_PORTUGUESE_PORTUGAL: lng = "pt"; break;
  281. case RETRO_LANGUAGE_RUSSIAN: lng = "ru"; break;
  282. case RETRO_LANGUAGE_KOREAN: lng = "ko"; break;
  283. case RETRO_LANGUAGE_CHINESE_SIMPLIFIED:
  284. case RETRO_LANGUAGE_CHINESE_TRADITIONAL: lng = "zh"; break;
  285. case RETRO_LANGUAGE_POLISH: lng = "pl"; break;
  286. case RETRO_LANGUAGE_VIETNAMESE: lng = "vi"; break;
  287. case RETRO_LANGUAGE_ARABIC: lng = "ar"; break;
  288. case RETRO_LANGUAGE_GREEK: lng = "el"; break;
  289. case RETRO_LANGUAGE_TURKISH: lng = "tr"; break;
  290. case RETRO_LANGUAGE_SLOVAK: lng = "sk"; break;
  291. case RETRO_LANGUAGE_FINNISH: lng = "fi"; break;
  292. case RETRO_LANGUAGE_INDONESIAN: lng = "in"; break;
  293. case RETRO_LANGUAGE_SWEDISH: lng = "sv"; break;
  294. case RETRO_LANGUAGE_UKRAINIAN: lng = "uk"; break;
  295. case RETRO_LANGUAGE_CZECH: lng = "cs"; break;
  296. case RETRO_LANGUAGE_CATALAN_VALENCIA:
  297. case RETRO_LANGUAGE_CATALAN: lng = "ca"; break;
  298. case RETRO_LANGUAGE_HUNGARIAN: lng = "hu"; break;
  299. default: lng = "en"; break;
  300. }
  301. /* turn on the emulator */
  302. meg4_poweron(lng);
  303. }
  304. /**
  305. * libretro callback; Global deinitialization.
  306. */
  307. RETRO_API void retro_deinit(void)
  308. {
  309. main_quit();
  310. }
  311. /**
  312. * libretro callback; Retrieves the internal libretro API version.
  313. */
  314. RETRO_API unsigned retro_api_version(void)
  315. {
  316. return RETRO_API_VERSION;
  317. }
  318. /**
  319. * libretro callback; Reports device changes.
  320. */
  321. RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device)
  322. {
  323. (void)port; (void)device;
  324. }
  325. /**
  326. * libretro callback; Retrieves information about the core.
  327. */
  328. RETRO_API void retro_get_system_info(struct retro_system_info *info)
  329. {
  330. memset(info, 0, sizeof(struct retro_system_info));
  331. info->library_name = "MEG-4";
  332. info->library_version = meg4ver;
  333. info->valid_extensions = "png|zip|tga|tmx|mid|mod|wav|bdf|sfn|sfd|psf|gpl|txt";
  334. info->need_fullpath = true;
  335. info->block_extract = false;
  336. }
  337. /**
  338. * libretro callback; Get information about the desired audio and video.
  339. */
  340. RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info)
  341. {
  342. pixel_format = RETRO_PIXEL_FORMAT_XRGB8888;
  343. if(!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &pixel_format)) {
  344. /* default format is deprecated... no comment */
  345. pixel_format = RETRO_PIXEL_FORMAT_RGB565;
  346. environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &pixel_format);
  347. }
  348. info->timing = (struct retro_system_timing) {
  349. .fps = 60,
  350. .sample_rate = 44100,
  351. };
  352. info->geometry = (struct retro_game_geometry) {
  353. .base_width = 320,
  354. .base_height = 200,
  355. .max_width = 640,
  356. .max_height = 400,
  357. .aspect_ratio = (float)640 / (float)400,
  358. };
  359. }
  360. /**
  361. * libretro callback; Sets up the environment callback.
  362. */
  363. RETRO_API void retro_set_environment(retro_environment_t cb)
  364. {
  365. char *tmp;
  366. bool no_content = true;
  367. environ_cb = cb;
  368. cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_content);
  369. main_floppydir = NULL;
  370. if(!cb(RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY, &main_floppydir) || !main_floppydir || !*main_floppydir)
  371. cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &main_floppydir);
  372. #ifndef __WIN32__
  373. if(!main_floppydir) {
  374. tmp = getenv("HOME");
  375. if(tmp) {
  376. main_floppydir = floppydir_tmp;
  377. strncpy(main_floppydir, tmp, sizeof(floppydir_tmp) - 1);
  378. strncat(main_floppydir, "/MEG-4", sizeof(floppydir_tmp) - 1);
  379. mkdir(main_floppydir, 0777);
  380. }
  381. }
  382. #endif
  383. }
  384. /**
  385. * libretro callback; Set up the audio sample callback.
  386. */
  387. RETRO_API void retro_set_audio_sample(retro_audio_sample_t cb)
  388. {
  389. audio_cb = cb;
  390. }
  391. /**
  392. * libretro callback; Set up the audio sample batch callback.
  393. *
  394. * @see tic80_libretro_audio()
  395. */
  396. RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
  397. {
  398. audio_batch_cb = cb;
  399. }
  400. /**
  401. * libretro callback; Set up the input poll callback.
  402. */
  403. RETRO_API void retro_set_input_poll(retro_input_poll_t cb)
  404. {
  405. input_poll_cb = cb;
  406. }
  407. /**
  408. * libretro callback; Set up the input state callback.
  409. */
  410. RETRO_API void retro_set_input_state(retro_input_state_t cb)
  411. {
  412. input_state_cb = cb;
  413. }
  414. /**
  415. * libretro callback; Set up the video refresh callback.
  416. */
  417. RETRO_API void retro_set_video_refresh(retro_video_refresh_t cb)
  418. {
  419. video_cb = cb;
  420. }
  421. /**
  422. * libretro callback; Reset the game.
  423. */
  424. RETRO_API void retro_reset(void)
  425. {
  426. meg4_reset();
  427. /* if we have already loaded a game, reload it */
  428. if(game_fn[0] && game_buf && game_len > 0)
  429. meg4_insert(game_fn, game_buf, game_len);
  430. }
  431. /**
  432. * libretro callback; Render the screen and play the audio.
  433. */
  434. RETRO_API void retro_run(void)
  435. {
  436. int i, j, k;
  437. /* handle events... by polling */
  438. input_poll_cb();
  439. /* mouse */
  440. mx += input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X);
  441. my += input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y);
  442. if(mx < 0) mx = 0;
  443. if(mx > meg4.screen.w) mx = meg4.screen.w;
  444. if(my < 0) my = 0;
  445. if(my > meg4.screen.h) my = meg4.screen.h;
  446. meg4_setptr(mx, my);
  447. /* we have only press events, but no release events... */
  448. i = input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT);
  449. if(i && !ml) { ml = 1; meg4_setbtn(MEG4_BTN_L); } else
  450. if(!i && ml) { ml = 0; meg4_clrbtn(MEG4_BTN_L); }
  451. i = input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_MIDDLE);
  452. if(i && !mm) { mm = 1; meg4_setbtn(MEG4_BTN_M); } else
  453. if(!i && mm) { mm = 0; meg4_clrbtn(MEG4_BTN_M); }
  454. i = input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT);
  455. if(i && !mr) { mr = 1; meg4_setbtn(MEG4_BTN_R); } else
  456. if(!i && mr) { mr = 0; meg4_clrbtn(MEG4_BTN_R); }
  457. if(input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_WHEELUP)) meg4_setscr(1, 0, 0, 0); else
  458. if(input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_WHEELDOWN)) meg4_setscr(0, 1, 0, 0);
  459. if(input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP)) meg4_setscr(0, 0, 0, 1); else
  460. if(input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN)) meg4_setscr(0, 0, 1, 0);
  461. /* keyboard */
  462. for(i = RETROK_FIRST; i < RETROK_LAST; i++)
  463. if(main_keymap[i]) {
  464. j = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, i);
  465. k = meg4_api_getkey(main_keymap[i]);
  466. if(j && !k) {
  467. /*printf("keypress i %d\n",i);*/
  468. switch(i) {
  469. case RETROK_LALT: case RETROK_LCTRL: main_alt = 1; break;
  470. case RETROK_RALT: main_alt = 0; break;
  471. case RETROK_RETURN:
  472. if(main_alt) main_fullscreen();
  473. else meg4_pushkey("\n\0\0");
  474. break;
  475. case RETROK_q: if(main_alt) { retro_deinit(); environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, NULL); } break;
  476. /* doesn't work. Have to check in keyboard_cb */
  477. /* case RETROK_ESCAPE: if(main_alt) { retro_deinit(); environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, NULL); } else meg4_pushkey("\x1b\0\0"); break;*/
  478. /* only for special keys that aren't handled by keyboard_cb */
  479. case RETROK_F1: meg4_pushkey("F1\0"); break;
  480. case RETROK_F2: meg4_pushkey("F2\0"); break;
  481. case RETROK_F3: meg4_pushkey("F3\0"); break;
  482. case RETROK_F4: meg4_pushkey("F4\0"); break;
  483. case RETROK_F5: meg4_pushkey("F5\0"); break;
  484. case RETROK_F6: meg4_pushkey("F6\0"); break;
  485. case RETROK_F7: meg4_pushkey("F7\0"); break;
  486. case RETROK_F8: meg4_pushkey("F8\0"); break;
  487. case RETROK_F9: meg4_pushkey("F9\0"); break;
  488. case RETROK_F10: meg4_pushkey("F10"); break;
  489. case RETROK_F11: main_fullscreen(); break;
  490. case RETROK_F12: meg4_pushkey("F12"); break;
  491. case RETROK_PRINT: meg4_pushkey("PSc"); break;
  492. case RETROK_SCROLLOCK: meg4_pushkey("SLk"); break;
  493. case RETROK_NUMLOCK: meg4_pushkey("NLk"); break;
  494. case RETROK_BACKSPACE: meg4_pushkey("\b\0\0"); break;
  495. case RETROK_TAB: meg4_pushkey("\t\0\0"); break;
  496. case RETROK_CAPSLOCK: meg4_pushkey("CLk"); break;
  497. case RETROK_UP: meg4_pushkey("Up\0"); break;
  498. case RETROK_DOWN: meg4_pushkey("Down"); break;
  499. case RETROK_LEFT: meg4_pushkey("Left"); break;
  500. case RETROK_RIGHT: meg4_pushkey("Rght"); break;
  501. case RETROK_HOME: meg4_pushkey("Home"); break;
  502. case RETROK_END: meg4_pushkey("End"); break;
  503. case RETROK_PAGEUP: meg4_pushkey("PgUp"); break;
  504. case RETROK_PAGEDOWN: meg4_pushkey("PgDn"); break;
  505. case RETROK_INSERT: meg4_pushkey("Ins"); break;
  506. case RETROK_DELETE: meg4_pushkey("Del"); break;
  507. default: break;
  508. }
  509. meg4_setkey(main_keymap[i]);
  510. } else
  511. if(!j && k) {
  512. switch(i) {
  513. case RETROK_LALT: case RETROK_LCTRL: main_alt = 0; break;
  514. default: break;
  515. }
  516. meg4_clrkey(main_keymap[i]);
  517. }
  518. }
  519. /* gamepads */
  520. for(i = 0; i < 4; i++) {
  521. /* we have only press events, but no release events... */
  522. j = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP);
  523. k = meg4_api_getpad(i, MEG4_BTN_U);
  524. if(j && !k) meg4_setpad(i, MEG4_BTN_U); else if(!j && k) meg4_clrpad(i, MEG4_BTN_U);
  525. j = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN);
  526. k = meg4_api_getpad(i, MEG4_BTN_D);
  527. if(j && !k) meg4_setpad(i, MEG4_BTN_D); else if(!j && k) meg4_clrpad(i, MEG4_BTN_D);
  528. j = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT);
  529. k = meg4_api_getpad(i, MEG4_BTN_L);
  530. if(j && !k) meg4_setpad(i, MEG4_BTN_L); else if(!j && k) meg4_clrpad(i, MEG4_BTN_L);
  531. j = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT);
  532. k = meg4_api_getpad(i, MEG4_BTN_R);
  533. if(j && !k) meg4_setpad(i, MEG4_BTN_R); else if(!j && k) meg4_clrpad(i, MEG4_BTN_R);
  534. j = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A);
  535. k = meg4_api_getpad(i, MEG4_BTN_A);
  536. if(j && !k) meg4_setpad(i, MEG4_BTN_A); else if(!j && k) meg4_clrpad(i, MEG4_BTN_A);
  537. j = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B);
  538. k = meg4_api_getpad(i, MEG4_BTN_B);
  539. if(j && !k) meg4_setpad(i, MEG4_BTN_B); else if(!j && k) meg4_clrpad(i, MEG4_BTN_B);
  540. j = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X);
  541. k = meg4_api_getpad(i, MEG4_BTN_X);
  542. if(j && !k) meg4_setpad(i, MEG4_BTN_X); else if(!j && k) meg4_clrpad(i, MEG4_BTN_X);
  543. j = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y);
  544. k = meg4_api_getpad(i, MEG4_BTN_Y);
  545. if(j && !k) meg4_setpad(i, MEG4_BTN_Y); else if(!j && k) meg4_clrpad(i, MEG4_BTN_Y);
  546. }
  547. meg4_run();
  548. meg4_redraw(scrbuf32, 640, 400, 640 * 4);
  549. /* Muhahaha, libretro sucks such a big time... on a real hw video channel order is independent to the CPU endianness
  550. * talking about wasting precious CPU time in a function that runs 60 times every sec... */
  551. if(pixel_format == RETRO_PIXEL_FORMAT_XRGB8888) {
  552. #if MEG4_BYTEORDER == 1234
  553. for(i = 0; i < 640 * 400; i++)
  554. scrbuf32[i] = ((scrbuf32[i] >> 16) & 0xff) | ((scrbuf32[i] & 0xff) << 16) | (scrbuf32[i] & 0xff00);
  555. #endif
  556. video_cb((void*)scrbuf32, meg4.screen.w, meg4.screen.h, 640 * sizeof(uint32_t));
  557. } else {
  558. for(i = 0; i < 640 * 400; i++)
  559. #if MEG4_BYTEORDER == 1234
  560. scrbuf16[i] = ((scrbuf32[i] & 0xf8) << 8) | ((scrbuf32[i] >> 19) & 0x1f) | ((scrbuf32[i] & 0xfc00) >> 5);
  561. #else
  562. scrbuf16[i] = ((scrbuf32[i] >> 3) & 0x1f) | ((scrbuf32[i] & 0xf80000) >> 8) | ((scrbuf32[i] & 0xfc00) >> 5);
  563. #endif
  564. video_cb((void*)scrbuf16, meg4.screen.w, meg4.screen.h, 640 * sizeof(uint16_t));
  565. }
  566. /* play audio in the main thread... could this be any more inefficient? */
  567. if(!use_audio_cb) audio_callback();
  568. }
  569. /**
  570. * libretro callback; Load a game.
  571. */
  572. RETRO_API bool retro_load_game(const struct retro_game_info *info)
  573. {
  574. uint8_t *ptr;
  575. char *fn;
  576. int l;
  577. /* not sure why we have to do this in load game function, why not in retro_init, but all libretro examples do it here */
  578. struct retro_audio_callback audio_cb = { audio_callback, audio_set_state };
  579. struct retro_keyboard_callback cb = { keyboard_cb };
  580. struct retro_input_descriptor desc[] = {
  581. { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
  582. { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
  583. { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
  584. { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
  585. { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
  586. { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
  587. { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" },
  588. { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" },
  589. { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
  590. { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
  591. { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
  592. { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
  593. { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
  594. { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
  595. { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" },
  596. { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" },
  597. { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
  598. { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
  599. { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
  600. { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
  601. { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
  602. { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
  603. { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" },
  604. { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" },
  605. { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
  606. { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
  607. { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
  608. { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
  609. { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
  610. { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
  611. { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" },
  612. { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" },
  613. { 0 }
  614. };
  615. environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
  616. environ_cb(RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK, &cb);
  617. use_audio_cb = environ_cb(RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK, &audio_cb);
  618. /* sometimes this is called with a NULL... and never return false from this function, retroarch will exit immediately! */
  619. if(!info || (!info->path && !info->data)) return true;
  620. /* save the floppy's data in game_X because we'll have to reload it on game reset */
  621. if(!info->path && info->data && info->size > 0) {
  622. strncpy(game_fn, "noname.png", sizeof(game_fn) - 1);
  623. meg4_insert(game_fn, (uint8_t *)info->data, info->size);
  624. game_buf = (uint8_t*)realloc(game_buf, info->size);
  625. if(game_buf) { memcpy(game_buf, info->data, info->size); game_len = info->size; }
  626. else { memset(game_fn, 0, sizeof(game_fn)); game_len = 0; }
  627. } else if(info->path && (ptr = main_readfile(!memcmp(info->path, "file://", 7) ? (char*)info->path + 7 : (char*)info->path, &l))) {
  628. fn = strrchr((char*)info->path, SEP[0]); if(!fn) fn = (char*)info->path; else fn++;
  629. meg4_insert(fn, ptr, l);
  630. game_buf = (uint8_t*)realloc(game_buf, l);
  631. if(game_buf) { strncpy(game_fn, fn, sizeof(game_fn) - 1); memcpy(game_buf, ptr, l); game_len = l; }
  632. else { memset(game_fn, 0, sizeof(game_fn)); game_len = 0; }
  633. free(ptr);
  634. }
  635. return true;
  636. }
  637. /**
  638. * libretro callback; Tells the core to unload the game.
  639. */
  640. RETRO_API void retro_unload_game(void)
  641. {
  642. meg4_reset();
  643. memset(game_fn, 0, sizeof(game_fn)); game_len = 0;
  644. if(game_buf) { free(game_buf); game_buf = NULL; }
  645. }
  646. /**
  647. * libretro callback; Retrieves the region for the content.
  648. */
  649. RETRO_API unsigned retro_get_region(void)
  650. {
  651. return RETRO_REGION_NTSC; /* 60 fps */
  652. }
  653. /**
  654. * libretro callback; Load a game using a subsystem.
  655. */
  656. RETRO_API bool retro_load_game_special(unsigned type, const struct retro_game_info *info, size_t num)
  657. {
  658. (void)num; (void)type;
  659. return retro_load_game(info);
  660. }
  661. /**
  662. * libretro callback; Retrieve the size of the serialized memory.
  663. */
  664. size_t retro_serialize_size(void)
  665. {
  666. return 0;
  667. }
  668. /**
  669. * libretro callback; Get the current persistent memory.
  670. */
  671. RETRO_API bool retro_serialize(void *data, size_t size)
  672. {
  673. (void)data; (void)size;
  674. return false;
  675. }
  676. /**
  677. * libretro callback; Given the serialized data, load it into the persistent memory.
  678. */
  679. RETRO_API bool retro_unserialize(const void *data, size_t size)
  680. {
  681. (void)data; (void)size;
  682. return false;
  683. }
  684. /**
  685. * libretro callback; Gets region of memory.
  686. */
  687. RETRO_API void *retro_get_memory_data(unsigned id)
  688. {
  689. (void)id;
  690. return NULL;
  691. }
  692. /**
  693. * libretro callback; Gets the size of the given memory slot.
  694. */
  695. RETRO_API size_t retro_get_memory_size(unsigned id)
  696. {
  697. (void)id;
  698. return 0;
  699. }
  700. /**
  701. * libretro callback; Reset all cheats to disabled.
  702. */
  703. RETRO_API void retro_cheat_reset(void)
  704. {
  705. meg4.mmio.kbdkeys[0] &= ~1;
  706. }
  707. /**
  708. * libretro callback; Enable/disable the given cheat code.
  709. */
  710. RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code)
  711. {
  712. (void)index; (void)code;
  713. if(enabled) meg4.mmio.kbdkeys[0] |= 1;
  714. else meg4.mmio.kbdkeys[0] &= ~1;
  715. }