main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  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 DEFAULT_SCREEN_WIDTH 1600
  14. #define DEFAULT_SCREEN_HEIGHT 900
  15. #define MANUAL_TIME_STEP 0.1
  16. #include "glextloader.c"
  17. char *slurp_file_into_malloced_cstr(const char *file_path)
  18. {
  19. FILE *f = NULL;
  20. char *buffer = NULL;
  21. f = fopen(file_path, "r");
  22. if (f == NULL) goto fail;
  23. if (fseek(f, 0, SEEK_END) < 0) goto fail;
  24. long size = ftell(f);
  25. if (size < 0) goto fail;
  26. buffer = malloc(size + 1);
  27. if (buffer == NULL) goto fail;
  28. if (fseek(f, 0, SEEK_SET) < 0) goto fail;
  29. fread(buffer, 1, size, f);
  30. if (ferror(f)) goto fail;
  31. buffer[size] = '\0';
  32. if (f) {
  33. fclose(f);
  34. errno = 0;
  35. }
  36. return buffer;
  37. fail:
  38. if (f) {
  39. int saved_errno = errno;
  40. fclose(f);
  41. errno = saved_errno;
  42. }
  43. if (buffer) {
  44. free(buffer);
  45. }
  46. return NULL;
  47. }
  48. const char *shader_type_as_cstr(GLuint shader)
  49. {
  50. switch (shader) {
  51. case GL_VERTEX_SHADER:
  52. return "GL_VERTEX_SHADER";
  53. case GL_FRAGMENT_SHADER:
  54. return "GL_FRAGMENT_SHADER";
  55. default:
  56. return "(Unknown)";
  57. }
  58. }
  59. bool compile_shader_source(const GLchar *source, GLenum shader_type, GLuint *shader)
  60. {
  61. *shader = glCreateShader(shader_type);
  62. glShaderSource(*shader, 1, &source, NULL);
  63. glCompileShader(*shader);
  64. GLint compiled = 0;
  65. glGetShaderiv(*shader, GL_COMPILE_STATUS, &compiled);
  66. if (!compiled) {
  67. GLchar message[1024];
  68. GLsizei message_size = 0;
  69. glGetShaderInfoLog(*shader, sizeof(message), &message_size, message);
  70. fprintf(stderr, "ERROR: could not compile %s\n", shader_type_as_cstr(shader_type));
  71. fprintf(stderr, "%.*s\n", message_size, message);
  72. return false;
  73. }
  74. return true;
  75. }
  76. bool compile_shader_file(const char *file_path, GLenum shader_type, GLuint *shader)
  77. {
  78. char *source = slurp_file_into_malloced_cstr(file_path);
  79. if (source == NULL) {
  80. fprintf(stderr, "ERROR: failed to read file `%s`: %s\n", file_path, strerror(errno));
  81. errno = 0;
  82. return false;
  83. }
  84. bool ok = compile_shader_source(source, shader_type, shader);
  85. if (!ok) {
  86. fprintf(stderr, "ERROR: failed to compile `%s` shader file\n", file_path);
  87. }
  88. free(source);
  89. return ok;
  90. }
  91. bool link_program(GLuint vert_shader, GLuint frag_shader, GLuint *program)
  92. {
  93. *program = glCreateProgram();
  94. glAttachShader(*program, vert_shader);
  95. glAttachShader(*program, frag_shader);
  96. glLinkProgram(*program);
  97. GLint linked = 0;
  98. glGetProgramiv(*program, GL_LINK_STATUS, &linked);
  99. if (!linked) {
  100. GLsizei message_size = 0;
  101. GLchar message[1024];
  102. glGetProgramInfoLog(*program, sizeof(message), &message_size, message);
  103. fprintf(stderr, "Program Linking: %.*s\n", message_size, message);
  104. }
  105. glDeleteShader(vert_shader);
  106. glDeleteShader(frag_shader);
  107. return program;
  108. }
  109. typedef enum {
  110. RESOLUTION_UNIFORM = 0,
  111. TIME_UNIFORM,
  112. MOUSE_UNIFORM,
  113. COUNT_UNIFORMS
  114. } Uniform;
  115. static_assert(COUNT_UNIFORMS == 3, "Update list of uniform names");
  116. static const char *uniform_names[COUNT_UNIFORMS] = {
  117. [RESOLUTION_UNIFORM] = "resolution",
  118. [TIME_UNIFORM] = "time",
  119. [MOUSE_UNIFORM] = "mouse",
  120. };
  121. typedef enum {
  122. VA_POS = 0,
  123. VA_UV,
  124. VA_COLOR,
  125. COUNT_VAS,
  126. } Vertex_Attrib;
  127. typedef struct {
  128. V2f pos;
  129. V2f uv;
  130. V4f color;
  131. } Vertex;
  132. #define VERTEX_BUF_CAP (8 * 1024)
  133. typedef struct {
  134. GLuint vao;
  135. GLuint vbo;
  136. bool program_failed;
  137. GLuint program;
  138. GLint uniforms[COUNT_UNIFORMS];
  139. Vertex vertex_buf[VERTEX_BUF_CAP];
  140. size_t vertex_buf_sz;
  141. } Renderer;
  142. // Global variables (fragile people with CS degree look away)
  143. static double time = 0.0;
  144. static bool pause = false;
  145. static Renderer global_renderer = {0};
  146. void renderer_push_vertex(Renderer *r, V2f pos, V2f uv, V4f color)
  147. {
  148. assert(r->vertex_buf_sz < VERTEX_BUF_CAP);
  149. r->vertex_buf[r->vertex_buf_sz].pos = pos;
  150. r->vertex_buf[r->vertex_buf_sz].uv = uv;
  151. r->vertex_buf[r->vertex_buf_sz].color = color;
  152. r->vertex_buf_sz += 1;
  153. }
  154. void renderer_push_quad(Renderer *r, V2f p1, V2f p2, V4f color)
  155. {
  156. V2f a = p1;
  157. V2f b = v2f(p2.x, p1.y);
  158. V2f c = v2f(p1.x, p2.y);
  159. V2f d = p2;
  160. renderer_push_vertex(r, a, v2f(0.0f, 0.0f), color);
  161. renderer_push_vertex(r, b, v2f(1.0f, 0.0f), color);
  162. renderer_push_vertex(r, c, v2f(0.0f, 1.0f), color);
  163. renderer_push_vertex(r, b, v2f(1.0f, 0.0f), color);
  164. renderer_push_vertex(r, c, v2f(0.0f, 1.0f), color);
  165. renderer_push_vertex(r, d, v2f(1.0f, 1.0f), color);
  166. }
  167. void renderer_push_checker_board(Renderer *r, int grid_size)
  168. {
  169. float cell_width = 2.0f/grid_size;
  170. float cell_height = 2.0f/grid_size;
  171. for (int y = 0; y < grid_size; ++y) {
  172. for (int x = 0; x < grid_size; ++x) {
  173. renderer_push_quad(
  174. r,
  175. v2f(-1.0f + x*cell_width, -1.0f + y*cell_height),
  176. v2f(-1.0f + (x + 1)*cell_width, -1.0f + (y + 1)*cell_height),
  177. (x + y)%2 == 0 ? v4f(1.0f, 0.0f, 0.0f, 1.0f) : v4f(0.0f, 0.0f, 0.0f, 1.0f));
  178. }
  179. }
  180. }
  181. void renderer_sync(Renderer *r)
  182. {
  183. glBufferSubData(GL_ARRAY_BUFFER,
  184. 0,
  185. sizeof(Vertex) * r->vertex_buf_sz,
  186. r->vertex_buf);
  187. }
  188. bool load_shader_program(const char *vertex_file_path,
  189. const char *fragment_file_path,
  190. GLuint *program)
  191. {
  192. GLuint vert = 0;
  193. if (!compile_shader_file(vertex_file_path, GL_VERTEX_SHADER, &vert)) {
  194. return false;
  195. }
  196. GLuint frag = 0;
  197. if (!compile_shader_file(fragment_file_path, GL_FRAGMENT_SHADER, &frag)) {
  198. return false;
  199. }
  200. if (!link_program(vert, frag, program)) {
  201. return false;
  202. }
  203. return true;
  204. }
  205. void renderer_reload_shaders(Renderer *r)
  206. {
  207. glDeleteProgram(r->program);
  208. r->program_failed = true;
  209. glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
  210. {
  211. if (!load_shader_program("main.vert", "main.frag", &r->program)) {
  212. return;
  213. }
  214. glUseProgram(r->program);
  215. for (Uniform index = 0; index < COUNT_UNIFORMS; ++index) {
  216. r->uniforms[index] = glGetUniformLocation(r->program, uniform_names[index]);
  217. }
  218. }
  219. r->program_failed = false;
  220. glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  221. printf("Successfully Reload the Shaders\n");
  222. }
  223. void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
  224. {
  225. (void) window;
  226. (void) scancode;
  227. (void) action;
  228. (void) mods;
  229. if (action == GLFW_PRESS) {
  230. if (key == GLFW_KEY_F5) {
  231. renderer_reload_shaders(&global_renderer);
  232. } else if (key == GLFW_KEY_SPACE) {
  233. pause = !pause;
  234. } else if (key == GLFW_KEY_Q) {
  235. exit(1);
  236. }
  237. if (pause) {
  238. if (key == GLFW_KEY_LEFT) {
  239. time -= MANUAL_TIME_STEP;
  240. } else if (key == GLFW_KEY_RIGHT) {
  241. time += MANUAL_TIME_STEP;
  242. }
  243. }
  244. }
  245. }
  246. void window_size_callback(GLFWwindow* window, int width, int height)
  247. {
  248. (void) window;
  249. glViewport(0, 0, width, height);
  250. }
  251. void MessageCallback(GLenum source,
  252. GLenum type,
  253. GLuint id,
  254. GLenum severity,
  255. GLsizei length,
  256. const GLchar* message,
  257. const void* userParam)
  258. {
  259. (void) source;
  260. (void) id;
  261. (void) length;
  262. (void) userParam;
  263. fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
  264. (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
  265. type, severity, message);
  266. }
  267. void renderer_init(Renderer *r)
  268. {
  269. glGenVertexArrays(1, &r->vao);
  270. glBindVertexArray(r->vao);
  271. glGenBuffers(1, &r->vbo);
  272. glBindBuffer(GL_ARRAY_BUFFER, r->vbo);
  273. glBufferData(GL_ARRAY_BUFFER, sizeof(r->vertex_buf), r->vertex_buf, GL_DYNAMIC_DRAW);
  274. glEnableVertexAttribArray(VA_POS);
  275. glVertexAttribPointer(VA_POS,
  276. 2,
  277. GL_FLOAT,
  278. GL_FALSE,
  279. sizeof(Vertex),
  280. (void*) offsetof(Vertex, pos));
  281. glEnableVertexAttribArray(VA_UV);
  282. glVertexAttribPointer(VA_UV,
  283. 2,
  284. GL_FLOAT,
  285. GL_FALSE,
  286. sizeof(Vertex),
  287. (void*) offsetof(Vertex, uv));
  288. glEnableVertexAttribArray(VA_COLOR);
  289. glVertexAttribPointer(VA_COLOR,
  290. 4,
  291. GL_FLOAT,
  292. GL_FALSE,
  293. sizeof(Vertex),
  294. (void*) offsetof(Vertex, color));
  295. }
  296. int main()
  297. {
  298. if (!glfwInit()) {
  299. fprintf(stderr, "ERROR: could not initialize GLFW\n");
  300. exit(1);
  301. }
  302. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  303. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  304. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  305. GLFWwindow * const window = glfwCreateWindow(
  306. DEFAULT_SCREEN_WIDTH,
  307. DEFAULT_SCREEN_HEIGHT,
  308. "OpenGL Template",
  309. NULL,
  310. NULL);
  311. if (window == NULL) {
  312. fprintf(stderr, "ERROR: could not create a window.\n");
  313. glfwTerminate();
  314. exit(1);
  315. }
  316. int gl_ver_major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
  317. int gl_ver_minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
  318. printf("OpenGL %d.%d\n", gl_ver_major, gl_ver_minor);
  319. glfwMakeContextCurrent(window);
  320. load_gl_extensions();
  321. if (glDrawArraysInstanced == NULL) {
  322. fprintf(stderr, "Support for EXT_draw_instanced is required!\n");
  323. exit(1);
  324. }
  325. if (glDebugMessageCallback != NULL) {
  326. glEnable(GL_DEBUG_OUTPUT);
  327. glDebugMessageCallback(MessageCallback, 0);
  328. }
  329. glEnable(GL_BLEND);
  330. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  331. renderer_init(&global_renderer);
  332. renderer_push_quad(&global_renderer, v2f(-1.0f, -1.0f), v2f(1.0f, 1.0f), (V4f) {
  333. 0
  334. });
  335. renderer_sync(&global_renderer);
  336. renderer_reload_shaders(&global_renderer);
  337. glfwSetKeyCallback(window, key_callback);
  338. glfwSetFramebufferSizeCallback(window, window_size_callback);
  339. time = glfwGetTime();
  340. double prev_time = 0.0;
  341. while (!glfwWindowShouldClose(window)) {
  342. glClear(GL_COLOR_BUFFER_BIT);
  343. if (!global_renderer.program_failed) {
  344. static_assert(COUNT_UNIFORMS == 3, "Update the uniform sync");
  345. int width, height;
  346. glfwGetWindowSize(window, &width, &height);
  347. glUniform2f(global_renderer.uniforms[RESOLUTION_UNIFORM], (GLfloat) width, (GLfloat) height);
  348. glUniform1f(global_renderer.uniforms[TIME_UNIFORM], (GLfloat) time);
  349. double xpos, ypos;
  350. glfwGetCursorPos(window, &xpos, &ypos);
  351. glUniform2f(global_renderer.uniforms[MOUSE_UNIFORM], (GLfloat) xpos, (GLfloat) (height - ypos));
  352. glDrawArraysInstanced(GL_TRIANGLES, 0, (GLsizei) global_renderer.vertex_buf_sz, 1);
  353. }
  354. glfwSwapBuffers(window);
  355. glfwPollEvents();
  356. double cur_time = glfwGetTime();
  357. if (!pause) {
  358. time += cur_time - prev_time;
  359. }
  360. prev_time = cur_time;
  361. }
  362. return 0;
  363. }