main.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. /*
  2. * meg4/platform/glfw_pa/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 GLFW + OpenAL "platform" for the MEG-4
  21. * NOTE: use only GLES2 so this could be compiled for mobiles too
  22. * there's also a `NOGLES=1 make clean all` fallback for old-school OpenGL
  23. *
  24. */
  25. #define _POSIX_C_SOURCE 199309L /* needed for timespec and nanosleep() */
  26. #include <time.h>
  27. #include "meg4.h"
  28. #include <GLFW/glfw3.h>
  29. #include <portaudio.h>
  30. GLFWwindow *window = NULL;
  31. GLFWmonitor *monitor = NULL;
  32. GLuint screen;
  33. uint32_t *scrbuf = NULL;
  34. #ifndef NOGLES
  35. #include <GLES2/gl2.h>
  36. GLuint program;
  37. GLint mloc, ploc, tloc, sloc;
  38. #endif
  39. int controllerid[4] = { -1, -1, -1, -1 };
  40. PaStream *pa = NULL;
  41. int main_w = 0, main_h = 0, win_w, win_h, win_f = 0, audio = 0, main_alt = 0, main_keymap[512];
  42. void main_pointer(GLFWwindow *window, double xpos, double ypos);
  43. void main_delay(int msec);
  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. #ifndef NOGLES
  55. if(program) { glDeleteProgram(program); program = 0; }
  56. #endif
  57. if(scrbuf) { free(scrbuf); scrbuf = NULL; }
  58. if(screen != -1U) { glDeleteTextures(1, &screen); screen = -1U; }
  59. if(window) {
  60. glfwDestroyWindow(window);
  61. /* restore original screen resolution */
  62. if(win_f && (main_w != win_w || main_h != win_h)) {
  63. window = glfwCreateWindow(main_w, main_h, "MEG-4", monitor, NULL);
  64. if(window) glfwDestroyWindow(window);
  65. }
  66. window = NULL;
  67. }
  68. glfwTerminate();
  69. if(audio) { if(pa) { Pa_CloseStream(pa); pa = NULL; } Pa_Terminate(); audio = 0; }
  70. exit(0);
  71. }
  72. /**
  73. * Create window
  74. */
  75. void main_win(int w, int h, int f)
  76. {
  77. GLFWimage icon;
  78. if(window) { glfwDestroyWindow(window); window = NULL; }
  79. if(!f) { win_w = w; win_h = h; }
  80. win_f = f;
  81. window = glfwCreateWindow(f ? main_w : w, f ? main_h : h, "MEG-4", f ? monitor : NULL, NULL);
  82. if(!window) return;
  83. if(!f) glfwSetWindowPos(window, (main_w - w) / 2, (main_h - h) / 2);
  84. glfwMakeContextCurrent(window);
  85. if(meg4_icons.buf) {
  86. icon.width = meg4_icons.w; icon.height = 64; icon.pixels = (uint8_t*)meg4_icons.buf;
  87. glfwSetWindowIcon(window, 1, &icon);
  88. }
  89. glfwShowWindow(window);
  90. }
  91. /**
  92. * Toggle fullscreen
  93. */
  94. void main_fullscreen(void)
  95. {
  96. win_f ^= 1;
  97. if(!win_f)
  98. glfwSetWindowMonitor(window, NULL, (main_w - win_w) / 2, (main_h - win_h) / 2, win_w, win_h, 0);
  99. else
  100. glfwSetWindowMonitor(window, monitor, 0, 0, main_w, main_h, 0);
  101. }
  102. /**
  103. * Make window focused
  104. */
  105. void main_focus(void)
  106. {
  107. glfwFocusWindow(window);
  108. if(win_f) glfwSetWindowMonitor(window, monitor, 0, 0, main_w, main_h, 0);
  109. }
  110. /**
  111. * The glfw error callback
  112. */
  113. void main_error(int error, const char *msg)
  114. {
  115. main_log(0, "glfw error %d: %s", error, msg);
  116. main_quit();
  117. }
  118. /**
  119. * Process a keyboard event callback
  120. */
  121. void main_key(GLFWwindow *window, int key, int scancode, int action, int mods)
  122. {
  123. (void)window; (void)mods;
  124. if(key == GLFW_KEY_UNKNOWN && scancode >= 119 && scancode <= 151) key = scancode;
  125. if(action == GLFW_PRESS) {
  126. if(key == GLFW_KEY_LEFT_CONTROL || key == GLFW_KEY_LEFT_ALT) main_alt = 1;
  127. if(key == GLFW_KEY_RIGHT_ALT) main_alt = 0;
  128. if(main_alt)
  129. switch(key) {
  130. case GLFW_KEY_ENTER: main_fullscreen(); return;
  131. case GLFW_KEY_Q: case GLFW_KEY_ESCAPE: glfwSetWindowShouldClose(window, GLFW_TRUE); return;
  132. }
  133. /* only for special keys that aren't handled by main_char() */
  134. switch(key) {
  135. case GLFW_KEY_ESCAPE: meg4_pushkey("\x1b\0\0"); break;
  136. case GLFW_KEY_F1: meg4_pushkey("F1\0"); break;
  137. case GLFW_KEY_F2: meg4_pushkey("F2\0"); break;
  138. case GLFW_KEY_F3: meg4_pushkey("F3\0"); break;
  139. case GLFW_KEY_F4: meg4_pushkey("F4\0"); break;
  140. case GLFW_KEY_F5: meg4_pushkey("F5\0"); break;
  141. case GLFW_KEY_F6: meg4_pushkey("F6\0"); break;
  142. case GLFW_KEY_F7: meg4_pushkey("F7\0"); break;
  143. case GLFW_KEY_F8: meg4_pushkey("F8\0"); break;
  144. case GLFW_KEY_F9: meg4_pushkey("F9\0"); break;
  145. case GLFW_KEY_F10: meg4_pushkey("F10"); break;
  146. case GLFW_KEY_F11: main_fullscreen(); break;
  147. case GLFW_KEY_F12: meg4_pushkey("F12"); break;
  148. case GLFW_KEY_PRINT_SCREEN: meg4_pushkey("PSc"); break;
  149. case GLFW_KEY_SCROLL_LOCK: meg4_pushkey("SLk"); break;
  150. case GLFW_KEY_NUM_LOCK: meg4_pushkey("NLk"); break;
  151. case GLFW_KEY_BACKSPACE: meg4_pushkey("\b\0\0"); break;
  152. case GLFW_KEY_TAB: meg4_pushkey("\t\0\0"); break;
  153. case GLFW_KEY_ENTER: meg4_pushkey("\n\0\0"); break;
  154. case GLFW_KEY_CAPS_LOCK: meg4_pushkey("CLk"); break;
  155. case GLFW_KEY_UP: meg4_pushkey("Up\0"); break;
  156. case GLFW_KEY_DOWN: meg4_pushkey("Down"); break;
  157. case GLFW_KEY_LEFT: meg4_pushkey("Left"); break;
  158. case GLFW_KEY_RIGHT: meg4_pushkey("Rght"); break;
  159. case GLFW_KEY_HOME: meg4_pushkey("Home"); break;
  160. case GLFW_KEY_END: meg4_pushkey("End"); break;
  161. case GLFW_KEY_PAGE_UP: meg4_pushkey("PgUp"); break;
  162. case GLFW_KEY_PAGE_DOWN: meg4_pushkey("PgDn"); break;
  163. case GLFW_KEY_INSERT: meg4_pushkey("Ins"); break;
  164. case GLFW_KEY_DELETE: meg4_pushkey("Del"); break;
  165. }
  166. if(key >= 0 && key < (int)(sizeof(main_keymap)/sizeof(main_keymap[0]))) meg4_setkey(main_keymap[key]);
  167. } else {
  168. if(key == GLFW_KEY_LEFT_CONTROL || key == GLFW_KEY_LEFT_ALT) main_alt = 0;
  169. if(key >= 0 && key < (int)(sizeof(main_keymap)/sizeof(main_keymap[0]))) meg4_clrkey(main_keymap[key]);
  170. }
  171. }
  172. /**
  173. * Text input event callback
  174. */
  175. void main_char(GLFWwindow *window, unsigned int unicode)
  176. {
  177. char s[5] = { 0 };
  178. (void)window;
  179. if(main_alt || unicode < 32) return;
  180. if(unicode<0x80) { s[0]=unicode; } else
  181. if(unicode<0x800) { s[0]=((unicode>>6)&0x1F)|0xC0; s[1]=(unicode&0x3F)|0x80; } else
  182. if(unicode<0x10000) { s[0]=((unicode>>12)&0x0F)|0xE0; s[1]=((unicode>>6)&0x3F)|0x80; s[2]=(unicode&0x3F)|0x80; }
  183. else { s[0]=((unicode>>18)&0x07)|0xF0; s[1]=((unicode>>12)&0x3F)|0x80; s[2]=((unicode>>6)&0x3F)|0x80; s[3]=(unicode&0x3F)|0x80; }
  184. meg4_pushkey(s);
  185. }
  186. /**
  187. * Mouse button event callback
  188. */
  189. void main_mouse(GLFWwindow *window, int button, int action, int mods) {
  190. uint16_t m = 0;
  191. (void)window; (void)mods;
  192. switch(button) {
  193. case GLFW_MOUSE_BUTTON_LEFT: m = MEG4_BTN_L; break;
  194. case GLFW_MOUSE_BUTTON_MIDDLE: m = MEG4_BTN_M; break;
  195. case GLFW_MOUSE_BUTTON_RIGHT: m = MEG4_BTN_R; break;
  196. }
  197. if(action == GLFW_PRESS)
  198. meg4_setbtn(m);
  199. else
  200. meg4_clrbtn(m);
  201. }
  202. /**
  203. * Mouse movement event callback
  204. */
  205. void main_pointer(GLFWwindow *window, double xpos, double ypos)
  206. {
  207. int x, y, w, h, ww, wh, xp = xpos, yp = ypos;
  208. if(!meg4.screen.w || !meg4.screen.h) return;
  209. glfwGetFramebufferSize(window, &ww, &wh);
  210. w = ww; h = (int)meg4.screen.h * ww / (int)meg4.screen.w;
  211. if(h > wh) { h = wh; w = (int)meg4.screen.w * wh / (int)meg4.screen.h; }
  212. x = (ww - w) >> 1; y = (wh - h) >> 1;
  213. meg4_setptr(xp < x || !w ? 0 : (xp >= x + w ? meg4.screen.w : (xp - x) * meg4.screen.w / w),
  214. yp < y || !h ? 0 : (yp >= y + h ? meg4.screen.h : (yp - y) * meg4.screen.h / h));
  215. }
  216. /**
  217. * Scrolling event callback
  218. */
  219. void main_scroll(GLFWwindow *window, double xdelta, double ydelta) {
  220. (void)window;
  221. meg4_setscr(ydelta > 0.0, ydelta < 0.0, xdelta > 0.0, xdelta < 0.0);
  222. }
  223. /**
  224. * Joystick event callback
  225. */
  226. void main_joystick(int jid, int event) {
  227. int i;
  228. for(i = 0; i < 4 && controllerid[i] != jid; i++);
  229. switch(event) {
  230. case GLFW_DISCONNECTED:
  231. if(i < 4) controllerid[i] = -1;
  232. break;
  233. case GLFW_CONNECTED:
  234. if(i >= 4) for(i = 0; i < 4 && controllerid[i] != -1; i++);
  235. if(i < 4) controllerid[i] = jid;
  236. break;
  237. }
  238. }
  239. /**
  240. * Drop file event callback
  241. */
  242. void main_dropfile(GLFWwindow *window, int count, const char **fn)
  243. {
  244. #ifndef NOEDITORS
  245. uint8_t *ptr;
  246. int i, l;
  247. char *n;
  248. (void)window;
  249. for(i = 0; i < count; i++) {
  250. if((ptr = main_readfile(!memcmp(fn[i], "file://", 7) ? (char*)fn[i] + 7 : (char*)fn[i], &l))) {
  251. n = strrchr(fn[i], SEP[0]); if(!n) n = (char*)fn[i]; else n++;
  252. meg4_insert(n, ptr, l);
  253. free(ptr);
  254. }
  255. }
  256. #else
  257. (void)window; (void)count; (void)fn;
  258. #endif
  259. }
  260. /**
  261. * Get text from clipboard (must be freed by caller)
  262. */
  263. char *main_getclipboard(void)
  264. {
  265. const char *str = glfwGetClipboardString(NULL);
  266. char *ret = NULL;
  267. if(str && *str) {
  268. ret = (char*)malloc(strlen(str) + 1);
  269. if(ret) strcpy(ret, str);
  270. }
  271. return ret;
  272. }
  273. /**
  274. * Set text to clipboard
  275. */
  276. void main_setclipboard(char *str)
  277. {
  278. glfwSetClipboardString(NULL, str);
  279. }
  280. /**
  281. * Show on-screen keyboard
  282. */
  283. void main_osk_show(void)
  284. {
  285. }
  286. /**
  287. * Hide on-screen keyboard
  288. */
  289. void main_osk_hide(void)
  290. {
  291. }
  292. /**
  293. * PA audio callback
  294. */
  295. static int main_audio(const void *inp, void *out, long unsigned int framesPerBuffer, const PaStreamCallbackTimeInfo *info,
  296. PaStreamCallbackFlags flags, void *ctx)
  297. {
  298. (void)inp; (void)info; (void)flags; (void)ctx;
  299. meg4_audiofeed((float*)out, framesPerBuffer);
  300. return 0;
  301. }
  302. /**
  303. * Delay
  304. */
  305. void main_delay(int msec)
  306. {
  307. struct timespec tv;
  308. tv.tv_sec = 0; tv.tv_nsec = msec * 1000000;
  309. while(nanosleep(&tv, &tv) == -1 && tv.tv_nsec > 1000000);
  310. }
  311. /**
  312. * Print program version and copyright
  313. */
  314. void main_hdr(void)
  315. {
  316. printf("\r\nMEG-4 v%s ("
  317. #ifndef NOGLES
  318. "GLES"
  319. #else
  320. "OpenGL"
  321. #endif
  322. ", build %u) by bzt Copyright (C) 2023 GPLv3+\r\n\r\n", meg4ver, BUILD);
  323. }
  324. /**
  325. * Set up orthographic projection in a matrix
  326. */
  327. #ifndef NOGLES
  328. void main_ortho(GLfloat *m, float l, float r, float b, float t, float n, float f)
  329. {
  330. memset(m, 0, 16 * sizeof(GLfloat));
  331. m[ 0] = 2.0/(r-l);
  332. m[ 5] = 2.0/(t-b);
  333. m[10] = -2.0/(f-n);
  334. m[ 3] = -(r+l)/(r-l);
  335. m[ 7] = -(t+b)/(t-b);
  336. m[11] = -(f+n)/(f-n);
  337. m[15] = 1.0;
  338. }
  339. #endif
  340. /**
  341. * The real main procedure
  342. */
  343. int main(int argc, char **argv)
  344. {
  345. #ifndef NOGLES
  346. const GLchar *vstr = "attribute vec2 apos;\nattribute vec2 atex;\nvarying vec2 vtex;\nuniform mat4 mvp;\nvoid main(){gl_Position=mvp*vec4(apos,0.0,1.0);vtex=atex;}";
  347. const GLchar *fstr = "precision mediump float;\nvarying vec2 vtex;\nuniform sampler2D stex;\nvoid main(){gl_FragColor=texture2D(stex,vtex);}";
  348. GLushort idx[] = { 0, 1, 2, 0, 2, 3 };
  349. GLuint vshdr = 0, fshdr = 0;
  350. GLint ret;
  351. GLfloat mvp[16] = { 0 };
  352. #endif
  353. GLfloat vert[16] = { 0 }, x2, y2;
  354. double mx, my;
  355. const GLFWvidmode *vidmode;
  356. GLFWgamepadstate state;
  357. int i, j, w, h, ww, wh, lx, ly, rx, ry;
  358. char **infile = NULL, *fn;
  359. int32_t tickdiff;
  360. uint32_t ticks;
  361. uint8_t *ptr;
  362. FILE *out, *err;
  363. #ifdef __WIN32__
  364. char *lng = main_lng;
  365. #else
  366. char *lng = getenv("LANG");
  367. #endif
  368. main_parsecommandline(argc, argv, &lng, &infile);
  369. main_hdr();
  370. for(i = 0; i < 3; i++) printf(" %s\r\n", copyright[i]);
  371. printf("\r\n");
  372. fflush(stdout);
  373. glfwGetVersion(&i, &j, &w); h = Pa_GetVersion();
  374. sprintf(meg4plat, "glfw %u.%u.%u, portaudio %u.%u.%u", i, j, w, (h >> 16) & 0xff, (h >> 8) & 0xff, h & 0xff);
  375. /* set up keymap */
  376. memset(main_keymap, 0, sizeof(main_keymap));
  377. main_keymap[GLFW_KEY_SPACE] = MEG4_KEY_SPACE;
  378. main_keymap[GLFW_KEY_APOSTROPHE] = MEG4_KEY_APOSTROPHE;
  379. main_keymap[GLFW_KEY_COMMA] = MEG4_KEY_COMMA;
  380. main_keymap[GLFW_KEY_MINUS] = MEG4_KEY_MINUS;
  381. main_keymap[GLFW_KEY_PERIOD] = MEG4_KEY_PERIOD;
  382. main_keymap[GLFW_KEY_SLASH] = MEG4_KEY_SLASH;
  383. main_keymap[GLFW_KEY_0] = MEG4_KEY_0;
  384. main_keymap[GLFW_KEY_1] = MEG4_KEY_1;
  385. main_keymap[GLFW_KEY_2] = MEG4_KEY_2;
  386. main_keymap[GLFW_KEY_3] = MEG4_KEY_3;
  387. main_keymap[GLFW_KEY_4] = MEG4_KEY_4;
  388. main_keymap[GLFW_KEY_5] = MEG4_KEY_5;
  389. main_keymap[GLFW_KEY_6] = MEG4_KEY_6;
  390. main_keymap[GLFW_KEY_7] = MEG4_KEY_7;
  391. main_keymap[GLFW_KEY_8] = MEG4_KEY_8;
  392. main_keymap[GLFW_KEY_9] = MEG4_KEY_9;
  393. main_keymap[GLFW_KEY_SEMICOLON] = MEG4_KEY_SEMICOLON;
  394. main_keymap[GLFW_KEY_EQUAL] = MEG4_KEY_EQUAL;
  395. main_keymap[GLFW_KEY_A] = MEG4_KEY_A;
  396. main_keymap[GLFW_KEY_B] = MEG4_KEY_B;
  397. main_keymap[GLFW_KEY_C] = MEG4_KEY_C;
  398. main_keymap[GLFW_KEY_D] = MEG4_KEY_D;
  399. main_keymap[GLFW_KEY_E] = MEG4_KEY_E;
  400. main_keymap[GLFW_KEY_F] = MEG4_KEY_F;
  401. main_keymap[GLFW_KEY_G] = MEG4_KEY_G;
  402. main_keymap[GLFW_KEY_H] = MEG4_KEY_H;
  403. main_keymap[GLFW_KEY_I] = MEG4_KEY_I;
  404. main_keymap[GLFW_KEY_J] = MEG4_KEY_J;
  405. main_keymap[GLFW_KEY_K] = MEG4_KEY_K;
  406. main_keymap[GLFW_KEY_L] = MEG4_KEY_L;
  407. main_keymap[GLFW_KEY_M] = MEG4_KEY_M;
  408. main_keymap[GLFW_KEY_N] = MEG4_KEY_N;
  409. main_keymap[GLFW_KEY_O] = MEG4_KEY_O;
  410. main_keymap[GLFW_KEY_P] = MEG4_KEY_P;
  411. main_keymap[GLFW_KEY_Q] = MEG4_KEY_Q;
  412. main_keymap[GLFW_KEY_R] = MEG4_KEY_R;
  413. main_keymap[GLFW_KEY_S] = MEG4_KEY_S;
  414. main_keymap[GLFW_KEY_T] = MEG4_KEY_T;
  415. main_keymap[GLFW_KEY_U] = MEG4_KEY_U;
  416. main_keymap[GLFW_KEY_V] = MEG4_KEY_V;
  417. main_keymap[GLFW_KEY_X] = MEG4_KEY_X;
  418. main_keymap[GLFW_KEY_Y] = MEG4_KEY_Y;
  419. main_keymap[GLFW_KEY_Z] = MEG4_KEY_Z;
  420. main_keymap[GLFW_KEY_LEFT_BRACKET] = MEG4_KEY_LBRACKET;
  421. main_keymap[GLFW_KEY_BACKSLASH] = MEG4_KEY_BACKSLASH;
  422. main_keymap[GLFW_KEY_RIGHT_BRACKET] = MEG4_KEY_RBRACKET;
  423. main_keymap[GLFW_KEY_GRAVE_ACCENT] = MEG4_KEY_BACKQUOTE;
  424. main_keymap[GLFW_KEY_WORLD_1] = MEG4_KEY_INT1;
  425. main_keymap[GLFW_KEY_WORLD_2] = MEG4_KEY_INT2;
  426. main_keymap[119] = MEG4_KEY_SELECT;
  427. main_keymap[120] = MEG4_KEY_STOP;
  428. main_keymap[121] = MEG4_KEY_AGAIN;
  429. main_keymap[122] = MEG4_KEY_UNDO;
  430. main_keymap[123] = MEG4_KEY_CUT;
  431. main_keymap[124] = MEG4_KEY_COPY;
  432. main_keymap[125] = MEG4_KEY_PASTE;
  433. main_keymap[126] = MEG4_KEY_FIND;
  434. main_keymap[127] = MEG4_KEY_MUTE;
  435. main_keymap[128] = MEG4_KEY_VOLUP;
  436. main_keymap[129] = MEG4_KEY_VOLDN;
  437. main_keymap[135] = MEG4_KEY_INT1;
  438. main_keymap[136] = MEG4_KEY_INT2;
  439. main_keymap[137] = MEG4_KEY_INT3;
  440. main_keymap[138] = MEG4_KEY_INT4;
  441. main_keymap[139] = MEG4_KEY_INT5;
  442. main_keymap[140] = MEG4_KEY_INT6;
  443. main_keymap[141] = MEG4_KEY_INT7;
  444. main_keymap[142] = MEG4_KEY_INT8;
  445. main_keymap[144] = MEG4_KEY_LNG1;
  446. main_keymap[145] = MEG4_KEY_LNG2;
  447. main_keymap[146] = MEG4_KEY_LNG3;
  448. main_keymap[147] = MEG4_KEY_LNG4;
  449. main_keymap[148] = MEG4_KEY_LNG5;
  450. main_keymap[149] = MEG4_KEY_LNG6;
  451. main_keymap[150] = MEG4_KEY_LNG7;
  452. main_keymap[151] = MEG4_KEY_LNG8;
  453. main_keymap[GLFW_KEY_ENTER] = MEG4_KEY_ENTER;
  454. main_keymap[GLFW_KEY_TAB] = MEG4_KEY_TAB;
  455. main_keymap[GLFW_KEY_BACKSPACE] = MEG4_KEY_BACKSPACE;
  456. main_keymap[GLFW_KEY_INSERT] = MEG4_KEY_INS;
  457. main_keymap[GLFW_KEY_DELETE] = MEG4_KEY_DEL;
  458. main_keymap[GLFW_KEY_RIGHT] = MEG4_KEY_RIGHT;
  459. main_keymap[GLFW_KEY_LEFT] = MEG4_KEY_LEFT;
  460. main_keymap[GLFW_KEY_DOWN] = MEG4_KEY_DOWN;
  461. main_keymap[GLFW_KEY_UP] = MEG4_KEY_UP;
  462. main_keymap[GLFW_KEY_PAGE_UP] = MEG4_KEY_PGUP;
  463. main_keymap[GLFW_KEY_PAGE_DOWN] = MEG4_KEY_PGDN;
  464. main_keymap[GLFW_KEY_HOME] = MEG4_KEY_HOME;
  465. main_keymap[GLFW_KEY_END] = MEG4_KEY_END;
  466. main_keymap[GLFW_KEY_CAPS_LOCK] = MEG4_KEY_CAPSLOCK;
  467. main_keymap[GLFW_KEY_SCROLL_LOCK] = MEG4_KEY_SCRLOCK;
  468. main_keymap[GLFW_KEY_NUM_LOCK] = MEG4_KEY_NUMLOCK;
  469. main_keymap[GLFW_KEY_PRINT_SCREEN] = MEG4_KEY_PRSCR;
  470. main_keymap[GLFW_KEY_PAUSE] = MEG4_KEY_PAUSE;
  471. main_keymap[GLFW_KEY_F1] = MEG4_KEY_F1;
  472. main_keymap[GLFW_KEY_F2] = MEG4_KEY_F2;
  473. main_keymap[GLFW_KEY_F3] = MEG4_KEY_F3;
  474. main_keymap[GLFW_KEY_F4] = MEG4_KEY_F4;
  475. main_keymap[GLFW_KEY_F5] = MEG4_KEY_F5;
  476. main_keymap[GLFW_KEY_F6] = MEG4_KEY_F6;
  477. main_keymap[GLFW_KEY_F7] = MEG4_KEY_F7;
  478. main_keymap[GLFW_KEY_F8] = MEG4_KEY_F8;
  479. main_keymap[GLFW_KEY_F9] = MEG4_KEY_F9;
  480. main_keymap[GLFW_KEY_F10] = MEG4_KEY_F10;
  481. main_keymap[GLFW_KEY_F11] = MEG4_KEY_F11;
  482. main_keymap[GLFW_KEY_F12] = MEG4_KEY_F12;
  483. main_keymap[GLFW_KEY_KP_0] = MEG4_KEY_KP_0;
  484. main_keymap[GLFW_KEY_KP_1] = MEG4_KEY_KP_1;
  485. main_keymap[GLFW_KEY_KP_2] = MEG4_KEY_KP_2;
  486. main_keymap[GLFW_KEY_KP_3] = MEG4_KEY_KP_3;
  487. main_keymap[GLFW_KEY_KP_4] = MEG4_KEY_KP_4;
  488. main_keymap[GLFW_KEY_KP_5] = MEG4_KEY_KP_5;
  489. main_keymap[GLFW_KEY_KP_6] = MEG4_KEY_KP_6;
  490. main_keymap[GLFW_KEY_KP_7] = MEG4_KEY_KP_7;
  491. main_keymap[GLFW_KEY_KP_8] = MEG4_KEY_KP_8;
  492. main_keymap[GLFW_KEY_KP_9] = MEG4_KEY_KP_9;
  493. main_keymap[GLFW_KEY_KP_DECIMAL] = MEG4_KEY_KP_DEC;
  494. main_keymap[GLFW_KEY_KP_DIVIDE] = MEG4_KEY_KP_DIV;
  495. main_keymap[GLFW_KEY_KP_MULTIPLY] = MEG4_KEY_KP_MUL;
  496. main_keymap[GLFW_KEY_KP_SUBTRACT] = MEG4_KEY_KP_SUB;
  497. main_keymap[GLFW_KEY_KP_ADD] = MEG4_KEY_KP_ADD;
  498. main_keymap[GLFW_KEY_KP_ENTER] = MEG4_KEY_KP_ENTER;
  499. main_keymap[GLFW_KEY_KP_EQUAL] = MEG4_KEY_KP_EQUAL;
  500. main_keymap[GLFW_KEY_LEFT_SHIFT] = MEG4_KEY_LSHIFT;
  501. main_keymap[GLFW_KEY_LEFT_CONTROL] = MEG4_KEY_LCTRL;
  502. main_keymap[GLFW_KEY_LEFT_ALT] = MEG4_KEY_LALT;
  503. main_keymap[GLFW_KEY_LEFT_SUPER] = MEG4_KEY_LSUPER;
  504. main_keymap[GLFW_KEY_RIGHT_SHIFT] = MEG4_KEY_RSHIFT;
  505. main_keymap[GLFW_KEY_RIGHT_CONTROL] = MEG4_KEY_RCTRL;
  506. main_keymap[GLFW_KEY_RIGHT_ALT] = MEG4_KEY_RALT;
  507. main_keymap[GLFW_KEY_RIGHT_SUPER] = MEG4_KEY_RSUPER;
  508. main_keymap[GLFW_KEY_MENU] = MEG4_KEY_MENU;
  509. scrbuf = (uint32_t*)malloc(640 * 400 * sizeof(uint32_t));
  510. if(!scrbuf) {
  511. main_log(0, "unable to allocate screen buffer");
  512. return 1;
  513. }
  514. /* PortAudio litters my screen with lots of garbage about missing daemons and server connection errors and such...
  515. * I won't install hudred of megabytes of bloatware just to make it shut up, so hush, little PortAudio */
  516. out = stdout; err = stderr; stdout = stderr = fopen(
  517. #ifdef __WIN32__
  518. "NUL:"
  519. #else
  520. "/dev/null"
  521. #endif
  522. , "w");
  523. /* initialize the audio */
  524. audio = (Pa_Initialize() == paNoError) ? 1 : 0; pa = NULL;
  525. if(audio && (Pa_OpenDefaultStream(&pa, 0, 1, paFloat32, 44100, 4096, main_audio, NULL) != paNoError || !pa)) {
  526. Pa_Terminate(); audio = 0; pa = NULL;
  527. }
  528. /* restore stdout, stderr */
  529. fclose(stderr); stdout = out; stderr = err;
  530. if(verbose && audio) main_log(1, "audio opened %uHz, %u bits", 44100, 32);
  531. /* initialize screen and other stuff */
  532. if(!glfwInit()) {
  533. main_log(0, "unable to initialize GLFW");
  534. return 1;
  535. }
  536. glfwSetErrorCallback(main_error);
  537. #ifndef NOGLES
  538. glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
  539. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
  540. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
  541. glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API);
  542. #endif
  543. glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
  544. if(!(monitor = glfwGetPrimaryMonitor()) || !(vidmode = glfwGetVideoMode(monitor))) {
  545. glfwTerminate();
  546. main_log(0, "unable to get GLFW monitor");
  547. return 1;
  548. }
  549. /* turn on the emulator */
  550. meg4_poweron(lng);
  551. #ifndef NOEDITORS
  552. for(; infile && *infile; infile++) {
  553. if((ptr = main_readfile(*infile, &i))) {
  554. fn = strrchr(*infile, SEP[0]); if(!fn) fn = *infile; else fn++;
  555. meg4_insert(fn, ptr, i);
  556. free(ptr);
  557. }
  558. }
  559. #else
  560. (void)ptr; (void)infile;
  561. #endif
  562. main_w = vidmode->width;
  563. main_h = vidmode->height;
  564. #if DEBUG
  565. main_win(640, 400, 0);
  566. #else
  567. i = main_w / 320; h = main_h / 200; if(i > h) i = h;
  568. win_w = 320 * i; win_h = 200 * i;
  569. main_win(win_w/*main_w*/, win_h/*main_h*/, 0/*1*/);
  570. if(!windowed) main_fullscreen();
  571. #endif
  572. if(!window) {
  573. meg4_poweroff();
  574. glfwTerminate();
  575. main_log(0, "unable to initialize GLFW window");
  576. return 1;
  577. }
  578. #ifdef __WIN32__
  579. hwnd = glfwGetWin32Window(window);
  580. #endif
  581. /* according to https://www.glfw.org/docs/latest/input_guide.html#gamepad_mapping we dont' have to load
  582. * gamecontrollerdb.txt ourselves, because glfw should already contain a copy of that */
  583. #ifndef NOGLES
  584. if(!(vshdr = glCreateShader(GL_VERTEX_SHADER))) {
  585. serr: if(vshdr) glDeleteShader(vshdr);
  586. if(fshdr) glDeleteShader(fshdr);
  587. glfwTerminate();
  588. main_log(0, "unable to get shaders");
  589. return 1;
  590. }
  591. glShaderSource(vshdr, 1, &vstr, NULL);
  592. glCompileShader(vshdr);
  593. glGetShaderiv(vshdr, GL_COMPILE_STATUS, &ret);
  594. if(!ret) goto serr;
  595. if(!(fshdr = glCreateShader(GL_FRAGMENT_SHADER))) goto serr;
  596. glShaderSource(fshdr, 1, &fstr, NULL);
  597. glCompileShader(fshdr);
  598. glGetShaderiv(fshdr, GL_COMPILE_STATUS, &ret);
  599. if(!ret) goto serr;
  600. program = glCreateProgram();
  601. if(!program) goto serr;
  602. glAttachShader(program, vshdr);
  603. glAttachShader(program, fshdr);
  604. glLinkProgram(program);
  605. glGetProgramiv(program, GL_LINK_STATUS, &ret);
  606. if(!ret) { glDeleteProgram(program); goto serr; }
  607. glDeleteShader(vshdr);
  608. glDeleteShader(fshdr);
  609. ploc = glGetAttribLocation(program, "apos");
  610. tloc = glGetAttribLocation(program, "atex");
  611. sloc = glGetUniformLocation(program, "stex");
  612. mloc = glGetUniformLocation(program, "mvp");
  613. glEnableVertexAttribArray(ploc);
  614. glEnableVertexAttribArray(tloc);
  615. #endif
  616. for(i = 0, j = GLFW_JOYSTICK_1; i < 4 && j < GLFW_JOYSTICK_LAST; j++)
  617. if(glfwJoystickPresent(j)) controllerid[i++] = j;
  618. glfwSetJoystickCallback(main_joystick);
  619. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  620. glGenTextures(1, &screen);
  621. glBindTexture(GL_TEXTURE_2D, screen);
  622. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  623. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  624. /* swapinterval is buggy in glfw, so we take care of the 60 FPS delay ourselves */
  625. glfwSwapInterval(0);
  626. glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
  627. glfwSetKeyCallback(window, main_key);
  628. glfwSetCharCallback(window, main_char);
  629. glfwSetMouseButtonCallback(window, main_mouse);
  630. glfwSetCursorPosCallback(window, main_pointer);
  631. glfwSetScrollCallback(window, main_scroll);
  632. glfwSetDropCallback(window, main_dropfile);
  633. if(audio && pa) Pa_StartStream(pa);
  634. while(!glfwWindowShouldClose(window)) {
  635. ticks = (uint32_t)(glfwGetTime() * 1000);
  636. glfwGetFramebufferSize(window, &ww, &wh);
  637. glfwGetCursorPos(window, &mx, &my);
  638. main_pointer(window, mx, my);
  639. meg4_run();
  640. meg4_redraw(scrbuf, 640, 400, 640 * 4);
  641. if(!win_f && nearest) {
  642. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  643. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  644. i = ww / 320; h = wh / 200; if(i > h) i = h;
  645. w = 320 * i; h = 200 * i;
  646. } else {
  647. i = nearest || (!(ww % 320) && !(wh % 200)) ? GL_NEAREST : GL_LINEAR;
  648. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, i);
  649. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, i);
  650. w = ww; h = (int)meg4.screen.h * ww / (int)meg4.screen.w;
  651. if(h > wh) { h = wh; w = (int)meg4.screen.w * wh / (int)meg4.screen.h; }
  652. }
  653. w >>= 1; h >>= 1;
  654. x2 = (float)meg4.screen.w / 640.0f;
  655. y2 = (float)meg4.screen.h / 400.0f;
  656. vert[ 0] = -w; vert[ 1] = -h; vert[ 2] = 0; vert[ 3] = 0;
  657. vert[ 4] = -w; vert[ 5] = h; vert[ 6] = 0; vert[ 7] = y2;
  658. vert[ 8] = w; vert[ 9] = h; vert[10] = x2; vert[11] = y2;
  659. vert[12] = w; vert[13] = -h; vert[14] = x2; vert[15] = 0;
  660. glViewport(0, 0, ww, wh);
  661. glClearColor(0.0, 0.0, 0.0, 1.0);
  662. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  663. #ifndef NOGLES
  664. /* new-wave. Mega hyper super fast and overcomplicated GLES2 */
  665. glUseProgram(program);
  666. glVertexAttribPointer(ploc, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), vert);
  667. glVertexAttribPointer(tloc, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), &vert[2]);
  668. glUniform1i(sloc, 0);
  669. main_ortho(mvp, -ww/2, ww/2, wh/2, -wh/2, 0.0, 1.0);
  670. glUniformMatrix4fv(mloc, 1, GL_FALSE, mvp);
  671. #else
  672. /* old-school. Much simpler, and even faster... */
  673. glMatrixMode(GL_PROJECTION);
  674. glLoadIdentity();
  675. glOrtho(-ww/2, ww/2, -wh/2, wh/2, 0.0, 1.0);
  676. glMatrixMode(GL_MODELVIEW);
  677. glLoadIdentity();
  678. glEnable(GL_TEXTURE_2D);
  679. #endif
  680. glActiveTexture(GL_TEXTURE0);
  681. glBindTexture(GL_TEXTURE_2D, screen);
  682. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 640, 400, 0, GL_RGBA, GL_UNSIGNED_BYTE, scrbuf);
  683. #ifndef NOGLES
  684. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, idx);
  685. #else
  686. glBegin(GL_QUADS);
  687. glVertex3f(vert[0], vert[1], 0); glTexCoord2f(vert[3], vert[2]);
  688. glVertex3f(vert[4], vert[5], 0); glTexCoord2f(vert[7], vert[6]);
  689. glVertex3f(vert[8], vert[9], 0); glTexCoord2f(vert[11], vert[10]);
  690. glVertex3f(vert[12], vert[13], 0); glTexCoord2f(vert[15], vert[14]);
  691. glEnd();
  692. glFlush();
  693. glDisable(GL_TEXTURE_2D);
  694. #endif
  695. /* no events for gamepads, we must poll... */
  696. for(i = 0; i < 4; i++)
  697. if(controllerid[i] != -1) {
  698. meg4_clrpad(i, 0xff);
  699. /* new gamepad interface, joysticks with proper mappings */
  700. if(glfwGetGamepadState(controllerid[i], &state)) {
  701. lx = state.axes[GLFW_GAMEPAD_AXIS_LEFT_X] * 32768.0; rx = state.axes[GLFW_GAMEPAD_AXIS_RIGHT_X] * 32768.0;
  702. ly = state.axes[GLFW_GAMEPAD_AXIS_LEFT_Y] * 32768.0; ry = state.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y] * 32768.0;
  703. if(lx < -le16toh(meg4.mmio.padtres) || rx < -le16toh(meg4.mmio.padtres) || state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT])
  704. meg4_setpad(i, MEG4_BTN_L);
  705. if(lx > le16toh(meg4.mmio.padtres) || rx > le16toh(meg4.mmio.padtres) || state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT])
  706. meg4_setpad(i, MEG4_BTN_R);
  707. if(ly < -le16toh(meg4.mmio.padtres) || ry < -le16toh(meg4.mmio.padtres) || state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_UP])
  708. meg4_setpad(i, MEG4_BTN_U);
  709. if(ly > le16toh(meg4.mmio.padtres) || ry > le16toh(meg4.mmio.padtres) || state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN])
  710. meg4_setpad(i, MEG4_BTN_D);
  711. if(state.buttons[GLFW_GAMEPAD_BUTTON_A]) meg4_setpad(i, MEG4_BTN_A);
  712. if(state.buttons[GLFW_GAMEPAD_BUTTON_B]) meg4_setpad(i, MEG4_BTN_B);
  713. if(state.buttons[GLFW_GAMEPAD_BUTTON_X]) meg4_setpad(i, MEG4_BTN_X);
  714. if(state.buttons[GLFW_GAMEPAD_BUTTON_Y]) meg4_setpad(i, MEG4_BTN_Y);
  715. }
  716. #ifdef JOYFALLBACK
  717. else {
  718. ptr = (uint8_t*)glfwGetJoystickButtons(controllerid[i], &w);
  719. for(j = 0; ptr && j < w; j++) {
  720. if(ptr[j] & GLFW_HAT_UP) meg4_setpad(i, MEG4_BTN_U);
  721. if(ptr[j] & GLFW_HAT_RIGHT) meg4_setpad(i, MEG4_BTN_R);
  722. if(ptr[j] & GLFW_HAT_DOWN) meg4_setpad(i, MEG4_BTN_D);
  723. if(ptr[j] & GLFW_HAT_LEFT) meg4_setpad(i, MEG4_BTN_L);
  724. /* just a guess because there's no mapping */
  725. if(ptr[j] & 16) meg4_setpad(i, MEG4_BTN_A);
  726. if(ptr[j] & 32) meg4_setpad(i, MEG4_BTN_B);
  727. if(ptr[j] & 64) meg4_setpad(i, MEG4_BTN_X);
  728. if(ptr[j] & 128) meg4_setpad(i, MEG4_BTN_Y);
  729. }
  730. }
  731. #endif
  732. }
  733. glfwSwapBuffers(window);
  734. glfwPollEvents();
  735. tickdiff = (1000/60) - ((uint32_t)(glfwGetTime() * 1000) - ticks);
  736. if(tickdiff > 0 && tickdiff < 1000) {
  737. if(verbose == 2) { printf("meg4: free time %d msec \r",tickdiff); fflush(stdout); }
  738. main_delay(tickdiff);
  739. }
  740. }
  741. main_quit();
  742. return 0;
  743. }