#include "render/shader.h" #include "core/platform.h" #include static char *readAsset(const char *asset) { char path[1024]; if (!Platform_assetPath(asset, path, sizeof(path))) { SDL_Log("Asset path too long: %s", asset); return NULL; } char *data = SDL_LoadFile(path, NULL); /* null-terminated */ if (!data) SDL_Log("Cannot read %s: %s", path, SDL_GetError()); return data; } #define GLSL_VERSION "#version 330 core\n" #define COMMON_ASSET "shaders/common.glsl" static GLuint compile(GLenum type, const char *common, const char *source, const char *name) { const char *parts[] = { GLSL_VERSION, common, "\n#line 1\n", source }; GLuint shader = glCreateShader(type); glShaderSource(shader, 4, parts, NULL); glCompileShader(shader); GLint ok = GL_FALSE; glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); if (!ok) { char log[1024]; glGetShaderInfoLog(shader, sizeof(log), NULL, log); SDL_Log("Shader compile error in %s:\n%s", name, log); glDeleteShader(shader); return 0; } return shader; } GLuint Shader_load(const char *vert_asset, const char *frag_asset) { GLuint program = 0, vert = 0, frag = 0; char *common = readAsset(COMMON_ASSET); char *vert_src = readAsset(vert_asset); char *frag_src = readAsset(frag_asset); if (!common || !vert_src || !frag_src) goto done; vert = compile(GL_VERTEX_SHADER, common, vert_src, vert_asset); frag = compile(GL_FRAGMENT_SHADER, common, frag_src, frag_asset); if (!vert || !frag) goto done; program = glCreateProgram(); glAttachShader(program, vert); glAttachShader(program, frag); glLinkProgram(program); GLint ok = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &ok); if (!ok) { char log[1024]; glGetProgramInfoLog(program, sizeof(log), NULL, log); SDL_Log("Shader link error (%s + %s):\n%s", vert_asset, frag_asset, log); glDeleteProgram(program); program = 0; } done: if (vert) glDeleteShader(vert); if (frag) glDeleteShader(frag); SDL_free(common); SDL_free(vert_src); SDL_free(frag_src); return program; } void Shader_destroy(GLuint *program) { if (*program) glDeleteProgram(*program); *program = 0; }