fix: color-op alpha (0x202/0x203/0x232) is TINT STRENGTH, not object opacity
Root cause (evidence: gfx-log) of the opening-CG grey background: a CG drawn with (alpha=0, color=white) means 'no tint' = fully opaque, but slice-A conflated the color alpha with object opacity -> the CG rendered transparent. RenderObject now carries TintStrength separately from Alpha (opacity); resolution keeps textured objects opaque. Tests updated to the evidence-based semantics. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -43,15 +43,17 @@ public class AnimInterpolatorTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ColorAnim_PingPongsAlphaTowardTarget()
|
||||
public void ColorAnim_PingPongsTintStrength_ObjectStaysOpaque()
|
||||
{
|
||||
var g = VisibleObj(0x100);
|
||||
// base = opaque white (no static color); target = alpha 0 (fade out) => pulses opaque<->transparent
|
||||
g.SetColorAnim(0x100, period: 1000, target: GfxState.PackColor(0x00, 0x000000));
|
||||
// base = no tint (strength 0); target = full-strength (alpha 0xff) red glow => strength pulses 0<->255
|
||||
g.SetColorAnim(0x100, period: 1000, target: GfxState.PackColor(0xFF, 0xFF0000));
|
||||
g.SnapshotVisibleObjects(0); // seeds start=0
|
||||
var opaque = g.SnapshotVisibleObjects(0).Single();
|
||||
Assert.Equal(255, opaque.Alpha); // t=0 -> base opaque
|
||||
var baseFrame = g.SnapshotVisibleObjects(0).Single();
|
||||
Assert.Equal(255, baseFrame.Alpha); // object opacity ALWAYS opaque (never the color alpha)
|
||||
Assert.Equal(0, baseFrame.TintStrength); // t=0 -> no tint
|
||||
var peak = g.SnapshotVisibleObjects(500).Single();
|
||||
Assert.Equal(0, peak.Alpha); // t=1 -> target alpha 0
|
||||
Assert.Equal(255, peak.Alpha); // still opaque
|
||||
Assert.Equal(255, peak.TintStrength); // t=1 -> full tint strength (the glow peak)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,25 +14,33 @@ public class RenderObjectBlendTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObjectWithoutColor_ResolvesOpaqueWhiteTint()
|
||||
public void ObjectWithoutColor_ResolvesOpaqueNoTint()
|
||||
{
|
||||
var g = WithVisibleObject(0x100, resId: 5, colorKey: -1);
|
||||
var ro = g.SnapshotVisibleObjects().Single();
|
||||
Assert.Equal(255, ro.Alpha);
|
||||
Assert.Equal(255, ro.Alpha); // opaque
|
||||
Assert.Equal(0, ro.TintStrength); // no tint
|
||||
Assert.Equal(0xFFFFFF, ro.Tint);
|
||||
Assert.Equal(BlendKind.Opaque, ro.Blend);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DrawColor_0x203_SetsAlphaTintAndBlend()
|
||||
public void DrawColor_0x203_IsTintStrength_ObjectStaysOpaque()
|
||||
{
|
||||
// Op 0x203/0x202 alpha is TINT-BLEND STRENGTH, not object opacity (evidence: a CG drawn with
|
||||
// (alpha=0, color=white) must stay fully OPAQUE + untinted, not vanish). Root cause of the grey-BG.
|
||||
var g = WithVisibleObject(0x100, resId: 5, colorKey: -1);
|
||||
// emulate op 0x203: pack (alpha=0x80, color=0x102030) and mark HasColor
|
||||
g.SetObjectColor(0x100, GfxState.PackColor(0x80, 0x102030));
|
||||
g.SetObjectColor(0x100, GfxState.PackColor(0x00, 0xFFFFFF)); // "no tint" — the grey-BG case
|
||||
var ro = g.SnapshotVisibleObjects().Single();
|
||||
Assert.Equal(0x80, ro.Alpha);
|
||||
Assert.Equal(0x102030, ro.Tint);
|
||||
Assert.Equal(BlendKind.Alpha, ro.Blend);
|
||||
Assert.Equal(255, ro.Alpha); // OBJECT STAYS OPAQUE (was wrongly 0 -> invisible)
|
||||
Assert.Equal(0, ro.TintStrength); // zero tint strength
|
||||
|
||||
g.SetObjectColor(0x100, GfxState.PackColor(0x80, 0x102030)); // half-strength tint toward 0x102030
|
||||
var ro2 = g.SnapshotVisibleObjects().Single();
|
||||
Assert.Equal(255, ro2.Alpha); // still opaque
|
||||
Assert.Equal(0x80, ro2.TintStrength); // strength from the alpha byte
|
||||
Assert.Equal(0x102030, ro2.Tint);
|
||||
Assert.Equal(BlendKind.Alpha, ro2.Blend);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user