shader_cache.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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_by_path.find(key);
  46. if (it != m_by_path.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_by_path.emplace(std::move(key), std::move(sh));
  57. return raw;
  58. }
  59. void initialize_defaults() {
  60. static const QString shader_base = QStringLiteral(":/assets/shaders/");
  61. auto resolve = [](const QString &path) {
  62. return Utils::Resources::resolveResourcePath(path);
  63. };
  64. const QString basic_vert =
  65. resolve(shader_base + QStringLiteral("basic.vert"));
  66. const QString basic_frag =
  67. resolve(shader_base + QStringLiteral("basic.frag"));
  68. const QString grid_frag =
  69. resolve(shader_base + QStringLiteral("grid.frag"));
  70. load(QStringLiteral("basic"), basic_vert, basic_frag);
  71. load(QStringLiteral("grid"), basic_vert, grid_frag);
  72. const QString cyl_vert =
  73. resolve(shader_base + QStringLiteral("cylinder_instanced.vert"));
  74. const QString cyl_frag =
  75. resolve(shader_base + QStringLiteral("cylinder_instanced.frag"));
  76. load(QStringLiteral("cylinder_instanced"), cyl_vert, cyl_frag);
  77. const QString prim_vert =
  78. resolve(shader_base + QStringLiteral("primitive_instanced.vert"));
  79. const QString prim_frag =
  80. resolve(shader_base + QStringLiteral("primitive_instanced.frag"));
  81. load(QStringLiteral("primitive_instanced"), prim_vert, prim_frag);
  82. const QString fog_vert =
  83. resolve(shader_base + QStringLiteral("fog_instanced.vert"));
  84. const QString fog_frag =
  85. resolve(shader_base + QStringLiteral("fog_instanced.frag"));
  86. load(QStringLiteral("fog_instanced"), fog_vert, fog_frag);
  87. const QString grass_vert =
  88. resolve(shader_base + QStringLiteral("grass_instanced.vert"));
  89. const QString grass_frag =
  90. resolve(shader_base + QStringLiteral("grass_instanced.frag"));
  91. load(QStringLiteral("grass_instanced"), grass_vert, grass_frag);
  92. const QString stone_vert =
  93. resolve(shader_base + QStringLiteral("stone_instanced.vert"));
  94. const QString stone_frag =
  95. resolve(shader_base + QStringLiteral("stone_instanced.frag"));
  96. load(QStringLiteral("stone_instanced"), stone_vert, stone_frag);
  97. const QString plant_vert =
  98. resolve(shader_base + QStringLiteral("plant_instanced.vert"));
  99. const QString plant_frag =
  100. resolve(shader_base + QStringLiteral("plant_instanced.frag"));
  101. load(QStringLiteral("plant_instanced"), plant_vert, plant_frag);
  102. const QString pine_vert =
  103. resolve(shader_base + QStringLiteral("pine_instanced.vert"));
  104. const QString pine_frag =
  105. resolve(shader_base + QStringLiteral("pine_instanced.frag"));
  106. load(QStringLiteral("pine_instanced"), pine_vert, pine_frag);
  107. const QString olive_vert =
  108. resolve(shader_base + QStringLiteral("olive_instanced.vert"));
  109. const QString olive_frag =
  110. resolve(shader_base + QStringLiteral("olive_instanced.frag"));
  111. load(QStringLiteral("olive_instanced"), olive_vert, olive_frag);
  112. const QString firecamp_vert =
  113. resolve(shader_base + QStringLiteral("firecamp.vert"));
  114. const QString firecamp_frag =
  115. resolve(shader_base + QStringLiteral("firecamp.frag"));
  116. load(QStringLiteral("firecamp"), firecamp_vert, firecamp_frag);
  117. const QString ground_vert =
  118. resolve(shader_base + QStringLiteral("ground_plane.vert"));
  119. const QString ground_frag =
  120. resolve(shader_base + QStringLiteral("ground_plane.frag"));
  121. load(QStringLiteral("ground_plane"), ground_vert, ground_frag);
  122. const QString terrain_vert =
  123. resolve(shader_base + QStringLiteral("terrain_chunk.vert"));
  124. const QString terrain_frag =
  125. resolve(shader_base + QStringLiteral("terrain_chunk.frag"));
  126. load(QStringLiteral("terrain_chunk"), terrain_vert, terrain_frag);
  127. const QString river_vert =
  128. resolve(shader_base + QStringLiteral("river.vert"));
  129. const QString river_frag =
  130. resolve(shader_base + QStringLiteral("river.frag"));
  131. load(QStringLiteral("river"), river_vert, river_frag);
  132. const QString riverbank_vert =
  133. resolve(shader_base + QStringLiteral("riverbank.vert"));
  134. const QString riverbank_frag =
  135. resolve(shader_base + QStringLiteral("riverbank.frag"));
  136. load(QStringLiteral("riverbank"), riverbank_vert, riverbank_frag);
  137. const QString road_vert =
  138. resolve(shader_base + QStringLiteral("road.vert"));
  139. const QString road_frag =
  140. resolve(shader_base + QStringLiteral("road.frag"));
  141. load(QStringLiteral("road"), road_vert, road_frag);
  142. const QString bridge_vert =
  143. resolve(shader_base + QStringLiteral("bridge.vert"));
  144. const QString bridge_frag =
  145. resolve(shader_base + QStringLiteral("bridge.frag"));
  146. load(QStringLiteral("bridge"), bridge_vert, bridge_frag);
  147. const QString troop_shadow_vert =
  148. resolve(shader_base + QStringLiteral("troop_shadow.vert"));
  149. const QString troop_shadow_frag =
  150. resolve(shader_base + QStringLiteral("troop_shadow.frag"));
  151. load(QStringLiteral("troop_shadow"), troop_shadow_vert, troop_shadow_frag);
  152. const QString banner_vert =
  153. resolve(shader_base + QStringLiteral("banner.vert"));
  154. const QString banner_frag =
  155. resolve(shader_base + QStringLiteral("banner.frag"));
  156. load(QStringLiteral("banner"), banner_vert, banner_frag);
  157. const QString healing_beam_vert =
  158. resolve(shader_base + QStringLiteral("healing_beam.vert"));
  159. const QString healing_beam_frag =
  160. resolve(shader_base + QStringLiteral("healing_beam.frag"));
  161. load(QStringLiteral("healing_beam"), healing_beam_vert, healing_beam_frag);
  162. const QString healing_aura_vert =
  163. resolve(shader_base + QStringLiteral("healing_aura.vert"));
  164. const QString healing_aura_frag =
  165. resolve(shader_base + QStringLiteral("healing_aura.frag"));
  166. load(QStringLiteral("healing_aura"), healing_aura_vert, healing_aura_frag);
  167. load(QStringLiteral("combat_dust"),
  168. resolve(shader_base + QStringLiteral("combat_dust.vert")),
  169. resolve(shader_base + QStringLiteral("combat_dust.frag")));
  170. load(QStringLiteral("mode_indicator"),
  171. resolve(shader_base + QStringLiteral("mode_indicator.vert")),
  172. resolve(shader_base + QStringLiteral("mode_indicator.frag")));
  173. const auto load_base_shader = [&](const QString &name) {
  174. const QString vert =
  175. resolve(shader_base + name + QStringLiteral(".vert"));
  176. const QString frag =
  177. resolve(shader_base + name + QStringLiteral(".frag"));
  178. load(name, vert, frag);
  179. return std::pair<QString, QString>{vert, frag};
  180. };
  181. const auto [archer_vert, archer_frag] =
  182. load_base_shader(QStringLiteral("archer"));
  183. const auto [swordsman_vert, swordsman_frag] =
  184. load_base_shader(QStringLiteral("swordsman"));
  185. const auto [horse_knight_vert, horse_knight_frag] =
  186. load_base_shader(QStringLiteral("horse_swordsman"));
  187. const auto [spearman_vert, spearman_frag] =
  188. load_base_shader(QStringLiteral("spearman"));
  189. const auto [healer_vert, healer_frag] =
  190. load_base_shader(QStringLiteral("healer"));
  191. const QStringList nation_variants = {QStringLiteral("roman_republic"),
  192. QStringLiteral("carthage")};
  193. auto resource_exists = [](const QString &path) -> bool {
  194. QFileInfo const info(path);
  195. return info.exists();
  196. };
  197. auto load_variant = [&](const QString &base_key,
  198. const QString &base_vert_path,
  199. const QString &base_frag_path) {
  200. for (const QString &nation : nation_variants) {
  201. const QString shader_name = base_key + QStringLiteral("_") + nation;
  202. const QString variant_vert_res = shader_base + base_key +
  203. QStringLiteral("_") + nation +
  204. QStringLiteral(".vert");
  205. const QString variant_frag_res = shader_base + base_key +
  206. QStringLiteral("_") + nation +
  207. QStringLiteral(".frag");
  208. QString resolved_vert = resolve(variant_vert_res);
  209. if (!resource_exists(resolved_vert)) {
  210. resolved_vert = base_vert_path;
  211. }
  212. QString resolved_frag = resolve(variant_frag_res);
  213. if (!resource_exists(resolved_frag)) {
  214. resolved_frag = base_frag_path;
  215. }
  216. load(shader_name, resolved_vert, resolved_frag);
  217. }
  218. };
  219. load_variant(QStringLiteral("archer"), archer_vert, archer_frag);
  220. load_variant(QStringLiteral("spearman"), spearman_vert, spearman_frag);
  221. load_variant(QStringLiteral("swordsman"), swordsman_vert, swordsman_frag);
  222. load_variant(QStringLiteral("horse_swordsman"), horse_knight_vert,
  223. horse_knight_frag);
  224. load_variant(QStringLiteral("healer"), healer_vert, healer_frag);
  225. load_variant(QStringLiteral("horse_archer"), horse_knight_vert,
  226. horse_knight_frag);
  227. load_variant(QStringLiteral("horse_spearman"), horse_knight_vert,
  228. horse_knight_frag);
  229. }
  230. void clear() {
  231. m_named.clear();
  232. m_by_path.clear();
  233. m_cache.clear();
  234. }
  235. private:
  236. std::unordered_map<QString, std::unique_ptr<Shader>> m_by_path;
  237. std::unordered_map<QString, std::unique_ptr<Shader>> m_named;
  238. std::unordered_map<QString, std::unique_ptr<Shader>> m_cache;
  239. };
  240. } // namespace Render::GL