main.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. #include <assert.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdarg.h>
  5. #include <stdbool.h>
  6. #include <string.h>
  7. #include <errno.h>
  8. #include <math.h>
  9. #define GLFW_INCLUDE_GLEXT
  10. #include <GLFW/glfw3.h>
  11. #define LA_IMPLEMENTATION
  12. #include "la.h"
  13. #define SV_IMPLEMENTATION
  14. #include "sv.h"
  15. #define DEFAULT_SCREEN_WIDTH 1600
  16. #define DEFAULT_SCREEN_HEIGHT 900
  17. #define MANUAL_TIME_STEP 0.1
  18. #include "glextloader.c"
  19. #define STB_IMAGE_IMPLEMENTATION
  20. #include "stb_image.h"
  21. #define STB_IMAGE_WRITE_IMPLEMENTATION
  22. #include "stb_image_write.h"
  23. char *slurp_file_into_malloced_cstr(const char *file_path)
  24. {
  25. FILE *f = NULL;
  26. char *buffer = NULL;
  27. f = fopen(file_path, "r");
  28. if (f == NULL) goto fail;
  29. if (fseek(f, 0, SEEK_END) < 0) goto fail;
  30. long size = ftell(f);
  31. if (size < 0) goto fail;
  32. buffer = malloc(size + 1);
  33. if (buffer == NULL) goto fail;
  34. if (fseek(f, 0, SEEK_SET) < 0) goto fail;
  35. fread(buffer, 1, size, f);
  36. if (ferror(f)) goto fail;
  37. buffer[size] = '\0';
  38. if (f) {
  39. fclose(f);
  40. errno = 0;
  41. }
  42. return buffer;
  43. fail:
  44. if (f) {
  45. int saved_errno = errno;
  46. fclose(f);
  47. errno = saved_errno;
  48. }
  49. if (buffer) {
  50. free(buffer);
  51. }
  52. return NULL;
  53. }
  54. const char *shader_type_as_cstr(GLuint shader)
  55. {
  56. switch (shader) {
  57. case GL_VERTEX_SHADER:
  58. return "GL_VERTEX_SHADER";
  59. case GL_FRAGMENT_SHADER:
  60. return "GL_FRAGMENT_SHADER";
  61. default:
  62. return "(Unknown)";
  63. }
  64. }
  65. bool compile_shader_source(const GLchar *source, GLenum shader_type, GLuint *shader)
  66. {
  67. *shader = glCreateShader(shader_type);
  68. glShaderSource(*shader, 1, &source, NULL);
  69. glCompileShader(*shader);
  70. GLint compiled = 0;
  71. glGetShaderiv(*shader, GL_COMPILE_STATUS, &compiled);
  72. if (!compiled) {
  73. GLchar message[1024];
  74. GLsizei message_size = 0;
  75. glGetShaderInfoLog(*shader, sizeof(message), &message_size, message);
  76. fprintf(stderr, "ERROR: could not compile %s\n", shader_type_as_cstr(shader_type));
  77. fprintf(stderr, "%.*s\n", message_size, message);
  78. return false;
  79. }
  80. return true;
  81. }
  82. bool compile_shader_file(const char *file_path, GLenum shader_type, GLuint *shader)
  83. {
  84. char *source = slurp_file_into_malloced_cstr(file_path);
  85. if (source == NULL) {
  86. fprintf(stderr, "ERROR: failed to read file `%s`: %s\n", file_path, strerror(errno));
  87. errno = 0;
  88. return false;
  89. }
  90. bool ok = compile_shader_source(source, shader_type, shader);
  91. if (!ok) {
  92. fprintf(stderr, "ERROR: failed to compile `%s` shader file\n", file_path);
  93. }
  94. free(source);
  95. return ok;
  96. }
  97. bool link_program(GLuint vert_shader, GLuint frag_shader, GLuint *program)
  98. {
  99. *program = glCreateProgram();
  100. glAttachShader(*program, vert_shader);
  101. glAttachShader(*program, frag_shader);
  102. glLinkProgram(*program);
  103. GLint linked = 0;
  104. glGetProgramiv(*program, GL_LINK_STATUS, &linked);
  105. if (!linked) {
  106. GLsizei message_size = 0;
  107. GLchar message[1024];
  108. glGetProgramInfoLog(*program, sizeof(message), &message_size, message);
  109. fprintf(stderr, "Program Linking: %.*s\n", message_size, message);
  110. }
  111. glDeleteShader(vert_shader);
  112. glDeleteShader(frag_shader);
  113. return program;
  114. }
  115. typedef enum {
  116. RESOLUTION_UNIFORM = 0,
  117. TIME_UNIFORM,
  118. MOUSE_UNIFORM,
  119. COUNT_UNIFORMS
  120. } Uniform;
  121. static_assert(COUNT_UNIFORMS == 3, "Update list of uniform names");
  122. static const char *uniform_names[COUNT_UNIFORMS] = {
  123. [RESOLUTION_UNIFORM] = "resolution",
  124. [TIME_UNIFORM] = "time",
  125. [MOUSE_UNIFORM] = "mouse",
  126. };
  127. typedef enum {
  128. VA_POS = 0,
  129. VA_UV,
  130. VA_COLOR,
  131. COUNT_VAS,
  132. } Vertex_Attrib;
  133. typedef struct {
  134. V2f pos;
  135. V2f uv;
  136. V4f color;
  137. } Vertex;
  138. #define VERTEX_BUF_CAP (8 * 1024)
  139. typedef struct {
  140. bool reload_failed;
  141. GLuint vao;
  142. GLuint vbo;
  143. GLuint program;
  144. GLint uniforms[COUNT_UNIFORMS];
  145. Vertex vertex_buf[VERTEX_BUF_CAP];
  146. size_t vertex_buf_sz;
  147. GLuint texture;
  148. } Renderer;
  149. // Global variables (fragile people with CS degree look away)
  150. static double time = 0.0;
  151. static bool pause = false;
  152. static Renderer global_renderer = {0};
  153. void r_vertex(Renderer *r, V2f pos, V2f uv, V4f color)
  154. {
  155. assert(r->vertex_buf_sz < VERTEX_BUF_CAP);
  156. r->vertex_buf[r->vertex_buf_sz].pos = pos;
  157. r->vertex_buf[r->vertex_buf_sz].uv = uv;
  158. r->vertex_buf[r->vertex_buf_sz].color = color;
  159. r->vertex_buf_sz += 1;
  160. }
  161. void r_quad_pp(Renderer *r, V2f p1, V2f p2, V4f color)
  162. {
  163. V2f a = p1;
  164. V2f b = v2f(p2.x, p1.y);
  165. V2f c = v2f(p1.x, p2.y);
  166. V2f d = p2;
  167. r_vertex(r, a, v2f(0.0f, 0.0f), color);
  168. r_vertex(r, b, v2f(1.0f, 0.0f), color);
  169. r_vertex(r, c, v2f(0.0f, 1.0f), color);
  170. r_vertex(r, b, v2f(1.0f, 0.0f), color);
  171. r_vertex(r, c, v2f(0.0f, 1.0f), color);
  172. r_vertex(r, d, v2f(1.0f, 1.0f), color);
  173. }
  174. void r_quad_cr(Renderer *r, V2f center, V2f radius, V4f color)
  175. {
  176. r_quad_pp(r, v2f_sub(center, radius), v2f_sum(center, radius), color);
  177. }
  178. void r_sync_buffers(Renderer *r)
  179. {
  180. glBufferSubData(GL_ARRAY_BUFFER,
  181. 0,
  182. sizeof(Vertex) * r->vertex_buf_sz,
  183. r->vertex_buf);
  184. }
  185. void r_sync_uniforms(Renderer *r,
  186. GLfloat resolution_width, GLfloat resolution_height,
  187. GLfloat time,
  188. GLfloat mouse_x, GLfloat mouse_y)
  189. {
  190. static_assert(COUNT_UNIFORMS == 3, "Exhaustive uniform handling in ");
  191. glUniform2f(r->uniforms[RESOLUTION_UNIFORM], resolution_width, resolution_height);
  192. glUniform1f(r->uniforms[TIME_UNIFORM], time);
  193. glUniform2f(r->uniforms[MOUSE_UNIFORM], mouse_x, mouse_y);
  194. }
  195. bool load_shader_program(const char *vertex_file_path,
  196. const char *fragment_file_path,
  197. GLuint *program)
  198. {
  199. GLuint vert = 0;
  200. if (!compile_shader_file(vertex_file_path, GL_VERTEX_SHADER, &vert)) {
  201. return false;
  202. }
  203. GLuint frag = 0;
  204. if (!compile_shader_file(fragment_file_path, GL_FRAGMENT_SHADER, &frag)) {
  205. return false;
  206. }
  207. if (!link_program(vert, frag, program)) {
  208. return false;
  209. }
  210. return true;
  211. }
  212. static char *render_conf = NULL;
  213. const char *vert_path = NULL;
  214. const char *frag_path = NULL;
  215. const char *texture_path = NULL;
  216. void reload_render_conf(const char *render_conf_path)
  217. {
  218. if (render_conf) free(render_conf);
  219. render_conf = slurp_file_into_malloced_cstr(render_conf_path);
  220. if (render_conf == NULL) {
  221. fprintf(stderr, "ERROR: could not load %s: %s\n", render_conf_path, strerror(errno));
  222. exit(1);
  223. }
  224. String_View content = sv_from_cstr(render_conf);
  225. vert_path = NULL;
  226. frag_path = NULL;
  227. texture_path = NULL;
  228. for (int row = 0; content.count > 0; row++) {
  229. String_View line = sv_chop_by_delim(&content, '\n');
  230. const char *line_start = line.data;
  231. line = sv_trim_left(line);
  232. if (line.count > 0 && line.data[0] != '#') {
  233. String_View key = sv_trim(sv_chop_by_delim(&line, '='));
  234. String_View value = sv_trim_left(line);
  235. ((char*)value.data)[value.count] = '\0';
  236. // ^^^SAFETY NOTES: this is needed so we can use `value` as a NULL-terminated C-string.
  237. // This should not cause any problems because the original string `render_conf`
  238. // that we are processing the `value` from is mutable, NULL-terminated and we are splitting
  239. // it by newlines which garantees that there is always a character after
  240. // the end of `value`.
  241. //
  242. // Let's consider an example where `render_conf` is equal to this:
  243. //
  244. // ```
  245. // key = value\n
  246. // key = value\n
  247. // key = value\0
  248. // ```
  249. //
  250. // There is always something after `value`. It's either `\n` or `\0`. With all of these
  251. // invariats in place writing to `value.data[value.count]` should be safe.
  252. if (sv_eq(key, SV("vert"))) {
  253. vert_path = value.data;
  254. printf("Vertex Path: %s\n", vert_path);
  255. } else if (sv_eq(key, SV("frag"))) {
  256. frag_path = value.data;
  257. printf("Fragment Path: %s\n", frag_path);
  258. } else if (sv_eq(key, SV("texture"))) {
  259. texture_path = value.data;
  260. printf("Texture Path: %s\n", texture_path);
  261. } else {
  262. printf("%s:%d:%ld: ERROR: unsupported key `"SV_Fmt"`\n",
  263. render_conf_path, row, key.data - line_start,
  264. SV_Arg(key));
  265. }
  266. }
  267. }
  268. }
  269. bool r_reload_textures(Renderer *r)
  270. {
  271. int texture_width, texture_height;
  272. unsigned char *texture_pixels = stbi_load(texture_path, &texture_width, &texture_height, NULL, 4);
  273. if (texture_pixels == NULL) {
  274. fprintf(stderr, "ERROR: could not load image %s: %s\n",
  275. texture_path, strerror(errno));
  276. return false;
  277. }
  278. glDeleteTextures(1, &r->texture);
  279. glGenTextures(1, &r->texture);
  280. glActiveTexture(GL_TEXTURE0);
  281. glBindTexture(GL_TEXTURE_2D, r->texture);
  282. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  283. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  284. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
  285. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
  286. glTexImage2D(GL_TEXTURE_2D,
  287. 0,
  288. GL_RGBA,
  289. texture_width,
  290. texture_height,
  291. 0,
  292. GL_RGBA,
  293. GL_UNSIGNED_BYTE,
  294. texture_pixels);
  295. stbi_image_free(texture_pixels);
  296. printf("Successfully reloaded textures\n");
  297. return true;
  298. }
  299. bool r_reload_shaders(Renderer *r)
  300. {
  301. glDeleteProgram(r->program);
  302. if (!load_shader_program(vert_path, frag_path, &r->program)) return false;
  303. glUseProgram(r->program);
  304. for (Uniform index = 0; index < COUNT_UNIFORMS; ++index) {
  305. r->uniforms[index] = glGetUniformLocation(r->program, uniform_names[index]);
  306. }
  307. printf("Successfully reloaded the Shaders\n");
  308. return true;
  309. }
  310. bool r_reload(Renderer *r)
  311. {
  312. r->reload_failed = true;
  313. if (!r_reload_shaders(r)) return false;
  314. if (!r_reload_textures(r)) return false;
  315. r->reload_failed = false;
  316. return true;
  317. }
  318. #define COLOR_BLACK_V4F ((V4f){0.0f, 0.0f, 0.0f, 1.0f})
  319. #define COLOR_RED_V4F ((V4f){1.0f, 0.0f, 0.0f, 1.0f})
  320. #define COLOR_GREEN_V4F ((V4f){0.0f, 1.0f, 0.0f, 1.0f})
  321. float t = 0.0f;
  322. float dt = 0.0f;
  323. V4f color = {0};
  324. void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
  325. {
  326. (void) scancode;
  327. (void) action;
  328. (void) mods;
  329. if (action == GLFW_PRESS) {
  330. if (key == GLFW_KEY_F5) {
  331. reload_render_conf("render.conf");
  332. dt = -2.0f;
  333. t = 1.0f;
  334. if (r_reload(&global_renderer)) {
  335. color = COLOR_GREEN_V4F;
  336. } else {
  337. color = COLOR_RED_V4F;
  338. }
  339. } else if (key == GLFW_KEY_F6) {
  340. #define SCREENSHOT_PNG_PATH "screenshot.png"
  341. printf("Saving the screenshot at %s\n", SCREENSHOT_PNG_PATH);
  342. int width, height;
  343. glfwGetWindowSize(window, &width, &height);
  344. void *pixels = malloc(4 * width * height);
  345. if (pixels == NULL) {
  346. fprintf(stderr, "ERROR: could not allocate memory for pixels to make a screenshot: %s\n",
  347. strerror(errno));
  348. return;
  349. }
  350. glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
  351. if (!stbi_write_png(SCREENSHOT_PNG_PATH, width, height, 4, pixels, width * 4)) {
  352. fprintf(stderr, "ERROR: could not save %s: %s\n", SCREENSHOT_PNG_PATH, strerror(errno));
  353. }
  354. free(pixels);
  355. } else if (key == GLFW_KEY_SPACE) {
  356. pause = !pause;
  357. } else if (key == GLFW_KEY_Q) {
  358. exit(1);
  359. }
  360. if (pause) {
  361. if (key == GLFW_KEY_LEFT) {
  362. time -= MANUAL_TIME_STEP;
  363. } else if (key == GLFW_KEY_RIGHT) {
  364. time += MANUAL_TIME_STEP;
  365. }
  366. }
  367. }
  368. }
  369. GLuint framebuffer;
  370. void window_size_callback(GLFWwindow* window, int width, int height)
  371. {
  372. (void) window;
  373. glViewport(0, 0, width, height);
  374. }
  375. void MessageCallback(GLenum source,
  376. GLenum type,
  377. GLuint id,
  378. GLenum severity,
  379. GLsizei length,
  380. const GLchar* message,
  381. const void* userParam)
  382. {
  383. (void) source;
  384. (void) id;
  385. (void) length;
  386. (void) userParam;
  387. fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
  388. (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
  389. type, severity, message);
  390. }
  391. void r_init(Renderer *r)
  392. {
  393. glGenVertexArrays(1, &r->vao);
  394. glBindVertexArray(r->vao);
  395. glGenBuffers(1, &r->vbo);
  396. glBindBuffer(GL_ARRAY_BUFFER, r->vbo);
  397. glBufferData(GL_ARRAY_BUFFER, sizeof(r->vertex_buf), r->vertex_buf, GL_DYNAMIC_DRAW);
  398. glEnableVertexAttribArray(VA_POS);
  399. glVertexAttribPointer(VA_POS,
  400. 2,
  401. GL_FLOAT,
  402. GL_FALSE,
  403. sizeof(Vertex),
  404. (void*) offsetof(Vertex, pos));
  405. glEnableVertexAttribArray(VA_UV);
  406. glVertexAttribPointer(VA_UV,
  407. 2,
  408. GL_FLOAT,
  409. GL_FALSE,
  410. sizeof(Vertex),
  411. (void*) offsetof(Vertex, uv));
  412. glEnableVertexAttribArray(VA_COLOR);
  413. glVertexAttribPointer(VA_COLOR,
  414. 4,
  415. GL_FLOAT,
  416. GL_FALSE,
  417. sizeof(Vertex),
  418. (void*) offsetof(Vertex, color));
  419. }
  420. void r_clear(Renderer *r)
  421. {
  422. r->vertex_buf_sz = 0;
  423. }
  424. int main(void)
  425. {
  426. reload_render_conf("render.conf");
  427. if (!glfwInit()) {
  428. fprintf(stderr, "ERROR: could not initialize GLFW\n");
  429. exit(1);
  430. }
  431. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  432. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  433. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  434. GLFWwindow * const window = glfwCreateWindow(
  435. DEFAULT_SCREEN_WIDTH,
  436. DEFAULT_SCREEN_HEIGHT,
  437. "OpenGL Template",
  438. NULL,
  439. NULL);
  440. if (window == NULL) {
  441. fprintf(stderr, "ERROR: could not create a window.\n");
  442. glfwTerminate();
  443. exit(1);
  444. }
  445. int gl_ver_major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
  446. int gl_ver_minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
  447. printf("OpenGL %d.%d\n", gl_ver_major, gl_ver_minor);
  448. glfwMakeContextCurrent(window);
  449. load_gl_extensions();
  450. if (glDrawArraysInstanced == NULL) {
  451. fprintf(stderr, "Support for EXT_draw_instanced is required!\n");
  452. exit(1);
  453. }
  454. if (glDebugMessageCallback != NULL) {
  455. glEnable(GL_DEBUG_OUTPUT);
  456. glDebugMessageCallback(MessageCallback, 0);
  457. }
  458. glEnable(GL_BLEND);
  459. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  460. GLuint framebuffer_texture;
  461. glGenTextures(1, &framebuffer_texture);
  462. glActiveTexture(GL_TEXTURE1);
  463. glBindTexture(GL_TEXTURE_2D, framebuffer_texture);
  464. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  465. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  466. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
  467. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
  468. glTexImage2D(
  469. GL_TEXTURE_2D,
  470. 0,
  471. GL_RGBA,
  472. DEFAULT_SCREEN_WIDTH,
  473. DEFAULT_SCREEN_HEIGHT,
  474. 0,
  475. GL_RGBA,
  476. GL_UNSIGNED_BYTE,
  477. NULL);
  478. glGenFramebuffers(1, &framebuffer);
  479. glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
  480. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebuffer_texture, 0);
  481. GLenum draw_buffers = GL_COLOR_ATTACHMENT0;
  482. glDrawBuffers(1, &draw_buffers);
  483. GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  484. if (status != GL_FRAMEBUFFER_COMPLETE) {
  485. fprintf(stderr, "ERROR: Could not complete the framebuffer\n");
  486. exit(1);
  487. }
  488. GLuint framebuffer_program;
  489. if (!load_shader_program("./shaders/debug.vert", "./shaders/debug.frag", &framebuffer_program)) {
  490. exit(1);
  491. }
  492. glUseProgram(framebuffer_program);
  493. GLuint framebuffer_tex_uniform = glGetUniformLocation(framebuffer_program, "tex");
  494. GLuint framebuffer_color_uniform = glGetUniformLocation(framebuffer_program, "color");
  495. GLuint framebuffer_t_uniform = glGetUniformLocation(framebuffer_program, "t");
  496. glUniform1i(framebuffer_tex_uniform, 1);
  497. glUniform4f(framebuffer_color_uniform, 1.0, 0.0, 0.0, 1.0);
  498. printf("Successfully created the debug framebuffer\n");
  499. Renderer *r = &global_renderer;
  500. r_init(r);
  501. r_reload(r);
  502. glfwSetKeyCallback(window, key_callback);
  503. glfwSetFramebufferSizeCallback(window, window_size_callback);
  504. time = glfwGetTime();
  505. double prev_time = 0.0;
  506. double delta_time = 0.0f;
  507. while (!glfwWindowShouldClose(window)) {
  508. glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
  509. glClear(GL_COLOR_BUFFER_BIT);
  510. int width, height;
  511. glfwGetWindowSize(window, &width, &height);
  512. double xpos, ypos;
  513. glfwGetCursorPos(window, &xpos, &ypos);
  514. xpos = xpos - width * 0.5f;
  515. ypos = (height - ypos) - height * 0.5f;
  516. // if (!r->reload_failed) {
  517. glUseProgram(r->program);
  518. r_clear(r);
  519. r_sync_uniforms(r, width, height, time, xpos, ypos);
  520. r_quad_cr(
  521. r,
  522. v2ff(0.0f),
  523. v2f_mul(v2f(width, height), v2ff(0.5f)),
  524. COLOR_BLACK_V4F);
  525. r_sync_buffers(r);
  526. glDrawArraysInstanced(GL_TRIANGLES, 0, (GLsizei) r->vertex_buf_sz, 1);
  527. // }
  528. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  529. glClear(GL_COLOR_BUFFER_BIT);
  530. glUseProgram(framebuffer_program);
  531. t += dt * delta_time;
  532. if (t <= 0.0f) {
  533. t = 0.0f;
  534. dt = 0.0f;
  535. }
  536. glUniform1f(framebuffer_t_uniform, t);
  537. glUniform4f(framebuffer_color_uniform, color.x, color.y, color.z, color.w);
  538. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  539. glfwSwapBuffers(window);
  540. glfwPollEvents();
  541. double cur_time = glfwGetTime();
  542. delta_time = cur_time - prev_time;
  543. if (!pause) {
  544. time += delta_time;
  545. }
  546. prev_time = cur_time;
  547. }
  548. return 0;
  549. }