draw_queue.h 14 KB

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