Add a shader registry and loader

This commit is contained in:
Kienan Stewart 2020-02-06 00:32:26 -05:00
parent efeeb25b0b
commit 865fa558e9
6 changed files with 289 additions and 0 deletions

View File

@ -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();

252
src/common/shaderloader.hpp Normal file
View File

@ -0,0 +1,252 @@
#ifndef _SHADERLOADER_H_
#define _SHADERLOADER_H_
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
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<char> 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>,<type>,<filepath>
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<char> 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<char> 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_

View File

@ -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;
}

View File

@ -0,0 +1,5 @@
#version 330 core
out vec3 color;
void main(){
color = vec3(1,0,0);
}

View File

@ -0,0 +1,10 @@
# Lines starting with '#' are comments and ignored
#
# Define a list of shaders to load, one per line
# <programName>,<shader_type>,<path_to_source_relative_to_this_file>
#
# <shader_type> is one of: vertex, tesselation, evaluation, geometry, fragment,
# or compute.
#
defaultVertexShader,vertex,defaultVertexShader.glsl
fragmentRed,fragment,fragmentRed.glsl

View File

@ -0,0 +1,5 @@
# Lines starting with '#' are comments
#
# Each line is a program. <program_name>:<shader1>,<shader2>,...<shaderN>
#
default:defaultVertexShader,fragmentRed