refactor(render): extract world frame preparation
Move camera/root resolution, live settings and listener preview, sky/lighting/fog preparation, animated classification, and building visibility scratch behind a typed WorldRenderFrameBuilder while preserving retail frame order and borrowed lifetimes. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
bc6f09f987
commit
6d6e5b5fa5
8 changed files with 1463 additions and 583 deletions
135
src/AcDream.App/Rendering/SkyPesFrameController.cs
Normal file
135
src/AcDream.App/Rendering/SkyPesFrameController.cs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
using System.Numerics;
|
||||
using AcDream.App.Rendering.Vfx;
|
||||
using AcDream.Core.Vfx;
|
||||
using AcDream.Core.World;
|
||||
|
||||
namespace AcDream.App.Rendering;
|
||||
|
||||
/// <summary>
|
||||
/// Owns the optional DAT-archaeology sky-PES experiment. Named retail shows
|
||||
/// GameSky does not consume SkyObject.PesObjectId, so production invokes this
|
||||
/// owner only when the explicit startup diagnostic is enabled.
|
||||
/// </summary>
|
||||
internal sealed class SkyPesFrameController
|
||||
{
|
||||
private readonly record struct SkyPesKey(
|
||||
int ObjectIndex,
|
||||
uint PesObjectId,
|
||||
bool PostScene);
|
||||
|
||||
private readonly PhysicsScriptRunner _scripts;
|
||||
private readonly ParticleHookSink _particles;
|
||||
private readonly EntityEffectPoseRegistry _poses;
|
||||
private readonly EntityEffectController? _effects;
|
||||
private readonly HashSet<SkyPesKey> _active = [];
|
||||
private readonly HashSet<SkyPesKey> _missing = [];
|
||||
|
||||
public SkyPesFrameController(
|
||||
PhysicsScriptRunner scripts,
|
||||
ParticleHookSink particles,
|
||||
EntityEffectPoseRegistry poses,
|
||||
EntityEffectController? effects)
|
||||
{
|
||||
_scripts = scripts ?? throw new ArgumentNullException(nameof(scripts));
|
||||
_particles = particles ?? throw new ArgumentNullException(nameof(particles));
|
||||
_poses = poses ?? throw new ArgumentNullException(nameof(poses));
|
||||
_effects = effects;
|
||||
}
|
||||
|
||||
public void Update(
|
||||
float dayFraction,
|
||||
DayGroupData? dayGroup,
|
||||
Vector3 cameraWorldPosition,
|
||||
bool suppressSky)
|
||||
{
|
||||
var seen = new HashSet<SkyPesKey>();
|
||||
if (!suppressSky && dayGroup is not null)
|
||||
{
|
||||
for (int index = 0; index < dayGroup.SkyObjects.Count; index++)
|
||||
{
|
||||
SkyObjectData skyObject = dayGroup.SkyObjects[index];
|
||||
if (skyObject.PesObjectId == 0 || !skyObject.IsVisible(dayFraction))
|
||||
continue;
|
||||
|
||||
var key = new SkyPesKey(
|
||||
index,
|
||||
skyObject.PesObjectId,
|
||||
skyObject.IsPostScene);
|
||||
seen.Add(key);
|
||||
uint ownerId = EntityId(key);
|
||||
ParticleRenderPass renderPass = skyObject.IsPostScene
|
||||
? ParticleRenderPass.SkyPostScene
|
||||
: ParticleRenderPass.SkyPreScene;
|
||||
_particles.SetEntityRenderPass(ownerId, renderPass);
|
||||
Vector3 anchor = Anchor(skyObject, cameraWorldPosition);
|
||||
Quaternion rotation = Rotation(skyObject, dayFraction);
|
||||
_poses.Publish(
|
||||
ownerId,
|
||||
Matrix4x4.CreateFromQuaternion(rotation)
|
||||
* Matrix4x4.CreateTranslation(anchor),
|
||||
Array.Empty<Matrix4x4>(),
|
||||
cellId: 0u);
|
||||
|
||||
if (_active.Contains(key) || _missing.Contains(key))
|
||||
continue;
|
||||
|
||||
_effects?.RegisterSyntheticOwner(ownerId);
|
||||
if (_scripts.Play(skyObject.PesObjectId, ownerId, anchor))
|
||||
{
|
||||
_active.Add(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
_missing.Add(key);
|
||||
_effects?.UnregisterSyntheticOwner(ownerId);
|
||||
_particles.ClearEntityRenderPass(ownerId);
|
||||
_poses.Remove(ownerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (SkyPesKey key in _active.ToArray())
|
||||
{
|
||||
if (seen.Contains(key))
|
||||
continue;
|
||||
|
||||
uint ownerId = EntityId(key);
|
||||
_scripts.StopAllForEntity(ownerId);
|
||||
_effects?.UnregisterSyntheticOwner(ownerId);
|
||||
_particles.StopAllForEntity(ownerId, fadeOut: true);
|
||||
_poses.Remove(ownerId);
|
||||
_active.Remove(key);
|
||||
}
|
||||
|
||||
foreach (SkyPesKey key in _missing.ToArray())
|
||||
{
|
||||
if (!seen.Contains(key))
|
||||
_missing.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
private static uint EntityId(SkyPesKey key)
|
||||
{
|
||||
uint postScene = key.PostScene ? 0x08000000u : 0u;
|
||||
return 0xF0000000u
|
||||
| postScene
|
||||
| ((uint)key.ObjectIndex & 0x07FFFFFFu);
|
||||
}
|
||||
|
||||
private static Vector3 Anchor(
|
||||
SkyObjectData skyObject,
|
||||
Vector3 cameraWorldPosition)
|
||||
{
|
||||
if (skyObject.IsWeather && (skyObject.Properties & 0x08u) == 0u)
|
||||
return cameraWorldPosition + new Vector3(0f, 0f, -120f);
|
||||
return cameraWorldPosition;
|
||||
}
|
||||
|
||||
private static Quaternion Rotation(
|
||||
SkyObjectData skyObject,
|
||||
float dayFraction)
|
||||
{
|
||||
float radians = skyObject.CurrentAngle(dayFraction) * (MathF.PI / 180f);
|
||||
return Quaternion.CreateFromAxisAngle(Vector3.UnitY, -radians);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue