|
1 | 1 | #include <cmath> |
| 2 | +#include <vector> |
2 | 3 | #include "game.h" |
3 | 4 | #include "client_card.h" |
4 | 5 | #include "materials.h" |
|
8 | 9 | #include "sound_manager.h" |
9 | 10 | #include "duelclient.h" |
10 | 11 |
|
11 | | -namespace { |
12 | | - |
13 | | -// Draws a camera-facing quad between two world-space points. |
14 | | -void DrawThickLine3D(irr::video::IVideoDriver* driver, |
15 | | - const irr::core::vector3df& start, const irr::core::vector3df& end, |
16 | | - const irr::core::vector3df& camFwd, irr::f32 halfThick, |
17 | | - irr::video::SColor color) { |
18 | | - irr::core::vector3df perp = (end - start).crossProduct(camFwd); |
19 | | - const irr::f32 len = perp.getLength(); |
20 | | - if(len < 1e-6f) return; |
21 | | - perp *= halfThick / len; |
22 | | - irr::video::S3DVertex v[4]; |
23 | | - static const irr::u16 idx[6] = {0, 2, 1, 1, 2, 3}; |
24 | | - for(int i = 0; i < 4; ++i) { v[i].Color = color; v[i].Normal = {0, 0, -1}; } |
25 | | - v[0].Pos = start + perp; |
26 | | - v[1].Pos = start - perp; |
27 | | - v[2].Pos = end + perp; |
28 | | - v[3].Pos = end - perp; |
29 | | - driver->drawVertexPrimitiveList(v, 4, idx, 2, |
30 | | - irr::video::EVT_STANDARD, irr::scene::EPT_TRIANGLES); |
31 | | -} |
32 | | - |
33 | | -} |
34 | | - |
35 | 12 | namespace ygo { |
36 | 13 |
|
37 | 14 | void Game::Draw2DImageQuad(irr::video::IVideoDriver* driver, irr::video::ITexture* texture, |
@@ -96,17 +73,40 @@ void Game::DrawSelectionLine(irr::video::S3DVertex* vec, bool stipple, irr::vide |
96 | 73 | const irr::core::matrix4& view = driver->getTransform(irr::video::ETS_VIEW); |
97 | 74 | const irr::core::vector3df camFwd(view(0,2), view(1,2), view(2,2)); |
98 | 75 | const irr::f32 halfThick = matManager.mOutLine.Thickness * 0.005f; |
| 76 | + std::vector<irr::video::S3DVertex> vertices; |
| 77 | + std::vector<irr::u16> indices; |
| 78 | + vertices.reserve(64); |
| 79 | + indices.reserve(96); |
| 80 | + constexpr size_t MAX_THICK_LINE_BATCH_VERTICES = (1 << (sizeof(irr::u16) * 8)) - 4; |
| 81 | + const auto appendThickLine = [&](const irr::core::vector3df& start, const irr::core::vector3df& end) { |
| 82 | + if(vertices.size() > MAX_THICK_LINE_BATCH_VERTICES) |
| 83 | + return; |
| 84 | + const auto direction = end - start; |
| 85 | + irr::core::vector3df perp = direction.crossProduct(camFwd); |
| 86 | + const irr::f32 lenSq = perp.getLengthSQ(); |
| 87 | + if(lenSq < 1e-12f) return; |
| 88 | + perp *= halfThick / std::sqrt(lenSq); |
| 89 | + const auto base = static_cast<irr::u16>(vertices.size()); |
| 90 | + static const irr::u16 idx[6] = {0, 2, 1, 1, 2, 3}; |
| 91 | + const irr::core::vector3df normal(0.0f, 0.0f, -1.0f); |
| 92 | + vertices.emplace_back(start + perp, normal, color, irr::core::vector2df()); |
| 93 | + vertices.emplace_back(start - perp, normal, color, irr::core::vector2df()); |
| 94 | + vertices.emplace_back(end + perp, normal, color, irr::core::vector2df()); |
| 95 | + vertices.emplace_back(end - perp, normal, color, irr::core::vector2df()); |
| 96 | + for(int i = 0; i < 6; ++i) |
| 97 | + indices.push_back(base + idx[i]); |
| 98 | + }; |
99 | 99 | driver->setTransform(irr::video::ETS_WORLD, irr::core::matrix4()); |
100 | 100 | if(!stipple) { |
101 | 101 | for(int i = 0; i < 4; ++i) |
102 | | - DrawThickLine3D(driver, wp[edgeStart[i]], wp[edgeEnd[i]], camFwd, halfThick, color); |
| 102 | + appendThickLine(wp[edgeStart[i]], wp[edgeEnd[i]]); |
103 | 103 | } else if(gameConf.solid_selection_line) { |
104 | 104 | const irr::f32 t0 = (linePattern < 15) ? 0.0f : (linePattern - 14) / 15.0f; |
105 | 105 | const irr::f32 t1 = (linePattern < 15) ? (linePattern + 1) / 15.0f : 1.0f; |
106 | 106 | for(int i = 0; i < 4; ++i) { |
107 | 107 | const auto& s = wp[edgeStart[i]]; |
108 | 108 | const auto d = wp[edgeEnd[i]] - s; |
109 | | - DrawThickLine3D(driver, s + d * t0, s + d * t1, camFwd, halfThick, color); |
| 109 | + appendThickLine(s + d * t0, s + d * t1); |
110 | 110 | } |
111 | 111 | } else { |
112 | 112 | // Project edge endpoints to screen space to get pixel length for pattern tiling. |
@@ -137,12 +137,17 @@ void Game::DrawSelectionLine(irr::video::S3DVertex* vec, bool stipple, irr::vide |
137 | 137 | runEnd += 1.0f; |
138 | 138 | if(runEnd > screenLen) |
139 | 139 | runEnd = screenLen; |
140 | | - DrawThickLine3D(driver, s + d * (cursor / screenLen), s + d * (runEnd / screenLen), camFwd, halfThick, color); |
| 140 | + appendThickLine(s + d * (cursor / screenLen), s + d * (runEnd / screenLen)); |
141 | 141 | cursor = runEnd; |
142 | 142 | } |
143 | 143 | patternCursor = std::fmod(patternCursor + screenLen, 16.0f); |
144 | 144 | } |
145 | 145 | } |
| 146 | + if(!indices.empty()) { |
| 147 | + driver->drawVertexPrimitiveList(vertices.data(), static_cast<irr::u32>(vertices.size()), |
| 148 | + indices.data(), static_cast<irr::u32>(indices.size() / 3), |
| 149 | + irr::video::EVT_STANDARD, irr::scene::EPT_TRIANGLES); |
| 150 | + } |
146 | 151 | driver->setTransform(irr::video::ETS_WORLD, oldWorld); |
147 | 152 | } |
148 | 153 | void Game::DrawSelectionLine(irr::gui::IGUIElement* element, int width, irr::video::SColor color) { |
|
0 commit comments