Bläddra i källkod

Fix hashing for material

Sam Jaffe 6 år sedan
förälder
incheckning
a8ce75b0b5
3 ändrade filer med 41 tillägg och 3 borttagningar
  1. 30 0
      graphics/src/helper.hpp
  2. 7 3
      graphics/src/material.cpp
  3. 4 0
      util/include/game/util/flyweight.hpp

+ 30 - 0
graphics/src/helper.hpp

@@ -38,9 +38,39 @@ 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 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);
     }
   };
+
+  template <std::size_t I> struct tuple_hash;
+
+  template <> struct tuple_hash<0> {
+    template <typename... As>
+    std::size_t operator()(std::tuple<As...> const &) const {
+      return 0;
+    }
+  };
+
+  template <std::size_t I> struct tuple_hash {
+    template <typename... As>
+    std::size_t operator()(std::tuple<As...> const & tuple) const {
+      using elt = typename std::tuple_element<I - 1, std::tuple<As...>>::type;
+      return std::hash<elt>()(std::get<I - 1>(tuple)) ^
+             tuple_hash<I - 1>()(tuple);
+    }
+  };
+
+  template <typename... As> struct hash<std::tuple<As...>> {
+    std::size_t operator()(std::tuple<As...> const & tuple) const {
+      return tuple_hash<sizeof...(As)>()(tuple);
+    }
+  };
 }

+ 7 - 3
graphics/src/material.cpp

@@ -13,8 +13,8 @@
 using namespace graphics;
 
 namespace {
-  using key_t = std::pair<shaders::type, std::string>;
-  std::unordered_map<std::string, flyweight<material>> g_materials;
+  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}};
@@ -41,12 +41,16 @@ flyweight<texture> get_texture(std::string const & texture,
 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 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("", fly).first->second;
+  return g_materials.emplace(key, fly).first->second;
 }
 
 material::material(unsigned int id, shader_program const & sp)

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

@@ -24,6 +24,10 @@ public:
   }
   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_;