fog_renderer.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #include "fog_renderer.h"
  2. #include "../gl/mesh.h"
  3. #include "../gl/resources.h"
  4. #include "../scene_renderer.h"
  5. #include <QElapsedTimer>
  6. #include <algorithm>
  7. namespace Render::GL {
  8. void FogRenderer::updateMask(int width, int height, float tileSize,
  9. const std::vector<std::uint8_t> &cells) {
  10. m_width = std::max(0, width);
  11. m_height = std::max(0, height);
  12. m_tileSize = std::max(0.0001f, tileSize);
  13. m_halfWidth = m_width * 0.5f - 0.5f;
  14. m_halfHeight = m_height * 0.5f - 0.5f;
  15. m_cells = cells;
  16. buildChunks();
  17. }
  18. void FogRenderer::submit(Renderer &renderer, ResourceManager &resources) {
  19. if (!m_enabled)
  20. return;
  21. if (m_width <= 0 || m_height <= 0)
  22. return;
  23. if (static_cast<int>(m_cells.size()) != m_width * m_height)
  24. return;
  25. Texture *white = resources.white();
  26. if (!white)
  27. return;
  28. QMatrix4x4 model;
  29. for (const auto &chunk : m_chunks) {
  30. if (!chunk.mesh)
  31. continue;
  32. renderer.mesh(chunk.mesh.get(), model, chunk.color, white, chunk.alpha);
  33. }
  34. }
  35. void FogRenderer::buildChunks() {
  36. m_chunks.clear();
  37. if (m_width <= 0 || m_height <= 0)
  38. return;
  39. if (static_cast<int>(m_cells.size()) != m_width * m_height)
  40. return;
  41. QElapsedTimer timer;
  42. timer.start();
  43. const float halfTile = m_tileSize * 0.5f;
  44. const int chunkSize = 16;
  45. std::size_t totalQuads = 0;
  46. for (int chunkZ = 0; chunkZ < m_height; chunkZ += chunkSize) {
  47. int chunkMaxZ = std::min(chunkZ + chunkSize, m_height);
  48. for (int chunkX = 0; chunkX < m_width; chunkX += chunkSize) {
  49. int chunkMaxX = std::min(chunkX + chunkSize, m_width);
  50. struct SectionData {
  51. std::vector<Vertex> vertices;
  52. std::vector<unsigned int> indices;
  53. };
  54. SectionData sections[2];
  55. auto appendQuad = [&](SectionData &section, float centerX,
  56. float centerZ) {
  57. Vertex v0{};
  58. Vertex v1{};
  59. Vertex v2{};
  60. Vertex v3{};
  61. v0.position[0] = centerX - halfTile;
  62. v0.position[1] = 0.25f;
  63. v0.position[2] = centerZ - halfTile;
  64. v1.position[0] = centerX + halfTile;
  65. v1.position[1] = 0.25f;
  66. v1.position[2] = centerZ - halfTile;
  67. v2.position[0] = centerX - halfTile;
  68. v2.position[1] = 0.25f;
  69. v2.position[2] = centerZ + halfTile;
  70. v3.position[0] = centerX + halfTile;
  71. v3.position[1] = 0.25f;
  72. v3.position[2] = centerZ + halfTile;
  73. v0.normal[0] = v1.normal[0] = v2.normal[0] = v3.normal[0] = 0.0f;
  74. v0.normal[1] = v1.normal[1] = v2.normal[1] = v3.normal[1] = 1.0f;
  75. v0.normal[2] = v1.normal[2] = v2.normal[2] = v3.normal[2] = 0.0f;
  76. v0.texCoord[0] = 0.0f;
  77. v0.texCoord[1] = 0.0f;
  78. v1.texCoord[0] = 1.0f;
  79. v1.texCoord[1] = 0.0f;
  80. v2.texCoord[0] = 0.0f;
  81. v2.texCoord[1] = 1.0f;
  82. v3.texCoord[0] = 1.0f;
  83. v3.texCoord[1] = 1.0f;
  84. const unsigned int base =
  85. static_cast<unsigned int>(section.vertices.size());
  86. section.vertices.push_back(v0);
  87. section.vertices.push_back(v1);
  88. section.vertices.push_back(v2);
  89. section.vertices.push_back(v3);
  90. section.indices.push_back(base + 0);
  91. section.indices.push_back(base + 1);
  92. section.indices.push_back(base + 2);
  93. section.indices.push_back(base + 2);
  94. section.indices.push_back(base + 1);
  95. section.indices.push_back(base + 3);
  96. };
  97. for (int z = chunkZ; z < chunkMaxZ; ++z) {
  98. for (int x = chunkX; x < chunkMaxX; ++x) {
  99. const std::uint8_t state = m_cells[z * m_width + x];
  100. if (state >= 2)
  101. continue;
  102. const float worldX = (x - m_halfWidth) * m_tileSize;
  103. const float worldZ = (z - m_halfHeight) * m_tileSize;
  104. SectionData &section = sections[std::min<int>(state, 1)];
  105. appendQuad(section, worldX, worldZ);
  106. }
  107. }
  108. if (!sections[0].indices.empty()) {
  109. FogChunk chunk;
  110. chunk.mesh =
  111. std::make_unique<Mesh>(sections[0].vertices, sections[0].indices);
  112. chunk.color = QVector3D(0.02f, 0.02f, 0.05f);
  113. chunk.alpha = 0.9f;
  114. totalQuads += sections[0].indices.size() / 6;
  115. m_chunks.push_back(std::move(chunk));
  116. }
  117. if (!sections[1].indices.empty()) {
  118. FogChunk chunk;
  119. chunk.mesh =
  120. std::make_unique<Mesh>(sections[1].vertices, sections[1].indices);
  121. chunk.color = QVector3D(0.05f, 0.05f, 0.05f);
  122. chunk.alpha = 0.45f;
  123. totalQuads += sections[1].indices.size() / 6;
  124. m_chunks.push_back(std::move(chunk));
  125. }
  126. }
  127. }
  128. qDebug() << "FogRenderer: built" << m_chunks.size() << "chunks in"
  129. << timer.elapsed() << "ms" << "quads:" << totalQuads;
  130. }
  131. } // namespace Render::GL