Fix skip completion for visual transitions

This commit is contained in:
gamer147
2026-07-29 17:09:37 -04:00
parent 3378abdeca
commit 09d765d89d
12 changed files with 271 additions and 50 deletions

View File

@@ -131,9 +131,13 @@ public interface IHost
void PresentFrame(GfxState gfx) { }
// Legacy SYS4 screen-transition family (ops 0x21, 0x22, and 0x25): scripts render complete
// frames into numbered surfaces, then block while the engine alpha-composites an endpoint.
// Native bypasses the timed service when ADV fast-forward is already active at opcode dispatch.
void FadeSurfaceWithBlack(
GfxState gfx, int surface, long intervalArgument, SurfaceBlackFadeDirection direction) { }
void CrossfadeSurfaces(GfxState gfx, int sourceSurface, int targetSurface, long intervalArgument) { }
GfxState gfx, int surface, long intervalArgument, SurfaceBlackFadeDirection direction,
bool forceEndpoint = false) { }
void CrossfadeSurfaces(
GfxState gfx, int sourceSurface, int targetSurface, long intervalArgument,
bool forceEndpoint = false) { }
void CreateTexture(int slot, int width, int height);
/// <summary>Return a stable RGBA snapshot of one numbered surface, or null when unavailable.</summary>
RgbaImage? CaptureSurfacePixels(int slot) => null;

View File

@@ -934,7 +934,49 @@ public sealed class GfxState
(o.RotationEnabled && o.RotationPeriodMs > 0)));
}
/// <summary>Click completion affects only type-0 foreground transitions, never ambient object channels.</summary>
/// <summary>Force the finite retained presentation serviced by native run-state bit 0x400 to its
/// endpoint. This is the EffectSkipOnClick path: type-0 surface commands and ordinary finite object
/// channels complete together, while movie masks, ambient cycles, and op-0x242-detached channels remain
/// active. Op 0x24e bit 0 disables click skipping; bit 1 suppresses the shared force-complete request.</summary>
public int CompleteClickSkippableTimedPresentation(long nowMs)
{
lock (_lock)
{
if ((AnimationServiceFlags & 3) != 0) return 0;
int completed = 0;
foreach (var t in _surfaceTransitions.Values)
{
if (t.Forced || TransitionProgress(t, nowMs) >= 1.0) continue;
t.Forced = true;
completed++;
}
completed += CountOneShotChannels(_rangeTransform);
foreach (var o in _objects.Values)
{
if ((o.OneShotAnimationControlFlags & 1) != 0) continue;
completed += CountOneShotChannels(o);
}
ForceCompleteOneShotChannels();
if (AnimClockDurationTicks != 0) completed++;
AnimClockDurationTicks = 0;
AnimClockGeneration++;
if (completed > 0) MarkRetainedMutation();
return completed;
}
}
private static int CountOneShotChannels(GfxObject o)
=> (o.OneShotColorEnabled ? 1 : 0)
+ (o.ScaleEnabled ? 1 : 0)
+ (o.RotationChannelEnabled ? 1 : 0)
+ (o.TranslationEnabled ? 1 : 0);
/// <summary>Force only queued type-0 foreground transitions. PresentFrame uses this to publish a
/// command endpoint immediately; interactive run-state-0x400 skipping uses the broader method above.</summary>
public int CompleteForegroundTransitions(long nowMs)
{
lock (_lock)

View File

@@ -2862,16 +2862,20 @@ public sealed class VirtualMachine
case "fade-surface-in-from-black": // 0x21: blocking black -> captured full-frame surface
case "u00418860":
_host.FadeSurfaceWithBlack(
Gfx, (int)Read(a[0]), Read(a[1]), SurfaceBlackFadeDirection.FromBlack);
Gfx, (int)Read(a[0]), Read(a[1]), SurfaceBlackFadeDirection.FromBlack,
_messageSkipServiceActive || _host.IsMessageSkipActive);
return pc + 1;
case "fade-surface-out-to-black": // 0x22: blocking captured full-frame surface -> black
case "u00418920":
_host.FadeSurfaceWithBlack(
Gfx, (int)Read(a[0]), Read(a[1]), SurfaceBlackFadeDirection.ToBlack);
Gfx, (int)Read(a[0]), Read(a[1]), SurfaceBlackFadeDirection.ToBlack,
_messageSkipServiceActive || _host.IsMessageSkipActive);
return pc + 1;
case "crossfade-surfaces": // 0x25: legacy full-frame surface alpha transition
case "u00418B40":
_host.CrossfadeSurfaces(Gfx, (int)Read(a[0]), (int)Read(a[1]), Read(a[2]));
_host.CrossfadeSurfaces(
Gfx, (int)Read(a[0]), (int)Read(a[1]), Read(a[2]),
_messageSkipServiceActive || _host.IsMessageSkipActive);
return pc + 1;
case "mark-frame-yield": // 0x21c: normal foreground-transition scheduler/resume boundary
_host.WaitForForegroundTransition(Gfx); return pc + 1;