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