main.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*
  2. * meg4/platform/sokol/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 sokol "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. #define SOKOL_IMPL
  27. #define SOKOL_AUDIO_IMPL
  28. #if defined(__APPLE__)
  29. #define SOKOL_METAL
  30. #elif defined(__WIN32__)
  31. #define SOKOL_D3D11
  32. #elif defined(__EMSCRIPTEN__)
  33. #define SOKOL_GLES2
  34. #else
  35. #define SOKOL_GLCORE33
  36. #endif
  37. #include "sokol_app.h"
  38. #include "sokol_gfx.h"
  39. #include "sokol_audio.h"
  40. #include "sokol_gl.h"
  41. #include "sokol_glue.h"
  42. uint32_t *scrbuf = NULL;
  43. sg_image img;
  44. sgl_pipeline pip;
  45. static const sg_pass_action pass_action = {
  46. .colors[0] = { .load_action = SG_LOADACTION_CLEAR, .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f } }
  47. };
  48. int main_w = 0, main_h = 0, win_w, win_h, win_f = 0, audio = 0, main_alt = 0, main_keymap[512];
  49. int mx = 160, my = 100;
  50. void main_delay(int msec);
  51. char main_clip[1048576];
  52. #define meg4_showcursor() sapp_show_mouse(1)
  53. #define meg4_hidecursor() sapp_show_mouse(0)
  54. #include "../common.h"
  55. /**
  56. * Logger
  57. */
  58. void slog(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, uint32_t line_nr, const char* filename, void* user_data)
  59. {
  60. const char *log_level_str[] = { "panic", "error", "warning", "info", "unk4", "unk5", "unk6", "unk7" };
  61. (void)user_data;
  62. main_log(3, "sokol-%s:%s(%u):%s(%u): %s", log_level_str[log_level], tag, log_item, filename, line_nr, message);
  63. }
  64. /**
  65. * Exit emulator
  66. */
  67. void main_quit(void)
  68. {
  69. main_log(1, "quitting... ");
  70. meg4_poweroff();
  71. if(audio) { saudio_shutdown(); audio = 0; }
  72. if(img.id != SG_INVALID_ID) { sg_destroy_image(img); img.id = SG_INVALID_ID; }
  73. if(scrbuf) { free(scrbuf); scrbuf = NULL; }
  74. meg4_showcursor();
  75. sgl_shutdown();
  76. sg_shutdown();
  77. exit(0);
  78. }
  79. /**
  80. * Toggle fullscreen
  81. */
  82. void main_fullscreen(void)
  83. {
  84. sapp_toggle_fullscreen();
  85. win_f = sapp_is_fullscreen();
  86. }
  87. /**
  88. * Make window focused
  89. */
  90. void main_focus(void)
  91. {
  92. /* TODO: how to focus window with sokol? */
  93. }
  94. /**
  95. * Get text from clipboard (must be freed by caller)
  96. */
  97. char *main_getclipboard(void)
  98. {
  99. char *ret = NULL;
  100. /* we use a cache because sapp_get_clipboard_string() can only be called in pasted event handler */
  101. if(main_clip[0]) {
  102. ret = (char*)malloc(strlen(main_clip) + 1);
  103. if(ret) strcpy(ret, main_clip);
  104. }
  105. return ret;
  106. }
  107. /**
  108. * Set text to clipboard
  109. */
  110. void main_setclipboard(char *str)
  111. {
  112. sapp_set_clipboard_string(str);
  113. }
  114. /**
  115. * Show on-screen keyboard
  116. */
  117. void main_osk_show(void)
  118. {
  119. sapp_show_keyboard(1);
  120. }
  121. /**
  122. * Hide on-screen keyboard
  123. */
  124. void main_osk_hide(void)
  125. {
  126. sapp_show_keyboard(0);
  127. }
  128. /**
  129. * Audio callback
  130. */
  131. void main_audio(float *buffer, int frames, int channels)
  132. {
  133. (void)channels;
  134. meg4_audiofeed(buffer, frames);
  135. }
  136. /**
  137. * Delay
  138. */
  139. void main_delay(int msec)
  140. {
  141. struct timespec tv;
  142. tv.tv_sec = 0; tv.tv_nsec = msec * 1000000;
  143. nanosleep(&tv, NULL);
  144. }
  145. /**
  146. * Print program version and copyright
  147. */
  148. void main_hdr(void)
  149. {
  150. printf("\r\nMEG-4 v%s (sokol, build %u) by bzt Copyright (C) 2023 GPLv3+\r\n\r\n", meg4ver, BUILD);
  151. }
  152. /**
  153. * Initialize Sokol
  154. */
  155. static void init(void)
  156. {
  157. memset(main_clip, 0, sizeof(main_clip));
  158. sg_setup(&(sg_desc){ .context = sapp_sgcontext(), .logger.func = slog });
  159. sgl_setup(&(sgl_desc_t){ .logger.func = slog });
  160. pip = sgl_make_pipeline(&(sg_pipeline_desc){ .colors[0] = { .write_mask = SG_COLORMASK_RGB } });
  161. img = sg_make_image(&(sg_image_desc){
  162. .pixel_format = SG_PIXELFORMAT_RGBA8,
  163. .width = 640,
  164. .height = 400,
  165. .usage = SG_USAGE_STREAM,
  166. .mag_filter = nearest ? SG_FILTER_NEAREST : SG_FILTER_LINEAR,
  167. .min_filter = nearest ? SG_FILTER_NEAREST : SG_FILTER_LINEAR,
  168. .wrap_u = SG_WRAP_CLAMP_TO_EDGE,
  169. .wrap_v = SG_WRAP_CLAMP_TO_EDGE
  170. });
  171. saudio_setup(&(saudio_desc){
  172. .sample_rate = 44100,
  173. .num_channels = 1,
  174. .stream_cb = main_audio,
  175. .logger.func = slog,
  176. });
  177. audio = saudio_isvalid();
  178. if(verbose && audio) main_log(1, "audio opened %uHz, %u bits", 44100, 32);
  179. #ifndef DEBUG
  180. if(!windowed) main_fullscreen();
  181. #endif
  182. meg4_setptr(mx, my);
  183. meg4_hidecursor();
  184. }
  185. /**
  186. * Render one Sokol frame
  187. */
  188. static void frame(void)
  189. {
  190. int i, w, h, ww = sapp_width(), wh = sapp_height();
  191. float vert[16], x2, y2;
  192. meg4_run();
  193. meg4_redraw(scrbuf, 640, 400, 640 * 4);
  194. sg_update_image(img, &(sg_image_data){ .subimage[0][0] = { .ptr = scrbuf, .size = 640 * 400 * 4 } });
  195. if(!win_f && nearest) {
  196. /* img.min_filter = img.mag_filter = SG_FILTER_NEAREST; */
  197. i = ww / 320; h = wh / 200; if(i > h) i = h;
  198. w = 320 * i; h = 200 * i;
  199. } else {
  200. /* img.min_filter = img.mag_filter = nearest || (!(ww % 320) && !(wh % 200)) ? SG_FILTER_NEAREST : SG_FILTER_LINEAR; */
  201. w = ww; h = (int)meg4.screen.h * ww / (int)meg4.screen.w;
  202. if(h > wh) { h = wh; w = (int)meg4.screen.w * wh / (int)meg4.screen.h; }
  203. }
  204. w >>= 1; h >>= 1;
  205. x2 = (float)meg4.screen.w / 640.0f;
  206. y2 = (float)meg4.screen.h / 400.0f;
  207. vert[ 0] = -w; vert[ 1] = -h; vert[ 2] = 0; vert[ 3] = 0;
  208. vert[ 4] = -w; vert[ 5] = h; vert[ 6] = 0; vert[ 7] = y2;
  209. vert[ 8] = w; vert[ 9] = h; vert[10] = x2; vert[11] = y2;
  210. vert[12] = w; vert[13] = -h; vert[14] = x2; vert[15] = 0;
  211. sgl_defaults();
  212. sgl_enable_texture();
  213. sgl_matrix_mode_projection();
  214. sgl_ortho(-(float)ww*0.5f, (float)ww*0.5f, (float)wh*0.5f, -(float)wh*0.5f, 0.0f, +1.0f);
  215. sgl_texture(img);
  216. sgl_load_pipeline(pip);
  217. sgl_c3f(1.0f, 1.0f, 1.0f);
  218. sgl_begin_quads();
  219. sgl_v2f_t2f(vert[0], vert[1], vert[2], vert[3]);
  220. sgl_v2f_t2f(vert[4], vert[5], vert[6], vert[7]);
  221. sgl_v2f_t2f(vert[8], vert[9], vert[10], vert[11]);
  222. sgl_v2f_t2f(vert[12], vert[13], vert[14], vert[15]);
  223. sgl_end();
  224. sg_begin_default_passf(&pass_action, ww, wh);
  225. sgl_draw();
  226. sg_end_pass();
  227. sg_commit();
  228. }
  229. /**
  230. * Sokol event handler
  231. */
  232. static void event(const sapp_event* ev)
  233. {
  234. int i, n, l;
  235. char *str, *fn, s[5];
  236. uint8_t *ptr;
  237. switch(ev->type) {
  238. case SAPP_EVENTTYPE_MOUSE_MOVE:
  239. mx += ev->mouse_dx; my += ev->mouse_dy;
  240. if(mx < 0) mx = 0;
  241. if(mx > meg4.screen.w) mx = meg4.screen.w;
  242. if(my < 0) my = 0;
  243. if(my > meg4.screen.h) my = meg4.screen.h;
  244. meg4_setptr(mx, my);
  245. break;
  246. case SAPP_EVENTTYPE_MOUSE_DOWN:
  247. switch(ev->mouse_button) {
  248. case SAPP_MOUSEBUTTON_LEFT: meg4_setbtn(MEG4_BTN_L); break;
  249. case SAPP_MOUSEBUTTON_MIDDLE: meg4_setbtn(MEG4_BTN_M); break;
  250. case SAPP_MOUSEBUTTON_RIGHT: meg4_setbtn(MEG4_BTN_R); break;
  251. default: break;
  252. }
  253. break;
  254. case SAPP_EVENTTYPE_MOUSE_UP:
  255. switch(ev->mouse_button) {
  256. case SAPP_MOUSEBUTTON_LEFT: meg4_clrbtn(MEG4_BTN_L); break;
  257. case SAPP_MOUSEBUTTON_MIDDLE: meg4_clrbtn(MEG4_BTN_M); break;
  258. case SAPP_MOUSEBUTTON_RIGHT: meg4_clrbtn(MEG4_BTN_R); break;
  259. default: break;
  260. }
  261. break;
  262. case SAPP_EVENTTYPE_MOUSE_SCROLL:
  263. meg4_setscr(ev->scroll_y > 0.0, ev->scroll_y < 0.0, ev->scroll_x > 0.0, ev->scroll_x < 0.0);
  264. break;
  265. case SAPP_EVENTTYPE_KEY_DOWN:
  266. switch(ev->key_code) {
  267. case SAPP_KEYCODE_LEFT_ALT: case SAPP_KEYCODE_LEFT_CONTROL: main_alt = 1; break;
  268. case SAPP_KEYCODE_RIGHT_ALT: main_alt = 0; break;
  269. case SAPP_KEYCODE_ENTER:
  270. if(main_alt) {
  271. main_fullscreen();
  272. return;
  273. }
  274. meg4_pushkey("\n\0\0");
  275. break;
  276. case SAPP_KEYCODE_Q: if(main_alt) { main_quit(); } break;
  277. case SAPP_KEYCODE_ESCAPE: if(main_alt) { main_quit(); } else meg4_pushkey("\x1b\0\0"); break;
  278. /* only for special keys that aren't handled by SAPP_EVENTTYPE_CHAR events */
  279. case SAPP_KEYCODE_F1: meg4_pushkey("F1\0"); break;
  280. case SAPP_KEYCODE_F2: meg4_pushkey("F2\0"); break;
  281. case SAPP_KEYCODE_F3: meg4_pushkey("F3\0"); break;
  282. case SAPP_KEYCODE_F4: meg4_pushkey("F4\0"); break;
  283. case SAPP_KEYCODE_F5: meg4_pushkey("F5\0"); break;
  284. case SAPP_KEYCODE_F6: meg4_pushkey("F6\0"); break;
  285. case SAPP_KEYCODE_F7: meg4_pushkey("F7\0"); break;
  286. case SAPP_KEYCODE_F8: meg4_pushkey("F8\0"); break;
  287. case SAPP_KEYCODE_F9: meg4_pushkey("F9\0"); break;
  288. case SAPP_KEYCODE_F10: meg4_pushkey("F10"); break;
  289. case SAPP_KEYCODE_F11: main_fullscreen(); break;
  290. case SAPP_KEYCODE_F12: meg4_pushkey("F12"); break;
  291. case SAPP_KEYCODE_PRINT_SCREEN: meg4_pushkey("PSc"); break;
  292. case SAPP_KEYCODE_SCROLL_LOCK: meg4_pushkey("SLk"); break;
  293. case SAPP_KEYCODE_NUM_LOCK: meg4_pushkey("NLk"); break;
  294. case SAPP_KEYCODE_BACKSPACE: meg4_pushkey("\b\0\0"); break;
  295. case SAPP_KEYCODE_TAB: meg4_pushkey("\t\0\0"); break;
  296. case SAPP_KEYCODE_CAPS_LOCK: meg4_pushkey("CLk"); break;
  297. case SAPP_KEYCODE_UP: meg4_pushkey("Up\0"); break;
  298. case SAPP_KEYCODE_DOWN: meg4_pushkey("Down"); break;
  299. case SAPP_KEYCODE_LEFT: meg4_pushkey("Left"); break;
  300. case SAPP_KEYCODE_RIGHT: meg4_pushkey("Rght"); break;
  301. case SAPP_KEYCODE_HOME: meg4_pushkey("Home"); break;
  302. case SAPP_KEYCODE_END: meg4_pushkey("End"); break;
  303. case SAPP_KEYCODE_PAGE_UP: meg4_pushkey("PgUp"); break;
  304. case SAPP_KEYCODE_PAGE_DOWN: meg4_pushkey("PgDn"); break;
  305. case SAPP_KEYCODE_INSERT: meg4_pushkey("Ins"); break;
  306. case SAPP_KEYCODE_DELETE: meg4_pushkey("Del"); break;
  307. default: break;
  308. }
  309. if(ev->key_code > 0 && ev->key_code < 512 && main_keymap[ev->key_code]) meg4_setkey(main_keymap[ev->key_code]);
  310. break;
  311. case SAPP_EVENTTYPE_KEY_UP:
  312. switch(ev->key_code) {
  313. case SAPP_KEYCODE_LEFT_ALT: case SAPP_KEYCODE_LEFT_CONTROL: main_alt = 0; break;
  314. default: break;
  315. }
  316. if(ev->key_code > 0 && ev->key_code < 512 && main_keymap[ev->key_code]) meg4_clrkey(main_keymap[ev->key_code]);
  317. break;
  318. case SAPP_EVENTTYPE_CHAR:
  319. if(!main_alt && ev->char_code >= 32) {
  320. memset(s, 0, sizeof(s));
  321. if(ev->char_code<0x80) { s[0]=ev->char_code; } else
  322. if(ev->char_code<0x800) { s[0]=((ev->char_code>>6)&0x1F)|0xC0; s[1]=(ev->char_code&0x3F)|0x80; } else
  323. if(ev->char_code<0x10000) { s[0]=((ev->char_code>>12)&0x0F)|0xE0; s[1]=((ev->char_code>>6)&0x3F)|0x80; s[2]=(ev->char_code&0x3F)|0x80; }
  324. else { s[0]=((ev->char_code>>18)&0x07)|0xF0; s[1]=((ev->char_code>>12)&0x3F)|0x80; s[2]=((ev->char_code>>6)&0x3F)|0x80; s[3]=(ev->char_code&0x3F)|0x80; }
  325. meg4_pushkey(s);
  326. }
  327. break;
  328. case SAPP_EVENTTYPE_CLIPBOARD_PASTED:
  329. /* according to the doc, sapp_get_clipboard_string() can only be called in pasted event handler. So we save the pasted
  330. * string in a cache, and when MEG-4 receives a paste keypress, it will call main_getclipboard() that reads this cache */
  331. memset(main_clip, 0, sizeof(main_clip));
  332. str = (char*)sapp_get_clipboard_string();
  333. if(str && *str) { strncpy(main_clip, str, sizeof(main_clip) - 1); }
  334. break;
  335. case SAPP_EVENTTYPE_FILES_DROPPED:
  336. for(i = 0, n = sapp_get_num_dropped_files(); i < n; i++) {
  337. str = (char*)sapp_get_dropped_file_path(i);
  338. if((ptr = main_readfile(!memcmp(str, "file://", 7) ? str + 7 : str, &l))) {
  339. fn = strrchr(str, SEP[0]); if(!fn) fn = str; else fn++;
  340. meg4_insert(fn, ptr, l);
  341. free(ptr);
  342. }
  343. }
  344. break;
  345. default: break;
  346. }
  347. }
  348. /**
  349. * The real main procedure
  350. */
  351. sapp_desc sokol_main(int argc, char* argv[])
  352. {
  353. int i;
  354. char **infile = NULL, *fn;
  355. uint8_t *ptr;
  356. #ifdef __WIN32__
  357. char *lng = main_lng;
  358. #else
  359. char *lng = getenv("LANG");
  360. #endif
  361. main_parsecommandline(argc, argv, &lng, &infile);
  362. main_hdr();
  363. for(i = 0; i < 3; i++) printf(" %s\r\n", copyright[i]);
  364. printf("\r\n");
  365. fflush(stdout);
  366. strcpy(meg4plat, "sokol");
  367. /* set up keymap */
  368. memset(main_keymap, 0, sizeof(main_keymap));
  369. main_keymap[SAPP_KEYCODE_SPACE] = MEG4_KEY_SPACE;
  370. main_keymap[SAPP_KEYCODE_APOSTROPHE] = MEG4_KEY_APOSTROPHE;
  371. main_keymap[SAPP_KEYCODE_COMMA] = MEG4_KEY_COMMA;
  372. main_keymap[SAPP_KEYCODE_MINUS] = MEG4_KEY_MINUS;
  373. main_keymap[SAPP_KEYCODE_PERIOD] = MEG4_KEY_PERIOD;
  374. main_keymap[SAPP_KEYCODE_SLASH] = MEG4_KEY_SLASH;
  375. main_keymap[SAPP_KEYCODE_0] = MEG4_KEY_0;
  376. main_keymap[SAPP_KEYCODE_1] = MEG4_KEY_1;
  377. main_keymap[SAPP_KEYCODE_2] = MEG4_KEY_2;
  378. main_keymap[SAPP_KEYCODE_3] = MEG4_KEY_3;
  379. main_keymap[SAPP_KEYCODE_4] = MEG4_KEY_4;
  380. main_keymap[SAPP_KEYCODE_5] = MEG4_KEY_5;
  381. main_keymap[SAPP_KEYCODE_6] = MEG4_KEY_6;
  382. main_keymap[SAPP_KEYCODE_7] = MEG4_KEY_7;
  383. main_keymap[SAPP_KEYCODE_8] = MEG4_KEY_8;
  384. main_keymap[SAPP_KEYCODE_9] = MEG4_KEY_9;
  385. main_keymap[SAPP_KEYCODE_SEMICOLON] = MEG4_KEY_SEMICOLON;
  386. main_keymap[SAPP_KEYCODE_EQUAL] = MEG4_KEY_EQUAL;
  387. main_keymap[SAPP_KEYCODE_A] = MEG4_KEY_A;
  388. main_keymap[SAPP_KEYCODE_B] = MEG4_KEY_B;
  389. main_keymap[SAPP_KEYCODE_C] = MEG4_KEY_C;
  390. main_keymap[SAPP_KEYCODE_D] = MEG4_KEY_D;
  391. main_keymap[SAPP_KEYCODE_E] = MEG4_KEY_E;
  392. main_keymap[SAPP_KEYCODE_F] = MEG4_KEY_F;
  393. main_keymap[SAPP_KEYCODE_G] = MEG4_KEY_G;
  394. main_keymap[SAPP_KEYCODE_H] = MEG4_KEY_H;
  395. main_keymap[SAPP_KEYCODE_I] = MEG4_KEY_I;
  396. main_keymap[SAPP_KEYCODE_J] = MEG4_KEY_J;
  397. main_keymap[SAPP_KEYCODE_K] = MEG4_KEY_K;
  398. main_keymap[SAPP_KEYCODE_L] = MEG4_KEY_L;
  399. main_keymap[SAPP_KEYCODE_M] = MEG4_KEY_M;
  400. main_keymap[SAPP_KEYCODE_N] = MEG4_KEY_N;
  401. main_keymap[SAPP_KEYCODE_O] = MEG4_KEY_O;
  402. main_keymap[SAPP_KEYCODE_P] = MEG4_KEY_P;
  403. main_keymap[SAPP_KEYCODE_Q] = MEG4_KEY_Q;
  404. main_keymap[SAPP_KEYCODE_R] = MEG4_KEY_R;
  405. main_keymap[SAPP_KEYCODE_S] = MEG4_KEY_S;
  406. main_keymap[SAPP_KEYCODE_T] = MEG4_KEY_T;
  407. main_keymap[SAPP_KEYCODE_U] = MEG4_KEY_U;
  408. main_keymap[SAPP_KEYCODE_V] = MEG4_KEY_V;
  409. main_keymap[SAPP_KEYCODE_X] = MEG4_KEY_X;
  410. main_keymap[SAPP_KEYCODE_Y] = MEG4_KEY_Y;
  411. main_keymap[SAPP_KEYCODE_Z] = MEG4_KEY_Z;
  412. main_keymap[SAPP_KEYCODE_LEFT_BRACKET] = MEG4_KEY_LBRACKET;
  413. main_keymap[SAPP_KEYCODE_BACKSLASH] = MEG4_KEY_BACKSLASH;
  414. main_keymap[SAPP_KEYCODE_RIGHT_BRACKET] = MEG4_KEY_RBRACKET;
  415. main_keymap[SAPP_KEYCODE_ENTER] = MEG4_KEY_ENTER;
  416. main_keymap[SAPP_KEYCODE_TAB] = MEG4_KEY_TAB;
  417. main_keymap[SAPP_KEYCODE_BACKSPACE] = MEG4_KEY_BACKSPACE;
  418. main_keymap[SAPP_KEYCODE_INSERT] = MEG4_KEY_INS;
  419. main_keymap[SAPP_KEYCODE_DELETE] = MEG4_KEY_DEL;
  420. main_keymap[SAPP_KEYCODE_RIGHT] = MEG4_KEY_RIGHT;
  421. main_keymap[SAPP_KEYCODE_LEFT] = MEG4_KEY_LEFT;
  422. main_keymap[SAPP_KEYCODE_DOWN] = MEG4_KEY_DOWN;
  423. main_keymap[SAPP_KEYCODE_UP] = MEG4_KEY_UP;
  424. main_keymap[SAPP_KEYCODE_PAGE_UP] = MEG4_KEY_PGUP;
  425. main_keymap[SAPP_KEYCODE_PAGE_DOWN] = MEG4_KEY_PGDN;
  426. main_keymap[SAPP_KEYCODE_HOME] = MEG4_KEY_HOME;
  427. main_keymap[SAPP_KEYCODE_END] = MEG4_KEY_END;
  428. main_keymap[SAPP_KEYCODE_CAPS_LOCK] = MEG4_KEY_CAPSLOCK;
  429. main_keymap[SAPP_KEYCODE_SCROLL_LOCK] = MEG4_KEY_SCRLOCK;
  430. main_keymap[SAPP_KEYCODE_NUM_LOCK] = MEG4_KEY_NUMLOCK;
  431. main_keymap[SAPP_KEYCODE_PRINT_SCREEN] = MEG4_KEY_PRSCR;
  432. main_keymap[SAPP_KEYCODE_PAUSE] = MEG4_KEY_PAUSE;
  433. main_keymap[SAPP_KEYCODE_F1] = MEG4_KEY_F1;
  434. main_keymap[SAPP_KEYCODE_F2] = MEG4_KEY_F2;
  435. main_keymap[SAPP_KEYCODE_F3] = MEG4_KEY_F3;
  436. main_keymap[SAPP_KEYCODE_F4] = MEG4_KEY_F4;
  437. main_keymap[SAPP_KEYCODE_F5] = MEG4_KEY_F5;
  438. main_keymap[SAPP_KEYCODE_F6] = MEG4_KEY_F6;
  439. main_keymap[SAPP_KEYCODE_F7] = MEG4_KEY_F7;
  440. main_keymap[SAPP_KEYCODE_F8] = MEG4_KEY_F8;
  441. main_keymap[SAPP_KEYCODE_F9] = MEG4_KEY_F9;
  442. main_keymap[SAPP_KEYCODE_F10] = MEG4_KEY_F10;
  443. main_keymap[SAPP_KEYCODE_F11] = MEG4_KEY_F11;
  444. main_keymap[SAPP_KEYCODE_F12] = MEG4_KEY_F12;
  445. main_keymap[SAPP_KEYCODE_KP_0] = MEG4_KEY_KP_0;
  446. main_keymap[SAPP_KEYCODE_KP_1] = MEG4_KEY_KP_1;
  447. main_keymap[SAPP_KEYCODE_KP_2] = MEG4_KEY_KP_2;
  448. main_keymap[SAPP_KEYCODE_KP_3] = MEG4_KEY_KP_3;
  449. main_keymap[SAPP_KEYCODE_KP_4] = MEG4_KEY_KP_4;
  450. main_keymap[SAPP_KEYCODE_KP_5] = MEG4_KEY_KP_5;
  451. main_keymap[SAPP_KEYCODE_KP_6] = MEG4_KEY_KP_6;
  452. main_keymap[SAPP_KEYCODE_KP_7] = MEG4_KEY_KP_7;
  453. main_keymap[SAPP_KEYCODE_KP_8] = MEG4_KEY_KP_8;
  454. main_keymap[SAPP_KEYCODE_KP_9] = MEG4_KEY_KP_9;
  455. main_keymap[SAPP_KEYCODE_KP_DECIMAL] = MEG4_KEY_KP_DEC;
  456. main_keymap[SAPP_KEYCODE_KP_DIVIDE] = MEG4_KEY_KP_DIV;
  457. main_keymap[SAPP_KEYCODE_KP_MULTIPLY] = MEG4_KEY_KP_MUL;
  458. main_keymap[SAPP_KEYCODE_KP_SUBTRACT] = MEG4_KEY_KP_SUB;
  459. main_keymap[SAPP_KEYCODE_KP_ADD] = MEG4_KEY_KP_ADD;
  460. main_keymap[SAPP_KEYCODE_KP_ENTER] = MEG4_KEY_KP_ENTER;
  461. main_keymap[SAPP_KEYCODE_KP_EQUAL] = MEG4_KEY_KP_EQUAL;
  462. main_keymap[SAPP_KEYCODE_LEFT_SHIFT] = MEG4_KEY_LSHIFT;
  463. main_keymap[SAPP_KEYCODE_LEFT_CONTROL] = MEG4_KEY_LCTRL;
  464. main_keymap[SAPP_KEYCODE_LEFT_ALT] = MEG4_KEY_LALT;
  465. main_keymap[SAPP_KEYCODE_LEFT_SUPER] = MEG4_KEY_LSUPER;
  466. main_keymap[SAPP_KEYCODE_RIGHT_SHIFT] = MEG4_KEY_RSHIFT;
  467. main_keymap[SAPP_KEYCODE_RIGHT_CONTROL] = MEG4_KEY_RCTRL;
  468. main_keymap[SAPP_KEYCODE_RIGHT_ALT] = MEG4_KEY_RALT;
  469. main_keymap[SAPP_KEYCODE_RIGHT_SUPER] = MEG4_KEY_RSUPER;
  470. main_keymap[SAPP_KEYCODE_MENU] = MEG4_KEY_MENU;
  471. scrbuf = (uint32_t*)malloc(640 * 400 * sizeof(uint32_t));
  472. if(!scrbuf) {
  473. main_log(0, "unable to allocate screen buffer");
  474. return (sapp_desc){ 0 };
  475. }
  476. /* turn on the emulator */
  477. meg4_poweron(lng);
  478. #ifndef NOEDITORS
  479. for(; infile && *infile; infile++) {
  480. if((ptr = main_readfile(*infile, &i))) {
  481. fn = strrchr(*infile, SEP[0]); if(!fn) fn = *infile; else fn++;
  482. meg4_insert(fn, ptr, i);
  483. free(ptr);
  484. }
  485. }
  486. #else
  487. (void)ptr; (void)infile;
  488. #endif
  489. return (sapp_desc) {
  490. .init_cb = init,
  491. .frame_cb = frame,
  492. .event_cb = event,
  493. .cleanup_cb = main_quit,
  494. .width = 0,
  495. .height = 0,
  496. .window_title = "MEG-4",
  497. .enable_clipboard = 1,
  498. .clipboard_size = sizeof(main_clip),
  499. .enable_dragndrop = 1,
  500. .icon.images = { { .width = meg4_icons.w, .height = 64, .pixels = { .ptr = meg4_icons.buf, .size = meg4_icons.w * 64 * 4 } } },
  501. .logger.func = slog
  502. };
  503. }