feat(render): Campaign V slice V4a - port TextRenderer/BitmapFont/DebugLineRenderer/TextureCache onto IGpuDevice
TextRenderer, BitmapFont, DebugLineRenderer, and TextureCache's UI-texture
upload path (GetOrUploadRenderSurface/UploadRgba8) now issue every draw and
resource creation through the pinned IGpuDevice/IGpuFrame/IGpuPassEncoder
RHI contract instead of raw GL. This is the RHI's first real production
consumer - V0-V3 only established the contract, GL backend skeleton, and a
shader-dialect migration with no live GL exercise. TextRenderer owns one
IGpuPipeline (ui_text shader, straight-alpha blend, depth disabled) and
allocates a per-bucket ring each Flush; BitmapFont's atlas texture is
created and uploaded via device.CreateTexture/.Upload; DebugLineRenderer
mirrors the same one-pipeline-per-Flush shape for its line-list draws.
World-path TextureCache methods (GetOrUpload, the raw-GL layer-array
upload) are untouched - still legacy GL, still out of scope.
Frame lifecycle: GpuDeviceFrameLifetime (RenderFrameOrchestrator.cs) wraps
IGpuDevice.BeginFrame()/IGpuFrame.End() inside the existing
IRenderFrameLifetime bracket HostInputCameraCompositionPhase already opens
per callback, additively - no frame-graph restructuring. Ported renderers
reach the frame via ICurrentGpuFrameSource, a plain interface (not a
delegate field) so WorldSceneDiagnosticsController keeps passing its
existing "no stored window/delegate" architectural-conformance test.
Two real bugs surfaced by actually exercising the RHI against a live GL
context (nothing here was previously reachable before this slice):
- GlGpuDevice.BeginFrame() now resets the render-state cache every frame.
The cache assumes it is the sole writer of GL program/blend/depth/cull
state, which was true while it had zero real consumers, but every
still-legacy renderer (WbDrawDispatcher, terrain, particles, EnvCells)
mutates that same GL state directly and never informs the cache. Once a
legacy renderer ran between two RHI binds, the cache's belief about the
current GL program went stale, so a later BindPipeline(text shader)
skipped re-issuing glUseProgram and the following push-constant upload
threw GL_INVALID_OPERATION against whatever program was actually bound.
Reset() at the frame boundary is the same defensive move BeginPass
already makes after a forced clear (see its comment); it costs one
redundant state application on the frame's first bind.
- GL_MULTISAMPLE has no representation in the pinned contract. Added a
GL-backend-internal Multisample field to GlRenderStateSnapshot/Changes,
computed from GpuPipelineDescription.SampleCount at BindPipeline time -
mirrors how Vulkan bakes MSAA into the pipeline instead of a separate
toggle.
Collateral, scoped to keep the port real rather than a stub:
- GpuTextureSlot (Unassigned = uint.MaxValue, NOT 0) now flows through
every consumer of TextureCache.GetOrUploadRenderSurface/UploadRgba8 and
TextRenderer.DrawSprite - the entire retained UI layer, since a pervasive
Func<uint,(uint,int,int)> sprite-resolve delegate threads through nearly
every UI element/controller. Every prior `== 0` / `!= 0` "no texture"
check became `.IsAssigned` / `!.IsAssigned`; slot 0 is a real assigned
slot (the device's default white texture), so the old sentinel would
have produced live visual regressions if left in place.
- GpuTextureSlot/IGpuDevice/IGpuFrame are internal, so ~270 previously
public AcDream.App types that touched them (directly or transitively)
are now internal too - safe, since AcDream.App is an exe with no
external project references; only the two test projects consume it, via
InternalsVisibleTo. A handful of unrelated types the sweep caught
(ElementInfo/ImportedLayout's property-bag hierarchy, several enums used
as public [Theory] parameters, CursorFeedbackSnapshot's DragAcceptState)
were reverted back to public where making them internal would have
either cascaded into unrelated files or broken xUnit's public-member
discovery.
- ExternalViewportTextureBridge (new) registers the still-raw-GL FBO
color textures PrivateEntityViewportRenderer/PaperdollViewportRenderer
produce (V4g's scope) into the device's texture table for
UiViewport.TextureHandle, via a temporary
GlGpuDevice.RegisterExternalColorTexture escape hatch (internal, not
part of IGpuDevice) deleted when V4g ports those viewports.
- TextRenderGlStateScope.cs and its test deleted: the pipeline description
now bakes what it used to restore by hand.
- ResourceCleanupGroupTests/GlTextureOwnershipTests: the two source-text
conformance tests keyed to TextRenderer's old multi-resource
construction shape (Shader + per-flight FrameBufferSet array + white
texture + tracked VAO/VBO, all via ResourceCleanupGroup) no longer apply
- that shape is gone, replaced by one IGpuPipeline created through
IGpuDevice. The construction-order test is deleted; the checked-commit
texture-creation check now targets GlGpuTexture (which already used
the same GlResourceCommand.CreateName primitive before this slice).
Gates:
- dotnet build -c Release: 0 warnings, 0 errors (AcDream.App has
TreatWarningsAsErrors).
- dotnet test tests/AcDream.App.Tests -c Release: 3,840 passed / 3
skipped (was 3,843/3 entering this slice - net 3 fewer tests:
TextRendererFailureSafetyTests.cs deleted (2, tested the now-deleted
TextRenderGlStateScope) plus the one retired ResourceCleanupGroupTests
method). Full solution: 8,908 passed / 5 skipped across all nine test
projects.
- Offline pixel gate (tools/run-offline-pixel-gate.ps1, parent ec414d60
vs this commit): differing fraction 0.318% (1,791/563,200 compared
pixels), above the 0.001 threshold. Investigated pixel-by-pixel rather
than waved through: a diff heatmap plus 4x crops at the differing
clusters show zero differences anywhere in the retained UI, terrain,
scenery, or static meshes - every differing pixel sits on continuously-
animated ambient content (flying-insect sprites over the swamp, foliage
sparkle/dew glints) whose exact phase depends on elapsed wall-clock
time, the same category the gate's own sky-masking rationale already
documents and the campaign doc's coverage table explicitly excludes
("Not covered - particles"). Confirming evidence: two same-commit
captures at HEAD compare clean against each other (0.0025%), and two
same-commit captures at the parent compare clean against each other
(0.0044%) - only base-vs-head is consistently elevated, which is what
frame-pacing drift from genuinely new per-frame RHI work (BeginFrame,
ring resets, the render-state reset above) would produce against a
fixed wall-clock capture deadline, not a rendering defect. Recommend a
quick user visual check of this capture pair alongside the automated
result, matching how V2c's particle work was already handled in this
campaign (flagged for user visual confirmation rather than blocked on
an automated gate that cannot cover animated content).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
ec414d60cd
commit
ceec3bc440
334 changed files with 3660 additions and 3840 deletions
|
|
@ -159,6 +159,7 @@ public sealed class HostInputCameraCompositionTests
|
|||
{
|
||||
public GpuFrameFlightController? GpuFrames { get; private set; }
|
||||
public IGpuDevice? GpuDevice { get; private set; }
|
||||
public GpuDeviceFrameLifetime? GpuFrameLifetime { get; private set; }
|
||||
public SilkKeyboardSource? Keyboard { get; private set; }
|
||||
public SilkMouseSource? Mouse { get; private set; }
|
||||
public IMouseLookCursor? Cursor { get; private set; }
|
||||
|
|
@ -172,6 +173,9 @@ public sealed class HostInputCameraCompositionTests
|
|||
public void PublishGpuDevice(IGpuDevice value) =>
|
||||
GpuDevice = PublishOnce(GpuDevice, value);
|
||||
|
||||
public void PublishGpuFrameLifetime(GpuDeviceFrameLifetime value) =>
|
||||
GpuFrameLifetime = PublishOnce(GpuFrameLifetime, value);
|
||||
|
||||
public void PublishKeyboardSource(SilkKeyboardSource value) =>
|
||||
Keyboard = PublishOnce(Keyboard, value);
|
||||
|
||||
|
|
|
|||
|
|
@ -189,9 +189,10 @@ public sealed class InteractionRetainedUiCompositionTests
|
|||
Dependencies = new InteractionRetainedUiDependencies(
|
||||
Options: options,
|
||||
Gl: null!,
|
||||
GpuDevice: null!,
|
||||
CurrentGpuFrame: null!,
|
||||
Window: null!,
|
||||
Input: null!,
|
||||
ShadersDirectory: "shaders",
|
||||
Dats: null!,
|
||||
DatLock: new object(),
|
||||
TextureCache: null!,
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ public sealed class SettingsDevToolsCompositionTests
|
|||
null!,
|
||||
null!,
|
||||
null!,
|
||||
null!,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ using System.Collections.Concurrent;
|
|||
using System.Runtime.CompilerServices;
|
||||
using AcDream.App.Composition;
|
||||
using AcDream.App.Rendering;
|
||||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.Rendering.Wb;
|
||||
using AcDream.App.Rendering.Residency;
|
||||
using AcDream.App.Tests.Rendering.Gpu;
|
||||
using AcDream.App.World;
|
||||
using AcDream.Content;
|
||||
using AcDream.Core.Physics;
|
||||
|
|
@ -159,6 +161,7 @@ public sealed class WorldRenderCompositionTests
|
|||
Factory = new Factory(hasFont);
|
||||
Publication = new Publication(publicationFailure);
|
||||
Lifetime = new RenderLifetime(Factory.Atlas);
|
||||
GpuDevice = new RecordingGpuDevice();
|
||||
var content = (ContentEffectsAudioResult)
|
||||
RuntimeHelpers.GetUninitializedObject(typeof(ContentEffectsAudioResult));
|
||||
Content = content;
|
||||
|
|
@ -167,6 +170,7 @@ public sealed class WorldRenderCompositionTests
|
|||
public Factory Factory { get; }
|
||||
public Publication Publication { get; }
|
||||
public RenderLifetime Lifetime { get; }
|
||||
public RecordingGpuDevice GpuDevice { get; }
|
||||
public List<WorldRenderCompositionPoint> Points { get; } = [];
|
||||
public ContentEffectsAudioResult Content { get; }
|
||||
|
||||
|
|
@ -176,6 +180,7 @@ public sealed class WorldRenderCompositionTests
|
|||
new WorldEnvironmentController(),
|
||||
Lifetime,
|
||||
ImmediateGpuResourceRetirementQueue.Instance,
|
||||
GpuDevice,
|
||||
_budgets,
|
||||
0xA9B4FFFFu,
|
||||
Path.Combine(Path.GetTempPath(), "acdream-tests"),
|
||||
|
|
@ -248,15 +253,15 @@ public sealed class WorldRenderCompositionTests
|
|||
public SceneLightingUboBinding CreateSceneLighting(GL gl) =>
|
||||
Resource<SceneLightingUboBinding>("scene lighting");
|
||||
|
||||
public DebugLineRenderer CreateDebugLines(GL gl, string shadersDirectory) =>
|
||||
public DebugLineRenderer CreateDebugLines(IGpuDevice device) =>
|
||||
Resource<DebugLineRenderer>("debug lines");
|
||||
|
||||
public byte[]? TryLoadDebugFont() => hasFont ? [1] : null;
|
||||
|
||||
public BitmapFont CreateDebugFont(GL gl, byte[] bytes) =>
|
||||
public BitmapFont CreateDebugFont(IGpuDevice device, byte[] bytes) =>
|
||||
Resource<BitmapFont>("debug font");
|
||||
|
||||
public TextRenderer CreateTextRenderer(GL gl, string shadersDirectory) =>
|
||||
public TextRenderer CreateTextRenderer(IGpuDevice device) =>
|
||||
Resource<TextRenderer>("text renderer");
|
||||
|
||||
public TerrainModernRenderer CreateTerrain(
|
||||
|
|
@ -295,6 +300,7 @@ public sealed class WorldRenderCompositionTests
|
|||
|
||||
public TextureCache CreateTextureCache(
|
||||
GL gl,
|
||||
IGpuDevice device,
|
||||
IDatReaderWriter dats,
|
||||
BindlessSupport bindless,
|
||||
IGpuResourceRetirementQueue retirement,
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@ global using AcDream.Runtime.Gameplay;
|
|||
global using AcDream.Runtime.Physics;
|
||||
global using ILocalPlayerMotionSource =
|
||||
AcDream.Runtime.Gameplay.IRuntimeLocalPlayerMotionSource;
|
||||
global using AcDream.App.Rendering.Gpu;
|
||||
|
|
|
|||
|
|
@ -104,8 +104,13 @@ public sealed class GlTextureOwnershipTests
|
|||
root, "src", "AcDream.App", "Rendering", "ShaderProgramConstruction.cs"));
|
||||
string terrain = File.ReadAllText(Path.Combine(
|
||||
root, "src", "AcDream.App", "Rendering", "TerrainAtlas.cs"));
|
||||
string text = File.ReadAllText(Path.Combine(
|
||||
root, "src", "AcDream.App", "Rendering", "TextRenderer.cs"));
|
||||
// Campaign V slice V4a ported TextRenderer/BitmapFont off raw GL onto
|
||||
// IGpuDevice: neither file creates a GL texture name directly anymore.
|
||||
// The checked-commit-boundary invariant this test enforces now lives in
|
||||
// the RHI's GlGpuTexture, which every ported (and legacy) texture path
|
||||
// shares.
|
||||
string gpuTexture = File.ReadAllText(Path.Combine(
|
||||
root, "src", "AcDream.App", "Rendering", "Gpu", "Gl", "GlGpuTexture.cs"));
|
||||
string bindless = File.ReadAllText(Path.Combine(
|
||||
root, "src", "AcDream.App", "Rendering", "Wb", "BindlessSupport.cs"));
|
||||
|
||||
|
|
@ -116,8 +121,8 @@ public sealed class GlTextureOwnershipTests
|
|||
Assert.Contains("GlResourceCommand.DeleteProgram", shaderPrograms, StringComparison.Ordinal);
|
||||
Assert.Contains("_anisotropyBindingMutation.Execute", terrain, StringComparison.Ordinal);
|
||||
Assert.Contains("GlResourceCommand.DeleteTexture", terrain, StringComparison.Ordinal);
|
||||
Assert.Contains("GlResourceCommand.CreateTexture", text, StringComparison.Ordinal);
|
||||
Assert.Contains("GlResourceCommand.Execute", text, StringComparison.Ordinal);
|
||||
Assert.Contains("GlResourceCommand.CreateName", gpuTexture, StringComparison.Ordinal);
|
||||
Assert.Contains("GLHelpers.ThrowOnResourceError", gpuTexture, StringComparison.Ordinal);
|
||||
Assert.Contains("make bindless handle", bindless, StringComparison.Ordinal);
|
||||
Assert.Contains("GlResourceCommand.Execute", bindless, StringComparison.Ordinal);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ public sealed class GlRenderStateCacheTests
|
|||
GpuCullMode.Back,
|
||||
GpuFrontFace.CounterClockwise,
|
||||
AlphaToCoverage: false,
|
||||
ColorWrite: true);
|
||||
ColorWrite: true,
|
||||
Multisample: false);
|
||||
|
||||
[Fact]
|
||||
public void FirstApplyReportsEveryDimensionChanged()
|
||||
|
|
|
|||
|
|
@ -49,6 +49,12 @@ public sealed class RenderFrameResourceControllerTests
|
|||
{
|
||||
string source = ResourceSource();
|
||||
|
||||
// TextRenderer (_worldText/_uiText) moved onto the IGpuDevice/IGpuFrame
|
||||
// RHI in Campaign V slice V4a: it no longer has a per-slot BeginFrame
|
||||
// step, so those two needles are retired from this ordering check.
|
||||
// The remaining GL-only renderers (WbDrawDispatcher, EnvCellRenderer,
|
||||
// terrain, sky/lighting) are untouched by V4a and keep their slot-based
|
||||
// BeginFrame(gpuSlot) order.
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"_textures?.BeginCompositeTextureFrame();",
|
||||
|
|
@ -56,8 +62,6 @@ public sealed class RenderFrameResourceControllerTests
|
|||
"_dispatcher?.BeginFrame(gpuSlot);",
|
||||
"_environmentCells?.BeginFrame(gpuSlot);",
|
||||
"_portalDepth?.BeginFrame(gpuSlot);",
|
||||
"_worldText?.BeginFrame(gpuSlot);",
|
||||
"_uiText?.BeginFrame(gpuSlot);",
|
||||
"_clip?.BeginFrame(gpuSlot);",
|
||||
"_terrain?.BeginFrame(gpuSlot);",
|
||||
"_lighting?.BeginFrame(gpuSlot);");
|
||||
|
|
|
|||
|
|
@ -130,40 +130,13 @@ public sealed class ResourceCleanupGroupTests
|
|||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TextRendererPublishesEveryConstructorResourceBeforeLaterGlWork()
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Rendering",
|
||||
"TextRenderer.cs"));
|
||||
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"shader = new Shader(gl,",
|
||||
"resources.Add(\"text shader\", shader.Dispose);",
|
||||
"frameBuffers[i] = CreateFrameBufferSet(resources);",
|
||||
"whiteTexture = GlResourceCommand.CreateTexture(",
|
||||
"resources.Add(",
|
||||
"\"white texture\"",
|
||||
"GlResourceCommand.Execute(",
|
||||
"initialize TextRenderer white texture",
|
||||
"resources.RetryCleanup();",
|
||||
"_resources = resources;");
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"private FrameBufferSet CreateFrameBufferSet(ResourceCleanupGroup resources)",
|
||||
"TrackedGlResource.CreateVertexArray(",
|
||||
"resources.Add(\"frame VAO\", vaoRelease.Run);",
|
||||
"TrackedGlResource.CreateBuffer(",
|
||||
"resources.Add(",
|
||||
"\"frame VBO\"");
|
||||
Assert.Contains("_resources.RetryCleanup();", source, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("private FrameBufferSet CreateFrameBufferSet()", source,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
// TextRendererPublishesEveryConstructorResourceBeforeLaterGlWork was retired
|
||||
// by Campaign V slice V4a: TextRenderer no longer owns a Shader, per-flight
|
||||
// FrameBufferSet array, white-texture fallback, or tracked VAO/VBO pair —
|
||||
// it now borrows a shared IGpuDevice and owns exactly one IGpuPipeline
|
||||
// created through it, so there is no multi-resource construction order left
|
||||
// to assert. The equivalent GL-only invariant now lives in GlTextureOwnershipTests
|
||||
// (GlGpuTexture's checked-commit texture creation).
|
||||
|
||||
[Fact]
|
||||
public void ReturnedNameIsRetainedWhenPostconditionAndFirstRollbackFail()
|
||||
|
|
|
|||
|
|
@ -1,217 +0,0 @@
|
|||
using System.Reflection;
|
||||
using AcDream.App.Rendering;
|
||||
using Silk.NET.OpenGL;
|
||||
|
||||
namespace AcDream.App.Tests.Rendering;
|
||||
|
||||
public sealed class TextRendererFailureSafetyTests
|
||||
{
|
||||
[Fact]
|
||||
public void Flush_CompilesCompleteGlStateScopeAsFinallyAroundBothDrawLayers()
|
||||
{
|
||||
MethodInfo flush = typeof(TextRenderer).GetMethod(nameof(TextRenderer.Flush))!;
|
||||
MethodBody body = flush.GetMethodBody()!;
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Rendering",
|
||||
"TextRenderer.cs"));
|
||||
|
||||
Assert.Contains(
|
||||
body.ExceptionHandlingClauses,
|
||||
clause => clause.Flags == ExceptionHandlingClauseOptions.Finally);
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"using var stateScope = new TextRenderGlStateScope(_glState);",
|
||||
"_gl.Disable(EnableCap.Multisample);",
|
||||
"DrawLayer(_spriteSegs,",
|
||||
"DrawLayer(_overlaySpriteSegs,");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FailedDraw_RestoresEveryGlValueMutatedByTheTextPass()
|
||||
{
|
||||
var gl = new RecordingGlState
|
||||
{
|
||||
DepthWrite = false,
|
||||
BlendSourceRgb = BlendingFactor.DstAlpha,
|
||||
BlendDestinationRgb = BlendingFactor.OneMinusDstAlpha,
|
||||
BlendSourceAlpha = BlendingFactor.One,
|
||||
BlendDestinationAlpha = BlendingFactor.Zero,
|
||||
Program = 17,
|
||||
VertexArray = 23,
|
||||
ArrayBuffer = 31,
|
||||
ActiveUnit = TextureUnit.Texture2,
|
||||
};
|
||||
gl.SetCapability(EnableCap.DepthTest, enabled: true);
|
||||
gl.SetCapability(EnableCap.Blend, enabled: false);
|
||||
gl.SetCapability(EnableCap.CullFace, enabled: true);
|
||||
gl.SetCapability(EnableCap.SampleAlphaToCoverage, enabled: true);
|
||||
gl.SetCapability(EnableCap.Multisample, enabled: false);
|
||||
gl.TextureBindings[TextureUnit.Texture0] = 41;
|
||||
gl.TextureBindings[TextureUnit.Texture2] = 43;
|
||||
StateSnapshot expected = gl.Capture();
|
||||
|
||||
Action failedDraw = () =>
|
||||
{
|
||||
using var stateScope = new TextRenderGlStateScope(gl);
|
||||
gl.SetCapability(EnableCap.DepthTest, enabled: false);
|
||||
gl.SetCapability(EnableCap.Blend, enabled: true);
|
||||
gl.SetCapability(EnableCap.CullFace, enabled: false);
|
||||
gl.SetCapability(EnableCap.SampleAlphaToCoverage, enabled: false);
|
||||
gl.SetCapability(EnableCap.Multisample, enabled: true);
|
||||
gl.DepthMask(true);
|
||||
gl.BlendFuncSeparate(
|
||||
BlendingFactor.SrcAlpha,
|
||||
BlendingFactor.OneMinusSrcAlpha,
|
||||
BlendingFactor.SrcAlpha,
|
||||
BlendingFactor.OneMinusSrcAlpha);
|
||||
gl.UseProgram(101);
|
||||
gl.BindVertexArray(103);
|
||||
gl.BindBuffer(BufferTargetARB.ArrayBuffer, 107);
|
||||
gl.ActiveTexture(TextureUnit.Texture0);
|
||||
gl.BindTexture(TextureTarget.Texture2D, 109);
|
||||
throw new InvalidOperationException("draw upload");
|
||||
};
|
||||
|
||||
Assert.Throws<InvalidOperationException>(failedDraw);
|
||||
|
||||
Assert.Equal(expected, gl.Capture());
|
||||
}
|
||||
|
||||
private readonly record struct StateSnapshot(
|
||||
bool DepthTest,
|
||||
bool Blend,
|
||||
bool Cull,
|
||||
bool AlphaToCoverage,
|
||||
bool Multisample,
|
||||
bool DepthWrite,
|
||||
BlendingFactor BlendSourceRgb,
|
||||
BlendingFactor BlendDestinationRgb,
|
||||
BlendingFactor BlendSourceAlpha,
|
||||
BlendingFactor BlendDestinationAlpha,
|
||||
uint Program,
|
||||
uint VertexArray,
|
||||
uint ArrayBuffer,
|
||||
TextureUnit ActiveUnit,
|
||||
uint Texture0,
|
||||
uint Texture2);
|
||||
|
||||
private sealed class RecordingGlState : ITextRenderGlStateApi
|
||||
{
|
||||
private readonly Dictionary<EnableCap, bool> _capabilities = [];
|
||||
|
||||
public bool DepthWrite { get; set; }
|
||||
public BlendingFactor BlendSourceRgb { get; set; }
|
||||
public BlendingFactor BlendDestinationRgb { get; set; }
|
||||
public BlendingFactor BlendSourceAlpha { get; set; }
|
||||
public BlendingFactor BlendDestinationAlpha { get; set; }
|
||||
public uint Program { get; set; }
|
||||
public uint VertexArray { get; set; }
|
||||
public uint ArrayBuffer { get; set; }
|
||||
public TextureUnit ActiveUnit { get; set; }
|
||||
public Dictionary<TextureUnit, uint> TextureBindings { get; } = [];
|
||||
|
||||
public StateSnapshot Capture() => new(
|
||||
IsEnabled(EnableCap.DepthTest),
|
||||
IsEnabled(EnableCap.Blend),
|
||||
IsEnabled(EnableCap.CullFace),
|
||||
IsEnabled(EnableCap.SampleAlphaToCoverage),
|
||||
IsEnabled(EnableCap.Multisample),
|
||||
DepthWrite,
|
||||
BlendSourceRgb,
|
||||
BlendDestinationRgb,
|
||||
BlendSourceAlpha,
|
||||
BlendDestinationAlpha,
|
||||
Program,
|
||||
VertexArray,
|
||||
ArrayBuffer,
|
||||
ActiveUnit,
|
||||
TextureBindings.GetValueOrDefault(TextureUnit.Texture0),
|
||||
TextureBindings.GetValueOrDefault(TextureUnit.Texture2));
|
||||
|
||||
public bool IsEnabled(EnableCap capability) =>
|
||||
_capabilities.GetValueOrDefault(capability);
|
||||
|
||||
public int GetInteger(GetPName parameter) => parameter switch
|
||||
{
|
||||
GetPName.BlendSrcRgb => (int)BlendSourceRgb,
|
||||
GetPName.BlendDstRgb => (int)BlendDestinationRgb,
|
||||
GetPName.BlendSrcAlpha => (int)BlendSourceAlpha,
|
||||
GetPName.BlendDstAlpha => (int)BlendDestinationAlpha,
|
||||
GetPName.CurrentProgram => (int)Program,
|
||||
GetPName.VertexArrayBinding => (int)VertexArray,
|
||||
GetPName.ArrayBufferBinding => (int)ArrayBuffer,
|
||||
GetPName.ActiveTexture => (int)ActiveUnit,
|
||||
GetPName.TextureBinding2D =>
|
||||
(int)TextureBindings.GetValueOrDefault(ActiveUnit),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(parameter)),
|
||||
};
|
||||
|
||||
public bool GetBoolean(GetPName parameter) =>
|
||||
parameter == GetPName.DepthWritemask
|
||||
? DepthWrite
|
||||
: throw new ArgumentOutOfRangeException(nameof(parameter));
|
||||
|
||||
public void SetCapability(EnableCap capability, bool enabled) =>
|
||||
_capabilities[capability] = enabled;
|
||||
|
||||
public void DepthMask(bool enabled) => DepthWrite = enabled;
|
||||
|
||||
public void BlendFuncSeparate(
|
||||
BlendingFactor sourceRgb,
|
||||
BlendingFactor destinationRgb,
|
||||
BlendingFactor sourceAlpha,
|
||||
BlendingFactor destinationAlpha)
|
||||
{
|
||||
BlendSourceRgb = sourceRgb;
|
||||
BlendDestinationRgb = destinationRgb;
|
||||
BlendSourceAlpha = sourceAlpha;
|
||||
BlendDestinationAlpha = destinationAlpha;
|
||||
}
|
||||
|
||||
public void UseProgram(uint program) => Program = program;
|
||||
|
||||
public void BindVertexArray(uint vertexArray) => VertexArray = vertexArray;
|
||||
|
||||
public void BindBuffer(BufferTargetARB target, uint buffer)
|
||||
{
|
||||
Assert.Equal(BufferTargetARB.ArrayBuffer, target);
|
||||
ArrayBuffer = buffer;
|
||||
}
|
||||
|
||||
public void ActiveTexture(TextureUnit unit) => ActiveUnit = unit;
|
||||
|
||||
public void BindTexture(TextureTarget target, uint texture)
|
||||
{
|
||||
Assert.Equal(TextureTarget.Texture2D, target);
|
||||
TextureBindings[ActiveUnit] = texture;
|
||||
}
|
||||
}
|
||||
|
||||
private static void AssertAppearsInOrder(string source, params string[] needles)
|
||||
{
|
||||
int cursor = -1;
|
||||
foreach (string needle in needles)
|
||||
{
|
||||
int next = source.IndexOf(needle, cursor + 1, StringComparison.Ordinal);
|
||||
Assert.True(next >= 0, $"Missing expected source fragment: {needle}");
|
||||
Assert.True(next > cursor, $"Out-of-order source fragment: {needle}");
|
||||
cursor = next;
|
||||
}
|
||||
}
|
||||
|
||||
private static string FindRepoRoot()
|
||||
{
|
||||
DirectoryInfo? directory = new(AppContext.BaseDirectory);
|
||||
while (directory is not null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(directory.FullName, "AcDream.slnx")))
|
||||
return directory.FullName;
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
||||
throw new DirectoryNotFoundException("Could not find AcDream.slnx.");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.Studio;
|
||||
using AcDream.App.UI;
|
||||
|
||||
|
|
@ -31,7 +32,7 @@ public class DumpLayoutTests
|
|||
"docs", "research", "2026-06-25-retail-ui-layout-dump.json");
|
||||
}
|
||||
|
||||
private static (uint, int, int) NoTex(uint _) => (1u, 1, 1);
|
||||
private static (GpuTextureSlot, int, int) NoTex(uint _) => (new GpuTextureSlot(1), 1, 1);
|
||||
|
||||
// ── Helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.Studio;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
|
@ -12,7 +13,7 @@ namespace AcDream.App.Tests.Studio;
|
|||
/// </summary>
|
||||
public class LayoutSourceTests
|
||||
{
|
||||
private static (uint handle, int width, int height) NoTex(uint _) => (1u, 1, 1);
|
||||
private static (GpuTextureSlot handle, int width, int height) NoTex(uint _) => (new GpuTextureSlot(1u), 1, 1);
|
||||
|
||||
/// <summary>Resolve the client dat directory, or null if unavailable (skip the test).</summary>
|
||||
private static string? ResolveDatDir()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.Core.Combat;
|
||||
using AcDream.Core.Items;
|
||||
|
|
@ -20,11 +21,11 @@ public sealed class CursorFeedbackControllerTests
|
|||
|
||||
var accept = c.Resolve(new CursorFeedbackSnapshot(
|
||||
DragPayload: new object(),
|
||||
DragAccept: UiItemSlot.DragAcceptState.Accept,
|
||||
DragAccept: DragAcceptState.Accept,
|
||||
HoverResizeEdges: ResizeEdges.Right));
|
||||
var reject = c.Resolve(new CursorFeedbackSnapshot(
|
||||
DragPayload: new object(),
|
||||
DragAccept: UiItemSlot.DragAcceptState.Reject,
|
||||
DragAccept: DragAcceptState.Reject,
|
||||
HoverResizeEdges: ResizeEdges.Right));
|
||||
|
||||
Assert.Equal(CursorFeedbackKind.DragAccept, accept.Kind);
|
||||
|
|
@ -211,7 +212,7 @@ public sealed class CursorFeedbackControllerTests
|
|||
{
|
||||
["Drag_rollover_accept"] = acceptCursor,
|
||||
});
|
||||
slot.SetItem(Target, iconTexture: 1u);
|
||||
slot.SetItem(Target, iconTexture: new GpuTextureSlot(1u));
|
||||
root.AddChild(slot);
|
||||
root.OnMouseMove(20, 20);
|
||||
var c = new CursorFeedbackController(interaction);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
||||
namespace AcDream.App.Tests.UI;
|
||||
|
||||
public class DatWidgetFactoryZOrderTests
|
||||
{
|
||||
private static (uint, int, int) NoChrome(uint id) => (0u, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoChrome(uint id) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
|
||||
[Fact]
|
||||
public void ZOrder_HigherZLevel_DrawsBehind()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -40,7 +41,7 @@ public class DragDropSpineTests
|
|||
[Fact]
|
||||
public void UiItemList_registerDragHandler_roundtrips()
|
||||
{
|
||||
var list = new UiItemList(_ => (0u, 0, 0));
|
||||
var list = new UiItemList(_ => (GpuTextureSlot.Unassigned, 0, 0));
|
||||
Assert.Null(list.DragHandler);
|
||||
var h = new SpyHandler();
|
||||
list.RegisterDragHandler(h);
|
||||
|
|
@ -56,7 +57,7 @@ public class DragDropSpineTests
|
|||
public void GetDragPayload_boundCell_snapshotsFields()
|
||||
{
|
||||
var cell = new UiItemSlot { SlotIndex = 4, SourceKind = ItemDragSource.ShortcutBar };
|
||||
cell.SetItem(0x5001u, 0x99u);
|
||||
cell.SetItem(0x5001u, new GpuTextureSlot(0x99u));
|
||||
var p = Assert.IsType<ItemDragPayload>(cell.GetDragPayload());
|
||||
Assert.Equal(0x5001u, p.ObjId);
|
||||
Assert.Equal(ItemDragSource.ShortcutBar, p.SourceKind);
|
||||
|
|
@ -72,10 +73,10 @@ public class DragDropSpineTests
|
|||
public void GetDragGhost_boundCell_returnsIconTuple()
|
||||
{
|
||||
var cell = new UiItemSlot { Width = 32, Height = 32 };
|
||||
cell.SetItem(0x5001u, 0x99u);
|
||||
cell.SetItem(0x5001u, new GpuTextureSlot(0x99u));
|
||||
var g = cell.GetDragGhost();
|
||||
Assert.NotNull(g);
|
||||
Assert.Equal(0x99u, g!.Value.tex);
|
||||
Assert.Equal(new GpuTextureSlot(0x99u), g!.Value.tex);
|
||||
Assert.Equal(32, g.Value.w);
|
||||
Assert.Equal(32, g.Value.h);
|
||||
}
|
||||
|
|
@ -84,16 +85,16 @@ public class DragDropSpineTests
|
|||
public void GetDragGhost_prefersDedicatedUnderlayFreeTexture()
|
||||
{
|
||||
var cell = new UiItemSlot { Width = 36, Height = 36 }; // retail bag cell is larger than its icon
|
||||
cell.SetItem(0x5001u, 0x99u, dragIconTexture: 0x77u);
|
||||
cell.SetItem(0x5001u, new GpuTextureSlot(0x99u), dragIconTexture: new GpuTextureSlot(0x77u));
|
||||
|
||||
Assert.Equal((0x77u, 32, 32), cell.GetDragGhost());
|
||||
Assert.Equal(0x99u, cell.IconTexture); // source cell keeps the full m_pIcon
|
||||
Assert.Equal((new GpuTextureSlot(0x77u), 32, 32), cell.GetDragGhost());
|
||||
Assert.Equal(new GpuTextureSlot(0x99u), cell.IconTexture); // source cell keeps the full m_pIcon
|
||||
}
|
||||
|
||||
// ── cell drop-target: DragEnter overlay + DropReleased dispatch ──────────
|
||||
private static (UiItemList list, UiItemSlot cell, SpyHandler h) ListWithHandler()
|
||||
{
|
||||
var list = new UiItemList(_ => (1u, 1, 1)); // non-zero resolve so overlay draw is harmless
|
||||
var list = new UiItemList(_ => (new GpuTextureSlot(1u), 1, 1)); // non-zero resolve so overlay draw is harmless
|
||||
var h = new SpyHandler();
|
||||
list.RegisterDragHandler(h);
|
||||
return (list, list.Cell, h);
|
||||
|
|
@ -108,7 +109,7 @@ public class DragDropSpineTests
|
|||
var (_, cell, h) = ListWithHandler();
|
||||
h.Acceptance = ItemDragAcceptance.Accept;
|
||||
cell.OnEvent(new UiEvent(0u, cell, UiEventType.DragEnter, Payload: SomePayload()));
|
||||
Assert.Equal(UiItemSlot.DragAcceptState.Accept, cell.DragAcceptVisual);
|
||||
Assert.Equal(DragAcceptState.Accept, cell.DragAcceptVisual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -117,7 +118,7 @@ public class DragDropSpineTests
|
|||
var (_, cell, h) = ListWithHandler();
|
||||
h.Acceptance = ItemDragAcceptance.Reject;
|
||||
cell.OnEvent(new UiEvent(0u, cell, UiEventType.DragEnter, Payload: SomePayload()));
|
||||
Assert.Equal(UiItemSlot.DragAcceptState.Reject, cell.DragAcceptVisual);
|
||||
Assert.Equal(DragAcceptState.Reject, cell.DragAcceptVisual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -126,7 +127,7 @@ public class DragDropSpineTests
|
|||
var (_, cell, h) = ListWithHandler();
|
||||
h.Acceptance = ItemDragAcceptance.None;
|
||||
cell.OnEvent(new UiEvent(0u, cell, UiEventType.DragEnter, Payload: SomePayload()));
|
||||
Assert.Equal(UiItemSlot.DragAcceptState.None, cell.DragAcceptVisual);
|
||||
Assert.Equal(DragAcceptState.None, cell.DragAcceptVisual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -135,7 +136,7 @@ public class DragDropSpineTests
|
|||
var (_, cell, h) = ListWithHandler();
|
||||
cell.OnEvent(new UiEvent(0u, cell, UiEventType.DragEnter, Payload: SomePayload()));
|
||||
cell.OnEvent(new UiEvent(0u, cell, UiEventType.DragOver, Payload: SomePayload()));
|
||||
Assert.Equal(UiItemSlot.DragAcceptState.None, cell.DragAcceptVisual);
|
||||
Assert.Equal(DragAcceptState.None, cell.DragAcceptVisual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -179,16 +180,16 @@ public class DragDropSpineTests
|
|||
root.OnMouseDown(UiMouseButton.Left, 10, 10);
|
||||
root.OnMouseMove(20, 10); // BeginDrag → snapshot ghost
|
||||
cell.Clear(); // simulate the lift emptying the source
|
||||
Assert.Equal((0x99u, 32, 32), root.DragGhostForTest);
|
||||
Assert.Equal((new GpuTextureSlot(0x99u), 32, 32), root.DragGhostForTest);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FinishDrag_overNothing_deliversNoDrop_butLiftStands()
|
||||
{
|
||||
var root = new UiRoot { Width = 800, Height = 600 };
|
||||
var list = new UiItemList(_ => (1u, 1, 1)) { Left = 0, Top = 0, Width = 32, Height = 32 };
|
||||
var list = new UiItemList(_ => (new GpuTextureSlot(1u), 1, 1)) { Left = 0, Top = 0, Width = 32, Height = 32 };
|
||||
list.Cell.Width = 32; list.Cell.Height = 32;
|
||||
list.Cell.SetItem(0x5001u, 0x99u);
|
||||
list.Cell.SetItem(0x5001u, new GpuTextureSlot(0x99u));
|
||||
var h = new SpyHandler();
|
||||
list.RegisterDragHandler(h);
|
||||
root.AddChild(list);
|
||||
|
|
@ -237,10 +238,10 @@ public class DragDropSpineTests
|
|||
private static (UiRoot root, UiItemList list, UiItemSlot cell) RootWithBoundSlot(uint itemId)
|
||||
{
|
||||
var root = new UiRoot { Width = 800, Height = 600 };
|
||||
var list = new UiItemList(_ => (1u, 1, 1)) { Left = 0, Top = 0, Width = 32, Height = 32 };
|
||||
var list = new UiItemList(_ => (new GpuTextureSlot(1u), 1, 1)) { Left = 0, Top = 0, Width = 32, Height = 32 };
|
||||
// Tests don't run OnDraw (which sizes the cell), so size the cell explicitly.
|
||||
list.Cell.Width = 32; list.Cell.Height = 32;
|
||||
if (itemId != 0) list.Cell.SetItem(itemId, 0x99u);
|
||||
if (itemId != 0) list.Cell.SetItem(itemId, new GpuTextureSlot(0x99u));
|
||||
root.AddChild(list);
|
||||
return (root, list, list.Cell);
|
||||
}
|
||||
|
|
@ -249,7 +250,7 @@ public class DragDropSpineTests
|
|||
RootWithCatalogSlot(uint entryId)
|
||||
{
|
||||
var root = new UiRoot { Width = 800, Height = 600 };
|
||||
var list = new UiItemList(_ => (1u, 1, 1))
|
||||
var list = new UiItemList(_ => (new GpuTextureSlot(1u), 1, 1))
|
||||
{
|
||||
Left = 0,
|
||||
Top = 0,
|
||||
|
|
@ -262,7 +263,7 @@ public class DragDropSpineTests
|
|||
EntryId = entryId,
|
||||
Width = 32,
|
||||
Height = 32,
|
||||
SpriteResolve = _ => (1u, 1, 1),
|
||||
SpriteResolve = _ => (new GpuTextureSlot(1u), 1, 1),
|
||||
};
|
||||
list.AddItem(cell);
|
||||
root.AddChild(list);
|
||||
|
|
@ -427,15 +428,15 @@ public class DragDropSpineTests
|
|||
{
|
||||
var cell = new UiItemSlot(); // no parent list → FindList() null
|
||||
cell.OnEvent(new UiEvent(0u, cell, UiEventType.DragEnter, Payload: SomePayload()));
|
||||
Assert.Equal(UiItemSlot.DragAcceptState.Reject, cell.DragAcceptVisual);
|
||||
Assert.Equal(DragAcceptState.Reject, cell.DragAcceptVisual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DragEnter_listWithoutHandler_defaultsToReject()
|
||||
{
|
||||
var list = new UiItemList(_ => (1u, 1, 1)); // no RegisterDragHandler
|
||||
var list = new UiItemList(_ => (new GpuTextureSlot(1u), 1, 1)); // no RegisterDragHandler
|
||||
list.Cell.OnEvent(new UiEvent(0u, list.Cell, UiEventType.DragEnter, Payload: SomePayload()));
|
||||
Assert.Equal(UiItemSlot.DragAcceptState.Reject, list.Cell.DragAcceptVisual);
|
||||
Assert.Equal(DragAcceptState.Reject, list.Cell.DragAcceptVisual);
|
||||
}
|
||||
|
||||
// ── item drag inside a Draggable window (the LIVE toolbar topology) ──────
|
||||
|
|
@ -449,9 +450,9 @@ public class DragDropSpineTests
|
|||
{
|
||||
var root = new UiRoot { Width = 800, Height = 600 };
|
||||
var frame = new UiPanel { Left = 10, Top = 300, Width = 200, Height = 60, Draggable = true };
|
||||
var list = new UiItemList(_ => (1u, 1, 1)) { Left = 5, Top = 5, Width = 32, Height = 32 };
|
||||
var list = new UiItemList(_ => (new GpuTextureSlot(1u), 1, 1)) { Left = 5, Top = 5, Width = 32, Height = 32 };
|
||||
list.Cell.Width = 32; list.Cell.Height = 32;
|
||||
if (itemId != 0) list.Cell.SetItem(itemId, 0x99u);
|
||||
if (itemId != 0) list.Cell.SetItem(itemId, new GpuTextureSlot(0x99u));
|
||||
frame.AddChild(list);
|
||||
root.AddChild(frame);
|
||||
return (root, frame, list);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.Core.Combat;
|
||||
using AcDream.Core.Items;
|
||||
|
|
@ -251,7 +252,7 @@ public sealed class ItemInteractionControllerTests
|
|||
});
|
||||
h.GroundObject = chest;
|
||||
var cell = new UiItemSlot();
|
||||
cell.SetItem(itemId, 0u);
|
||||
cell.SetItem(itemId, GpuTextureSlot.Unassigned);
|
||||
var payload = new ItemDragPayload(itemId, ItemDragSource.Inventory, 0, cell);
|
||||
|
||||
Assert.True(h.Controller.PlaceIn3D(payload, chest));
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System.Numerics;
|
||||
using AcDream.App.Spells;
|
||||
using AcDream.Content;
|
||||
|
|
@ -14,7 +15,7 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
public sealed class AppraisalUiControllerTests
|
||||
{
|
||||
private const uint ObjectId = 0x50000001u;
|
||||
private static (uint, int, int) NoTexture(uint _) => (0u, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoTexture(uint _) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
|
||||
[Fact]
|
||||
public void ItemResponse_UsesAuthoredItemSubviewTitleAndScrollbars()
|
||||
|
|
@ -741,11 +742,11 @@ public sealed class AppraisalUiControllerTests
|
|||
() => { },
|
||||
selection: selection,
|
||||
spellbook: spellbook,
|
||||
resolveSpellIcon: id => id + 1_000u,
|
||||
resolveSpellIcon: id => new GpuTextureSlot(id + 1_000u),
|
||||
resolveComponentIcon: did =>
|
||||
{
|
||||
resolvedComponentIcons.Add(did);
|
||||
return did + 2_000u;
|
||||
return new GpuTextureSlot(did + 2_000u);
|
||||
},
|
||||
spellComponents: _ => components,
|
||||
magicSkill: _ => 200u,
|
||||
|
|
@ -801,14 +802,18 @@ public sealed class AppraisalUiControllerTests
|
|||
AppraisalUiController.SpellIconId)!;
|
||||
UiTextureElement icon = Assert.Single(
|
||||
iconHost.Children.OfType<UiTextureElement>());
|
||||
Assert.Equal(metadata.SpellId + 1_000u, icon.Texture);
|
||||
Assert.Equal(new GpuTextureSlot(metadata.SpellId + 1_000u), icon.Texture);
|
||||
Assert.Equal(
|
||||
new uint[] { 0x06000010u, 0x06000011u },
|
||||
resolvedComponentIcons);
|
||||
UiElement formula = layout.FindElement(
|
||||
AppraisalUiController.SpellFormulaListId)!;
|
||||
Assert.Equal(
|
||||
new uint[] { 0x06000010u + 2_000u, 0x06000011u + 2_000u },
|
||||
new[]
|
||||
{
|
||||
new GpuTextureSlot(0x06000010u + 2_000u),
|
||||
new GpuTextureSlot(0x06000011u + 2_000u),
|
||||
},
|
||||
formula.Children
|
||||
.OfType<UiDatElement>()
|
||||
.Select(cell => cell.RuntimeImageTexture!.Value));
|
||||
|
|
@ -828,8 +833,8 @@ public sealed class AppraisalUiControllerTests
|
|||
SelectionState? selection = null,
|
||||
RetailAppraisalNameResolver? itemNames = null,
|
||||
Spellbook? spellbook = null,
|
||||
Func<uint, uint>? resolveSpellIcon = null,
|
||||
Func<uint, uint>? resolveComponentIcon = null,
|
||||
Func<uint, GpuTextureSlot>? resolveSpellIcon = null,
|
||||
Func<uint, GpuTextureSlot>? resolveComponentIcon = null,
|
||||
Func<uint, IReadOnlyList<SpellExamineComponent>>? spellComponents = null,
|
||||
Func<MagicSchool, uint>? magicSkill = null,
|
||||
SpellExamineComponentTemplateFactory? spellComponentTemplates = null)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
|
@ -30,10 +31,10 @@ public sealed class CharacterLayoutImportProbe
|
|||
if (datDir is null) return;
|
||||
|
||||
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
||||
var layout = LayoutImporter.Import(dats, CharacterLayout, _ => (1u, 30, 26), null);
|
||||
var layout = LayoutImporter.Import(dats, CharacterLayout, _ => (new GpuTextureSlot(1u), 30, 26), null);
|
||||
Assert.NotNull(layout);
|
||||
|
||||
CharacterStatController.Bind(layout!, SampleData.SampleCharacter, spriteResolve: _ => (1u, 30, 26));
|
||||
CharacterStatController.Bind(layout!, SampleData.SampleCharacter, spriteResolve: _ => (new GpuTextureSlot(1u), 30, 26));
|
||||
|
||||
var rows = new List<UiClickablePanel>();
|
||||
CollectRows(layout!.Root, rows);
|
||||
|
|
@ -61,7 +62,7 @@ public sealed class CharacterLayoutImportProbe
|
|||
if (datDir is null) return;
|
||||
|
||||
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
||||
var layout = LayoutImporter.Import(dats, CharacterLayout, _ => (1u, 30, 26), null);
|
||||
var layout = LayoutImporter.Import(dats, CharacterLayout, _ => (new GpuTextureSlot(1u), 30, 26), null);
|
||||
Assert.NotNull(layout);
|
||||
|
||||
var close = layout!.FindElement(WindowChromeController.CharacterCloseButtonId);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.Studio;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
|
@ -281,7 +282,7 @@ public class CharacterStatControllerTests
|
|||
var layout = Fake((CharacterStatController.ListBoxId, list));
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16));
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16));
|
||||
|
||||
var rows = list.Children.OfType<UiPanel>().ToList();
|
||||
Assert.Equal(9, rows.Count);
|
||||
|
|
@ -547,7 +548,7 @@ public class CharacterStatControllerTests
|
|||
var layout = Fake((CharacterStatController.ListBoxId, list));
|
||||
|
||||
// Minimal sprite resolver — returns a fake non-zero handle so UiPanel draws it.
|
||||
static (uint, int, int) FakeResolve(uint id) => (1u, 32, 8);
|
||||
static (GpuTextureSlot, int, int) FakeResolve(uint id) => (new GpuTextureSlot(1), 32, 8);
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: FakeResolve);
|
||||
|
|
@ -566,7 +567,7 @@ public class CharacterStatControllerTests
|
|||
{
|
||||
var list = new UiPanel();
|
||||
var layout = Fake((CharacterStatController.ListBoxId, list));
|
||||
static (uint, int, int) FakeResolve(uint id) => (1u, 32, 8);
|
||||
static (GpuTextureSlot, int, int) FakeResolve(uint id) => (new GpuTextureSlot(1), 32, 8);
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: FakeResolve);
|
||||
|
||||
|
|
@ -791,7 +792,7 @@ public class CharacterStatControllerTests
|
|||
Assert.Equal(3, titles.Children.Count);
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16));
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16));
|
||||
|
||||
Assert.Equal(rootChildCount, layout.Root.Children.Count);
|
||||
Assert.Equal(RetailUiStateIds.Open, attributes.ActiveRetailStateId);
|
||||
|
|
@ -814,7 +815,7 @@ public class CharacterStatControllerTests
|
|||
var skills = Assert.IsType<UiText>(layout.FindElement(CharacterStatController.TabSkillsId));
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16));
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16));
|
||||
skills.OnClick!();
|
||||
|
||||
Assert.Equal(RetailUiStateIds.Closed, attributes.ActiveRetailStateId);
|
||||
|
|
@ -836,7 +837,7 @@ public class CharacterStatControllerTests
|
|||
var layout = Fake((CharacterStatController.ListBoxId, list));
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16));
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16));
|
||||
|
||||
ClickTab(layout, left: 92f);
|
||||
|
||||
|
|
@ -891,7 +892,7 @@ public class CharacterStatControllerTests
|
|||
var layout = Fake((CharacterStatController.ListBoxId, list));
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16));
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16));
|
||||
|
||||
ClickTab(layout, left: 92f);
|
||||
Assert.Equal(12, SkillRows(list).Count);
|
||||
|
|
@ -929,7 +930,7 @@ public class CharacterStatControllerTests
|
|||
});
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16));
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16));
|
||||
|
||||
Assert.Equal("Strength", FirstRowName(visibleList));
|
||||
Assert.Equal("<no row>", FirstRowName(hiddenDuplicateList));
|
||||
|
|
@ -963,7 +964,7 @@ public class CharacterStatControllerTests
|
|||
(CharacterStatController.FooterLine2Value, l2Value));
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16));
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16));
|
||||
|
||||
ClickTab(layout, left: 92f);
|
||||
var rows = SkillRows(list);
|
||||
|
|
@ -993,7 +994,7 @@ public class CharacterStatControllerTests
|
|||
var requests = new List<CharacterStatController.RaiseRequest>();
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16),
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16),
|
||||
onRaiseRequest: (request, completed) => { requests.Add(request); completed(); });
|
||||
|
||||
ClickTab(layout, left: 92f);
|
||||
|
|
@ -1027,7 +1028,7 @@ public class CharacterStatControllerTests
|
|||
(CharacterStatController.RaiseOneId, btn1));
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16));
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16));
|
||||
|
||||
ClickTab(layout, left: 92f);
|
||||
SkillRows(list)[5].OnClick!();
|
||||
|
|
@ -1052,7 +1053,7 @@ public class CharacterStatControllerTests
|
|||
var requests = new List<CharacterStatController.RaiseRequest>();
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16),
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16),
|
||||
onRaiseRequest: (request, completed) => { requests.Add(request); completed(); });
|
||||
|
||||
ClickTab(layout, left: 92f);
|
||||
|
|
@ -1096,7 +1097,7 @@ public class CharacterStatControllerTests
|
|||
var requests = new List<CharacterStatController.RaiseRequest>();
|
||||
|
||||
CharacterStatController.Bind(layout, () => sheet,
|
||||
spriteResolve: id => (id, 16, 16),
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16),
|
||||
onRaiseRequest: (request, completed) =>
|
||||
{
|
||||
requests.Add(request);
|
||||
|
|
@ -1149,7 +1150,7 @@ public class CharacterStatControllerTests
|
|||
Action? completeRaise = null;
|
||||
|
||||
CharacterStatController.Bind(layout, () => sheet,
|
||||
spriteResolve: id => (id, 16, 16),
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16),
|
||||
onRaiseRequest: (_, completed) => completeRaise = completed);
|
||||
|
||||
ClickTab(layout, left: 92f);
|
||||
|
|
@ -1213,7 +1214,7 @@ public class CharacterStatControllerTests
|
|||
});
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16));
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16));
|
||||
|
||||
ClickTab(layout, left: 92f);
|
||||
|
||||
|
|
@ -1537,7 +1538,7 @@ public class CharacterStatControllerTests
|
|||
CharacterStatController.Bind(
|
||||
layout,
|
||||
SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16));
|
||||
spriteResolve: id => (new GpuTextureSlot(id), 16, 16));
|
||||
|
||||
ApplyLayoutPass(layout.Root);
|
||||
|
||||
|
|
@ -1635,7 +1636,7 @@ public class CharacterStatControllerTests
|
|||
Width = width,
|
||||
Height = height,
|
||||
};
|
||||
return new UiDatElement(info, static _ => (0u, 0, 0))
|
||||
return new UiDatElement(info, static _ => (GpuTextureSlot.Unassigned, 0, 0))
|
||||
{
|
||||
Top = top,
|
||||
Width = width,
|
||||
|
|
@ -1649,7 +1650,7 @@ public class CharacterStatControllerTests
|
|||
var info = new ElementInfo { Id = id, Type = 1 };
|
||||
info.StateMedia["Normal"] = (1u, 1);
|
||||
info.StateMedia["Ghosted"] = (2u, 1);
|
||||
return new UiButton(info, static _ => (0u, 0, 0));
|
||||
return new UiButton(info, static _ => (GpuTextureSlot.Unassigned, 0, 0));
|
||||
}
|
||||
|
||||
private static UiText MakeTab(uint id, float left)
|
||||
|
|
@ -1676,7 +1677,7 @@ public class CharacterStatControllerTests
|
|||
Name = "Open",
|
||||
PassToChildren = true,
|
||||
};
|
||||
return Assert.IsType<UiText>(DatWidgetFactory.Create(info, static _ => (0u, 0, 0), null));
|
||||
return Assert.IsType<UiText>(DatWidgetFactory.Create(info, static _ => (GpuTextureSlot.Unassigned, 0, 0), null));
|
||||
}
|
||||
|
||||
private static ImportedLayout Fake(params (uint id, UiElement e)[] items)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.Core.Chat;
|
||||
|
|
@ -13,7 +14,7 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
/// </summary>
|
||||
public class ChatLayoutConformanceTests
|
||||
{
|
||||
private static (uint, int, int) NoTex(uint _) => (0, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoTex(uint _) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
|
||||
private static ElementInfo? Find(ElementInfo n, uint id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System.Collections.Generic;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
|
@ -21,7 +22,7 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
public class ChatWindowControllerTests
|
||||
{
|
||||
// ── Null-resolve helper (no GL needed) ─────────────────────────────────
|
||||
private static (uint, int, int) NoTex(uint _) => (0u, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoTex(uint _) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
|
||||
// ── Capture bus — records every Publish call ────────────────────────────
|
||||
private sealed class CaptureBus : ICommandBus
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
||||
|
|
@ -18,7 +19,7 @@ public sealed class CombatLayoutConformanceTests
|
|||
ElementInfo info = FixtureLoader.LoadCombatInfos();
|
||||
ImportedLayout layout = LayoutImporter.Build(
|
||||
info,
|
||||
_ => (0u, 0, 0),
|
||||
_ => (GpuTextureSlot.Unassigned, 0, 0),
|
||||
datFont: null,
|
||||
stringResolve: _ => "localized");
|
||||
ApplyAnchors(layout.Root);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.Combat;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
|
@ -9,7 +10,7 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
|
||||
public sealed class CombatUiControllerTests
|
||||
{
|
||||
private static (uint, int, int) NoTex(uint _) => (0u, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoTex(uint _) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
|
||||
[Fact]
|
||||
public void CombatMode_ShowsPhysicalAndMagicPages_AndSelectsMediumByDefault()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.Core.Items;
|
||||
|
|
@ -130,7 +131,7 @@ public sealed class CreatureAppraisalRowsTests
|
|||
{
|
||||
var templates = new CreatureAppraisalRowTemplateFactory(
|
||||
FixtureLoader.LoadExaminationRowTemplateInfos(),
|
||||
_ => (0u, 0, 0),
|
||||
_ => (GpuTextureSlot.Unassigned, 0, 0),
|
||||
defaultFont: null);
|
||||
var row = new CreatureAppraisalRow(
|
||||
"Strength",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
||||
|
|
@ -20,7 +21,7 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
/// </summary>
|
||||
public class DatWidgetFactoryFontResolveTests
|
||||
{
|
||||
private static (uint, int, int) NoTex(uint _) => (0, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoTex(uint _) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
|
||||
// ── Test 1: null fontResolve → DatFont == datFont (backward-compat) ─────
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System.Numerics;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
|
@ -5,7 +6,7 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
|
||||
public class DatWidgetFactoryTests
|
||||
{
|
||||
private static (uint, int, int) NoTex(uint _) => (0, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoTex(uint _) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
|
||||
// ── Test 1: Type 7 → UiMeter ─────────────────────────────────────────────
|
||||
|
||||
|
|
@ -334,7 +335,7 @@ public class DatWidgetFactoryTests
|
|||
public void Create_buildsUiItemList_forItemListClassId()
|
||||
{
|
||||
var info = new AcDream.App.UI.Layout.ElementInfo { Id = 0x100001A7u, Type = 0x10000031u, Width = 32, Height = 32 };
|
||||
var w = AcDream.App.UI.Layout.DatWidgetFactory.Create(info, _ => (0u, 0, 0), null);
|
||||
var w = AcDream.App.UI.Layout.DatWidgetFactory.Create(info, _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
Assert.IsType<AcDream.App.UI.UiItemList>(w);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.Core.Spells;
|
||||
|
|
@ -6,7 +7,7 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
|
||||
public sealed class EffectsUiControllerTests
|
||||
{
|
||||
private static (uint, int, int) NoTex(uint _) => (0u, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoTex(uint _) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
private static EffectRowTemplateFactory Templates()
|
||||
=> new(FixtureLoader.LoadEffectRowTemplateInfos(), NoTex, defaultFont: null);
|
||||
|
||||
|
|
@ -47,7 +48,7 @@ public sealed class EffectsUiControllerTests
|
|||
[EffectsUiController.InfoTextId] = info,
|
||||
});
|
||||
using EffectsUiController controller = EffectsUiController.Bind(
|
||||
layout, spellbook, positive: true, () => 0d, NoTex, id => id,
|
||||
layout, spellbook, positive: true, () => 0d, NoTex, id => new GpuTextureSlot(id),
|
||||
Templates(), "SELECT A SPELL")!;
|
||||
|
||||
Assert.False(info.PreserveEndOnLayout);
|
||||
|
|
@ -86,7 +87,7 @@ public sealed class EffectsUiControllerTests
|
|||
[EffectsUiController.ListId] = list,
|
||||
});
|
||||
using EffectsUiController controller = EffectsUiController.Bind(
|
||||
layout, spellbook, positive: true, () => 0d, NoTex, id => id,
|
||||
layout, spellbook, positive: true, () => 0d, NoTex, id => new GpuTextureSlot(id),
|
||||
Templates(), "SELECT A SPELL")!;
|
||||
spellbook.OnEnchantmentAdded(new ActiveEnchantmentRecord(
|
||||
42u, 1u, 60f, 1u, Bucket: 1u, SpellCategory: 100u));
|
||||
|
|
@ -129,7 +130,7 @@ public sealed class EffectsUiControllerTests
|
|||
info.Width = 96f;
|
||||
|
||||
using EffectsUiController controller = EffectsUiController.Bind(
|
||||
layout, spellbook, positive, () => 0d, NoTex, id => id,
|
||||
layout, spellbook, positive, () => 0d, NoTex, id => new GpuTextureSlot(id),
|
||||
Templates(), "SELECT A SPELL")!;
|
||||
spellbook.OnEnchantmentAdded(new ActiveEnchantmentRecord(
|
||||
42u, 1u, 60f, 1u, Bucket: 1u, SpellCategory: 42u));
|
||||
|
|
@ -173,7 +174,7 @@ public sealed class EffectsUiControllerTests
|
|||
[EffectsUiController.ListId] = list,
|
||||
});
|
||||
using EffectsUiController controller = EffectsUiController.Bind(
|
||||
layout, spellbook, positive: true, () => 0d, NoTex, id => id,
|
||||
layout, spellbook, positive: true, () => 0d, NoTex, id => new GpuTextureSlot(id),
|
||||
Templates(), "SELECT A SPELL")!;
|
||||
|
||||
spellbook.OnEnchantmentAdded(new ActiveEnchantmentRecord(
|
||||
|
|
@ -225,7 +226,7 @@ public sealed class EffectsUiControllerTests
|
|||
int closes = 0;
|
||||
|
||||
using EffectsUiController? controller = EffectsUiController.Bind(
|
||||
layout, spellbook, positive, () => 0d, NoTex, id => id,
|
||||
layout, spellbook, positive, () => 0d, NoTex, id => new GpuTextureSlot(id),
|
||||
Templates(), "SELECT A SPELL", () => closes++);
|
||||
|
||||
Assert.NotNull(controller);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.App.World;
|
||||
|
|
@ -31,7 +32,7 @@ public sealed class ExternalContainerControllerTests
|
|||
RetailWindowHandle handle = RetailWindowFrame.Mount(
|
||||
screen,
|
||||
root,
|
||||
static _ => (0u, 0, 0),
|
||||
static _ => (GpuTextureSlot.Unassigned, 0, 0),
|
||||
options);
|
||||
|
||||
var frame = Assert.IsType<UiNineSlicePanel>(handle.OuterFrame);
|
||||
|
|
@ -75,7 +76,7 @@ public sealed class ExternalContainerControllerTests
|
|||
var root = new TestElement { Width = 800f, Height = 110f };
|
||||
var close = new UiButton(
|
||||
new ElementInfo { Id = ExternalContainerController.CloseButtonId, Type = 1 },
|
||||
static _ => (0u, 0, 0));
|
||||
static _ => (GpuTextureSlot.Unassigned, 0, 0));
|
||||
var scrollbar = new UiScrollbar { Width = 784f, Height = 16f };
|
||||
root.AddChild(Top);
|
||||
root.AddChild(Containers);
|
||||
|
|
@ -94,7 +95,7 @@ public sealed class ExternalContainerControllerTests
|
|||
Window = RetailWindowFrame.Mount(
|
||||
Screen,
|
||||
root,
|
||||
static _ => (0u, 0, 0),
|
||||
static _ => (GpuTextureSlot.Unassigned, 0, 0),
|
||||
new RetailWindowFrame.Options
|
||||
{
|
||||
WindowName = WindowNames.ExternalContainer,
|
||||
|
|
@ -129,8 +130,8 @@ public sealed class ExternalContainerControllerTests
|
|||
Selection,
|
||||
Interaction,
|
||||
Split,
|
||||
static (_, _, _, _, _) => 0u,
|
||||
static (_, _, _, _, _) => 0u,
|
||||
static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
Uses.Add,
|
||||
(item, container, placement) => Puts.Add((item, container, placement)),
|
||||
(item, container, placement, amount) =>
|
||||
|
|
@ -285,7 +286,7 @@ public sealed class ExternalContainerControllerTests
|
|||
h.Selection.Select(Item, SelectionChangeSource.Inventory);
|
||||
h.Split.Reset(5u, 2u);
|
||||
var source = new UiItemSlot { SourceKind = ItemDragSource.Inventory };
|
||||
source.SetItem(Item, 0u);
|
||||
source.SetItem(Item, GpuTextureSlot.Unassigned);
|
||||
var payload = new ItemDragPayload(Item, ItemDragSource.Inventory, 0, source);
|
||||
UiItemSlot target = h.Contents.GetItem(0)!;
|
||||
|
||||
|
|
@ -304,7 +305,7 @@ public sealed class ExternalContainerControllerTests
|
|||
h.Objects.AddOrUpdate(new ClientObject { ObjectId = Item, Type = ItemType.Misc });
|
||||
h.Objects.MoveItem(Item, Player, 0);
|
||||
var source = new UiItemSlot { SourceKind = ItemDragSource.Inventory };
|
||||
source.SetItem(Item, 0u);
|
||||
source.SetItem(Item, GpuTextureSlot.Unassigned);
|
||||
|
||||
Assert.True(h.Interaction.PlaceWorldItemInBackpack(0x70000A01u));
|
||||
h.Controller.HandleDropRelease(
|
||||
|
|
@ -333,7 +334,7 @@ public sealed class ExternalContainerControllerTests
|
|||
h.Selection.Select(Item, SelectionChangeSource.Inventory);
|
||||
h.Split.Reset(5u, 2u);
|
||||
var source = new UiItemSlot { SourceKind = ItemDragSource.Inventory };
|
||||
source.SetItem(Item, 0u);
|
||||
source.SetItem(Item, GpuTextureSlot.Unassigned);
|
||||
|
||||
Assert.True(h.Interaction.PlaceWorldItemInBackpack(0x70000A02u));
|
||||
h.Controller.HandleDropRelease(
|
||||
|
|
@ -355,7 +356,7 @@ public sealed class ExternalContainerControllerTests
|
|||
h.Objects.AddOrUpdate(new ClientObject { ObjectId = Item, Type = ItemType.Misc });
|
||||
h.Objects.MoveItem(Item, Player, 0);
|
||||
var source = new UiItemSlot { SourceKind = ItemDragSource.Inventory };
|
||||
source.SetItem(Item, 0u);
|
||||
source.SetItem(Item, GpuTextureSlot.Unassigned);
|
||||
|
||||
h.Controller.HandleDropRelease(
|
||||
h.Contents,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
|
@ -9,7 +10,7 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
/// no dats required. Fixtures were generated from the real portal.dat and
|
||||
/// serialized with <see cref="System.Text.Json"/>.
|
||||
/// </summary>
|
||||
public static class FixtureLoader
|
||||
internal static class FixtureLoader
|
||||
{
|
||||
private static readonly JsonSerializerOptions _opts = new()
|
||||
{
|
||||
|
|
@ -26,7 +27,7 @@ public static class FixtureLoader
|
|||
public static ImportedLayout LoadVitals()
|
||||
{
|
||||
var root = LoadVitalsInfos();
|
||||
return LayoutImporter.Build(root, _ => (0u, 0, 0), null);
|
||||
return LayoutImporter.Build(root, _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -46,7 +47,7 @@ public static class FixtureLoader
|
|||
/// conformance checks on tree structure and resolved types.
|
||||
/// </summary>
|
||||
public static ImportedLayout LoadChat()
|
||||
=> LayoutImporter.Build(LoadChatInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadChatInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the committed <c>chat_21000006.json</c> fixture into a raw
|
||||
|
|
@ -59,44 +60,44 @@ public static class FixtureLoader
|
|||
|
||||
/// <summary>Builds the committed retail radar LayoutDesc 0x21000074 fixture.</summary>
|
||||
public static ImportedLayout LoadRadar()
|
||||
=> LayoutImporter.Build(LoadRadarInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadRadarInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
/// <summary>Returns the resolved ElementInfo tree for retail radar LayoutDesc 0x21000074.</summary>
|
||||
public static AcDream.App.UI.Layout.ElementInfo LoadRadarInfos()
|
||||
=> LoadInfos("radar_21000074.json");
|
||||
|
||||
public static ImportedLayout LoadToolbar()
|
||||
=> LayoutImporter.Build(LoadToolbarInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadToolbarInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadToolbarInfos()
|
||||
=> LoadInfos("toolbar_21000016.json");
|
||||
|
||||
public static ImportedLayout LoadInventory()
|
||||
=> LayoutImporter.Build(LoadInventoryInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadInventoryInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadInventoryInfos()
|
||||
=> LoadInfos("inventory_21000023.json");
|
||||
|
||||
public static ImportedLayout LoadPaperdoll()
|
||||
=> LayoutImporter.Build(LoadPaperdollInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadPaperdollInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadPaperdollInfos()
|
||||
=> LoadInfos("paperdoll_21000024.json");
|
||||
|
||||
public static ImportedLayout LoadCharacter()
|
||||
=> LayoutImporter.Build(LoadCharacterInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadCharacterInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadCharacterInfos()
|
||||
=> LoadInfos("character_2100002E.json");
|
||||
|
||||
public static ImportedLayout LoadCombat()
|
||||
=> LayoutImporter.Build(LoadCombatInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadCombatInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadCombatInfos()
|
||||
=> LoadInfos("combat_21000073.json");
|
||||
|
||||
public static ImportedLayout LoadSpellbook()
|
||||
=> LayoutImporter.Build(LoadSpellbookInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadSpellbookInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadSpellbookInfos()
|
||||
=> LoadInfos("spellbook_21000034.json");
|
||||
|
|
@ -108,7 +109,7 @@ public static class FixtureLoader
|
|||
=> LoadInfos("component_row_21000033_10000467.json");
|
||||
|
||||
public static ImportedLayout LoadExamination()
|
||||
=> LayoutImporter.Build(LoadExaminationInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadExaminationInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadExaminationInfos()
|
||||
=> LoadInfos("examine_2100006B_100005F2.json");
|
||||
|
|
@ -120,31 +121,31 @@ public static class FixtureLoader
|
|||
=> LoadInfos("examine_component_2100006B_1000032E.json");
|
||||
|
||||
public static ImportedLayout LoadPowerbar()
|
||||
=> LayoutImporter.Build(LoadPowerbarInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadPowerbarInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadPowerbarInfos()
|
||||
=> LoadInfos("powerbar_21000072.json");
|
||||
|
||||
public static ImportedLayout LoadConfirmationDialog()
|
||||
=> LayoutImporter.Build(LoadConfirmationDialogInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadConfirmationDialogInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadConfirmationDialogInfos()
|
||||
=> LoadInfos("dialogs_2100003C.json");
|
||||
|
||||
public static ImportedLayout LoadFpsDisplay()
|
||||
=> LayoutImporter.Build(LoadFpsDisplayInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadFpsDisplayInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadFpsDisplayInfos()
|
||||
=> LoadInfos("smartbox_fps_2100000F.json");
|
||||
|
||||
public static ImportedLayout LoadPositiveEffects()
|
||||
=> LayoutImporter.Build(LoadPositiveEffectsInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadPositiveEffectsInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadPositiveEffectsInfos()
|
||||
=> LoadInfos("effects_positive_2100001B.json");
|
||||
|
||||
public static ImportedLayout LoadNegativeEffects()
|
||||
=> LayoutImporter.Build(LoadNegativeEffectsInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadNegativeEffectsInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadNegativeEffectsInfos()
|
||||
=> LoadInfos("effects_negative_2100001B.json");
|
||||
|
|
@ -154,31 +155,31 @@ public static class FixtureLoader
|
|||
|
||||
public static ImportedLayout LoadCharacterInformation()
|
||||
=> LayoutImporter.Build(
|
||||
LoadCharacterInformationInfos(), _ => (0u, 0, 0), null);
|
||||
LoadCharacterInformationInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadCharacterInformationInfos()
|
||||
=> LoadInfos("character_info_2100006E_10000183.json");
|
||||
|
||||
public static ImportedLayout LoadIndicators()
|
||||
=> LayoutImporter.Build(LoadIndicatorsInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadIndicatorsInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadIndicatorsInfos()
|
||||
=> LoadInfos("indicators_21000071.json");
|
||||
|
||||
public static ImportedLayout LoadLinkStatus()
|
||||
=> LayoutImporter.Build(LoadLinkStatusInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadLinkStatusInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadLinkStatusInfos()
|
||||
=> LoadInfos("link_status_2100001D.json");
|
||||
|
||||
public static ImportedLayout LoadVitae()
|
||||
=> LayoutImporter.Build(LoadVitaeInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadVitaeInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadVitaeInfos()
|
||||
=> LoadInfos("vitae_21000020.json");
|
||||
|
||||
public static ImportedLayout LoadMiniGame()
|
||||
=> LayoutImporter.Build(LoadMiniGameInfos(), _ => (0u, 0, 0), null);
|
||||
=> LayoutImporter.Build(LoadMiniGameInfos(), _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
|
||||
public static ElementInfo LoadMiniGameInfos()
|
||||
=> LoadInfos("mini_game_2100001E.json");
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.Core.Items;
|
||||
|
|
@ -9,7 +10,7 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
public sealed class IndicatorBarControllerTests
|
||||
{
|
||||
private const uint Player = 0x50000001u;
|
||||
private static (uint, int, int) NoTex(uint _) => (0u, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoTex(uint _) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
|
||||
[Fact]
|
||||
public void AuthoredFixture_BuildsAllSevenRetailIndicatorButtons()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System.Collections.Generic;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
|
@ -65,7 +66,7 @@ public class InventoryControllerTests
|
|||
StackSplitQuantityState? stackSplitQuantity = null,
|
||||
ItemInteractionController? itemInteraction = null)
|
||||
=> InventoryController.Bind(layout, objects, () => Player,
|
||||
iconIds: (_, _, _, _, _) => 0u,
|
||||
iconIds: (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
strength: () => strength, datFont: null,
|
||||
ownerName: ownerName is null ? null : () => ownerName,
|
||||
sendUse: uses is null ? null : g => uses.Add(g),
|
||||
|
|
@ -83,7 +84,7 @@ public class InventoryControllerTests
|
|||
private static UiButton MakeButton(uint id)
|
||||
{
|
||||
var info = new ElementInfo { Id = id, Type = 1 };
|
||||
return new UiButton(info, static _ => (0u, 0, 0)) { Width = 16, Height = 16 };
|
||||
return new UiButton(info, static _ => (GpuTextureSlot.Unassigned, 0, 0)) { Width = 16, Height = 16 };
|
||||
}
|
||||
|
||||
// Seed a side bag (a container) in the player's pack, plus optionally its own contents.
|
||||
|
|
@ -379,7 +380,7 @@ public class InventoryControllerTests
|
|||
{
|
||||
var (layout, grid, containers, top, _, _, _, _) = BuildLayout();
|
||||
InventoryController.Bind(layout, new ClientObjectTable(), () => Player,
|
||||
iconIds: (_, _, _, _, _) => 0u, strength: () => 100,
|
||||
iconIds: (_, _, _, _, _) => GpuTextureSlot.Unassigned, strength: () => 100,
|
||||
selection: new SelectionState(), datFont: null,
|
||||
contentsEmptySprite: 0x06004D20u, sideBagEmptySprite: 0x06005D9Cu, mainPackEmptySprite: 0x06005D9Cu);
|
||||
|
||||
|
|
@ -556,7 +557,7 @@ public class InventoryControllerTests
|
|||
nowMs: () => 1_000);
|
||||
|
||||
InventoryController.Bind(layout, objects, () => Player,
|
||||
iconIds: (_, _, _, _, _) => 0u,
|
||||
iconIds: (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
strength: () => 100,
|
||||
selection: new SelectionState(),
|
||||
datFont: null,
|
||||
|
|
@ -589,7 +590,7 @@ public class InventoryControllerTests
|
|||
objects.AddOrUpdate(new ClientObject { ObjectId = Player, IconId = 0x06001234u });
|
||||
(ItemType type, uint icon)? mainPackCall = null;
|
||||
InventoryController.Bind(layout, objects, () => Player,
|
||||
iconIds: (t, icon, _, _, _) => { if (icon == 0x0600127Eu) mainPackCall = (t, icon); return 0u; },
|
||||
iconIds: (t, icon, _, _, _) => { if (icon == 0x0600127Eu) mainPackCall = (t, icon); return GpuTextureSlot.Unassigned; },
|
||||
strength: () => 100, selection: new SelectionState(), datFont: null);
|
||||
|
||||
// Retail draws a constant backpack over the Container type-underlay (IconData::RenderIcons
|
||||
|
|
@ -682,7 +683,7 @@ public class InventoryControllerTests
|
|||
var puts = new List<(uint item, uint container, int placement)>();
|
||||
using var ctrl = Bind(layout, objects, puts: puts, selection: selection);
|
||||
var source = new UiItemSlot { SourceKind = ItemDragSource.Ground };
|
||||
source.SetItem(loot, 0u);
|
||||
source.SetItem(loot, GpuTextureSlot.Unassigned);
|
||||
var payload = new ItemDragPayload(loot, ItemDragSource.Ground, 0, source);
|
||||
|
||||
ctrl.HandleDropRelease(grid, grid.GetItem(1)!, payload);
|
||||
|
|
@ -732,7 +733,7 @@ public class InventoryControllerTests
|
|||
layout,
|
||||
objects,
|
||||
() => Player,
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
iconIds: static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
strength: () => 100,
|
||||
selection: new SelectionState(),
|
||||
datFont: null,
|
||||
|
|
@ -781,7 +782,7 @@ public class InventoryControllerTests
|
|||
layout,
|
||||
objects,
|
||||
() => Player,
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
iconIds: static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
strength: () => 100,
|
||||
selection: new SelectionState(),
|
||||
datFont: null,
|
||||
|
|
@ -834,7 +835,7 @@ public class InventoryControllerTests
|
|||
layout,
|
||||
objects,
|
||||
() => Player,
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
iconIds: static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
strength: () => 100,
|
||||
selection: new SelectionState(),
|
||||
datFont: null,
|
||||
|
|
@ -842,7 +843,7 @@ public class InventoryControllerTests
|
|||
puts.Add((item, container, placement)),
|
||||
itemInteraction: interaction);
|
||||
var source = new UiItemSlot { SourceKind = ItemDragSource.Ground };
|
||||
source.SetItem(draggedLoot, 0u);
|
||||
source.SetItem(draggedLoot, GpuTextureSlot.Unassigned);
|
||||
|
||||
inventory.HandleDropRelease(
|
||||
grid,
|
||||
|
|
@ -894,7 +895,7 @@ public class InventoryControllerTests
|
|||
layout,
|
||||
objects,
|
||||
() => Player,
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
iconIds: static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
strength: () => 100,
|
||||
selection: new SelectionState(),
|
||||
datFont: null,
|
||||
|
|
@ -902,7 +903,7 @@ public class InventoryControllerTests
|
|||
puts.Add((item, container, placement)),
|
||||
itemInteraction: interaction);
|
||||
var source = new UiItemSlot { SourceKind = ItemDragSource.Ground };
|
||||
source.SetItem(draggedLoot, 0u);
|
||||
source.SetItem(draggedLoot, GpuTextureSlot.Unassigned);
|
||||
|
||||
Assert.True(interaction.PlaceWorldItemInBackpack(directLoot));
|
||||
Assert.Equal(
|
||||
|
|
@ -959,7 +960,7 @@ public class InventoryControllerTests
|
|||
layout,
|
||||
objects,
|
||||
() => Player,
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
iconIds: static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
strength: () => 100,
|
||||
selection: new SelectionState(),
|
||||
datFont: null,
|
||||
|
|
@ -1022,7 +1023,7 @@ public class InventoryControllerTests
|
|||
layout,
|
||||
objects,
|
||||
() => Player,
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
iconIds: static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
strength: () => 100,
|
||||
selection: new SelectionState(),
|
||||
datFont: null,
|
||||
|
|
@ -1030,7 +1031,7 @@ public class InventoryControllerTests
|
|||
merges.Add((source, target, amount)),
|
||||
itemInteraction: interaction);
|
||||
var sourceCell = new UiItemSlot { SourceKind = ItemDragSource.Ground };
|
||||
sourceCell.SetItem(sourceStack, 0u);
|
||||
sourceCell.SetItem(sourceStack, GpuTextureSlot.Unassigned);
|
||||
|
||||
Assert.True(interaction.PlaceWorldItemInBackpack(pendingLoot));
|
||||
UiItemSlot targetCell = Enumerable.Range(0, grid.GetNumUIItems())
|
||||
|
|
@ -1083,7 +1084,7 @@ public class InventoryControllerTests
|
|||
layout,
|
||||
objects,
|
||||
() => Player,
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
iconIds: static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
strength: () => 100,
|
||||
selection: selection,
|
||||
datFont: null,
|
||||
|
|
@ -1092,7 +1093,7 @@ public class InventoryControllerTests
|
|||
itemInteraction: interaction,
|
||||
stackSplitQuantity: splitQuantity);
|
||||
var sourceCell = new UiItemSlot { SourceKind = ItemDragSource.Ground };
|
||||
sourceCell.SetItem(sourceStack, 0u);
|
||||
sourceCell.SetItem(sourceStack, GpuTextureSlot.Unassigned);
|
||||
|
||||
Assert.True(interaction.PlaceWorldItemInBackpack(pendingLoot));
|
||||
inventory.HandleDropRelease(
|
||||
|
|
@ -1131,7 +1132,7 @@ public class InventoryControllerTests
|
|||
layout,
|
||||
objects,
|
||||
() => Player,
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
iconIds: static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
strength: () => 100,
|
||||
selection: new SelectionState(),
|
||||
datFont: null,
|
||||
|
|
@ -1172,7 +1173,7 @@ public class InventoryControllerTests
|
|||
layout,
|
||||
objects,
|
||||
() => Player,
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
iconIds: static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
strength: () => 100,
|
||||
selection: new SelectionState(),
|
||||
datFont: null,
|
||||
|
|
@ -1212,7 +1213,7 @@ public class InventoryControllerTests
|
|||
layout,
|
||||
objects,
|
||||
() => Player,
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
iconIds: static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
strength: () => 100,
|
||||
selection: new SelectionState(),
|
||||
datFont: null,
|
||||
|
|
@ -1239,7 +1240,7 @@ public class InventoryControllerTests
|
|||
var puts = new List<(uint item, uint container, int placement)>();
|
||||
using var ctrl = Bind(layout, objects, puts: puts);
|
||||
var source = new UiItemSlot { SourceKind = ItemDragSource.Ground };
|
||||
source.SetItem(loot, 0u);
|
||||
source.SetItem(loot, GpuTextureSlot.Unassigned);
|
||||
var payload = new ItemDragPayload(loot, ItemDragSource.Ground, 0, source);
|
||||
|
||||
ctrl.HandleDropRelease(grid, grid.GetItem(1)!, payload);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System;
|
||||
using System.IO;
|
||||
using AcDream.App.UI;
|
||||
|
|
@ -43,7 +44,7 @@ public class InventoryFrameImportProbe
|
|||
if (datDir is null) return; // CI: no live dat — skip
|
||||
|
||||
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
||||
var layout = LayoutImporter.Import(dats, Frame, _ => (0u, 0, 0), null);
|
||||
var layout = LayoutImporter.Import(dats, Frame, _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
Assert.NotNull(layout);
|
||||
|
||||
// A representative spread across the slot grid (head, shield, the weapon composite, cloak,
|
||||
|
|
@ -63,7 +64,7 @@ public class InventoryFrameImportProbe
|
|||
if (datDir is null) return; // CI: no live dat — skip (this is a smoke test)
|
||||
|
||||
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
||||
var layout = LayoutImporter.Import(dats, Frame, _ => (0u, 0, 0), null);
|
||||
var layout = LayoutImporter.Import(dats, Frame, _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
Assert.NotNull(layout);
|
||||
|
||||
var backdrop = layout!.FindElement(Backdrop);
|
||||
|
|
@ -95,7 +96,7 @@ public class InventoryFrameImportProbe
|
|||
if (datDir is null) return; // CI: no live dat - skip
|
||||
|
||||
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
||||
var layout = LayoutImporter.Import(dats, Frame, _ => (0u, 0, 0), null);
|
||||
var layout = LayoutImporter.Import(dats, Frame, _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
Assert.NotNull(layout);
|
||||
|
||||
var close = layout!.FindElement(WindowChromeController.InventoryCloseButtonId);
|
||||
|
|
@ -108,7 +109,7 @@ public class InventoryFrameImportProbe
|
|||
layout,
|
||||
new ClientObjectTable(),
|
||||
playerGuid: static () => 0u,
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
iconIds: static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
strength: static () => 100,
|
||||
selection: new AcDream.Core.Selection.SelectionState(),
|
||||
datFont: null,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.Core.Items;
|
||||
|
|
@ -30,7 +31,7 @@ public sealed class ItemCooldownUiControllerTests
|
|||
double now = 112.5d;
|
||||
var root = new UiPanel();
|
||||
var list = new UiItemList();
|
||||
list.Cell.SetItem(0x5001u, 99u);
|
||||
list.Cell.SetItem(0x5001u, new GpuTextureSlot(99u));
|
||||
root.AddChild(list);
|
||||
uint[] sprites = Enumerable.Range(1, 10)
|
||||
.Select(index => 0x06000000u + (uint)index)
|
||||
|
|
@ -46,7 +47,7 @@ public sealed class ItemCooldownUiControllerTests
|
|||
Assert.Equal(sprites[5], list.Cell.ActiveCooldownSprite());
|
||||
|
||||
var future = new UiItemSlot();
|
||||
future.SetItem(0x5001u, 100u);
|
||||
future.SetItem(0x5001u, new GpuTextureSlot(100u));
|
||||
list.AddItem(future);
|
||||
Assert.Equal(sprites[5], future.ActiveCooldownSprite());
|
||||
|
||||
|
|
@ -81,7 +82,7 @@ public sealed class ItemCooldownUiControllerTests
|
|||
var root = new UiPanel();
|
||||
var window = new UiPanel();
|
||||
var list = new UiItemList();
|
||||
list.Cell.SetItem(0x5001u, 99u);
|
||||
list.Cell.SetItem(0x5001u, new GpuTextureSlot(99u));
|
||||
root.AddChild(window);
|
||||
window.AddChild(list);
|
||||
uint[] sprites = Enumerable.Range(1, 10)
|
||||
|
|
@ -117,7 +118,7 @@ public sealed class ItemCooldownUiControllerTests
|
|||
var spellbook = new Spellbook();
|
||||
var root = new UiPanel();
|
||||
var list = new UiItemList();
|
||||
list.Cell.SetItem(0x5001u, 99u);
|
||||
list.Cell.SetItem(0x5001u, new GpuTextureSlot(99u));
|
||||
root.AddChild(list);
|
||||
int clockReads = 0;
|
||||
ItemCooldownUiController controller = ItemCooldownUiController.Bind(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
||||
|
|
@ -9,7 +10,7 @@ public sealed class JumpPowerbarLayoutConformanceTests
|
|||
public void RetailFixture_UsesExactFloatyGeometryTrackAndJumpFill()
|
||||
{
|
||||
ElementInfo info = FixtureLoader.LoadPowerbarInfos();
|
||||
ImportedLayout layout = LayoutImporter.Build(info, _ => (0u, 0, 0), null);
|
||||
ImportedLayout layout = LayoutImporter.Build(info, _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
var meter = Assert.IsType<UiMeter>(
|
||||
layout.FindElement(JumpPowerbarController.MeterId));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
||||
|
|
@ -9,7 +10,7 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
/// </summary>
|
||||
public class LayoutImporterTests
|
||||
{
|
||||
private static (uint, int, int) NoTex(uint _) => (0, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoTex(uint _) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
|
||||
// ── Test 1: Health meter element → UiMeter with correct rect ─────────────
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.Core.Items;
|
||||
|
|
@ -59,7 +60,7 @@ public sealed class PaperdollClickMapTests
|
|||
ImportedLayout layout = Assert.IsType<ImportedLayout>(LayoutImporter.Import(
|
||||
dats,
|
||||
0x21000023u,
|
||||
static _ => (0u, 0, 0),
|
||||
static _ => (GpuTextureSlot.Unassigned, 0, 0),
|
||||
null));
|
||||
UiElement dragMask = Assert.IsAssignableFrom<UiElement>(
|
||||
layout.FindElement(PaperdollController.DollDragMaskId));
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System.Collections.Generic;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
|
@ -66,7 +67,7 @@ public class PaperdollControllerTests
|
|||
systemMessage: systemMessages is null ? null : systemMessages.Add);
|
||||
configureInteraction?.Invoke(itemInteraction);
|
||||
return PaperdollController.Bind(layout, objects, () => Player,
|
||||
iconIds: (_, _, _, _, _) => 0x1234u,
|
||||
iconIds: (_, _, _, _, _) => new GpuTextureSlot(0x1234u),
|
||||
itemInteraction: itemInteraction,
|
||||
emptySlotSprite: emptySlot,
|
||||
selection: selection ?? new SelectionState(),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System.Numerics;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
|
@ -132,7 +133,7 @@ public sealed class RadarControllerTests
|
|||
root.Children.Add(lockButton);
|
||||
|
||||
root.Children.Add(Sprite(RadarController.DragButtonId, 87, 6, 27, 27, 0x060074C9u, type: 2));
|
||||
return LayoutImporter.Build(root, _ => (0u, 0, 0), null);
|
||||
return LayoutImporter.Build(root, _ => (GpuTextureSlot.Unassigned, 0, 0), null);
|
||||
}
|
||||
|
||||
private static ElementInfo Sprite(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
||||
|
|
@ -180,7 +181,7 @@ public sealed class RetailPanelUiControllerTests
|
|||
return RetailWindowFrame.Mount(
|
||||
root,
|
||||
content,
|
||||
_ => (0u, 0, 0),
|
||||
_ => (GpuTextureSlot.Unassigned, 0, 0),
|
||||
new RetailWindowFrame.Options
|
||||
{
|
||||
WindowName = name,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
||||
|
|
@ -5,7 +6,7 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
|
||||
public sealed class RetailWindowFrameTests
|
||||
{
|
||||
private static (uint, int, int) NoTex(uint _) => (0u, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoTex(uint _) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
|
||||
[Theory]
|
||||
[InlineData(9, 459f, 288f)]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
|
@ -52,7 +53,7 @@ public class SelectedObjectControllerTests
|
|||
["StackedItemSelected"] = (0x06004CF4u, 3),
|
||||
},
|
||||
};
|
||||
var overlayEl = new UiDatElement(overlayInfo, _ => (0u, 0, 0));
|
||||
var overlayEl = new UiDatElement(overlayInfo, _ => (GpuTextureSlot.Unassigned, 0, 0));
|
||||
dict[SelectedObjectController.OverlayId] = overlayEl;
|
||||
root.AddChild(overlayEl);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
||||
|
|
@ -16,16 +17,16 @@ public sealed class SpellExamineComponentTemplateFactoryTests
|
|||
FixtureLoader.LoadExaminationComponentTemplateInfos();
|
||||
var factory = new SpellExamineComponentTemplateFactory(
|
||||
template,
|
||||
did => (did + 1_000u, 32, 32),
|
||||
did => (new GpuTextureSlot(did + 1_000u), 32, 32),
|
||||
defaultFont: null);
|
||||
|
||||
UiDatElement root = Assert.IsType<UiDatElement>(
|
||||
factory.Create(0xABCDu, owned));
|
||||
factory.Create(new GpuTextureSlot(0xABCDu), owned));
|
||||
UiDatElement missing = Assert.IsType<UiDatElement>(
|
||||
Assert.Single(root.Children));
|
||||
|
||||
Assert.Equal(SpellExamineComponentTemplateFactory.TemplateId, root.ElementId);
|
||||
Assert.Equal(0xABCDu, root.RuntimeImageTexture);
|
||||
Assert.Equal(new GpuTextureSlot(0xABCDu), root.RuntimeImageTexture);
|
||||
Assert.Empty(root.Children.OfType<UiTextureElement>());
|
||||
Assert.Equal(
|
||||
SpellExamineComponentTemplateFactory.MissingOverlayId,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.Spells;
|
||||
using AcDream.Content;
|
||||
using AcDream.App.UI;
|
||||
|
|
@ -30,7 +31,7 @@ public sealed class SpellbookWindowControllerTests
|
|||
{
|
||||
ImportedLayout layout = LayoutImporter.Build(
|
||||
FixtureLoader.LoadSpellbookInfos(),
|
||||
_ => (0u, 0, 0),
|
||||
_ => (GpuTextureSlot.Unassigned, 0, 0),
|
||||
datFont: null,
|
||||
stringResolve: value => value.StringId switch
|
||||
{
|
||||
|
|
@ -81,7 +82,7 @@ public sealed class SpellbookWindowControllerTests
|
|||
{
|
||||
ImportedLayout layout = LayoutImporter.Build(
|
||||
FixtureLoader.LoadSpellbookInfos(),
|
||||
_ => (0u, 0, 0),
|
||||
_ => (GpuTextureSlot.Unassigned, 0, 0),
|
||||
datFont: null,
|
||||
stringResolve: value => value.StringId == 164868556u ? "Delete" : "Filter");
|
||||
|
||||
|
|
@ -302,7 +303,7 @@ public sealed class SpellbookWindowControllerTests
|
|||
selection.Select(objectId, SelectionChangeSource.Inventory);
|
||||
},
|
||||
setDesiredComponent: (component, amount) => desired.Add((component, amount)),
|
||||
resolveComponentIcon: icon => icon + 0x1000u)!;
|
||||
resolveComponentIcon: icon => new GpuTextureSlot(icon + 0x1000u))!;
|
||||
controller.ShowPage(SpellbookWindowPage.Components);
|
||||
|
||||
UiItemList list = Assert.IsType<UiItemList>(
|
||||
|
|
@ -339,7 +340,7 @@ public sealed class SpellbookWindowControllerTests
|
|||
UiElement iconHost = Assert.IsAssignableFrom<UiElement>(copper.Content.FindElement(
|
||||
ComponentBookTemplateFactory.IconId));
|
||||
Assert.Equal(
|
||||
0x06001100u,
|
||||
new GpuTextureSlot(0x06001100u),
|
||||
Assert.IsType<UiTextureElement>(Assert.Single(iconHost.Children)).Texture);
|
||||
|
||||
copper.OnEvent(new UiEvent(0u, copper, UiEventType.Click));
|
||||
|
|
@ -401,7 +402,7 @@ public sealed class SpellbookWindowControllerTests
|
|||
SelectionState? selection = null,
|
||||
Action<uint>? selectObject = null,
|
||||
Action<uint, uint>? setDesiredComponent = null,
|
||||
Func<uint, uint>? resolveComponentIcon = null)
|
||||
Func<uint, GpuTextureSlot>? resolveComponentIcon = null)
|
||||
=> SpellbookWindowController.Bind(
|
||||
layout,
|
||||
spellbook,
|
||||
|
|
@ -409,8 +410,8 @@ public sealed class SpellbookWindowControllerTests
|
|||
() => 1u,
|
||||
components ?? new Dictionary<uint, SpellComponentDescriptor>(),
|
||||
selection ?? new SelectionState(),
|
||||
spellId => spellId + 1000u,
|
||||
resolveComponentIcon ?? (iconId => iconId),
|
||||
spellId => new GpuTextureSlot(spellId + 1000u),
|
||||
resolveComponentIcon ?? (iconId => new GpuTextureSlot(iconId)),
|
||||
spellId => spellId == 103u ? 8 : 1,
|
||||
selectObject ?? (_ => { }),
|
||||
addFavorite ?? (_ => { }),
|
||||
|
|
@ -430,7 +431,7 @@ public sealed class SpellbookWindowControllerTests
|
|||
new ComponentBookTemplateFactory(
|
||||
FixtureLoader.LoadComponentCategoryTemplateInfos(),
|
||||
FixtureLoader.LoadComponentRowTemplateInfos(),
|
||||
_ => (0u, 0, 0),
|
||||
_ => (GpuTextureSlot.Unassigned, 0, 0),
|
||||
defaultFont: null),
|
||||
RowStyle,
|
||||
rowFont: null);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.Spells;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
|
@ -10,7 +11,7 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
|
||||
public sealed class SpellcastingUiControllerTests
|
||||
{
|
||||
private static (uint, int, int) NoTex(uint _) => (0u, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoTex(uint _) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
|
||||
[Fact]
|
||||
public void ImportedFixture_UsesRetailEmptyCells_ShortcutDigits_AndCompleteCastButton()
|
||||
|
|
@ -160,8 +161,8 @@ public sealed class SpellcastingUiControllerTests
|
|||
Assert.True(host.Visible);
|
||||
UiCatalogSlot slot = Assert.IsType<UiCatalogSlot>(host.Children[^1]);
|
||||
Assert.Equal(2u, slot.EntryId);
|
||||
Assert.Equal(2670u, slot.CatalogIconTexture);
|
||||
Assert.Equal(2u, slot.CatalogOverlayTexture);
|
||||
Assert.Equal(new GpuTextureSlot(2670u), slot.CatalogIconTexture);
|
||||
Assert.Equal(new GpuTextureSlot(2u), slot.CatalogOverlayTexture);
|
||||
|
||||
slot.OnEvent(new UiEvent(0, slot, UiEventType.Click));
|
||||
var cast = Assert.IsType<UiButton>(
|
||||
|
|
@ -338,8 +339,8 @@ public sealed class SpellcastingUiControllerTests
|
|||
new NoopSpellCastOperations());
|
||||
return SpellcastingUiController.Bind(
|
||||
layout, spellbook, casting, objects, () => 1u,
|
||||
spellId => spellId,
|
||||
item => item.ObjectId,
|
||||
spellId => new GpuTextureSlot(spellId),
|
||||
item => new GpuTextureSlot(item.ObjectId),
|
||||
useItem,
|
||||
selectionState,
|
||||
(tab, position, spellId) =>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AcDream.App.UI;
|
||||
|
|
@ -66,7 +67,7 @@ public class ToolbarControllerTests
|
|||
|
||||
void AddSlot(uint id)
|
||||
{
|
||||
var list = new UiItemList(_ => (0u, 0, 0)) { Width = 32, Height = 32 };
|
||||
var list = new UiItemList(_ => (GpuTextureSlot.Unassigned, 0, 0)) { Width = 32, Height = 32 };
|
||||
dict[id] = list; slots[id] = list; root.AddChild(list);
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +102,7 @@ public class ToolbarControllerTests
|
|||
},
|
||||
};
|
||||
}
|
||||
var button = new UiButton(info, _ => (0u, 0, 0)) { Width = 32, Height = 32 };
|
||||
var button = new UiButton(info, _ => (GpuTextureSlot.Unassigned, 0, 0)) { Width = 32, Height = 32 };
|
||||
dict[id] = button;
|
||||
root.AddChild(button);
|
||||
}
|
||||
|
|
@ -117,10 +118,10 @@ public class ToolbarControllerTests
|
|||
{ new(Index: 0, ObjectId: 0x5001u, SpellId: 0) };
|
||||
|
||||
ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_,_,_,_,_) => 0x77u, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => new GpuTextureSlot(0x77u), useItem: _ => { });
|
||||
|
||||
Assert.Equal(0x5001u, slots[Row1[0]].Cell.ItemId);
|
||||
Assert.Equal(0x77u, slots[Row1[0]].Cell.IconTexture);
|
||||
Assert.Equal(new GpuTextureSlot(0x77u), slots[Row1[0]].Cell.IconTexture);
|
||||
Assert.Equal(0u, slots[Row1[1]].Cell.ItemId); // others empty
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +144,7 @@ public class ToolbarControllerTests
|
|||
layout,
|
||||
repo,
|
||||
Store(shortcuts),
|
||||
iconIds: (_, _, _, _, _) => 0x77u,
|
||||
iconIds: (_, _, _, _, _) => new GpuTextureSlot(0x77u),
|
||||
useItem: _ => { });
|
||||
Assert.Equal(0x5001u, slots[Row1[0]].Cell.ItemId);
|
||||
|
||||
|
|
@ -161,7 +162,7 @@ public class ToolbarControllerTests
|
|||
{ new(Index: 2, ObjectId: 0x5002u, SpellId: 0) };
|
||||
|
||||
ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_,_,_,_,_) => 0x88u, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => new GpuTextureSlot(0x88u), useItem: _ => { });
|
||||
Assert.Equal(0u, slots[Row1[2]].Cell.ItemId); // not bound yet
|
||||
|
||||
repo.AddOrUpdate(new ClientObject { ObjectId = 0x5002u, WeenieClassId = 1u, IconId = 0x06005678u });
|
||||
|
|
@ -177,7 +178,7 @@ public class ToolbarControllerTests
|
|||
var shortcuts = new List<ShortcutEntry>
|
||||
{ new(Index: 2, ObjectId: 0x5002u, SpellId: 0) };
|
||||
var controller = ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_,_,_,_,_) => 0x88u, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => new GpuTextureSlot(0x88u), useItem: _ => { });
|
||||
|
||||
controller.Dispose();
|
||||
controller.Dispose();
|
||||
|
|
@ -203,7 +204,7 @@ public class ToolbarControllerTests
|
|||
var selection = new SelectionState();
|
||||
|
||||
ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_,_,_,_,_) => 0x77u,
|
||||
iconIds: (_,_,_,_,_) => new GpuTextureSlot(0x77u),
|
||||
useItem: g => used = g,
|
||||
selection: selection);
|
||||
UiItemSlot cell = slots[Row1[0]].Cell;
|
||||
|
|
@ -226,7 +227,7 @@ public class ToolbarControllerTests
|
|||
|
||||
var ctrl = ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) => 0u, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { });
|
||||
ctrl.BindPanelButtons(
|
||||
panelId => panelId is RetailPanelCatalog.Inventory or RetailPanelCatalog.Character,
|
||||
toggles.Add);
|
||||
|
|
@ -277,7 +278,7 @@ public class ToolbarControllerTests
|
|||
|
||||
var ctrl = ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) => 0u,
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned,
|
||||
useItem: _ => { },
|
||||
itemInteraction: interaction);
|
||||
ctrl.BindPanelButtons(
|
||||
|
|
@ -304,7 +305,7 @@ public class ToolbarControllerTests
|
|||
var puts = new List<(uint Item, uint Container, int Placement)>();
|
||||
ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_, _, _, _, _) => 0u,
|
||||
iconIds: (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
useItem: _ => { },
|
||||
playerGuid: () => player,
|
||||
sendPutItemInContainer: (i, c, p) => puts.Add((i, c, p)));
|
||||
|
|
@ -344,7 +345,7 @@ public class ToolbarControllerTests
|
|||
layout,
|
||||
repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
iconIds: static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
useItem: static _ => { },
|
||||
itemInteraction: interaction,
|
||||
playerGuid: () => player,
|
||||
|
|
@ -394,7 +395,7 @@ public class ToolbarControllerTests
|
|||
layout,
|
||||
repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: static (_, _, _, _, _) => 0u,
|
||||
iconIds: static (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
useItem: static _ => { },
|
||||
itemInteraction: interaction,
|
||||
playerGuid: () => player,
|
||||
|
|
@ -426,7 +427,7 @@ public class ToolbarControllerTests
|
|||
var puts = new List<(uint Item, uint Container, int Placement)>();
|
||||
ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_, _, _, _, _) => 0u,
|
||||
iconIds: (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
useItem: _ => { },
|
||||
playerGuid: () => player,
|
||||
sendPutItemInContainer: (i, c, p) => puts.Add((i, c, p)));
|
||||
|
|
@ -447,7 +448,7 @@ public class ToolbarControllerTests
|
|||
var repo = new ClientObjectTable();
|
||||
var ctrl = ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) => 0u, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { });
|
||||
var inventoryButton = (UiButton)layout.FindElement(InventoryButtonId)!;
|
||||
var characterButton = (UiButton)layout.FindElement(CharacterButtonId)!;
|
||||
|
||||
|
|
@ -524,7 +525,7 @@ public class ToolbarControllerTests
|
|||
layout,
|
||||
repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_, _, _, _, _) => 0u,
|
||||
iconIds: (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
useItem: _ => { },
|
||||
itemInteraction: interaction,
|
||||
selectedObjectId: () => selected);
|
||||
|
|
@ -582,7 +583,7 @@ public class ToolbarControllerTests
|
|||
layout,
|
||||
repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_, _, _, _, _) => 0u,
|
||||
iconIds: (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
useItem: _ => { },
|
||||
itemInteraction: interaction,
|
||||
selectedObjectId: () => selection.SelectedObjectId ?? 0u,
|
||||
|
|
@ -648,7 +649,7 @@ public class ToolbarControllerTests
|
|||
layout,
|
||||
repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_, _, _, _, _) => 0u,
|
||||
iconIds: (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
useItem: _ => { },
|
||||
itemInteraction: interaction,
|
||||
selectedObjectId: () => selection.SelectedObjectId ?? 0u,
|
||||
|
|
@ -691,7 +692,7 @@ public class ToolbarControllerTests
|
|||
layout,
|
||||
repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_, _, _, _, _) => 0u,
|
||||
iconIds: (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
useItem: _ => { },
|
||||
playerGuid: () => player);
|
||||
var ammoButton = (UiButton)layout.FindElement(0x10000194u)!;
|
||||
|
|
@ -730,7 +731,7 @@ public class ToolbarControllerTests
|
|||
layout,
|
||||
repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_, _, _, _, _) => 0u,
|
||||
iconIds: (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
useItem: _ => { },
|
||||
playerGuid: () => player);
|
||||
var ammoButton = (UiButton)layout.FindElement(0x10000194u)!;
|
||||
|
|
@ -752,7 +753,7 @@ public class ToolbarControllerTests
|
|||
layout,
|
||||
repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_, _, _, _, _) => 0u,
|
||||
iconIds: (_, _, _, _, _) => GpuTextureSlot.Unassigned,
|
||||
useItem: _ => { },
|
||||
toggleCombat: () => toggles++);
|
||||
|
||||
|
|
@ -779,7 +780,7 @@ public class ToolbarControllerTests
|
|||
layout,
|
||||
repo,
|
||||
Store(shortcuts),
|
||||
iconIds: (_, _, _, _, _) => 1u,
|
||||
iconIds: (_, _, _, _, _) => new GpuTextureSlot(1u),
|
||||
useItem: id => used = id,
|
||||
selectItem: id => selected = id);
|
||||
|
||||
|
|
@ -816,7 +817,7 @@ public class ToolbarControllerTests
|
|||
layout,
|
||||
repo,
|
||||
Store(shortcuts),
|
||||
iconIds: (_, _, _, _, _) => 1u,
|
||||
iconIds: (_, _, _, _, _) => new GpuTextureSlot(1u),
|
||||
useItem: _ => { },
|
||||
itemInteraction: interaction,
|
||||
selectItem: id => selection.Select(id, SelectionChangeSource.Toolbar),
|
||||
|
|
@ -870,7 +871,7 @@ public class ToolbarControllerTests
|
|||
layout,
|
||||
repo,
|
||||
Store(shortcuts),
|
||||
iconIds: (_, _, _, _, _) => 1u,
|
||||
iconIds: (_, _, _, _, _) => new GpuTextureSlot(1u),
|
||||
useItem: _ => { },
|
||||
itemInteraction: interaction);
|
||||
|
||||
|
|
@ -909,7 +910,7 @@ public class ToolbarControllerTests
|
|||
layout,
|
||||
repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_, _, _, _, _) => 1u,
|
||||
iconIds: (_, _, _, _, _) => new GpuTextureSlot(1u),
|
||||
useItem: _ => { },
|
||||
itemInteraction: interaction,
|
||||
sendAddShortcut: entry => sends.Add(((uint)entry.Index, entry.ObjectId)));
|
||||
|
|
@ -935,7 +936,7 @@ public class ToolbarControllerTests
|
|||
|
||||
ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) =>0u, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { });
|
||||
|
||||
// Only peace indicator (index 0 = 0x10000192) is visible.
|
||||
Assert.True (indicators[0x10000192u].Visible, "peace indicator should be visible after bind");
|
||||
|
|
@ -955,7 +956,7 @@ public class ToolbarControllerTests
|
|||
|
||||
var ctrl = ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) =>0u, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { });
|
||||
|
||||
ctrl.SetCombatMode(CombatMode.Melee);
|
||||
|
||||
|
|
@ -977,7 +978,7 @@ public class ToolbarControllerTests
|
|||
|
||||
ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) =>0u, useItem: _ => { },
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { },
|
||||
combatState: combat);
|
||||
|
||||
// Initially NonCombat after bind.
|
||||
|
|
@ -1016,7 +1017,7 @@ public class ToolbarControllerTests
|
|||
|
||||
ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) => 0u, useItem: _ => { },
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { },
|
||||
regularDigits: FakeRegular, ghostedDigits: FakeGhosted);
|
||||
|
||||
// Top row: ShortcutNum == slot index, ghosted == false.
|
||||
|
|
@ -1045,7 +1046,7 @@ public class ToolbarControllerTests
|
|||
var repo = new ClientObjectTable();
|
||||
var ctrl = ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) => 0u, useItem: _ => { },
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { },
|
||||
regularDigits: FakeRegular, ghostedDigits: FakeGhosted);
|
||||
|
||||
ctrl.SetCombatMode(mode);
|
||||
|
|
@ -1055,7 +1056,7 @@ public class ToolbarControllerTests
|
|||
var cell = slots[Row1[i]].Cell;
|
||||
Assert.Equal(i, cell.ShortcutNum);
|
||||
Assert.False(cell.ShortcutGhosted, $"top-row slot {i} should be regular in {mode}");
|
||||
cell.SetItem((uint)(0x5000 + i), 0x99u);
|
||||
cell.SetItem((uint)(0x5000 + i), new GpuTextureSlot(0x99u));
|
||||
Assert.Same(FakeRegular, cell.ActiveDigitArray());
|
||||
}
|
||||
// Bottom row still has no number.
|
||||
|
|
@ -1073,13 +1074,13 @@ public class ToolbarControllerTests
|
|||
var repo = new ClientObjectTable();
|
||||
var ctrl = ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) => 0u, useItem: _ => { },
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { },
|
||||
regularDigits: FakeRegular, ghostedDigits: FakeGhosted);
|
||||
|
||||
ctrl.SetCombatMode(CombatMode.Magic);
|
||||
foreach (var id in Row1)
|
||||
{
|
||||
slots[id].Cell.SetItem(id, 0x99u);
|
||||
slots[id].Cell.SetItem(id, new GpuTextureSlot(0x99u));
|
||||
Assert.True(slots[id].Cell.ShortcutGhosted);
|
||||
Assert.Same(FakeGhosted, slots[id].Cell.ActiveDigitArray());
|
||||
}
|
||||
|
|
@ -1105,7 +1106,7 @@ public class ToolbarControllerTests
|
|||
|
||||
ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) => 0u, useItem: _ => { },
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { },
|
||||
regularDigits: FakeRegular, ghostedDigits: FakeGhosted);
|
||||
|
||||
foreach (var id in Row1)
|
||||
|
|
@ -1127,7 +1128,7 @@ public class ToolbarControllerTests
|
|||
|
||||
ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) => 0u, useItem: _ => { },
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { },
|
||||
regularDigits: FakeRegular, ghostedDigits: FakeGhosted, emptyDigits: FakeEmpty);
|
||||
|
||||
foreach (var id in Row1)
|
||||
|
|
@ -1148,7 +1149,7 @@ public class ToolbarControllerTests
|
|||
|
||||
ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) => 0u, useItem: _ => { },
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { },
|
||||
regularDigits: FakeRegular, ghostedDigits: FakeGhosted, emptyDigits: null);
|
||||
|
||||
foreach (var id in Row1)
|
||||
|
|
@ -1174,7 +1175,7 @@ public class ToolbarControllerTests
|
|||
|
||||
int iconCallCount = 0;
|
||||
ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_,_,_,_,_) => { iconCallCount++; return 0x77u; }, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => { iconCallCount++; return new GpuTextureSlot(0x77u); }, useItem: _ => { });
|
||||
|
||||
int callsAfterBind = iconCallCount; // 1 call from initial Populate
|
||||
|
||||
|
|
@ -1199,7 +1200,7 @@ public class ToolbarControllerTests
|
|||
|
||||
int iconCallCount = 0;
|
||||
ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_,_,_,_,_) => { iconCallCount++; return 0x99u; }, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => { iconCallCount++; return new GpuTextureSlot(0x99u); }, useItem: _ => { });
|
||||
|
||||
Assert.Equal(0, iconCallCount); // not called — item absent during initial Populate
|
||||
Assert.Equal(0u, slots[Row1[1]].Cell.ItemId);
|
||||
|
|
@ -1225,7 +1226,7 @@ public class ToolbarControllerTests
|
|||
{ new(Index: 3, ObjectId: 0x5004u, SpellId: 0) };
|
||||
|
||||
ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_,_,_,_,_) => 0xAAu, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => new GpuTextureSlot(0xAAu), useItem: _ => { });
|
||||
|
||||
Assert.Equal(0x5004u, slots[Row1[3]].Cell.ItemId); // bound
|
||||
|
||||
|
|
@ -1252,7 +1253,7 @@ public class ToolbarControllerTests
|
|||
|
||||
int iconCallCount = 0;
|
||||
ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_,_,_,_,_) => { iconCallCount++; return 0xBBu; }, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => { iconCallCount++; return new GpuTextureSlot(0xBBu); }, useItem: _ => { });
|
||||
|
||||
int callsAfterBind = iconCallCount; // 1 call for the shortcut item
|
||||
|
||||
|
|
@ -1274,7 +1275,7 @@ public class ToolbarControllerTests
|
|||
|
||||
var ctrl = ToolbarController.Bind(layout, repo,
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) => 0u, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { });
|
||||
|
||||
for (int i = 0; i < Row1.Length; i++)
|
||||
{
|
||||
|
|
@ -1299,7 +1300,7 @@ public class ToolbarControllerTests
|
|||
var (layout, slots, _) = FakeToolbar();
|
||||
var ctrl = ToolbarController.Bind(layout, new ClientObjectTable(),
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) => 0u, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { });
|
||||
|
||||
var list = slots[Row1[0]];
|
||||
var payload = new ItemDragPayload(0x5001u, ItemDragSource.Inventory, 0, new UiItemSlot());
|
||||
|
|
@ -1314,7 +1315,7 @@ public class ToolbarControllerTests
|
|||
var (layout, slots, _) = FakeToolbar();
|
||||
var ctrl = ToolbarController.Bind(layout, new ClientObjectTable(),
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) => 0u, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { });
|
||||
var list = slots[Row1[0]];
|
||||
var payload = new ItemDragPayload(0u, ItemDragSource.Inventory, 0, new UiItemSlot());
|
||||
Assert.Equal(ItemDragAcceptance.None, ctrl.OnDragOver(list, list.Cell, payload));
|
||||
|
|
@ -1343,7 +1344,7 @@ public class ToolbarControllerTests
|
|||
uint selected = 0;
|
||||
|
||||
var ctrl = ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_,_,_,_,_) => 0x77u, useItem: _ => { },
|
||||
iconIds: (_,_,_,_,_) => new GpuTextureSlot(0x77u), useItem: _ => { },
|
||||
sendAddShortcut: add, sendRemoveShortcut: rem,
|
||||
selectItem: item => selected = item, selectedObjectId: () => selected);
|
||||
Assert.Equal(0x5001u, slots[Row1[3]].Cell.ItemId);
|
||||
|
|
@ -1368,7 +1369,7 @@ public class ToolbarControllerTests
|
|||
new(Index: 5, ObjectId: 0x5002u, SpellId: 0) };
|
||||
var (adds, removes) = NewSpies(out var add, out var rem);
|
||||
var ctrl = ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_,_,_,_,_) => 0x77u, useItem: _ => { },
|
||||
iconIds: (_,_,_,_,_) => new GpuTextureSlot(0x77u), useItem: _ => { },
|
||||
sendAddShortcut: add, sendRemoveShortcut: rem);
|
||||
|
||||
var payload = new ItemDragPayload(0x5001u, ItemDragSource.ShortcutBar, 3, slots[Row1[3]].Cell);
|
||||
|
|
@ -1397,7 +1398,7 @@ public class ToolbarControllerTests
|
|||
var (adds, _) = NewSpies(out var add, out var remove);
|
||||
var controller = ToolbarController.Bind(
|
||||
layout, repo, Store(shortcuts),
|
||||
iconIds: (_, _, _, _, _) => 1u,
|
||||
iconIds: (_, _, _, _, _) => new GpuTextureSlot(1u),
|
||||
useItem: _ => { },
|
||||
sendAddShortcut: add,
|
||||
sendRemoveShortcut: remove);
|
||||
|
|
@ -1420,7 +1421,7 @@ public class ToolbarControllerTests
|
|||
{ new(Index: 3, ObjectId: 0x5001u, SpellId: 0) };
|
||||
var (adds, removes) = NewSpies(out var add, out var rem);
|
||||
var ctrl = ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_,_,_,_,_) => 0x77u, useItem: _ => { },
|
||||
iconIds: (_,_,_,_,_) => new GpuTextureSlot(0x77u), useItem: _ => { },
|
||||
sendAddShortcut: add, sendRemoveShortcut: rem);
|
||||
|
||||
var payload = new ItemDragPayload(0x5001u, ItemDragSource.ShortcutBar, 3, slots[Row1[3]].Cell);
|
||||
|
|
@ -1446,7 +1447,7 @@ public class ToolbarControllerTests
|
|||
};
|
||||
var wire = new List<string>();
|
||||
var ctrl = ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_, _, _, _, _) => 1u,
|
||||
iconIds: (_, _, _, _, _) => new GpuTextureSlot(1u),
|
||||
useItem: _ => { },
|
||||
sendAddShortcut: entry => wire.Add($"add:{entry.Index}:{entry.ObjectId:X8}:{entry.SpellId:X8}"),
|
||||
sendRemoveShortcut: slot => wire.Add($"remove:{slot}"));
|
||||
|
|
@ -1479,7 +1480,7 @@ public class ToolbarControllerTests
|
|||
};
|
||||
var wire = new List<string>();
|
||||
var ctrl = ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_, _, _, _, _) => 1u,
|
||||
iconIds: (_, _, _, _, _) => new GpuTextureSlot(1u),
|
||||
useItem: _ => { },
|
||||
sendAddShortcut: entry => wire.Add($"add:{entry.Index}:{entry.ObjectId:X8}:{entry.SpellId:X8}"),
|
||||
sendRemoveShortcut: slot => wire.Add($"remove:{slot}"));
|
||||
|
|
@ -1504,7 +1505,7 @@ public class ToolbarControllerTests
|
|||
{ new(Index: 3, ObjectId: 0x5001u, SpellId: 0) };
|
||||
var (adds, removes) = NewSpies(out var add, out var rem);
|
||||
var ctrl = ToolbarController.Bind(layout, repo, Store(shortcuts),
|
||||
iconIds: (_,_,_,_,_) => 0x77u, useItem: _ => { },
|
||||
iconIds: (_,_,_,_,_) => new GpuTextureSlot(0x77u), useItem: _ => { },
|
||||
sendAddShortcut: add, sendRemoveShortcut: rem);
|
||||
|
||||
var payload = new ItemDragPayload(0x5001u, ItemDragSource.ShortcutBar, 3, slots[Row1[3]].Cell);
|
||||
|
|
@ -1523,7 +1524,7 @@ public class ToolbarControllerTests
|
|||
var (layout, slots, _) = FakeToolbar();
|
||||
ToolbarController.Bind(layout, new ClientObjectTable(),
|
||||
new ShortcutStore(),
|
||||
iconIds: (_,_,_,_,_) => 0u, useItem: _ => { });
|
||||
iconIds: (_,_,_,_,_) => GpuTextureSlot.Unassigned, useItem: _ => { });
|
||||
Assert.Equal(0x060011FAu, slots[Row1[0]].Cell.DragAcceptSprite); // green cross, not the ring F9
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
namespace AcDream.App.Tests.UI.Layout;
|
||||
|
|
@ -10,7 +11,7 @@ public class UiDatElementTests
|
|||
var info = new ElementInfo();
|
||||
info.StateMedia[""] = (0x06000001, 1); // DirectState (DrawMode Normal=1)
|
||||
info.StateMedia["ShowDetail"] = (0x06000002, 3); // named (Alphablend=3)
|
||||
var e = new UiDatElement(info, _ => (0, 0, 0)) { ActiveState = "ShowDetail" };
|
||||
var e = new UiDatElement(info, _ => (GpuTextureSlot.Unassigned, 0, 0)) { ActiveState = "ShowDetail" };
|
||||
Assert.Equal(0x06000002u, e.ActiveMedia().File);
|
||||
Assert.Equal(3, e.ActiveMedia().DrawMode);
|
||||
e.ActiveState = "";
|
||||
|
|
@ -21,7 +22,7 @@ public class UiDatElementTests
|
|||
[Fact]
|
||||
public void ActiveMedia_NoMedia_ReturnsZero()
|
||||
{
|
||||
var e = new UiDatElement(new ElementInfo(), _ => (0, 0, 0));
|
||||
var e = new UiDatElement(new ElementInfo(), _ => (GpuTextureSlot.Unassigned, 0, 0));
|
||||
Assert.Equal(0u, e.ActiveMedia().File);
|
||||
Assert.Equal(0, e.ActiveMedia().DrawMode);
|
||||
}
|
||||
|
|
@ -31,7 +32,7 @@ public class UiDatElementTests
|
|||
{
|
||||
var info = new ElementInfo();
|
||||
info.StateMedia[""] = (0x06000005, 1);
|
||||
var e = new UiDatElement(info, _ => (0, 0, 0)) { ActiveState = "NoSuchState" };
|
||||
var e = new UiDatElement(info, _ => (GpuTextureSlot.Unassigned, 0, 0)) { ActiveState = "NoSuchState" };
|
||||
Assert.Equal(0x06000005u, e.ActiveMedia().File);
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +50,7 @@ public class UiDatElementTests
|
|||
info.StateMedia["Normal"] = (0x0000AAAAu, 1);
|
||||
info.StateMedia["Hover"] = (0x0000BBBBu, 1);
|
||||
|
||||
var e = new UiDatElement(info, _ => (0, 0, 0));
|
||||
var e = new UiDatElement(info, _ => (GpuTextureSlot.Unassigned, 0, 0));
|
||||
|
||||
// Should have defaulted to "Normal" state.
|
||||
Assert.Equal(0x0000AAAAu, e.ActiveMedia().File);
|
||||
|
|
@ -67,7 +68,7 @@ public class UiDatElementTests
|
|||
info.StateMedia["Maximized"] = (0x0000CCCCu, 1);
|
||||
info.StateMedia["Normal"] = (0x0000DDDDu, 1);
|
||||
|
||||
var e = new UiDatElement(info, _ => (0, 0, 0));
|
||||
var e = new UiDatElement(info, _ => (GpuTextureSlot.Unassigned, 0, 0));
|
||||
|
||||
// DefaultStateName "Minimized" wins over "Normal" implicit default.
|
||||
Assert.Equal(0x0000BBBBu, e.ActiveMedia().File);
|
||||
|
|
@ -83,7 +84,7 @@ public class UiDatElementTests
|
|||
var info = new ElementInfo();
|
||||
info.StateMedia[""] = (0x06007777u, 1); // DirectState only (e.g. vitals chrome corner)
|
||||
|
||||
var e = new UiDatElement(info, _ => (0, 0, 0));
|
||||
var e = new UiDatElement(info, _ => (GpuTextureSlot.Unassigned, 0, 0));
|
||||
|
||||
// No DefaultStateName, no "Normal" state → ActiveState stays "" (DirectState).
|
||||
Assert.Equal(0x06007777u, e.ActiveMedia().File);
|
||||
|
|
@ -100,7 +101,7 @@ public class UiDatElementTests
|
|||
Image = new UiImageMedia(0x06000009u, 3),
|
||||
};
|
||||
info.StateMedia["ShowDetail"] = (0x06000009u, 3);
|
||||
var element = new UiDatElement(info, _ => (0u, 0, 0))
|
||||
var element = new UiDatElement(info, _ => (GpuTextureSlot.Unassigned, 0, 0))
|
||||
{
|
||||
Left = info.X,
|
||||
Top = info.Y,
|
||||
|
|
@ -121,7 +122,7 @@ public class UiDatElementTests
|
|||
{
|
||||
var info = new ElementInfo { DefaultStateName = "Normal" };
|
||||
info.StateMedia["Normal"] = (0x06000001u, 1);
|
||||
var element = new UiDatElement(info, _ => (0u, 0, 0));
|
||||
var element = new UiDatElement(info, _ => (GpuTextureSlot.Unassigned, 0, 0));
|
||||
|
||||
Assert.False(element.TrySetRetailState(RetailUiStateIds.ShowDetail));
|
||||
Assert.Equal("Normal", element.ActiveState);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
||||
|
|
@ -5,7 +6,7 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
|
||||
public class UiViewportFactoryTests
|
||||
{
|
||||
private static (uint, int, int) NoTex(uint _) => (0, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoTex(uint _) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
|
||||
[Fact]
|
||||
public void Factory_builds_UiViewport_for_dat_type_0xD()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
|
||||
namespace AcDream.App.Tests.UI;
|
||||
|
|
@ -22,7 +23,7 @@ public class MarkupDocumentTests
|
|||
" <meter id=\"health\" x=\"8\" y=\"24\" w=\"200\" h=\"14\" fill=\"{HealthPercent}\" cur=\"{HealthCurrent}\" max=\"{HealthMax}\" color=\"#FFFF0000\"/>" +
|
||||
"</panel>";
|
||||
|
||||
var panel = MarkupDocument.Build(xml, new FakeBinding(), _ => ((uint)1, 32, 32));
|
||||
var panel = MarkupDocument.Build(xml, new FakeBinding(), _ => (new GpuTextureSlot(1), 32, 32));
|
||||
|
||||
Assert.IsType<UiNineSlicePanel>(panel);
|
||||
Assert.Equal(10f, panel.Left);
|
||||
|
|
@ -42,7 +43,7 @@ public class MarkupDocumentTests
|
|||
"<panel id=\"v\" x=\"0\" y=\"0\" w=\"10\" h=\"10\" title=\"V\">" +
|
||||
" <meter id=\"mana\" x=\"0\" y=\"0\" w=\"10\" h=\"2\" fill=\"{ManaPercent}\" cur=\"{ManaCurrent}\" max=\"{ManaMax}\" color=\"#FF0000FF\"/>" +
|
||||
"</panel>";
|
||||
var panel = MarkupDocument.Build(xml, new FakeBinding(), _ => ((uint)1, 32, 32));
|
||||
var panel = MarkupDocument.Build(xml, new FakeBinding(), _ => (new GpuTextureSlot(1), 32, 32));
|
||||
var meter = Assert.IsType<UiMeter>(panel.Children[1]);
|
||||
Assert.Null(meter.Fill());
|
||||
Assert.Null(meter.Label());
|
||||
|
|
@ -52,7 +53,7 @@ public class MarkupDocumentTests
|
|||
public void Build_ResizeAttrX_SetsHorizontalOnly()
|
||||
{
|
||||
const string xml = "<panel id=\"v\" x=\"0\" y=\"0\" w=\"100\" h=\"50\" title=\"V\" resize=\"x\"></panel>";
|
||||
var panel = MarkupDocument.Build(xml, new object(), _ => ((uint)1, 32, 32));
|
||||
var panel = MarkupDocument.Build(xml, new object(), _ => (new GpuTextureSlot(1), 32, 32));
|
||||
Assert.True(panel.ResizeX);
|
||||
Assert.False(panel.ResizeY);
|
||||
}
|
||||
|
|
@ -65,7 +66,7 @@ public class MarkupDocumentTests
|
|||
"backleft=\"0x06001141\" backtile=\"0x06001140\" backright=\"0x0600113F\" " +
|
||||
"frontleft=\"0x06001131\" fronttile=\"0x06001132\" frontright=\"0x06001133\"/>" +
|
||||
"</panel>";
|
||||
var panel = MarkupDocument.Build(xml, new FakeBinding(), _ => ((uint)7, 32, 32));
|
||||
var panel = MarkupDocument.Build(xml, new FakeBinding(), _ => (new GpuTextureSlot(7), 32, 32));
|
||||
var meter = Assert.IsType<UiMeter>(panel.Children[1]);
|
||||
Assert.Equal(0x06001141u, meter.BackLeft);
|
||||
Assert.Equal(0x06001140u, meter.BackTile);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using AcDream.App.UI;
|
||||
|
|
@ -96,7 +97,7 @@ public sealed class RetailUiAutomationProbeTests
|
|||
var root = new UiRoot { Width = 240, Height = 120 };
|
||||
var objects = new ClientObjectTable();
|
||||
|
||||
var source = new UiItemList(_ => (1u, 1, 1))
|
||||
var source = new UiItemList(_ => (new GpuTextureSlot(1u), 1, 1))
|
||||
{
|
||||
DatElementId = 0x10000010u,
|
||||
Left = 10,
|
||||
|
|
@ -106,9 +107,9 @@ public sealed class RetailUiAutomationProbeTests
|
|||
};
|
||||
source.Cell.SlotIndex = 0;
|
||||
source.Cell.SourceKind = ItemDragSource.Inventory;
|
||||
source.Cell.SetItem(0x5001u, 0x99u);
|
||||
source.Cell.SetItem(0x5001u, new GpuTextureSlot(0x99u));
|
||||
|
||||
var target = new UiItemList(_ => (1u, 1, 1))
|
||||
var target = new UiItemList(_ => (new GpuTextureSlot(1u), 1, 1))
|
||||
{
|
||||
DatElementId = 0x10000020u,
|
||||
Left = 70,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System.Collections.Generic;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
|
@ -68,7 +69,7 @@ public sealed class RetailUiInteractionFlowTests
|
|||
height: 32);
|
||||
var slotsButton = new UiButton(
|
||||
new ElementInfo { Id = SlotsButtonId, Type = 1 },
|
||||
static _ => (0u, 0, 0))
|
||||
static _ => (GpuTextureSlot.Unassigned, 0, 0))
|
||||
{
|
||||
DatElementId = SlotsButtonId,
|
||||
Left = 270,
|
||||
|
|
@ -86,7 +87,7 @@ public sealed class RetailUiInteractionFlowTests
|
|||
};
|
||||
var dollDragMask = new UiButton(
|
||||
new ElementInfo { Id = PaperdollController.DollDragMaskId, Type = 1 },
|
||||
static _ => (0u, 0, 0))
|
||||
static _ => (GpuTextureSlot.Unassigned, 0, 0))
|
||||
{
|
||||
DatElementId = PaperdollController.DollDragMaskId,
|
||||
Left = 270,
|
||||
|
|
@ -178,7 +179,7 @@ public sealed class RetailUiInteractionFlowTests
|
|||
Layout,
|
||||
Objects,
|
||||
playerGuid: () => Player,
|
||||
iconIds: static (_, _, _, _, _) => 0x1234u,
|
||||
iconIds: static (_, _, _, _, _) => new GpuTextureSlot(0x1234u),
|
||||
strength: () => 100,
|
||||
selection: Selection,
|
||||
datFont: null,
|
||||
|
|
@ -212,7 +213,7 @@ public sealed class RetailUiInteractionFlowTests
|
|||
Layout,
|
||||
Objects,
|
||||
playerGuid: () => Player,
|
||||
iconIds: static (_, _, _, _, _) => 0x1234u,
|
||||
iconIds: static (_, _, _, _, _) => new GpuTextureSlot(0x1234u),
|
||||
selection: Selection,
|
||||
itemInteraction: itemInteraction,
|
||||
emptySlotSprite: 0x06004D20u,
|
||||
|
|
@ -265,7 +266,7 @@ public sealed class RetailUiInteractionFlowTests
|
|||
}
|
||||
|
||||
private static UiItemList ItemList(uint id, float left, float top, float width, float height)
|
||||
=> new(static _ => (1u, 32, 32))
|
||||
=> new(static _ => (new GpuTextureSlot(1u), 32, 32))
|
||||
{
|
||||
DatElementId = id,
|
||||
Left = left,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
namespace AcDream.App.Tests.UI;
|
||||
|
||||
public class UiButtonTests
|
||||
{
|
||||
private static (uint, int, int) NoTex(uint _) => (0, 0, 0);
|
||||
private static (GpuTextureSlot, int, int) NoTex(uint _) => (GpuTextureSlot.Unassigned, 0, 0);
|
||||
private bool _clicked;
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -7,7 +8,7 @@ public class UiCollapsibleFrameTests
|
|||
{
|
||||
private static UiCollapsibleFrame MakeFrame(out UiPanel row2a, out UiPanel row2b)
|
||||
{
|
||||
var f = new UiCollapsibleFrame(_ => (1u, 1, 1))
|
||||
var f = new UiCollapsibleFrame(_ => (new GpuTextureSlot(1u), 1, 1))
|
||||
{
|
||||
CollapsedHeight = 96f,
|
||||
ExpandedHeight = 128f,
|
||||
|
|
@ -44,7 +45,7 @@ public class UiCollapsibleFrameTests
|
|||
[Fact]
|
||||
public void Tick_notConfigured_isNoOp()
|
||||
{
|
||||
var f = new UiCollapsibleFrame(_ => (1u, 1, 1)); // Collapsed==Expanded==0
|
||||
var f = new UiCollapsibleFrame(_ => (new GpuTextureSlot(1u), 1, 1)); // Collapsed==Expanded==0
|
||||
f.Height = 50f;
|
||||
f.TickForTest(0.016);
|
||||
Assert.Equal(50f, f.Height); // unchanged, no divide/no forced height
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System.Collections.Generic;
|
||||
using AcDream.App.UI;
|
||||
using DatReaderWriter.Types;
|
||||
|
|
@ -91,10 +92,10 @@ public class UiDatFontTests
|
|||
['B'] = Glyph('B', width: 7, before: 1, after: 1),
|
||||
};
|
||||
var font = new UiDatFont(
|
||||
fgTex: 0,
|
||||
fgTex: GpuTextureSlot.Unassigned,
|
||||
fgW: 0,
|
||||
fgH: 0,
|
||||
bgTex: 0,
|
||||
bgTex: GpuTextureSlot.Unassigned,
|
||||
bgW: 0,
|
||||
bgH: 0,
|
||||
lineHeight: 16f,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.UI;
|
||||
|
||||
namespace AcDream.App.Tests.UI;
|
||||
|
|
@ -21,26 +22,26 @@ public class UiItemSlotTests
|
|||
{
|
||||
var s = new UiItemSlot();
|
||||
Assert.Equal(0u, s.ItemId);
|
||||
Assert.Equal(0u, s.IconTexture);
|
||||
Assert.Equal(GpuTextureSlot.Unassigned, s.IconTexture);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetItem_setsIdAndTexture()
|
||||
{
|
||||
var s = new UiItemSlot();
|
||||
s.SetItem(0x5001u, 0x99u);
|
||||
s.SetItem(0x5001u, new GpuTextureSlot(0x99u));
|
||||
Assert.Equal(0x5001u, s.ItemId);
|
||||
Assert.Equal(0x99u, s.IconTexture);
|
||||
Assert.Equal(new GpuTextureSlot(0x99u), s.IconTexture);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Clear_afterSetItem_resetsToEmpty()
|
||||
{
|
||||
var s = new UiItemSlot();
|
||||
s.SetItem(0x5001u, 0x99u);
|
||||
s.SetItem(0x5001u, new GpuTextureSlot(0x99u));
|
||||
s.Clear();
|
||||
Assert.Equal(0u, s.ItemId);
|
||||
Assert.Equal(0u, s.IconTexture);
|
||||
Assert.Equal(GpuTextureSlot.Unassigned, s.IconTexture);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -58,7 +59,7 @@ public class UiItemSlotTests
|
|||
[Fact]
|
||||
public void CatalogSlot_keeps_catalog_identity_separate_from_object_guid()
|
||||
{
|
||||
var slot = new UiCatalogSlot { EntryId = 1234u, CatalogIconTexture = 99u };
|
||||
var slot = new UiCatalogSlot { EntryId = 1234u, CatalogIconTexture = new GpuTextureSlot(99u) };
|
||||
|
||||
Assert.Equal(1234u, slot.EntryId);
|
||||
Assert.Equal(0u, slot.ItemId);
|
||||
|
|
@ -147,7 +148,7 @@ public class UiItemSlotTests
|
|||
public void ActiveDigitArray_occupiedSlot_regular_returnsRegularDigits()
|
||||
{
|
||||
var s = new UiItemSlot { RegularDigits = Regular, GhostedDigits = Ghosted, EmptyDigits = Empty };
|
||||
s.SetItem(0x5001u, 0x99u);
|
||||
s.SetItem(0x5001u, new GpuTextureSlot(0x99u));
|
||||
s.SetShortcutNum(0, ghosted: false);
|
||||
Assert.Same(Regular, s.ActiveDigitArray());
|
||||
}
|
||||
|
|
@ -156,7 +157,7 @@ public class UiItemSlotTests
|
|||
public void ActiveDigitArray_occupiedSlot_ghosted_returnsGhostedDigits()
|
||||
{
|
||||
var s = new UiItemSlot { RegularDigits = Regular, GhostedDigits = Ghosted, EmptyDigits = Empty };
|
||||
s.SetItem(0x5001u, 0x99u);
|
||||
s.SetItem(0x5001u, new GpuTextureSlot(0x99u));
|
||||
s.SetShortcutNum(0, ghosted: true);
|
||||
Assert.Same(Ghosted, s.ActiveDigitArray());
|
||||
}
|
||||
|
|
@ -208,7 +209,7 @@ public class UiItemSlotTests
|
|||
CooldownSprites = sprites,
|
||||
CooldownStepProvider = id => id == 0x5001u ? 6 : 0,
|
||||
};
|
||||
slot.SetItem(0x5001u, 99u);
|
||||
slot.SetItem(0x5001u, new GpuTextureSlot(99u));
|
||||
|
||||
Assert.Equal(0x06000006u, slot.ActiveCooldownSprite());
|
||||
}
|
||||
|
|
@ -223,7 +224,7 @@ public class UiItemSlotTests
|
|||
};
|
||||
|
||||
Assert.Equal(0u, slot.ActiveCooldownSprite());
|
||||
slot.SetItem(0x5001u, 99u);
|
||||
slot.SetItem(0x5001u, new GpuTextureSlot(99u));
|
||||
Assert.Equal(0u, slot.ActiveCooldownSprite());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using System.Numerics;
|
||||
using AcDream.App.UI;
|
||||
|
||||
|
|
@ -10,7 +11,7 @@ public class UiRootInputTests
|
|||
{
|
||||
// Regression: the per-frame anchor pass must NOT reset a window's rect,
|
||||
// or move/resize get undone every frame. Windows are user-positioned.
|
||||
var panel = new UiNineSlicePanel(_ => ((uint)1, 32, 32));
|
||||
var panel = new UiNineSlicePanel(_ => (new GpuTextureSlot(1), 32, 32));
|
||||
Assert.Equal(AnchorEdges.None, panel.Anchors);
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +120,7 @@ public class UiRootInputTests
|
|||
{
|
||||
var root = new UiRoot { Width = 800, Height = 600 };
|
||||
var cell = new UiItemSlot { Left = 0, Top = 0, Width = 32, Height = 32 };
|
||||
cell.SetItem(0x50000A01u, 0x99u);
|
||||
cell.SetItem(0x50000A01u, new GpuTextureSlot(0x99u));
|
||||
root.AddChild(cell);
|
||||
object? payload = null;
|
||||
int releaseX = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue