shader_cache.h 11 KB

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