ded

Dramatic EDitor
Index Commits Files Refs README LICENSE
src/simple_renderer.c (10820B)
   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 }