draw_queue.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. #pragma once
  2. #include "ground/firecamp_gpu.h"
  3. #include "ground/grass_gpu.h"
  4. #include "ground/olive_gpu.h"
  5. #include "ground/pine_gpu.h"
  6. #include "ground/plant_gpu.h"
  7. #include "ground/rain_gpu.h"
  8. #include "ground/stone_gpu.h"
  9. #include "ground/terrain_gpu.h"
  10. #include "primitive_batch.h"
  11. #include <QMatrix4x4>
  12. #include <QVector3D>
  13. #include <algorithm>
  14. #include <cstddef>
  15. #include <cstdint>
  16. #include <variant>
  17. #include <vector>
  18. namespace Render::GL {
  19. class Mesh;
  20. class Texture;
  21. class Buffer;
  22. class Shader;
  23. } // namespace Render::GL
  24. namespace Render::GL {
  25. constexpr int k_sort_key_bucket_shift = 56;
  26. constexpr float k_opaque_threshold = 0.999F;
  27. struct MeshCmd {
  28. Mesh *mesh = nullptr;
  29. Texture *texture = nullptr;
  30. QMatrix4x4 model;
  31. QMatrix4x4 mvp;
  32. QVector3D color{1, 1, 1};
  33. float alpha = 1.0F;
  34. int material_id = 0;
  35. class Shader *shader = nullptr;
  36. };
  37. struct CylinderCmd {
  38. QVector3D start{0.0F, -0.5F, 0.0F};
  39. QVector3D end{0.0F, 0.5F, 0.0F};
  40. QVector3D color{1.0F, 1.0F, 1.0F};
  41. float radius = 1.0F;
  42. float alpha = 1.0F;
  43. };
  44. struct FogInstanceData {
  45. QVector3D center{0.0F, 0.25F, 0.0F};
  46. QVector3D color{0.05F, 0.05F, 0.05F};
  47. float alpha = 1.0F;
  48. float size = 1.0F;
  49. };
  50. struct FogBatchCmd {
  51. const FogInstanceData *instances = nullptr;
  52. std::size_t count = 0;
  53. };
  54. struct GrassBatchCmd {
  55. Buffer *instance_buffer = nullptr;
  56. std::size_t instance_count = 0;
  57. GrassBatchParams params;
  58. };
  59. struct StoneBatchCmd {
  60. Buffer *instance_buffer = nullptr;
  61. std::size_t instance_count = 0;
  62. StoneBatchParams params;
  63. };
  64. struct PlantBatchCmd {
  65. Buffer *instance_buffer = nullptr;
  66. std::size_t instance_count = 0;
  67. PlantBatchParams params;
  68. };
  69. struct PineBatchCmd {
  70. Buffer *instance_buffer = nullptr;
  71. std::size_t instance_count = 0;
  72. PineBatchParams params;
  73. };
  74. struct OliveBatchCmd {
  75. Buffer *instance_buffer = nullptr;
  76. std::size_t instance_count = 0;
  77. OliveBatchParams params;
  78. };
  79. struct FireCampBatchCmd {
  80. Buffer *instance_buffer = nullptr;
  81. std::size_t instance_count = 0;
  82. FireCampBatchParams params;
  83. };
  84. struct RainBatchCmd {
  85. Buffer *instance_buffer = nullptr;
  86. std::size_t instance_count = 0;
  87. RainBatchParams params;
  88. };
  89. struct TerrainChunkCmd {
  90. Mesh *mesh = nullptr;
  91. QMatrix4x4 model;
  92. TerrainChunkParams params;
  93. std::uint16_t sort_key = 0x8000U;
  94. bool depth_write = true;
  95. float depth_bias = 0.0F;
  96. };
  97. struct GridCmd {
  98. QMatrix4x4 model;
  99. QMatrix4x4 mvp;
  100. QVector3D color{0.2F, 0.25F, 0.2F};
  101. float cell_size = 1.0F;
  102. float thickness = 0.06F;
  103. float extent = 50.0F;
  104. };
  105. struct SelectionRingCmd {
  106. QMatrix4x4 model;
  107. QMatrix4x4 mvp;
  108. QVector3D color{0, 0, 0};
  109. float alpha_inner = 0.6F;
  110. float alpha_outer = 0.25F;
  111. };
  112. struct SelectionSmokeCmd {
  113. QMatrix4x4 model;
  114. QMatrix4x4 mvp;
  115. QVector3D color{1, 1, 1};
  116. float base_alpha = 0.15F;
  117. };
  118. struct HealingBeamCmd {
  119. QVector3D start_pos{0, 0, 0};
  120. QVector3D end_pos{0, 0, 0};
  121. QVector3D color{0.4F, 1.0F, 0.5F};
  122. float progress = 1.0F;
  123. float beam_width = 0.15F;
  124. float intensity = 1.0F;
  125. float time = 0.0F;
  126. };
  127. struct HealerAuraCmd {
  128. QVector3D position{0, 0, 0};
  129. QVector3D color{0.4F, 1.0F, 0.5F};
  130. float radius = 5.0F;
  131. float intensity = 1.0F;
  132. float time = 0.0F;
  133. };
  134. struct CombatDustCmd {
  135. QVector3D position{0, 0, 0};
  136. QVector3D color{0.6F, 0.55F, 0.45F};
  137. float radius = 2.0F;
  138. float intensity = 0.7F;
  139. float time = 0.0F;
  140. };
  141. struct BuildingFlameCmd {
  142. QVector3D position{0, 0, 0};
  143. QVector3D color{1.0F, 0.4F, 0.1F};
  144. float radius = 3.0F;
  145. float intensity = 0.8F;
  146. float time = 0.0F;
  147. };
  148. struct StoneImpactCmd {
  149. QVector3D position{0, 0, 0};
  150. QVector3D color{0.75F, 0.65F, 0.50F};
  151. float radius = 4.0F;
  152. float intensity = 1.2F;
  153. float time = 0.0F;
  154. };
  155. struct ModeIndicatorCmd {
  156. QMatrix4x4 model;
  157. QMatrix4x4 mvp;
  158. QVector3D color{1.0F, 1.0F, 1.0F};
  159. float alpha = 1.0F;
  160. int mode_type = 0;
  161. };
  162. using DrawCmd =
  163. std::variant<GridCmd, SelectionRingCmd, SelectionSmokeCmd, CylinderCmd,
  164. MeshCmd, FogBatchCmd, GrassBatchCmd, StoneBatchCmd,
  165. PlantBatchCmd, PineBatchCmd, OliveBatchCmd, FireCampBatchCmd,
  166. RainBatchCmd, TerrainChunkCmd, PrimitiveBatchCmd,
  167. HealingBeamCmd, HealerAuraCmd, CombatDustCmd, BuildingFlameCmd,
  168. StoneImpactCmd, ModeIndicatorCmd>;
  169. enum class DrawCmdType : std::uint8_t {
  170. Grid = 0,
  171. SelectionRing = 1,
  172. SelectionSmoke = 2,
  173. Cylinder = 3,
  174. Mesh = 4,
  175. FogBatch = 5,
  176. GrassBatch = 6,
  177. StoneBatch = 7,
  178. PlantBatch = 8,
  179. PineBatch = 9,
  180. OliveBatch = 10,
  181. FireCampBatch = 11,
  182. RainBatch = 12,
  183. TerrainChunk = 13,
  184. PrimitiveBatch = 14,
  185. HealingBeam = 15,
  186. HealerAura = 16,
  187. CombatDust = 17,
  188. BuildingFlame = 18,
  189. StoneImpact = 19,
  190. ModeIndicator = 20
  191. };
  192. constexpr std::size_t MeshCmdIndex =
  193. static_cast<std::size_t>(DrawCmdType::Mesh);
  194. constexpr std::size_t GridCmdIndex =
  195. static_cast<std::size_t>(DrawCmdType::Grid);
  196. constexpr std::size_t SelectionRingCmdIndex =
  197. static_cast<std::size_t>(DrawCmdType::SelectionRing);
  198. constexpr std::size_t SelectionSmokeCmdIndex =
  199. static_cast<std::size_t>(DrawCmdType::SelectionSmoke);
  200. constexpr std::size_t CylinderCmdIndex =
  201. static_cast<std::size_t>(DrawCmdType::Cylinder);
  202. constexpr std::size_t FogBatchCmdIndex =
  203. static_cast<std::size_t>(DrawCmdType::FogBatch);
  204. constexpr std::size_t GrassBatchCmdIndex =
  205. static_cast<std::size_t>(DrawCmdType::GrassBatch);
  206. constexpr std::size_t StoneBatchCmdIndex =
  207. static_cast<std::size_t>(DrawCmdType::StoneBatch);
  208. constexpr std::size_t PlantBatchCmdIndex =
  209. static_cast<std::size_t>(DrawCmdType::PlantBatch);
  210. constexpr std::size_t PineBatchCmdIndex =
  211. static_cast<std::size_t>(DrawCmdType::PineBatch);
  212. constexpr std::size_t OliveBatchCmdIndex =
  213. static_cast<std::size_t>(DrawCmdType::OliveBatch);
  214. constexpr std::size_t FireCampBatchCmdIndex =
  215. static_cast<std::size_t>(DrawCmdType::FireCampBatch);
  216. constexpr std::size_t RainBatchCmdIndex =
  217. static_cast<std::size_t>(DrawCmdType::RainBatch);
  218. constexpr std::size_t TerrainChunkCmdIndex =
  219. static_cast<std::size_t>(DrawCmdType::TerrainChunk);
  220. constexpr std::size_t PrimitiveBatchCmdIndex =
  221. static_cast<std::size_t>(DrawCmdType::PrimitiveBatch);
  222. constexpr std::size_t HealingBeamCmdIndex =
  223. static_cast<std::size_t>(DrawCmdType::HealingBeam);
  224. constexpr std::size_t HealerAuraCmdIndex =
  225. static_cast<std::size_t>(DrawCmdType::HealerAura);
  226. constexpr std::size_t CombatDustCmdIndex =
  227. static_cast<std::size_t>(DrawCmdType::CombatDust);
  228. constexpr std::size_t BuildingFlameCmdIndex =
  229. static_cast<std::size_t>(DrawCmdType::BuildingFlame);
  230. constexpr std::size_t StoneImpactCmdIndex =
  231. static_cast<std::size_t>(DrawCmdType::StoneImpact);
  232. constexpr std::size_t ModeIndicatorCmdIndex =
  233. static_cast<std::size_t>(DrawCmdType::ModeIndicator);
  234. inline auto draw_cmd_type(const DrawCmd &cmd) -> DrawCmdType {
  235. return static_cast<DrawCmdType>(cmd.index());
  236. }
  237. class DrawQueue {
  238. public:
  239. void clear() { m_items.clear(); }
  240. void submit(const MeshCmd &c) { m_items.emplace_back(c); }
  241. void submit(const GridCmd &c) { m_items.emplace_back(c); }
  242. void submit(const SelectionRingCmd &c) { m_items.emplace_back(c); }
  243. void submit(const SelectionSmokeCmd &c) { m_items.emplace_back(c); }
  244. void submit(const CylinderCmd &c) { m_items.emplace_back(c); }
  245. void submit(const FogBatchCmd &c) { m_items.emplace_back(c); }
  246. void submit(const GrassBatchCmd &c) { m_items.emplace_back(c); }
  247. void submit(const StoneBatchCmd &c) { m_items.emplace_back(c); }
  248. void submit(const PlantBatchCmd &c) { m_items.emplace_back(c); }
  249. void submit(const PineBatchCmd &c) { m_items.emplace_back(c); }
  250. void submit(const OliveBatchCmd &c) { m_items.emplace_back(c); }
  251. void submit(const FireCampBatchCmd &c) { m_items.emplace_back(c); }
  252. void submit(const RainBatchCmd &c) { m_items.emplace_back(c); }
  253. void submit(const TerrainChunkCmd &c) { m_items.emplace_back(c); }
  254. void submit(const PrimitiveBatchCmd &c) { m_items.emplace_back(c); }
  255. void submit(const HealingBeamCmd &c) { m_items.emplace_back(c); }
  256. void submit(const HealerAuraCmd &c) { m_items.emplace_back(c); }
  257. void submit(const CombatDustCmd &c) { m_items.emplace_back(c); }
  258. void submit(const BuildingFlameCmd &c) { m_items.emplace_back(c); }
  259. void submit(const StoneImpactCmd &c) { m_items.emplace_back(c); }
  260. void submit(const ModeIndicatorCmd &c) { m_items.emplace_back(c); }
  261. [[nodiscard]] auto empty() const -> bool { return m_items.empty(); }
  262. [[nodiscard]] auto size() const -> std::size_t { return m_items.size(); }
  263. [[nodiscard]] auto get_sorted(std::size_t i) const -> const DrawCmd & {
  264. return m_items[m_sort_indices[i]];
  265. }
  266. [[nodiscard]] auto items() const -> const std::vector<DrawCmd> & {
  267. return m_items;
  268. }
  269. void sort_for_batching() {
  270. const std::size_t count = m_items.size();
  271. m_sort_keys.resize(count);
  272. m_sort_indices.resize(count);
  273. for (std::size_t i = 0; i < count; ++i) {
  274. m_sort_indices[i] = static_cast<uint32_t>(i);
  275. m_sort_keys[i] = compute_sort_key(m_items[i]);
  276. }
  277. if (count >= 2) {
  278. radix_sort_two_pass(count);
  279. }
  280. }
  281. [[nodiscard]] auto can_batch_mesh(std::size_t sorted_idx_a,
  282. std::size_t sorted_idx_b) const -> bool {
  283. if (sorted_idx_a >= m_items.size() || sorted_idx_b >= m_items.size()) {
  284. return false;
  285. }
  286. const auto &a = m_items[m_sort_indices[sorted_idx_a]];
  287. const auto &b = m_items[m_sort_indices[sorted_idx_b]];
  288. if (a.index() != MeshCmdIndex || b.index() != MeshCmdIndex) {
  289. return false;
  290. }
  291. const auto &mesh_a = std::get<MeshCmdIndex>(a);
  292. const auto &mesh_b = std::get<MeshCmdIndex>(b);
  293. if (mesh_a.alpha < k_opaque_threshold ||
  294. mesh_b.alpha < k_opaque_threshold) {
  295. return false;
  296. }
  297. return mesh_a.mesh == mesh_b.mesh && mesh_a.shader == mesh_b.shader &&
  298. mesh_a.texture == mesh_b.texture;
  299. }
  300. private:
  301. void radix_sort_two_pass(std::size_t count) {
  302. constexpr int BUCKETS = 256;
  303. m_temp_indices.resize(count);
  304. {
  305. int histogram[BUCKETS] = {0};
  306. for (std::size_t i = 0; i < count; ++i) {
  307. auto const bucket =
  308. static_cast<uint8_t>(m_sort_keys[i] >> k_sort_key_bucket_shift);
  309. ++histogram[bucket];
  310. }
  311. int offsets[BUCKETS];
  312. offsets[0] = 0;
  313. for (int i = 1; i < BUCKETS; ++i) {
  314. offsets[i] = offsets[i - 1] + histogram[i - 1];
  315. }
  316. for (std::size_t i = 0; i < count; ++i) {
  317. auto const bucket = static_cast<uint8_t>(
  318. m_sort_keys[m_sort_indices[i]] >> k_sort_key_bucket_shift);
  319. m_temp_indices[offsets[bucket]++] = m_sort_indices[i];
  320. }
  321. }
  322. {
  323. int histogram[BUCKETS] = {0};
  324. for (std::size_t i = 0; i < count; ++i) {
  325. uint8_t const bucket =
  326. static_cast<uint8_t>(m_sort_keys[m_temp_indices[i]] >> 48) & 0xFF;
  327. ++histogram[bucket];
  328. }
  329. int offsets[BUCKETS];
  330. offsets[0] = 0;
  331. for (int i = 1; i < BUCKETS; ++i) {
  332. offsets[i] = offsets[i - 1] + histogram[i - 1];
  333. }
  334. for (std::size_t i = 0; i < count; ++i) {
  335. uint8_t const bucket =
  336. static_cast<uint8_t>(m_sort_keys[m_temp_indices[i]] >> 48) & 0xFF;
  337. m_sort_indices[offsets[bucket]++] = m_temp_indices[i];
  338. }
  339. }
  340. }
  341. [[nodiscard]] static auto compute_sort_key(const DrawCmd &cmd) -> uint64_t {
  342. enum class RenderOrder : uint8_t {
  343. TerrainChunk = 0,
  344. GrassBatch = 1,
  345. StoneBatch = 2,
  346. PlantBatch = 3,
  347. PineBatch = 4,
  348. OliveBatch = 5,
  349. FireCampBatch = 6,
  350. RainBatch = 7,
  351. PrimitiveBatch = 8,
  352. Mesh = 9,
  353. Cylinder = 10,
  354. FogBatch = 11,
  355. SelectionSmoke = 12,
  356. Grid = 13,
  357. SelectionRing = 16,
  358. ModeIndicator = 17
  359. };
  360. static constexpr uint8_t k_type_order[] = {
  361. static_cast<uint8_t>(RenderOrder::Grid),
  362. static_cast<uint8_t>(RenderOrder::SelectionRing),
  363. static_cast<uint8_t>(RenderOrder::SelectionSmoke),
  364. static_cast<uint8_t>(RenderOrder::Cylinder),
  365. static_cast<uint8_t>(RenderOrder::Mesh),
  366. static_cast<uint8_t>(RenderOrder::FogBatch),
  367. static_cast<uint8_t>(RenderOrder::GrassBatch),
  368. static_cast<uint8_t>(RenderOrder::StoneBatch),
  369. static_cast<uint8_t>(RenderOrder::PlantBatch),
  370. static_cast<uint8_t>(RenderOrder::PineBatch),
  371. static_cast<uint8_t>(RenderOrder::OliveBatch),
  372. static_cast<uint8_t>(RenderOrder::FireCampBatch),
  373. static_cast<uint8_t>(RenderOrder::RainBatch),
  374. static_cast<uint8_t>(RenderOrder::TerrainChunk),
  375. static_cast<uint8_t>(RenderOrder::PrimitiveBatch),
  376. 15,
  377. 16,
  378. 17,
  379. static_cast<uint8_t>(RenderOrder::ModeIndicator)};
  380. const std::size_t type_index = cmd.index();
  381. constexpr std::size_t type_count =
  382. sizeof(k_type_order) / sizeof(k_type_order[0]);
  383. const uint8_t type_order = type_index < type_count
  384. ? k_type_order[type_index]
  385. : static_cast<uint8_t>(type_index);
  386. uint64_t key = static_cast<uint64_t>(type_order) << 56;
  387. if (cmd.index() == MeshCmdIndex) {
  388. const auto &mesh = std::get<MeshCmdIndex>(cmd);
  389. uint64_t const tex_ptr =
  390. reinterpret_cast<uintptr_t>(mesh.texture) & 0x0000FFFFFFFFFFFF;
  391. key |= tex_ptr;
  392. } else if (cmd.index() == GrassBatchCmdIndex) {
  393. const auto &grass = std::get<GrassBatchCmdIndex>(cmd);
  394. uint64_t const buffer_ptr =
  395. reinterpret_cast<uintptr_t>(grass.instance_buffer) &
  396. 0x0000FFFFFFFFFFFF;
  397. key |= buffer_ptr;
  398. } else if (cmd.index() == StoneBatchCmdIndex) {
  399. const auto &stone = std::get<StoneBatchCmdIndex>(cmd);
  400. uint64_t const buffer_ptr =
  401. reinterpret_cast<uintptr_t>(stone.instance_buffer) &
  402. 0x0000FFFFFFFFFFFF;
  403. key |= buffer_ptr;
  404. } else if (cmd.index() == PlantBatchCmdIndex) {
  405. const auto &plant = std::get<PlantBatchCmdIndex>(cmd);
  406. uint64_t const buffer_ptr =
  407. reinterpret_cast<uintptr_t>(plant.instance_buffer) &
  408. 0x0000FFFFFFFFFFFF;
  409. key |= buffer_ptr;
  410. } else if (cmd.index() == PineBatchCmdIndex) {
  411. const auto &pine = std::get<PineBatchCmdIndex>(cmd);
  412. uint64_t const buffer_ptr =
  413. reinterpret_cast<uintptr_t>(pine.instance_buffer) &
  414. 0x0000FFFFFFFFFFFF;
  415. key |= buffer_ptr;
  416. } else if (cmd.index() == OliveBatchCmdIndex) {
  417. const auto &olive = std::get<OliveBatchCmdIndex>(cmd);
  418. uint64_t const buffer_ptr =
  419. reinterpret_cast<uintptr_t>(olive.instance_buffer) &
  420. 0x0000FFFFFFFFFFFF;
  421. key |= buffer_ptr;
  422. } else if (cmd.index() == FireCampBatchCmdIndex) {
  423. const auto &firecamp = std::get<FireCampBatchCmdIndex>(cmd);
  424. uint64_t const buffer_ptr =
  425. reinterpret_cast<uintptr_t>(firecamp.instance_buffer) &
  426. 0x0000FFFFFFFFFFFF;
  427. key |= buffer_ptr;
  428. } else if (cmd.index() == TerrainChunkCmdIndex) {
  429. const auto &terrain = std::get<TerrainChunkCmdIndex>(cmd);
  430. auto const sort_byte =
  431. static_cast<uint64_t>((terrain.sort_key >> 8) & 0xFFU);
  432. key |= sort_byte << 48;
  433. uint64_t const mesh_ptr =
  434. reinterpret_cast<uintptr_t>(terrain.mesh) & 0x0000FFFFFFFFFFFFU;
  435. key |= mesh_ptr;
  436. } else if (cmd.index() == PrimitiveBatchCmdIndex) {
  437. const auto &prim = std::get<PrimitiveBatchCmdIndex>(cmd);
  438. key |= static_cast<uint64_t>(prim.type) << 48;
  439. key |= static_cast<uint64_t>(prim.instance_count() & 0xFFFFFFFF);
  440. }
  441. return key;
  442. }
  443. std::vector<DrawCmd> m_items;
  444. std::vector<uint32_t> m_sort_indices;
  445. std::vector<uint64_t> m_sort_keys;
  446. std::vector<uint32_t> m_temp_indices;
  447. };
  448. } // namespace Render::GL