Render DEBUGMAP tiled field surfaces

This commit is contained in:
gamer147
2026-07-21 13:02:02 -04:00
parent d5f69853d5
commit ff39c7f3f9
14 changed files with 465 additions and 112 deletions

View File

@@ -81,6 +81,22 @@ public class AgfDecoderTests
Assert.Contains(image.Pixels.Where((_, i) => (i & 3) == 3), a => a is > 0 and < 255);
}
[Theory]
[InlineData(0x32da, "SO005.AGF")]
[InlineData(0x32db, "SO007.AGF")]
[InlineData(0x32dc, "SO008A.AGF")]
[InlineData(0x32dd, "SO007A.AGF")]
public void InstalledFieldMapSheetsResolveAndDecodeByRawCatalogIndex(int rawId, string name)
{
var resources = ResourceMap.Load();
var asset = resources.ResolveRawTexture(rawId);
Assert.NotNull(asset);
Assert.Equal(name, asset.Name);
var image = resources.DecodeTexture(asset);
Assert.True(image.Width > 0);
Assert.True(image.Height > 0);
}
private sealed class MemoryStore(byte[] bytes) : IAssetStore
{
public Stream Open(AssetEntry entry) => new MemoryStream(bytes, writable: false);

View File

@@ -102,6 +102,8 @@ public class GfxCommandBufferTests
=> (0x1fb, new[] { G(handle), G(slot), I(0), I(0), G(w), G(h), G(dx), G(dy) });
private static (int, Operand[]) SetTex(int resId, int slot) => (0x1f9, new[] { G(resId), G(slot), I(0) });
private static (int, Operand[]) SetRawTex(long resId, long slot, long colorKey)
=> (0x249, new[] { I(resId), I(slot), I(colorKey) });
[Fact]
public void SetThenDrawTextureMakesAVisibleObjectFromTheSurface()
@@ -122,4 +124,26 @@ public class GfxCommandBufferTests
Assert.Equal(0x25, vis[0].SurfaceResId); // resolved from the object's live source slot
Assert.Equal((800, 600, 0, 0), (vis[0].W, vis[0].H, vis[0].DstX, vis[0].DstY));
}
[Fact]
public void RawTextureLoadBypassesSceneResourceNormalizationAndFeedsRetainedDraws()
{
var t = T();
var scene = ScriptAssembler.Assemble(t, "RAW-GFX", new List<(int, Operand[])>
{
SetRawTex(0x32da, 0x3e, 0),
(0x1fb, new[] { I(0x100), I(0x3e), I(0), I(0), I(100), I(100), I(20), I(30) }),
Exit(),
}, System.Array.Empty<string>());
var host = new RecordingHost { TextureResourceIdOffset = 0x1000 };
var vm = new VirtualMachine(scene, t, host);
vm.Run();
Assert.Equal((0x32daL, 0x3e), Assert.Single(host.Textures));
var visible = Assert.Single(vm.Gfx.SnapshotVisibleObjects());
Assert.Equal(0x32da, visible.SurfaceResId);
Assert.Equal(0, visible.ColorKey);
Assert.Equal((100, 100, 20, 30), (visible.W, visible.H, visible.DstX, visible.DstY));
}
}

View File

@@ -0,0 +1,76 @@
using System.Collections.Generic;
using System.Linq;
using Age.Engine.Model;
using Age.Engine.Sys4;
using Age.Engine.Vm;
using Xunit;
public class GfxRangeTransformTests
{
[Fact]
public void RangeCameraCentersItsAnchorAndLeavesUiHandlesUnchanged()
{
var gfx = new GfxState();
gfx.SetSurface(1, 1, -1);
gfx.BindDraw(10, 1, 0, 0, 1, 1, 500, 350); // selected map object at the camera anchor
gfx.BindDraw(20, 1, 0, 0, 1, 1, 500, 350); // screen-fixed UI object outside the range
gfx.SetRangeTransform(10, 1, (500, 350, 0));
gfx.SetRangeTranslationCurrent((-100, -50, 0));
gfx.SetRangeScaleCurrent((150, 150, 100));
var objects = gfx.SnapshotVisibleObjects();
var map = objects.Single(x => x.Handle == 10);
var ui = objects.Single(x => x.Handle == 20);
var mapOrigin = Transform2DMath.Build(map.Transform).FromLocalOrigin(map.DstX, map.DstY)
.Then(map.RangeTransform!.Value).Apply(0, 0);
var uiOrigin = Transform2DMath.Build(ui.Transform).FromLocalOrigin(ui.DstX, ui.DstY).Apply(0, 0);
Assert.Equal((400.0, 300.0), mapOrigin);
Assert.Null(ui.RangeTransform);
Assert.Equal((500.0, 350.0), uiOrigin);
}
[Fact]
public void RangeScaleTargetUsesTheOrdinaryOneShotClock()
{
var gfx = new GfxState();
gfx.SetSurface(1, 1, -1);
gfx.BindDraw(10, 1, 0, 0, 1, 1, 410, 300);
gfx.SetRangeTransform(10, 1, (400, 300, 0));
gfx.SetRangeScaleCurrent((100, 100, 100));
gfx.SetRangeScaleChannel(delayMs: 0, durationMs: 300, percent: (200, 200, 100));
gfx.SnapshotVisibleObjects(1000); // seeds the native-style shared channel start
var halfway = gfx.SnapshotVisibleObjects(1150).Single();
var p = Transform2DMath.Build(halfway.Transform).FromLocalOrigin(halfway.DstX, halfway.DstY)
.Then(halfway.RangeTransform!.Value).Apply(0, 0);
Assert.Equal((415.0, 300.0), p);
Assert.True(gfx.HasActiveTimedPresentation(1150));
gfx.SnapshotVisibleObjects(1300);
Assert.False(gfx.HasActiveTimedPresentation(1300));
}
[Fact]
public void Opcode229SelectsRangeWithoutCreatingAnOrdinaryObject()
{
var table = OpcodeTableJson.Load(Paths.OpcodesJson);
var script = ScriptAssembler.Assemble(table, "RANGE", new List<(int, Operand[])>
{
(0x229, new[] { I(1), I(100), I(400), I(300), I(0) }),
(0x22c, new[] { I(0), I(0), I(0) }),
(0x22a, new[] { I(100), I(100), I(100) }),
(0x2, System.Array.Empty<Operand>()),
}, System.Array.Empty<string>());
var vm = new VirtualMachine(script, table, new RecordingHost());
vm.Run();
Assert.Null(vm.Gfx.TryGet(1));
vm.Gfx.SetSurface(1, 1, -1);
vm.Gfx.BindDraw(1, 1, 0, 0, 1, 1, 400, 300);
Assert.NotNull(vm.Gfx.SnapshotVisibleObjects().Single().RangeTransform);
}
private static Operand I(long v) => new(0, v);
}

View File

@@ -42,12 +42,15 @@ internal class RecordingHost : IHost
public readonly List<int> ClearedRenderTargets = new();
public readonly List<(int First, int Count)> ReleasedSurfaceRanges = 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();
public readonly List<bool> PhysicalMessageSkipChanges = new();
public readonly List<long> CursorResources = new();
public readonly List<bool> AdvPagePresentationSuspended = new();
public int CursorClearCount;
public int SceneContextResets;
public long TextureResourceIdOffset;
public long ResolveTextureResourceId(long resourceId) => resourceId + TextureResourceIdOffset;
public void ShowText(int offset, string text) => Lines.Add((offset, text));
public void SetAdvTextCursor(int layoutSlot, int x, int y) => TextCursors.Add((layoutSlot, x, y));
public void DrawStringToSurface(int surfaceSlot, int x, int y, string text)
@@ -123,7 +126,7 @@ internal class RecordingHost : IHost
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) { }
public void SetTexture(long resId, int slot) { }
public void SetTexture(long resId, int slot) => Textures.Add((resId, slot));
public void ClearRenderTarget(int surfaceSlot) => ClearedRenderTargets.Add(surfaceSlot);
public void ReleaseSurfaceRange(int firstSlot, int count) => ReleasedSurfaceRanges.Add((firstSlot, count));
public void DrawTexture(int slot, int sx, int sy, int w, int h, int dx, int dy) { }