Split GfxState public contracts

This commit is contained in:
gamer147
2026-08-02 21:08:05 -04:00
parent 12ddbe006a
commit 3291f86f38
4 changed files with 110 additions and 99 deletions

View File

@@ -107,6 +107,8 @@ S:\Game Hacking\Eushully\Himegari\ ← workspace root (three siblings)
│ └── manifest.json, opcode-coverage.md (opcode-coverage.md GENERATED from opcodes.toml)
├── engine/ DELIVERABLE — the .NET VM core (AgeEngine.sln: Age.Engine / Age.Cli / tests)
│ ├── Age.Engine/Model/ retained graphics state plus separately navigable public
│ render, transition, diagnostic, and persistence contracts
│ ├── Age.Engine/Sys4/ runtime game-root selection, catalog parser, loose-first bounded
│ ALF asset store, script provider, AGF/LZSS and Windows CUR decoders,
│ and resource facade

View File

@@ -596,6 +596,11 @@ do not mix mechanical moves with semantic changes.
scene reset, and frame-pulse consumers retain direct access through the sealed partial class. The planned
host decomposition is complete; runtime validation remains green.
The first bounded `GfxState` split moved its public render, transition, diagnostic, persistence, animation,
numeric-glyph, and handle-range value contracts into `engine/Age.Engine/Model/GfxState.Contracts.cs`.
`GfxState` remains the same sealed runtime type, and every moved declaration is textually unchanged; runtime
validation remains green.
**Gate:** no externally visible behavior or command changes; generated artifacts are byte-identical where
deterministic, and the corresponding engine, Python, Godot, and corpus validations remain green after
each domain move.
@@ -967,7 +972,7 @@ layer's rendering diverges from ADV; save layout.
## 8. Immediate next step
Continue step 2 of the **codebase consolidation** maintenance slice: behavior-neutral physical splits backed
by the tracked launcher and layered validation driver. With the planned `Main` and `GodotAdvHost` domains
isolated, begin the `GfxState` decomposition with one existing ownership domain at a time, preserving public
types, commands, and generated output.
isolated and the `GfxState` public contract layer separated, move `GfxState` surface ownership next, preserving
public types, commands, and generated output.
Concrete playthrough blockers may still preempt this bounded maintenance work; the consolidation effort does
not replace Phase B gameplay validation or the open cross-platform gates.

View File

@@ -0,0 +1,101 @@
using Age.Engine.Hosting;
namespace Age.Engine.Model;
/// <summary>The sampled native one-shot channels carried to the compositor: op 0x21e scale, op 0x21f
/// axis-angle rotation, and op 0x220 translation. Z is retained through full 4x4 composition.</summary>
public readonly record struct TransformState(double ScaleX, double ScaleY, double ScaleZ,
double TranslateX, double TranslateY, double TranslateZ,
double AnchorX, double AnchorY, double AnchorZ,
double RotationAxisX = 0, double RotationAxisY = 0,
double RotationAxisZ = 0, double RotationAngleDegrees = 0);
public readonly record struct RotationCycleState(bool Enabled, long PeriodMs,
double AxisX, double AxisY, double AxisZ,
double AngleDegrees = 0);
public readonly record struct ScaleCycleState(bool Enabled, long PeriodMs,
double ScaleX, double ScaleY, double ScaleZ);
[System.Flags]
public enum GfxPresentationReason
{
None = 0,
RetainedMutation = 1,
ContinuousChannel = 2,
DiscreteSourceCell = 4,
}
/// <summary>Sampled op-0x223 type-0 surface transition. Range A is already present in normal z-order;
/// the compositor draws range B over it with <paramref name="Progress"/> to form the native crossfade.</summary>
public readonly record struct SurfaceTransitionState(long CommandKey, int TargetSlot,
long RangeAStart, int RangeACount, long RangeBStart, int RangeBCount,
long DelayMs, long DurationMs, long StartMs, double Progress, bool Forced);
public readonly record struct MovieMaskTransitionState(
MovieMaskTransitionRequest Request, bool Completed);
/// <summary>One synchronized sample of op 0x202's native one-shot packed-color channel.</summary>
public readonly record struct ColorTransitionState(long Current, long Target,
long DelayMs, long DurationMs, long StartMs, double Progress, bool Active);
/// <summary>One EngineCtx numeric-glyph style registered by opcode 0x13a.</summary>
public readonly record struct NumericGlyphStyle(int SurfaceSlot, int AtlasX, int AtlasY,
int DigitWidth, int DigitHeight)
{
public bool Registered => SurfaceSlot != 0;
}
public sealed record BlockingGfxObjectDiagnostic(
long Handle, int SourceSlot, long StartMs, long ControlFlags,
bool ColorEnabled, long ColorDelayMs, long ColorDurationMs,
bool ScaleEnabled, long ScaleDelayMs, long ScaleDurationMs,
bool RotationEnabled, long RotationDelayMs, long RotationDurationMs,
bool TranslationEnabled, long TranslationDelayMs, long TranslationDurationMs);
public sealed record GfxDiagnosticSnapshot(
long NowMs, bool HasActiveTimedPresentation, int ObjectCount, int VisibleObjectCount,
int ActiveSurfaceTransitionCount, long AnimationServiceFlags,
long AnimClockDurationTicks, long AnimClockGeneration,
uint PreviousFrameTimeMilliseconds, uint CurrentFrameTimeMilliseconds,
long RangeTransformFirst, long RangeTransformCount,
BlockingGfxObjectDiagnostic? BlockingRangeTransform,
IReadOnlyList<BlockingGfxObjectDiagnostic> BlockingObjects);
public readonly record struct GfxSurfacePersistenceState(
int Slot, long ResourceId, long ColorKey, bool Created, bool ReloadOnRestore);
public sealed record GfxPersistenceSnapshot(
IReadOnlyList<GfxSurfacePersistenceState> Surfaces,
IReadOnlyList<(long Handle, GfxState.GfxObject Object)> Objects,
long RangeFirst,
long RangeCount,
GfxState.GfxObject RangeTransform);
/// <summary>A renderable view of one visible gfx object — the host composites these in ascending-handle order
/// (= the engine's z-order) each frame. Built by <see cref="GfxState.SnapshotVisibleObjects"/>; the surface
/// resId/colorkey are resolved from the object's live source slot at snapshot time (see docs/engine-re.md,
/// "The full gfx render model").</summary>
/// <summary>The packed-color channel is mode-dependent. Textured mode 0 ignores packed alpha and
/// multiplicatively modulates by <paramref name="Tint"/>; surfaceless mode 0 uses <paramref name="TintStrength"/>.
/// A mode-0 color which has passed through op 0x202, and mode 1, use <paramref name="Alpha"/> as opacity.
/// <paramref name="MultiplyTint"/> selects the latter compositor path.</summary>
public readonly record struct RenderObject(long Handle, long SurfaceResId, long ColorKey,
int SrcX, int SrcY, int W, int H, int DstX, int DstY,
TransformState Transform, RotationCycleState Rotation,
int Alpha, long Tint, int TintStrength, BlendKind Blend,
bool MultiplyTint,
SurfaceTransitionState? SurfaceTransition = null,
ColorTransitionState? ColorTransition = null,
Affine2D? RangeTransform = null,
bool TimeVarying = false,
ScaleCycleState ScaleCycle = default);
/// <summary>The retained handle interval selected by an op-0x222 backbuffer publication.</summary>
public readonly record struct GfxHandleRange(long First, long Count)
{
public static GfxHandleRange All => new(0, long.MaxValue);
public bool Contains(long handle)
=> Count > 0 && handle >= First && (ulong)(handle - First) < (ulong)Count;
}

View File

@@ -3,103 +3,6 @@ using Age.Engine.Hosting;
namespace Age.Engine.Model;
/// <summary>The sampled native one-shot channels carried to the compositor: op 0x21e scale, op 0x21f
/// axis-angle rotation, and op 0x220 translation. Z is retained through full 4x4 composition.</summary>
public readonly record struct TransformState(double ScaleX, double ScaleY, double ScaleZ,
double TranslateX, double TranslateY, double TranslateZ,
double AnchorX, double AnchorY, double AnchorZ,
double RotationAxisX = 0, double RotationAxisY = 0,
double RotationAxisZ = 0, double RotationAngleDegrees = 0);
public readonly record struct RotationCycleState(bool Enabled, long PeriodMs,
double AxisX, double AxisY, double AxisZ,
double AngleDegrees = 0);
public readonly record struct ScaleCycleState(bool Enabled, long PeriodMs,
double ScaleX, double ScaleY, double ScaleZ);
[System.Flags]
public enum GfxPresentationReason
{
None = 0,
RetainedMutation = 1,
ContinuousChannel = 2,
DiscreteSourceCell = 4,
}
/// <summary>Sampled op-0x223 type-0 surface transition. Range A is already present in normal z-order;
/// the compositor draws range B over it with <paramref name="Progress"/> to form the native crossfade.</summary>
public readonly record struct SurfaceTransitionState(long CommandKey, int TargetSlot,
long RangeAStart, int RangeACount, long RangeBStart, int RangeBCount,
long DelayMs, long DurationMs, long StartMs, double Progress, bool Forced);
public readonly record struct MovieMaskTransitionState(
MovieMaskTransitionRequest Request, bool Completed);
/// <summary>One synchronized sample of op 0x202's native one-shot packed-color channel.</summary>
public readonly record struct ColorTransitionState(long Current, long Target,
long DelayMs, long DurationMs, long StartMs, double Progress, bool Active);
/// <summary>One EngineCtx numeric-glyph style registered by opcode 0x13a.</summary>
public readonly record struct NumericGlyphStyle(int SurfaceSlot, int AtlasX, int AtlasY,
int DigitWidth, int DigitHeight)
{
public bool Registered => SurfaceSlot != 0;
}
public sealed record BlockingGfxObjectDiagnostic(
long Handle, int SourceSlot, long StartMs, long ControlFlags,
bool ColorEnabled, long ColorDelayMs, long ColorDurationMs,
bool ScaleEnabled, long ScaleDelayMs, long ScaleDurationMs,
bool RotationEnabled, long RotationDelayMs, long RotationDurationMs,
bool TranslationEnabled, long TranslationDelayMs, long TranslationDurationMs);
public sealed record GfxDiagnosticSnapshot(
long NowMs, bool HasActiveTimedPresentation, int ObjectCount, int VisibleObjectCount,
int ActiveSurfaceTransitionCount, long AnimationServiceFlags,
long AnimClockDurationTicks, long AnimClockGeneration,
uint PreviousFrameTimeMilliseconds, uint CurrentFrameTimeMilliseconds,
long RangeTransformFirst, long RangeTransformCount,
BlockingGfxObjectDiagnostic? BlockingRangeTransform,
IReadOnlyList<BlockingGfxObjectDiagnostic> BlockingObjects);
public readonly record struct GfxSurfacePersistenceState(
int Slot, long ResourceId, long ColorKey, bool Created, bool ReloadOnRestore);
public sealed record GfxPersistenceSnapshot(
IReadOnlyList<GfxSurfacePersistenceState> Surfaces,
IReadOnlyList<(long Handle, GfxState.GfxObject Object)> Objects,
long RangeFirst,
long RangeCount,
GfxState.GfxObject RangeTransform);
/// <summary>A renderable view of one visible gfx object — the host composites these in ascending-handle order
/// (= the engine's z-order) each frame. Built by <see cref="GfxState.SnapshotVisibleObjects"/>; the surface
/// resId/colorkey are resolved from the object's live source slot at snapshot time (see docs/engine-re.md,
/// "The full gfx render model").</summary>
/// <summary>The packed-color channel is mode-dependent. Textured mode 0 ignores packed alpha and
/// multiplicatively modulates by <paramref name="Tint"/>; surfaceless mode 0 uses <paramref name="TintStrength"/>.
/// A mode-0 color which has passed through op 0x202, and mode 1, use <paramref name="Alpha"/> as opacity.
/// <paramref name="MultiplyTint"/> selects the latter compositor path.</summary>
public readonly record struct RenderObject(long Handle, long SurfaceResId, long ColorKey,
int SrcX, int SrcY, int W, int H, int DstX, int DstY,
TransformState Transform, RotationCycleState Rotation,
int Alpha, long Tint, int TintStrength, BlendKind Blend,
bool MultiplyTint,
SurfaceTransitionState? SurfaceTransition = null,
ColorTransitionState? ColorTransition = null,
Affine2D? RangeTransform = null,
bool TimeVarying = false,
ScaleCycleState ScaleCycle = default);
/// <summary>The retained handle interval selected by an op-0x222 backbuffer publication.</summary>
public readonly record struct GfxHandleRange(long First, long Count)
{
public static GfxHandleRange All => new(0, long.MaxValue);
public bool Contains(long handle)
=> Count > 0 && handle >= First && (ulong)(handle - First) < (ulong)Count;
}
/// <summary>Host-agnostic model of the AGE native gfx command-buffer (reversed in
/// docs/engine-re.md, gfx op-contract table). One registry maps an object handle to a GfxObject — the