Browse Source

tesselation shader support, more generic shader compiling

Kajetan Johannes Hammerle 3 years ago
parent
commit
c7ebc81e44
4 changed files with 74 additions and 49 deletions
  1. 29 42
      rendering/Shader.cpp
  2. 39 7
      rendering/Shader.h
  3. 3 0
      wrapper/GL.cpp
  4. 3 0
      wrapper/GL.h

+ 29 - 42
rendering/Shader.cpp

@@ -4,61 +4,48 @@
 #include "utils/Logger.h"
 #include "wrapper/GL.h"
 
-Shader::Shader() : vertex(0), geometry(0), fragment(0), program(0) {
+Shader::Shader() : shaders(0), program(0) {
 }
 
 Shader::~Shader() {
-    GL::deleteShader(vertex);
-    GL::deleteShader(geometry);
-    GL::deleteShader(fragment);
+    for(GL::Shader shader : shaders) {
+        GL::deleteShader(shader);
+    }
     GL::deleteProgram(program);
 }
 
-Error Shader::compile(const char* vertexPath, const char* geometryPath,
-                      const char* fragmentPath) {
-    if(vertexPath != nullptr) {
-        Error error = compile(vertexPath, vertex, GL::VERTEX_SHADER);
-        if(error.has()) {
-            return error;
-        }
-    }
-    if(geometryPath != nullptr) {
-        Error error = compile(geometryPath, geometry, GL::GEOMETRY_SHADER);
-        if(error.has()) {
-            return error;
-        }
-    }
-    if(fragmentPath != nullptr) {
-        Error error = compile(fragmentPath, fragment, GL::FRAGMENT_SHADER);
-        if(error.has()) {
-            return error;
-        }
-    }
-    program = GL::createProgram();
-    if(vertexPath != nullptr) {
-        GL::attachShader(program, vertex);
+static bool endsWith(const char* path, int length, const char* ending) {
+    int endingLength = strlen(ending);
+    if(length < endingLength) {
+        return false;
     }
-    if(geometryPath != nullptr) {
-        GL::attachShader(program, geometry);
-    }
-    if(fragmentPath != nullptr) {
-        GL::attachShader(program, fragment);
-    }
-    GL::linkProgram(program);
-    Error error = GL::getError("cannot link");
-    if(error.has()) {
-        return error;
+    return strcmp(path + (length - endingLength), ending) == 0;
+}
+
+GL::ShaderType Shader::getShaderType(const char* path) const {
+    int length = strlen(path);
+    if(endsWith(path, length, ".vs")) {
+        return GL::VERTEX_SHADER;
+    } else if(endsWith(path, length, ".fs")) {
+        return GL::FRAGMENT_SHADER;
+    } else if(endsWith(path, length, ".gs")) {
+        return GL::GEOMETRY_SHADER;
+    } else if(endsWith(path, length, ".tcs")) {
+        return GL::TESSELATION_CONTROL_SHADER;
+    } else if(endsWith(path, length, ".tes")) {
+        return GL::TESSELATION_EVALUATION_SHADER;
     }
-    return GL::getLinkerError(program);
+    return GL::NO_SHADER;
 }
 
-Error Shader::compile(const char* path, GL::Shader& s, GL::ShaderType st) {
+Error Shader::readAndCompile(const char* path, GL::Shader& s,
+                             GL::ShaderType st) {
     List<char> code;
     Error error = readFile(code, path);
     if(error.has()) {
         return error;
     }
-    return compile(s, code, st);
+    return compileType(s, code, st);
 }
 
 Error Shader::readFile(List<char>& code, const char* path) const {
@@ -78,8 +65,8 @@ Error Shader::readFile(List<char>& code, const char* path) const {
     return {};
 }
 
-Error Shader::compile(GL::Shader& s, const List<char>& code,
-                      GL::ShaderType st) {
+Error Shader::compileType(GL::Shader& s, const List<char>& code,
+                          GL::ShaderType st) {
     s = GL::createShader(st);
     GL::compileShader(s, code.begin());
     Error error = GL::getError("compile error");

+ 39 - 7
rendering/Shader.h

@@ -2,14 +2,14 @@
 #define SHADER_H
 
 #include "math/Vector.h"
+#include "utils/Array.h"
 #include "utils/Error.h"
 #include "utils/List.h"
 #include "wrapper/GL.h"
 
 class Shader final {
-    GL::Shader vertex;
-    GL::Shader geometry;
-    GL::Shader fragment;
+    static constexpr int MAX_SHADERS = 5;
+    Array<GL::Shader, MAX_SHADERS> shaders;
     GL::Program program;
 
 public:
@@ -20,8 +20,39 @@ public:
     Shader& operator=(const Shader& other) = delete;
     Shader& operator=(Shader&& other) = delete;
 
-    Error compile(const char* vertexPath, const char* geometryPath,
-                  const char* fragmentPath);
+    template<typename... Args>
+    Error compile(Args&&... args) {
+        const int size = sizeof...(args);
+        const char* paths[size] = {args...};
+        static_assert(size <= MAX_SHADERS, "too much shaders paths given");
+
+        for(int i = 0; i < size; i++) {
+            GL::ShaderType type = getShaderType(paths[i]);
+            if(type == GL::NO_SHADER) {
+                Error error = {"'"};
+                error.message.append(paths[i]).append(
+                    "' is not a valid shader type");
+                return error;
+            }
+            Error error = readAndCompile(paths[i], shaders[i], type);
+            if(error.has()) {
+                return error;
+            }
+        }
+
+        program = GL::createProgram();
+        for(GL::Shader shader : shaders) {
+            if(shader != 0) {
+                GL::attachShader(program, shader);
+            }
+        }
+        GL::linkProgram(program);
+        Error error = GL::getError("cannot link");
+        if(error.has()) {
+            return error;
+        }
+        return GL::getLinkerError(program);
+    }
 
     void use() const;
     void setMatrix(const char* name, const float* data);
@@ -33,9 +64,10 @@ public:
     void setVector(const char* name, const Vector4& v);
 
 private:
-    Error compile(const char* path, GL::Shader& s, GL::ShaderType st);
+    GL::ShaderType getShaderType(const char* path) const;
+    Error readAndCompile(const char* path, GL::Shader& s, GL::ShaderType st);
     Error readFile(List<char>& code, const char* path) const;
-    Error compile(GL::Shader& s, const List<char>& code, GL::ShaderType st);
+    Error compileType(GL::Shader& s, const List<char>& code, GL::ShaderType st);
 };
 
 #endif

+ 3 - 0
wrapper/GL.cpp

@@ -26,9 +26,12 @@ static_assert(std::is_same<GL::VertexArray, GLuint>::value,
 static_assert(std::is_same<GL::Buffer, GLuint>::value,
               "buffer has invalid type");
 
+GL::ShaderType GL::NO_SHADER = 0;
 GL::ShaderType GL::VERTEX_SHADER = GL_VERTEX_SHADER;
 GL::ShaderType GL::FRAGMENT_SHADER = GL_FRAGMENT_SHADER;
 GL::ShaderType GL::GEOMETRY_SHADER = GL_GEOMETRY_SHADER;
+GL::ShaderType GL::TESSELATION_CONTROL_SHADER = GL_TESS_CONTROL_SHADER;
+GL::ShaderType GL::TESSELATION_EVALUATION_SHADER = GL_TESS_EVALUATION_SHADER;
 
 GL::Attribute::Attribute(int count, int size, int type, bool normalized)
     : count(count), size(size), type(type), normalized(normalized) {

+ 3 - 0
wrapper/GL.h

@@ -13,9 +13,12 @@ namespace GL {
     typedef unsigned int VertexArray;
     typedef unsigned int Buffer;
 
+    extern ShaderType NO_SHADER;
     extern ShaderType VERTEX_SHADER;
     extern ShaderType FRAGMENT_SHADER;
     extern ShaderType GEOMETRY_SHADER;
+    extern ShaderType TESSELATION_CONTROL_SHADER;
+    extern ShaderType TESSELATION_EVALUATION_SHADER;
 
     class Attribute final {
         int count;