backend.cpp 68 KB

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