|
@@ -1,8 +1,109 @@
|
|
|
#include <assert.h>
|
|
|
#include <stdio.h>
|
|
|
+#include <stdbool.h>
|
|
|
#include <stdlib.h>
|
|
|
+#include <string.h>
|
|
|
+#include <errno.h>
|
|
|
#include "./simple_renderer.h"
|
|
|
-#include "./gl_extra.h"
|
|
|
+
|
|
|
+static char *slurp_file(const char *file_path)
|
|
|
+{
|
|
|
+#define SLURP_FILE_PANIC \
|
|
|
+ do { \
|
|
|
+ fprintf(stderr, "Could not read file `%s`: %s\n", file_path, strerror(errno)); \
|
|
|
+ exit(1); \
|
|
|
+ } while (0)
|
|
|
+
|
|
|
+ FILE *f = fopen(file_path, "r");
|
|
|
+ if (f == NULL) SLURP_FILE_PANIC;
|
|
|
+ if (fseek(f, 0, SEEK_END) < 0) SLURP_FILE_PANIC;
|
|
|
+
|
|
|
+ long size = ftell(f);
|
|
|
+ if (size < 0) SLURP_FILE_PANIC;
|
|
|
+
|
|
|
+ char *buffer = malloc(size + 1);
|
|
|
+ if (buffer == NULL) SLURP_FILE_PANIC;
|
|
|
+
|
|
|
+ if (fseek(f, 0, SEEK_SET) < 0) SLURP_FILE_PANIC;
|
|
|
+
|
|
|
+ fread(buffer, 1, size, f);
|
|
|
+ if (ferror(f) < 0) SLURP_FILE_PANIC;
|
|
|
+
|
|
|
+ buffer[size] = '\0';
|
|
|
+
|
|
|
+ if (fclose(f) < 0) SLURP_FILE_PANIC;
|
|
|
+
|
|
|
+ return buffer;
|
|
|
+#undef SLURP_FILE_PANIC
|
|
|
+}
|
|
|
+
|
|
|
+static const char *shader_type_as_cstr(GLuint shader)
|
|
|
+{
|
|
|
+ switch (shader) {
|
|
|
+ case GL_VERTEX_SHADER:
|
|
|
+ return "GL_VERTEX_SHADER";
|
|
|
+ case GL_FRAGMENT_SHADER:
|
|
|
+ return "GL_FRAGMENT_SHADER";
|
|
|
+ default:
|
|
|
+ return "(Unknown)";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static bool compile_shader_source(const GLchar *source, GLenum shader_type, GLuint *shader)
|
|
|
+{
|
|
|
+ *shader = glCreateShader(shader_type);
|
|
|
+ glShaderSource(*shader, 1, &source, NULL);
|
|
|
+ glCompileShader(*shader);
|
|
|
+
|
|
|
+ GLint compiled = 0;
|
|
|
+ glGetShaderiv(*shader, GL_COMPILE_STATUS, &compiled);
|
|
|
+
|
|
|
+ if (!compiled) {
|
|
|
+ GLchar message[1024];
|
|
|
+ GLsizei message_size = 0;
|
|
|
+ glGetShaderInfoLog(*shader, sizeof(message), &message_size, message);
|
|
|
+ fprintf(stderr, "ERROR: could not compile %s\n", shader_type_as_cstr(shader_type));
|
|
|
+ fprintf(stderr, "%.*s\n", message_size, message);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static bool compile_shader_file(const char *file_path, GLenum shader_type, GLuint *shader)
|
|
|
+{
|
|
|
+ char *source = slurp_file(file_path);
|
|
|
+ bool ok = compile_shader_source(source, shader_type, shader);
|
|
|
+ if (!ok) {
|
|
|
+ fprintf(stderr, "ERROR: failed to compile `%s` shader file\n", file_path);
|
|
|
+ }
|
|
|
+ free(source);
|
|
|
+ return ok;
|
|
|
+}
|
|
|
+
|
|
|
+static void attach_shaders_to_program(GLuint *shaders, size_t shaders_count, GLuint program)
|
|
|
+{
|
|
|
+ for (size_t i = 0; i < shaders_count; ++i) {
|
|
|
+ glAttachShader(program, shaders[i]);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static bool link_program(GLuint program, const char *file_path, size_t line)
|
|
|
+{
|
|
|
+ glLinkProgram(program);
|
|
|
+
|
|
|
+ GLint linked = 0;
|
|
|
+ glGetProgramiv(program, GL_LINK_STATUS, &linked);
|
|
|
+ if (!linked) {
|
|
|
+ GLsizei message_size = 0;
|
|
|
+ GLchar message[1024];
|
|
|
+
|
|
|
+ glGetProgramInfoLog(program, sizeof(message), &message_size, message);
|
|
|
+ fprintf(stderr, "%s:%zu: Program Linking: %.*s\n", file_path, line, message_size, message);
|
|
|
+ }
|
|
|
+
|
|
|
+ return linked;
|
|
|
+}
|
|
|
|
|
|
typedef struct {
|
|
|
Uniform_Slot slot;
|