gs_platform_impl.h 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. /*================================================================
  2. * Copyright: 2020 John Jackson
  3. * File: gs_platform_impl.h
  4. All Rights Reserved
  5. =================================================================*/
  6. #ifndef __GS_PLATFORM_IMPL_H__
  7. #define __GS_PLATFORM_IMPL_H__
  8. /*=================================
  9. // Default Platform Implemenattion
  10. =================================*/
  11. // Define default platform implementation if certain platforms are enabled
  12. #if (defined GS_PLATFORM_IMPL_GLFW)
  13. #define GS_PLATFORM_IMPL_DEFAULT
  14. #endif
  15. /*=============================
  16. // Default Impl
  17. =============================*/
  18. #ifdef GS_PLATFORM_IMPL_DEFAULT
  19. #if !( defined GS_PLATFORM_WIN )
  20. #include <sys/stat.h>
  21. #endif
  22. /*== Platform Window ==*/
  23. gs_platform_i* gs_platform_create()
  24. {
  25. // Construct new platform interface
  26. gs_platform_i* platform = gs_malloc_init(gs_platform_i);
  27. // Initialize windows
  28. platform->windows = gs_slot_array_new(void*);
  29. // Set up video mode (for now, just do opengl)
  30. platform->settings.video.driver = GS_PLATFORM_VIDEO_DRIVER_TYPE_OPENGL;
  31. return platform;
  32. }
  33. void gs_platform_destroy(gs_platform_i* platform)
  34. {
  35. if (platform == NULL) return;
  36. // Free all resources
  37. gs_slot_array_free(platform->windows);
  38. // Free platform
  39. gs_free(platform);
  40. platform = NULL;
  41. }
  42. uint32_t gs_platform_create_window(const char* title, uint32_t width, uint32_t height)
  43. {
  44. gs_assert(gs_engine_instance() != NULL);
  45. gs_platform_i* platform = gs_engine_subsystem(platform);
  46. void* win = gs_platform_create_window_internal(title, width, height);
  47. return (gs_slot_array_insert(platform->windows, win));
  48. }
  49. uint32_t gs_platform_main_window()
  50. {
  51. // Should be the first element of the slot array...Great assumption to make.
  52. return 0;
  53. }
  54. /*== Platform UUID ==*/
  55. struct gs_uuid_t gs_platform_generate_uuid()
  56. {
  57. gs_uuid_t uuid;
  58. srand(clock());
  59. char guid[40];
  60. int32_t t = 0;
  61. char* sz_temp = "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx";
  62. char* sz_hex = "0123456789abcdef-";
  63. int32_t n_len = strlen(sz_temp);
  64. for (t=0; t < n_len + 1; t++)
  65. {
  66. int32_t r = rand () % 16;
  67. char c = ' ';
  68. switch (sz_temp[t])
  69. {
  70. case 'x' : { c = sz_hex [r]; } break;
  71. case 'y' : { c = sz_hex [(r & 0x03) | 0x08]; } break;
  72. case '-' : { c = '-'; } break;
  73. case '4' : { c = '4'; } break;
  74. }
  75. guid[t] = (t < n_len) ? c : 0x00;
  76. }
  77. // Convert to uuid bytes from string
  78. const char* hex_string = sz_temp, *pos = hex_string;
  79. /* WARNING: no sanitization or error-checking whatsoever */
  80. for (size_t count = 0; count < 16; count++)
  81. {
  82. sscanf(pos, "%2hhx", &uuid.bytes[count]);
  83. pos += 2;
  84. }
  85. return uuid;
  86. }
  87. // Mutable temp buffer 'tmp_buffer'
  88. void gs_platform_uuid_to_string(char* tmp_buffer, const gs_uuid_t* uuid)
  89. {
  90. gs_snprintf
  91. (
  92. tmp_buffer,
  93. 32,
  94. "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
  95. uuid->bytes[0],
  96. uuid->bytes[1],
  97. uuid->bytes[2],
  98. uuid->bytes[3],
  99. uuid->bytes[4],
  100. uuid->bytes[5],
  101. uuid->bytes[6],
  102. uuid->bytes[7],
  103. uuid->bytes[8],
  104. uuid->bytes[9],
  105. uuid->bytes[10],
  106. uuid->bytes[11],
  107. uuid->bytes[12],
  108. uuid->bytes[13],
  109. uuid->bytes[14],
  110. uuid->bytes[15]
  111. );
  112. }
  113. uint32_t gs_platform_hash_uuid(const gs_uuid_t* uuid)
  114. {
  115. char temp_buffer[] = gs_uuid_temp_str_buffer();
  116. gs_platform_uuid_to_string(temp_buffer, uuid);
  117. return (gs_hash_str(temp_buffer));
  118. }
  119. #define __gs_input()\
  120. (&gs_engine_subsystem(platform)->input)
  121. /*=== Platform Input ===*/
  122. void gs_platform_update_input()
  123. {
  124. gs_platform_input_t* input = __gs_input();
  125. // Update all input and mouse keys from previous frame
  126. // Previous key presses
  127. gs_for_range_i(GS_KEYCODE_COUNT)
  128. {
  129. input->prev_key_map[i] = input->key_map[i];
  130. }
  131. // Previous mouse button presses
  132. gs_for_range_i(GS_MOUSE_BUTTON_CODE_COUNT)
  133. {
  134. input->mouse.prev_button_map[i] = input->mouse.button_map[i];
  135. }
  136. input->mouse.prev_position = input->mouse.position;
  137. input->mouse.wheel = gs_v2(0.0f, 0.0f);
  138. input->mouse.moved_this_frame = false;
  139. }
  140. bool gs_platform_was_key_down(gs_platform_keycode code)
  141. {
  142. gs_platform_input_t* input = __gs_input();
  143. return (input->prev_key_map[code]);
  144. }
  145. bool gs_platform_key_down(gs_platform_keycode code)
  146. {
  147. gs_platform_input_t* input = __gs_input();
  148. return (input->key_map[code]);
  149. }
  150. bool gs_platform_key_pressed(gs_platform_keycode code)
  151. {
  152. gs_platform_input_t* input = __gs_input();
  153. if (gs_platform_key_down(code) && !gs_platform_was_key_down(code))
  154. {
  155. return true;
  156. }
  157. return false;
  158. }
  159. bool gs_platform_key_released(gs_platform_keycode code)
  160. {
  161. gs_platform_input_t* input = __gs_input();
  162. return (gs_platform_was_key_down(code) && !gs_platform_key_down(code));
  163. }
  164. bool gs_platform_was_mouse_down(gs_platform_mouse_button_code code)
  165. {
  166. gs_platform_input_t* input = __gs_input();
  167. return (input->mouse.prev_button_map[code]);
  168. }
  169. void gs_platform_press_mouse_button(gs_platform_mouse_button_code code)
  170. {
  171. gs_platform_input_t* input = __gs_input();
  172. if ((u32)code < (u32)GS_MOUSE_BUTTON_CODE_COUNT)
  173. {
  174. input->mouse.button_map[code] = true;
  175. }
  176. }
  177. void gs_platform_release_mouse_button(gs_platform_mouse_button_code code)
  178. {
  179. gs_platform_input_t* input = __gs_input();
  180. if ((u32)code < (u32)GS_MOUSE_BUTTON_CODE_COUNT)
  181. {
  182. input->mouse.button_map[code] = false;
  183. }
  184. }
  185. bool gs_platform_mouse_down(gs_platform_mouse_button_code code)
  186. {
  187. gs_platform_input_t* input = __gs_input();
  188. return (input->mouse.button_map[code]);
  189. }
  190. bool gs_platform_mouse_pressed(gs_platform_mouse_button_code code)
  191. {
  192. gs_platform_input_t* input = __gs_input();
  193. if (gs_platform_mouse_down(code) && !gs_platform_was_mouse_down(code))
  194. {
  195. return true;
  196. }
  197. return false;
  198. }
  199. bool gs_platform_mouse_released(gs_platform_mouse_button_code code)
  200. {
  201. gs_platform_input_t* input = __gs_input();
  202. return (gs_platform_was_mouse_down(code) && !gs_platform_mouse_down(code));
  203. }
  204. void gs_platform_mouse_delta(float* x, float* y)
  205. {
  206. gs_platform_input_t* input = __gs_input();
  207. if (input->mouse.prev_position.x < 0.0f ||
  208. input->mouse.prev_position.y < 0.0f ||
  209. input->mouse.position.x < 0.0f ||
  210. input->mouse.position.y < 0.0f)
  211. {
  212. *x = 0.f;
  213. *y = 0.f;
  214. return;
  215. }
  216. *x = input->mouse.position.x - input->mouse.prev_position.x;
  217. *y = input->mouse.position.y - input->mouse.prev_position.y;
  218. }
  219. gs_vec2 gs_platform_mouse_deltav()
  220. {
  221. gs_platform_input_t* input = __gs_input();
  222. if (input->mouse.prev_position.x < 0.0f ||
  223. input->mouse.prev_position.y < 0.0f ||
  224. input->mouse.position.x < 0.0f ||
  225. input->mouse.position.y < 0.0f)
  226. {
  227. return (gs_vec2){0.0f, 0.0f};
  228. }
  229. return (gs_vec2){input->mouse.position.x - input->mouse.prev_position.x,
  230. input->mouse.position.y - input->mouse.prev_position.y};
  231. }
  232. gs_vec2 gs_platform_mouse_positionv()
  233. {
  234. gs_platform_input_t* input = __gs_input();
  235. return (gs_vec2)
  236. {
  237. input->mouse.position.x,
  238. input->mouse.position.y
  239. };
  240. }
  241. void gs_platform_mouse_position(f32* x, f32* y)
  242. {
  243. gs_platform_input_t* input = __gs_input();
  244. *x = input->mouse.position.x;
  245. *y = input->mouse.position.y;
  246. }
  247. void gs_platform_mouse_wheel(f32* x, f32* y)
  248. {
  249. gs_platform_input_t* input = __gs_input();
  250. *x = input->mouse.wheel.x;
  251. *y = input->mouse.wheel.y;
  252. }
  253. void gs_platform_press_key(gs_platform_keycode code)
  254. {
  255. gs_platform_input_t* input = __gs_input();
  256. if (code < GS_KEYCODE_COUNT)
  257. {
  258. input->key_map[code] = true;
  259. }
  260. }
  261. void gs_platform_release_key(gs_platform_keycode code)
  262. {
  263. gs_platform_input_t* input = __gs_input();
  264. if (code < GS_KEYCODE_COUNT)
  265. {
  266. input->key_map[code] = false;
  267. }
  268. }
  269. // Platform File IO
  270. char* gs_platform_read_file_contents(const char* file_path, const char* mode, int32_t* sz)
  271. {
  272. char* buffer = 0;
  273. FILE* fp = fopen(file_path, mode);
  274. usize _sz = 0;
  275. if (fp)
  276. {
  277. _sz = gs_platform_file_size_in_bytes(file_path);
  278. // fseek(fp, 0, SEEK_END);
  279. // _sz = ftell(fp);
  280. // fseek(fp, 0, SEEK_SET);
  281. buffer = (char*)gs_malloc(_sz);
  282. if (buffer)
  283. {
  284. fread(buffer, 1, _sz, fp);
  285. }
  286. fclose(fp);
  287. // buffer[_sz] = '\0';
  288. }
  289. if (sz)
  290. *sz = _sz;
  291. return buffer;
  292. }
  293. gs_result gs_platform_write_file_contents(const char* file_path, const char* mode, void* data, size_t sz)
  294. {
  295. FILE* fp = fopen(file_path, mode);
  296. if (fp)
  297. {
  298. size_t ret = fwrite(data, sizeof(uint8_t), sz, fp);
  299. if (ret == sz)
  300. {
  301. return GS_RESULT_SUCCESS;
  302. }
  303. }
  304. return GS_RESULT_FAILURE;
  305. }
  306. bool gs_platform_file_exists(const char* file_path)
  307. {
  308. return (gs_util_file_exists(file_path));
  309. }
  310. int32_t gs_platform_file_size_in_bytes(const char* file_path)
  311. {
  312. #ifdef GS_PLATFORM_WIN
  313. HANDLE hFile = CreateFile(file_path, GENERIC_READ,
  314. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  315. FILE_ATTRIBUTE_NORMAL, NULL);
  316. if (hFile==INVALID_HANDLE_VALUE)
  317. return -1; // error condition, could call GetLastError to find out more
  318. LARGE_INTEGER size;
  319. if (!GetFileSizeEx(hFile, &size))
  320. {
  321. CloseHandle(hFile);
  322. return -1; // error condition, could call GetLastError to find out more
  323. }
  324. CloseHandle(hFile);
  325. return gs_util_safe_truncate_u64(size.QuadPart);
  326. #else
  327. struct stat st;
  328. stat(file_path, &st);
  329. return (int32_t)st.st_size;
  330. #endif
  331. }
  332. void gs_platform_file_extension(char* buffer, size_t buffer_sz, const char* file_path)
  333. {
  334. gs_util_get_file_extension(buffer, buffer_sz, file_path);
  335. }
  336. #undef GS_PLATFORM_IMPL_DEFAULT
  337. #endif // GS_PLATFORM_IMPL_DEFAULT
  338. /*======================
  339. // GLFW Implemenation
  340. ======================*/
  341. #ifdef GS_PLATFORM_IMPL_GLFW
  342. #define GLAD_IMPL
  343. #include "../external/glad/glad_impl.h"
  344. #define GLFW_IMPL
  345. #include "../external/glfw/glfw_impl.h"
  346. #if (defined GS_PLATFORM_APPLE || defined GS_PLATFORM_LINUX)
  347. #include <sched.h>
  348. #include <unistd.h>
  349. #elif (defined GS_PLATFORM_WINDOWS)
  350. #include <windows.h>
  351. #endif
  352. // Forward Decls.
  353. void __glfw_key_callback(GLFWwindow* window, s32 key, s32 scancode, s32 action, s32 mods);
  354. void __glfw_mouse_button_callback(GLFWwindow* window, s32 button, s32 action, s32 mods);
  355. void __glfw_mouse_cursor_position_callback(GLFWwindow* window, f64 x, f64 y);
  356. void __glfw_mouse_scroll_wheel_callback(GLFWwindow* window, f64 xoffset, f64 yoffset);
  357. void __glfw_mouse_cursor_enter_callback(GLFWwindow* window, s32 entered);
  358. void __glfw_frame_buffer_size_callback(GLFWwindow* window, s32 width, s32 height);
  359. void __glfw_drop_callback(GLFWwindow* window);
  360. #define __glfw_window_from_handle(platform, handle)\
  361. ((GLFWwindow*)(gs_slot_array_get((platform)->windows, (handle))))
  362. /*== Platform Init / Shutdown == */
  363. gs_result gs_platform_init(gs_platform_i* pf)
  364. {
  365. gs_assert(pf);
  366. gs_println("Initializing GLFW");
  367. glfwInit();
  368. switch (pf->settings.video.driver)
  369. {
  370. case GS_PLATFORM_VIDEO_DRIVER_TYPE_OPENGL:
  371. {
  372. #if (defined GS_PLATFORM_APPLE)
  373. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
  374. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
  375. glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
  376. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  377. glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
  378. #else
  379. // glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, platform->settings.video.graphics.opengl.major_version);
  380. // glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, platform->settings.video.graphics.opengl.minor_version);
  381. // glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
  382. // glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
  383. // glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
  384. // glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  385. #endif
  386. // glfwSwapInterval(platform->settings.video.vsync_enabled);
  387. // glfwSwapInterval(0);
  388. } break;
  389. default:
  390. {
  391. // Default to no output at all.
  392. gs_println("Video format not supported.");
  393. gs_assert(false);
  394. } break;
  395. }
  396. // Construct cursors
  397. pf->cursors[(u32)GS_PLATFORM_CURSOR_ARROW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
  398. pf->cursors[(u32)GS_PLATFORM_CURSOR_IBEAM] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
  399. pf->cursors[(u32)GS_PLATFORM_CURSOR_SIZE_NW_SE] = glfwCreateStandardCursor(GLFW_CROSSHAIR_CURSOR);
  400. pf->cursors[(u32)GS_PLATFORM_CURSOR_SIZE_NE_SW] = glfwCreateStandardCursor(GLFW_CROSSHAIR_CURSOR);
  401. pf->cursors[(u32)GS_PLATFORM_CURSOR_SIZE_NS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
  402. pf->cursors[(u32)GS_PLATFORM_CURSOR_SIZE_WE] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
  403. pf->cursors[(u32)GS_PLATFORM_CURSOR_SIZE_ALL] = glfwCreateStandardCursor(GLFW_CROSSHAIR_CURSOR);
  404. pf->cursors[(u32)GS_PLATFORM_CURSOR_HAND] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
  405. pf->cursors[(u32)GS_PLATFORM_CURSOR_NO] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
  406. return GS_RESULT_SUCCESS;
  407. }
  408. gs_result gs_platform_shutdown(gs_platform_i* pf)
  409. {
  410. // Free all windows in glfw
  411. // TODO(john): Figure out crash with glfwDestroyWindow && glfwTerminate
  412. for
  413. (
  414. gs_slot_array_iter it = 0;
  415. gs_slot_array_iter_valid(pf->windows, it);
  416. gs_slot_array_iter_advance(pf->windows, it)
  417. )
  418. {
  419. GLFWwindow* win = __glfw_window_from_handle(pf, it);
  420. // glfwDestroyWindow(win);
  421. }
  422. // glfwTerminate();
  423. return GS_RESULT_SUCCESS;
  424. }
  425. /*=== GLFW Callbacks ===*/
  426. gs_platform_keycode glfw_key_to_gs_keycode(u32 code)
  427. {
  428. switch (code)
  429. {
  430. case GLFW_KEY_A: return GS_KEYCODE_A; break;
  431. case GLFW_KEY_B: return GS_KEYCODE_B; break;
  432. case GLFW_KEY_C: return GS_KEYCODE_C; break;
  433. case GLFW_KEY_D: return GS_KEYCODE_D; break;
  434. case GLFW_KEY_E: return GS_KEYCODE_E; break;
  435. case GLFW_KEY_F: return GS_KEYCODE_F; break;
  436. case GLFW_KEY_G: return GS_KEYCODE_G; break;
  437. case GLFW_KEY_H: return GS_KEYCODE_H; break;
  438. case GLFW_KEY_I: return GS_KEYCODE_I; break;
  439. case GLFW_KEY_J: return GS_KEYCODE_J; break;
  440. case GLFW_KEY_K: return GS_KEYCODE_K; break;
  441. case GLFW_KEY_L: return GS_KEYCODE_L; break;
  442. case GLFW_KEY_M: return GS_KEYCODE_M; break;
  443. case GLFW_KEY_N: return GS_KEYCODE_N; break;
  444. case GLFW_KEY_O: return GS_KEYCODE_O; break;
  445. case GLFW_KEY_P: return GS_KEYCODE_P; break;
  446. case GLFW_KEY_Q: return GS_KEYCODE_Q; break;
  447. case GLFW_KEY_R: return GS_KEYCODE_R; break;
  448. case GLFW_KEY_S: return GS_KEYCODE_S; break;
  449. case GLFW_KEY_T: return GS_KEYCODE_T; break;
  450. case GLFW_KEY_U: return GS_KEYCODE_U; break;
  451. case GLFW_KEY_V: return GS_KEYCODE_V; break;
  452. case GLFW_KEY_W: return GS_KEYCODE_W; break;
  453. case GLFW_KEY_X: return GS_KEYCODE_X; break;
  454. case GLFW_KEY_Y: return GS_KEYCODE_Y; break;
  455. case GLFW_KEY_Z: return GS_KEYCODE_Z; break;
  456. case GLFW_KEY_LEFT_SHIFT: return GS_KEYCODE_LSHIFT; break;
  457. case GLFW_KEY_RIGHT_SHIFT: return GS_KEYCODE_RSHIFT; break;
  458. case GLFW_KEY_LEFT_ALT: return GS_KEYCODE_LALT; break;
  459. case GLFW_KEY_RIGHT_ALT: return GS_KEYCODE_RALT; break;
  460. case GLFW_KEY_LEFT_CONTROL: return GS_KEYCODE_LCTRL; break;
  461. case GLFW_KEY_RIGHT_CONTROL: return GS_KEYCODE_RCTRL; break;
  462. case GLFW_KEY_BACKSPACE: return GS_KEYCODE_BSPACE; break;
  463. case GLFW_KEY_BACKSLASH: return GS_KEYCODE_BSLASH; break;
  464. case GLFW_KEY_SLASH: return GS_KEYCODE_QMARK; break;
  465. case GLFW_KEY_GRAVE_ACCENT: return GS_KEYCODE_TILDE; break;
  466. case GLFW_KEY_COMMA: return GS_KEYCODE_COMMA; break;
  467. case GLFW_KEY_PERIOD: return GS_KEYCODE_PERIOD; break;
  468. case GLFW_KEY_ESCAPE: return GS_KEYCODE_ESC; break;
  469. case GLFW_KEY_SPACE: return GS_KEYCODE_SPACE; break;
  470. case GLFW_KEY_LEFT: return GS_KEYCODE_LEFT; break;
  471. case GLFW_KEY_UP: return GS_KEYCODE_UP; break;
  472. case GLFW_KEY_RIGHT: return GS_KEYCODE_RIGHT; break;
  473. case GLFW_KEY_DOWN: return GS_KEYCODE_DOWN; break;
  474. case GLFW_KEY_0: return GS_KEYCODE_ZERO; break;
  475. case GLFW_KEY_1: return GS_KEYCODE_ONE; break;
  476. case GLFW_KEY_2: return GS_KEYCODE_TWO; break;
  477. case GLFW_KEY_3: return GS_KEYCODE_THREE; break;
  478. case GLFW_KEY_4: return GS_KEYCODE_FOUR; break;
  479. case GLFW_KEY_5: return GS_KEYCODE_FIVE; break;
  480. case GLFW_KEY_6: return GS_KEYCODE_SIX; break;
  481. case GLFW_KEY_7: return GS_KEYCODE_SEVEN; break;
  482. case GLFW_KEY_8: return GS_KEYCODE_EIGHT; break;
  483. case GLFW_KEY_9: return GS_KEYCODE_NINE; break;
  484. case GLFW_KEY_KP_0: return GS_KEYCODE_NPZERO; break;
  485. case GLFW_KEY_KP_1: return GS_KEYCODE_NPONE; break;
  486. case GLFW_KEY_KP_2: return GS_KEYCODE_NPTWO; break;
  487. case GLFW_KEY_KP_3: return GS_KEYCODE_NPTHREE; break;
  488. case GLFW_KEY_KP_4: return GS_KEYCODE_NPFOUR; break;
  489. case GLFW_KEY_KP_5: return GS_KEYCODE_NPFIVE; break;
  490. case GLFW_KEY_KP_6: return GS_KEYCODE_NPSIX; break;
  491. case GLFW_KEY_KP_7: return GS_KEYCODE_NPSEVEN; break;
  492. case GLFW_KEY_KP_8: return GS_KEYCODE_NPEIGHT; break;
  493. case GLFW_KEY_KP_9: return GS_KEYCODE_NPNINE; break;
  494. case GLFW_KEY_CAPS_LOCK: return GS_KEYCODE_CAPS; break;
  495. case GLFW_KEY_DELETE: return GS_KEYCODE_DELETE; break;
  496. case GLFW_KEY_END: return GS_KEYCODE_END; break;
  497. case GLFW_KEY_F1: return GS_KEYCODE_F1; break;
  498. case GLFW_KEY_F2: return GS_KEYCODE_F2; break;
  499. case GLFW_KEY_F3: return GS_KEYCODE_F3; break;
  500. case GLFW_KEY_F4: return GS_KEYCODE_F4; break;
  501. case GLFW_KEY_F5: return GS_KEYCODE_F5; break;
  502. case GLFW_KEY_F6: return GS_KEYCODE_F6; break;
  503. case GLFW_KEY_F7: return GS_KEYCODE_F7; break;
  504. case GLFW_KEY_F8: return GS_KEYCODE_F8; break;
  505. case GLFW_KEY_F9: return GS_KEYCODE_F9; break;
  506. case GLFW_KEY_F10: return GS_KEYCODE_F10; break;
  507. case GLFW_KEY_F11: return GS_KEYCODE_F11; break;
  508. case GLFW_KEY_F12: return GS_KEYCODE_F12; break;
  509. case GLFW_KEY_HOME: return GS_KEYCODE_HOME; break;
  510. case GLFW_KEY_EQUAL: return GS_KEYCODE_PLUS; break;
  511. case GLFW_KEY_MINUS: return GS_KEYCODE_MINUS; break;
  512. case GLFW_KEY_LEFT_BRACKET: return GS_KEYCODE_LBRACKET; break;
  513. case GLFW_KEY_RIGHT_BRACKET: return GS_KEYCODE_RBRACKET; break;
  514. case GLFW_KEY_SEMICOLON: return GS_KEYCODE_SEMI_COLON; break;
  515. case GLFW_KEY_ENTER: return GS_KEYCODE_ENTER; break;
  516. case GLFW_KEY_INSERT: return GS_KEYCODE_INSERT; break;
  517. case GLFW_KEY_PAGE_UP: return GS_KEYCODE_PGUP; break;
  518. case GLFW_KEY_PAGE_DOWN: return GS_KEYCODE_PGDOWN; break;
  519. case GLFW_KEY_NUM_LOCK: return GS_KEYCODE_NUMLOCK; break;
  520. case GLFW_KEY_TAB: return GS_KEYCODE_TAB; break;
  521. case GLFW_KEY_KP_MULTIPLY: return GS_KEYCODE_NPMULT; break;
  522. case GLFW_KEY_KP_DIVIDE: return GS_KEYCODE_NPDIV; break;
  523. case GLFW_KEY_KP_ADD: return GS_KEYCODE_NPPLUS; break;
  524. case GLFW_KEY_KP_SUBTRACT: return GS_KEYCODE_NPMINUS; break;
  525. case GLFW_KEY_KP_ENTER: return GS_KEYCODE_NPENTER; break;
  526. case GLFW_KEY_KP_DECIMAL: return GS_KEYCODE_NPDEL; break;
  527. case GLFW_KEY_PAUSE: return GS_KEYCODE_PAUSE; break;
  528. case GLFW_KEY_PRINT_SCREEN: return GS_KEYCODE_PRINT; break;
  529. case GLFW_KEY_UNKNOWN: return GS_KEYCODE_COUNT; break;
  530. }
  531. // Shouldn't reach here
  532. return GS_KEYCODE_COUNT;
  533. }
  534. gs_platform_mouse_button_code __glfw_button_to_gs_mouse_button(s32 code)
  535. {
  536. switch (code)
  537. {
  538. case GLFW_MOUSE_BUTTON_LEFT: return GS_MOUSE_LBUTTON; break;
  539. case GLFW_MOUSE_BUTTON_RIGHT: return GS_MOUSE_RBUTTON; break;
  540. case GLFW_MOUSE_BUTTON_MIDDLE: return GS_MOUSE_MBUTTON; break;
  541. }
  542. // Shouldn't reach here
  543. return GS_MOUSE_BUTTON_CODE_COUNT;
  544. }
  545. void __glfw_key_callback(GLFWwindow* window, s32 key, s32 scancode, s32 action, s32 mods)
  546. {
  547. // Grab platform instance from engine
  548. gs_platform_i* platform = gs_engine_subsystem(platform);
  549. // Get keycode from key
  550. gs_platform_keycode code = glfw_key_to_gs_keycode(key);
  551. switch (action)
  552. {
  553. // Released
  554. case 0: {
  555. gs_platform_release_key(code);
  556. } break;
  557. // Pressed
  558. case 1: {
  559. gs_platform_press_key(code);
  560. } break;
  561. default: {
  562. } break;
  563. }
  564. }
  565. void __glfw_mouse_button_callback(GLFWwindow* window, s32 button, s32 action, s32 mods)
  566. {
  567. // Grab platform instance from engine
  568. gs_platform_i* platform = gs_engine_subsystem(platform);
  569. // Get mouse code from key
  570. gs_platform_mouse_button_code code = __glfw_button_to_gs_mouse_button(button);
  571. switch (action)
  572. {
  573. // Released
  574. case 0:
  575. {
  576. gs_platform_release_mouse_button(code);
  577. } break;
  578. // Pressed
  579. case 1:
  580. {
  581. gs_platform_press_mouse_button(code);
  582. } break;
  583. }
  584. }
  585. void __glfw_mouse_cursor_position_callback(GLFWwindow* window, f64 x, f64 y)
  586. {
  587. gs_platform_i* platform = gs_engine_subsystem(platform);
  588. platform->input.mouse.position = (gs_vec2){x, y};
  589. platform->input.mouse.moved_this_frame = true;
  590. }
  591. void __glfw_mouse_scroll_wheel_callback(GLFWwindow* window, f64 x, f64 y)
  592. {
  593. gs_platform_i* platform = gs_engine_subsystem(platform);
  594. platform->input.mouse.wheel = (gs_vec2){(f32)x, (f32)y};
  595. }
  596. // Gets called when mouse enters or leaves frame of window
  597. void __glfw_mouse_cursor_enter_callback(GLFWwindow* window, s32 entered)
  598. {
  599. // Nothing for now, will capture state for windows later
  600. }
  601. void __glfw_frame_buffer_size_callback(GLFWwindow* window, s32 width, s32 height)
  602. {
  603. // gs_graphics_i* gfx = gs_engine_instance()->ctx.graphics;
  604. // if (gfx)
  605. // {
  606. // gfx->set_viewport(width, height);
  607. //}
  608. }
  609. /*== Platform Input == */
  610. gs_result gs_platform_process_input(gs_platform_input_t* input)
  611. {
  612. glfwPollEvents();
  613. return GS_RESULT_IN_PROGRESS;
  614. }
  615. /*== Platform Util == */
  616. void gs_platform_sleep(float ms)
  617. {
  618. #if (defined GS_PLATFORM_WIN)
  619. _sleep(ms);
  620. #elif (defined GS_PLATFORM_APPLE)
  621. usleep(ms * 1000.f); // unistd.h
  622. #else
  623. usleep(ms * 1000.f); // unistd.h
  624. #endif
  625. }
  626. double gs_platform_elapsed_time()
  627. {
  628. return (glfwGetTime() * 1000.0);
  629. }
  630. /*== Platform Video == */
  631. void gs_platform_enable_vsync(int32_t enabled)
  632. {
  633. glfwSwapInterval(enabled ? 1 : 0);
  634. }
  635. /*== Platform Window == */
  636. void* gs_platform_create_window_internal(const char* title, uint32_t width, uint32_t height)
  637. {
  638. // Grab window hints from application desc
  639. u32 window_hints = gs_engine_instance()->ctx.app.window_flags;
  640. // Set whether or not the screen is resizable
  641. glfwWindowHint(GLFW_RESIZABLE, (window_hints & GS_WINDOW_FLAGS_RESIZABLE) == GS_WINDOW_FLAGS_RESIZABLE);
  642. GLFWwindow* window = glfwCreateWindow(width, height, title, NULL, NULL);
  643. if (window == NULL)
  644. {
  645. gs_println("Failed to create window.");
  646. glfwTerminate();
  647. return NULL;
  648. }
  649. glfwMakeContextCurrent(window);
  650. glfwSetKeyCallback(window, &__glfw_key_callback);
  651. glfwSetMouseButtonCallback(window, &__glfw_mouse_button_callback);
  652. glfwSetCursorPosCallback(window, &__glfw_mouse_cursor_position_callback);
  653. // Need to make sure this is ONLY done once.
  654. if (gs_slot_array_empty(gs_engine_subsystem(platform)->windows))
  655. {
  656. if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
  657. {
  658. gs_println("Failed to initialize GLFW.");
  659. return NULL;
  660. }
  661. switch (gs_engine_subsystem(platform)->settings.video.driver)
  662. {
  663. case GS_PLATFORM_VIDEO_DRIVER_TYPE_OPENGL:
  664. {
  665. gs_println("OpenGL Version: %s", glGetString(GL_VERSION));
  666. } break;
  667. default: break;
  668. }
  669. }
  670. return window;
  671. }
  672. void gs_platform_set_dropped_files_callback(uint32_t handle, gs_dropped_files_callback_t cb)
  673. {
  674. gs_platform_i* platform = gs_engine_subsystem(platform);
  675. GLFWwindow* win = __glfw_window_from_handle(platform, handle);
  676. glfwSetDropCallback(win, (GLFWdropfun)cb);
  677. }
  678. void gs_platform_set_window_close_callback(uint32_t handle, gs_window_close_callback_t cb)
  679. {
  680. gs_platform_i* platform = gs_engine_subsystem(platform);
  681. GLFWwindow* win = __glfw_window_from_handle(platform, handle);
  682. glfwSetWindowCloseCallback(win, (GLFWwindowclosefun)cb);
  683. }
  684. void gs_platform_set_mouse_position(uint32_t handle, float x, float y)
  685. {
  686. struct gs_platform_i* platform = gs_engine_subsystem(platform);
  687. GLFWwindow* win = __glfw_window_from_handle(platform, handle);
  688. glfwSetCursorPos(win, x, y);
  689. }
  690. void* gs_platform_raw_window_handle(uint32_t handle)
  691. {
  692. // Grab instance of platform from engine
  693. gs_platform_i* platform = gs_engine_subsystem(platform);
  694. // Grab window from handle
  695. GLFWwindow* win = __glfw_window_from_handle(platform, handle);
  696. return (void*)win;
  697. }
  698. void gs_platform_window_swap_buffer(uint32_t handle)
  699. {
  700. // Grab instance of platform from engine
  701. gs_platform_i* platform = gs_engine_subsystem(platform);
  702. // Grab window from handle
  703. GLFWwindow* win = __glfw_window_from_handle(platform, handle);
  704. glfwSwapBuffers(win);
  705. }
  706. gs_vec2 gs_platform_window_sizev(uint32_t handle)
  707. {
  708. GLFWwindow* win = __glfw_window_from_handle(gs_engine_subsystem(platform), handle);
  709. uint32_t w, h;
  710. glfwGetWindowSize(win, &w, &h);
  711. return gs_v2(w, h);
  712. }
  713. void gs_platform_window_size(uint32_t handle, uint32_t* w, uint32_t* h)
  714. {
  715. GLFWwindow* win = __glfw_window_from_handle(gs_engine_instance()->ctx.platform, handle);
  716. glfwGetWindowSize(win, w, h);
  717. }
  718. uint32_t gs_platform_window_width(uint32_t handle)
  719. {
  720. GLFWwindow* win = __glfw_window_from_handle(gs_engine_instance()->ctx.platform, handle);
  721. uint32_t w, h;
  722. glfwGetWindowSize(win, &w, &h);
  723. return w;
  724. }
  725. uint32_t gs_platform_window_height(uint32_t handle)
  726. {
  727. GLFWwindow* win = __glfw_window_from_handle(gs_engine_instance()->ctx.platform, handle);
  728. uint32_t w, h;
  729. glfwGetWindowSize(win, &w, &h);
  730. return h;
  731. }
  732. void gs_platform_set_window_size(uint32_t handle, uint32_t w, uint32_t h)
  733. {
  734. GLFWwindow* win = __glfw_window_from_handle(gs_engine_subsystem(platform), handle);
  735. glfwSetWindowSize(win, w, h);
  736. }
  737. void gs_platform_set_window_sizev(uint32_t handle, gs_vec2 v)
  738. {
  739. GLFWwindow* win = __glfw_window_from_handle(gs_engine_subsystem(platform), handle);
  740. glfwSetWindowSize(win, (uint32_t)v.x, (uint32_t)v.y);
  741. }
  742. void gs_platform_framebuffer_size(uint32_t handle, uint32_t* w, uint32_t* h)
  743. {
  744. GLFWwindow* win = __glfw_window_from_handle(gs_engine_subsystem(platform), handle);
  745. float xscale = 0.f, yscale = 0.f;
  746. glfwGetWindowContentScale(win, &xscale, &yscale);
  747. glfwGetWindowSize(win, w, h);
  748. *w = (uint32_t)((float)*w * xscale);
  749. *h = (uint32_t)((float)*h * yscale);
  750. }
  751. gs_vec2 gs_platform_framebuffer_sizev(uint32_t handle)
  752. {
  753. uint32_t w = 0, h = 0;
  754. gs_platform_framebuffer_size(handle, &w, &h);
  755. return (gs_vec2){w, h};
  756. }
  757. uint32_t gs_platform_framebuffer_width(uint32_t handle)
  758. {
  759. uint32_t w = 0, h = 0;
  760. gs_platform_framebuffer_size(handle, &w, &h);
  761. return w;
  762. }
  763. uint32_t gs_platform_framebuffer_height(uint32_t handle)
  764. {
  765. uint32_t w = 0, h = 0;
  766. gs_platform_framebuffer_size(handle, &w, &h);
  767. return h;
  768. }
  769. void gs_platform_set_cursor(uint32_t handle, gs_platform_cursor cursor)
  770. {
  771. gs_platform_i* platform = gs_engine_subsystem(platform);
  772. GLFWwindow* win = __glfw_window_from_handle(platform, handle);
  773. GLFWcursor* cp = ((GLFWcursor*)platform->cursors[(u32)cursor]);
  774. glfwSetCursor(win, cp);
  775. }
  776. #undef GS_PLATFORM_IMPL_GLFW
  777. #endif // GS_PLATFORM_IMPL_GLFW
  778. #endif // __GS_PLATFORM_IMPL_H__