port EterLib/GrpShadowTexture verbatim; D3D top-left fill rule for the shadow target (unit C/D)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-28 13:05:55 +09:00
co-authored by Claude Opus 5.5
parent 5be37b6363
commit 86e602cb32
6 changed files with 281 additions and 62 deletions
@@ -642,14 +642,22 @@ private:
const int y0 = std::max(0, int(std::floor(std::min({a.y, b.y, c.y}))));
const int x1 = std::min(width - 1, int(std::ceil(std::max({a.x, b.x, c.x}))));
const int y1 = std::min(height - 1, int(std::ceil(std::max({a.y, b.y, c.y}))));
// D3D top-left fill rule: a pixel centre exactly on an edge is covered only when that edge
// is a left edge (weight grows to the right) or a top edge (horizontal, weight grows downward).
auto top_left = [area](const Point& p, const Point& q) {
const float dx = (q.y - p.y) / area, dy = (p.x - q.x) / area;
return dx > 0.0f || (dx == 0.0f && dy > 0.0f);
};
const bool tlA = top_left(b, c), tlB = top_left(c, a), tlC = top_left(a, b);
auto covered = [](float w, bool tl) { return w > 0.0f || (w == 0.0f && tl); };
for (int y = y0; y <= y1; ++y)
for (int x = x0; x <= x1; ++x)
{
const float px = float(x) + 0.5f, py = float(y) + 0.5f;
const float wa = edge(b, c, px, py) / area;
const float wb = edge(c, a, px, py) / area;
const float wc = 1.0f - wa - wb;
if (wa < 0.0f || wb < 0.0f || wc < 0.0f) continue;
const float wc = edge(a, b, px, py) / area;
if (!covered(wa, tlA) || !covered(wb, tlB) || !covered(wc, tlC)) continue;
const float z = wa * a.z + wb * b.z + wc * c.z;
const size_t pixel = size_t(y) * width + x;
if (z < 0.0f || z > 1.0f || z > m_offscreenDepth[pixel]) continue;