Skip to content

Commit 9efac56

Browse files
committed
update
1 parent a86b494 commit 9efac56

2 files changed

Lines changed: 114 additions & 50 deletions

File tree

gframe/drawing.cpp

Lines changed: 113 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,13 @@ void Game::Draw2DImageQuad(irr::video::IVideoDriver* driver, irr::video::ITextur
6464
void Game::DrawSelectionLine(irr::video::S3DVertex* vec, bool stipple, irr::video::SColor color) {
6565
static const int edgeStart[] = { 0, 1, 3, 2 };
6666
static const int edgeEnd[] = { 1, 3, 2, 0 };
67-
driver->setMaterial(matManager.mOutLine);
6867
const irr::core::matrix4 oldWorld = driver->getTransform(irr::video::ETS_WORLD);
6968
irr::core::vector3df wp[4];
7069
for(int i = 0; i < 4; ++i)
7170
oldWorld.transformVect(wp[i], vec[i].Pos);
7271
const irr::core::matrix4& view = driver->getTransform(irr::video::ETS_VIEW);
7372
irr::core::matrix4 pv = driver->getTransform(irr::video::ETS_PROJECTION);
7473
pv *= view;
75-
irr::core::matrix4 invPv;
76-
if(!pv.getInverse(invPv))
77-
return;
7874
const auto sz = driver->getCurrentRenderTargetSize();
7975
if(sz.Width == 0 || sz.Height == 0)
8076
return;
@@ -83,6 +79,11 @@ void Game::DrawSelectionLine(irr::video::S3DVertex* vec, bool stipple, irr::vide
8379
const irr::f32 yScale = sz.Height / static_cast<irr::f32>(GAME_WINDOW_HEIGHT);
8480
const irr::f32 pixelScale = (xScale < yScale) ? xScale : yScale;
8581
const irr::f32 halfThick = matManager.mOutLine.Thickness * pixelScale * 0.2f;
82+
if(halfThick <= 0.0f)
83+
return;
84+
irr::core::matrix4 invPv;
85+
if(!pv.getInverse(invPv))
86+
return;
8687
struct ProjectedPoint {
8788
irr::core::vector2df screen;
8889
irr::f32 ndcZ;
@@ -105,39 +106,26 @@ void Game::DrawSelectionLine(irr::video::S3DVertex* vec, bool stipple, irr::vide
105106
const irr::f32 invW = 1.0f / point[3];
106107
return irr::core::vector3df(point[0] * invW, point[1] * invW, point[2] * invW);
107108
};
108-
std::vector<irr::video::S3DVertex> vertices;
109-
std::vector<irr::u16> indices;
110-
vertices.reserve(128);
111-
indices.reserve(240);
112109
constexpr size_t THICK_LINE_VERTICES_PER_SEGMENT = 8;
113-
constexpr size_t MAX_THICK_LINE_BATCH_VERTICES = (size_t{1} << (sizeof(irr::u16) * 8)) - THICK_LINE_VERTICES_PER_SEGMENT;
114-
const auto drawBatch = [&]() {
115-
if(indices.empty())
116-
return;
117-
driver->drawVertexPrimitiveList(vertices.data(), static_cast<irr::u32>(vertices.size()),
118-
indices.data(), static_cast<irr::u32>(indices.size() / 3),
119-
irr::video::EVT_STANDARD, irr::scene::EPT_TRIANGLES);
120-
vertices.clear();
121-
indices.clear();
110+
constexpr size_t THICK_LINE_INDICES_PER_SEGMENT = 30;
111+
const auto lerpProjected = [](const ProjectedPoint& start, const ProjectedPoint& end, irr::f32 t) {
112+
ProjectedPoint result;
113+
result.screen = start.screen + (end.screen - start.screen) * t;
114+
result.ndcZ = start.ndcZ + (end.ndcZ - start.ndcZ) * t;
115+
return result;
122116
};
123-
const auto appendThickLine = [&](const irr::core::vector3df& start, const irr::core::vector3df& end) {
124-
if(halfThick <= 0.0f) return;
125-
ProjectedPoint ps, pe;
126-
if(!projectPoint(start, ps) || !projectPoint(end, pe))
127-
return;
117+
const auto buildThickLine = [&](const ProjectedPoint& ps, const ProjectedPoint& pe,
118+
irr::video::S3DVertex* outVertices, irr::u16* outIndices, irr::u16 base) {
128119
const auto screenDirection = pe.screen - ps.screen;
129120
const irr::f32 screenLenSq = screenDirection.getLengthSQ();
130-
if(screenLenSq < 1e-4f) return;
131-
if(vertices.size() > MAX_THICK_LINE_BATCH_VERTICES)
132-
drawBatch();
121+
if(screenLenSq < 1e-4f) return false;
133122
const irr::f32 invScreenLen = 1.0f / std::sqrt(screenLenSq);
134123
const irr::core::vector2df dir = screenDirection * invScreenLen;
135124
const irr::core::vector2df perp(-dir.Y, dir.X);
136125
const irr::f32 feather = halfThick * 2.0f;
137126
const auto innerPerp = perp * halfThick;
138127
const auto outerPerp = perp * (halfThick + feather);
139128
const auto endFeather = dir * feather;
140-
const auto base = static_cast<irr::u16>(vertices.size());
141129
static const irr::u16 idx[30] = {
142130
0, 1, 3, 0, 3, 2,
143131
4, 5, 0, 0, 5, 1,
@@ -148,55 +136,130 @@ void Game::DrawSelectionLine(irr::video::S3DVertex* vec, bool stipple, irr::vide
148136
const irr::core::vector3df normal(0.0f, 0.0f, -1.0f);
149137
irr::video::SColor transparent = color;
150138
transparent.setAlpha(0);
151-
vertices.emplace_back(unprojectScreen(ps.screen + innerPerp, ps.ndcZ), normal, color, irr::core::vector2df());
152-
vertices.emplace_back(unprojectScreen(pe.screen + innerPerp, pe.ndcZ), normal, color, irr::core::vector2df());
153-
vertices.emplace_back(unprojectScreen(ps.screen - innerPerp, ps.ndcZ), normal, color, irr::core::vector2df());
154-
vertices.emplace_back(unprojectScreen(pe.screen - innerPerp, pe.ndcZ), normal, color, irr::core::vector2df());
155-
vertices.emplace_back(unprojectScreen(ps.screen - endFeather + outerPerp, ps.ndcZ), normal, transparent, irr::core::vector2df());
156-
vertices.emplace_back(unprojectScreen(pe.screen + endFeather + outerPerp, pe.ndcZ), normal, transparent, irr::core::vector2df());
157-
vertices.emplace_back(unprojectScreen(pe.screen + endFeather - outerPerp, pe.ndcZ), normal, transparent, irr::core::vector2df());
158-
vertices.emplace_back(unprojectScreen(ps.screen - endFeather - outerPerp, ps.ndcZ), normal, transparent, irr::core::vector2df());
159-
for(int i = 0; i < 30; ++i)
160-
indices.push_back(base + idx[i]);
139+
outVertices[0] = irr::video::S3DVertex(unprojectScreen(ps.screen + innerPerp, ps.ndcZ), normal, color, irr::core::vector2df());
140+
outVertices[1] = irr::video::S3DVertex(unprojectScreen(pe.screen + innerPerp, pe.ndcZ), normal, color, irr::core::vector2df());
141+
outVertices[2] = irr::video::S3DVertex(unprojectScreen(ps.screen - innerPerp, ps.ndcZ), normal, color, irr::core::vector2df());
142+
outVertices[3] = irr::video::S3DVertex(unprojectScreen(pe.screen - innerPerp, pe.ndcZ), normal, color, irr::core::vector2df());
143+
outVertices[4] = irr::video::S3DVertex(unprojectScreen(ps.screen - endFeather + outerPerp, ps.ndcZ), normal, transparent, irr::core::vector2df());
144+
outVertices[5] = irr::video::S3DVertex(unprojectScreen(pe.screen + endFeather + outerPerp, pe.ndcZ), normal, transparent, irr::core::vector2df());
145+
outVertices[6] = irr::video::S3DVertex(unprojectScreen(pe.screen + endFeather - outerPerp, pe.ndcZ), normal, transparent, irr::core::vector2df());
146+
outVertices[7] = irr::video::S3DVertex(unprojectScreen(ps.screen - endFeather - outerPerp, ps.ndcZ), normal, transparent, irr::core::vector2df());
147+
for(size_t i = 0; i < THICK_LINE_INDICES_PER_SEGMENT; ++i)
148+
outIndices[i] = base + idx[i];
149+
return true;
161150
};
151+
driver->setMaterial(matManager.mOutLine);
162152
driver->setTransform(irr::video::ETS_WORLD, irr::core::matrix4());
153+
const auto drawFixedSegments = [&](const auto& getSegment) {
154+
irr::video::S3DVertex vertices[4 * THICK_LINE_VERTICES_PER_SEGMENT];
155+
irr::u16 indices[4 * THICK_LINE_INDICES_PER_SEGMENT];
156+
size_t vertexCount = 0;
157+
size_t indexCount = 0;
158+
for(int i = 0; i < 4; ++i) {
159+
ProjectedPoint ps, pe;
160+
if(!getSegment(i, ps, pe))
161+
continue;
162+
if(buildThickLine(ps, pe, vertices + vertexCount, indices + indexCount, static_cast<irr::u16>(vertexCount))) {
163+
vertexCount += THICK_LINE_VERTICES_PER_SEGMENT;
164+
indexCount += THICK_LINE_INDICES_PER_SEGMENT;
165+
}
166+
}
167+
if(indexCount)
168+
driver->drawVertexPrimitiveList(vertices, static_cast<irr::u32>(vertexCount),
169+
indices, static_cast<irr::u32>(indexCount / 3),
170+
irr::video::EVT_STANDARD, irr::scene::EPT_TRIANGLES);
171+
};
163172
if(!stipple) {
164-
for(int i = 0; i < 4; ++i)
165-
appendThickLine(wp[edgeStart[i]], wp[edgeEnd[i]]);
173+
drawFixedSegments([&](int i, ProjectedPoint& ps, ProjectedPoint& pe) {
174+
return projectPoint(wp[edgeStart[i]], ps) && projectPoint(wp[edgeEnd[i]], pe);
175+
});
166176
} else if(gameConf.solid_selection_line) {
167177
const irr::f32 t0 = (linePattern < 15) ? 0.0f : (linePattern - 14) / 15.0f;
168178
const irr::f32 t1 = (linePattern < 15) ? (linePattern + 1) / 15.0f : 1.0f;
169-
for(int i = 0; i < 4; ++i) {
179+
drawFixedSegments([&](int i, ProjectedPoint& ps, ProjectedPoint& pe) {
170180
const auto& s = wp[edgeStart[i]];
171181
const auto d = wp[edgeEnd[i]] - s;
172-
appendThickLine(s + d * t0, s + d * t1);
173-
}
182+
return projectPoint(s + d * t0, ps) && projectPoint(s + d * t1, pe);
183+
});
174184
} else {
185+
constexpr size_t MAX_THICK_LINE_BATCH_VERTICES = size_t{1} << (sizeof(irr::u16) * 8);
186+
struct ProjectedEdge {
187+
ProjectedPoint start;
188+
ProjectedPoint end;
189+
irr::f32 screenLen;
190+
bool projected;
191+
};
192+
ProjectedEdge projectedEdges[4];
193+
irr::f32 totalProjectedLen = 0.0f;
194+
for(int i = 0; i < 4; ++i) {
195+
auto& edge = projectedEdges[i];
196+
edge.projected = projectPoint(wp[edgeStart[i]], edge.start) && projectPoint(wp[edgeEnd[i]], edge.end);
197+
edge.screenLen = 1.0f;
198+
if(edge.projected) {
199+
edge.screenLen = std::sqrt((edge.start.screen - edge.end.screen).getLengthSQ());
200+
totalProjectedLen += edge.screenLen;
201+
}
202+
}
203+
const size_t estimatedSegments = static_cast<size_t>(totalProjectedLen * 0.5f) + 4;
204+
size_t reserveVertices = estimatedSegments * THICK_LINE_VERTICES_PER_SEGMENT;
205+
if(reserveVertices > MAX_THICK_LINE_BATCH_VERTICES)
206+
reserveVertices = MAX_THICK_LINE_BATCH_VERTICES;
207+
std::vector<irr::video::S3DVertex> vertices;
208+
std::vector<irr::u16> indices;
209+
vertices.reserve(reserveVertices);
210+
indices.reserve((reserveVertices / THICK_LINE_VERTICES_PER_SEGMENT) * THICK_LINE_INDICES_PER_SEGMENT);
211+
const auto drawBatch = [&]() {
212+
if(indices.empty())
213+
return;
214+
driver->drawVertexPrimitiveList(vertices.data(), static_cast<irr::u32>(vertices.size()),
215+
indices.data(), static_cast<irr::u32>(indices.size() / 3),
216+
irr::video::EVT_STANDARD, irr::scene::EPT_TRIANGLES);
217+
vertices.clear();
218+
indices.clear();
219+
};
220+
const auto appendProjectedThickLine = [&](const ProjectedPoint& ps, const ProjectedPoint& pe) {
221+
if(vertices.size() + THICK_LINE_VERTICES_PER_SEGMENT > MAX_THICK_LINE_BATCH_VERTICES)
222+
drawBatch();
223+
const auto base = static_cast<irr::u16>(vertices.size());
224+
const size_t oldVertexCount = vertices.size();
225+
const size_t oldIndexCount = indices.size();
226+
vertices.resize(oldVertexCount + THICK_LINE_VERTICES_PER_SEGMENT);
227+
indices.resize(oldIndexCount + THICK_LINE_INDICES_PER_SEGMENT);
228+
if(!buildThickLine(ps, pe, vertices.data() + oldVertexCount, indices.data() + oldIndexCount, base)) {
229+
vertices.resize(oldVertexCount);
230+
indices.resize(oldIndexCount);
231+
}
232+
};
175233
// Project edge endpoints to screen space to get pixel length for pattern tiling.
176234
// (1 pattern bit = 1 screen pixel, matching the original GL stipple behaviour.)
177235
irr::f32 patternCursor = 0.0f;
178236
for(int i = 0; i < 4; ++i) {
179-
const auto& s = wp[edgeStart[i]];
180-
const auto d = wp[edgeEnd[i]] - s;
181-
ProjectedPoint ps, pe;
182-
irr::f32 screenLen = 1.0f;
183-
if(projectPoint(s, ps) && projectPoint(s + d, pe))
184-
screenLen = std::sqrt((ps.screen - pe.screen).getLengthSQ());
237+
const auto& edge = projectedEdges[i];
238+
const irr::f32 screenLen = edge.screenLen;
185239
for(irr::f32 cursor = 0.0f; cursor < screenLen; ) {
186240
const int bit = static_cast<int>(patternCursor + cursor) & 0xf;
187-
if(!((stippleMask >> bit) & 1)) { cursor += 1.0f; continue; }
241+
if(!((stippleMask >> bit) & 1)) {
242+
irr::f32 runEnd = cursor + 1.0f;
243+
while(runEnd < screenLen && !((stippleMask >> (static_cast<int>(patternCursor + runEnd) & 0xf)) & 1))
244+
runEnd += 1.0f;
245+
cursor = runEnd;
246+
continue;
247+
}
188248
irr::f32 runEnd = cursor + 1.0f;
189249
while(runEnd < screenLen && ((stippleMask >> (static_cast<int>(patternCursor + runEnd) & 0xf)) & 1))
190250
runEnd += 1.0f;
191251
if(runEnd > screenLen)
192252
runEnd = screenLen;
193-
appendThickLine(s + d * (cursor / screenLen), s + d * (runEnd / screenLen));
253+
if(edge.projected) {
254+
appendProjectedThickLine(lerpProjected(edge.start, edge.end, cursor / screenLen),
255+
lerpProjected(edge.start, edge.end, runEnd / screenLen));
256+
}
194257
cursor = runEnd;
195258
}
196259
patternCursor = std::fmod(patternCursor + screenLen, 16.0f);
197260
}
261+
drawBatch();
198262
}
199-
drawBatch();
200263
driver->setTransform(irr::video::ETS_WORLD, oldWorld);
201264
}
202265
void Game::DrawSelectionLine(irr::gui::IGUIElement* element, int width, irr::video::SColor color) {

gframe/materials.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ Materials::Materials() {
124124
mOutLine.ColorMaterial = irr::video::ECM_AMBIENT;
125125
mOutLine.DiffuseColor = 0xff000000;
126126
mOutLine.MaterialType = irr::video::EMT_TRANSPARENT_VERTEX_ALPHA;
127+
mOutLine.ZWriteEnable = irr::video::EZW_ON;
127128
mOutLine.Thickness = 2;
128129
mOutLine.setFlag(irr::video::EMF_LIGHTING, false);
129130
mOutLine.setFlag(irr::video::EMF_BACK_FACE_CULLING, false);

0 commit comments

Comments
 (0)