// // 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/object.hpp" #include "game/graphics/shader.hpp" #include "game/graphics/shader_program.hpp" #include "game/graphics/texture.hpp" #include "game/math/shape.hpp" #include "game/util/hash.hpp" #include "helper.hpp" using namespace graphics; template struct key; template using key_t = typename key::type; template <> struct key { using type = std::string; }; template <> struct key { using type = std::pair; }; template <> struct key { using type = std::pair; }; template <> struct key { using type = std::tuple, std::string, std::string>; }; template struct cache { identity emplace(key_t const & key, T && value); std::unordered_map, key_t> keys; std::unordered_map, T> values; }; template identity cache::emplace(key_t const & key, T && value) { keys.emplace(value, key); return values.emplace(key, std::forward(value)).first->second; } struct graphics::manager_impl { cache materials; cache shaders; cache programs; cache textures; }; manager::manager() : pimpl_(new manager_impl) {} manager::~manager() {} identity manager::get(identity 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 uniforms; uniforms.push_back({texture_or_uniform(texture, uniform), shaders::uniform_location(program, uniform)}); math::vec2i size = get(uniforms[0].texture).size; // if (!uniforms.empty()) { size = ...; } return cache.emplace(key, material(program, size, uniforms)); } material const & manager::get(identity identity) const { auto & cache = pimpl_->materials; return cache.values.find(cache.keys.find(identity)->second)->second; } texture const & manager::get(identity identity) const { auto & cache = pimpl_->textures; auto it = cache.keys.find(identity); if (it == cache.keys.end()) { return texture::WHITE(); } return cache.values.find(it->second)->second; } identity 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 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 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 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)); } object manager::create_object(identity fromMaterial, math::vec2 atPosition, math::vec2 frameWidth) const { math::dim2::rectangle bounds{atPosition, frameWidth * get(fromMaterial).size}; return {bounds, bounds, fromMaterial, {make_vector(0.f, 0.f), frameWidth}}; }