diff --git a/Services/Compositor/SceneCompositor.cs b/Services/Compositor/SceneCompositor.cs index 33a9e51..c5d1bfa 100644 --- a/Services/Compositor/SceneCompositor.cs +++ b/Services/Compositor/SceneCompositor.cs @@ -545,27 +545,57 @@ public sealed class SceneCompositor var s = src.BgraPixels; var srcStride = src.Width; // canvas stride in pixels (not bytes) + // Build horizontal LUT for scaled blit to reduce per-pixel divides + var lutCount = x1 - x0 + 1; + var sxLut = new float[lutCount]; + var pxBase = x0 - ex; + for (var xi = 0; xi < lutCount; xi++) + { + var px = pxBase + xi; + float sxCanvas; + if (px < ox || px > ox + drawnW) + { + sxCanvas = float.NaN; + } + else + { + var sxNorm = (px - ox) / drawnW; + sxNorm = sxNorm < 0f ? 0f : sxNorm > 1f ? 1f : sxNorm; + var sxCrop = sxNorm * cbW; + sxCanvas = cbX + sxCrop; + if (sxCanvas < 0f) sxCanvas = 0f; + if (sxCanvas > src.Width - 1f) sxCanvas = src.Width - 1f; + if (isMirror) sxCanvas = src.Width - 1f - sxCanvas; + } + sxLut[xi] = sxCanvas; + } + for (var y = y0; y <= y1; y++) { var py = y - ey; if (py < oy || py > oy + drawnH) continue; // syNorm: normalized [0,1] position within the drawn content (vertically) - var syNorm = Math.Clamp((py - oy) / drawnH, 0f, 1f); + var syNorm = (py - oy) / drawnH; + if (syNorm < 0f) syNorm = 0f; + if (syNorm > 1f) syNorm = 1f; // syCrop: pixel position within the crop region var syCrop = syNorm * cbH; // syCanvas: canvas pixel row (for buffer indexing) - var syCanvas = Math.Clamp(cbY + syCrop, 0f, src.Height - 1f); + var syCanvas = cbY + syCrop; + if (syCanvas < 0f) syCanvas = 0f; + if (syCanvas > src.Height - 1f) syCanvas = src.Height - 1f; var syi = (int)syCanvas; var sy1i = Math.Min(syi + 1, src.Height - 1); var fy8 = (int)((syCanvas - syi) * 256); var fyInv = 256 - fy8; var di = (y * dstW + x0) * 4; - for (var x = x0; x <= x1; x++, di += 4) + for (var xi = 0; xi < lutCount; xi++, di += 4) { - var px = x - ex; - if (px < ox || px > ox + drawnW) continue; + var sxCanvas = sxLut[xi]; + if (float.IsNaN(sxCanvas)) continue; + var px = pxBase + xi; if (isRound) { var dx = px - cx; @@ -573,13 +603,6 @@ public sealed class SceneCompositor if (dx * dx + dy * dy > radius * radius) continue; } - // sxNorm: normalized [0,1] position within the drawn content (horizontally) - var sxNorm = Math.Clamp((px - ox) / drawnW, 0f, 1f); - // sxCrop: pixel position within the crop region - var sxCrop = sxNorm * cbW; - // sxCanvas: canvas pixel column (for buffer indexing) - var sxCanvas = Math.Clamp(cbX + sxCrop, 0f, src.Width - 1f); - if (isMirror) sxCanvas = src.Width - 1 - sxCanvas; var sxi = (int)sxCanvas; var sx1i = Math.Min(sxi + 1, src.Width - 1); var fx8 = (int)((sxCanvas - sxi) * 256);