vegetation_pipeline.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. #include "vegetation_pipeline.h"
  2. #include "../render_constants.h"
  3. #include "gl/shader_cache.h"
  4. #include <GL/gl.h>
  5. #include <QDebug>
  6. #include <QOpenGLContext>
  7. #include <cmath>
  8. #include <cstddef>
  9. #include <cstdint>
  10. #include <qglobal.h>
  11. #include <qopenglcontext.h>
  12. #include <qopenglext.h>
  13. #include <qstringliteral.h>
  14. #include <qvectornd.h>
  15. #include <vector>
  16. namespace Render::GL::BackendPipelines {
  17. using namespace Render::GL::VertexAttrib;
  18. using namespace Render::GL::ComponentCount;
  19. using namespace Render::GL::Geometry;
  20. VegetationPipeline::VegetationPipeline(ShaderCache *shaderCache)
  21. : m_shaderCache(shaderCache) {}
  22. VegetationPipeline::~VegetationPipeline() { shutdown(); }
  23. auto VegetationPipeline::initialize() -> bool {
  24. initializeOpenGLFunctions();
  25. if (m_shaderCache == nullptr) {
  26. return false;
  27. }
  28. m_stoneShader = m_shaderCache->get(QStringLiteral("stone_instanced"));
  29. m_plantShader = m_shaderCache->get(QStringLiteral("plant_instanced"));
  30. m_pineShader = m_shaderCache->get(QStringLiteral("pine_instanced"));
  31. m_firecampShader = m_shaderCache->get(QStringLiteral("firecamp"));
  32. if (m_stoneShader == nullptr) {
  33. qWarning() << "VegetationPipeline: stone shader missing";
  34. }
  35. if (m_plantShader == nullptr) {
  36. qWarning() << "VegetationPipeline: plant shader missing";
  37. }
  38. if (m_pineShader == nullptr) {
  39. qWarning() << "VegetationPipeline: pine shader missing";
  40. }
  41. if (m_firecampShader == nullptr) {
  42. qWarning() << "VegetationPipeline: firecamp shader missing";
  43. }
  44. initializeStonePipeline();
  45. initializePlantPipeline();
  46. initializePinePipeline();
  47. initializeFireCampPipeline();
  48. cacheUniforms();
  49. m_initialized = true;
  50. return true;
  51. }
  52. void VegetationPipeline::shutdown() {
  53. shutdownStonePipeline();
  54. shutdownPlantPipeline();
  55. shutdownPinePipeline();
  56. shutdownFireCampPipeline();
  57. m_initialized = false;
  58. }
  59. void VegetationPipeline::cacheUniforms() {
  60. if (m_stoneShader != nullptr) {
  61. m_stoneUniforms.view_proj = m_stoneShader->uniformHandle("uViewProj");
  62. m_stoneUniforms.light_direction =
  63. m_stoneShader->uniformHandle("uLightDirection");
  64. }
  65. if (m_plantShader != nullptr) {
  66. m_plantUniforms.view_proj = m_plantShader->uniformHandle("uViewProj");
  67. m_plantUniforms.time = m_plantShader->uniformHandle("uTime");
  68. m_plantUniforms.windStrength =
  69. m_plantShader->uniformHandle("uWindStrength");
  70. m_plantUniforms.windSpeed = m_plantShader->uniformHandle("uWindSpeed");
  71. m_plantUniforms.light_direction =
  72. m_plantShader->uniformHandle("uLightDirection");
  73. }
  74. if (m_pineShader != nullptr) {
  75. m_pineUniforms.view_proj = m_pineShader->uniformHandle("uViewProj");
  76. m_pineUniforms.time = m_pineShader->uniformHandle("uTime");
  77. m_pineUniforms.windStrength = m_pineShader->uniformHandle("uWindStrength");
  78. m_pineUniforms.windSpeed = m_pineShader->uniformHandle("uWindSpeed");
  79. m_pineUniforms.light_direction =
  80. m_pineShader->uniformHandle("uLightDirection");
  81. }
  82. if (m_firecampShader != nullptr) {
  83. m_firecampUniforms.view_proj =
  84. m_firecampShader->uniformHandle("u_viewProj");
  85. m_firecampUniforms.time = m_firecampShader->uniformHandle("u_time");
  86. m_firecampUniforms.flickerSpeed =
  87. m_firecampShader->uniformHandle("u_flickerSpeed");
  88. m_firecampUniforms.flickerAmount =
  89. m_firecampShader->uniformHandle("u_flickerAmount");
  90. m_firecampUniforms.glowStrength =
  91. m_firecampShader->uniformHandle("u_glowStrength");
  92. m_firecampUniforms.fireTexture =
  93. m_firecampShader->uniformHandle("fireTexture");
  94. m_firecampUniforms.camera_right =
  95. m_firecampShader->uniformHandle("u_cameraRight");
  96. m_firecampUniforms.camera_forward =
  97. m_firecampShader->uniformHandle("u_cameraForward");
  98. }
  99. }
  100. void VegetationPipeline::initializeStonePipeline() {
  101. initializeOpenGLFunctions();
  102. shutdownStonePipeline();
  103. struct StoneVertex {
  104. QVector3D position;
  105. QVector3D normal;
  106. };
  107. const StoneVertex stone_vertices[] = {
  108. {{-0.5F, -0.5F, 0.5F}, {0.0F, 0.0F, 1.0F}},
  109. {{0.5F, -0.5F, 0.5F}, {0.0F, 0.0F, 1.0F}},
  110. {{0.5F, 0.5F, 0.5F}, {0.0F, 0.0F, 1.0F}},
  111. {{-0.5F, 0.5F, 0.5F}, {0.0F, 0.0F, 1.0F}},
  112. {{-0.5F, -0.5F, -0.5F}, {0.0F, 0.0F, -1.0F}},
  113. {{-0.5F, 0.5F, -0.5F}, {0.0F, 0.0F, -1.0F}},
  114. {{0.5F, 0.5F, -0.5F}, {0.0F, 0.0F, -1.0F}},
  115. {{0.5F, -0.5F, -0.5F}, {0.0F, 0.0F, -1.0F}},
  116. {{-0.5F, 0.5F, -0.5F}, {0.0F, 1.0F, 0.0F}},
  117. {{-0.5F, 0.5F, 0.5F}, {0.0F, 1.0F, 0.0F}},
  118. {{0.5F, 0.5F, 0.5F}, {0.0F, 1.0F, 0.0F}},
  119. {{0.5F, 0.5F, -0.5F}, {0.0F, 1.0F, 0.0F}},
  120. {{-0.5F, -0.5F, -0.5F}, {0.0F, -1.0F, 0.0F}},
  121. {{0.5F, -0.5F, -0.5F}, {0.0F, -1.0F, 0.0F}},
  122. {{0.5F, -0.5F, 0.5F}, {0.0F, -1.0F, 0.0F}},
  123. {{-0.5F, -0.5F, 0.5F}, {0.0F, -1.0F, 0.0F}},
  124. {{0.5F, -0.5F, -0.5F}, {1.0F, 0.0F, 0.0F}},
  125. {{0.5F, 0.5F, -0.5F}, {1.0F, 0.0F, 0.0F}},
  126. {{0.5F, 0.5F, 0.5F}, {1.0F, 0.0F, 0.0F}},
  127. {{0.5F, -0.5F, 0.5F}, {1.0F, 0.0F, 0.0F}},
  128. {{-0.5F, -0.5F, -0.5F}, {-1.0F, 0.0F, 0.0F}},
  129. {{-0.5F, -0.5F, 0.5F}, {-1.0F, 0.0F, 0.0F}},
  130. {{-0.5F, 0.5F, 0.5F}, {-1.0F, 0.0F, 0.0F}},
  131. {{-0.5F, 0.5F, -0.5F}, {-1.0F, 0.0F, 0.0F}},
  132. };
  133. const uint16_t stone_indices[] = {
  134. 0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4, 8, 9, 10, 10, 11, 8,
  135. 12, 13, 14, 14, 15, 12, 16, 17, 18, 18, 19, 16, 20, 21, 22, 22, 23, 20};
  136. glGenVertexArrays(1, &m_stoneVao);
  137. glBindVertexArray(m_stoneVao);
  138. glGenBuffers(1, &m_stoneVertexBuffer);
  139. glBindBuffer(GL_ARRAY_BUFFER, m_stoneVertexBuffer);
  140. glBufferData(GL_ARRAY_BUFFER, sizeof(stone_vertices), stone_vertices,
  141. GL_STATIC_DRAW);
  142. m_stoneVertexCount = CubeVertexCount;
  143. glGenBuffers(1, &m_stoneIndexBuffer);
  144. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_stoneIndexBuffer);
  145. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(stone_indices), stone_indices,
  146. GL_STATIC_DRAW);
  147. constexpr int k_stone_index_count = 36;
  148. m_stoneIndexCount = k_stone_index_count;
  149. glEnableVertexAttribArray(Position);
  150. glVertexAttribPointer(
  151. Position, Vec3, GL_FLOAT, GL_FALSE, sizeof(StoneVertex),
  152. reinterpret_cast<void *>(offsetof(StoneVertex, position)));
  153. glEnableVertexAttribArray(Normal);
  154. glVertexAttribPointer(
  155. Normal, Vec3, GL_FLOAT, GL_FALSE, sizeof(StoneVertex),
  156. reinterpret_cast<void *>(offsetof(StoneVertex, normal)));
  157. glEnableVertexAttribArray(TexCoord);
  158. glVertexAttribDivisor(TexCoord, 1);
  159. glEnableVertexAttribArray(InstancePosition);
  160. glVertexAttribDivisor(InstancePosition, 1);
  161. glBindVertexArray(0);
  162. glBindBuffer(GL_ARRAY_BUFFER, 0);
  163. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  164. }
  165. void VegetationPipeline::shutdownStonePipeline() {
  166. if (QOpenGLContext::currentContext() == nullptr) {
  167. m_stoneVao = 0;
  168. m_stoneVertexBuffer = 0;
  169. m_stoneIndexBuffer = 0;
  170. m_stoneVertexCount = 0;
  171. m_stoneIndexCount = 0;
  172. return;
  173. }
  174. initializeOpenGLFunctions();
  175. if (m_stoneIndexBuffer != 0U) {
  176. glDeleteBuffers(1, &m_stoneIndexBuffer);
  177. m_stoneIndexBuffer = 0;
  178. }
  179. if (m_stoneVertexBuffer != 0U) {
  180. glDeleteBuffers(1, &m_stoneVertexBuffer);
  181. m_stoneVertexBuffer = 0;
  182. }
  183. if (m_stoneVao != 0U) {
  184. glDeleteVertexArrays(1, &m_stoneVao);
  185. m_stoneVao = 0;
  186. }
  187. m_stoneVertexCount = 0;
  188. m_stoneIndexCount = 0;
  189. }
  190. void VegetationPipeline::initializePlantPipeline() {
  191. initializeOpenGLFunctions();
  192. shutdownPlantPipeline();
  193. struct PlantVertex {
  194. QVector3D position;
  195. QVector2D tex_coord;
  196. QVector3D normal;
  197. };
  198. const PlantVertex plant_vertices[] = {
  199. {{-0.5F, 0.0F, 0.0F}, {0.0F, 0.0F}, {0.0F, 0.0F, 1.0F}},
  200. {{0.5F, 0.0F, 0.0F}, {1.0F, 0.0F}, {0.0F, 0.0F, 1.0F}},
  201. {{0.5F, 1.0F, 0.0F}, {1.0F, 1.0F}, {0.0F, 0.0F, 1.0F}},
  202. {{-0.5F, 1.0F, 0.0F}, {0.0F, 1.0F}, {0.0F, 0.0F, 1.0F}},
  203. {{0.5F, 0.0F, 0.0F}, {0.0F, 0.0F}, {0.0F, 0.0F, -1.0F}},
  204. {{-0.5F, 0.0F, 0.0F}, {1.0F, 0.0F}, {0.0F, 0.0F, -1.0F}},
  205. {{-0.5F, 1.0F, 0.0F}, {1.0F, 1.0F}, {0.0F, 0.0F, -1.0F}},
  206. {{0.5F, 1.0F, 0.0F}, {0.0F, 1.0F}, {0.0F, 0.0F, -1.0F}},
  207. {{0.0F, 0.0F, -0.5F}, {0.0F, 0.0F}, {1.0F, 0.0F, 0.0F}},
  208. {{0.0F, 0.0F, 0.5F}, {1.0F, 0.0F}, {1.0F, 0.0F, 0.0F}},
  209. {{0.0F, 1.0F, 0.5F}, {1.0F, 1.0F}, {1.0F, 0.0F, 0.0F}},
  210. {{0.0F, 1.0F, -0.5F}, {0.0F, 1.0F}, {1.0F, 0.0F, 0.0F}},
  211. {{0.0F, 0.0F, 0.5F}, {0.0F, 0.0F}, {-1.0F, 0.0F, 0.0F}},
  212. {{0.0F, 0.0F, -0.5F}, {1.0F, 0.0F}, {-1.0F, 0.0F, 0.0F}},
  213. {{0.0F, 1.0F, -0.5F}, {1.0F, 1.0F}, {-1.0F, 0.0F, 0.0F}},
  214. {{0.0F, 1.0F, 0.5F}, {0.0F, 1.0F}, {-1.0F, 0.0F, 0.0F}},
  215. };
  216. const unsigned short plant_indices[] = {
  217. 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7,
  218. 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15,
  219. };
  220. glGenVertexArrays(1, &m_plantVao);
  221. glBindVertexArray(m_plantVao);
  222. glGenBuffers(1, &m_plantVertexBuffer);
  223. glBindBuffer(GL_ARRAY_BUFFER, m_plantVertexBuffer);
  224. glBufferData(GL_ARRAY_BUFFER, sizeof(plant_vertices), plant_vertices,
  225. GL_STATIC_DRAW);
  226. m_plantVertexCount = PlantCrossQuadVertexCount;
  227. glEnableVertexAttribArray(Position);
  228. glVertexAttribPointer(
  229. Position, Vec3, GL_FLOAT, GL_FALSE, sizeof(PlantVertex),
  230. reinterpret_cast<void *>(offsetof(PlantVertex, position)));
  231. glEnableVertexAttribArray(Normal);
  232. glVertexAttribPointer(
  233. Normal, Vec2, GL_FLOAT, GL_FALSE, sizeof(PlantVertex),
  234. reinterpret_cast<void *>(offsetof(PlantVertex, tex_coord)));
  235. glEnableVertexAttribArray(TexCoord);
  236. glVertexAttribPointer(
  237. TexCoord, Vec3, GL_FLOAT, GL_FALSE, sizeof(PlantVertex),
  238. reinterpret_cast<void *>(offsetof(PlantVertex, normal)));
  239. glGenBuffers(1, &m_plantIndexBuffer);
  240. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_plantIndexBuffer);
  241. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(plant_indices), plant_indices,
  242. GL_STATIC_DRAW);
  243. m_plantIndexCount = PlantCrossQuadIndexCount;
  244. glEnableVertexAttribArray(InstancePosition);
  245. glVertexAttribDivisor(InstancePosition, 1);
  246. glEnableVertexAttribArray(InstanceScale);
  247. glVertexAttribDivisor(InstanceScale, 1);
  248. glEnableVertexAttribArray(InstanceColor);
  249. glVertexAttribDivisor(InstanceColor, 1);
  250. glBindVertexArray(0);
  251. glBindBuffer(GL_ARRAY_BUFFER, 0);
  252. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  253. }
  254. void VegetationPipeline::shutdownPlantPipeline() {
  255. if (QOpenGLContext::currentContext() == nullptr) {
  256. m_plantVao = 0;
  257. m_plantVertexBuffer = 0;
  258. m_plantIndexBuffer = 0;
  259. m_plantVertexCount = 0;
  260. m_plantIndexCount = 0;
  261. return;
  262. }
  263. initializeOpenGLFunctions();
  264. if (m_plantIndexBuffer != 0U) {
  265. glDeleteBuffers(1, &m_plantIndexBuffer);
  266. m_plantIndexBuffer = 0;
  267. }
  268. if (m_plantVertexBuffer != 0U) {
  269. glDeleteBuffers(1, &m_plantVertexBuffer);
  270. m_plantVertexBuffer = 0;
  271. }
  272. if (m_plantVao != 0U) {
  273. glDeleteVertexArrays(1, &m_plantVao);
  274. m_plantVao = 0;
  275. }
  276. m_plantVertexCount = 0;
  277. m_plantIndexCount = 0;
  278. }
  279. void VegetationPipeline::initializePinePipeline() {
  280. initializeOpenGLFunctions();
  281. shutdownPinePipeline();
  282. struct PineVertex {
  283. QVector3D position;
  284. QVector2D tex_coord;
  285. QVector3D normal;
  286. };
  287. constexpr int k_segments = PineTreeSegments;
  288. constexpr float k_two_pi = 6.28318530718F;
  289. std::vector<PineVertex> vertices;
  290. vertices.reserve(k_segments * 5 + 1);
  291. std::vector<unsigned short> indices;
  292. indices.reserve(k_segments * 6 * 4 + k_segments * 3);
  293. auto add_ring = [&](float radius, float y, float normalUp,
  294. float v_coord) -> int {
  295. const int start = static_cast<int>(vertices.size());
  296. for (int i = 0; i < k_segments; ++i) {
  297. const float t = static_cast<float>(i) / static_cast<float>(k_segments);
  298. const float angle = t * k_two_pi;
  299. const float nx = std::cos(angle);
  300. const float nz = std::sin(angle);
  301. QVector3D normal(nx, normalUp, nz);
  302. normal.normalize();
  303. QVector3D const position(radius * nx, y, radius * nz);
  304. QVector2D const tex_coord(t, v_coord);
  305. vertices.push_back({position, tex_coord, normal});
  306. }
  307. return start;
  308. };
  309. auto connect_rings = [&](int lowerStart, int upperStart) {
  310. for (int i = 0; i < k_segments; ++i) {
  311. const int next = (i + 1) % k_segments;
  312. const auto lower0 = static_cast<unsigned short>(lowerStart + i);
  313. const auto lower1 = static_cast<unsigned short>(lowerStart + next);
  314. const auto upper0 = static_cast<unsigned short>(upperStart + i);
  315. const auto upper1 = static_cast<unsigned short>(upperStart + next);
  316. indices.push_back(lower0);
  317. indices.push_back(lower1);
  318. indices.push_back(upper1);
  319. indices.push_back(lower0);
  320. indices.push_back(upper1);
  321. indices.push_back(upper0);
  322. }
  323. };
  324. const int trunk_bottom = add_ring(0.12F, 0.0F, 0.0F, 0.0F);
  325. const int trunk_mid = add_ring(0.11F, 0.35F, 0.0F, 0.12F);
  326. const int trunk_top = add_ring(0.10F, 0.58F, 0.05F, 0.30F);
  327. const int branch_base = add_ring(0.60F, 0.64F, 0.35F, 0.46F);
  328. const int branch_mid = add_ring(0.42F, 0.82F, 0.6F, 0.68F);
  329. const int branch_upper = add_ring(0.24F, 1.00F, 0.7F, 0.88F);
  330. const int branch_tip = add_ring(0.12F, 1.10F, 0.85F, 0.96F);
  331. connect_rings(trunk_bottom, trunk_mid);
  332. connect_rings(trunk_mid, trunk_top);
  333. connect_rings(trunk_top, branch_base);
  334. connect_rings(branch_base, branch_mid);
  335. connect_rings(branch_mid, branch_upper);
  336. connect_rings(branch_upper, branch_tip);
  337. const auto trunk_cap_index = static_cast<unsigned short>(vertices.size());
  338. vertices.push_back({QVector3D(0.0F, 0.0F, 0.0F), QVector2D(0.5F, 0.0F),
  339. QVector3D(0.0F, -1.0F, 0.0F)});
  340. for (int i = 0; i < k_segments; ++i) {
  341. const int next = (i + 1) % k_segments;
  342. indices.push_back(static_cast<unsigned short>(trunk_bottom + next));
  343. indices.push_back(static_cast<unsigned short>(trunk_bottom + i));
  344. indices.push_back(trunk_cap_index);
  345. }
  346. const auto apex_index = static_cast<unsigned short>(vertices.size());
  347. vertices.push_back({QVector3D(0.0F, 1.18F, 0.0F), QVector2D(0.5F, 1.0F),
  348. QVector3D(0.0F, 1.0F, 0.0F)});
  349. for (int i = 0; i < k_segments; ++i) {
  350. const int next = (i + 1) % k_segments;
  351. indices.push_back(static_cast<unsigned short>(branch_tip + i));
  352. indices.push_back(static_cast<unsigned short>(branch_tip + next));
  353. indices.push_back(apex_index);
  354. }
  355. glGenVertexArrays(1, &m_pineVao);
  356. glBindVertexArray(m_pineVao);
  357. glGenBuffers(1, &m_pineVertexBuffer);
  358. glBindBuffer(GL_ARRAY_BUFFER, m_pineVertexBuffer);
  359. glBufferData(GL_ARRAY_BUFFER,
  360. static_cast<GLsizeiptr>(vertices.size() * sizeof(PineVertex)),
  361. vertices.data(), GL_STATIC_DRAW);
  362. m_pineVertexCount = static_cast<GLsizei>(vertices.size());
  363. glEnableVertexAttribArray(Position);
  364. glVertexAttribPointer(
  365. Position, Vec3, GL_FLOAT, GL_FALSE, sizeof(PineVertex),
  366. reinterpret_cast<void *>(offsetof(PineVertex, position)));
  367. glEnableVertexAttribArray(Normal);
  368. glVertexAttribPointer(
  369. Normal, Vec2, GL_FLOAT, GL_FALSE, sizeof(PineVertex),
  370. reinterpret_cast<void *>(offsetof(PineVertex, tex_coord)));
  371. glEnableVertexAttribArray(TexCoord);
  372. glVertexAttribPointer(TexCoord, Vec3, GL_FLOAT, GL_FALSE, sizeof(PineVertex),
  373. reinterpret_cast<void *>(offsetof(PineVertex, normal)));
  374. glGenBuffers(1, &m_pineIndexBuffer);
  375. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pineIndexBuffer);
  376. glBufferData(GL_ELEMENT_ARRAY_BUFFER,
  377. static_cast<GLsizeiptr>(indices.size() * sizeof(unsigned short)),
  378. indices.data(), GL_STATIC_DRAW);
  379. m_pineIndexCount = static_cast<GLsizei>(indices.size());
  380. glEnableVertexAttribArray(InstancePosition);
  381. glVertexAttribDivisor(InstancePosition, 1);
  382. glEnableVertexAttribArray(InstanceScale);
  383. glVertexAttribDivisor(InstanceScale, 1);
  384. glEnableVertexAttribArray(InstanceColor);
  385. glVertexAttribDivisor(InstanceColor, 1);
  386. glBindVertexArray(0);
  387. glBindBuffer(GL_ARRAY_BUFFER, 0);
  388. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  389. }
  390. void VegetationPipeline::shutdownPinePipeline() {
  391. if (QOpenGLContext::currentContext() == nullptr) {
  392. m_pineVao = 0;
  393. m_pineVertexBuffer = 0;
  394. m_pineIndexBuffer = 0;
  395. m_pineVertexCount = 0;
  396. m_pineIndexCount = 0;
  397. return;
  398. }
  399. initializeOpenGLFunctions();
  400. if (m_pineIndexBuffer != 0U) {
  401. glDeleteBuffers(1, &m_pineIndexBuffer);
  402. m_pineIndexBuffer = 0;
  403. }
  404. if (m_pineVertexBuffer != 0U) {
  405. glDeleteBuffers(1, &m_pineVertexBuffer);
  406. m_pineVertexBuffer = 0;
  407. }
  408. if (m_pineVao != 0U) {
  409. glDeleteVertexArrays(1, &m_pineVao);
  410. m_pineVao = 0;
  411. }
  412. m_pineVertexCount = 0;
  413. m_pineIndexCount = 0;
  414. }
  415. void VegetationPipeline::initializeFireCampPipeline() {
  416. initializeOpenGLFunctions();
  417. shutdownFireCampPipeline();
  418. struct FireCampVertex {
  419. QVector3D position;
  420. QVector2D tex_coord;
  421. };
  422. constexpr std::size_t k_firecamp_vertex_reserve = 12;
  423. constexpr std::size_t k_firecamp_index_reserve = 18;
  424. std::vector<FireCampVertex> vertices;
  425. vertices.reserve(k_firecamp_vertex_reserve);
  426. std::vector<unsigned short> indices;
  427. indices.reserve(k_firecamp_index_reserve);
  428. auto append_plane = [&](float planeIndex) {
  429. auto const base = static_cast<unsigned short>(vertices.size());
  430. vertices.push_back(
  431. {QVector3D(-1.0F, 0.0F, planeIndex), QVector2D(0.0F, 0.0F)});
  432. vertices.push_back(
  433. {QVector3D(1.0F, 0.0F, planeIndex), QVector2D(1.0F, 0.0F)});
  434. vertices.push_back(
  435. {QVector3D(1.0F, 2.0F, planeIndex), QVector2D(1.0F, 1.0F)});
  436. vertices.push_back(
  437. {QVector3D(-1.0F, 2.0F, planeIndex), QVector2D(0.0F, 1.0F)});
  438. indices.push_back(base + 0);
  439. indices.push_back(base + 1);
  440. indices.push_back(base + 2);
  441. indices.push_back(base + 0);
  442. indices.push_back(base + 2);
  443. indices.push_back(base + 3);
  444. };
  445. append_plane(0.0F);
  446. append_plane(1.0F);
  447. append_plane(2.0F);
  448. glGenVertexArrays(1, &m_firecampVao);
  449. glBindVertexArray(m_firecampVao);
  450. glGenBuffers(1, &m_firecampVertexBuffer);
  451. glBindBuffer(GL_ARRAY_BUFFER, m_firecampVertexBuffer);
  452. glBufferData(
  453. GL_ARRAY_BUFFER,
  454. static_cast<GLsizeiptr>(vertices.size() * sizeof(FireCampVertex)),
  455. vertices.data(), GL_STATIC_DRAW);
  456. m_firecampVertexCount = static_cast<GLsizei>(vertices.size());
  457. glEnableVertexAttribArray(Position);
  458. glVertexAttribPointer(Position, Vec3, GL_FLOAT, GL_FALSE,
  459. sizeof(FireCampVertex), reinterpret_cast<void *>(0));
  460. glEnableVertexAttribArray(Normal);
  461. glVertexAttribPointer(
  462. Normal, Vec2, GL_FLOAT, GL_FALSE, sizeof(FireCampVertex),
  463. reinterpret_cast<void *>(offsetof(FireCampVertex, tex_coord)));
  464. glGenBuffers(1, &m_firecampIndexBuffer);
  465. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_firecampIndexBuffer);
  466. glBufferData(GL_ELEMENT_ARRAY_BUFFER,
  467. static_cast<GLsizeiptr>(indices.size() * sizeof(unsigned short)),
  468. indices.data(), GL_STATIC_DRAW);
  469. m_firecampIndexCount = static_cast<GLsizei>(indices.size());
  470. glEnableVertexAttribArray(InstancePosition);
  471. glVertexAttribDivisor(InstancePosition, 1);
  472. glEnableVertexAttribArray(InstanceScale);
  473. glVertexAttribDivisor(InstanceScale, 1);
  474. glBindVertexArray(0);
  475. glBindBuffer(GL_ARRAY_BUFFER, 0);
  476. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  477. }
  478. void VegetationPipeline::shutdownFireCampPipeline() {
  479. if (QOpenGLContext::currentContext() == nullptr) {
  480. m_firecampVao = 0;
  481. m_firecampVertexBuffer = 0;
  482. m_firecampIndexBuffer = 0;
  483. m_firecampVertexCount = 0;
  484. m_firecampIndexCount = 0;
  485. return;
  486. }
  487. initializeOpenGLFunctions();
  488. if (m_firecampIndexBuffer != 0U) {
  489. glDeleteBuffers(1, &m_firecampIndexBuffer);
  490. m_firecampIndexBuffer = 0;
  491. }
  492. if (m_firecampVertexBuffer != 0U) {
  493. glDeleteBuffers(1, &m_firecampVertexBuffer);
  494. m_firecampVertexBuffer = 0;
  495. }
  496. if (m_firecampVao != 0U) {
  497. glDeleteVertexArrays(1, &m_firecampVao);
  498. m_firecampVao = 0;
  499. }
  500. m_firecampVertexCount = 0;
  501. m_firecampIndexCount = 0;
  502. }
  503. } // namespace Render::GL::BackendPipelines