Implement legacy black surface fades
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Age.Engine.Hosting;
|
||||
using Age.Engine.Model;
|
||||
using Age.Engine.Sys4;
|
||||
using Age.Engine.Vm;
|
||||
@@ -48,6 +49,31 @@ public class CoreScalarAndScreenTransitionOpsTests
|
||||
Assert.InRange(vm.Globals[0x100], 0, 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BlackSurfaceFades_ForwardCapturedSlotTimingAndDirection()
|
||||
{
|
||||
var table = OpcodeTableJson.Load(Paths.OpcodesJson);
|
||||
var script = ScriptAssembler.Assemble(table, "SURFACE_BLACK_FADES", new List<(int, Operand[])>
|
||||
{
|
||||
(0x21, new[] { new Operand(Imm, 1), new Operand(Imm, 30) }),
|
||||
(0x22, new[] { new Operand(Imm, 2), new Operand(Imm, 65) }),
|
||||
(0x2, Array.Empty<Operand>()),
|
||||
}, Array.Empty<string>());
|
||||
var host = new RecordingHost();
|
||||
|
||||
new VirtualMachine(script, table, host).Run();
|
||||
|
||||
Assert.Equal(
|
||||
new[]
|
||||
{
|
||||
(1, 30L, SurfaceBlackFadeDirection.FromBlack),
|
||||
(2, 65L, SurfaceBlackFadeDirection.ToBlack),
|
||||
},
|
||||
host.SurfaceBlackFades);
|
||||
Assert.Equal(480, LegacyScreenTransitionTiming.DurationMilliseconds(30));
|
||||
Assert.Equal(1024, LegacyScreenTransitionTiming.DurationMilliseconds(65));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CrossfadeSurfaces_ForwardsBothCapturedSlotsAndTimingArgument()
|
||||
{
|
||||
|
||||
@@ -53,6 +53,7 @@ internal class RecordingHost : IHost
|
||||
public readonly List<(long Resource, int Surface, long Flags)> ModalMovies = new();
|
||||
public readonly List<int> ClearedRenderTargets = new();
|
||||
public readonly List<(int First, int Count)> ReleasedSurfaceRanges = new();
|
||||
public readonly List<(int Surface, long Interval, SurfaceBlackFadeDirection Direction)> SurfaceBlackFades = new();
|
||||
public readonly List<(int Source, int Target, long Interval)> SurfaceCrossfades = new();
|
||||
public readonly List<(long Resource, int Slot)> Textures = new();
|
||||
public readonly List<bool> MessageSkipChanges = new();
|
||||
@@ -154,6 +155,9 @@ internal class RecordingHost : IHost
|
||||
gfx.StartForegroundTransitions(100);
|
||||
gfx.CompleteForegroundTransitions(100);
|
||||
}
|
||||
public void FadeSurfaceWithBlack(
|
||||
GfxState gfx, int surface, long intervalArgument, SurfaceBlackFadeDirection direction)
|
||||
=> SurfaceBlackFades.Add((surface, intervalArgument, direction));
|
||||
public void CrossfadeSurfaces(GfxState gfx, int sourceSurface, int targetSurface, long intervalArgument)
|
||||
=> SurfaceCrossfades.Add((sourceSurface, targetSurface, intervalArgument));
|
||||
public void CreateTexture(int slot, int w, int h) { }
|
||||
|
||||
@@ -28,6 +28,12 @@ public readonly record struct SurfaceRectCopy(
|
||||
int SourceSurface, int DestinationSurface, int SourceX, int SourceY,
|
||||
int Width, int Height, int DestinationX, int DestinationY);
|
||||
|
||||
public enum SurfaceBlackFadeDirection
|
||||
{
|
||||
FromBlack,
|
||||
ToBlack,
|
||||
}
|
||||
|
||||
public interface IHost
|
||||
{
|
||||
/// <summary>Report a recoverable runtime discrepancy while allowing script execution to continue.</summary>
|
||||
@@ -103,8 +109,10 @@ public interface IHost
|
||||
// read/message-skip branch reaches op 0x20c and presents the completed endpoint immediately.
|
||||
void WaitForForegroundTransition(GfxState gfx) { }
|
||||
void PresentFrame(GfxState gfx) { }
|
||||
// Legacy SYS4 screen-transition family (op 0x25): scripts render two complete frames into
|
||||
// numbered surfaces, then block while the engine alpha-composites target over source.
|
||||
// Legacy SYS4 screen-transition family (ops 0x21, 0x22, and 0x25): scripts render complete
|
||||
// frames into numbered surfaces, then block while the engine alpha-composites an endpoint.
|
||||
void FadeSurfaceWithBlack(
|
||||
GfxState gfx, int surface, long intervalArgument, SurfaceBlackFadeDirection direction) { }
|
||||
void CrossfadeSurfaces(GfxState gfx, int sourceSurface, int targetSurface, long intervalArgument) { }
|
||||
void CreateTexture(int slot, int width, int height);
|
||||
/// <summary>Return a stable RGBA snapshot of one numbered surface, or null when unavailable.</summary>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Age.Engine.Model;
|
||||
|
||||
/// <summary>Native timing conversion shared by the legacy op-0x25 screen-transition family.</summary>
|
||||
/// <summary>Native timing conversion shared by the legacy full-frame screen-transition family.</summary>
|
||||
public static class LegacyScreenTransitionTiming
|
||||
{
|
||||
public static long DurationMilliseconds(long argument)
|
||||
|
||||
@@ -2657,6 +2657,16 @@ public sealed class VirtualMachine
|
||||
Read(a[4]), (int)Read(a[5]), Read(a[6]), Read(a[7])); return pc + 1;
|
||||
case "present-frame": // 0x20c: read/message-skip path snaps a queued transition to its endpoint
|
||||
_host.PresentFrame(Gfx); return pc + 1;
|
||||
case "fade-surface-in-from-black": // 0x21: blocking black -> captured full-frame surface
|
||||
case "u00418860":
|
||||
_host.FadeSurfaceWithBlack(
|
||||
Gfx, (int)Read(a[0]), Read(a[1]), SurfaceBlackFadeDirection.FromBlack);
|
||||
return pc + 1;
|
||||
case "fade-surface-out-to-black": // 0x22: blocking captured full-frame surface -> black
|
||||
case "u00418920":
|
||||
_host.FadeSurfaceWithBlack(
|
||||
Gfx, (int)Read(a[0]), Read(a[1]), SurfaceBlackFadeDirection.ToBlack);
|
||||
return pc + 1;
|
||||
case "crossfade-surfaces": // 0x25: legacy full-frame surface alpha transition
|
||||
case "u00418B40":
|
||||
_host.CrossfadeSurfaces(Gfx, (int)Read(a[0]), (int)Read(a[1]), Read(a[2]));
|
||||
|
||||
Reference in New Issue
Block a user