Browse Source

Complete refactor to a centralized caching solution for graphics objects.

Sam Jaffe 6 năm trước cách đây
mục cha
commit
5e63c38d51

+ 4 - 0
graphics/graphics.xcodeproj/project.pbxproj

@@ -8,6 +8,7 @@
 
 /* Begin PBXBuildFile section */
 		CD1C82BD22988EC700825C4E /* matrix.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CD1C82BC22988EC700825C4E /* matrix.cxx */; settings = {COMPILER_FLAGS = "-fvisibility=default"; }; };
+		CD1C83E922998E2600825C4E /* manager.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CD1C83E722998E2600825C4E /* manager.cxx */; };
 		CD3AC6F21D2C03B7002B4BB0 /* material.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3AC6F01D2C03B7002B4BB0 /* material.cpp */; settings = {COMPILER_FLAGS = "-fvisibility=default"; }; };
 		CD3AC6F81D2C0518002B4BB0 /* texture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3AC6F61D2C0518002B4BB0 /* texture.cpp */; settings = {COMPILER_FLAGS = "-fvisibility=default"; }; };
 		CD3AC6FD1D2C06B5002B4BB0 /* shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3AC6FB1D2C06B5002B4BB0 /* shader.cpp */; settings = {COMPILER_FLAGS = "-fvisibility=default"; }; };
@@ -57,6 +58,7 @@
 /* Begin PBXFileReference section */
 		CD1C82B722988E4E00825C4E /* matrix.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = matrix.hpp; sourceTree = "<group>"; };
 		CD1C82BC22988EC700825C4E /* matrix.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = matrix.cxx; sourceTree = "<group>"; };
+		CD1C83E722998E2600825C4E /* manager.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = manager.cxx; sourceTree = "<group>"; };
 		CD3AC6E21D2C0364002B4BB0 /* libgraphics.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libgraphics.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
 		CD3AC6F01D2C03B7002B4BB0 /* material.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = material.cpp; sourceTree = "<group>"; };
 		CD3AC6F61D2C0518002B4BB0 /* texture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = texture.cpp; sourceTree = "<group>"; };
@@ -138,6 +140,7 @@
 				CD3AC6FB1D2C06B5002B4BB0 /* shader.cpp */,
 				CD3AC7171D2C0950002B4BB0 /* shader_program.cpp */,
 				CD3AC6F61D2C0518002B4BB0 /* texture.cpp */,
+				CD1C83E722998E2600825C4E /* manager.cxx */,
 			);
 			name = model;
 			sourceTree = "<group>";
@@ -297,6 +300,7 @@
 				CD62FD1E2292412900376440 /* renderer.cxx in Sources */,
 				CD3AC6F81D2C0518002B4BB0 /* texture.cpp in Sources */,
 				CD3AC7261D2C0C63002B4BB0 /* object.cpp in Sources */,
+				CD1C83E922998E2600825C4E /* manager.cxx in Sources */,
 				CD62FCF82290DC9000376440 /* opengl_helper.cxx in Sources */,
 				CD62FD232292C76B00376440 /* opengl_renderer.cxx in Sources */,
 			);

+ 45 - 0
graphics/include/game/graphics/manager.hpp

@@ -0,0 +1,45 @@
+//
+//  manager.hpp
+//  graphics
+//
+//  Created by Sam Jaffe on 5/25/19.
+//  Copyright © 2019 Sam Jaffe. All rights reserved.
+//
+
+#pragma once
+
+#include <unordered_map>
+
+#include "game/util/identity.hpp"
+
+namespace graphics {
+  namespace shaders {
+    enum class type : unsigned int;
+  }
+  class material;
+  class shader;
+  class shader_program;
+  class texture;
+
+  class manager {
+  public:
+    manager();
+    ~manager();
+
+    identity<material> get(identity<shader_program> program,
+                           std::string const & texture,
+                           std::string const & uniform) const;
+    identity<shader> get(shaders::type type, std::string const & path) const;
+    identity<shader_program> get(std::string const & fragment,
+                                 std::string const & vertex) const;
+    identity<texture> get(std::string const & path) const;
+
+    material const & get(identity<material> identity) const;
+
+  private:
+    identity<texture> texture_or_uniform(std::string const & path,
+                                         std::string const & uniform) const;
+
+    std::unique_ptr<struct manager_impl> pimpl_;
+  };
+}

+ 10 - 14
graphics/include/game/graphics/material.hpp

@@ -11,29 +11,25 @@
 
 #include "game/math/math_fwd.hpp"
 #include "game/util/identity.hpp"
-#include "shader_program.hpp"
+#include "vector/vector.hpp"
 
 namespace graphics {
   class texture;
+  struct shader_program;
+
   struct uniform {
-    flyweight<texture> texture;
+    identity<texture> texture;
     int uniform_id; // TODO (sjaffe): use an enum and hide remapping?
   };
 
-  class material : public identity<material> {
-  public:
-    shader_program const shaders;
-    std::vector<uniform> uniforms;
-
-  public:
-    static flyweight<material> create(shader_program const & sp,
-                                      std::string const & texture,
-                                      std::string const & uniform);
+  struct material : public identity<material> {
+    material(identity<shader_program> const & sp, math::vec2i size,
+             std::vector<uniform> const & uniforms);
 
-    math::vec2i size() const;
     void activate() const;
 
-  private:
-    material(unsigned int, shader_program const &);
+    identity<shader_program> program;
+    math::vec2i size;
+    std::vector<uniform> uniforms;
   };
 }

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

@@ -11,7 +11,7 @@
 
 #include "game/math/math_fwd.hpp"
 #include "game/math/shape.hpp"
-#include "game/util/flyweight.hpp"
+#include "game/util/identity.hpp"
 #include "vector/vector.hpp"
 
 namespace graphics {
@@ -21,7 +21,7 @@ namespace graphics {
   struct object {
     math::dim2::rectangle location;
     math::dim2::quad points;
-    flyweight<material> material;
+    identity<material> material;
     math::dim2::rectangle frame;
   }; // size:56, align:4
 

+ 7 - 5
graphics/include/game/graphics/renderer.hpp

@@ -8,9 +8,11 @@
 
 #pragma once
 
+#include <unordered_map>
+
 #include "game/math/math_fwd.hpp"
-#include "game/util/flyweight.hpp"
 #include "game/util/hash.hpp"
+#include "game/util/identity.hpp"
 #include "vector/vector.hpp"
 
 namespace graphics {
@@ -22,7 +24,7 @@ namespace graphics {
   struct renderer {
     virtual ~renderer() {}
     virtual void draw(object const & obj) = 0;
-    virtual void draw(flyweight<material>, math::matr4 const &,
+    virtual void draw(identity<material>, math::matr4 const &,
                       std::vector<vertex> const &) = 0;
     virtual void clear() = 0;
     virtual void flush() = 0;
@@ -34,7 +36,7 @@ namespace graphics {
   public:
     direct_renderer(driver d);
     void draw(object const & obj) override;
-    void draw(flyweight<material>, math::matr4 const &,
+    void draw(identity<material>, math::matr4 const &,
               std::vector<vertex> const &) override;
     void clear() override;
     void flush() override;
@@ -48,7 +50,7 @@ namespace graphics {
     batch_renderer(renderer * impl, std::size_t batch_size = 0);
     ~batch_renderer();
     void draw(object const & obj) override;
-    void draw(flyweight<material>, math::matr4 const &,
+    void draw(identity<material>, math::matr4 const &,
               std::vector<vertex> const &) override;
     void clear() override { impl_->clear(); }
     void flush() override;
@@ -59,7 +61,7 @@ namespace graphics {
 
   private:
     renderer * impl_;
-    std::unordered_map<flyweight<material>, std::vector<vertex>> batches_;
+    std::unordered_map<identity<material>, std::vector<vertex>> batches_;
     std::size_t batch_size_;
     std::size_t elements_;
   };

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

@@ -9,21 +9,16 @@
 
 #include <string>
 
-#include "game/util/flyweight.hpp"
+#include "game/util/identity.hpp"
 
 namespace graphics {
   namespace shaders {
     enum class type : unsigned int;
   }
-  class shader : public identity<shader> {
-  public:
+  struct shader : public identity<shader> {
+    shader(shaders::type, std::string const &);
+
     shaders::type type;
     std::string path;
-
-  public:
-    static flyweight<shader> create(shaders::type tp, std::string const & path);
-
-  private:
-    shader(unsigned int, shaders::type, std::string const &);
   };
 }

+ 6 - 12
graphics/include/game/graphics/shader_program.hpp

@@ -9,22 +9,16 @@
 
 #include <string>
 
-#include "game/util/flyweight.hpp"
-
-#include "shader.hpp"
+#include "game/util/identity.hpp"
 
 namespace graphics {
-  class shader_program : public identity<shader_program> {
-  public:
-    flyweight<shader> fragment_shader;
-    flyweight<shader> vertex_shader;
+  struct shader;
+  struct shader_program : public identity<shader_program> {
+    shader_program(identity<shader>, identity<shader>);
 
-  public:
-    static flyweight<shader_program> create(std::string const & frag,
-                                            std::string const & vert);
     void activate() const;
 
-  private:
-    shader_program(unsigned int, flyweight<shader>, flyweight<shader>);
+    identity<shader> fragment_shader;
+    identity<shader> vertex_shader;
   };
 }

+ 8 - 7
graphics/include/game/graphics/texture.hpp

@@ -8,22 +8,23 @@
 #pragma once
 
 #include "game/math/math_fwd.hpp"
-#include "game/util/flyweight.hpp"
+#include "game/util/identity.hpp"
 #include "vector/vector.hpp"
 
 namespace graphics {
   class texture : public identity<texture> {
   public:
+    texture(std::string const & str);
+
     static texture const WHITE();
     static texture const DARK_YELLOW();
     static texture const LIGHT_BLUE();
-    math::vec2i const size;
-
-  public:
-    static flyweight<texture> create(std::string const & imagefile);
 
   private:
-    static texture create(char const *, math::vec2i);
-    texture(unsigned int, math::vec2i = math::vec2i{{0, 0}});
+    texture(std::pair<unsigned int, math::vec2i>);
+    texture(char const *, math::vec2i);
+
+  public:
+    math::vec2i const size;
   };
 }

+ 7 - 7
graphics/src/helper.hpp

@@ -12,8 +12,7 @@
 #include <utility>
 
 #include "game/math/math_fwd.hpp"
-
-template <typename> class flyweight;
+#include "game/util/identity.hpp"
 
 namespace graphics {
   class shader;
@@ -26,13 +25,14 @@ namespace graphics {
   namespace shaders {
     enum class type : unsigned int { FRAGMENT, VERTEX };
     unsigned int init(type, std::string const &);
-    unsigned int init(flyweight<shader> const & fragmentShader,
-                      flyweight<shader> const & vertexShader);
-    void activate(unsigned int id);
-    int uniform_location(unsigned int id, std::string const & uniform);
+    unsigned int init(identity<shader> const & fragmentShader,
+                      identity<shader> const & vertexShader);
+    void activate(identity<shader_program> id);
+    int uniform_location(identity<shader_program> id,
+                         std::string const & uniform);
   }
   namespace materials {
-    void activate(flyweight<shader_program> program,
+    void activate(identity<shader_program> program,
                   std::vector<uniform> const & uniforms);
   }
 }

+ 123 - 0
graphics/src/manager.cxx

@@ -0,0 +1,123 @@
+//
+//  manager.cxx
+//  graphics
+//
+//  Created by Sam Jaffe on 5/25/19.
+//  Copyright © 2019 Sam Jaffe. All rights reserved.
+//
+
+#include "game/graphics/manager.hpp"
+
+#include "game/graphics/material.hpp"
+#include "game/graphics/shader.hpp"
+#include "game/graphics/shader_program.hpp"
+#include "game/graphics/texture.hpp"
+#include "game/util/hash.hpp"
+#include "helper.hpp"
+
+using namespace graphics;
+
+template <typename> struct key;
+template <typename T> using key_t = typename key<T>::type;
+
+template <> struct key<texture> { using type = std::string; };
+template <> struct key<shader> {
+  using type = std::pair<shaders::type, std::string>;
+};
+template <> struct key<shader_program> {
+  using type = std::pair<std::string, std::string>;
+};
+template <> struct key<material> {
+  using type = std::tuple<identity<shader_program>, std::string, std::string>;
+};
+
+template <typename T> struct cache {
+  identity<T> emplace(key_t<T> const & key, T && value);
+  std::unordered_map<identity<T>, key_t<T>> keys;
+  std::unordered_map<key_t<T>, T> values;
+};
+
+template <typename T>
+identity<T> cache<T>::emplace(key_t<T> const & key, T && value) {
+  keys.emplace(value, key);
+  return values.emplace(key, std::forward<T>(value)).first->second;
+}
+
+struct graphics::manager_impl {
+  cache<material> materials;
+  cache<shader> shaders;
+  cache<shader_program> programs;
+  cache<texture> textures;
+};
+
+manager::manager() : pimpl_(new manager_impl) {}
+manager::~manager() {}
+
+identity<material> manager::get(identity<shader_program> program,
+                                std::string const & texture,
+                                std::string const & uniform) const {
+  auto key = std::make_tuple(program, texture, uniform);
+  auto & cache = pimpl_->materials;
+  auto found = cache.values.find(key);
+  if (found != cache.values.end()) { return found->second; }
+
+  std::vector<struct uniform> uniforms;
+  uniforms.push_back({texture_or_uniform(texture, uniform),
+                      shaders::uniform_location(program, uniform)});
+  math::vec2i size = make_vector(1, 1);
+  //  if (!uniforms.empty()) { size = ...; }
+  return cache.emplace(key, material(program, size, uniforms));
+}
+
+material const & manager::get(identity<material> identity) const {
+  auto & cache = pimpl_->materials;
+  return cache.values.find(cache.keys.find(identity)->second)->second;
+}
+
+identity<shader> manager::get(shaders::type type,
+                              std::string const & path) const {
+  auto key = std::make_pair(type, path);
+  auto & cache = pimpl_->shaders;
+  auto found = cache.values.find(key);
+  if (found != cache.values.end()) { return found->second; }
+  return cache.emplace(key, shader(type, path));
+}
+
+identity<texture>
+manager::texture_or_uniform(std::string const & path,
+                            std::string const & uniform) const {
+  if (!path.empty()) {
+    try {
+      return get(path);
+    } catch (std::exception const & e) {
+      // TODO: Logging
+    }
+  }
+  if (uniform == "u_normalMap") {
+    return texture::LIGHT_BLUE();
+  } else if (uniform == "u_specularMap") {
+    return texture::DARK_YELLOW();
+  } else if (uniform == "u_diffuseMap") {
+    return texture::WHITE();
+  }
+  throw;
+}
+
+identity<shader_program> manager::get(std::string const & fragment,
+                                      std::string const & vertex) const {
+  auto key = std::make_pair(fragment, vertex);
+  auto & cache = pimpl_->programs;
+  auto found = cache.values.find(key);
+  if (found != cache.values.end()) { return found->second; }
+  auto fragment_shader = get(shaders::type::FRAGMENT, fragment);
+  auto vertex_shader = get(shaders::type::VERTEX, vertex);
+
+  return cache.emplace(key, shader_program(fragment_shader, vertex_shader));
+}
+
+identity<texture> manager::get(std::string const & path) const {
+  auto & cache = pimpl_->textures;
+  auto found = cache.values.find(path);
+  if (found != cache.values.end()) { return found->second; }
+  return cache.emplace(path, texture(path));
+}

+ 7 - 43
graphics/src/material.cpp

@@ -13,52 +13,16 @@
 
 using namespace graphics;
 
-namespace {
-  using key_t = std::tuple<flyweight<shader_program>, std::string, std::string>;
-  std::unordered_map<key_t, flyweight<material>> g_materials;
-}
-
 static math::vec2i ZERO{{0, 0}};
 
-flyweight<texture> get_texture(std::string const & texture,
-                               std::string const & uniform) {
-  if (!texture.empty()) {
-    try {
-      return texture::create(texture);
-    } catch (std::exception const & e) {
-      // TODO: Logging
-    }
-  }
-  if (uniform == "u_normalMap") {
-    return texture::LIGHT_BLUE();
-  } else if (uniform == "u_specularMap") {
-    return texture::DARK_YELLOW();
-  } else if (uniform == "u_diffuseMap") {
-    return texture::WHITE();
-  }
-  throw;
-}
-
-flyweight<material> material::create(shader_program const & sp,
-                                     std::string const & texture,
-                                     std::string const & uniform) {
-  key_t key = std::make_tuple(sp, texture, uniform);
-  auto found = g_materials.find(key);
-  if (found != g_materials.end()) { return found->second; }
-
+static unsigned int next_id() {
   static unsigned int id{0};
-  material mat{++id, sp};
-  mat.uniforms.push_back({get_texture(texture, uniform),
-                          shaders::uniform_location(sp.id, uniform)});
-  flyweight<material> fly{id, mat};
-  return g_materials.emplace(key, fly).first->second;
+  return ++id;
 }
 
-material::material(unsigned int id, shader_program const & sp)
-    : identity<material>(id), shaders(sp) {}
-
-math::vec2i material::size() const {
-  return uniforms.empty() ? ZERO : uniforms.front().texture.actual().size;
-}
+material::material(identity<shader_program> const & sp, math::vec2i size,
+                   std::vector<uniform> const & uniforms)
+    : identity<material>(next_id()), program(sp), size(size),
+      uniforms(uniforms) {}
 
-void material::activate() const { materials::activate(shaders, uniforms); }
+void material::activate() const { materials::activate(program, uniforms); }

+ 22 - 20
graphics/src/opengl_helper.cxx

@@ -250,8 +250,8 @@ namespace graphics { namespace shaders {
     return id;
   }
 
-  unsigned int init(flyweight<shader> const & fragmentShader,
-                    flyweight<shader> const & vertexShader) {
+  unsigned int init(identity<shader> const & fragmentShader,
+                    identity<shader> const & vertexShader) {
     // 9. Create a new shader program ID
     unsigned int id = glCreateProgram();
 
@@ -274,16 +274,17 @@ namespace graphics { namespace shaders {
     glGetProgramiv(id, GL_LINK_STATUS, &return_code);
 
     if (return_code != GL_TRUE) {
-      error_formatter::shader_program_error(id, fragmentShader.actual().path,
-                                            vertexShader.actual().path);
+      //      error_formatter::shader_program_error(id,
+      //      fragmentShader.actual().path,
+      //                                            vertexShader.actual().path);
       throw linker_error("Could not link shader program");
     }
     return id;
   }
 
-  void activate(unsigned int id) {
+  void activate(identity<shader_program> program) {
     // 100. Use the shader program ID to "turn it on" for all subsequent drawing
-    glUseProgram(id);
+    glUseProgram(program.id);
 
     /*
      // 101. Enable texturing and Bind texture(s) to GPU texture units
@@ -306,13 +307,13 @@ namespace graphics { namespace shaders {
 
     // 102. Get the location # of each named uniform you wish to pass in to the
     // shader
-    int timeUniformLocation = glGetUniformLocation(id, "u_time");
-    int scale = glGetUniformLocation(id, "Scale");
-    int diffuseMapUniformLocation = glGetUniformLocation(id, "u_diffuseMap");
-    int normalMapUniformLocation = glGetUniformLocation(id, "u_normalMap");
-    int specularMapUniformLocation = glGetUniformLocation(id, "u_specularMap");
-    int emissiveMapUniformLocation = glGetUniformLocation(id, "u_emissiveMap");
-    int debugWave = glGetUniformLocation(id, "g_debugWave");
+    int timeUniformLocation = glGetUniformLocation(program.id, "u_time");
+    int scale = glGetUniformLocation(program.id, "Scale");
+    int diffuseMap = glGetUniformLocation(program.id, "u_diffuseMap");
+    int normalMap = glGetUniformLocation(program.id, "u_normalMap");
+    int specularMap = glGetUniformLocation(program.id, "u_specularMap");
+    int emissiveMap = glGetUniformLocation(program.id, "u_emissiveMap");
+    int debugWave = glGetUniformLocation(program.id, "g_debugWave");
 
     // 103. Set the uniform values, including the texture unit numbers for
     // texture (sampler) uniforms
@@ -321,22 +322,23 @@ namespace graphics { namespace shaders {
     glUniform1f(scale, 2.f);
     glUniform1i(debugWave, 1); // TODO: m_waveEffectOn in ShaderProgram??
     // for GL_TEXTURE0, texture unit 0
-    glUniform1i(diffuseMapUniformLocation, 0);
+    glUniform1i(diffuseMap, 0);
     // for GL_TEXTURE1, texture unit 1
-    glUniform1i(normalMapUniformLocation, 1);
+    glUniform1i(normalMap, 1);
     // for GL_TEXTURE2, texture unit 2
-    glUniform1i(specularMapUniformLocation, 2);
+    glUniform1i(specularMap, 2);
     // for GL_TEXTURE3, texture unit 3
-    glUniform1i(emissiveMapUniformLocation, 3);
+    glUniform1i(emissiveMap, 3);
   }
 
-  int uniform_location(unsigned int id, std::string const & uniform) {
-    return glGetUniformLocation(id, uniform.c_str());
+  int uniform_location(identity<shader_program> program,
+                       std::string const & uniform) {
+    return glGetUniformLocation(program.id, uniform.c_str());
   }
 }}
 
 namespace graphics { namespace materials {
-  void activate(flyweight<shader_program> program,
+  void activate(identity<shader_program> program,
                 std::vector<uniform> const & uniforms) {
     glUseProgram(program.id);
 

+ 13 - 7
graphics/src/opengl_renderer.cxx

@@ -12,6 +12,7 @@
 #include <OpenGL/gl3.h>
 #endif
 
+#include "game/graphics/manager.hpp"
 #include "game/graphics/material.hpp"
 #include "game/graphics/vertex.h"
 #include "game/util/env.hpp"
@@ -27,19 +28,25 @@ public:
   opengl_renderer();
   ~opengl_renderer();
 
-  void draw(flyweight<material>, math::matr4 const &,
+  void draw(identity<material>, math::matr4 const &,
             std::vector<vertex> const &) override;
   void clear() override;
   void flush() override;
 
+  std::shared_ptr<class manager const> manager() const override { return mgr; }
+
 private:
   const math::matr4 identity{math::matrix::identity<float, 4>()};
+
+  std::shared_ptr<class manager> mgr;
+  unsigned int active_material;
+
   math::matr4 world_to_clip{identity};
   double current_time{0.0};
   unsigned int vertex_array_object{0}, vertex_buffer_object{0};
 };
 
-opengl_renderer::opengl_renderer() {
+opengl_renderer::opengl_renderer() : mgr(), active_material(0) {
   glGenVertexArrays(1, &vertex_array_object);
   glBindVertexArray(vertex_array_object);
   glGenBuffers(1, &vertex_buffer_object);
@@ -73,14 +80,13 @@ void opengl_renderer::clear() {
 
 void opengl_renderer::flush() { glFlush(); }
 
-void opengl_renderer::draw(flyweight<material> material,
+void opengl_renderer::draw(::identity<material> material_id,
                            math::matr4 const & object_to_world,
                            std::vector<vertex> const & vertices) {
-  // TODO: Don't activate here?
-  auto const & mat = material.actual();
+  material const & mat = manager()->get(material_id);
+  if (material_id != active_material) { mat.activate(); }
   // TODO: Attatch shader-id to material-id
-  unsigned int const id = mat.shaders.id;
-  mat.activate();
+  unsigned int const id = mat.program.id;
 
   int objectLocation = glGetUniformLocation(id, "u_objectToWorldMatrix");
   // Argument 2: GL_TRUE -> row-major ; GL_FALSE -> column-major

+ 2 - 2
graphics/src/renderer.cxx

@@ -34,7 +34,7 @@ void direct_renderer::draw(object const & obj) {
   draw(obj.material, math::matr4(), verts);
 }
 
-void direct_renderer::draw(flyweight<material> material,
+void direct_renderer::draw(identity<material> material,
                            math::matr4 const & object_to_world,
                            std::vector<vertex> const & verts) {
   pimpl->draw(material, object_to_world, verts);
@@ -57,7 +57,7 @@ void batch_renderer::draw(object const & obj) {
 }
 
 // TODO (sjaffe): object-to-world matrix...
-void batch_renderer::draw(flyweight<material> material, math::matr4 const &,
+void batch_renderer::draw(identity<material> material, math::matr4 const &,
                           std::vector<vertex> const & verts) {
   auto & batch_verts = batches_[material];
   batch_verts.insert(batch_verts.end(), verts.begin(), verts.end());

+ 4 - 2
graphics/src/renderer_impl.hpp

@@ -10,17 +10,19 @@
 
 #include "game/graphics/renderer.hpp"
 #include "game/math/math_fwd.hpp"
-#include "game/util/flyweight.hpp"
+#include "game/util/identity.hpp"
 
 namespace graphics {
   template <driver> renderer_impl * get_renderer_impl();
 
+  class manager;
   class material;
   struct vertex;
 
   struct renderer_impl {
     virtual ~renderer_impl() {}
-    virtual void draw(flyweight<material>, math::matr4 const &,
+    virtual std::shared_ptr<manager const> manager() const = 0;
+    virtual void draw(identity<material>, math::matr4 const &,
                       std::vector<vertex> const &) = 0;
     virtual void clear() = 0;
     virtual void flush() = 0;

+ 2 - 20
graphics/src/shader.cpp

@@ -7,27 +7,9 @@
 
 #include "game/graphics/shader.hpp"
 
-#include <unordered_map>
-
-#include "game/util/hash.hpp"
 #include "helper.hpp"
 
 using namespace graphics;
 
-namespace {
-  using key_t = std::pair<shaders::type, std::string>;
-  std::unordered_map<key_t, flyweight<shader>> g_shaders;
-}
-
-flyweight<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; }
-
-  auto id = shaders::init(tp, path);
-  flyweight<shader> fly{id, {id, tp, path}};
-  return g_shaders.emplace(key, fly).first->second;
-}
-
-shader::shader(unsigned int id, shaders::type type, std::string const & path)
-    : identity<shader>(id), type(type), path(path) {}
+shader::shader(shaders::type type, std::string const & path)
+    : identity<shader>(shaders::init(type, path)), type(type), path(path) {}

+ 3 - 27
graphics/src/shader_program.cpp

@@ -7,37 +7,13 @@
 
 #include "game/graphics/shader_program.hpp"
 
-#include <unordered_map>
-#include <utility>
-
 #include "game/graphics/shader.hpp"
-#include "game/util/hash.hpp"
 #include "helper.hpp"
 
 using namespace graphics;
 
-namespace {
-  using key_t = std::pair<std::string, std::string>;
-  std::unordered_map<key_t, flyweight<shader_program>> g_shader_programs;
-}
-
-flyweight<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; }
-
-  auto fragment_shader = shader::create(shaders::type::FRAGMENT, frag);
-  auto vertex_shader = shader::create(shaders::type::VERTEX, vert);
-
-  auto id = shaders::init(fragment_shader, vertex_shader);
-  flyweight<shader_program> fly{id, {id, fragment_shader, vertex_shader}};
-  return g_shader_programs.emplace(key, fly).first->second;
-}
-
-shader_program::shader_program(unsigned int id, flyweight<shader> frag,
-                               flyweight<shader> vert)
-    : identity<shader_program>(id), fragment_shader(frag), vertex_shader(vert) {
-}
+shader_program::shader_program(identity<shader> frag, identity<shader> vert)
+    : identity<shader_program>(shaders::init(fragment_shader, vertex_shader)),
+      fragment_shader(frag), vertex_shader(vert) {}
 
 void shader_program::activate() const { shaders::activate(id); }

+ 12 - 20
graphics/src/texture.cpp

@@ -26,10 +26,6 @@ void stbi_image_free(void *);
 
 using namespace graphics;
 
-namespace {
-  std::unordered_map<std::string, flyweight<texture>> g_textures;
-}
-
 static textures::format format(int comps) {
   switch (comps) {
   case 3:
@@ -41,36 +37,32 @@ static textures::format format(int comps) {
   }
 }
 
-flyweight<texture> texture::create(std::string const & imagefile) {
-  auto found = g_textures.find(imagefile);
-  if (found != g_textures.end()) { return found->second; }
-
+std::pair<unsigned int, math::vec2i> create(std::string const & path) {
   int components = 0;
   math::vec2i size;
-  std::string file = env::resource_file(imagefile);
+  std::string file = env::resource_file(path);
   auto data = stbi_load(file.c_str(), &size.x(), &size.y(), &components, 0);
   scope(exit) { stbi_image_free(data); };
-  auto id = textures::init(format(components), size, data);
-  flyweight<texture> fly{id, {id, size}};
-  return g_textures.emplace(imagefile, fly).first->second;
+  return {textures::init(format(components), size, data), size};
 }
 
-texture texture::create(char const * data, math::vec2i size) {
-  return {textures::init(format(4), size, data), size};
-}
+texture::texture(std::string const & path) : texture(create(path)) {}
+
+texture::texture(std::pair<unsigned int, math::vec2i> pair)
+    : identity<texture>(pair.first), size(pair.second) {}
 
-texture::texture(unsigned int id, math::vec2i sz)
-    : identity<texture>(id), size(sz) {}
+texture::texture(char const * data, math::vec2i size)
+    : identity<texture>(textures::init(format(4), size, data)), size(size) {}
 
 texture const texture::WHITE() {
-  static auto t = texture::create("\xFF\xFF\xFF\xFF", {{1, 1}});
+  static auto t = texture("\xFF\xFF\xFF\xFF", {{1, 1}});
   return t;
 }
 texture const texture::DARK_YELLOW() {
-  static auto t = texture::create("\x80\x80\x00\xFF", {{1, 1}});
+  static auto t = texture("\x80\x80\x00\xFF", {{1, 1}});
   return t;
 }
 texture const texture::LIGHT_BLUE() {
-  static auto t = texture::create("\x80\x80\xFF\xFF", {{1, 1}});
+  static auto t = texture("\x80\x80\xFF\xFF", {{1, 1}});
   return t;
 }

+ 0 - 33
util/include/game/util/flyweight.hpp

@@ -1,33 +0,0 @@
-//
-//  flyweight.hpp
-//  gameutils
-//
-//  Created by Sam Jaffe on 5/19/19.
-//
-
-#pragma once
-
-#include <unordered_map>
-
-#include "identity.hpp"
-
-template <typename T> class flyweight {
-private:
-  static std::unordered_map<unsigned int, T> actual_;
-
-public:
-  const unsigned int id;
-
-public:
-  flyweight(unsigned int id, T actual) : id(id) {
-    actual_.emplace(id, std::move(actual));
-  }
-  flyweight(identity<T> actual) : id(actual.id) {}
-  T const & actual() const { return actual_.find(this->id)->second; }
-
-  friend bool operator==(flyweight lhs, flyweight rhs) {
-    return lhs.id == rhs.id;
-  }
-};
-
-template <typename T> std::unordered_map<unsigned int, T> flyweight<T>::actual_;

+ 4 - 4
util/include/game/util/hash.hpp

@@ -11,12 +11,12 @@
 #include <tuple>
 #include <utility>
 
-template <typename> class flyweight;
+template <typename, typename> class identity;
 
 namespace std {
-  template <typename T> struct hash<flyweight<T>> {
-    std::size_t operator()(flyweight<T> tp) const {
-      return std::hash<unsigned int>()(tp.id);
+  template <typename T, typename I> struct hash<identity<T, I>> {
+    std::size_t operator()(identity<T, I> tp) const {
+      return std::hash<I>()(tp.id);
     }
   };
 

+ 7 - 0
util/include/game/util/identity.hpp

@@ -17,4 +17,11 @@ private:
   friend T;
   identity(ID _id) : id(std::move(_id)) {}
   identity() = delete;
+
+  friend bool operator==(identity const & lhs, identity const & rhs) {
+    return lhs.id == rhs.id;
+  }
+  friend bool operator!=(identity const & lhs, ID const & rhs) {
+    return lhs.id != rhs;
+  }
 };