Build a compare-only dispatcher classifier from RenderFrameView and compare complete opaque, alpha, selection, clip, light, texture, transform, and draw payloads against the accepted path. Preserve retail's stable equal-CYpt ordering with explicit draw-local submission ordinals so material-group history cannot affect alpha ties.
108 lines
3.8 KiB
C#
108 lines
3.8 KiB
C#
using System.Numerics;
|
|
using AcDream.Core.World;
|
|
|
|
namespace AcDream.App.Rendering.Scene;
|
|
|
|
/// <summary>
|
|
/// The complete acdream-owned value boundary consumed by the object
|
|
/// dispatcher. It contains presentation facts only; the dispatcher must not
|
|
/// call back into <see cref="WorldEntity"/> or any gameplay owner after this
|
|
/// value has been produced.
|
|
/// </summary>
|
|
internal readonly record struct RenderInstanceCandidate(
|
|
RenderProjectionId ProjectionId,
|
|
uint LocalEntityId,
|
|
uint ServerGuid,
|
|
uint SourceId,
|
|
uint ParentCellId,
|
|
Matrix4x4 RootWorld,
|
|
Vector3 Position,
|
|
Quaternion Rotation,
|
|
float Scale,
|
|
RenderWorldBounds Bounds,
|
|
PaletteOverride? PaletteOverride,
|
|
bool IsBuildingShell,
|
|
bool Animated,
|
|
int MeshPartCount,
|
|
uint TupleLandblockId)
|
|
{
|
|
internal uint Id => LocalEntityId;
|
|
|
|
internal uint? ParentCell =>
|
|
ParentCellId == 0 ? null : ParentCellId;
|
|
|
|
internal uint CacheLandblockId =>
|
|
ParentCellId != 0
|
|
? (ParentCellId & 0xFFFF0000u) | 0xFFFFu
|
|
: TupleLandblockId;
|
|
|
|
internal static RenderInstanceCandidate FromWorldEntity(
|
|
WorldEntity entity,
|
|
bool animated,
|
|
int meshPartCount,
|
|
uint tupleLandblockId)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(entity);
|
|
if (meshPartCount < 0)
|
|
throw new ArgumentOutOfRangeException(nameof(meshPartCount));
|
|
if (entity.AabbDirty)
|
|
entity.RefreshAabb();
|
|
|
|
return new RenderInstanceCandidate(
|
|
ProjectionId: default,
|
|
LocalEntityId: entity.Id,
|
|
ServerGuid: entity.ServerGuid,
|
|
SourceId: entity.SourceGfxObjOrSetupId,
|
|
ParentCellId: entity.ParentCellId ?? 0u,
|
|
RootWorld:
|
|
Matrix4x4.CreateFromQuaternion(entity.Rotation)
|
|
* Matrix4x4.CreateTranslation(entity.Position),
|
|
Position: entity.Position,
|
|
Rotation: entity.Rotation,
|
|
Scale: entity.Scale,
|
|
Bounds: new RenderWorldBounds(
|
|
entity.AabbMin,
|
|
entity.AabbMax),
|
|
PaletteOverride: entity.PaletteOverride,
|
|
IsBuildingShell: entity.IsBuildingShell,
|
|
Animated: animated,
|
|
MeshPartCount: meshPartCount,
|
|
TupleLandblockId: tupleLandblockId);
|
|
}
|
|
|
|
internal static RenderInstanceCandidate FromFrame(
|
|
in RenderFrameEntityCandidate source,
|
|
uint tupleLandblockId)
|
|
{
|
|
RenderProjectionRecord projection = source.Projection;
|
|
return new RenderInstanceCandidate(
|
|
ProjectionId: projection.Id,
|
|
LocalEntityId: projection.Source.LocalEntityId,
|
|
ServerGuid: projection.Source.ServerGuid,
|
|
SourceId: projection.Source.SourceId,
|
|
ParentCellId: projection.Source.ParentCellId,
|
|
RootWorld: projection.Transform.LocalToWorld,
|
|
Position: projection.Transform.Position,
|
|
Rotation: projection.Transform.Rotation,
|
|
Scale: projection.Transform.UniformScale,
|
|
Bounds: projection.Bounds,
|
|
PaletteOverride:
|
|
projection.EntityPayload.PaletteOverride,
|
|
IsBuildingShell:
|
|
projection.EntityPayload.IsBuildingShell,
|
|
Animated: source.Animated,
|
|
MeshPartCount: source.MeshPartCount,
|
|
TupleLandblockId: tupleLandblockId);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// One ordered mesh reference belonging to a dispatcher candidate. Candidate
|
|
/// values repeat across the entity's tuples only in the transitional current
|
|
/// source; the scene frame product supplies the same facts from retained arena
|
|
/// storage.
|
|
/// </summary>
|
|
internal readonly record struct RenderInstanceTuple(
|
|
RenderInstanceCandidate Candidate,
|
|
int MeshRefIndex,
|
|
MeshRef MeshRef);
|