backend.cpp 54 KB

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