bridge_renderer.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. #include "bridge_renderer.h"
  2. #include "../../game/map/visibility_service.h"
  3. #include "../gl/mesh.h"
  4. #include "../gl/resources.h"
  5. #include "../scene_renderer.h"
  6. #include "terrain_gpu.h"
  7. #include <QVector2D>
  8. #include <QVector3D>
  9. #include <algorithm>
  10. #include <cmath>
  11. namespace Render::GL {
  12. BridgeRenderer::BridgeRenderer() = default;
  13. BridgeRenderer::~BridgeRenderer() = default;
  14. void BridgeRenderer::configure(const std::vector<Game::Map::Bridge> &bridges,
  15. float tileSize) {
  16. m_bridges = bridges;
  17. m_tileSize = tileSize;
  18. buildMeshes();
  19. }
  20. void BridgeRenderer::buildMeshes() {
  21. m_meshes.clear();
  22. if (m_bridges.empty()) {
  23. return;
  24. }
  25. for (const auto &bridge : m_bridges) {
  26. QVector3D dir = bridge.end - bridge.start;
  27. float length = dir.length();
  28. if (length < 0.01f) {
  29. m_meshes.push_back(nullptr);
  30. continue;
  31. }
  32. dir.normalize();
  33. QVector3D perpendicular(-dir.z(), 0.0f, dir.x());
  34. float halfWidth = bridge.width * 0.5f;
  35. int lengthSegments =
  36. static_cast<int>(std::ceil(length / (m_tileSize * 0.3f)));
  37. lengthSegments = std::max(lengthSegments, 8);
  38. std::vector<Vertex> vertices;
  39. std::vector<unsigned int> indices;
  40. const int vertsPerSegment = 12;
  41. const float deckThickness = std::clamp(bridge.width * 0.25f, 0.35f, 0.8f);
  42. const float parapetHeight = std::clamp(bridge.width * 0.25f, 0.25f, 0.55f);
  43. const float parapetOffset = halfWidth * 1.05f;
  44. auto addVertex = [&](const QVector3D &position, const QVector3D &normal,
  45. float u, float v) {
  46. Vertex vtx{};
  47. vtx.position[0] = position.x();
  48. vtx.position[1] = position.y();
  49. vtx.position[2] = position.z();
  50. QVector3D n = normal.normalized();
  51. vtx.normal[0] = n.x();
  52. vtx.normal[1] = n.y();
  53. vtx.normal[2] = n.z();
  54. vtx.texCoord[0] = u;
  55. vtx.texCoord[1] = v;
  56. vertices.push_back(vtx);
  57. };
  58. auto pushQuad = [&](unsigned int a, unsigned int b, unsigned int c,
  59. unsigned int d) {
  60. indices.push_back(a);
  61. indices.push_back(b);
  62. indices.push_back(c);
  63. indices.push_back(a);
  64. indices.push_back(c);
  65. indices.push_back(d);
  66. };
  67. for (int i = 0; i <= lengthSegments; ++i) {
  68. float t = static_cast<float>(i) / static_cast<float>(lengthSegments);
  69. QVector3D centerPos = bridge.start + dir * (length * t);
  70. float archCurve = 4.0f * t * (1.0f - t);
  71. float archHeight = bridge.height * archCurve * 0.8f;
  72. float deckHeight = bridge.start.y() + bridge.height + archHeight * 0.3f;
  73. float stoneNoise = std::sin(centerPos.x() * 3.0f) *
  74. std::cos(centerPos.z() * 2.5f) * 0.02f;
  75. float deckY = deckHeight + stoneNoise;
  76. float undersideY =
  77. deckHeight - deckThickness - archCurve * bridge.height * 0.55f;
  78. float railTopY = deckY + parapetHeight;
  79. QVector3D leftNormal = (-perpendicular).normalized();
  80. QVector3D rightNormal = perpendicular.normalized();
  81. QVector3D topLeft = centerPos + perpendicular * (-halfWidth);
  82. topLeft.setY(deckY);
  83. QVector3D topRight = centerPos + perpendicular * (halfWidth);
  84. topRight.setY(deckY);
  85. QVector3D bottomLeft = topLeft;
  86. bottomLeft.setY(undersideY);
  87. QVector3D bottomRight = topRight;
  88. bottomRight.setY(undersideY);
  89. QVector3D sideLeftTop = topLeft;
  90. QVector3D sideLeftBottom = bottomLeft;
  91. QVector3D sideRightTop = topRight;
  92. QVector3D sideRightBottom = bottomRight;
  93. QVector3D parapetLeftBottom =
  94. centerPos + perpendicular * (-parapetOffset);
  95. parapetLeftBottom.setY(deckY);
  96. QVector3D parapetLeftTop = parapetLeftBottom;
  97. parapetLeftTop.setY(railTopY);
  98. QVector3D parapetRightBottom =
  99. centerPos + perpendicular * (parapetOffset);
  100. parapetRightBottom.setY(deckY);
  101. QVector3D parapetRightTop = parapetRightBottom;
  102. parapetRightTop.setY(railTopY);
  103. float texU0 = 0.0f;
  104. float texU1 = 1.0f;
  105. float texV = t * length * 0.4f;
  106. addVertex(topLeft, QVector3D(0.0f, 1.0f, 0.0f), texU0, texV);
  107. addVertex(topRight, QVector3D(0.0f, 1.0f, 0.0f), texU1, texV);
  108. addVertex(bottomLeft, QVector3D(0.0f, -1.0f, 0.0f), texU0, texV);
  109. addVertex(bottomRight, QVector3D(0.0f, -1.0f, 0.0f), texU1, texV);
  110. addVertex(sideLeftTop, leftNormal, texU0, texV);
  111. addVertex(sideLeftBottom, leftNormal, texU0, texV);
  112. addVertex(sideRightTop, rightNormal, texU1, texV);
  113. addVertex(sideRightBottom, rightNormal, texU1, texV);
  114. addVertex(parapetLeftTop, leftNormal, texU0, texV);
  115. addVertex(parapetLeftBottom, leftNormal, texU0, texV);
  116. addVertex(parapetRightTop, rightNormal, texU1, texV);
  117. addVertex(parapetRightBottom, rightNormal, texU1, texV);
  118. if (i < lengthSegments) {
  119. unsigned int baseIdx = static_cast<unsigned int>(i * vertsPerSegment);
  120. unsigned int nextIdx = baseIdx + vertsPerSegment;
  121. pushQuad(baseIdx + 0, baseIdx + 1, nextIdx + 1, nextIdx + 0);
  122. pushQuad(nextIdx + 3, nextIdx + 2, baseIdx + 2, baseIdx + 3);
  123. pushQuad(baseIdx + 4, baseIdx + 5, nextIdx + 5, nextIdx + 4);
  124. pushQuad(baseIdx + 6, baseIdx + 7, nextIdx + 7, nextIdx + 6);
  125. pushQuad(baseIdx + 9, baseIdx + 8, nextIdx + 8, nextIdx + 9);
  126. pushQuad(baseIdx + 11, baseIdx + 10, nextIdx + 10, nextIdx + 11);
  127. }
  128. }
  129. if (!vertices.empty()) {
  130. unsigned int startIdx = 0;
  131. unsigned int endIdx =
  132. static_cast<unsigned int>(lengthSegments * vertsPerSegment);
  133. QVector3D forwardNormal = dir;
  134. auto addCap = [&](unsigned int topL, unsigned int topR,
  135. unsigned int bottomR, unsigned int bottomL,
  136. const QVector3D &normal) {
  137. unsigned int capStart = static_cast<unsigned int>(vertices.size());
  138. auto copyVertex = [&](unsigned int source, const QVector3D &norm) {
  139. const Vertex &src = vertices[source];
  140. Vertex vtx = src;
  141. QVector3D n = norm.normalized();
  142. vtx.normal[0] = n.x();
  143. vtx.normal[1] = n.y();
  144. vtx.normal[2] = n.z();
  145. vertices.push_back(vtx);
  146. };
  147. copyVertex(topL, normal);
  148. copyVertex(topR, normal);
  149. copyVertex(bottomR, normal);
  150. copyVertex(bottomL, normal);
  151. pushQuad(capStart + 0, capStart + 1, capStart + 2, capStart + 3);
  152. };
  153. addCap(startIdx + 0, startIdx + 1, startIdx + 3, startIdx + 2,
  154. -forwardNormal);
  155. addCap(endIdx + 0, endIdx + 1, endIdx + 3, endIdx + 2, forwardNormal);
  156. }
  157. if (!vertices.empty() && !indices.empty()) {
  158. m_meshes.push_back(std::make_unique<Mesh>(vertices, indices));
  159. } else {
  160. m_meshes.push_back(nullptr);
  161. }
  162. }
  163. }
  164. void BridgeRenderer::submit(Renderer &renderer, ResourceManager *resources) {
  165. if (m_meshes.empty() || m_bridges.empty()) {
  166. return;
  167. }
  168. Q_UNUSED(resources);
  169. auto &visibility = Game::Map::VisibilityService::instance();
  170. const bool useVisibility = visibility.isInitialized();
  171. auto shader = renderer.getShader("bridge");
  172. if (!shader) {
  173. shader = renderer.getShader("basic");
  174. if (!shader) {
  175. return;
  176. }
  177. }
  178. renderer.setCurrentShader(shader);
  179. QMatrix4x4 model;
  180. model.setToIdentity();
  181. QVector3D stoneColor(0.55f, 0.52f, 0.48f);
  182. size_t meshIndex = 0;
  183. for (const auto &bridge : m_bridges) {
  184. if (meshIndex >= m_meshes.size()) {
  185. break;
  186. }
  187. auto *mesh = m_meshes[meshIndex].get();
  188. ++meshIndex;
  189. if (!mesh) {
  190. continue;
  191. }
  192. QVector3D dir = bridge.end - bridge.start;
  193. float length = dir.length();
  194. float alpha = 1.0f;
  195. QVector3D colorMultiplier(1.0f, 1.0f, 1.0f);
  196. if (useVisibility) {
  197. int maxVisibilityState = 0;
  198. dir.normalize();
  199. int samplesPerBridge = 5;
  200. for (int i = 0; i < samplesPerBridge; ++i) {
  201. float t =
  202. static_cast<float>(i) / static_cast<float>(samplesPerBridge - 1);
  203. QVector3D pos = bridge.start + dir * (length * t);
  204. if (visibility.isVisibleWorld(pos.x(), pos.z())) {
  205. maxVisibilityState = 2;
  206. break;
  207. } else if (visibility.isExploredWorld(pos.x(), pos.z())) {
  208. maxVisibilityState = std::max(maxVisibilityState, 1);
  209. }
  210. }
  211. if (maxVisibilityState == 0) {
  212. continue;
  213. } else if (maxVisibilityState == 1) {
  214. alpha = 0.5f;
  215. colorMultiplier = QVector3D(0.4f, 0.4f, 0.45f);
  216. }
  217. }
  218. QVector3D finalColor(stoneColor.x() * colorMultiplier.x(),
  219. stoneColor.y() * colorMultiplier.y(),
  220. stoneColor.z() * colorMultiplier.z());
  221. renderer.mesh(mesh, model, finalColor, nullptr, alpha);
  222. }
  223. renderer.setCurrentShader(nullptr);
  224. }
  225. } // namespace Render::GL