backend.cpp 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746
  1. #include "backend.h"
  2. #include "../draw_queue.h"
  3. #include "../geom/mode_indicator.h"
  4. #include "../geom/selection_disc.h"
  5. #include "../geom/selection_ring.h"
  6. #include "../primitive_batch.h"
  7. #include "backend/banner_pipeline.h"
  8. #include "backend/character_pipeline.h"
  9. #include "backend/combat_dust_pipeline.h"
  10. #include "backend/cylinder_pipeline.h"
  11. #include "backend/effects_pipeline.h"
  12. #include "backend/healer_aura_pipeline.h"
  13. #include "backend/healing_beam_pipeline.h"
  14. #include "backend/mesh_instancing_pipeline.h"
  15. #include "backend/mode_indicator_pipeline.h"
  16. #include "backend/primitive_batch_pipeline.h"
  17. #include "backend/rain_pipeline.h"
  18. #include "backend/terrain_pipeline.h"
  19. #include "backend/vegetation_pipeline.h"
  20. #include "backend/water_pipeline.h"
  21. #include "buffer.h"
  22. #include "gl/camera.h"
  23. #include "gl/resources.h"
  24. #include "ground/firecamp_gpu.h"
  25. #include "ground/grass_gpu.h"
  26. #include "ground/olive_gpu.h"
  27. #include "ground/pine_gpu.h"
  28. #include "ground/plant_gpu.h"
  29. #include "ground/rain_gpu.h"
  30. #include "ground/stone_gpu.h"
  31. #include "mesh.h"
  32. #include "render_constants.h"
  33. #include "shader.h"
  34. #include "state_scopes.h"
  35. #include "texture.h"
  36. #include <GL/gl.h>
  37. #include <QDebug>
  38. #include <QOpenGLContext>
  39. #include <cmath>
  40. #include <cstddef>
  41. #include <memory>
  42. #include <qglobal.h>
  43. #include <qmatrix4x4.h>
  44. #include <qopenglcontext.h>
  45. #include <qstringliteral.h>
  46. #include <qvectornd.h>
  47. #include <vector>
  48. namespace Render::GL {
  49. using namespace Render::GL::ColorIndex;
  50. using namespace Render::GL::VertexAttrib;
  51. using namespace Render::GL::ComponentCount;
  52. namespace {
  53. const QVector3D k_grid_line_color(0.22F, 0.25F, 0.22F);
  54. [[nodiscard]] inline auto can_batch_mesh_cmds(const MeshCmd &a,
  55. const MeshCmd &b) -> bool {
  56. if (a.alpha < k_opaque_threshold || b.alpha < k_opaque_threshold) {
  57. return false;
  58. }
  59. return a.mesh == b.mesh && a.shader == b.shader && a.texture == b.texture;
  60. }
  61. } // namespace
  62. Backend::Backend() = default;
  63. Backend::~Backend() {
  64. if (QOpenGLContext::currentContext() == nullptr) {
  65. (void)m_cylinderPipeline.release();
  66. (void)m_vegetationPipeline.release();
  67. (void)m_terrainPipeline.release();
  68. (void)m_characterPipeline.release();
  69. (void)m_waterPipeline.release();
  70. (void)m_effectsPipeline.release();
  71. (void)m_meshInstancingPipeline.release();
  72. } else {
  73. m_cylinderPipeline.reset();
  74. m_vegetationPipeline.reset();
  75. m_terrainPipeline.reset();
  76. m_characterPipeline.reset();
  77. m_waterPipeline.reset();
  78. m_effectsPipeline.reset();
  79. m_meshInstancingPipeline.reset();
  80. }
  81. }
  82. void Backend::initialize() {
  83. qInfo() << "Backend::initialize() - Starting...";
  84. qInfo() << "Backend: Initializing OpenGL functions...";
  85. initializeOpenGLFunctions();
  86. qInfo() << "Backend: OpenGL functions initialized";
  87. qInfo() << "Backend: Setting up depth test...";
  88. glEnable(GL_DEPTH_TEST);
  89. glDepthFunc(GL_LESS);
  90. glDepthRange(0.0, 1.0);
  91. glDepthMask(GL_TRUE);
  92. qInfo() << "Backend: Setting up blending...";
  93. glEnable(GL_BLEND);
  94. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  95. qInfo() << "Backend: Creating ResourceManager...";
  96. m_resources = std::make_unique<ResourceManager>();
  97. if (!m_resources->initialize()) {
  98. qWarning() << "Backend: failed to initialize ResourceManager";
  99. }
  100. qInfo() << "Backend: ResourceManager created";
  101. qInfo() << "Backend: Creating ShaderCache...";
  102. m_shaderCache = std::make_unique<ShaderCache>();
  103. m_shaderCache->initialize_defaults();
  104. qInfo() << "Backend: ShaderCache created";
  105. qInfo() << "Backend: Creating CylinderPipeline...";
  106. m_cylinderPipeline =
  107. std::make_unique<BackendPipelines::CylinderPipeline>(m_shaderCache.get());
  108. m_cylinderPipeline->initialize();
  109. qInfo() << "Backend: CylinderPipeline initialized";
  110. qInfo() << "Backend: Creating VegetationPipeline...";
  111. m_vegetationPipeline = std::make_unique<BackendPipelines::VegetationPipeline>(
  112. m_shaderCache.get());
  113. m_vegetationPipeline->initialize();
  114. qInfo() << "Backend: VegetationPipeline initialized";
  115. qInfo() << "Backend: Creating TerrainPipeline...";
  116. m_terrainPipeline = std::make_unique<BackendPipelines::TerrainPipeline>(
  117. this, m_shaderCache.get());
  118. m_terrainPipeline->initialize();
  119. qInfo() << "Backend: TerrainPipeline initialized";
  120. qInfo() << "Backend: Creating CharacterPipeline...";
  121. m_characterPipeline = std::make_unique<BackendPipelines::CharacterPipeline>(
  122. this, m_shaderCache.get());
  123. m_characterPipeline->initialize();
  124. qInfo() << "Backend: CharacterPipeline initialized";
  125. qInfo() << "Backend: Creating WaterPipeline...";
  126. m_waterPipeline = std::make_unique<BackendPipelines::WaterPipeline>(
  127. this, m_shaderCache.get());
  128. m_waterPipeline->initialize();
  129. qInfo() << "Backend: WaterPipeline initialized";
  130. qInfo() << "Backend: Creating EffectsPipeline...";
  131. m_effectsPipeline = std::make_unique<BackendPipelines::EffectsPipeline>(
  132. this, m_shaderCache.get());
  133. m_effectsPipeline->initialize();
  134. qInfo() << "Backend: EffectsPipeline initialized";
  135. qInfo() << "Backend: Creating PrimitiveBatchPipeline...";
  136. m_primitiveBatchPipeline =
  137. std::make_unique<BackendPipelines::PrimitiveBatchPipeline>(
  138. m_shaderCache.get());
  139. m_primitiveBatchPipeline->initialize();
  140. qInfo() << "Backend: PrimitiveBatchPipeline initialized";
  141. qInfo() << "Backend: Creating BannerPipeline...";
  142. m_bannerPipeline = std::make_unique<BackendPipelines::BannerPipeline>(
  143. this, m_shaderCache.get());
  144. m_bannerPipeline->initialize();
  145. qInfo() << "Backend: BannerPipeline initialized";
  146. qInfo() << "Backend: Creating HealingBeamPipeline...";
  147. m_healingBeamPipeline =
  148. std::make_unique<BackendPipelines::HealingBeamPipeline>(
  149. this, m_shaderCache.get());
  150. m_healingBeamPipeline->initialize();
  151. qInfo() << "Backend: HealingBeamPipeline initialized";
  152. qInfo() << "Backend: Creating HealerAuraPipeline...";
  153. m_healerAuraPipeline = std::make_unique<BackendPipelines::HealerAuraPipeline>(
  154. this, m_shaderCache.get());
  155. m_healerAuraPipeline->initialize();
  156. qInfo() << "Backend: HealerAuraPipeline initialized";
  157. qInfo() << "Backend: Creating CombatDustPipeline...";
  158. m_combatDustPipeline = std::make_unique<BackendPipelines::CombatDustPipeline>(
  159. this, m_shaderCache.get());
  160. m_combatDustPipeline->initialize();
  161. qInfo() << "Backend: CombatDustPipeline initialized";
  162. qInfo() << "Backend: Creating RainPipeline...";
  163. m_rainPipeline = std::make_unique<BackendPipelines::RainPipeline>(
  164. this, m_shaderCache.get());
  165. m_rainPipeline->initialize();
  166. qInfo() << "Backend: RainPipeline initialized";
  167. qInfo() << "Backend: Creating ModeIndicatorPipeline...";
  168. m_modeIndicatorPipeline =
  169. std::make_unique<BackendPipelines::ModeIndicatorPipeline>(
  170. this, m_shaderCache.get());
  171. m_modeIndicatorPipeline->initialize();
  172. qInfo() << "Backend: ModeIndicatorPipeline initialized";
  173. qInfo() << "Backend: Creating MeshInstancingPipeline...";
  174. m_meshInstancingPipeline =
  175. std::make_unique<BackendPipelines::MeshInstancingPipeline>(
  176. this, m_shaderCache.get());
  177. m_meshInstancingPipeline->initialize();
  178. qInfo() << "Backend: MeshInstancingPipeline initialized";
  179. qInfo() << "Backend: Loading basic shaders...";
  180. m_basicShader = m_shaderCache->get(QStringLiteral("basic"));
  181. m_gridShader = m_shaderCache->get(QStringLiteral("grid"));
  182. if (m_basicShader == nullptr) {
  183. qWarning() << "Backend: basic shader missing";
  184. }
  185. if (m_gridShader == nullptr) {
  186. qWarning() << "Backend: grid shader missing";
  187. }
  188. qInfo() << "Backend::initialize() - Complete!";
  189. }
  190. auto Backend::banner_mesh() const -> Mesh * {
  191. if (m_bannerPipeline != nullptr) {
  192. return m_bannerPipeline->get_banner_mesh();
  193. }
  194. return nullptr;
  195. }
  196. auto Backend::banner_shader() const -> Shader * {
  197. if (m_bannerPipeline != nullptr) {
  198. return m_bannerPipeline->m_bannerShader;
  199. }
  200. return nullptr;
  201. }
  202. void Backend::begin_frame() {
  203. if (m_viewportWidth > 0 && m_viewportHeight > 0) {
  204. glViewport(0, 0, m_viewportWidth, m_viewportHeight);
  205. }
  206. glClearColor(m_clearColor[Red], m_clearColor[Green], m_clearColor[Blue],
  207. m_clearColor[Alpha]);
  208. glClearDepth(1.0);
  209. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  210. glEnable(GL_DEPTH_TEST);
  211. glDepthFunc(GL_LESS);
  212. glDepthMask(GL_TRUE);
  213. if (m_cylinderPipeline) {
  214. m_cylinderPipeline->begin_frame();
  215. }
  216. if (m_meshInstancingPipeline) {
  217. m_meshInstancingPipeline->begin_frame();
  218. }
  219. }
  220. void Backend::set_viewport(int w, int h) {
  221. m_viewportWidth = w;
  222. m_viewportHeight = h;
  223. }
  224. void Backend::set_clear_color(float r, float g, float b, float a) {
  225. m_clearColor[Red] = r;
  226. m_clearColor[Green] = g;
  227. m_clearColor[Blue] = b;
  228. m_clearColor[Alpha] = a;
  229. }
  230. void Backend::execute(const DrawQueue &queue, const Camera &cam) {
  231. if (m_basicShader == nullptr) {
  232. return;
  233. }
  234. const QMatrix4x4 view_proj =
  235. cam.get_projection_matrix() * cam.get_view_matrix();
  236. m_lastBoundShader = nullptr;
  237. m_lastBoundTexture = nullptr;
  238. const std::size_t count = queue.size();
  239. std::size_t i = 0;
  240. while (i < count) {
  241. const auto &cmd = queue.get_sorted(i);
  242. switch (cmd.index()) {
  243. case CylinderCmdIndex: {
  244. if (!m_cylinderPipeline) {
  245. ++i;
  246. continue;
  247. }
  248. m_cylinderPipeline->m_cylinderScratch.clear();
  249. do {
  250. const auto &cy = std::get<CylinderCmdIndex>(queue.get_sorted(i));
  251. BackendPipelines::CylinderPipeline::CylinderInstanceGpu gpu{};
  252. gpu.start = cy.start;
  253. gpu.end = cy.end;
  254. gpu.radius = cy.radius;
  255. gpu.alpha = cy.alpha;
  256. gpu.color = cy.color;
  257. m_cylinderPipeline->m_cylinderScratch.emplace_back(gpu);
  258. ++i;
  259. } while (i < count && queue.get_sorted(i).index() == CylinderCmdIndex);
  260. const std::size_t instance_count =
  261. m_cylinderPipeline->m_cylinderScratch.size();
  262. if (instance_count > 0 &&
  263. (m_cylinderPipeline->cylinderShader() != nullptr)) {
  264. glDepthMask(GL_TRUE);
  265. if (glIsEnabled(GL_POLYGON_OFFSET_FILL) != 0U) {
  266. glDisable(GL_POLYGON_OFFSET_FILL);
  267. }
  268. Shader *cylinder_shader = m_cylinderPipeline->cylinderShader();
  269. if (m_lastBoundShader != cylinder_shader) {
  270. cylinder_shader->use();
  271. m_lastBoundShader = cylinder_shader;
  272. m_lastBoundTexture = nullptr;
  273. }
  274. if (m_cylinderPipeline->m_cylinderUniforms.view_proj !=
  275. Shader::InvalidUniform) {
  276. cylinder_shader->set_uniform(
  277. m_cylinderPipeline->m_cylinderUniforms.view_proj, view_proj);
  278. }
  279. m_cylinderPipeline->upload_cylinder_instances(instance_count);
  280. m_cylinderPipeline->draw_cylinders(instance_count);
  281. }
  282. continue;
  283. }
  284. case FogBatchCmdIndex: {
  285. if (!m_cylinderPipeline) {
  286. ++i;
  287. continue;
  288. }
  289. const auto &batch = std::get<FogBatchCmdIndex>(cmd);
  290. const FogInstanceData *instances = batch.instances;
  291. const std::size_t instance_count = batch.count;
  292. if ((instances != nullptr) && instance_count > 0 &&
  293. (m_cylinderPipeline->fogShader() != nullptr)) {
  294. m_cylinderPipeline->m_fogScratch.resize(instance_count);
  295. for (std::size_t idx = 0; idx < instance_count; ++idx) {
  296. BackendPipelines::CylinderPipeline::FogInstanceGpu gpu{};
  297. gpu.center = instances[idx].center;
  298. gpu.size = instances[idx].size;
  299. gpu.color = instances[idx].color;
  300. gpu.alpha = instances[idx].alpha;
  301. m_cylinderPipeline->m_fogScratch[idx] = gpu;
  302. }
  303. glDepthMask(GL_TRUE);
  304. if (glIsEnabled(GL_POLYGON_OFFSET_FILL) != 0U) {
  305. glDisable(GL_POLYGON_OFFSET_FILL);
  306. }
  307. Shader *fog_shader = m_cylinderPipeline->fogShader();
  308. if (m_lastBoundShader != fog_shader) {
  309. fog_shader->use();
  310. m_lastBoundShader = fog_shader;
  311. m_lastBoundTexture = nullptr;
  312. }
  313. if (m_cylinderPipeline->m_fogUniforms.view_proj !=
  314. Shader::InvalidUniform) {
  315. fog_shader->set_uniform(m_cylinderPipeline->m_fogUniforms.view_proj,
  316. view_proj);
  317. }
  318. m_cylinderPipeline->upload_fog_instances(instance_count);
  319. m_cylinderPipeline->draw_fog(instance_count);
  320. }
  321. ++i;
  322. continue;
  323. }
  324. case GrassBatchCmdIndex: {
  325. const auto &grass = std::get<GrassBatchCmdIndex>(cmd);
  326. if ((grass.instance_buffer == nullptr) || grass.instance_count == 0 ||
  327. (m_terrainPipeline->m_grassShader == nullptr) ||
  328. (m_terrainPipeline->m_grassVao == 0U) ||
  329. m_terrainPipeline->m_grassVertexCount == 0) {
  330. break;
  331. }
  332. DepthMaskScope const depth_mask(false);
  333. BlendScope const blend(true);
  334. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  335. GLboolean const prev_cull = glIsEnabled(GL_CULL_FACE);
  336. if (prev_cull != 0U) {
  337. glDisable(GL_CULL_FACE);
  338. }
  339. if (m_lastBoundShader != m_terrainPipeline->m_grassShader) {
  340. m_terrainPipeline->m_grassShader->use();
  341. m_lastBoundShader = m_terrainPipeline->m_grassShader;
  342. m_lastBoundTexture = nullptr;
  343. }
  344. if (m_terrainPipeline->m_grassUniforms.view_proj !=
  345. Shader::InvalidUniform) {
  346. m_terrainPipeline->m_grassShader->set_uniform(
  347. m_terrainPipeline->m_grassUniforms.view_proj, view_proj);
  348. }
  349. if (m_terrainPipeline->m_grassUniforms.time != Shader::InvalidUniform) {
  350. m_terrainPipeline->m_grassShader->set_uniform(
  351. m_terrainPipeline->m_grassUniforms.time, grass.params.time);
  352. }
  353. if (m_terrainPipeline->m_grassUniforms.wind_strength !=
  354. Shader::InvalidUniform) {
  355. m_terrainPipeline->m_grassShader->set_uniform(
  356. m_terrainPipeline->m_grassUniforms.wind_strength,
  357. grass.params.wind_strength);
  358. }
  359. if (m_terrainPipeline->m_grassUniforms.wind_speed !=
  360. Shader::InvalidUniform) {
  361. m_terrainPipeline->m_grassShader->set_uniform(
  362. m_terrainPipeline->m_grassUniforms.wind_speed,
  363. grass.params.wind_speed);
  364. }
  365. if (m_terrainPipeline->m_grassUniforms.soil_color !=
  366. Shader::InvalidUniform) {
  367. m_terrainPipeline->m_grassShader->set_uniform(
  368. m_terrainPipeline->m_grassUniforms.soil_color,
  369. grass.params.soil_color);
  370. }
  371. if (m_terrainPipeline->m_grassUniforms.light_dir !=
  372. Shader::InvalidUniform) {
  373. QVector3D light_dir = grass.params.light_direction;
  374. if (!light_dir.isNull()) {
  375. light_dir.normalize();
  376. }
  377. m_terrainPipeline->m_grassShader->set_uniform(
  378. m_terrainPipeline->m_grassUniforms.light_dir, light_dir);
  379. }
  380. glBindVertexArray(m_terrainPipeline->m_grassVao);
  381. grass.instance_buffer->bind();
  382. const auto stride = static_cast<GLsizei>(sizeof(GrassInstanceGpu));
  383. glVertexAttribPointer(
  384. TexCoord, Vec4, GL_FLOAT, GL_FALSE, stride,
  385. reinterpret_cast<void *>(offsetof(GrassInstanceGpu, pos_height)));
  386. glVertexAttribPointer(
  387. InstancePosition, Vec4, GL_FLOAT, GL_FALSE, stride,
  388. reinterpret_cast<void *>(offsetof(GrassInstanceGpu, color_width)));
  389. glVertexAttribPointer(
  390. InstanceScale, Vec4, GL_FLOAT, GL_FALSE, stride,
  391. reinterpret_cast<void *>(offsetof(GrassInstanceGpu, sway_params)));
  392. grass.instance_buffer->unbind();
  393. glDrawArraysInstanced(GL_TRIANGLES, 0,
  394. m_terrainPipeline->m_grassVertexCount,
  395. static_cast<GLsizei>(grass.instance_count));
  396. glBindVertexArray(0);
  397. if (prev_cull != 0U) {
  398. glEnable(GL_CULL_FACE);
  399. }
  400. break;
  401. }
  402. case StoneBatchCmdIndex: {
  403. if (!m_vegetationPipeline) {
  404. ++i;
  405. continue;
  406. }
  407. const auto &stone = std::get<StoneBatchCmdIndex>(cmd);
  408. if ((stone.instance_buffer == nullptr) || stone.instance_count == 0 ||
  409. (m_vegetationPipeline->stone_shader() == nullptr) ||
  410. (m_vegetationPipeline->m_stoneVao == 0U) ||
  411. m_vegetationPipeline->m_stoneIndexCount == 0) {
  412. break;
  413. }
  414. DepthMaskScope const depth_mask(true);
  415. BlendScope const blend(false);
  416. Shader *stone_shader = m_vegetationPipeline->stone_shader();
  417. if (m_lastBoundShader != stone_shader) {
  418. stone_shader->use();
  419. m_lastBoundShader = stone_shader;
  420. m_lastBoundTexture = nullptr;
  421. }
  422. if (m_vegetationPipeline->m_stoneUniforms.view_proj !=
  423. Shader::InvalidUniform) {
  424. stone_shader->set_uniform(
  425. m_vegetationPipeline->m_stoneUniforms.view_proj, view_proj);
  426. }
  427. if (m_vegetationPipeline->m_stoneUniforms.light_direction !=
  428. Shader::InvalidUniform) {
  429. QVector3D light_dir = stone.params.light_direction;
  430. if (!light_dir.isNull()) {
  431. light_dir.normalize();
  432. }
  433. stone_shader->set_uniform(
  434. m_vegetationPipeline->m_stoneUniforms.light_direction, light_dir);
  435. }
  436. glBindVertexArray(m_vegetationPipeline->m_stoneVao);
  437. stone.instance_buffer->bind();
  438. const auto stride = static_cast<GLsizei>(sizeof(StoneInstanceGpu));
  439. glVertexAttribPointer(
  440. TexCoord, Vec4, GL_FLOAT, GL_FALSE, stride,
  441. reinterpret_cast<void *>(offsetof(StoneInstanceGpu, pos_scale)));
  442. glVertexAttribPointer(
  443. InstancePosition, Vec4, GL_FLOAT, GL_FALSE, stride,
  444. reinterpret_cast<void *>(offsetof(StoneInstanceGpu, color_rot)));
  445. stone.instance_buffer->unbind();
  446. glDrawElementsInstanced(GL_TRIANGLES,
  447. m_vegetationPipeline->m_stoneIndexCount,
  448. GL_UNSIGNED_SHORT, nullptr,
  449. static_cast<GLsizei>(stone.instance_count));
  450. glBindVertexArray(0);
  451. break;
  452. }
  453. case PlantBatchCmdIndex: {
  454. if (!m_vegetationPipeline) {
  455. ++i;
  456. continue;
  457. }
  458. const auto &plant = std::get<PlantBatchCmdIndex>(cmd);
  459. if ((plant.instance_buffer == nullptr) || plant.instance_count == 0 ||
  460. (m_vegetationPipeline->plant_shader() == nullptr) ||
  461. (m_vegetationPipeline->m_plantVao == 0U) ||
  462. m_vegetationPipeline->m_plantIndexCount == 0) {
  463. break;
  464. }
  465. DepthMaskScope const depth_mask(true);
  466. glEnable(GL_DEPTH_TEST);
  467. BlendScope const blend(true);
  468. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  469. GLboolean const prev_cull = glIsEnabled(GL_CULL_FACE);
  470. if (prev_cull != 0U) {
  471. glDisable(GL_CULL_FACE);
  472. }
  473. Shader *plant_shader = m_vegetationPipeline->plant_shader();
  474. if (m_lastBoundShader != plant_shader) {
  475. plant_shader->use();
  476. m_lastBoundShader = plant_shader;
  477. m_lastBoundTexture = nullptr;
  478. }
  479. if (m_vegetationPipeline->m_plantUniforms.view_proj !=
  480. Shader::InvalidUniform) {
  481. plant_shader->set_uniform(
  482. m_vegetationPipeline->m_plantUniforms.view_proj, view_proj);
  483. }
  484. if (m_vegetationPipeline->m_plantUniforms.time !=
  485. Shader::InvalidUniform) {
  486. plant_shader->set_uniform(m_vegetationPipeline->m_plantUniforms.time,
  487. plant.params.time);
  488. }
  489. if (m_vegetationPipeline->m_plantUniforms.wind_strength !=
  490. Shader::InvalidUniform) {
  491. plant_shader->set_uniform(
  492. m_vegetationPipeline->m_plantUniforms.wind_strength,
  493. plant.params.wind_strength);
  494. }
  495. if (m_vegetationPipeline->m_plantUniforms.wind_speed !=
  496. Shader::InvalidUniform) {
  497. plant_shader->set_uniform(
  498. m_vegetationPipeline->m_plantUniforms.wind_speed,
  499. plant.params.wind_speed);
  500. }
  501. if (m_vegetationPipeline->m_plantUniforms.light_direction !=
  502. Shader::InvalidUniform) {
  503. QVector3D light_dir = plant.params.light_direction;
  504. if (!light_dir.isNull()) {
  505. light_dir.normalize();
  506. }
  507. plant_shader->set_uniform(
  508. m_vegetationPipeline->m_plantUniforms.light_direction, light_dir);
  509. }
  510. glBindVertexArray(m_vegetationPipeline->m_plantVao);
  511. plant.instance_buffer->bind();
  512. const auto stride = static_cast<GLsizei>(sizeof(PlantInstanceGpu));
  513. glVertexAttribPointer(
  514. InstancePosition, Vec4, GL_FLOAT, GL_FALSE, stride,
  515. reinterpret_cast<void *>(offsetof(PlantInstanceGpu, pos_scale)));
  516. glVertexAttribPointer(
  517. InstanceScale, Vec4, GL_FLOAT, GL_FALSE, stride,
  518. reinterpret_cast<void *>(offsetof(PlantInstanceGpu, color_sway)));
  519. glVertexAttribPointer(
  520. InstanceColor, Vec4, GL_FLOAT, GL_FALSE, stride,
  521. reinterpret_cast<void *>(offsetof(PlantInstanceGpu, type_params)));
  522. plant.instance_buffer->unbind();
  523. glDrawElementsInstanced(GL_TRIANGLES,
  524. m_vegetationPipeline->m_plantIndexCount,
  525. GL_UNSIGNED_SHORT, nullptr,
  526. static_cast<GLsizei>(plant.instance_count));
  527. glBindVertexArray(0);
  528. if (prev_cull != 0U) {
  529. glEnable(GL_CULL_FACE);
  530. }
  531. break;
  532. }
  533. case PineBatchCmdIndex: {
  534. if (!m_vegetationPipeline) {
  535. ++i;
  536. continue;
  537. }
  538. const auto &pine = std::get<PineBatchCmdIndex>(cmd);
  539. if ((pine.instance_buffer == nullptr) || pine.instance_count == 0 ||
  540. (m_vegetationPipeline->pine_shader() == nullptr) ||
  541. (m_vegetationPipeline->m_pineVao == 0U) ||
  542. m_vegetationPipeline->m_pineIndexCount == 0) {
  543. break;
  544. }
  545. DepthMaskScope const depth_mask(true);
  546. glEnable(GL_DEPTH_TEST);
  547. BlendScope const blend(true);
  548. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  549. GLboolean const prev_cull = glIsEnabled(GL_CULL_FACE);
  550. if (prev_cull != 0U) {
  551. glDisable(GL_CULL_FACE);
  552. }
  553. Shader *pine_shader = m_vegetationPipeline->pine_shader();
  554. if (m_lastBoundShader != pine_shader) {
  555. pine_shader->use();
  556. m_lastBoundShader = pine_shader;
  557. m_lastBoundTexture = nullptr;
  558. }
  559. if (m_vegetationPipeline->m_pineUniforms.view_proj !=
  560. Shader::InvalidUniform) {
  561. pine_shader->set_uniform(m_vegetationPipeline->m_pineUniforms.view_proj,
  562. view_proj);
  563. }
  564. if (m_vegetationPipeline->m_pineUniforms.time != Shader::InvalidUniform) {
  565. pine_shader->set_uniform(m_vegetationPipeline->m_pineUniforms.time,
  566. pine.params.time);
  567. }
  568. if (m_vegetationPipeline->m_pineUniforms.wind_strength !=
  569. Shader::InvalidUniform) {
  570. pine_shader->set_uniform(
  571. m_vegetationPipeline->m_pineUniforms.wind_strength,
  572. pine.params.wind_strength);
  573. }
  574. if (m_vegetationPipeline->m_pineUniforms.wind_speed !=
  575. Shader::InvalidUniform) {
  576. pine_shader->set_uniform(
  577. m_vegetationPipeline->m_pineUniforms.wind_speed,
  578. pine.params.wind_speed);
  579. }
  580. if (m_vegetationPipeline->m_pineUniforms.light_direction !=
  581. Shader::InvalidUniform) {
  582. QVector3D light_dir = pine.params.light_direction;
  583. if (!light_dir.isNull()) {
  584. light_dir.normalize();
  585. }
  586. pine_shader->set_uniform(
  587. m_vegetationPipeline->m_pineUniforms.light_direction, light_dir);
  588. }
  589. glBindVertexArray(m_vegetationPipeline->m_pineVao);
  590. pine.instance_buffer->bind();
  591. const auto stride = static_cast<GLsizei>(sizeof(PineInstanceGpu));
  592. glVertexAttribPointer(
  593. InstancePosition, Vec4, GL_FLOAT, GL_FALSE, stride,
  594. reinterpret_cast<void *>(offsetof(PineInstanceGpu, pos_scale)));
  595. glVertexAttribPointer(
  596. InstanceScale, Vec4, GL_FLOAT, GL_FALSE, stride,
  597. reinterpret_cast<void *>(offsetof(PineInstanceGpu, color_sway)));
  598. glVertexAttribPointer(
  599. InstanceColor, Vec4, GL_FLOAT, GL_FALSE, stride,
  600. reinterpret_cast<void *>(offsetof(PineInstanceGpu, rotation)));
  601. pine.instance_buffer->unbind();
  602. glDrawElementsInstanced(GL_TRIANGLES,
  603. m_vegetationPipeline->m_pineIndexCount,
  604. GL_UNSIGNED_SHORT, nullptr,
  605. static_cast<GLsizei>(pine.instance_count));
  606. glBindVertexArray(0);
  607. if (prev_cull != 0U) {
  608. glEnable(GL_CULL_FACE);
  609. }
  610. break;
  611. }
  612. case OliveBatchCmdIndex: {
  613. if (!m_vegetationPipeline) {
  614. ++i;
  615. continue;
  616. }
  617. const auto &olive = std::get<OliveBatchCmdIndex>(cmd);
  618. if ((olive.instance_buffer == nullptr) || olive.instance_count == 0 ||
  619. (m_vegetationPipeline->olive_shader() == nullptr) ||
  620. (m_vegetationPipeline->m_oliveVao == 0U) ||
  621. m_vegetationPipeline->m_oliveIndexCount == 0) {
  622. break;
  623. }
  624. DepthMaskScope const depth_mask(true);
  625. glEnable(GL_DEPTH_TEST);
  626. BlendScope const blend(true);
  627. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  628. GLboolean const prev_cull = glIsEnabled(GL_CULL_FACE);
  629. if (prev_cull != 0U) {
  630. glDisable(GL_CULL_FACE);
  631. }
  632. Shader *olive_shader = m_vegetationPipeline->olive_shader();
  633. if (m_lastBoundShader != olive_shader) {
  634. olive_shader->use();
  635. m_lastBoundShader = olive_shader;
  636. m_lastBoundTexture = nullptr;
  637. }
  638. if (m_vegetationPipeline->m_oliveUniforms.view_proj !=
  639. Shader::InvalidUniform) {
  640. olive_shader->set_uniform(
  641. m_vegetationPipeline->m_oliveUniforms.view_proj, view_proj);
  642. }
  643. if (m_vegetationPipeline->m_oliveUniforms.time !=
  644. Shader::InvalidUniform) {
  645. olive_shader->set_uniform(m_vegetationPipeline->m_oliveUniforms.time,
  646. olive.params.time);
  647. }
  648. if (m_vegetationPipeline->m_oliveUniforms.wind_strength !=
  649. Shader::InvalidUniform) {
  650. olive_shader->set_uniform(
  651. m_vegetationPipeline->m_oliveUniforms.wind_strength,
  652. olive.params.wind_strength);
  653. }
  654. if (m_vegetationPipeline->m_oliveUniforms.wind_speed !=
  655. Shader::InvalidUniform) {
  656. olive_shader->set_uniform(
  657. m_vegetationPipeline->m_oliveUniforms.wind_speed,
  658. olive.params.wind_speed);
  659. }
  660. if (m_vegetationPipeline->m_oliveUniforms.light_direction !=
  661. Shader::InvalidUniform) {
  662. QVector3D light_dir = olive.params.light_direction;
  663. if (!light_dir.isNull()) {
  664. light_dir.normalize();
  665. }
  666. olive_shader->set_uniform(
  667. m_vegetationPipeline->m_oliveUniforms.light_direction, light_dir);
  668. }
  669. glBindVertexArray(m_vegetationPipeline->m_oliveVao);
  670. olive.instance_buffer->bind();
  671. const auto stride = static_cast<GLsizei>(sizeof(OliveInstanceGpu));
  672. glVertexAttribPointer(
  673. InstancePosition, Vec4, GL_FLOAT, GL_FALSE, stride,
  674. reinterpret_cast<void *>(offsetof(OliveInstanceGpu, pos_scale)));
  675. glVertexAttribPointer(
  676. InstanceScale, Vec4, GL_FLOAT, GL_FALSE, stride,
  677. reinterpret_cast<void *>(offsetof(OliveInstanceGpu, color_sway)));
  678. glVertexAttribPointer(
  679. InstanceColor, Vec4, GL_FLOAT, GL_FALSE, stride,
  680. reinterpret_cast<void *>(offsetof(OliveInstanceGpu, rotation)));
  681. olive.instance_buffer->unbind();
  682. glDrawElementsInstanced(GL_TRIANGLES,
  683. m_vegetationPipeline->m_oliveIndexCount,
  684. GL_UNSIGNED_SHORT, nullptr,
  685. static_cast<GLsizei>(olive.instance_count));
  686. glBindVertexArray(0);
  687. if (prev_cull != 0U) {
  688. glEnable(GL_CULL_FACE);
  689. }
  690. break;
  691. }
  692. case FireCampBatchCmdIndex: {
  693. if (!m_vegetationPipeline) {
  694. ++i;
  695. continue;
  696. }
  697. const auto &firecamp = std::get<FireCampBatchCmdIndex>(cmd);
  698. if ((firecamp.instance_buffer == nullptr) ||
  699. firecamp.instance_count == 0 ||
  700. (m_vegetationPipeline->firecamp_shader() == nullptr) ||
  701. (m_vegetationPipeline->m_firecampVao == 0U) ||
  702. m_vegetationPipeline->m_firecampIndexCount == 0) {
  703. break;
  704. }
  705. DepthMaskScope const depth_mask(true);
  706. glEnable(GL_DEPTH_TEST);
  707. BlendScope const blend(true);
  708. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  709. GLboolean const prev_cull = glIsEnabled(GL_CULL_FACE);
  710. if (prev_cull != 0U) {
  711. glDisable(GL_CULL_FACE);
  712. }
  713. Shader *firecamp_shader = m_vegetationPipeline->firecamp_shader();
  714. if (m_lastBoundShader != firecamp_shader) {
  715. firecamp_shader->use();
  716. m_lastBoundShader = firecamp_shader;
  717. m_lastBoundTexture = nullptr;
  718. }
  719. if (m_vegetationPipeline->m_firecampUniforms.view_proj !=
  720. Shader::InvalidUniform) {
  721. firecamp_shader->set_uniform(
  722. m_vegetationPipeline->m_firecampUniforms.view_proj, view_proj);
  723. }
  724. if (m_vegetationPipeline->m_firecampUniforms.time !=
  725. Shader::InvalidUniform) {
  726. firecamp_shader->set_uniform(
  727. m_vegetationPipeline->m_firecampUniforms.time,
  728. firecamp.params.time);
  729. }
  730. if (m_vegetationPipeline->m_firecampUniforms.flickerSpeed !=
  731. Shader::InvalidUniform) {
  732. firecamp_shader->set_uniform(
  733. m_vegetationPipeline->m_firecampUniforms.flickerSpeed,
  734. firecamp.params.flicker_speed);
  735. }
  736. if (m_vegetationPipeline->m_firecampUniforms.flickerAmount !=
  737. Shader::InvalidUniform) {
  738. firecamp_shader->set_uniform(
  739. m_vegetationPipeline->m_firecampUniforms.flickerAmount,
  740. firecamp.params.flicker_amount);
  741. }
  742. if (m_vegetationPipeline->m_firecampUniforms.glowStrength !=
  743. Shader::InvalidUniform) {
  744. firecamp_shader->set_uniform(
  745. m_vegetationPipeline->m_firecampUniforms.glowStrength,
  746. firecamp.params.glow_strength);
  747. }
  748. if (m_vegetationPipeline->m_firecampUniforms.camera_right !=
  749. Shader::InvalidUniform) {
  750. QVector3D camera_right = cam.get_right_vector();
  751. if (camera_right.lengthSquared() < 1e-6F) {
  752. camera_right = QVector3D(1.0F, 0.0F, 0.0F);
  753. } else {
  754. camera_right.normalize();
  755. }
  756. firecamp_shader->set_uniform(
  757. m_vegetationPipeline->m_firecampUniforms.camera_right,
  758. camera_right);
  759. }
  760. if (m_vegetationPipeline->m_firecampUniforms.camera_forward !=
  761. Shader::InvalidUniform) {
  762. QVector3D camera_forward = cam.get_forward_vector();
  763. if (camera_forward.lengthSquared() < 1e-6F) {
  764. camera_forward = QVector3D(0.0F, 0.0F, -1.0F);
  765. } else {
  766. camera_forward.normalize();
  767. }
  768. firecamp_shader->set_uniform(
  769. m_vegetationPipeline->m_firecampUniforms.camera_forward,
  770. camera_forward);
  771. }
  772. if (m_vegetationPipeline->m_firecampUniforms.fireTexture !=
  773. Shader::InvalidUniform) {
  774. if (m_resources && (m_resources->white() != nullptr)) {
  775. m_resources->white()->bind(0);
  776. firecamp_shader->set_uniform(
  777. m_vegetationPipeline->m_firecampUniforms.fireTexture, 0);
  778. }
  779. }
  780. glBindVertexArray(m_vegetationPipeline->m_firecampVao);
  781. firecamp.instance_buffer->bind();
  782. const auto stride = static_cast<GLsizei>(sizeof(FireCampInstanceGpu));
  783. glVertexAttribPointer(InstancePosition, Vec4, GL_FLOAT, GL_FALSE, stride,
  784. reinterpret_cast<void *>(
  785. offsetof(FireCampInstanceGpu, pos_intensity)));
  786. glVertexAttribPointer(InstanceScale, Vec4, GL_FLOAT, GL_FALSE, stride,
  787. reinterpret_cast<void *>(
  788. offsetof(FireCampInstanceGpu, radius_phase)));
  789. firecamp.instance_buffer->unbind();
  790. glDrawElementsInstanced(GL_TRIANGLES,
  791. m_vegetationPipeline->m_firecampIndexCount,
  792. GL_UNSIGNED_SHORT, nullptr,
  793. static_cast<GLsizei>(firecamp.instance_count));
  794. glBindVertexArray(0);
  795. if (prev_cull != 0U) {
  796. glEnable(GL_CULL_FACE);
  797. }
  798. break;
  799. }
  800. case RainBatchCmdIndex: {
  801. const auto &rain = std::get<RainBatchCmdIndex>(cmd);
  802. if (m_rainPipeline == nullptr || !m_rainPipeline->is_initialized()) {
  803. break;
  804. }
  805. m_rainPipeline->render(cam, rain.params);
  806. break;
  807. }
  808. case TerrainChunkCmdIndex: {
  809. const auto &terrain = std::get<TerrainChunkCmdIndex>(cmd);
  810. Shader *active_shader = terrain.params.is_ground_plane
  811. ? m_terrainPipeline->m_groundShader
  812. : m_terrainPipeline->m_terrainShader;
  813. if ((terrain.mesh == nullptr) || (active_shader == nullptr)) {
  814. break;
  815. }
  816. if (m_lastBoundShader != active_shader) {
  817. active_shader->use();
  818. m_lastBoundShader = active_shader;
  819. m_lastBoundTexture = nullptr;
  820. }
  821. const QMatrix4x4 mvp = view_proj * terrain.model;
  822. if (terrain.params.is_ground_plane) {
  823. if (m_terrainPipeline->m_groundUniforms.mvp != Shader::InvalidUniform) {
  824. active_shader->set_uniform(m_terrainPipeline->m_groundUniforms.mvp,
  825. mvp);
  826. }
  827. if (m_terrainPipeline->m_groundUniforms.model !=
  828. Shader::InvalidUniform) {
  829. active_shader->set_uniform(m_terrainPipeline->m_groundUniforms.model,
  830. terrain.model);
  831. }
  832. if (m_terrainPipeline->m_groundUniforms.grass_primary !=
  833. Shader::InvalidUniform) {
  834. active_shader->set_uniform(
  835. m_terrainPipeline->m_groundUniforms.grass_primary,
  836. terrain.params.grass_primary);
  837. }
  838. if (m_terrainPipeline->m_groundUniforms.grass_secondary !=
  839. Shader::InvalidUniform) {
  840. active_shader->set_uniform(
  841. m_terrainPipeline->m_groundUniforms.grass_secondary,
  842. terrain.params.grass_secondary);
  843. }
  844. if (m_terrainPipeline->m_groundUniforms.grass_dry !=
  845. Shader::InvalidUniform) {
  846. active_shader->set_uniform(
  847. m_terrainPipeline->m_groundUniforms.grass_dry,
  848. terrain.params.grass_dry);
  849. }
  850. if (m_terrainPipeline->m_groundUniforms.soil_color !=
  851. Shader::InvalidUniform) {
  852. active_shader->set_uniform(
  853. m_terrainPipeline->m_groundUniforms.soil_color,
  854. terrain.params.soil_color);
  855. }
  856. if (m_terrainPipeline->m_groundUniforms.tint !=
  857. Shader::InvalidUniform) {
  858. active_shader->set_uniform(m_terrainPipeline->m_groundUniforms.tint,
  859. terrain.params.tint);
  860. }
  861. if (m_terrainPipeline->m_groundUniforms.noise_offset !=
  862. Shader::InvalidUniform) {
  863. active_shader->set_uniform(
  864. m_terrainPipeline->m_groundUniforms.noise_offset,
  865. terrain.params.noise_offset);
  866. }
  867. if (m_terrainPipeline->m_groundUniforms.tile_size !=
  868. Shader::InvalidUniform) {
  869. active_shader->set_uniform(
  870. m_terrainPipeline->m_groundUniforms.tile_size,
  871. terrain.params.tile_size);
  872. }
  873. if (m_terrainPipeline->m_groundUniforms.macro_noise_scale !=
  874. Shader::InvalidUniform) {
  875. active_shader->set_uniform(
  876. m_terrainPipeline->m_groundUniforms.macro_noise_scale,
  877. terrain.params.macro_noise_scale);
  878. }
  879. if (m_terrainPipeline->m_groundUniforms.detail_noise_scale !=
  880. Shader::InvalidUniform) {
  881. active_shader->set_uniform(
  882. m_terrainPipeline->m_groundUniforms.detail_noise_scale,
  883. terrain.params.detail_noise_scale);
  884. }
  885. if (m_terrainPipeline->m_groundUniforms.soil_blend_height !=
  886. Shader::InvalidUniform) {
  887. active_shader->set_uniform(
  888. m_terrainPipeline->m_groundUniforms.soil_blend_height,
  889. terrain.params.soil_blend_height);
  890. }
  891. if (m_terrainPipeline->m_groundUniforms.soil_blend_sharpness !=
  892. Shader::InvalidUniform) {
  893. active_shader->set_uniform(
  894. m_terrainPipeline->m_groundUniforms.soil_blend_sharpness,
  895. terrain.params.soil_blend_sharpness);
  896. }
  897. if (m_terrainPipeline->m_groundUniforms.height_noise_strength !=
  898. Shader::InvalidUniform) {
  899. active_shader->set_uniform(
  900. m_terrainPipeline->m_groundUniforms.height_noise_strength,
  901. terrain.params.height_noise_strength);
  902. }
  903. if (m_terrainPipeline->m_groundUniforms.height_noise_frequency !=
  904. Shader::InvalidUniform) {
  905. active_shader->set_uniform(
  906. m_terrainPipeline->m_groundUniforms.height_noise_frequency,
  907. terrain.params.height_noise_frequency);
  908. }
  909. if (m_terrainPipeline->m_groundUniforms.ambient_boost !=
  910. Shader::InvalidUniform) {
  911. active_shader->set_uniform(
  912. m_terrainPipeline->m_groundUniforms.ambient_boost,
  913. terrain.params.ambient_boost);
  914. }
  915. if (m_terrainPipeline->m_groundUniforms.light_dir !=
  916. Shader::InvalidUniform) {
  917. QVector3D light_dir = terrain.params.light_direction;
  918. if (!light_dir.isNull()) {
  919. light_dir.normalize();
  920. }
  921. active_shader->set_uniform(
  922. m_terrainPipeline->m_groundUniforms.light_dir, light_dir);
  923. }
  924. if (m_terrainPipeline->m_groundUniforms.snow_coverage !=
  925. Shader::InvalidUniform) {
  926. active_shader->set_uniform(
  927. m_terrainPipeline->m_groundUniforms.snow_coverage,
  928. terrain.params.snow_coverage);
  929. }
  930. if (m_terrainPipeline->m_groundUniforms.moisture_level !=
  931. Shader::InvalidUniform) {
  932. active_shader->set_uniform(
  933. m_terrainPipeline->m_groundUniforms.moisture_level,
  934. terrain.params.moisture_level);
  935. }
  936. if (m_terrainPipeline->m_groundUniforms.crack_intensity !=
  937. Shader::InvalidUniform) {
  938. active_shader->set_uniform(
  939. m_terrainPipeline->m_groundUniforms.crack_intensity,
  940. terrain.params.crack_intensity);
  941. }
  942. if (m_terrainPipeline->m_groundUniforms.grass_saturation !=
  943. Shader::InvalidUniform) {
  944. active_shader->set_uniform(
  945. m_terrainPipeline->m_groundUniforms.grass_saturation,
  946. terrain.params.grass_saturation);
  947. }
  948. if (m_terrainPipeline->m_groundUniforms.soil_roughness !=
  949. Shader::InvalidUniform) {
  950. active_shader->set_uniform(
  951. m_terrainPipeline->m_groundUniforms.soil_roughness,
  952. terrain.params.soil_roughness);
  953. }
  954. if (m_terrainPipeline->m_groundUniforms.snow_color !=
  955. Shader::InvalidUniform) {
  956. active_shader->set_uniform(
  957. m_terrainPipeline->m_groundUniforms.snow_color,
  958. terrain.params.snow_color);
  959. }
  960. } else {
  961. if (m_terrainPipeline->m_terrainUniforms.mvp !=
  962. Shader::InvalidUniform) {
  963. active_shader->set_uniform(m_terrainPipeline->m_terrainUniforms.mvp,
  964. mvp);
  965. }
  966. if (m_terrainPipeline->m_terrainUniforms.model !=
  967. Shader::InvalidUniform) {
  968. active_shader->set_uniform(m_terrainPipeline->m_terrainUniforms.model,
  969. terrain.model);
  970. }
  971. if (m_terrainPipeline->m_terrainUniforms.grass_primary !=
  972. Shader::InvalidUniform) {
  973. active_shader->set_uniform(
  974. m_terrainPipeline->m_terrainUniforms.grass_primary,
  975. terrain.params.grass_primary);
  976. }
  977. if (m_terrainPipeline->m_terrainUniforms.grass_secondary !=
  978. Shader::InvalidUniform) {
  979. active_shader->set_uniform(
  980. m_terrainPipeline->m_terrainUniforms.grass_secondary,
  981. terrain.params.grass_secondary);
  982. }
  983. if (m_terrainPipeline->m_terrainUniforms.grass_dry !=
  984. Shader::InvalidUniform) {
  985. active_shader->set_uniform(
  986. m_terrainPipeline->m_terrainUniforms.grass_dry,
  987. terrain.params.grass_dry);
  988. }
  989. if (m_terrainPipeline->m_terrainUniforms.soil_color !=
  990. Shader::InvalidUniform) {
  991. active_shader->set_uniform(
  992. m_terrainPipeline->m_terrainUniforms.soil_color,
  993. terrain.params.soil_color);
  994. }
  995. if (m_terrainPipeline->m_terrainUniforms.rock_low !=
  996. Shader::InvalidUniform) {
  997. active_shader->set_uniform(
  998. m_terrainPipeline->m_terrainUniforms.rock_low,
  999. terrain.params.rock_low);
  1000. }
  1001. if (m_terrainPipeline->m_terrainUniforms.rock_high !=
  1002. Shader::InvalidUniform) {
  1003. active_shader->set_uniform(
  1004. m_terrainPipeline->m_terrainUniforms.rock_high,
  1005. terrain.params.rock_high);
  1006. }
  1007. if (m_terrainPipeline->m_terrainUniforms.tint !=
  1008. Shader::InvalidUniform) {
  1009. active_shader->set_uniform(m_terrainPipeline->m_terrainUniforms.tint,
  1010. terrain.params.tint);
  1011. }
  1012. if (m_terrainPipeline->m_terrainUniforms.noise_offset !=
  1013. Shader::InvalidUniform) {
  1014. active_shader->set_uniform(
  1015. m_terrainPipeline->m_terrainUniforms.noise_offset,
  1016. terrain.params.noise_offset);
  1017. }
  1018. if (m_terrainPipeline->m_terrainUniforms.tile_size !=
  1019. Shader::InvalidUniform) {
  1020. active_shader->set_uniform(
  1021. m_terrainPipeline->m_terrainUniforms.tile_size,
  1022. terrain.params.tile_size);
  1023. }
  1024. if (m_terrainPipeline->m_terrainUniforms.macro_noise_scale !=
  1025. Shader::InvalidUniform) {
  1026. active_shader->set_uniform(
  1027. m_terrainPipeline->m_terrainUniforms.macro_noise_scale,
  1028. terrain.params.macro_noise_scale);
  1029. }
  1030. if (m_terrainPipeline->m_terrainUniforms.detail_noise_scale !=
  1031. Shader::InvalidUniform) {
  1032. active_shader->set_uniform(
  1033. m_terrainPipeline->m_terrainUniforms.detail_noise_scale,
  1034. terrain.params.detail_noise_scale);
  1035. }
  1036. if (m_terrainPipeline->m_terrainUniforms.slope_rock_threshold !=
  1037. Shader::InvalidUniform) {
  1038. active_shader->set_uniform(
  1039. m_terrainPipeline->m_terrainUniforms.slope_rock_threshold,
  1040. terrain.params.slope_rock_threshold);
  1041. }
  1042. if (m_terrainPipeline->m_terrainUniforms.slope_rock_sharpness !=
  1043. Shader::InvalidUniform) {
  1044. active_shader->set_uniform(
  1045. m_terrainPipeline->m_terrainUniforms.slope_rock_sharpness,
  1046. terrain.params.slope_rock_sharpness);
  1047. }
  1048. if (m_terrainPipeline->m_terrainUniforms.soil_blend_height !=
  1049. Shader::InvalidUniform) {
  1050. active_shader->set_uniform(
  1051. m_terrainPipeline->m_terrainUniforms.soil_blend_height,
  1052. terrain.params.soil_blend_height);
  1053. }
  1054. if (m_terrainPipeline->m_terrainUniforms.soil_blend_sharpness !=
  1055. Shader::InvalidUniform) {
  1056. active_shader->set_uniform(
  1057. m_terrainPipeline->m_terrainUniforms.soil_blend_sharpness,
  1058. terrain.params.soil_blend_sharpness);
  1059. }
  1060. if (m_terrainPipeline->m_terrainUniforms.height_noise_strength !=
  1061. Shader::InvalidUniform) {
  1062. active_shader->set_uniform(
  1063. m_terrainPipeline->m_terrainUniforms.height_noise_strength,
  1064. terrain.params.height_noise_strength);
  1065. }
  1066. if (m_terrainPipeline->m_terrainUniforms.height_noise_frequency !=
  1067. Shader::InvalidUniform) {
  1068. active_shader->set_uniform(
  1069. m_terrainPipeline->m_terrainUniforms.height_noise_frequency,
  1070. terrain.params.height_noise_frequency);
  1071. }
  1072. if (m_terrainPipeline->m_terrainUniforms.ambient_boost !=
  1073. Shader::InvalidUniform) {
  1074. active_shader->set_uniform(
  1075. m_terrainPipeline->m_terrainUniforms.ambient_boost,
  1076. terrain.params.ambient_boost);
  1077. }
  1078. if (m_terrainPipeline->m_terrainUniforms.rock_detail_strength !=
  1079. Shader::InvalidUniform) {
  1080. active_shader->set_uniform(
  1081. m_terrainPipeline->m_terrainUniforms.rock_detail_strength,
  1082. terrain.params.rock_detail_strength);
  1083. }
  1084. if (m_terrainPipeline->m_terrainUniforms.light_dir !=
  1085. Shader::InvalidUniform) {
  1086. QVector3D light_dir = terrain.params.light_direction;
  1087. if (!light_dir.isNull()) {
  1088. light_dir.normalize();
  1089. }
  1090. active_shader->set_uniform(
  1091. m_terrainPipeline->m_terrainUniforms.light_dir, light_dir);
  1092. }
  1093. if (m_terrainPipeline->m_terrainUniforms.snow_coverage !=
  1094. Shader::InvalidUniform) {
  1095. active_shader->set_uniform(
  1096. m_terrainPipeline->m_terrainUniforms.snow_coverage,
  1097. terrain.params.snow_coverage);
  1098. }
  1099. if (m_terrainPipeline->m_terrainUniforms.moisture_level !=
  1100. Shader::InvalidUniform) {
  1101. active_shader->set_uniform(
  1102. m_terrainPipeline->m_terrainUniforms.moisture_level,
  1103. terrain.params.moisture_level);
  1104. }
  1105. if (m_terrainPipeline->m_terrainUniforms.crack_intensity !=
  1106. Shader::InvalidUniform) {
  1107. active_shader->set_uniform(
  1108. m_terrainPipeline->m_terrainUniforms.crack_intensity,
  1109. terrain.params.crack_intensity);
  1110. }
  1111. if (m_terrainPipeline->m_terrainUniforms.rock_exposure !=
  1112. Shader::InvalidUniform) {
  1113. active_shader->set_uniform(
  1114. m_terrainPipeline->m_terrainUniforms.rock_exposure,
  1115. terrain.params.rock_exposure);
  1116. }
  1117. if (m_terrainPipeline->m_terrainUniforms.grass_saturation !=
  1118. Shader::InvalidUniform) {
  1119. active_shader->set_uniform(
  1120. m_terrainPipeline->m_terrainUniforms.grass_saturation,
  1121. terrain.params.grass_saturation);
  1122. }
  1123. if (m_terrainPipeline->m_terrainUniforms.soil_roughness !=
  1124. Shader::InvalidUniform) {
  1125. active_shader->set_uniform(
  1126. m_terrainPipeline->m_terrainUniforms.soil_roughness,
  1127. terrain.params.soil_roughness);
  1128. }
  1129. if (m_terrainPipeline->m_terrainUniforms.snow_color !=
  1130. Shader::InvalidUniform) {
  1131. active_shader->set_uniform(
  1132. m_terrainPipeline->m_terrainUniforms.snow_color,
  1133. terrain.params.snow_color);
  1134. }
  1135. }
  1136. DepthMaskScope const depth_mask(terrain.depth_write);
  1137. std::unique_ptr<PolygonOffsetScope> poly_scope;
  1138. if (terrain.depth_bias != 0.0F) {
  1139. poly_scope = std::make_unique<PolygonOffsetScope>(terrain.depth_bias,
  1140. terrain.depth_bias);
  1141. }
  1142. terrain.mesh->draw();
  1143. break;
  1144. }
  1145. case MeshCmdIndex: {
  1146. const auto &it = std::get<MeshCmdIndex>(cmd);
  1147. if (it.mesh == nullptr) {
  1148. break;
  1149. }
  1150. Shader *active_shader =
  1151. (it.shader != nullptr) ? it.shader : m_basicShader;
  1152. if (active_shader == nullptr) {
  1153. break;
  1154. }
  1155. if (glIsEnabled(GL_POLYGON_OFFSET_FILL) != 0U) {
  1156. glDisable(GL_POLYGON_OFFSET_FILL);
  1157. }
  1158. Shader *shadowShader =
  1159. m_shaderCache ? m_shaderCache->get(QStringLiteral("troop_shadow"))
  1160. : nullptr;
  1161. bool const isShadowShader = (active_shader == shadowShader);
  1162. std::unique_ptr<DepthMaskScope> shadow_depth_scope;
  1163. std::unique_ptr<BlendScope> shadow_blend_scope;
  1164. if (isShadowShader) {
  1165. shadow_depth_scope = std::make_unique<DepthMaskScope>(false);
  1166. shadow_blend_scope = std::make_unique<BlendScope>(true);
  1167. } else {
  1168. glDepthMask(GL_TRUE);
  1169. }
  1170. bool const isTransparent = (!isShadowShader) && (it.alpha < 0.999F);
  1171. std::unique_ptr<DepthMaskScope> transparent_depth_scope;
  1172. std::unique_ptr<BlendScope> transparent_blend_scope;
  1173. GLint prev_depth_func = GL_LESS;
  1174. if (isTransparent) {
  1175. glGetIntegerv(GL_DEPTH_FUNC, &prev_depth_func);
  1176. transparent_depth_scope = std::make_unique<DepthMaskScope>(false);
  1177. transparent_blend_scope = std::make_unique<BlendScope>(true);
  1178. glDepthFunc(GL_LEQUAL);
  1179. }
  1180. if (active_shader == m_waterPipeline->m_riverShader) {
  1181. if (m_lastBoundShader != active_shader) {
  1182. active_shader->use();
  1183. m_lastBoundShader = active_shader;
  1184. }
  1185. active_shader->set_uniform(m_waterPipeline->m_riverUniforms.model,
  1186. it.model);
  1187. active_shader->set_uniform(m_waterPipeline->m_riverUniforms.view,
  1188. cam.get_view_matrix());
  1189. active_shader->set_uniform(m_waterPipeline->m_riverUniforms.projection,
  1190. cam.get_projection_matrix());
  1191. active_shader->set_uniform(m_waterPipeline->m_riverUniforms.time,
  1192. m_animationTime);
  1193. it.mesh->draw();
  1194. break;
  1195. }
  1196. if (active_shader == m_waterPipeline->m_riverbankShader) {
  1197. if (m_lastBoundShader != active_shader) {
  1198. active_shader->use();
  1199. m_lastBoundShader = active_shader;
  1200. }
  1201. active_shader->set_uniform(m_waterPipeline->m_riverbankUniforms.model,
  1202. it.model);
  1203. active_shader->set_uniform(m_waterPipeline->m_riverbankUniforms.view,
  1204. cam.get_view_matrix());
  1205. active_shader->set_uniform(
  1206. m_waterPipeline->m_riverbankUniforms.projection,
  1207. cam.get_projection_matrix());
  1208. active_shader->set_uniform(m_waterPipeline->m_riverbankUniforms.time,
  1209. m_animationTime);
  1210. if (m_waterPipeline->m_riverbankUniforms.segment_visibility !=
  1211. Shader::InvalidUniform) {
  1212. active_shader->set_uniform(
  1213. m_waterPipeline->m_riverbankUniforms.segment_visibility,
  1214. it.alpha);
  1215. }
  1216. if (m_waterPipeline->m_riverbankUniforms.has_visibility !=
  1217. Shader::InvalidUniform) {
  1218. int const has_vis = m_riverbankVisibility.enabled ? 1 : 0;
  1219. active_shader->set_uniform(
  1220. m_waterPipeline->m_riverbankUniforms.has_visibility, has_vis);
  1221. }
  1222. if (m_riverbankVisibility.enabled &&
  1223. m_riverbankVisibility.texture != nullptr) {
  1224. if (m_waterPipeline->m_riverbankUniforms.visibility_size !=
  1225. Shader::InvalidUniform) {
  1226. active_shader->set_uniform(
  1227. m_waterPipeline->m_riverbankUniforms.visibility_size,
  1228. m_riverbankVisibility.size);
  1229. }
  1230. if (m_waterPipeline->m_riverbankUniforms.visibility_tile_size !=
  1231. Shader::InvalidUniform) {
  1232. active_shader->set_uniform(
  1233. m_waterPipeline->m_riverbankUniforms.visibility_tile_size,
  1234. m_riverbankVisibility.tile_size);
  1235. }
  1236. if (m_waterPipeline->m_riverbankUniforms.explored_alpha !=
  1237. Shader::InvalidUniform) {
  1238. active_shader->set_uniform(
  1239. m_waterPipeline->m_riverbankUniforms.explored_alpha,
  1240. m_riverbankVisibility.explored_alpha);
  1241. }
  1242. constexpr int k_riverbank_vis_texture_unit = 7;
  1243. m_riverbankVisibility.texture->bind(k_riverbank_vis_texture_unit);
  1244. if (m_waterPipeline->m_riverbankUniforms.visibility_texture !=
  1245. Shader::InvalidUniform) {
  1246. active_shader->set_uniform(
  1247. m_waterPipeline->m_riverbankUniforms.visibility_texture,
  1248. k_riverbank_vis_texture_unit);
  1249. }
  1250. m_lastBoundTexture = m_riverbankVisibility.texture;
  1251. }
  1252. it.mesh->draw();
  1253. break;
  1254. }
  1255. if (active_shader == m_waterPipeline->m_bridgeShader) {
  1256. if (m_lastBoundShader != active_shader) {
  1257. active_shader->use();
  1258. m_lastBoundShader = active_shader;
  1259. }
  1260. active_shader->set_uniform(m_waterPipeline->m_bridgeUniforms.mvp,
  1261. it.mvp);
  1262. active_shader->set_uniform(m_waterPipeline->m_bridgeUniforms.model,
  1263. it.model);
  1264. active_shader->set_uniform(m_waterPipeline->m_bridgeUniforms.color,
  1265. it.color);
  1266. QVector3D const light_dir(0.35F, 0.8F, 0.45F);
  1267. active_shader->set_uniform(
  1268. m_waterPipeline->m_bridgeUniforms.light_direction, light_dir);
  1269. it.mesh->draw();
  1270. break;
  1271. }
  1272. if (active_shader == m_waterPipeline->m_road_shader) {
  1273. if (m_lastBoundShader != active_shader) {
  1274. active_shader->use();
  1275. m_lastBoundShader = active_shader;
  1276. }
  1277. active_shader->set_uniform(m_waterPipeline->m_road_uniforms.mvp,
  1278. it.mvp);
  1279. active_shader->set_uniform(m_waterPipeline->m_road_uniforms.model,
  1280. it.model);
  1281. active_shader->set_uniform(m_waterPipeline->m_road_uniforms.color,
  1282. it.color);
  1283. active_shader->set_uniform(m_waterPipeline->m_road_uniforms.alpha,
  1284. it.alpha);
  1285. QVector3D const road_light_dir(0.35F, 0.8F, 0.45F);
  1286. active_shader->set_uniform(
  1287. m_waterPipeline->m_road_uniforms.light_direction, road_light_dir);
  1288. it.mesh->draw();
  1289. break;
  1290. }
  1291. if (m_bannerPipeline != nullptr &&
  1292. active_shader == m_bannerPipeline->m_bannerShader) {
  1293. if (m_lastBoundShader != active_shader) {
  1294. active_shader->use();
  1295. m_lastBoundShader = active_shader;
  1296. }
  1297. QMatrix4x4 mvp =
  1298. cam.get_projection_matrix() * cam.get_view_matrix() * it.model;
  1299. active_shader->set_uniform(m_bannerPipeline->m_bannerUniforms.mvp, mvp);
  1300. active_shader->set_uniform(m_bannerPipeline->m_bannerUniforms.model,
  1301. it.model);
  1302. active_shader->set_uniform(m_bannerPipeline->m_bannerUniforms.time,
  1303. m_animationTime);
  1304. float windStrength = 0.8F + 0.2F * std::sin(m_animationTime * 0.5F);
  1305. active_shader->set_uniform(
  1306. m_bannerPipeline->m_bannerUniforms.windStrength, windStrength);
  1307. active_shader->set_uniform(m_bannerPipeline->m_bannerUniforms.color,
  1308. it.color);
  1309. QVector3D trimColor = it.color * 0.7F;
  1310. active_shader->set_uniform(m_bannerPipeline->m_bannerUniforms.trimColor,
  1311. trimColor);
  1312. active_shader->set_uniform(m_bannerPipeline->m_bannerUniforms.alpha,
  1313. it.alpha);
  1314. active_shader->set_uniform(
  1315. m_bannerPipeline->m_bannerUniforms.useTexture,
  1316. it.texture != nullptr);
  1317. Texture *tex_to_use =
  1318. (it.texture != nullptr)
  1319. ? it.texture
  1320. : (m_resources ? m_resources->white() : nullptr);
  1321. if ((tex_to_use != nullptr) && tex_to_use != m_lastBoundTexture) {
  1322. tex_to_use->bind(0);
  1323. m_lastBoundTexture = tex_to_use;
  1324. active_shader->set_uniform(m_bannerPipeline->m_bannerUniforms.texture,
  1325. 0);
  1326. }
  1327. it.mesh->draw();
  1328. break;
  1329. }
  1330. auto *uniforms = m_characterPipeline
  1331. ? m_characterPipeline->resolveUniforms(active_shader)
  1332. : nullptr;
  1333. if (uniforms == nullptr) {
  1334. break;
  1335. }
  1336. if (m_lastBoundShader != active_shader) {
  1337. active_shader->use();
  1338. m_lastBoundShader = active_shader;
  1339. }
  1340. active_shader->set_uniform(uniforms->mvp, it.mvp);
  1341. active_shader->set_uniform(uniforms->model, it.model);
  1342. Texture *tex_to_use =
  1343. (it.texture != nullptr)
  1344. ? it.texture
  1345. : (m_resources ? m_resources->white() : nullptr);
  1346. if ((tex_to_use != nullptr) && tex_to_use != m_lastBoundTexture) {
  1347. tex_to_use->bind(0);
  1348. m_lastBoundTexture = tex_to_use;
  1349. active_shader->set_uniform(uniforms->texture, 0);
  1350. }
  1351. active_shader->set_uniform(uniforms->useTexture, it.texture != nullptr);
  1352. active_shader->set_uniform(uniforms->color, it.color);
  1353. active_shader->set_uniform(uniforms->alpha, it.alpha);
  1354. active_shader->set_uniform(uniforms->materialId, it.material_id);
  1355. it.mesh->draw();
  1356. if (isTransparent) {
  1357. glDepthFunc(static_cast<GLenum>(prev_depth_func));
  1358. }
  1359. break;
  1360. }
  1361. case GridCmdIndex: {
  1362. if (m_effectsPipeline->m_gridShader == nullptr) {
  1363. break;
  1364. }
  1365. const auto &gc = std::get<GridCmdIndex>(cmd);
  1366. if (m_lastBoundShader != m_effectsPipeline->m_gridShader) {
  1367. m_effectsPipeline->m_gridShader->use();
  1368. m_lastBoundShader = m_effectsPipeline->m_gridShader;
  1369. }
  1370. m_effectsPipeline->m_gridShader->set_uniform(
  1371. m_effectsPipeline->m_gridUniforms.mvp, gc.mvp);
  1372. m_effectsPipeline->m_gridShader->set_uniform(
  1373. m_effectsPipeline->m_gridUniforms.model, gc.model);
  1374. m_effectsPipeline->m_gridShader->set_uniform(
  1375. m_effectsPipeline->m_gridUniforms.gridColor, gc.color);
  1376. m_effectsPipeline->m_gridShader->set_uniform(
  1377. m_effectsPipeline->m_gridUniforms.lineColor, k_grid_line_color);
  1378. m_effectsPipeline->m_gridShader->set_uniform(
  1379. m_effectsPipeline->m_gridUniforms.cellSize, gc.cell_size);
  1380. m_effectsPipeline->m_gridShader->set_uniform(
  1381. m_effectsPipeline->m_gridUniforms.thickness, gc.thickness);
  1382. if (m_resources) {
  1383. if (auto *plane = m_resources->ground()) {
  1384. plane->draw();
  1385. }
  1386. }
  1387. break;
  1388. }
  1389. case SelectionRingCmdIndex: {
  1390. const auto &sc = std::get<SelectionRingCmdIndex>(cmd);
  1391. Mesh *ring = Render::Geom::SelectionRing::get();
  1392. if (ring == nullptr) {
  1393. break;
  1394. }
  1395. if (m_lastBoundShader != m_effectsPipeline->m_basicShader) {
  1396. m_effectsPipeline->m_basicShader->use();
  1397. m_lastBoundShader = m_effectsPipeline->m_basicShader;
  1398. }
  1399. m_effectsPipeline->m_basicShader->use();
  1400. m_effectsPipeline->m_basicShader->set_uniform(
  1401. m_effectsPipeline->m_basicUniforms.useTexture, false);
  1402. m_effectsPipeline->m_basicShader->set_uniform(
  1403. m_effectsPipeline->m_basicUniforms.color, sc.color);
  1404. DepthMaskScope const depth_mask(false);
  1405. PolygonOffsetScope const poly(-1.0F, -1.0F);
  1406. BlendScope const blend(true);
  1407. {
  1408. QMatrix4x4 m = sc.model;
  1409. m.scale(1.08F, 1.0F, 1.08F);
  1410. const QMatrix4x4 mvp = view_proj * m;
  1411. m_effectsPipeline->m_basicShader->set_uniform(
  1412. m_effectsPipeline->m_basicUniforms.mvp, mvp);
  1413. m_effectsPipeline->m_basicShader->set_uniform(
  1414. m_effectsPipeline->m_basicUniforms.model, m);
  1415. m_effectsPipeline->m_basicShader->set_uniform(
  1416. m_effectsPipeline->m_basicUniforms.alpha, sc.alpha_outer);
  1417. ring->draw();
  1418. }
  1419. {
  1420. const QMatrix4x4 mvp = view_proj * sc.model;
  1421. m_effectsPipeline->m_basicShader->set_uniform(
  1422. m_effectsPipeline->m_basicUniforms.mvp, mvp);
  1423. m_effectsPipeline->m_basicShader->set_uniform(
  1424. m_effectsPipeline->m_basicUniforms.model, sc.model);
  1425. m_effectsPipeline->m_basicShader->set_uniform(
  1426. m_effectsPipeline->m_basicUniforms.alpha, sc.alpha_inner);
  1427. ring->draw();
  1428. }
  1429. break;
  1430. }
  1431. case SelectionSmokeCmdIndex: {
  1432. const auto &sm = std::get<SelectionSmokeCmdIndex>(cmd);
  1433. Mesh *disc = Render::Geom::SelectionDisc::get();
  1434. if (disc == nullptr) {
  1435. break;
  1436. }
  1437. if (m_lastBoundShader != m_effectsPipeline->m_basicShader) {
  1438. m_effectsPipeline->m_basicShader->use();
  1439. m_lastBoundShader = m_effectsPipeline->m_basicShader;
  1440. }
  1441. m_effectsPipeline->m_basicShader->set_uniform(
  1442. m_effectsPipeline->m_basicUniforms.useTexture, false);
  1443. m_effectsPipeline->m_basicShader->set_uniform(
  1444. m_effectsPipeline->m_basicUniforms.color, sm.color);
  1445. DepthMaskScope const depth_mask(false);
  1446. DepthTestScope const depth_test(true);
  1447. PolygonOffsetScope const poly(-1.0F, -1.0F);
  1448. BlendScope const blend(true);
  1449. for (int i = 0; i < 7; ++i) {
  1450. float const scale = 1.35F + 0.12F * i;
  1451. float const a = sm.base_alpha * (1.0F - 0.09F * i);
  1452. QMatrix4x4 m = sm.model;
  1453. m.translate(0.0F, 0.02F, 0.0F);
  1454. m.scale(scale, 1.0F, scale);
  1455. const QMatrix4x4 mvp = view_proj * m;
  1456. m_effectsPipeline->m_basicShader->set_uniform(
  1457. m_effectsPipeline->m_basicUniforms.mvp, mvp);
  1458. m_effectsPipeline->m_basicShader->set_uniform(
  1459. m_effectsPipeline->m_basicUniforms.model, m);
  1460. m_effectsPipeline->m_basicShader->set_uniform(
  1461. m_effectsPipeline->m_basicUniforms.alpha, a);
  1462. disc->draw();
  1463. }
  1464. break;
  1465. }
  1466. case PrimitiveBatchCmdIndex: {
  1467. const auto &batch = std::get<PrimitiveBatchCmdIndex>(cmd);
  1468. if (batch.instance_count() == 0 || m_primitiveBatchPipeline == nullptr ||
  1469. !m_primitiveBatchPipeline->is_initialized()) {
  1470. break;
  1471. }
  1472. const auto *data = batch.instance_data();
  1473. switch (batch.type) {
  1474. case PrimitiveType::Sphere:
  1475. m_primitiveBatchPipeline->upload_sphere_instances(
  1476. data, batch.instance_count());
  1477. m_primitiveBatchPipeline->draw_spheres(batch.instance_count(),
  1478. view_proj);
  1479. break;
  1480. case PrimitiveType::Cylinder:
  1481. m_primitiveBatchPipeline->upload_cylinder_instances(
  1482. data, batch.instance_count());
  1483. m_primitiveBatchPipeline->draw_cylinders(batch.instance_count(),
  1484. view_proj);
  1485. break;
  1486. case PrimitiveType::Cone:
  1487. m_primitiveBatchPipeline->upload_cone_instances(data,
  1488. batch.instance_count());
  1489. m_primitiveBatchPipeline->draw_cones(batch.instance_count(), view_proj);
  1490. break;
  1491. }
  1492. m_lastBoundShader = m_primitiveBatchPipeline->shader();
  1493. break;
  1494. }
  1495. case HealingBeamCmdIndex: {
  1496. const auto &beam = std::get<HealingBeamCmdIndex>(cmd);
  1497. if (m_healingBeamPipeline == nullptr ||
  1498. !m_healingBeamPipeline->is_initialized()) {
  1499. break;
  1500. }
  1501. m_healingBeamPipeline->render_single_beam(
  1502. beam.start_pos, beam.end_pos, beam.color, beam.progress,
  1503. beam.beam_width, beam.intensity, beam.time, view_proj);
  1504. m_lastBoundShader = nullptr;
  1505. break;
  1506. }
  1507. case HealerAuraCmdIndex: {
  1508. const auto &aura = std::get<HealerAuraCmdIndex>(cmd);
  1509. if (m_healerAuraPipeline == nullptr ||
  1510. !m_healerAuraPipeline->is_initialized()) {
  1511. break;
  1512. }
  1513. m_healerAuraPipeline->render_single_aura(aura.position, aura.color,
  1514. aura.radius, aura.intensity,
  1515. aura.time, view_proj);
  1516. m_lastBoundShader = nullptr;
  1517. break;
  1518. }
  1519. case CombatDustCmdIndex: {
  1520. const auto &dust = std::get<CombatDustCmdIndex>(cmd);
  1521. if (m_combatDustPipeline == nullptr ||
  1522. !m_combatDustPipeline->is_initialized()) {
  1523. break;
  1524. }
  1525. m_combatDustPipeline->render_single_dust(dust.position, dust.color,
  1526. dust.radius, dust.intensity,
  1527. dust.time, view_proj);
  1528. m_lastBoundShader = nullptr;
  1529. break;
  1530. }
  1531. case BuildingFlameCmdIndex: {
  1532. const auto &flame = std::get<BuildingFlameCmdIndex>(cmd);
  1533. if (m_combatDustPipeline == nullptr ||
  1534. !m_combatDustPipeline->is_initialized()) {
  1535. break;
  1536. }
  1537. m_combatDustPipeline->render_single_flame(flame.position, flame.color,
  1538. flame.radius, flame.intensity,
  1539. flame.time, view_proj);
  1540. m_lastBoundShader = nullptr;
  1541. break;
  1542. }
  1543. case StoneImpactCmdIndex: {
  1544. const auto &impact = std::get<StoneImpactCmdIndex>(cmd);
  1545. if (m_combatDustPipeline == nullptr ||
  1546. !m_combatDustPipeline->is_initialized()) {
  1547. break;
  1548. }
  1549. m_combatDustPipeline->render_single_stone_impact(
  1550. impact.position, impact.color, impact.radius, impact.intensity,
  1551. impact.time, view_proj);
  1552. m_lastBoundShader = nullptr;
  1553. break;
  1554. }
  1555. case ModeIndicatorCmdIndex: {
  1556. const auto &mc = std::get<ModeIndicatorCmdIndex>(cmd);
  1557. if (m_modeIndicatorPipeline == nullptr ||
  1558. !m_modeIndicatorPipeline->is_initialized()) {
  1559. break;
  1560. }
  1561. Mesh *indicator_mesh = nullptr;
  1562. if (mc.mode_type == Render::Geom::k_mode_type_attack) {
  1563. indicator_mesh = Render::Geom::ModeIndicator::get_attack_mode_mesh();
  1564. } else if (mc.mode_type == Render::Geom::k_mode_type_guard) {
  1565. indicator_mesh = Render::Geom::ModeIndicator::get_guard_mode_mesh();
  1566. } else if (mc.mode_type == Render::Geom::k_mode_type_hold) {
  1567. indicator_mesh = Render::Geom::ModeIndicator::get_hold_mode_mesh();
  1568. } else if (mc.mode_type == Render::Geom::k_mode_type_patrol) {
  1569. indicator_mesh = Render::Geom::ModeIndicator::get_patrol_mode_mesh();
  1570. }
  1571. if (indicator_mesh == nullptr) {
  1572. break;
  1573. }
  1574. m_modeIndicatorPipeline->render_indicator(indicator_mesh, mc.model,
  1575. view_proj, mc.color, mc.alpha,
  1576. m_animationTime);
  1577. m_lastBoundShader = nullptr;
  1578. break;
  1579. }
  1580. default:
  1581. break;
  1582. }
  1583. ++i;
  1584. }
  1585. if (m_lastBoundShader != nullptr) {
  1586. m_lastBoundShader->release();
  1587. m_lastBoundShader = nullptr;
  1588. }
  1589. }
  1590. } // namespace Render::GL