2
0

main.c 12 KB

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