Procházet zdrojové kódy

Add code for constructing a shader_program, rename graphics::program to graphics::shader_program.
TODO: Activate shader_program
TODO: Verbose linker errors.

Sam Jaffe před 6 roky
rodič
revize
7852406d51

+ 2 - 2
graphics/include/game/graphics/material.hpp

@@ -14,9 +14,9 @@
 namespace graphics {
   class material : public identity<material> {
   public:
-    program const shaders;
+    shader_program const shaders;
 
   private:
-    material(unsigned int, program);
+    material(unsigned int, shader_program);
   };
 }

+ 4 - 1
graphics/include/game/graphics/shader.hpp

@@ -12,9 +12,12 @@
 #include <string>
 
 namespace graphics {
+  namespace shaders {
+    enum class type : unsigned int;
+  }
   class shader : public identity<shader> {
   public:
-    static shader create(unsigned int type, std::string const & path);
+    static shader create(shaders::type tp, std::string const & path);
 
   private:
     shader(unsigned int);

+ 8 - 2
graphics/include/game/graphics/shader_program.hpp

@@ -7,12 +7,18 @@
 
 #pragma once
 
+#include <string>
+
 #include "game/util/identity.hpp"
 
 namespace graphics {
-  class program : public identity<program> {
+  class shader_program : public identity<shader_program> {
   public:
+    static shader_program create(std::string const & frag,
+                                 std::string const & vert);
+    void activate() const;
+
   private:
-    program(unsigned int);
+    shader_program(unsigned int);
   };
 }

+ 19 - 9
graphics/src/helper.hpp

@@ -13,20 +13,30 @@
 
 #include "game/math/math_fwd.hpp"
 
-namespace std {
-  template <typename T, typename S> struct hash<std::pair<T, S>> {
-    std::size_t operator()(std::pair<T, S> const & pair) const {
-      return std::hash<T>()(pair.first) ^ std::hash<S>()(pair.second);
-    }
-  };
-}
-
 namespace graphics {
+  class shader;
   namespace textures {
     enum class format { RGB, RGBA };
     unsigned int init(format, math::vec2i, void const *);
   }
   namespace shaders {
-    unsigned int init(unsigned int, std::string const &);
+    enum class type : unsigned int { FRAGMENT, VERTEX };
+    unsigned int init(type, std::string const &);
+    unsigned int init_program(shader const & fragmentShader,
+                              shader const & vertexShader);
   }
 }
+
+namespace std {
+  template <> struct hash<graphics::shaders::type> {
+    std::size_t operator()(graphics::shaders::type tp) const {
+      return std::hash<unsigned int>()(static_cast<unsigned int>(tp));
+    }
+  };
+
+  template <typename T, typename S> struct hash<std::pair<T, S>> {
+    std::size_t operator()(std::pair<T, S> const & pair) const {
+      return std::hash<T>()(pair.first) ^ std::hash<S>()(pair.second);
+    }
+  };
+}

+ 47 - 3
graphics/src/opengl_helper.cxx

@@ -18,6 +18,7 @@
 #include "scope_guard/scope_guard.hpp"
 #include "vector/vector.hpp"
 
+#include "game/graphics/shader.hpp"
 #include "game/util/env.hpp"
 #include "game/util/files.hpp"
 
@@ -190,8 +191,20 @@ namespace graphics { namespace shaders {
     using std::runtime_error::runtime_error;
   };
 
-  unsigned int init(unsigned int type, std::string const & path) {
-    unsigned int id;
+  struct linker_error : std::runtime_error {
+    using std::runtime_error::runtime_error;
+  };
+
+  static int gltype(type tp) {
+    switch (tp) {
+    case type::FRAGMENT:
+      return GL_FRAGMENT_SHADER;
+    case type::VERTEX:
+      return GL_VERTEX_SHADER;
+    }
+  }
+
+  unsigned int init(type tp, std::string const & path) {
     std::unique_ptr<char const[]> buffer;
 
     // 1. Load the vertex shader code (text file) to a new memory buffer
@@ -201,7 +214,8 @@ namespace graphics { namespace shaders {
     }
 
     // 2. Create a new shader ID
-    id = glCreateShader(type); // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
+    // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
+    unsigned int id = glCreateShader(gltype(tp));
 
     // 3. Associate the shader code with the new shader ID
     char const * buffer_ptr = buffer.get();
@@ -221,4 +235,34 @@ namespace graphics { namespace shaders {
     }
     return id;
   }
+
+  unsigned int init_program(shader const & fragmentShader,
+                            shader const & vertexShader) {
+    // 9. Create a new shader program ID
+    unsigned int id = glCreateProgram();
+
+    // 10. Attach the vertex and fragment shaders to the new shader program
+    glAttachShader(id, vertexShader.id);
+    glAttachShader(id, fragmentShader.id);
+
+    // 11. Do some other advanced stuff we'll do later on (like setting generic
+    // vertex attrib locations)
+    glBindAttribLocation(id, 0, "a_position");
+    glBindAttribLocation(id, 1, "a_color");
+    glBindAttribLocation(id, 2, "a_texCoords");
+    glBindAttribLocation(id, 3, "a_normal");
+
+    // 12. Link the program
+    glLinkProgram(id);
+
+    // 13. Check for link errors
+    int return_code;
+    glGetProgramiv(id, GL_LINK_STATUS, &return_code);
+
+    if (return_code != GL_TRUE) {
+      //      LogShaderProgramError(*id, vertPath, fragPath);
+      throw linker_error("Could not link shader program");
+    }
+    return id;
+  }
 }}

+ 4 - 4
graphics/src/shader.cpp

@@ -12,17 +12,17 @@
 #include "helper.hpp"
 
 namespace {
-  using key_t = std::pair<unsigned int, std::string>;
+  using key_t = std::pair<graphics::shaders::type, std::string>;
   std::unordered_map<key_t, ::graphics::shader> g_shaders;
 }
 
 namespace graphics {
-  shader shader::create(unsigned int type, std::string const & path) {
-    auto key = std::make_pair(type, path);
+  shader shader::create(shaders::type tp, std::string const & path) {
+    auto key = std::make_pair(tp, path);
     auto found = g_shaders.find(key);
     if (found != g_shaders.end()) { return found->second; }
 
-    shader shad{shaders::init(type, path)};
+    shader shad{shaders::init(tp, path)};
     return g_shaders.emplace(key, std::move(shad)).first->second;
   }
 

+ 29 - 0
graphics/src/shader_program.cpp

@@ -6,3 +6,32 @@
 //
 
 #include "game/graphics/shader_program.hpp"
+
+#include <unordered_map>
+#include <utility>
+
+#include "game/graphics/shader.hpp"
+#include "helper.hpp"
+
+namespace {
+  using key_t = std::pair<std::string, std::string>;
+  std::unordered_map<key_t, ::graphics::shader_program> g_shader_programs;
+}
+
+namespace graphics {
+  shader_program shader_program::create(std::string const & frag,
+                                        std::string const & vert) {
+    auto key = std::make_pair(frag, vert);
+    auto found = g_shader_programs.find(key);
+    if (found != g_shader_programs.end()) { return found->second; }
+
+    shader fragment_shader = shader::create(shaders::type::FRAGMENT, frag);
+    shader vertex_shader = shader::create(shaders::type::VERTEX, vert);
+
+    shader_program prog{shaders::init_program(fragment_shader, vertex_shader)};
+    return g_shader_programs.emplace(key, std::move(prog)).first->second;
+  }
+
+  shader_program::shader_program(unsigned int id)
+      : identity<shader_program>(id) {}
+}