Lands the fading-secret-door feature and fixes the door "flip-back" that surfaced while testing it. #188 — fading-wall doors (e.g. "Pedestal Weak Spot") fade their wall part out via TransparentPartHook instead of swinging: - TranslucencyHookSink consumes TransparentPartHook -> TranslucencyFadeManager (per-(entity,part) linear translucency ramp; holds at End frame). - WbDrawDispatcher: new per-instance alpha SSBO (binding 7); ClassifyBatches takes opacityMultiplier (1 - translucency, per CMaterial::SetTranslucencySimple 0x005396f0) forcing AlphaBlend; fully-invisible parts skipped. - mesh_modern.vert/.frag: binding-7 InstanceAlphaBuf -> vOpacityMultiplier -> FragColor.a *= vOpacityMultiplier. - Register AP-89: the fade multiplies sampled texture alpha, not a separate D3D9 material alpha channel (observably identical for texture-alpha==1 surfaces). Door flip-back fix (affected BOTH #188 fading walls AND #187 sliding doors): a door/wall that finished opening holds a single unchanging frame, so the uncommitted IsEntityCurrentlyMoving cache-bypass narrowing dropped it onto the Tier-1 static cache -- which only remembers the REST pose + opacity 1.0 -- snapping it visually shut/opaque while physics stayed open. Reverted that narrowing: every Sequencer entity stays on the per-frame path (live pose + live fade opacity), the known-good pre-optimization behavior. The per-frame CPU cost that narrowing chased was a Debug-build artifact -- Release is GPU-bound (~200 fps in Sawato, measured), so the unconditional add is free where it matters. Left a code comment barring re-introduction. Tests: full Core suite green (2649 passed, 2 skipped). Live visual gate PASSED -- both fading-wall and sliding doors hold open. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
38 lines
1.4 KiB
C#
38 lines
1.4 KiB
C#
using System;
|
|
using System.Numerics;
|
|
using AcDream.Core.Physics;
|
|
using DatReaderWriter.Types;
|
|
|
|
namespace AcDream.Core.Rendering;
|
|
|
|
/// <summary>
|
|
/// #188 — routes <see cref="TransparentPartHook"/> animation hooks to a
|
|
/// <see cref="TranslucencyFadeManager"/>. Retail's
|
|
/// <c>TransparentPartHook::Execute</c> (0x00526cc0) is a one-liner calling
|
|
/// <c>CPhysicsObj::SetPartTranslucency(obj, part, start, end, time)</c> —
|
|
/// this sink is that same one-line forward.
|
|
///
|
|
/// <para>
|
|
/// Whole-object <see cref="TransparentHook"/> and <see cref="EtherealHook"/>
|
|
/// are deliberately NOT handled here. Retail's <c>EtherealHook::Execute</c>
|
|
/// (0x00526bc0) touches only <c>CPhysicsObj::set_ethereal</c> — collision
|
|
/// state, zero rendering coupling — and acdream's collision-passthrough
|
|
/// already applies server-authoritative via the <c>SetState</c> wire
|
|
/// message, independent of this hook firing client-side.
|
|
/// </para>
|
|
/// </summary>
|
|
public sealed class TranslucencyHookSink : IAnimationHookSink
|
|
{
|
|
private readonly TranslucencyFadeManager _fades;
|
|
|
|
public TranslucencyHookSink(TranslucencyFadeManager fades)
|
|
{
|
|
_fades = fades ?? throw new ArgumentNullException(nameof(fades));
|
|
}
|
|
|
|
public void OnHook(uint entityId, Vector3 entityWorldPosition, AnimationHook hook)
|
|
{
|
|
if (hook is not TransparentPartHook tph) return;
|
|
_fades.StartPartFade(entityId, tph.PartIndex, tph.Start, tph.End, tph.Time);
|
|
}
|
|
}
|