main.c 13 KB

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