1 #include <assert.h> 2 #include <stdio.h> 3 #include <stdbool.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <errno.h> 7 #include "./simple_renderer.h" 8 #include "./common.h" 9 10 #define vert_shader_file_path "./shaders/simple.vert" 11 12 static_assert(COUNT_SIMPLE_SHADERS == 4, "The amount of fragment shaders has changed"); 13 const char *frag_shader_file_paths[COUNT_SIMPLE_SHADERS] = { 14 [SHADER_FOR_COLOR] = "./shaders/simple_color.frag", 15 [SHADER_FOR_IMAGE] = "./shaders/simple_image.frag", 16 [SHADER_FOR_TEXT] = "./shaders/simple_text.frag", 17 [SHADER_FOR_EPICNESS] = "./shaders/simple_epic.frag", 18 }; 19 20 static const char *shader_type_as_cstr(GLuint shader) 21 { 22 switch (shader) { 23 case GL_VERTEX_SHADER: 24 return "GL_VERTEX_SHADER"; 25 case GL_FRAGMENT_SHADER: 26 return "GL_FRAGMENT_SHADER"; 27 default: 28 return "(Unknown)"; 29 } 30 } 31 32 static bool compile_shader_source(const GLchar *source, GLenum shader_type, GLuint *shader) 33 { 34 *shader = glCreateShader(shader_type); 35 glShaderSource(*shader, 1, &source, NULL); 36 glCompileShader(*shader); 37 38 GLint compiled = 0; 39 glGetShaderiv(*shader, GL_COMPILE_STATUS, &compiled); 40 41 if (!compiled) { 42 GLchar message[1024]; 43 GLsizei message_size = 0; 44 glGetShaderInfoLog(*shader, sizeof(message), &message_size, message); 45 fprintf(stderr, "ERROR: could not compile %s\n", shader_type_as_cstr(shader_type)); 46 fprintf(stderr, "%.*s\n", message_size, message); 47 return false; 48 } 49 50 return true; 51 } 52 53 static bool compile_shader_file(const char *file_path, GLenum shader_type, GLuint *shader) 54 { 55 bool result = true; 56 57 String_Builder source = {0}; 58 Errno err = read_entire_file(file_path, &source); 59 if (err != 0) { 60 fprintf(stderr, "ERROR: failed to load `%s` shader file: %s\n", file_path, strerror(errno)); 61 return_defer(false); 62 } 63 sb_append_null(&source); 64 65 if (!compile_shader_source(source.items, shader_type, shader)) { 66 fprintf(stderr, "ERROR: failed to compile `%s` shader file\n", file_path); 67 return_defer(false); 68 } 69 defer: 70 free(source.items); 71 return result; 72 } 73 74 static void attach_shaders_to_program(GLuint *shaders, size_t shaders_count, GLuint program) 75 { 76 for (size_t i = 0; i < shaders_count; ++i) { 77 glAttachShader(program, shaders[i]); 78 } 79 } 80 81 static bool link_program(GLuint program, const char *file_path, size_t line) 82 { 83 glLinkProgram(program); 84 85 GLint linked = 0; 86 glGetProgramiv(program, GL_LINK_STATUS, &linked); 87 if (!linked) { 88 GLsizei message_size = 0; 89 GLchar message[1024]; 90 91 glGetProgramInfoLog(program, sizeof(message), &message_size, message); 92 fprintf(stderr, "%s:%zu: Program Linking: %.*s\n", file_path, line, message_size, message); 93 } 94 95 return linked; 96 } 97 98 typedef struct { 99 Uniform_Slot slot; 100 const char *name; 101 } Uniform_Def; 102 103 static_assert(COUNT_UNIFORM_SLOTS == 4, "The amount of the shader uniforms have change. Please update the definition table accordingly"); 104 static const Uniform_Def uniform_defs[COUNT_UNIFORM_SLOTS] = { 105 [UNIFORM_SLOT_TIME] = { 106 .slot = UNIFORM_SLOT_TIME, 107 .name = "time", 108 }, 109 [UNIFORM_SLOT_RESOLUTION] = { 110 .slot = UNIFORM_SLOT_RESOLUTION, 111 .name = "resolution", 112 }, 113 [UNIFORM_SLOT_CAMERA_POS] = { 114 .slot = UNIFORM_SLOT_CAMERA_POS, 115 .name = "camera_pos", 116 }, 117 [UNIFORM_SLOT_CAMERA_SCALE] = { 118 .slot = UNIFORM_SLOT_CAMERA_SCALE, 119 .name = "camera_scale", 120 }, 121 }; 122 123 124 static void get_uniform_location(GLuint program, GLint locations[COUNT_UNIFORM_SLOTS]) 125 { 126 for (Uniform_Slot slot = 0; slot < COUNT_UNIFORM_SLOTS; ++slot) { 127 locations[slot] = glGetUniformLocation(program, uniform_defs[slot].name); 128 } 129 } 130 131 void simple_renderer_init(Simple_Renderer *sr) 132 { 133 sr->camera_scale = 3.0f; 134 135 { 136 glGenVertexArrays(1, &sr->vao); 137 glBindVertexArray(sr->vao); 138 139 glGenBuffers(1, &sr->vbo); 140 glBindBuffer(GL_ARRAY_BUFFER, sr->vbo); 141 glBufferData(GL_ARRAY_BUFFER, sizeof(sr->verticies), sr->verticies, GL_DYNAMIC_DRAW); 142 143 // position 144 glEnableVertexAttribArray(SIMPLE_VERTEX_ATTR_POSITION); 145 glVertexAttribPointer( 146 SIMPLE_VERTEX_ATTR_POSITION, 147 2, 148 GL_FLOAT, 149 GL_FALSE, 150 sizeof(Simple_Vertex), 151 (GLvoid *) offsetof(Simple_Vertex, position)); 152 153 // color 154 glEnableVertexAttribArray(SIMPLE_VERTEX_ATTR_COLOR); 155 glVertexAttribPointer( 156 SIMPLE_VERTEX_ATTR_COLOR, 157 4, 158 GL_FLOAT, 159 GL_FALSE, 160 sizeof(Simple_Vertex), 161 (GLvoid *) offsetof(Simple_Vertex, color)); 162 163 // uv 164 glEnableVertexAttribArray(SIMPLE_VERTEX_ATTR_UV); 165 glVertexAttribPointer( 166 SIMPLE_VERTEX_ATTR_UV, 167 2, 168 GL_FLOAT, 169 GL_FALSE, 170 sizeof(Simple_Vertex), 171 (GLvoid *) offsetof(Simple_Vertex, uv)); 172 } 173 174 GLuint shaders[2] = {0}; 175 176 if (!compile_shader_file(vert_shader_file_path, GL_VERTEX_SHADER, &shaders[0])) { 177 exit(1); 178 } 179 180 for (int i = 0; i < COUNT_SIMPLE_SHADERS; ++i) { 181 if (!compile_shader_file(frag_shader_file_paths[i], GL_FRAGMENT_SHADER, &shaders[1])) { 182 exit(1); 183 } 184 sr->programs[i] = glCreateProgram(); 185 attach_shaders_to_program(shaders, sizeof(shaders) / sizeof(shaders[0]), sr->programs[i]); 186 if (!link_program(sr->programs[i], __FILE__, __LINE__)) { 187 exit(1); 188 } 189 glDeleteShader(shaders[1]); 190 } 191 glDeleteShader(shaders[0]); 192 } 193 194 void simple_renderer_reload_shaders(Simple_Renderer *sr) 195 { 196 GLuint programs[COUNT_SIMPLE_SHADERS]; 197 GLuint shaders[2] = {0}; 198 199 bool ok = true; 200 201 if (!compile_shader_file(vert_shader_file_path, GL_VERTEX_SHADER, &shaders[0])) { 202 ok = false; 203 } 204 205 for (int i = 0; i < COUNT_SIMPLE_SHADERS; ++i) { 206 if (!compile_shader_file(frag_shader_file_paths[i], GL_FRAGMENT_SHADER, &shaders[1])) { 207 ok = false; 208 } 209 programs[i] = glCreateProgram(); 210 attach_shaders_to_program(shaders, sizeof(shaders) / sizeof(shaders[0]), programs[i]); 211 if (!link_program(programs[i], __FILE__, __LINE__)) { 212 ok = false; 213 } 214 glDeleteShader(shaders[1]); 215 } 216 glDeleteShader(shaders[0]); 217 218 if (ok) { 219 for (int i = 0; i < COUNT_SIMPLE_SHADERS; ++i) { 220 glDeleteProgram(sr->programs[i]); 221 sr->programs[i] = programs[i]; 222 } 223 printf("Reloaded shaders successfully!\n"); 224 } else { 225 for (int i = 0; i < COUNT_SIMPLE_SHADERS; ++i) { 226 glDeleteProgram(programs[i]); 227 } 228 } 229 } 230 231 // TODO: Don't render triples of verticies that form a triangle that is completely outside of the screen 232 // 233 // Ideas on how to check if a triangle is outside of the screen: 234 // 1. Apply camera transformations to the triangle. 235 // 2. Form an axis-aligned boundary box (AABB) of the triangle. 236 // 3. Check if the Triangle AABB does not intersect the Screen AABB. 237 // 238 // This might not be what we want at the end of the day, though. Because in case of a lot of triangles we 239 // end up iterating each of them at least once and doing camera trasformations on the CPU (which is 240 // something we do on GPU already). 241 // 242 // It would be probably better if such culling occurred on a higher level of abstractions. For example 243 // in the Editor. For instance, if the Editor noticed that the line it is currently rendering is 244 // below the screen, it should stop rendering the rest of the text, thus never calling 245 // simple_renderer_vertex() for a potentially large amount of verticies in the first place. 246 void simple_renderer_vertex(Simple_Renderer *sr, Vec2f p, Vec4f c, Vec2f uv) 247 { 248 #if 0 249 // TODO: flush the renderer on vertex buffer overflow instead firing the assert 250 if (sr->verticies_count >= SIMPLE_VERTICIES_CAP) simple_renderer_flush(sr); 251 #else 252 // NOTE: it is better to just crash the app in this case until the culling described 253 // above is sorted out. 254 assert(sr->verticies_count < SIMPLE_VERTICIES_CAP); 255 #endif 256 Simple_Vertex *last = &sr->verticies[sr->verticies_count]; 257 last->position = p; 258 last->color = c; 259 last->uv = uv; 260 sr->verticies_count += 1; 261 } 262 263 void simple_renderer_triangle(Simple_Renderer *sr, 264 Vec2f p0, Vec2f p1, Vec2f p2, 265 Vec4f c0, Vec4f c1, Vec4f c2, 266 Vec2f uv0, Vec2f uv1, Vec2f uv2) 267 { 268 simple_renderer_vertex(sr, p0, c0, uv0); 269 simple_renderer_vertex(sr, p1, c1, uv1); 270 simple_renderer_vertex(sr, p2, c2, uv2); 271 } 272 273 // 2-3 274 // |\| 275 // 0-1 276 void simple_renderer_quad(Simple_Renderer *sr, 277 Vec2f p0, Vec2f p1, Vec2f p2, Vec2f p3, 278 Vec4f c0, Vec4f c1, Vec4f c2, Vec4f c3, 279 Vec2f uv0, Vec2f uv1, Vec2f uv2, Vec2f uv3) 280 { 281 simple_renderer_triangle(sr, p0, p1, p2, c0, c1, c2, uv0, uv1, uv2); 282 simple_renderer_triangle(sr, p1, p2, p3, c1, c2, c3, uv1, uv2, uv3); 283 } 284 285 void simple_renderer_image_rect(Simple_Renderer *sr, Vec2f p, Vec2f s, Vec2f uvp, Vec2f uvs, Vec4f c) 286 { 287 simple_renderer_quad( 288 sr, 289 p, vec2f_add(p, vec2f(s.x, 0)), vec2f_add(p, vec2f(0, s.y)), vec2f_add(p, s), 290 c, c, c, c, 291 uvp, vec2f_add(uvp, vec2f(uvs.x, 0)), vec2f_add(uvp, vec2f(0, uvs.y)), vec2f_add(uvp, uvs)); 292 } 293 294 void simple_renderer_solid_rect(Simple_Renderer *sr, Vec2f p, Vec2f s, Vec4f c) 295 { 296 Vec2f uv = vec2fs(0); 297 simple_renderer_quad( 298 sr, 299 p, vec2f_add(p, vec2f(s.x, 0)), vec2f_add(p, vec2f(0, s.y)), vec2f_add(p, s), 300 c, c, c, c, 301 uv, uv, uv, uv); 302 } 303 304 void simple_renderer_sync(Simple_Renderer *sr) 305 { 306 glBufferSubData(GL_ARRAY_BUFFER, 307 0, 308 sr->verticies_count * sizeof(Simple_Vertex), 309 sr->verticies); 310 } 311 312 void simple_renderer_draw(Simple_Renderer *sr) 313 { 314 glDrawArrays(GL_TRIANGLES, 0, sr->verticies_count); 315 } 316 317 void simple_renderer_set_shader(Simple_Renderer *sr, Simple_Shader shader) 318 { 319 sr->current_shader = shader; 320 glUseProgram(sr->programs[sr->current_shader]); 321 get_uniform_location(sr->programs[sr->current_shader], sr->uniforms); 322 glUniform2f(sr->uniforms[UNIFORM_SLOT_RESOLUTION], sr->resolution.x, sr->resolution.y); 323 glUniform1f(sr->uniforms[UNIFORM_SLOT_TIME], sr->time); 324 glUniform2f(sr->uniforms[UNIFORM_SLOT_CAMERA_POS], sr->camera_pos.x, sr->camera_pos.y); 325 glUniform1f(sr->uniforms[UNIFORM_SLOT_CAMERA_SCALE], sr->camera_scale); 326 } 327 328 void simple_renderer_flush(Simple_Renderer *sr) 329 { 330 simple_renderer_sync(sr); 331 simple_renderer_draw(sr); 332 sr->verticies_count = 0; 333 }
