main.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. /*
  2. * meg4/platform/sdl/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 SDL "platform" for the MEG-4
  21. *
  22. */
  23. #include "meg4.h"
  24. #define SDL_ENABLE_OLD_NAMES
  25. #include <SDL.h>
  26. #ifdef __EMSCRIPTEN__
  27. #include <emscripten.h>
  28. #endif
  29. #include "../../src/stb_image.h" /* for stbi_zlib_decompress */
  30. #include "data.h"
  31. #if SDL_VERSION_ATLEAST(3,0,0)
  32. #include <SDL_main.h>
  33. #define SDL_ENABLE 1
  34. #define SDL_DISABLE 0
  35. #define SDL_WINDOW_FULLSCREEN_DESKTOP 1
  36. #define cdevice jdevice
  37. #define caxis jaxis
  38. #define cbutton button
  39. #define meg4_showcursor() SDL_ShowCursor()
  40. #define meg4_hidecursor() SDL_HideCursor()
  41. SDL_Gamepad *controller[4] = { 0 };
  42. #else
  43. #define meg4_showcursor() SDL_ShowCursor(SDL_ENABLE)
  44. #define meg4_hidecursor() SDL_ShowCursor(SDL_DISABLE)
  45. SDL_GameController *controller[4] = { 0 };
  46. #endif
  47. SDL_Window *window = NULL;
  48. SDL_Renderer *renderer = NULL;
  49. SDL_Texture *screen = NULL;
  50. SDL_Event event;
  51. SDL_AudioSpec have;
  52. int controllerid[4] = { -1, -1, -1, -1 };
  53. int main_draw = 1, main_ret, main_w = 0, main_h = 0, win_w, win_h, win_f = 0, audio = 0, main_alt = 0;
  54. int main_keymap[SDL_NUM_SCANCODES];
  55. void main_delay(int msec);
  56. #include "../common.h"
  57. /**
  58. * Exit emulator
  59. */
  60. void main_quit(void)
  61. {
  62. main_log(1, "quitting... ");
  63. meg4_poweroff();
  64. meg4_showcursor();
  65. if(screen) { SDL_DestroyTexture(screen); screen = NULL; }
  66. /* this crashes sometimes... but only sometimes... We'll exit so should be freed anyway */
  67. /* if(renderer) { SDL_DestroyRenderer(renderer); renderer = NULL; }*/
  68. if(window) {
  69. SDL_DestroyWindow(window);
  70. #ifndef __EMSCRIPTEN__
  71. /* restore original screen resolution */
  72. if(win_f && (main_w != win_w || main_h != win_h)) {
  73. #if SDL_VERSION_ATLEAST(3,0,0)
  74. window = SDL_CreateWindow("MEG-4", main_w, main_h, 1);
  75. #else
  76. window = SDL_CreateWindow("MEG-4", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, main_w, main_h,
  77. SDL_WINDOW_FULLSCREEN);
  78. #endif
  79. if(window) SDL_DestroyWindow(window);
  80. }
  81. #endif
  82. window = NULL;
  83. }
  84. if(audio) {
  85. #if SDL_VERSION_ATLEAST(3,0,0)
  86. SDL_PauseAudioDevice(audio);
  87. #else
  88. SDL_PauseAudioDevice(audio, 1);
  89. #endif
  90. SDL_CloseAudioDevice(audio); audio = 0; }
  91. SDL_Quit();
  92. #ifdef __EMSCRIPTEN__
  93. /* don't let emscripten fool you, this won't cancel the loop. it will quit... but neither of these work with asyncify! */
  94. emscripten_cancel_main_loop();
  95. /*emscripten_force_exit(0);*/
  96. #else
  97. /* DO NOT call exit(), that crashes android... */
  98. /* exit(0); */
  99. #endif
  100. }
  101. /**
  102. * Create window
  103. */
  104. void main_win(int w, int h, int f)
  105. {
  106. int p;
  107. void *data;
  108. char *title =
  109. #ifndef NOEDITORS
  110. "MEG-4";
  111. #else
  112. (char*)binary_game;
  113. #endif
  114. SDL_Surface *srf;
  115. if(screen) { SDL_DestroyTexture(screen); screen = NULL; }
  116. if(renderer) { SDL_DestroyRenderer(renderer); renderer = NULL; }
  117. if(window) { SDL_DestroyWindow(window); window = NULL; }
  118. if(!f) { win_w = w; win_h = h; }
  119. win_f = f;
  120. #if SDL_VERSION_ATLEAST(3,0,0)
  121. window = SDL_CreateWindow(title, f ? main_w : w, f ? main_h : h, f);
  122. #else
  123. window = SDL_CreateWindow(title,
  124. SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
  125. f ? main_w : w, f ? main_h : h,
  126. f ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE);
  127. #endif
  128. if(!window) return;
  129. #if SDL_VERSION_ATLEAST(3,0,0)
  130. renderer = SDL_CreateRenderer(window, NULL, SDL_RENDERER_ACCELERATED);
  131. if(!renderer) {
  132. renderer = SDL_CreateRenderer(window, NULL, SDL_RENDERER_SOFTWARE);
  133. if(!renderer) return;
  134. }
  135. #else
  136. renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
  137. if(!renderer) {
  138. renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
  139. if(!renderer) return;
  140. }
  141. #endif
  142. if(meg4_icons.buf) {
  143. #if SDL_VERSION_ATLEAST(3,0,0)
  144. srf = SDL_CreateSurfaceFrom((Uint32 *)meg4_icons.buf, meg4_icons.w, meg4_icons.h, meg4_icons.w * 4,
  145. SDL_PIXELFORMAT_RGBA8888);
  146. #else
  147. srf = SDL_CreateRGBSurfaceFrom((Uint32 *)meg4_icons.buf, meg4_icons.w, 64, 32, meg4_icons.w * 4,
  148. 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
  149. #endif
  150. if(srf) {
  151. SDL_SetWindowIcon(window, srf);
  152. #if SDL_VERSION_ATLEAST(3,0,0)
  153. SDL_DestroySurface(srf);
  154. #else
  155. SDL_FreeSurface(srf);
  156. #endif
  157. }
  158. }
  159. screen = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, 640, 400);
  160. if(screen) {
  161. SDL_LockTexture(screen, NULL, &data, &p);
  162. memset(data, 0, p * 400);
  163. SDL_UnlockTexture(screen);
  164. }
  165. }
  166. /**
  167. * Toggle fullscreen
  168. */
  169. void main_fullscreen(void)
  170. {
  171. win_f ^= 1;
  172. /* workaround an annoying bug in newer SDL releases */
  173. if(win_f) {
  174. SDL_SetWindowSize(window, main_w, main_h);
  175. SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
  176. } else {
  177. SDL_SetWindowFullscreen(window, 0);
  178. /* we'll loose the previous window size because of this, but if we don't set it, RenderCopy will fail later... */
  179. win_w = main_w; win_h = 320 * main_w / 200;
  180. if(win_h > main_h) { win_h = main_h; win_w = 320 * main_h / 200; }
  181. win_w = (win_w / 320) * 320; win_h = (win_h / 200) * 200;
  182. SDL_SetWindowSize(window, win_w, win_h);
  183. }
  184. }
  185. /**
  186. * Make window focused
  187. */
  188. void main_focus(void)
  189. {
  190. SDL_RaiseWindow(window);
  191. if(win_f) SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
  192. }
  193. /**
  194. * Calculate pointer coordinates
  195. */
  196. void main_pointer(SDL_Rect *dst, int x, int y)
  197. {
  198. meg4_setptr(x < dst->x || !dst->w ? 0 : (x >= dst->x + dst->w ? meg4.screen.w : (x - dst->x) * meg4.screen.w / dst->w),
  199. y < dst->y || !dst->h ? 0 : (y >= dst->y + dst->h ? meg4.screen.h : (y - dst->y) * meg4.screen.h / dst->h));
  200. }
  201. /**
  202. * Main SDL emulator loop
  203. */
  204. /* emscripten does not allow return value... */
  205. void main_loop(void) {
  206. #ifdef __EMSCRIPTEN__
  207. #define exit_loop() main_quit()
  208. #else
  209. #define exit_loop() do{ main_ret = 0; return; }while(0)
  210. #endif
  211. int i, p, w, h;
  212. void *data;
  213. #ifndef NOEDITORS
  214. char *fn;
  215. #endif
  216. #if SDL_VERSION_ATLEAST(3,0,0)
  217. SDL_FRect src, dst;
  218. SDL_Rect idst;
  219. float mx, my;
  220. #else
  221. SDL_Rect src, dst;
  222. #endif
  223. meg4_run();
  224. data = NULL; p = 0;
  225. if(main_draw) {
  226. SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
  227. SDL_RenderClear(renderer);
  228. if(screen) SDL_LockTexture(screen, NULL, &data, &p);
  229. }
  230. meg4_redraw((uint32_t*)data, 640, 400, p);
  231. if(data) SDL_UnlockTexture(screen);
  232. /* workaround a bug in newer SDL, it does not set window size correctly */
  233. if(win_f) { w = main_w; h = main_h; } else { w = win_w; h = win_h; }
  234. src.x = src.y = 0; src.w = meg4.screen.w; src.h = meg4.screen.h;
  235. if(src.w && src.h) {
  236. if(!win_f && nearest) {
  237. #if SDL_VERSION_ATLEAST(2,0,12)
  238. SDL_SetTextureScaleMode(screen,
  239. #if SDL_VERSION_ATLEAST(3,0,0)
  240. SDL_SCALEMODE_NEAREST
  241. #else
  242. SDL_ScaleModeNearest
  243. #endif
  244. );
  245. #endif
  246. i = win_w / 320; p = win_h / 200; if(i > p) i = p;
  247. dst.w = 320 * i; dst.h = 200 * i;
  248. } else {
  249. #if SDL_VERSION_ATLEAST(2,0,12)
  250. SDL_SetTextureScaleMode(screen, nearest || (!(w % 320) && !(w % 200)) ?
  251. #if SDL_VERSION_ATLEAST(3,0,0)
  252. SDL_SCALEMODE_NEAREST : SDL_SCALEMODE_LINEAR
  253. #else
  254. SDL_ScaleModeNearest : SDL_ScaleModeLinear
  255. #endif
  256. );
  257. #endif
  258. dst.w = w; dst.h = src.h * w / src.w;
  259. if(dst.h > h) { dst.h = h; dst.w = src.w * h / src.h; }
  260. }
  261. } else dst.w = dst.h = 0;
  262. dst.x = (w - dst.w) / 2; dst.y = (h - dst.h) / 2;
  263. if(main_draw) {
  264. if(screen) SDL_RenderCopy(renderer, screen, &src, &dst);
  265. SDL_RenderPresent(renderer);
  266. }
  267. #if SDL_VERSION_ATLEAST(3,0,0)
  268. SDL_GetMouseState(&mx, &my);
  269. idst.x = dst.x; idst.y = dst.y; idst.w = dst.w; idst.h = dst.h;
  270. main_pointer(&idst, (int)mx, (int)my);
  271. #else
  272. SDL_GetMouseState(&i, &p);
  273. main_pointer(&dst, i, p);
  274. #endif
  275. event.type = 0; main_ret = 1;
  276. while(SDL_PollEvent(&event)) {
  277. switch(event.type) {
  278. #if SDL_VERSION_ATLEAST(3,0,0)
  279. case SDL_EVENT_QUIT: exit_loop(); break;
  280. case SDL_EVENT_WINDOW_RESIZED: {
  281. #else
  282. case SDL_QUIT: exit_loop(); break;
  283. case SDL_WINDOWEVENT:
  284. switch(event.window.event) {
  285. case SDL_WINDOWEVENT_CLOSE: exit_loop(); break;
  286. case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_SIZE_CHANGED:
  287. #endif
  288. win_w = event.window.data1; win_h = event.window.data2;
  289. break;
  290. }
  291. break;
  292. case SDL_MOUSEBUTTONDOWN:
  293. switch(event.button.button) {
  294. case SDL_BUTTON_LEFT: meg4_setbtn(MEG4_BTN_L); break;
  295. case SDL_BUTTON_MIDDLE: meg4_setbtn(MEG4_BTN_M); break;
  296. case SDL_BUTTON_RIGHT: meg4_setbtn(MEG4_BTN_R); break;
  297. }
  298. break;
  299. case SDL_MOUSEBUTTONUP:
  300. switch(event.button.button) {
  301. case SDL_BUTTON_LEFT: meg4_clrbtn(MEG4_BTN_L); break;
  302. case SDL_BUTTON_MIDDLE: meg4_clrbtn(MEG4_BTN_M); break;
  303. case SDL_BUTTON_RIGHT: meg4_clrbtn(MEG4_BTN_R); break;
  304. }
  305. break;
  306. case SDL_MOUSEWHEEL:
  307. meg4_setscr(event.wheel.y > 0, event.wheel.y < 0, event.wheel.x < 0, event.wheel.x > 0);
  308. break;
  309. case SDL_KEYDOWN:
  310. switch(event.key.keysym.sym) {
  311. case SDLK_LALT: case SDLK_LCTRL: main_alt = 1; break;
  312. case SDLK_RALT: main_alt = 0; break;
  313. case SDLK_RETURN:
  314. if(main_alt) {
  315. main_fullscreen();
  316. return;
  317. }
  318. meg4_pushkey("\n\0\0");
  319. break;
  320. case SDLK_q: if(main_alt) { exit_loop(); } break;
  321. case SDLK_ESCAPE:
  322. #ifndef NOEDITORS
  323. if(main_alt) { exit_loop(); } else meg4_pushkey("\x1b\0\0");
  324. #else
  325. exit_loop();
  326. #endif
  327. break;
  328. /* only for special keys that aren't handled by SDL_TEXTINPUT events */
  329. case SDLK_F1: meg4_pushkey("F1\0"); break;
  330. case SDLK_F2: meg4_pushkey("F2\0"); break;
  331. case SDLK_F3: meg4_pushkey("F3\0"); break;
  332. case SDLK_F4: meg4_pushkey("F4\0"); break;
  333. case SDLK_F5: meg4_pushkey("F5\0"); break;
  334. case SDLK_F6: meg4_pushkey("F6\0"); break;
  335. case SDLK_F7: meg4_pushkey("F7\0"); break;
  336. case SDLK_F8: meg4_pushkey("F8\0"); break;
  337. case SDLK_F9: meg4_pushkey("F9\0"); break;
  338. case SDLK_F10: meg4_pushkey("F10"); break;
  339. case SDLK_F11: main_fullscreen(); break;
  340. case SDLK_F12: meg4_pushkey("F12"); break;
  341. case SDLK_PRINTSCREEN: meg4_pushkey("PSc"); break;
  342. case SDLK_SCROLLLOCK: meg4_pushkey("SLk"); break;
  343. case SDLK_NUMLOCKCLEAR: meg4_pushkey("NLk"); break;
  344. case SDLK_BACKSPACE: meg4_pushkey("\b\0\0"); break;
  345. case SDLK_TAB: meg4_pushkey("\t\0\0"); break;
  346. case SDLK_CAPSLOCK: meg4_pushkey("CLk"); break;
  347. case SDLK_UP: meg4_pushkey("Up\0"); break;
  348. case SDLK_DOWN: meg4_pushkey("Down"); break;
  349. case SDLK_LEFT: meg4_pushkey("Left"); break;
  350. case SDLK_RIGHT: meg4_pushkey("Rght"); break;
  351. case SDLK_HOME: meg4_pushkey("Home"); break;
  352. case SDLK_END: meg4_pushkey("End"); break;
  353. case SDLK_PAGEUP: meg4_pushkey("PgUp"); break;
  354. case SDLK_PAGEDOWN: meg4_pushkey("PgDn"); break;
  355. case SDLK_INSERT: meg4_pushkey("Ins"); break;
  356. case SDLK_DELETE: meg4_pushkey("Del"); break;
  357. }
  358. if(event.key.keysym.scancode < SDL_NUM_SCANCODES) meg4_setkey(main_keymap[event.key.keysym.scancode]);
  359. break;
  360. case SDL_KEYUP:
  361. switch(event.key.keysym.sym) {
  362. case SDLK_LALT: case SDLK_LCTRL: main_alt = 0; break;
  363. }
  364. if(event.key.keysym.scancode < SDL_NUM_SCANCODES) meg4_clrkey(main_keymap[event.key.keysym.scancode]);
  365. break;
  366. case SDL_TEXTINPUT:
  367. if(!main_alt && (uint8_t)event.text.text[0] >= 32)
  368. meg4_pushkey((char*)&event.text.text);
  369. break;
  370. case SDL_CONTROLLERDEVICEADDED:
  371. for(i = 0; i < 4 && controllerid[i] != (int)event.cdevice.which; i++);
  372. if(i >= 4) for(i = 0; i < 4 && controllerid[i] != -1; i++);
  373. if(i < 4) {
  374. if(controller[i]) SDL_GameControllerClose(controller[i]);
  375. controller[i] = SDL_GameControllerOpen(event.cdevice.which);
  376. controllerid[i] = event.cdevice.which;
  377. }
  378. break;
  379. case SDL_CONTROLLERDEVICEREMOVED:
  380. for(i = 0; i < 4 && controllerid[i] != (int)event.cdevice.which; i++);
  381. if(i < 4) {
  382. if(controller[i]) SDL_GameControllerClose(controller[i]);
  383. controller[i] = NULL;
  384. controllerid[i] = -1;
  385. }
  386. break;
  387. case SDL_CONTROLLERBUTTONDOWN:
  388. for(i = 0; i < 4 && controllerid[i] != (int)event.cbutton.which; i++);
  389. if(i < 4) {
  390. switch(event.cbutton.button) {
  391. case SDL_CONTROLLER_BUTTON_DPAD_LEFT: meg4_setpad(i, MEG4_BTN_L); break;
  392. case SDL_CONTROLLER_BUTTON_DPAD_UP: meg4_setpad(i, MEG4_BTN_U); break;
  393. case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: meg4_setpad(i, MEG4_BTN_R); break;
  394. case SDL_CONTROLLER_BUTTON_DPAD_DOWN: meg4_setpad(i, MEG4_BTN_D); break;
  395. case SDL_CONTROLLER_BUTTON_A: meg4_setpad(i, MEG4_BTN_A); break;
  396. case SDL_CONTROLLER_BUTTON_B: meg4_setpad(i, MEG4_BTN_B); break;
  397. case SDL_CONTROLLER_BUTTON_X: meg4_setpad(i, MEG4_BTN_X); break;
  398. case SDL_CONTROLLER_BUTTON_Y: meg4_setpad(i, MEG4_BTN_Y); break;
  399. }
  400. }
  401. break;
  402. case SDL_CONTROLLERBUTTONUP:
  403. for(i = 0; i < 4 && controllerid[i] != (int)event.cbutton.which; i++);
  404. if(i < 4) {
  405. switch(event.cbutton.button) {
  406. case SDL_CONTROLLER_BUTTON_DPAD_LEFT: meg4_clrpad(i, MEG4_BTN_L); break;
  407. case SDL_CONTROLLER_BUTTON_DPAD_UP: meg4_clrpad(i, MEG4_BTN_U); break;
  408. case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: meg4_clrpad(i, MEG4_BTN_R); break;
  409. case SDL_CONTROLLER_BUTTON_DPAD_DOWN: meg4_clrpad(i, MEG4_BTN_D); break;
  410. case SDL_CONTROLLER_BUTTON_A: meg4_clrpad(i, MEG4_BTN_A); break;
  411. case SDL_CONTROLLER_BUTTON_B: meg4_clrpad(i, MEG4_BTN_B); break;
  412. case SDL_CONTROLLER_BUTTON_X: meg4_clrpad(i, MEG4_BTN_X); break;
  413. case SDL_CONTROLLER_BUTTON_Y: meg4_clrpad(i, MEG4_BTN_Y); break;
  414. }
  415. }
  416. break;
  417. case SDL_CONTROLLERAXISMOTION:
  418. for(i = 0; i < 4 && controllerid[i] != (int)event.caxis.which; i++);
  419. if(i < 4) {
  420. if(event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY || event.caxis.axis == SDL_CONTROLLER_AXIS_RIGHTY) {
  421. meg4_clrpad(i, MEG4_BTN_L | MEG4_BTN_R);
  422. if(event.caxis.value < -le16toh(meg4.mmio.padtres)) meg4_setpad(i, MEG4_BTN_L);
  423. if(event.caxis.value > le16toh(meg4.mmio.padtres)) meg4_setpad(i, MEG4_BTN_R);
  424. }
  425. if(event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX || event.caxis.axis == SDL_CONTROLLER_AXIS_RIGHTX) {
  426. meg4_clrpad(i, MEG4_BTN_U | MEG4_BTN_D);
  427. if(event.caxis.value < -le16toh(meg4.mmio.padtres)) meg4_setpad(i, MEG4_BTN_U);
  428. if(event.caxis.value > le16toh(meg4.mmio.padtres)) meg4_setpad(i, MEG4_BTN_D);
  429. }
  430. }
  431. break;
  432. /* normally finger events are automatically converted to mouse events, but in case SDL is configured not to do so */
  433. #if FINGEREVENTS
  434. case SDL_FINGERUP: case SDL_FINGERDOWN: case SDL_FINGERMOTION:
  435. SDL_GetWindowPosition(window, &i, &p);
  436. main_pointer(&dst, event.tfinger.x * main_w - i, event.tfinger.y * main_h - p);
  437. switch(event.tfinger.fingerId) {
  438. case 0: i = MEG4_BTN_L; break;
  439. case 1: i = MEG4_BTN_M; break;
  440. case 2: i = MEG4_BTN_R; break;
  441. default: i = -1; break;
  442. }
  443. if(i != -1) {
  444. if(event.type == SDL_FINGERUP)
  445. meg4_clrbtn(i);
  446. else
  447. meg4_setbtn(i);
  448. }
  449. break;
  450. #endif
  451. #ifndef NOEDITORS
  452. case SDL_DROPFILE:
  453. if(event.drop.file) {
  454. if((data = main_readfile(!memcmp(event.drop.file, "file://", 7) ? event.drop.file + 7 : event.drop.file, &i))) {
  455. fn = strrchr(event.drop.file, SEP[0]); if(!fn) fn = event.drop.file; else fn++;
  456. meg4_insert(fn, (uint8_t*)data, i);
  457. free(data);
  458. }
  459. SDL_free(event.drop.file);
  460. }
  461. break;
  462. #endif
  463. }
  464. }
  465. }
  466. /**
  467. * Workaround a stupid iOS and Android bug
  468. */
  469. int main_stupidios(void *data, SDL_Event *event)
  470. {
  471. (void)data;
  472. switch(event->type) {
  473. case SDL_APP_WILLENTERBACKGROUND: main_draw = 0; break;
  474. case SDL_APP_WILLENTERFOREGROUND: main_draw = 1; break;
  475. }
  476. return 1;
  477. }
  478. /**
  479. * Get text from clipboard (must be freed by caller)
  480. */
  481. char *main_getclipboard(void)
  482. {
  483. return SDL_GetClipboardText();
  484. }
  485. /**
  486. * Set text to clipboard
  487. */
  488. void main_setclipboard(char *str)
  489. {
  490. SDL_SetClipboardText((const char*)str);
  491. }
  492. /**
  493. * Show on-screen keyboard
  494. */
  495. void main_osk_show(void)
  496. {
  497. #if defined(__ANDROID__) || defined(__IOS__)
  498. SDL_StartTextInput();
  499. #endif
  500. }
  501. /**
  502. * Hide on-screen keyboard
  503. */
  504. void main_osk_hide(void)
  505. {
  506. #if defined(__ANDROID__) || defined(__IOS__)
  507. SDL_StopTextInput();
  508. #endif
  509. }
  510. /**
  511. * SDL audio callback
  512. */
  513. void main_audio(void *ctx, Uint8 *buf, int len)
  514. {
  515. (void)ctx;
  516. meg4_audiofeed((float*)buf, len >> 2);
  517. }
  518. /**
  519. * Delay
  520. */
  521. void main_delay(int msec)
  522. {
  523. SDL_Delay(msec);
  524. }
  525. /**
  526. * Print program version and copyright
  527. */
  528. void main_hdr(void)
  529. {
  530. printf("\r\nMEG-4 v%s (SDL%d, build %u) by bzt Copyright (C) 2023 GPLv3+\r\n\r\n", meg4ver, SDL_MAJOR_VERSION, BUILD);
  531. }
  532. /**
  533. * The real main procedure
  534. */
  535. int main(int argc, char **argv)
  536. {
  537. int i, j, w;
  538. char **infile = NULL, *ptr2;
  539. uint8_t *ptr;
  540. SDL_RWops *ops = NULL;
  541. SDL_AudioSpec want;
  542. SDL_version ver;
  543. #ifdef __EMSCRIPTEN__
  544. char detlng[3] = { 0 }, *lng = detlng;
  545. (void)argc; (void)argv;
  546. i = EM_ASM_INT({
  547. var ln=document.location.href.split('?')[1];if(ln==undefined)ln=navigator.language.substr(0,2);
  548. return ln.charCodeAt(1) * 256 + ln.charCodeAt(0);
  549. });
  550. detlng[0] = i & 0xff; detlng[1] = (i >> 8) & 0xff; detlng[2] = 0;
  551. #else
  552. #if !defined(NOEDITORS) && !defined(__EMSCRIPTEN__)
  553. char *fn;
  554. #endif
  555. int32_t tickdiff;
  556. uint32_t ticks;
  557. #if SDL_VERSION_ATLEAST(3,0,0)
  558. const SDL_DisplayMode *dm;
  559. #else
  560. SDL_DisplayMode dm;
  561. #endif
  562. #ifdef __WIN32__
  563. SDL_SysWMinfo wmInfo = { 0 };
  564. char *lng = main_lng;
  565. #else
  566. char *lng = getenv("LANG");
  567. #endif
  568. main_parsecommandline(argc, argv, &lng, &infile);
  569. #endif
  570. #ifndef NOEDITORS
  571. main_hdr();
  572. for(i = 0; i < 3; i++) printf(" %s\r\n", copyright[i]);
  573. printf("\r\n");
  574. #else
  575. for(i = 0; i < 128; i++) binary_game[i] ^= i + 7;
  576. #endif
  577. fflush(stdout);
  578. SDL_GetVersion(&ver);
  579. sprintf(meg4plat, "SDL %u.%u.%u", ver.major, ver.minor, ver.patch);
  580. /* set up keymap */
  581. memset(main_keymap, 0, sizeof(main_keymap));
  582. main_keymap[SDL_SCANCODE_A] = MEG4_KEY_A;
  583. main_keymap[SDL_SCANCODE_B] = MEG4_KEY_B;
  584. main_keymap[SDL_SCANCODE_C] = MEG4_KEY_C;
  585. main_keymap[SDL_SCANCODE_D] = MEG4_KEY_D;
  586. main_keymap[SDL_SCANCODE_E] = MEG4_KEY_E;
  587. main_keymap[SDL_SCANCODE_F] = MEG4_KEY_F;
  588. main_keymap[SDL_SCANCODE_G] = MEG4_KEY_G;
  589. main_keymap[SDL_SCANCODE_H] = MEG4_KEY_H;
  590. main_keymap[SDL_SCANCODE_I] = MEG4_KEY_I;
  591. main_keymap[SDL_SCANCODE_J] = MEG4_KEY_J;
  592. main_keymap[SDL_SCANCODE_K] = MEG4_KEY_K;
  593. main_keymap[SDL_SCANCODE_L] = MEG4_KEY_L;
  594. main_keymap[SDL_SCANCODE_M] = MEG4_KEY_M;
  595. main_keymap[SDL_SCANCODE_N] = MEG4_KEY_N;
  596. main_keymap[SDL_SCANCODE_O] = MEG4_KEY_O;
  597. main_keymap[SDL_SCANCODE_P] = MEG4_KEY_P;
  598. main_keymap[SDL_SCANCODE_Q] = MEG4_KEY_Q;
  599. main_keymap[SDL_SCANCODE_R] = MEG4_KEY_R;
  600. main_keymap[SDL_SCANCODE_S] = MEG4_KEY_S;
  601. main_keymap[SDL_SCANCODE_T] = MEG4_KEY_T;
  602. main_keymap[SDL_SCANCODE_U] = MEG4_KEY_U;
  603. main_keymap[SDL_SCANCODE_V] = MEG4_KEY_V;
  604. main_keymap[SDL_SCANCODE_W] = MEG4_KEY_W;
  605. main_keymap[SDL_SCANCODE_X] = MEG4_KEY_X;
  606. main_keymap[SDL_SCANCODE_Y] = MEG4_KEY_Y;
  607. main_keymap[SDL_SCANCODE_Z] = MEG4_KEY_Z;
  608. main_keymap[SDL_SCANCODE_1] = MEG4_KEY_1;
  609. main_keymap[SDL_SCANCODE_2] = MEG4_KEY_2;
  610. main_keymap[SDL_SCANCODE_3] = MEG4_KEY_3;
  611. main_keymap[SDL_SCANCODE_4] = MEG4_KEY_4;
  612. main_keymap[SDL_SCANCODE_5] = MEG4_KEY_5;
  613. main_keymap[SDL_SCANCODE_6] = MEG4_KEY_6;
  614. main_keymap[SDL_SCANCODE_7] = MEG4_KEY_7;
  615. main_keymap[SDL_SCANCODE_8] = MEG4_KEY_8;
  616. main_keymap[SDL_SCANCODE_9] = MEG4_KEY_9;
  617. main_keymap[SDL_SCANCODE_0] = MEG4_KEY_0;
  618. main_keymap[SDL_SCANCODE_RETURN] = MEG4_KEY_ENTER;
  619. main_keymap[SDL_SCANCODE_BACKSPACE] = MEG4_KEY_BACKSPACE;
  620. main_keymap[SDL_SCANCODE_TAB] = MEG4_KEY_TAB;
  621. main_keymap[SDL_SCANCODE_SPACE] = MEG4_KEY_SPACE;
  622. main_keymap[SDL_SCANCODE_MINUS] = MEG4_KEY_MINUS;
  623. main_keymap[SDL_SCANCODE_EQUALS] = MEG4_KEY_EQUAL;
  624. main_keymap[SDL_SCANCODE_LEFTBRACKET] = MEG4_KEY_LBRACKET;
  625. main_keymap[SDL_SCANCODE_RIGHTBRACKET] = MEG4_KEY_RBRACKET;
  626. main_keymap[SDL_SCANCODE_BACKSLASH] = MEG4_KEY_BACKSLASH;
  627. main_keymap[SDL_SCANCODE_NONUSHASH] = MEG4_KEY_BACKSLASH;
  628. main_keymap[SDL_SCANCODE_SEMICOLON] = MEG4_KEY_SEMICOLON;
  629. main_keymap[SDL_SCANCODE_APOSTROPHE] = MEG4_KEY_APOSTROPHE;
  630. main_keymap[SDL_SCANCODE_GRAVE] = MEG4_KEY_BACKQUOTE;
  631. main_keymap[SDL_SCANCODE_COMMA] = MEG4_KEY_COMMA;
  632. main_keymap[SDL_SCANCODE_PERIOD] = MEG4_KEY_PERIOD;
  633. main_keymap[SDL_SCANCODE_SLASH] = MEG4_KEY_SLASH;
  634. main_keymap[SDL_SCANCODE_CAPSLOCK] = MEG4_KEY_CAPSLOCK;
  635. main_keymap[SDL_SCANCODE_F1] = MEG4_KEY_F1;
  636. main_keymap[SDL_SCANCODE_F2] = MEG4_KEY_F2;
  637. main_keymap[SDL_SCANCODE_F3] = MEG4_KEY_F3;
  638. main_keymap[SDL_SCANCODE_F4] = MEG4_KEY_F4;
  639. main_keymap[SDL_SCANCODE_F5] = MEG4_KEY_F5;
  640. main_keymap[SDL_SCANCODE_F6] = MEG4_KEY_F6;
  641. main_keymap[SDL_SCANCODE_F7] = MEG4_KEY_F7;
  642. main_keymap[SDL_SCANCODE_F8] = MEG4_KEY_F8;
  643. main_keymap[SDL_SCANCODE_F9] = MEG4_KEY_F9;
  644. main_keymap[SDL_SCANCODE_F10] = MEG4_KEY_F10;
  645. main_keymap[SDL_SCANCODE_F11] = MEG4_KEY_F11;
  646. main_keymap[SDL_SCANCODE_F12] = MEG4_KEY_F12;
  647. main_keymap[SDL_SCANCODE_PRINTSCREEN] = MEG4_KEY_PRSCR;
  648. main_keymap[SDL_SCANCODE_SCROLLLOCK] = MEG4_KEY_SCRLOCK;
  649. main_keymap[SDL_SCANCODE_PAUSE] = MEG4_KEY_PAUSE;
  650. main_keymap[SDL_SCANCODE_INSERT] = MEG4_KEY_INS;
  651. main_keymap[SDL_SCANCODE_HOME] = MEG4_KEY_HOME;
  652. main_keymap[SDL_SCANCODE_PAGEUP] = MEG4_KEY_PGUP;
  653. main_keymap[SDL_SCANCODE_DELETE] = MEG4_KEY_DEL;
  654. main_keymap[SDL_SCANCODE_END] = MEG4_KEY_END;
  655. main_keymap[SDL_SCANCODE_PAGEDOWN] = MEG4_KEY_PGDN;
  656. main_keymap[SDL_SCANCODE_RIGHT] = MEG4_KEY_RIGHT;
  657. main_keymap[SDL_SCANCODE_LEFT] = MEG4_KEY_LEFT;
  658. main_keymap[SDL_SCANCODE_DOWN] = MEG4_KEY_DOWN;
  659. main_keymap[SDL_SCANCODE_UP] = MEG4_KEY_UP;
  660. main_keymap[SDL_SCANCODE_NUMLOCKCLEAR] = MEG4_KEY_NUMLOCK;
  661. main_keymap[SDL_SCANCODE_KP_DIVIDE] = MEG4_KEY_KP_DIV;
  662. main_keymap[SDL_SCANCODE_KP_MULTIPLY] = MEG4_KEY_KP_MUL;
  663. main_keymap[SDL_SCANCODE_KP_MINUS] = MEG4_KEY_KP_SUB;
  664. main_keymap[SDL_SCANCODE_KP_PLUS] = MEG4_KEY_KP_ADD;
  665. main_keymap[SDL_SCANCODE_KP_ENTER] = MEG4_KEY_KP_ENTER;
  666. main_keymap[SDL_SCANCODE_KP_1] = MEG4_KEY_KP_1;
  667. main_keymap[SDL_SCANCODE_KP_2] = MEG4_KEY_KP_2;
  668. main_keymap[SDL_SCANCODE_KP_3] = MEG4_KEY_KP_3;
  669. main_keymap[SDL_SCANCODE_KP_4] = MEG4_KEY_KP_4;
  670. main_keymap[SDL_SCANCODE_KP_5] = MEG4_KEY_KP_5;
  671. main_keymap[SDL_SCANCODE_KP_6] = MEG4_KEY_KP_6;
  672. main_keymap[SDL_SCANCODE_KP_7] = MEG4_KEY_KP_7;
  673. main_keymap[SDL_SCANCODE_KP_8] = MEG4_KEY_KP_8;
  674. main_keymap[SDL_SCANCODE_KP_9] = MEG4_KEY_KP_9;
  675. main_keymap[SDL_SCANCODE_KP_0] = MEG4_KEY_KP_0;
  676. main_keymap[SDL_SCANCODE_KP_PERIOD] = MEG4_KEY_KP_DEC;
  677. main_keymap[SDL_SCANCODE_DECIMALSEPARATOR] = MEG4_KEY_KP_DEC;
  678. main_keymap[SDL_SCANCODE_NONUSBACKSLASH] = MEG4_KEY_LESS;
  679. main_keymap[SDL_SCANCODE_APPLICATION] = MEG4_KEY_APP;
  680. main_keymap[SDL_SCANCODE_POWER] = MEG4_KEY_POWER;
  681. main_keymap[SDL_SCANCODE_KP_EQUALS] = MEG4_KEY_EQUAL;
  682. main_keymap[SDL_SCANCODE_EXECUTE] = MEG4_KEY_EXEC;
  683. main_keymap[SDL_SCANCODE_HELP] = MEG4_KEY_HELP;
  684. main_keymap[SDL_SCANCODE_MENU] = MEG4_KEY_MENU;
  685. main_keymap[SDL_SCANCODE_SELECT] = MEG4_KEY_SELECT;
  686. main_keymap[SDL_SCANCODE_STOP] = MEG4_KEY_STOP;
  687. main_keymap[SDL_SCANCODE_AGAIN] = MEG4_KEY_AGAIN;
  688. main_keymap[SDL_SCANCODE_UNDO] = MEG4_KEY_UNDO;
  689. main_keymap[SDL_SCANCODE_CUT] = MEG4_KEY_CUT;
  690. main_keymap[SDL_SCANCODE_COPY] = MEG4_KEY_COPY;
  691. main_keymap[SDL_SCANCODE_PASTE] = MEG4_KEY_PASTE;
  692. main_keymap[SDL_SCANCODE_FIND] = MEG4_KEY_FIND;
  693. main_keymap[SDL_SCANCODE_MUTE] = MEG4_KEY_MUTE;
  694. main_keymap[SDL_SCANCODE_VOLUMEUP] = MEG4_KEY_VOLUP;
  695. main_keymap[SDL_SCANCODE_VOLUMEDOWN] = MEG4_KEY_VOLDN;
  696. main_keymap[SDL_SCANCODE_INTERNATIONAL1] = MEG4_KEY_INT1;
  697. main_keymap[SDL_SCANCODE_INTERNATIONAL2] = MEG4_KEY_INT2;
  698. main_keymap[SDL_SCANCODE_INTERNATIONAL3] = MEG4_KEY_INT3;
  699. main_keymap[SDL_SCANCODE_INTERNATIONAL4] = MEG4_KEY_INT4;
  700. main_keymap[SDL_SCANCODE_INTERNATIONAL5] = MEG4_KEY_INT5;
  701. main_keymap[SDL_SCANCODE_INTERNATIONAL6] = MEG4_KEY_INT6;
  702. main_keymap[SDL_SCANCODE_INTERNATIONAL7] = MEG4_KEY_INT7;
  703. main_keymap[SDL_SCANCODE_INTERNATIONAL8] = MEG4_KEY_INT8;
  704. main_keymap[SDL_SCANCODE_LANG1] = MEG4_KEY_LNG1;
  705. main_keymap[SDL_SCANCODE_LANG2] = MEG4_KEY_LNG2;
  706. main_keymap[SDL_SCANCODE_LANG3] = MEG4_KEY_LNG3;
  707. main_keymap[SDL_SCANCODE_LANG4] = MEG4_KEY_LNG4;
  708. main_keymap[SDL_SCANCODE_LANG5] = MEG4_KEY_LNG5;
  709. main_keymap[SDL_SCANCODE_LANG6] = MEG4_KEY_LNG6;
  710. main_keymap[SDL_SCANCODE_LANG7] = MEG4_KEY_LNG7;
  711. main_keymap[SDL_SCANCODE_LANG8] = MEG4_KEY_LNG8;
  712. main_keymap[SDL_SCANCODE_LCTRL] = MEG4_KEY_LCTRL;
  713. main_keymap[SDL_SCANCODE_LSHIFT] = MEG4_KEY_LSHIFT;
  714. main_keymap[SDL_SCANCODE_LALT] = MEG4_KEY_LALT;
  715. main_keymap[SDL_SCANCODE_LGUI] = MEG4_KEY_LSUPER;
  716. main_keymap[SDL_SCANCODE_RCTRL] = MEG4_KEY_RCTRL;
  717. main_keymap[SDL_SCANCODE_RSHIFT] = MEG4_KEY_RSHIFT;
  718. main_keymap[SDL_SCANCODE_RALT] = MEG4_KEY_RALT;
  719. main_keymap[SDL_SCANCODE_RGUI] = MEG4_KEY_RSUPER;
  720. /* initialize screen and other SDL stuff */
  721. if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_TIMER|SDL_INIT_EVENTS|SDL_INIT_GAMECONTROLLER)) {
  722. main_log(0, "unable to initialize SDL");
  723. return 1;
  724. }
  725. /* initialize audio */
  726. memset(&want, 0, sizeof(want));
  727. memset(&have, 0, sizeof(have));
  728. want.freq = 44100;
  729. #if SDL_VERSION_ATLEAST(3,0,0)
  730. want.format = SDL_AUDIO_F32;
  731. #else
  732. want.format = AUDIO_F32;
  733. #endif
  734. want.channels = 1;
  735. want.samples = 4096;
  736. want.callback = main_audio;
  737. audio = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
  738. if(audio && (have.freq != 44100 || have.channels != 1 || have.format !=
  739. #if SDL_VERSION_ATLEAST(3,0,0)
  740. SDL_AUDIO_F32
  741. #else
  742. AUDIO_F32
  743. #endif
  744. )) {
  745. SDL_CloseAudioDevice(audio); audio = 0;
  746. }
  747. if(verbose && audio) main_log(1, "audio opened %uHz, %u bits", have.freq, 32);
  748. /* turn on the emulator */
  749. meg4_poweron(lng);
  750. #if !defined(NOEDITORS) && !defined(__EMSCRIPTEN__)
  751. for(; infile && *infile; infile++) {
  752. if((ptr = main_readfile(*infile, &i))) {
  753. fn = strrchr(*infile, SEP[0]); if(!fn) fn = *infile; else fn++;
  754. meg4_insert(fn, ptr, i);
  755. free(ptr);
  756. }
  757. }
  758. #else
  759. (void)infile;
  760. #endif
  761. #ifdef __EMSCRIPTEN__
  762. win_w = main_w = EM_ASM_INT({ return Module.canvas.width; });
  763. win_h = main_h = EM_ASM_INT({ return Module.canvas.height; });
  764. main_win(main_w, main_h, 0);
  765. #else
  766. #if SDL_VERSION_ATLEAST(3,0,0)
  767. dm = SDL_GetDesktopDisplayMode(SDL_GetPrimaryDisplay());
  768. main_w = dm->w; main_h = dm->h;
  769. #else
  770. SDL_GetDesktopDisplayMode(0, &dm);
  771. /*dm.w = 640; dm.h = 400;*/
  772. main_w = dm.w; main_h = dm.h;
  773. #endif
  774. #if DEBUG
  775. main_win(640, 400, 0);
  776. #else
  777. i = main_w / 320; j = main_h / 200; if(i > j) i = j;
  778. win_w = 320 * i; win_h = 200 * i;
  779. main_win(win_w/*main_w*/, win_h/*main_h*/, 0/*1*/);
  780. if(!windowed) main_fullscreen();
  781. #endif
  782. #endif
  783. if(!window || !renderer) {
  784. meg4_poweroff();
  785. SDL_Quit();
  786. main_log(0, "unable to get SDL window");
  787. return 1;
  788. }
  789. #ifdef __WIN32__
  790. SDL_VERSION(&wmInfo.version);
  791. SDL_GetWindowWMInfo(window, &wmInfo);
  792. hwnd = wmInfo.info.win.window;
  793. #endif
  794. /* uncompress built-in gamecontrollerdb */
  795. ptr = (uint8_t*)binary_gamecontrollerdb + 3;
  796. i = *ptr++; ptr += 6; if(i & 4) { w = *ptr++; w += (*ptr++ << 8); ptr += w; } if(i & 8) { while(*ptr++ != 0); }
  797. if(i & 16) { while(*ptr++ != 0); } j = sizeof(binary_gamecontrollerdb) - (size_t)(ptr - binary_gamecontrollerdb);
  798. w = 0; ptr2 = (char*)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)ptr, j, 4096, (int*)&w, 0);
  799. if(ptr2) {
  800. ops = SDL_RWFromConstMem(ptr2, w);
  801. SDL_GameControllerAddMappingsFromRW(ops, 0);
  802. #if SDL_VERSION_ATLEAST(3,0,0)
  803. SDL_DestroyRW(ops);
  804. #else
  805. SDL_FreeRW(ops);
  806. #endif
  807. free(ptr2);
  808. }
  809. #if SDL_VERSION_ATLEAST(3,0,0)
  810. SDL_SetGamepadEventsEnabled(SDL_ENABLE);
  811. #else
  812. SDL_GameControllerEventState(SDL_ENABLE);
  813. #endif
  814. meg4_hidecursor();
  815. if(audio) {
  816. #if SDL_VERSION_ATLEAST(3,0,0)
  817. SDL_PlayAudioDevice(audio);
  818. #else
  819. SDL_PauseAudioDevice(audio, 0);
  820. #endif
  821. }
  822. #if !defined(__ANDROID__) && !defined(__IOS__)
  823. SDL_StartTextInput();
  824. #endif
  825. /* execute the main emulator loop */
  826. #ifdef __EMSCRIPTEN__
  827. emscripten_set_main_loop(main_loop, 60, 1);
  828. /* this never reached! cancel_main_loop does not cancel the loop, it actually quits the app! */
  829. #else
  830. SDL_AddEventWatch(main_stupidios, NULL);
  831. while(1) {
  832. ticks = SDL_GetTicks();
  833. /* emscripten does not allow return value... so we have to use a global */
  834. main_loop();
  835. if(!main_ret) break;
  836. tickdiff = (1000/60) - (SDL_GetTicks() - ticks);
  837. if(tickdiff > 0 && tickdiff < 1000) {
  838. if(verbose == 2) { printf("meg4: free time %d msec \r",tickdiff); fflush(stdout); }
  839. SDL_Delay(tickdiff);
  840. }
  841. }
  842. main_quit();
  843. #endif
  844. return 0;
  845. }