app.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. #ifndef APP_H
  2. #define APP_H
  3. #include <GL/glew.h>
  4. #include <SDL2/SDL.h>
  5. #include "ht.h"
  6. #include "da.h"
  7. #include "vec2.h"
  8. #include "window.h"
  9. #include "buffer.h"
  10. DA_DEF_STRUCT(struct buffer, app_buffers);
  11. enum keybind_dir {
  12. DIR_NO = -1,
  13. DIR_FORWARD = 0,
  14. DIR_BACKWARD,
  15. };
  16. struct app;
  17. typedef void (*keybind_func)(struct app *, enum keybind_dir);
  18. struct app_kbd {
  19. SDL_Keymod mod;
  20. keybind_func func;
  21. enum keybind_dir dir;
  22. };
  23. HT_DEF_STRUCT(struct app_kbd, app_kbd_ht);
  24. struct app {
  25. struct window win;
  26. SDL_Renderer *rdr;
  27. SDL_GLContext glctx;
  28. struct buffer *cbuf;
  29. struct app_buffers bufs;
  30. bool running;
  31. uint64_t target_fps;
  32. double dt;
  33. uint32_t last_press;
  34. SDL_KeyCode last_pressed_key;
  35. struct {
  36. uint8_t tab_size;
  37. } cfg;
  38. bool show_fps;
  39. struct free_glyph_atlas *fga;
  40. struct cursor_render *cr;
  41. struct app_kbd_ht kbds;
  42. };
  43. #include "free_glyph.h"
  44. struct ret_app_vec2 {
  45. struct app f1;
  46. struct vec2 f2;
  47. };
  48. struct app app_create(const char *win_title);
  49. void app_destroy(struct app app);
  50. void app_set_text_color(struct app app, uint32_t color);
  51. uint32_t app_get_text_color(struct app app);
  52. void app_render_cursor_in_pos(struct app app, struct vec2 pos, uint32_t color);
  53. void app_render_cursor(struct app app, uint32_t color);
  54. void app_render_char(struct app app, const char c, struct vec2 pos,
  55. double scale);
  56. void app_render_buffer(struct app app, struct vec2 pos,
  57. uint32_t color, double scale);
  58. void app_render_text(struct app app, const char *text, size_t text_size,
  59. struct vec2 pos, uint32_t color, double scale);
  60. struct vec2 app_calc_cur_pos(struct app app);
  61. void MessageCallback(GLenum source, GLenum type, GLuint id,
  62. GLenum severity, GLsizei length,
  63. const GLchar *msg, const void *up);
  64. struct vec2i app_calc_cursor(struct app app);
  65. struct ret_app_vec2 app_calc_buffer_cam(struct app app, double dt);
  66. void app_add_global_keybind(struct app *app, const char *keybind,
  67. keybind_func func, enum keybind_dir dir);
  68. #if defined(APP_IMP) || defined(IMP)
  69. #define UNHEX_COLOR(hex) \
  70. (uint8_t) ((hex >> 24) & 0xFF), \
  71. (uint8_t) ((hex >> 16) & 0xFF), \
  72. (uint8_t) ((hex >> 8 ) & 0xFF), \
  73. (uint8_t) ((hex >> 0 ) & 0xFF)
  74. #include "sc.h"
  75. #include "str.h"
  76. #include "char.h"
  77. struct app
  78. app_create(const char *win_title)
  79. {
  80. SCE(SDL_Init(SDL_INIT_VIDEO));
  81. struct app app = {
  82. .win = window_create(win_title),
  83. .rdr = NULL,
  84. .running = true,
  85. .cfg = {
  86. .tab_size = 8
  87. },
  88. .target_fps = 120,
  89. };
  90. HT_CREATE(app.kbds, 16);
  91. app.kbds.hash = ht_hash_nop;
  92. DA_CREATE(app.bufs);
  93. DA_APPEND(app.bufs, buffer_create());
  94. app.cbuf = &app.bufs.items[0];
  95. app.dt = (1.0 / (double)app.target_fps) * 3;
  96. {
  97. SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
  98. SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
  99. SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
  100. SDL_GL_CONTEXT_PROFILE_CORE);
  101. int32_t major = 0;
  102. int32_t minor = 0;
  103. SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
  104. SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
  105. printf("GL Version: %d.%d\n", major, minor);
  106. }
  107. /* SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, GL_DOUBLEBUFFER); */
  108. /* SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); */
  109. /* SDL_GL_SetSwapInterval(0); */
  110. app.glctx = SDL_GL_CreateContext(app.win.ptr);
  111. SCP(app.glctx);
  112. if ( GLEW_OK != glewInit() ) {
  113. fprintf(stderr, "Could Not Initilize GLEW!\n");
  114. exit(EXIT_FAILURE);
  115. }
  116. if ( ! GLEW_ARB_draw_instanced ) {
  117. fprintf(stderr,
  118. "WARNING! GLEW_ARB_draw_instanced is not availible\n");
  119. exit(EXIT_FAILURE);
  120. }
  121. if ( ! GLEW_ARB_instanced_arrays ) {
  122. fprintf(stderr,
  123. "WARNING! GLEW_ARB_instanced_arrays"
  124. " is not availible\n");
  125. exit(EXIT_FAILURE);
  126. }
  127. if ( GLEW_ARB_debug_output ) {
  128. glEnable(GL_DEBUG_OUTPUT);
  129. glDebugMessageCallback(MessageCallback, 0);
  130. } else {
  131. fprintf(stderr,
  132. "WARNING! GLEW_ARB_debug_output is not availible\n");
  133. }
  134. glEnable(GL_BLEND);
  135. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  136. return app;
  137. }
  138. void
  139. app_destroy(struct app app)
  140. {
  141. SDL_DestroyWindow(app.win.ptr);
  142. SDL_GL_DeleteContext(app.glctx);
  143. free(app.cbuf->data.items);
  144. SDL_Quit();
  145. }
  146. #define BRANCHLESS_IF(cond, when_true, when_false) \
  147. (((cond)) * (when_true) + (!(cond)) * (when_false))
  148. struct vec2
  149. app_calc_cur_pos(struct app app)
  150. {
  151. size_t col = 0;
  152. size_t row = buffer_calc_cur_row(app.cbuf);
  153. enum buffer_err err;
  154. /* RET_UNWRAP2(col, row, */
  155. /* struct ret_size_t_size_t, */
  156. /* buffer_calc_cur_pos(app.buf)); */
  157. size_t start_line;
  158. start_line = buffer_index_bw_char(app.cbuf, '\n', app.cbuf->cur, &err);
  159. col = (app.cbuf->cur - start_line) - 1;
  160. if ( err == BUFFER_ERR_NOT_FOUND ) {
  161. col = app.cbuf->cur;
  162. }
  163. size_t tabs_n = 0;
  164. tabs_n = buffer_count_char_between(app.cbuf, '\t', start_line,
  165. app.cbuf->cur, &err);
  166. col += ( tabs_n > 0 ) * ((tabs_n * app.cfg.tab_size) - tabs_n);
  167. double row_px = -(((double)row)
  168. * app.fga->atlas_dim.y);
  169. double col_px = (((double) col)
  170. * ((double) 1));
  171. return vec2(col_px, row_px);
  172. }
  173. void
  174. MessageCallback(GLenum source, GLenum type, GLuint id,
  175. GLenum severity, GLsizei length,
  176. const GLchar *msg, const void *up)
  177. {
  178. (void) source; (void) id; (void) length; (void) up;
  179. fprintf(stderr,
  180. "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
  181. (type == GL_DEBUG_TYPE_ERROR ? "*** GL ERROR ***" : ""),
  182. type, severity, msg);
  183. }
  184. struct vec2i
  185. app_calc_cursor(struct app app)
  186. {
  187. size_t row, col;
  188. RET_UNWRAP2(col, row,
  189. struct ret_size_t_size_t, buffer_calc_cur_pos(app.cbuf));
  190. return vec2i((int32_t)col, (int32_t)row);
  191. }
  192. struct ret_app_vec2
  193. app_calc_buffer_cam(struct app app, double dt)
  194. {
  195. struct vec2 cur_pos = app_calc_cur_pos(app);
  196. struct vec2 cpos = app.cbuf->cam.pos;
  197. struct vec2 cvel = app.cbuf->cam.vel;
  198. cvel = vec2_sub(cur_pos, cpos);
  199. cpos = vec2_add(cpos, vec2_mul(cvel, vec2s(dt)));
  200. app.cbuf->cam.pos = cpos;
  201. app.cbuf->cam.vel = cvel;
  202. return (struct ret_app_vec2) {
  203. .f1 = app,
  204. .f2 = cpos
  205. };
  206. }
  207. static SDL_KeyCode
  208. char_to_keycode(char c)
  209. {
  210. return char_to_lower(c);
  211. }
  212. static SDL_KeyCode
  213. str_to_keycode(struct str str)
  214. {
  215. if ( str_eq_cstr(str, "<left>", 6) ) {
  216. return SDLK_LEFT;
  217. }
  218. if ( str_eq_cstr(str, "<down>", 6) ) {
  219. return SDLK_DOWN;
  220. }
  221. if ( str_eq_cstr(str, "<up>", 4) ) {
  222. return SDLK_UP;
  223. }
  224. if ( str_eq_cstr(str, "<right>", 7) ) {
  225. return SDLK_RIGHT;
  226. }
  227. if ( str_eq_cstr(str, "<delete>", 8) ) {
  228. return SDLK_DELETE;
  229. }
  230. if ( str_eq_cstr(str, "<backspace>", 11) ) {
  231. return SDLK_BACKSPACE;
  232. }
  233. return SDLK_UNKNOWN;
  234. }
  235. static SDL_Keymod
  236. char_to_keymod(char c)
  237. {
  238. switch ( c ) {
  239. case 'N': return KMOD_NONE; break;
  240. /* case '': return KMOD_LSHIFT; break; */
  241. /* case '': return KMOD_RSHIFT; break; */
  242. /* case '': return KMOD_LCTRL; break; */
  243. /* case '': return KMOD_RCTRL; break; */
  244. /* case '': return KMOD_LALT; break; */
  245. /* case '': return KMOD_RALT; break; */
  246. /* case '': return KMOD_LGUI; break; */
  247. /* case '': return KMOD_RGUI; break; */
  248. /* case '': return KMOD_NUM; break; */
  249. /* case '': return KMOD_CAPS; break; */
  250. /* case '': return KMOD_MODE; break; */
  251. /* case '': return KMOD_SCROLL; break; */
  252. case 'C': return KMOD_CTRL; break;
  253. case 'S': return KMOD_SHIFT; break;
  254. case 'A': return KMOD_ALT; break;
  255. case 'M': return KMOD_GUI; break;
  256. default: return -1; break;
  257. }
  258. }
  259. #define IF_GOTO(cond, to) \
  260. if ( (cond) ) { \
  261. fprintf(stderr, #cond"\n"); \
  262. goto to; \
  263. }
  264. void
  265. app_add_global_keybind(struct app *app, const char *keybind,
  266. keybind_func func,
  267. enum keybind_dir dir)
  268. {
  269. struct str kbd_str = str_from_cstr_ns(keybind);
  270. if ( kbd_str.size == 1 ) {
  271. SDL_KeyCode key = char_to_keycode(kbd_str.data[0]);
  272. IF_GOTO(key == SDLK_UNKNOWN, invalid_key);
  273. struct app_kbd kbd = {
  274. .mod = KMOD_NONE,
  275. .func = func,
  276. .dir = dir
  277. };
  278. HT_ISET(app->kbds, (int64_t)(key), kbd);
  279. return;
  280. }
  281. if ( kbd_str.data[0] == '<' ) {
  282. IF_GOTO(str_contain_char(kbd_str, '-'), invalid_key)
  283. SDL_KeyCode key = str_to_keycode(kbd_str);
  284. IF_GOTO(key == SDLK_UNKNOWN, invalid_key);
  285. struct app_kbd kbd = {
  286. .mod = KMOD_NONE,
  287. .func = func,
  288. .dir = dir
  289. };
  290. HT_ISET(app->kbds, (int64_t)(key), kbd);
  291. return;
  292. }
  293. struct str_da words = str_split(kbd_str, ' ');
  294. IF_GOTO(words.size != 1, invalid_key);
  295. /* for */ {
  296. struct str_da chars = str_split(words.items[0], '-');
  297. IF_GOTO(chars.size != 2, invalid_key)
  298. IF_GOTO(chars.items[0].size != 1, invalid_key)
  299. IF_GOTO(chars.items[1].size != 1, invalid_key)
  300. SDL_Keymod mod = char_to_keymod(chars.items[0].data[0]);
  301. IF_GOTO((int32_t)(mod) == -1, invalid_key);
  302. SDL_KeyCode key = char_to_keycode(chars.items[1].data[0]);
  303. IF_GOTO(key == SDLK_UNKNOWN, invalid_key);
  304. DA_DESTROY(chars);
  305. struct app_kbd kbd = {
  306. .mod = mod,
  307. .func = func,
  308. .dir = dir
  309. };
  310. HT_ISET(app->kbds, (int64_t)(key + mod), kbd);
  311. }
  312. DA_DESTROY(words);
  313. return;
  314. invalid_key: ;
  315. fprintf(stderr, "[ERROR] Invalid keybind `%s`\n",
  316. keybind);
  317. exit(EXIT_FAILURE);
  318. }
  319. #endif /* defined(APP_IMP) || defined(IMP) */
  320. #endif