manager.cxx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. //
  2. // manager.cxx
  3. // graphics
  4. //
  5. // Created by Sam Jaffe on 5/25/19.
  6. // Copyright © 2019 Sam Jaffe. All rights reserved.
  7. //
  8. #include "game/graphics/manager.hpp"
  9. #include "game/graphics/exception.h"
  10. #include "game/graphics/material.hpp"
  11. #include "game/graphics/object.hpp"
  12. #include "game/graphics/shader.hpp"
  13. #include "game/graphics/shader_program.hpp"
  14. #include "game/graphics/texture.hpp"
  15. #include "game/math/shape.hpp"
  16. #include "game/util/hash.hpp"
  17. #include "helper.hpp"
  18. using namespace graphics;
  19. template <typename> struct key;
  20. template <typename T> using key_t = typename key<T>::type;
  21. template <> struct key<texture> { using type = std::string; };
  22. template <> struct key<shader> {
  23. using type = std::pair<shaders::type, std::string>;
  24. };
  25. template <> struct key<shader_program> {
  26. using type = std::pair<std::string, std::string>;
  27. };
  28. template <> struct key<material> {
  29. using type = std::tuple<identity<shader_program>, std::string, std::string>;
  30. };
  31. template <typename T> struct cache {
  32. identity<T> emplace(key_t<T> const & key, T && value);
  33. std::unordered_map<identity<T>, key_t<T>> keys;
  34. std::unordered_map<key_t<T>, T> values;
  35. };
  36. template <typename T>
  37. identity<T> cache<T>::emplace(key_t<T> const & key, T && value) {
  38. keys.emplace(value, key);
  39. return values.emplace(key, std::forward<T>(value)).first->second;
  40. }
  41. struct graphics::manager_cache {
  42. cache<material> materials;
  43. cache<shader> shaders;
  44. cache<shader_program> programs;
  45. cache<texture> textures;
  46. };
  47. manager::manager() : pcache_(new manager_cache) {}
  48. manager::~manager() {}
  49. materials::uniform uniform_id(std::string const & uniform) {
  50. if (uniform == "u_normalMap") {
  51. return materials::uniform::NORMAL;
  52. } else if (uniform == "u_specularMap") {
  53. return materials::uniform::SPECULAR;
  54. } else if (uniform == "u_diffuseMap") {
  55. return materials::uniform::DIFFUSE;
  56. }
  57. throw unmapped_enum<materials::uniform>(uniform);
  58. }
  59. identity<material> manager::get(identity<shader_program> program,
  60. std::string const & texture,
  61. std::string const & uniform) const {
  62. auto key = std::make_tuple(program, texture, uniform);
  63. auto & cache = pcache_->materials;
  64. auto found = cache.values.find(key);
  65. if (found != cache.values.end()) { return found->second; }
  66. std::vector<struct uniform> uniforms;
  67. uniforms.push_back(
  68. {texture_or_uniform(texture, uniform), uniform_id(uniform)});
  69. math::vec2i size = get(uniforms[0].texture).size;
  70. // if (!uniforms.empty()) { size = ...; }
  71. return cache.emplace(key, material(program, size, uniforms));
  72. }
  73. identity<shader> manager::get(shaders::type type,
  74. std::string const & path) const {
  75. auto key = std::make_pair(type, path);
  76. auto & cache = pcache_->shaders;
  77. auto found = cache.values.find(key);
  78. if (found != cache.values.end()) { return found->second; }
  79. return cache.emplace(key, compile(type, path));
  80. }
  81. identity<shader_program> manager::get(std::string const & fragment,
  82. std::string const & vertex) const {
  83. auto key = std::make_pair(fragment, vertex);
  84. auto & cache = pcache_->programs;
  85. auto found = cache.values.find(key);
  86. if (found != cache.values.end()) { return found->second; }
  87. auto fragment_shader = get(shaders::type::FRAGMENT, fragment);
  88. auto vertex_shader = get(shaders::type::VERTEX, vertex);
  89. return cache.emplace(key, compile(fragment_shader, vertex_shader));
  90. }
  91. identity<texture> manager::get(std::string const & path) const {
  92. auto & cache = pcache_->textures;
  93. auto found = cache.values.find(path);
  94. if (found != cache.values.end()) { return found->second; }
  95. textures::external_data data(path);
  96. return cache.emplace(path, compile(data.color, data.size, data.buffer));
  97. }
  98. object manager::create_object(identity<material> fromMaterial,
  99. math::vec2 atPosition, math::vec2 frameWidth,
  100. float scale) const {
  101. math::dim2::rectangle bounds{atPosition, frameWidth * get(fromMaterial).size *
  102. (scale ? scale : 1.f)};
  103. return {bounds, bounds, fromMaterial, {make_vector(0.f, 0.f), frameWidth}};
  104. }
  105. material const & manager::get(identity<material> identity) const {
  106. auto & cache = pcache_->materials;
  107. return cache.values.find(cache.keys.find(identity)->second)->second;
  108. }
  109. texture const & manager::get(identity<texture> identity) const {
  110. auto & cache = pcache_->textures;
  111. auto it = cache.keys.find(identity);
  112. // if (it == cache.keys.end()) { return texture::WHITE(); }
  113. return cache.values.find(it->second)->second;
  114. }
  115. void manager::prepare_uniforms() const {
  116. // Initialize the three default uniform-textures immediately
  117. auto & cache = pcache_->textures;
  118. if (cache.values.count("u_normalMap") != 0) return;
  119. auto RGBA = textures::format::RGBA;
  120. cache.emplace("u_normalMap", compile(RGBA, {{1, 1}}, "\x80\x80\xFF\xFF"));
  121. cache.emplace("u_specularMap", compile(RGBA, {{1, 1}}, "\x80\x80\x00\xFF"));
  122. cache.emplace("u_diffuseMap", compile(RGBA, {{1, 1}}, "\xFF\xFF\xFF\xFF"));
  123. }
  124. identity<texture>
  125. manager::texture_or_uniform(std::string const & path,
  126. std::string const & uniform) const {
  127. if (!path.empty()) {
  128. try {
  129. return get(path);
  130. } catch (std::exception const & e) {
  131. // TODO: Logging
  132. }
  133. }
  134. prepare_uniforms();
  135. // The uniform is primed into the cache already.
  136. auto & cache = pcache_->textures;
  137. return cache.values.find(uniform)->second;
  138. }