From 865fa558e950a017e57ca7656896c069d4478761 Mon Sep 17 00:00:00 2001 From: Kienan Stewart Date: Thu, 6 Feb 2020 00:32:26 -0500 Subject: [PATCH] Add a shader registry and loader --- src/client/client_imgui.cpp | 11 ++ src/common/shaderloader.hpp | 252 +++++++++++++++++++++++++++ src/shaders/defaultVertexShader.glsl | 6 + src/shaders/fragmentRed.glsl | 5 + src/shaders/shader_list.txt | 10 ++ src/shaders/shader_programs.txt | 5 + 6 files changed, 289 insertions(+) create mode 100644 src/common/shaderloader.hpp create mode 100644 src/shaders/defaultVertexShader.glsl create mode 100644 src/shaders/fragmentRed.glsl create mode 100644 src/shaders/shader_list.txt create mode 100644 src/shaders/shader_programs.txt diff --git a/src/client/client_imgui.cpp b/src/client/client_imgui.cpp index 6a2f6c6..7917956 100644 --- a/src/client/client_imgui.cpp +++ b/src/client/client_imgui.cpp @@ -13,6 +13,8 @@ #include "common/logging.hpp" #include "common/messaging/bus.hpp" +#include "common/shaderloader.hpp" + // Globals static Logger logger; static MessageBus messager(&logger); @@ -95,6 +97,15 @@ int main(int argc, char** argv) g_vertex_buffer_data, GL_STATIC_DRAW); static Console console(&messager); bool show_console = false; + + // Shader load information + bool shaders_loaded = false; + int num_shaders_loaded = 0; + int num_shaders_failed = 0; + int num_shader_files = 0; + const char* shader_list = "shaders/list.txt"; + static struct ShaderRegistry shader_registry; + loadShadersFromFile(shader_list, &shader_registry); messager.registerCallback(&debug_messagebus_callback); while(!glfwWindowShouldClose(window)) { glfwPollEvents(); diff --git a/src/common/shaderloader.hpp b/src/common/shaderloader.hpp new file mode 100644 index 0000000..ab04ca5 --- /dev/null +++ b/src/common/shaderloader.hpp @@ -0,0 +1,252 @@ +#ifndef _SHADERLOADER_H_ +#define _SHADERLOADER_H_ + +#include +#include +#include +#include + +#include +#include + +enum ShaderType { + vertex = GL_VERTEX_SHADER, + fragment = GL_FRAGMENT_SHADER, + geometry = GL_GEOMETRY_SHADER, + //tesselation = GL_TESS_CONTROL_SHADER, // GL4.0 || ARB_tesselation_shader + //valuation = GL_TESS_EVALUATION_SHADER, + //compute = GL_COMPUTE_SHADER, // GL4.3 || ARB_compute_shader +}; + +struct RegisteredShader { + char *shaderName; + int shaderType; + GLuint shaderID; +} RegisteredShader; + +struct RegisteredShaderProgram { + char *programName; + GLuint programID; +} RegisteredShaderProgram; + +struct ShaderRegistry { + struct RegisteredShader *list = 0; + int size = 0; +} ShaderRegistry; + +void register_shader(struct ShaderRegistry *r, char *name, int type, GLuint id) { + // Allocate storage for the name + int name_size = strlen(name); + char *n = (char*) malloc(name_size * sizeof(char)); + + // Grow and copy + int new_size = r->size + 1; + struct RegisteredShader *list = (struct RegisteredShader *) malloc(new_size * sizeof(RegisteredShader)); + memcpy(list, r->list, r->size * sizeof(RegisteredShader)); + + // Add new element + list[new_size-1].shaderName = n; + list[new_size-1].shaderType = type; + list[new_size-1].shaderID = id; + + // Replace in registry + r->size = new_size; + free(r->list); + r->list = list; +} + +struct RegisteredShader* find_shader(struct ShaderRegistry *r, char *name) { + int i = 0; + struct RegisteredShader *s = 0; + for(i; i < r->size; i++) { + s = (r->list) + (i * sizeof(struct RegisteredShader)); + if(strcmp(s->shaderName, name) == 0) { + return s; + } + } + return 0; +} + +void remove_shader(struct ShaderRegistry *r, struct RegisteredShader *s) { + if(s == 0) { + return; + } + int index = (s - (r->list)) / sizeof(struct RegisteredShader); + int new_size = r->size - 1; + struct RegisteredShader *list; + list = (struct RegisteredShader*) malloc(new_size * sizeof(struct RegisteredShader)); + // Copy the first half + memcpy(list, r->list, index * sizeof(struct RegisteredShader)); + // Copy the second half + memcpy(list, r->list + ((index + 1) * sizeof(struct RegisteredShader)), (r->size - 1 - index) * sizeof(struct RegisteredShader)); + // Deallocate the string of the registered shader + free(s->shaderName); + // Deallocate the old list + free(r->list); + r->list = list; + r->size = new_size; +} + +void remove_shader_by_name(struct ShaderRegistry *r, char *name) { + remove_shader(r, find_shader(r, name)); +} + + + +struct ShaderProgramRegistry { + struct RegisteredShareProgram *list = 0; + int size = 0; +} ShaderProgramRegistry; + + +GLuint compile_shader(const char* file_path, int t) { + GLuint shader_id = glCreateShader(t); + + // From: https://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/ + // Read the Vertex Shader code from the file + std::string code; + std::ifstream stream(file_path, std::ios::in); + if(stream.is_open()){ + std::stringstream sstr; + sstr << stream.rdbuf(); + code = sstr.str(); + stream.close(); + } + else { + // @TODO Inform user. + return 0; + } + + GLint Result = GL_FALSE; + int InfoLogLength; + + // Compile Vertex Shader + printf("Compiling shader : %s\n", file_path); + char const *source = code.c_str(); + glShaderSource(shader_id, 1, &source , NULL); + glCompileShader(shader_id); + + glGetShaderiv(shader_id, GL_COMPILE_STATUS, &Result); + glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &InfoLogLength); + if ( InfoLogLength > 0 ){ + std::vector error_message(InfoLogLength+1); + glGetShaderInfoLog(shader_id, InfoLogLength, NULL, &error_message[0]); + printf("%s\n", &error_message[0]); + } + + return shader_id; +} + +int loadShadersFromFile(const char* file_path, struct ShaderRegistry *registry) { + FILE *fp; + char *line; + size_t size = 0; + const char *delim = ","; + fp = fopen(file_path, "r"); + if (fp == NULL) { + return -1; + } + char *name; + char *type; + char *path; + while((size = getline(&line, &size, fp)) != -1) { + if(size == 0) { + // Skipping, line length 0 + continue; + } + if(line[0] == '#') { + // Skipping, line is a comment + continue; + } + char *line_copy = (char*) malloc((size) * sizeof(char*)); + strncpy(line_copy, line, size); + // Format ,, + name = strtok(line_copy, delim); + type = strtok(NULL, delim); + path = strtok(NULL, delim); + if (name == NULL || type == NULL || path == NULL) { + // Invalid line, not enough elements. + // @TODO Inform the user. + free(line_copy); + name = type = path = NULL; + continue; + } + + // Validate type + enum ShaderType shader_type; + if(strcmp("fragment", type) == 0) { + shader_type = fragment; + } + else if(strcmp("vertex", type) == 0) { + shader_type = vertex; + } + else if(strcmp("geometry", type) == 0) { + shader_type = geometry; + } + + if(shader_type == 0) { + // Invalid line, unknown type. + // @TODO Inform the user. + free(line_copy); + name = type = path = NULL; + continue; + } + + GLuint shader_id = compile_shader(path, shader_type); + if(shader_id == 0) { + // Error in compilation of the shader + // @TODO Inform the user. + free(line_copy); + name = type = path = NULL; + continue; + } + } + return 0; +} + +// GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){ + + +// // Check Vertex Shader +// glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); +// glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); +// if ( InfoLogLength > 0 ){ +// std::vector VertexShaderErrorMessage(InfoLogLength+1); +// glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); +// printf("%s\n", &VertexShaderErrorMessage[0]); +// } + +// // Compile Fragment Shader +// printf("Compiling shader : %s\n", fragment_file_path); +// char const * FragmentSourcePointer = FragmentShaderCode.c_str(); +// glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL); +// glCompileShader(FragmentShaderID); + +// // Check Fragment Shader + +// // Link the program +// printf("Linking program\n"); +// GLuint ProgramID = glCreateProgram(); +// glAttachShader(ProgramID, VertexShaderID); +// glAttachShader(ProgramID, FragmentShaderID); +// glLinkProgram(ProgramID); + +// // Check the program +// glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); +// glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); +// if ( InfoLogLength > 0 ){ +// std::vector ProgramErrorMessage(InfoLogLength+1); +// glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); +// printf("%s\n", &ProgramErrorMessage[0]); +// } + +// glDetachShader(ProgramID, VertexShaderID); +// glDetachShader(ProgramID, FragmentShaderID); + +// glDeleteShader(VertexShaderID); +// glDeleteShader(FragmentShaderID); + +// return ProgramID; +// } + +#endif // _SHADERLOADER_H_ diff --git a/src/shaders/defaultVertexShader.glsl b/src/shaders/defaultVertexShader.glsl new file mode 100644 index 0000000..330cb20 --- /dev/null +++ b/src/shaders/defaultVertexShader.glsl @@ -0,0 +1,6 @@ +#version 330 core +layout(location = 0) in vec3 vertexPosition_modelspace; +void main(){ + gl_Position.xyz = vertexPosition_modelspace; + gl_Position.w = 1.0; +} diff --git a/src/shaders/fragmentRed.glsl b/src/shaders/fragmentRed.glsl new file mode 100644 index 0000000..15e33a1 --- /dev/null +++ b/src/shaders/fragmentRed.glsl @@ -0,0 +1,5 @@ +#version 330 core +out vec3 color; +void main(){ + color = vec3(1,0,0); +} diff --git a/src/shaders/shader_list.txt b/src/shaders/shader_list.txt new file mode 100644 index 0000000..42e348a --- /dev/null +++ b/src/shaders/shader_list.txt @@ -0,0 +1,10 @@ +# Lines starting with '#' are comments and ignored +# +# Define a list of shaders to load, one per line +# ,, +# +# is one of: vertex, tesselation, evaluation, geometry, fragment, +# or compute. +# +defaultVertexShader,vertex,defaultVertexShader.glsl +fragmentRed,fragment,fragmentRed.glsl diff --git a/src/shaders/shader_programs.txt b/src/shaders/shader_programs.txt new file mode 100644 index 0000000..c2b097a --- /dev/null +++ b/src/shaders/shader_programs.txt @@ -0,0 +1,5 @@ +# Lines starting with '#' are comments +# +# Each line is a program. :,,... +# +default:defaultVertexShader,fragmentRed