backend.cpp 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747
  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 =
  1331. m_characterPipeline
  1332. ? m_characterPipeline->resolve_uniforms(active_shader)
  1333. : nullptr;
  1334. if (uniforms == nullptr) {
  1335. break;
  1336. }
  1337. if (m_lastBoundShader != active_shader) {
  1338. active_shader->use();
  1339. m_lastBoundShader = active_shader;
  1340. }
  1341. active_shader->set_uniform(uniforms->mvp, it.mvp);
  1342. active_shader->set_uniform(uniforms->model, it.model);
  1343. Texture *tex_to_use =
  1344. (it.texture != nullptr)
  1345. ? it.texture
  1346. : (m_resources ? m_resources->white() : nullptr);
  1347. if ((tex_to_use != nullptr) && tex_to_use != m_lastBoundTexture) {
  1348. tex_to_use->bind(0);
  1349. m_lastBoundTexture = tex_to_use;
  1350. active_shader->set_uniform(uniforms->texture, 0);
  1351. }
  1352. active_shader->set_uniform(uniforms->use_texture, it.texture != nullptr);
  1353. active_shader->set_uniform(uniforms->color, it.color);
  1354. active_shader->set_uniform(uniforms->alpha, it.alpha);
  1355. active_shader->set_uniform(uniforms->material_id, it.material_id);
  1356. it.mesh->draw();
  1357. if (isTransparent) {
  1358. glDepthFunc(static_cast<GLenum>(prev_depth_func));
  1359. }
  1360. break;
  1361. }
  1362. case GridCmdIndex: {
  1363. if (m_effectsPipeline->m_gridShader == nullptr) {
  1364. break;
  1365. }
  1366. const auto &gc = std::get<GridCmdIndex>(cmd);
  1367. if (m_lastBoundShader != m_effectsPipeline->m_gridShader) {
  1368. m_effectsPipeline->m_gridShader->use();
  1369. m_lastBoundShader = m_effectsPipeline->m_gridShader;
  1370. }
  1371. m_effectsPipeline->m_gridShader->set_uniform(
  1372. m_effectsPipeline->m_gridUniforms.mvp, gc.mvp);
  1373. m_effectsPipeline->m_gridShader->set_uniform(
  1374. m_effectsPipeline->m_gridUniforms.model, gc.model);
  1375. m_effectsPipeline->m_gridShader->set_uniform(
  1376. m_effectsPipeline->m_gridUniforms.gridColor, gc.color);
  1377. m_effectsPipeline->m_gridShader->set_uniform(
  1378. m_effectsPipeline->m_gridUniforms.lineColor, k_grid_line_color);
  1379. m_effectsPipeline->m_gridShader->set_uniform(
  1380. m_effectsPipeline->m_gridUniforms.cellSize, gc.cell_size);
  1381. m_effectsPipeline->m_gridShader->set_uniform(
  1382. m_effectsPipeline->m_gridUniforms.thickness, gc.thickness);
  1383. if (m_resources) {
  1384. if (auto *plane = m_resources->ground()) {
  1385. plane->draw();
  1386. }
  1387. }
  1388. break;
  1389. }
  1390. case SelectionRingCmdIndex: {
  1391. const auto &sc = std::get<SelectionRingCmdIndex>(cmd);
  1392. Mesh *ring = Render::Geom::SelectionRing::get();
  1393. if (ring == nullptr) {
  1394. break;
  1395. }
  1396. if (m_lastBoundShader != m_effectsPipeline->m_basicShader) {
  1397. m_effectsPipeline->m_basicShader->use();
  1398. m_lastBoundShader = m_effectsPipeline->m_basicShader;
  1399. }
  1400. m_effectsPipeline->m_basicShader->use();
  1401. m_effectsPipeline->m_basicShader->set_uniform(
  1402. m_effectsPipeline->m_basicUniforms.useTexture, false);
  1403. m_effectsPipeline->m_basicShader->set_uniform(
  1404. m_effectsPipeline->m_basicUniforms.color, sc.color);
  1405. DepthMaskScope const depth_mask(false);
  1406. PolygonOffsetScope const poly(-1.0F, -1.0F);
  1407. BlendScope const blend(true);
  1408. {
  1409. QMatrix4x4 m = sc.model;
  1410. m.scale(1.08F, 1.0F, 1.08F);
  1411. const QMatrix4x4 mvp = view_proj * m;
  1412. m_effectsPipeline->m_basicShader->set_uniform(
  1413. m_effectsPipeline->m_basicUniforms.mvp, mvp);
  1414. m_effectsPipeline->m_basicShader->set_uniform(
  1415. m_effectsPipeline->m_basicUniforms.model, m);
  1416. m_effectsPipeline->m_basicShader->set_uniform(
  1417. m_effectsPipeline->m_basicUniforms.alpha, sc.alpha_outer);
  1418. ring->draw();
  1419. }
  1420. {
  1421. const QMatrix4x4 mvp = view_proj * sc.model;
  1422. m_effectsPipeline->m_basicShader->set_uniform(
  1423. m_effectsPipeline->m_basicUniforms.mvp, mvp);
  1424. m_effectsPipeline->m_basicShader->set_uniform(
  1425. m_effectsPipeline->m_basicUniforms.model, sc.model);
  1426. m_effectsPipeline->m_basicShader->set_uniform(
  1427. m_effectsPipeline->m_basicUniforms.alpha, sc.alpha_inner);
  1428. ring->draw();
  1429. }
  1430. break;
  1431. }
  1432. case SelectionSmokeCmdIndex: {
  1433. const auto &sm = std::get<SelectionSmokeCmdIndex>(cmd);
  1434. Mesh *disc = Render::Geom::SelectionDisc::get();
  1435. if (disc == nullptr) {
  1436. break;
  1437. }
  1438. if (m_lastBoundShader != m_effectsPipeline->m_basicShader) {
  1439. m_effectsPipeline->m_basicShader->use();
  1440. m_lastBoundShader = m_effectsPipeline->m_basicShader;
  1441. }
  1442. m_effectsPipeline->m_basicShader->set_uniform(
  1443. m_effectsPipeline->m_basicUniforms.useTexture, false);
  1444. m_effectsPipeline->m_basicShader->set_uniform(
  1445. m_effectsPipeline->m_basicUniforms.color, sm.color);
  1446. DepthMaskScope const depth_mask(false);
  1447. DepthTestScope const depth_test(true);
  1448. PolygonOffsetScope const poly(-1.0F, -1.0F);
  1449. BlendScope const blend(true);
  1450. for (int i = 0; i < 7; ++i) {
  1451. float const scale = 1.35F + 0.12F * i;
  1452. float const a = sm.base_alpha * (1.0F - 0.09F * i);
  1453. QMatrix4x4 m = sm.model;
  1454. m.translate(0.0F, 0.02F, 0.0F);
  1455. m.scale(scale, 1.0F, scale);
  1456. const QMatrix4x4 mvp = view_proj * m;
  1457. m_effectsPipeline->m_basicShader->set_uniform(
  1458. m_effectsPipeline->m_basicUniforms.mvp, mvp);
  1459. m_effectsPipeline->m_basicShader->set_uniform(
  1460. m_effectsPipeline->m_basicUniforms.model, m);
  1461. m_effectsPipeline->m_basicShader->set_uniform(
  1462. m_effectsPipeline->m_basicUniforms.alpha, a);
  1463. disc->draw();
  1464. }
  1465. break;
  1466. }
  1467. case PrimitiveBatchCmdIndex: {
  1468. const auto &batch = std::get<PrimitiveBatchCmdIndex>(cmd);
  1469. if (batch.instance_count() == 0 || m_primitiveBatchPipeline == nullptr ||
  1470. !m_primitiveBatchPipeline->is_initialized()) {
  1471. break;
  1472. }
  1473. const auto *data = batch.instance_data();
  1474. switch (batch.type) {
  1475. case PrimitiveType::Sphere:
  1476. m_primitiveBatchPipeline->upload_sphere_instances(
  1477. data, batch.instance_count());
  1478. m_primitiveBatchPipeline->draw_spheres(batch.instance_count(),
  1479. view_proj);
  1480. break;
  1481. case PrimitiveType::Cylinder:
  1482. m_primitiveBatchPipeline->upload_cylinder_instances(
  1483. data, batch.instance_count());
  1484. m_primitiveBatchPipeline->draw_cylinders(batch.instance_count(),
  1485. view_proj);
  1486. break;
  1487. case PrimitiveType::Cone:
  1488. m_primitiveBatchPipeline->upload_cone_instances(data,
  1489. batch.instance_count());
  1490. m_primitiveBatchPipeline->draw_cones(batch.instance_count(), view_proj);
  1491. break;
  1492. }
  1493. m_lastBoundShader = m_primitiveBatchPipeline->shader();
  1494. break;
  1495. }
  1496. case HealingBeamCmdIndex: {
  1497. const auto &beam = std::get<HealingBeamCmdIndex>(cmd);
  1498. if (m_healingBeamPipeline == nullptr ||
  1499. !m_healingBeamPipeline->is_initialized()) {
  1500. break;
  1501. }
  1502. m_healingBeamPipeline->render_single_beam(
  1503. beam.start_pos, beam.end_pos, beam.color, beam.progress,
  1504. beam.beam_width, beam.intensity, beam.time, view_proj);
  1505. m_lastBoundShader = nullptr;
  1506. break;
  1507. }
  1508. case HealerAuraCmdIndex: {
  1509. const auto &aura = std::get<HealerAuraCmdIndex>(cmd);
  1510. if (m_healerAuraPipeline == nullptr ||
  1511. !m_healerAuraPipeline->is_initialized()) {
  1512. break;
  1513. }
  1514. m_healerAuraPipeline->render_single_aura(aura.position, aura.color,
  1515. aura.radius, aura.intensity,
  1516. aura.time, view_proj);
  1517. m_lastBoundShader = nullptr;
  1518. break;
  1519. }
  1520. case CombatDustCmdIndex: {
  1521. const auto &dust = std::get<CombatDustCmdIndex>(cmd);
  1522. if (m_combatDustPipeline == nullptr ||
  1523. !m_combatDustPipeline->is_initialized()) {
  1524. break;
  1525. }
  1526. m_combatDustPipeline->render_single_dust(dust.position, dust.color,
  1527. dust.radius, dust.intensity,
  1528. dust.time, view_proj);
  1529. m_lastBoundShader = nullptr;
  1530. break;
  1531. }
  1532. case BuildingFlameCmdIndex: {
  1533. const auto &flame = std::get<BuildingFlameCmdIndex>(cmd);
  1534. if (m_combatDustPipeline == nullptr ||
  1535. !m_combatDustPipeline->is_initialized()) {
  1536. break;
  1537. }
  1538. m_combatDustPipeline->render_single_flame(flame.position, flame.color,
  1539. flame.radius, flame.intensity,
  1540. flame.time, view_proj);
  1541. m_lastBoundShader = nullptr;
  1542. break;
  1543. }
  1544. case StoneImpactCmdIndex: {
  1545. const auto &impact = std::get<StoneImpactCmdIndex>(cmd);
  1546. if (m_combatDustPipeline == nullptr ||
  1547. !m_combatDustPipeline->is_initialized()) {
  1548. break;
  1549. }
  1550. m_combatDustPipeline->render_single_stone_impact(
  1551. impact.position, impact.color, impact.radius, impact.intensity,
  1552. impact.time, view_proj);
  1553. m_lastBoundShader = nullptr;
  1554. break;
  1555. }
  1556. case ModeIndicatorCmdIndex: {
  1557. const auto &mc = std::get<ModeIndicatorCmdIndex>(cmd);
  1558. if (m_modeIndicatorPipeline == nullptr ||
  1559. !m_modeIndicatorPipeline->is_initialized()) {
  1560. break;
  1561. }
  1562. Mesh *indicator_mesh = nullptr;
  1563. if (mc.mode_type == Render::Geom::k_mode_type_attack) {
  1564. indicator_mesh = Render::Geom::ModeIndicator::get_attack_mode_mesh();
  1565. } else if (mc.mode_type == Render::Geom::k_mode_type_guard) {
  1566. indicator_mesh = Render::Geom::ModeIndicator::get_guard_mode_mesh();
  1567. } else if (mc.mode_type == Render::Geom::k_mode_type_hold) {
  1568. indicator_mesh = Render::Geom::ModeIndicator::get_hold_mode_mesh();
  1569. } else if (mc.mode_type == Render::Geom::k_mode_type_patrol) {
  1570. indicator_mesh = Render::Geom::ModeIndicator::get_patrol_mode_mesh();
  1571. }
  1572. if (indicator_mesh == nullptr) {
  1573. break;
  1574. }
  1575. m_modeIndicatorPipeline->render_indicator(indicator_mesh, mc.model,
  1576. view_proj, mc.color, mc.alpha,
  1577. m_animationTime);
  1578. m_lastBoundShader = nullptr;
  1579. break;
  1580. }
  1581. default:
  1582. break;
  1583. }
  1584. ++i;
  1585. }
  1586. if (m_lastBoundShader != nullptr) {
  1587. m_lastBoundShader->release();
  1588. m_lastBoundShader = nullptr;
  1589. }
  1590. }
  1591. } // namespace Render::GL