main.c 22 KB

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