shader_cache.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #pragma once
  2. #include "shader.h"
  3. #include "utils/resource_utils.h"
  4. #include <QDebug>
  5. #include <QFile>
  6. #include <QString>
  7. #include <QStringList>
  8. #include <memory>
  9. #include <unordered_map>
  10. #include <utility>
  11. namespace Render::GL {
  12. class ShaderCache {
  13. public:
  14. auto load(const QString &name, const QString &vertPath,
  15. const QString &fragPath) -> Shader * {
  16. auto it = m_named.find(name);
  17. if (it != m_named.end()) {
  18. return it->second.get();
  19. }
  20. const QString resolved_vert =
  21. Utils::Resources::resolveResourcePath(vertPath);
  22. const QString resolved_frag =
  23. Utils::Resources::resolveResourcePath(fragPath);
  24. auto sh = std::make_unique<Shader>();
  25. if (!sh->loadFromFiles(resolved_vert, resolved_frag)) {
  26. qWarning() << "ShaderCache: Failed to load shader" << name;
  27. return nullptr;
  28. }
  29. Shader *raw = sh.get();
  30. m_named.emplace(name, std::move(sh));
  31. return raw;
  32. }
  33. auto get(const QString &name) const -> Shader * {
  34. auto it = m_named.find(name);
  35. return (it != m_named.end()) ? it->second.get() : nullptr;
  36. }
  37. auto getOrLoad(const QString &vertPath, const QString &fragPath) -> Shader * {
  38. const QString resolved_vert =
  39. Utils::Resources::resolveResourcePath(vertPath);
  40. const QString resolved_frag =
  41. Utils::Resources::resolveResourcePath(fragPath);
  42. auto key = resolved_vert + "|" + resolved_frag;
  43. auto it = m_byPath.find(key);
  44. if (it != m_byPath.end()) {
  45. return it->second.get();
  46. }
  47. auto sh = std::make_unique<Shader>();
  48. if (!sh->loadFromFiles(resolved_vert, resolved_frag)) {
  49. qWarning() << "ShaderCache: Failed to load shader from paths:"
  50. << resolved_vert << "," << resolved_frag;
  51. return nullptr;
  52. }
  53. Shader *raw = sh.get();
  54. m_byPath.emplace(std::move(key), std::move(sh));
  55. return raw;
  56. }
  57. void initializeDefaults() {
  58. static const QString kShaderBase = QStringLiteral(":/assets/shaders/");
  59. auto resolve = [](const QString &path) {
  60. return Utils::Resources::resolveResourcePath(path);
  61. };
  62. const QString basicVert =
  63. resolve(kShaderBase + QStringLiteral("basic.vert"));
  64. const QString basicFrag =
  65. resolve(kShaderBase + QStringLiteral("basic.frag"));
  66. const QString gridFrag = resolve(kShaderBase + QStringLiteral("grid.frag"));
  67. load(QStringLiteral("basic"), basicVert, basicFrag);
  68. load(QStringLiteral("grid"), basicVert, gridFrag);
  69. const QString cylVert =
  70. resolve(kShaderBase + QStringLiteral("cylinder_instanced.vert"));
  71. const QString cylFrag =
  72. resolve(kShaderBase + QStringLiteral("cylinder_instanced.frag"));
  73. load(QStringLiteral("cylinder_instanced"), cylVert, cylFrag);
  74. const QString fogVert =
  75. resolve(kShaderBase + QStringLiteral("fog_instanced.vert"));
  76. const QString fogFrag =
  77. resolve(kShaderBase + QStringLiteral("fog_instanced.frag"));
  78. load(QStringLiteral("fog_instanced"), fogVert, fogFrag);
  79. const QString grassVert =
  80. resolve(kShaderBase + QStringLiteral("grass_instanced.vert"));
  81. const QString grassFrag =
  82. resolve(kShaderBase + QStringLiteral("grass_instanced.frag"));
  83. load(QStringLiteral("grass_instanced"), grassVert, grassFrag);
  84. const QString stoneVert =
  85. resolve(kShaderBase + QStringLiteral("stone_instanced.vert"));
  86. const QString stoneFrag =
  87. resolve(kShaderBase + QStringLiteral("stone_instanced.frag"));
  88. load(QStringLiteral("stone_instanced"), stoneVert, stoneFrag);
  89. const QString plantVert =
  90. resolve(kShaderBase + QStringLiteral("plant_instanced.vert"));
  91. const QString plantFrag =
  92. resolve(kShaderBase + QStringLiteral("plant_instanced.frag"));
  93. load(QStringLiteral("plant_instanced"), plantVert, plantFrag);
  94. const QString pineVert =
  95. resolve(kShaderBase + QStringLiteral("pine_instanced.vert"));
  96. const QString pineFrag =
  97. resolve(kShaderBase + QStringLiteral("pine_instanced.frag"));
  98. load(QStringLiteral("pine_instanced"), pineVert, pineFrag);
  99. const QString firecampVert =
  100. resolve(kShaderBase + QStringLiteral("firecamp.vert"));
  101. const QString firecampFrag =
  102. resolve(kShaderBase + QStringLiteral("firecamp.frag"));
  103. load(QStringLiteral("firecamp"), firecampVert, firecampFrag);
  104. const QString groundVert =
  105. resolve(kShaderBase + QStringLiteral("ground_plane.vert"));
  106. const QString groundFrag =
  107. resolve(kShaderBase + QStringLiteral("ground_plane.frag"));
  108. load(QStringLiteral("ground_plane"), groundVert, groundFrag);
  109. const QString terrainVert =
  110. resolve(kShaderBase + QStringLiteral("terrain_chunk.vert"));
  111. const QString terrainFrag =
  112. resolve(kShaderBase + QStringLiteral("terrain_chunk.frag"));
  113. load(QStringLiteral("terrain_chunk"), terrainVert, terrainFrag);
  114. const QString riverVert =
  115. resolve(kShaderBase + QStringLiteral("river.vert"));
  116. const QString riverFrag =
  117. resolve(kShaderBase + QStringLiteral("river.frag"));
  118. load(QStringLiteral("river"), riverVert, riverFrag);
  119. const QString riverbankVert =
  120. resolve(kShaderBase + QStringLiteral("riverbank.vert"));
  121. const QString riverbankFrag =
  122. resolve(kShaderBase + QStringLiteral("riverbank.frag"));
  123. load(QStringLiteral("riverbank"), riverbankVert, riverbankFrag);
  124. const QString roadVert = resolve(kShaderBase + QStringLiteral("road.vert"));
  125. const QString roadFrag = resolve(kShaderBase + QStringLiteral("road.frag"));
  126. load(QStringLiteral("road"), roadVert, roadFrag);
  127. const QString bridgeVert =
  128. resolve(kShaderBase + QStringLiteral("bridge.vert"));
  129. const QString bridgeFrag =
  130. resolve(kShaderBase + QStringLiteral("bridge.frag"));
  131. load(QStringLiteral("bridge"), bridgeVert, bridgeFrag);
  132. const QString troopShadowVert =
  133. resolve(kShaderBase + QStringLiteral("troop_shadow.vert"));
  134. const QString troopShadowFrag =
  135. resolve(kShaderBase + QStringLiteral("troop_shadow.frag"));
  136. load(QStringLiteral("troop_shadow"), troopShadowVert, troopShadowFrag);
  137. const auto loadBaseShader = [&](const QString &name) {
  138. const QString vert =
  139. resolve(kShaderBase + name + QStringLiteral(".vert"));
  140. const QString frag =
  141. resolve(kShaderBase + name + QStringLiteral(".frag"));
  142. load(name, vert, frag);
  143. return std::pair<QString, QString>{vert, frag};
  144. };
  145. const auto [archerVert, archerFrag] =
  146. loadBaseShader(QStringLiteral("archer"));
  147. const auto [swordsmanVert, swordsmanFrag] =
  148. loadBaseShader(QStringLiteral("swordsman"));
  149. const auto [horseKnightVert, horseKnightFrag] =
  150. loadBaseShader(QStringLiteral("horse_swordsman"));
  151. const auto [spearmanVert, spearmanFrag] =
  152. loadBaseShader(QStringLiteral("spearman"));
  153. const QStringList nationVariants = {QStringLiteral("kingdom_of_iron"),
  154. QStringLiteral("roman_republic"),
  155. QStringLiteral("carthage")};
  156. auto loadVariant = [&](const QString &baseKey, const QString &baseVertPath,
  157. const QString &baseFragPath) {
  158. for (const QString &nation : nationVariants) {
  159. const QString shaderName = baseKey + QStringLiteral("_") + nation;
  160. const QString variantVertRes = kShaderBase + baseKey +
  161. QStringLiteral("_") + nation +
  162. QStringLiteral(".vert");
  163. const QString variantFragRes = kShaderBase + baseKey +
  164. QStringLiteral("_") + nation +
  165. QStringLiteral(".frag");
  166. QString resolvedVert = resolve(variantVertRes);
  167. if (!QFile::exists(resolvedVert)) {
  168. resolvedVert = baseVertPath;
  169. }
  170. QString resolvedFrag = resolve(variantFragRes);
  171. if (!QFile::exists(resolvedFrag)) {
  172. resolvedFrag = baseFragPath;
  173. }
  174. load(shaderName, resolvedVert, resolvedFrag);
  175. }
  176. };
  177. loadVariant(QStringLiteral("archer"), archerVert, archerFrag);
  178. loadVariant(QStringLiteral("spearman"), spearmanVert, spearmanFrag);
  179. loadVariant(QStringLiteral("swordsman"), swordsmanVert, swordsmanFrag);
  180. loadVariant(QStringLiteral("horse_swordsman"), horseKnightVert,
  181. horseKnightFrag);
  182. }
  183. void clear() {
  184. m_named.clear();
  185. m_byPath.clear();
  186. m_cache.clear();
  187. }
  188. private:
  189. std::unordered_map<QString, std::unique_ptr<Shader>> m_byPath;
  190. std::unordered_map<QString, std::unique_ptr<Shader>> m_named;
  191. std::unordered_map<QString, std::unique_ptr<Shader>> m_cache;
  192. };
  193. } // namespace Render::GL