vegetation_pipeline.cpp 19 KB

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