fix(rendering): port retail shared alpha list

Queue translucent world GfxObj batches and scene particles in one stable far-to-near stream using transformed DAT sort centers, then drain it at retail's landscape and final-world boundaries. Preserve authored blend, cull, lighting, opacity, and adjacent-only batching so particles behind lifestones are composited through the crystal instead of overpainting it.

Release build succeeds and all 5,914 tests pass with five intentional skips.

Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-18 08:14:05 +02:00
parent ec1bb19609
commit 6b0472ee32
14 changed files with 1083 additions and 34 deletions

View file

@ -375,6 +375,7 @@ public sealed class GameWindow : IDisposable
private AcDream.App.Rendering.Vfx.EntityEffectController? _entityEffects;
private double _physicsScriptGameTime;
private AcDream.App.Rendering.ParticleRenderer? _particleRenderer;
private readonly AcDream.App.Rendering.RetailAlphaQueue _retailAlphaQueue = new();
// Retail GameSky copies SkyObject.PesObjectId into CelestialPosition but
// never consumes it in CreateDeletePhysicsObjects/MakeObject/UseTime.
// Keep the experimental path available for DAT archaeology only.
@ -2627,7 +2628,8 @@ public sealed class GameWindow : IDisposable
_classificationCache, _translucencyFades,
_retailSelectionScene ??= new AcDream.App.Rendering.Selection.RetailSelectionScene(
new AcDream.App.Rendering.Selection.RetailSelectionGeometryCache(
_dats!, _datLock)));
_dats!, _datLock)),
_retailAlphaQueue);
// A.5 T22.5: apply A2C gate from quality preset.
_wbDrawDispatcher.AlphaToCoverage = _resolvedQuality.AlphaToCoverage;
@ -2686,7 +2688,8 @@ public sealed class GameWindow : IDisposable
_particleSystem,
_textureCache,
_dats,
_wbMeshAdapter);
_wbMeshAdapter,
_retailAlphaQueue);
// A.5 T22.5: apply radii from the already-resolved _resolvedQuality.
// _resolvedQuality was set by the quality block immediately after
@ -9632,6 +9635,7 @@ public sealed class GameWindow : IDisposable
_retailSelectionScene?.BeginFrame();
if (_cameraController is not null && !portalViewportVisible)
{
_retailAlphaQueue.BeginFrame();
var activeCamera = _cameraController.Active;
var camera = _teleportViewPlane.ApplyTo(activeCamera);
var worldProjection = camera.Projection;
@ -10212,6 +10216,7 @@ public sealed class GameWindow : IDisposable
AcDream.Core.Vfx.ParticleRenderPass.Scene,
emitter => emitter.AttachedObjectId == 0);
},
FlushLandscapeAlpha = _retailAlphaQueue.Flush,
DrawCellParticles = sliceCtx =>
DrawRetailPViewCellParticles(sliceCtx, camera, camPos),
DrawDynamicsParticles = survivors =>
@ -10543,6 +10548,7 @@ public sealed class GameWindow : IDisposable
// pre-login screen shows a live, correctly-tinted sky and
// nothing else.
SkipWorldGeometry:
_retailAlphaQueue.EndFrame();
if (_terrain is not null)
_particleVisibility.MarkVisibleCells(_terrain.VisibleCellIds);
_particleVisibility.CompleteFrame();