feat(render): implement Campaign AR and terrain fidelity
This commit is contained in:
parent
99cf26e00c
commit
7a5f96ede5
368 changed files with 50611 additions and 950 deletions
|
|
@ -51,7 +51,9 @@ internal sealed record FrameRootDependencies(
|
|||
LiveEntityAnimationRuntimeView<LiveEntityAnimationState> Animations,
|
||||
UpdateFrameClock UpdateClock,
|
||||
GameFrameGraphSlot FrameGraphs,
|
||||
Action<string> Log)
|
||||
Action<string> Log,
|
||||
AcDream.App.Rendering.Packs.DeferredRenderPackDiagnosticsSource?
|
||||
RenderPackDiagnostics = null)
|
||||
{
|
||||
public RuntimeLocalPlayerMovementState PlayerController =>
|
||||
Runtime.MovementOwner;
|
||||
|
|
@ -234,6 +236,7 @@ internal sealed class FrameRootCompositionPhase
|
|||
ref bool bindingsOwnedByScope)
|
||||
{
|
||||
FrameRootDependencies d = _dependencies;
|
||||
bindings = new FrameRootRuntimeBindings();
|
||||
WorldRenderFoundation foundation = world.Foundation;
|
||||
// Campaign V slice V6h: the frame root's raw-GL render graph fork was
|
||||
// deleted at slice V11. The graph is the clear pass, the private-
|
||||
|
|
@ -285,6 +288,35 @@ internal sealed class FrameRootCompositionPhase
|
|||
renderFrameLivePreparation);
|
||||
Fault(FrameRootCompositionPoint.RenderResourcesCreated);
|
||||
|
||||
AcDream.App.Rendering.Packs.RenderPackController? renderPackController = null;
|
||||
AcDream.App.Rendering.Packs.RenderPackSelectionBinding? renderPackSelection = null;
|
||||
AcDream.App.Rendering.Packs.AtmosphericFrameInputState? atmosphericInputs = null;
|
||||
if (settings.RenderPacks is { } renderPackCatalog)
|
||||
{
|
||||
renderPackController = new AcDream.App.Rendering.Packs.RenderPackController(
|
||||
renderPackCatalog.Snapshot,
|
||||
new AcDream.App.Rendering.Packs.AtmosphericRenderPackRuntimeFactory(
|
||||
host.GpuDevice),
|
||||
new AcDream.App.Rendering.Packs.RenderPackReceiverPipelineCoordinator(
|
||||
foundation.Terrain!,
|
||||
live.DrawDispatcher!),
|
||||
AcDream.App.Rendering.Packs.ThreadPoolRenderPackPreparationScheduler.Instance,
|
||||
renderPackCatalog);
|
||||
bindings.Adopt("render-pack controller", renderPackController);
|
||||
renderPackSelection = new AcDream.App.Rendering.Packs.RenderPackSelectionBinding(
|
||||
d.Settings,
|
||||
renderPackController,
|
||||
d.Log);
|
||||
bindings.Adopt("render-pack selection", renderPackSelection);
|
||||
if (d.RenderPackDiagnostics is { } renderPackDiagnostics)
|
||||
{
|
||||
bindings.Adopt(
|
||||
"render-pack diagnostics",
|
||||
renderPackDiagnostics.BindOwned(renderPackController));
|
||||
}
|
||||
atmosphericInputs = new AcDream.App.Rendering.Packs.AtmosphericFrameInputState();
|
||||
}
|
||||
|
||||
var renderWeatherFrame = new RenderWeatherFrameController(
|
||||
d.WorldTime,
|
||||
d.Weather);
|
||||
|
|
@ -463,7 +495,8 @@ internal sealed class FrameRootCompositionPhase
|
|||
worldScenePasses,
|
||||
d.RenderRange,
|
||||
worldSceneDiagnostics,
|
||||
live.WorldAvailability);
|
||||
live.WorldAvailability,
|
||||
atmosphericInputs);
|
||||
// The world renderer runs INSIDE the frame's one backbuffer pass,
|
||||
// which this phase opens, publishes on the scope, and closes.
|
||||
worldSceneRenderer =
|
||||
|
|
@ -474,14 +507,70 @@ internal sealed class FrameRootCompositionPhase
|
|||
(d.Graphics as VulkanGameWindowGraphics)?.WorldPassScopeCore
|
||||
?? throw new InvalidOperationException(
|
||||
"The Vulkan world phase requires the Vulkan graphics handle."),
|
||||
worldSceneRenderer);
|
||||
worldSceneRenderer,
|
||||
renderPackController,
|
||||
atmosphericInputs,
|
||||
renderPackSelection is null
|
||||
? null
|
||||
: renderPackSelection.ApplyAtFrameBoundary,
|
||||
live.RenderSceneShadow,
|
||||
live.DrawDispatcher,
|
||||
foundation.Terrain);
|
||||
}
|
||||
Fault(FrameRootCompositionPoint.WorldRendererCreated);
|
||||
bindings = new FrameRootRuntimeBindings();
|
||||
WorldLifecycleAutomationController? lifecycleAutomation = null;
|
||||
if (interaction.RetainedUi?.Screenshots is { } screenshots
|
||||
&& d.Options.AutomationArtifactDirectory is { } artifactDirectory)
|
||||
{
|
||||
AcDream.UI.Abstractions.Panels.Settings.RenderPackSelectionSettings?
|
||||
automationLastEnhancedSelection = null;
|
||||
|
||||
(bool Succeeded, string Error) SaveAutomationRenderPackSelection(
|
||||
AcDream.UI.Abstractions.Panels.Settings.RenderPackSelectionSettings selection)
|
||||
{
|
||||
d.Settings.SaveDisplay(d.Settings.Display with
|
||||
{
|
||||
RenderPack = selection,
|
||||
});
|
||||
return d.Settings.Display.RenderPack == selection
|
||||
? (true, string.Empty)
|
||||
: (false, $"render-pack selection '{selection.PresetId}' was not persisted");
|
||||
}
|
||||
|
||||
(bool Succeeded, string Error) SelectAutomationRenderPack(string preset)
|
||||
{
|
||||
var selection = string.Equals(
|
||||
preset,
|
||||
"retail",
|
||||
StringComparison.Ordinal)
|
||||
? AcDream.UI.Abstractions.Panels.Settings
|
||||
.RenderPackSelectionSettings.Retail
|
||||
: new AcDream.UI.Abstractions.Panels.Settings
|
||||
.RenderPackSelectionSettings(
|
||||
AcDream.App.Rendering.Packs
|
||||
.BuiltInAtmosphericRenderPack.Id,
|
||||
"1.0.0",
|
||||
preset);
|
||||
return SaveAutomationRenderPackSelection(selection);
|
||||
}
|
||||
|
||||
(bool Succeeded, string Error) DisableAutomationRenderPack()
|
||||
{
|
||||
var current = d.Settings.Display.RenderPack;
|
||||
if (!current.IsRetail)
|
||||
automationLastEnhancedSelection = current;
|
||||
return SaveAutomationRenderPackSelection(
|
||||
AcDream.UI.Abstractions.Panels.Settings
|
||||
.RenderPackSelectionSettings.Retail);
|
||||
}
|
||||
|
||||
(bool Succeeded, string Error) ReenableAutomationRenderPack()
|
||||
{
|
||||
return automationLastEnhancedSelection is { } selection
|
||||
? SaveAutomationRenderPackSelection(selection)
|
||||
: (false, "render-pack re-enable requires a prior enhanced selection");
|
||||
}
|
||||
|
||||
var resourceSnapshots =
|
||||
new WorldLifecycleResourceSnapshotSource(
|
||||
live.WorldState,
|
||||
|
|
@ -515,7 +604,86 @@ internal sealed class FrameRootCompositionPhase
|
|||
resourceSnapshots.Capture,
|
||||
screenshots,
|
||||
artifactDirectory,
|
||||
message => d.Log("[UI-PROBE] " + message));
|
||||
message => d.Log("[UI-PROBE] " + message),
|
||||
() => renderPackController?.MinimumPerformanceSampleCount ?? 0,
|
||||
() =>
|
||||
{
|
||||
if (renderPackController is null)
|
||||
{
|
||||
return (
|
||||
false,
|
||||
"render-pack performance automation is unavailable");
|
||||
}
|
||||
bool reset = renderPackController.TryResetPerformanceEvidence(
|
||||
out string error);
|
||||
return (reset, error);
|
||||
},
|
||||
() => renderPackController?.Snapshot.State ==
|
||||
AcDream.App.Rendering.Packs.RenderPackActivationState.FailedToRetail,
|
||||
getRenderPackStatus: () =>
|
||||
{
|
||||
AcDream.App.Rendering.Packs.RenderPackActivationSnapshot snapshot =
|
||||
renderPackController?.Snapshot
|
||||
?? new AcDream.App.Rendering.Packs.RenderPackActivationSnapshot(
|
||||
AcDream.App.Rendering.Packs.RenderPackActivationState.Retail,
|
||||
AcDream.UI.Abstractions.Panels.Settings
|
||||
.RenderPackSelectionSettings.Retail,
|
||||
ActivePackDisplayName: null,
|
||||
Reason: null,
|
||||
ActivationGeneration: 0);
|
||||
var state = snapshot.State switch
|
||||
{
|
||||
AcDream.App.Rendering.Packs.RenderPackActivationState.Retail =>
|
||||
AcDream.App.UI.Testing
|
||||
.RetailUiAutomationRenderPackState.Retail,
|
||||
AcDream.App.Rendering.Packs.RenderPackActivationState.CandidatePending =>
|
||||
AcDream.App.UI.Testing
|
||||
.RetailUiAutomationRenderPackState.CandidatePending,
|
||||
AcDream.App.Rendering.Packs.RenderPackActivationState.Active =>
|
||||
AcDream.App.UI.Testing
|
||||
.RetailUiAutomationRenderPackState.Active,
|
||||
AcDream.App.Rendering.Packs.RenderPackActivationState.FailedToRetail =>
|
||||
AcDream.App.UI.Testing
|
||||
.RetailUiAutomationRenderPackState.FailedToRetail,
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
return new AcDream.App.UI.Testing
|
||||
.RetailUiAutomationRenderPackStatus(
|
||||
state,
|
||||
snapshot.Selection.PackId,
|
||||
snapshot.Selection.PresetId,
|
||||
snapshot.ActivationGeneration,
|
||||
snapshot.Reason);
|
||||
},
|
||||
selectRenderPack: SelectAutomationRenderPack,
|
||||
disableRenderPack: DisableAutomationRenderPack,
|
||||
reenableRenderPack: ReenableAutomationRenderPack,
|
||||
getFramebufferSize: () =>
|
||||
{
|
||||
var size = d.Window.FramebufferSize;
|
||||
return (size.X, size.Y);
|
||||
},
|
||||
resizeFramebuffer: (width, height) =>
|
||||
{
|
||||
if (d.Settings.Display.Fullscreen)
|
||||
{
|
||||
return (
|
||||
false,
|
||||
"automation framebuffer resize requires windowed mode");
|
||||
}
|
||||
string resolution = $"{width}x{height}";
|
||||
d.Settings.SaveDisplay(d.Settings.Display with
|
||||
{
|
||||
Resolution = resolution,
|
||||
});
|
||||
return string.Equals(
|
||||
d.Settings.Display.Resolution,
|
||||
resolution,
|
||||
StringComparison.Ordinal)
|
||||
? (true, string.Empty)
|
||||
: (false, $"framebuffer resize '{resolution}' was not persisted");
|
||||
},
|
||||
requestClientClose: d.Window.Close);
|
||||
bindings.Adopt(
|
||||
"world lifecycle automation owner",
|
||||
lifecycleAutomation);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,10 @@ internal sealed record HostInputCameraDependencies(
|
|||
LocalPlayerModeState LocalPlayerMode,
|
||||
ChaseCameraInputState ChaseCameraInput,
|
||||
PointerPositionState PointerPosition,
|
||||
IRenderFrameDiagnosticLog RenderDiagnosticLog);
|
||||
IRenderFrameDiagnosticLog RenderDiagnosticLog,
|
||||
float? InitialOrbitDistanceMeters = null,
|
||||
float? InitialOrbitYawDegrees = null,
|
||||
float? InitialOrbitPitchDegrees = null);
|
||||
|
||||
/// <summary>
|
||||
/// The construction seam every backend differs at. Campaign V slice V6h widened
|
||||
|
|
@ -101,7 +104,10 @@ internal interface IHostInputCameraCompositionFactory
|
|||
IKeyboardSource keyboard,
|
||||
IMouseSource mouse,
|
||||
KeyBindings bindings);
|
||||
CameraController CreateCameraController();
|
||||
CameraController CreateCameraController(
|
||||
float? initialOrbitDistanceMeters,
|
||||
float? initialOrbitYawDegrees,
|
||||
float? initialOrbitPitchDegrees);
|
||||
IFramebufferCameraTarget CreateCameraTarget(CameraController camera);
|
||||
CameraPointerInputController CreateCameraPointerInput(
|
||||
IReadOnlyList<IMouse> mice,
|
||||
|
|
@ -311,7 +317,10 @@ internal sealed class HostInputCameraCompositionPhase :
|
|||
Fault(HostInputCameraCompositionPoint.CameraInputBound);
|
||||
}
|
||||
|
||||
CameraController camera = _factory.CreateCameraController();
|
||||
CameraController camera = _factory.CreateCameraController(
|
||||
_dependencies.InitialOrbitDistanceMeters,
|
||||
_dependencies.InitialOrbitYawDegrees,
|
||||
_dependencies.InitialOrbitPitchDegrees);
|
||||
_publication.PublishCameraController(camera);
|
||||
Fault(HostInputCameraCompositionPoint.CameraPublished);
|
||||
_dependencies.FramebufferResize.BindCamera(
|
||||
|
|
|
|||
|
|
@ -92,7 +92,10 @@ internal sealed record InteractionRetainedUiDependencies(
|
|||
// needed. gmMapUI::Update @0x004a1eb0 reads GameTime::current_game_time
|
||||
// every 5s — MapPageController owns that cadence, this just supplies the
|
||||
// current reading.
|
||||
Func<AcDream.Core.World.DerethDateTime.Calendar> CurrentCalendar)
|
||||
Func<AcDream.Core.World.DerethDateTime.Calendar> CurrentCalendar,
|
||||
AcDream.App.Rendering.Packs.RenderPackCatalogSource? RenderPackCatalog = null,
|
||||
Func<AcDream.App.Rendering.Packs.RenderPackDiagnosticsSnapshot>?
|
||||
RenderPackDiagnostics = null)
|
||||
{
|
||||
public RuntimeActionState Actions => Runtime.ActionOwner;
|
||||
|
||||
|
|
@ -643,7 +646,8 @@ internal sealed class RetailInteractionRetainedUiCompositionFactory
|
|||
screenshots = new FrameScreenshotController(
|
||||
d.BackbufferReader,
|
||||
Path.Combine(artifactDirectory, "screenshots"),
|
||||
ProbeLog);
|
||||
ProbeLog,
|
||||
d.RenderPackDiagnostics);
|
||||
}
|
||||
checkpoint(InteractionRetainedUiCompositionPoint.UiProbeCreated);
|
||||
|
||||
|
|
@ -949,7 +953,53 @@ internal sealed class RetailInteractionRetainedUiCompositionFactory
|
|||
LoadDisplay: () => d.Settings.Display,
|
||||
SaveDisplay: d.Settings.SaveDisplay,
|
||||
LoadAudio: () => d.Settings.Audio,
|
||||
SaveAudio: d.Settings.SaveAudio),
|
||||
SaveAudio: d.Settings.SaveAudio,
|
||||
LoadRenderPackChoices: d.RenderPackCatalog is null
|
||||
? null
|
||||
: () => d.RenderPackCatalog.Snapshot().Entries
|
||||
.Select(entry =>
|
||||
new ConfigOptionsPageController.RenderPackChoice(
|
||||
entry.Descriptor.Id,
|
||||
entry.Descriptor.DisplayName,
|
||||
entry.Descriptor.PackVersion.ToString(),
|
||||
entry.IsCompatible,
|
||||
entry.IncompatibilityReason,
|
||||
entry.Descriptor.QualityPresets
|
||||
.Select(preset =>
|
||||
{
|
||||
entry.PresetIncompatibilityReasons.TryGetValue(
|
||||
preset.Id,
|
||||
out string? reason);
|
||||
return new ConfigOptionsPageController.RenderPackPresetChoice(
|
||||
preset.Id,
|
||||
preset.DisplayName,
|
||||
entry.IsCompatible && reason is null,
|
||||
reason ?? entry.IncompatibilityReason)
|
||||
{
|
||||
SettingOverrides = preset.SettingOverrides,
|
||||
MaxResidentGpuBytes = preset.MaxResidentGpuBytes,
|
||||
MaxIncrementalGpuMillisecondsP50 =
|
||||
preset.MaxIncrementalGpuMillisecondsP50,
|
||||
MaxIncrementalGpuMillisecondsP99 =
|
||||
preset.MaxIncrementalGpuMillisecondsP99,
|
||||
MaxIncrementalCpuMillisecondsP50 =
|
||||
preset.MaxIncrementalCpuMillisecondsP50,
|
||||
MaxIncrementalCpuMillisecondsP99 =
|
||||
preset.MaxIncrementalCpuMillisecondsP99,
|
||||
};
|
||||
})
|
||||
.ToArray())
|
||||
{
|
||||
FeatureSummary = entry.Descriptor.FeatureSummary,
|
||||
Settings = entry.Descriptor.Settings,
|
||||
})
|
||||
.ToArray(),
|
||||
LoadRenderPackCatalogRevision: d.RenderPackCatalog is null
|
||||
? null
|
||||
: () => d.RenderPackCatalog.Revision,
|
||||
LoadRenderPackFailureNotice: d.RenderPackDiagnostics is null
|
||||
? null
|
||||
: () => d.RenderPackDiagnostics().FailureReason),
|
||||
// Campaign FA slice FA3: the social panel's own bindings —
|
||||
// FA2's typed Fellowship/Allegiance snapshot readers off the
|
||||
// GameRuntime views, plus J4.1's Friends/Squelch owners
|
||||
|
|
|
|||
|
|
@ -792,6 +792,67 @@ internal sealed class DeferredWorldLifecycleAutomationRuntime
|
|||
!_deactivated && _target?.IsWorldViewportVisible == true;
|
||||
public int PortalMaterializationCount =>
|
||||
!_deactivated ? _target?.PortalMaterializationCount ?? 0 : 0;
|
||||
public int RenderPackPerformanceSampleCount =>
|
||||
!_deactivated ? _target?.RenderPackPerformanceSampleCount ?? 0 : 0;
|
||||
public bool RenderPackFailedToRetail =>
|
||||
!_deactivated && _target?.RenderPackFailedToRetail == true;
|
||||
public RetailUiAutomationRenderPackStatus RenderPackStatus =>
|
||||
!_deactivated
|
||||
? _target?.RenderPackStatus
|
||||
?? RetailUiAutomationRenderPackStatus.Retail
|
||||
: RetailUiAutomationRenderPackStatus.Retail;
|
||||
public int FramebufferWidth =>
|
||||
!_deactivated ? _target?.FramebufferWidth ?? 0 : 0;
|
||||
public int FramebufferHeight =>
|
||||
!_deactivated ? _target?.FramebufferHeight ?? 0 : 0;
|
||||
|
||||
public bool TrySelectRenderPack(string presetId, out string error)
|
||||
{
|
||||
if (!_deactivated && _target is { } target)
|
||||
return target.TrySelectRenderPack(presetId, out error);
|
||||
error = "world lifecycle automation is not bound";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryDisableRenderPack(out string error)
|
||||
{
|
||||
if (!_deactivated && _target is { } target)
|
||||
return target.TryDisableRenderPack(out error);
|
||||
error = "world lifecycle automation is not bound";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReenableRenderPack(out string error)
|
||||
{
|
||||
if (!_deactivated && _target is { } target)
|
||||
return target.TryReenableRenderPack(out error);
|
||||
error = "world lifecycle automation is not bound";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryResizeFramebuffer(int width, int height, out string error)
|
||||
{
|
||||
if (!_deactivated && _target is { } target)
|
||||
return target.TryResizeFramebuffer(width, height, out error);
|
||||
error = "world lifecycle automation is not bound";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryResetRenderPackPerformance(out string error)
|
||||
{
|
||||
if (!_deactivated && _target is { } target)
|
||||
return target.TryResetRenderPackPerformance(out error);
|
||||
error = "world lifecycle automation is not bound";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryRequestClientClose(out string error)
|
||||
{
|
||||
if (!_deactivated && _target is { } target)
|
||||
return target.TryRequestClientClose(out error);
|
||||
error = "world lifecycle automation is not bound";
|
||||
return false;
|
||||
}
|
||||
|
||||
public IDisposable Bind(IRetailUiAutomationRuntime target)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -74,7 +74,9 @@ internal sealed record LivePresentationDependencies(
|
|||
DeferredRenderFrameDiagnosticsSource? DevFrameDiagnostics,
|
||||
DeferredRenderFrameDiagnosticsSource UiFrameDiagnostics,
|
||||
Action<string> Log,
|
||||
Action<string>? Toast)
|
||||
Action<string>? Toast,
|
||||
AcDream.App.Rendering.Packs.IRenderPackDiagnosticsSnapshotSource?
|
||||
RenderPackDiagnostics = null)
|
||||
{
|
||||
public SelectionState Selection => Runtime.ActionOwner.Selection;
|
||||
|
||||
|
|
@ -448,7 +450,8 @@ internal sealed class LivePresentationCompositionPhase
|
|||
LiveRenderProjectionJournal? liveRenderProjections =
|
||||
renderSceneShadow?.BindLiveRuntime(
|
||||
liveEntities,
|
||||
new GpuWorldRenderTraversalOrderSource(worldState));
|
||||
new GpuWorldRenderTraversalOrderSource(worldState),
|
||||
d.PlayerIdentity);
|
||||
Fault(LivePresentationCompositionPoint.CanonicalRuntimeCreated);
|
||||
|
||||
bindings.Adopt(
|
||||
|
|
@ -803,7 +806,9 @@ internal sealed class LivePresentationCompositionPhase
|
|||
d.TranslucencyFades,
|
||||
selectionScene,
|
||||
d.RetailAlphaQueue,
|
||||
alphaScratchBudgets.DispatcherBytes),
|
||||
alphaScratchBudgets.DispatcherBytes,
|
||||
foundation.TerrainAtlas?.BuildingDetailTexture ?? default,
|
||||
() => d.Settings.DisplayPreview.BuildingDetailTextures),
|
||||
static value => value.Dispose());
|
||||
var selectionQuery = new WorldSelectionQuery(
|
||||
liveEntities,
|
||||
|
|
@ -1238,9 +1243,11 @@ internal sealed class LivePresentationCompositionPhase
|
|||
?? throw new InvalidOperationException(
|
||||
"The graphics backend must publish a world pass scope."),
|
||||
foundation.MeshAdapter!.MeshManager!,
|
||||
envCellFrustum),
|
||||
envCellFrustum,
|
||||
foundation.TerrainAtlas?.EnvironmentDetailTexture ?? default,
|
||||
() => d.Settings.DisplayPreview.BuildingDetailTextures),
|
||||
static value => value.Dispose());
|
||||
// The three pipelines ARE its program, built at construction — the
|
||||
// The four pipelines ARE its program, built at construction — the
|
||||
// raw-GL arm's separate Initialize(Shader) step was deleted at V11.
|
||||
Fault(LivePresentationCompositionPoint.EnvironmentCellsCreated);
|
||||
|
||||
|
|
@ -1484,7 +1491,8 @@ internal sealed class LivePresentationCompositionPhase
|
|||
new SilkRenderFrameTitleSink(d.Window),
|
||||
d.RenderDiagnosticLog,
|
||||
d.Options.UiProbeDump,
|
||||
resourceDiagnostics);
|
||||
resourceDiagnostics,
|
||||
d.RenderPackDiagnostics);
|
||||
if (d.DevFrameDiagnostics is { } devFrameDiagnostics)
|
||||
{
|
||||
bindings.Adopt(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
using AcDream.App.Settings;
|
||||
using AcDream.App.Plugins;
|
||||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.Rendering.Packs;
|
||||
using AcDream.UI.Abstractions.Panels.Settings;
|
||||
using Silk.NET.Input;
|
||||
|
||||
namespace AcDream.App.Composition;
|
||||
|
|
@ -18,11 +22,22 @@ namespace AcDream.App.Composition;
|
|||
/// keybinds.json (not retail's <c>.keymap</c> format — register row AP-202).
|
||||
/// </summary>
|
||||
internal sealed record SettingsDevToolsResult(
|
||||
AcDream.UI.Abstractions.Settings.QualitySettings ResolvedQuality);
|
||||
AcDream.UI.Abstractions.Settings.QualitySettings ResolvedQuality)
|
||||
{
|
||||
internal RenderPackCatalogSource? RenderPacks { get; init; }
|
||||
|
||||
internal RenderPackSelectionSettings RenderPackSelection { get; init; } =
|
||||
RenderPackSelectionSettings.Retail;
|
||||
}
|
||||
|
||||
internal sealed record SettingsDevToolsDependencies(
|
||||
RuntimeSettingsController Settings,
|
||||
IRuntimeSettingsStartupTarget StartupTarget);
|
||||
IRuntimeSettingsStartupTarget StartupTarget)
|
||||
{
|
||||
internal BufferedRenderPackRegistry? RenderPacks { get; init; }
|
||||
|
||||
internal IGpuDevice? GpuDevice { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Production Phase 3: applies the resolved startup display/audio settings.
|
||||
|
|
@ -51,6 +66,19 @@ internal sealed class SettingsDevToolsCompositionPhase :
|
|||
ArgumentNullException.ThrowIfNull(content);
|
||||
|
||||
_dependencies.Settings.ApplyStartup(_dependencies.StartupTarget);
|
||||
return new SettingsDevToolsResult(_dependencies.Settings.ResolvedQuality);
|
||||
RenderPackCatalogSource? renderPacks = null;
|
||||
if (_dependencies.RenderPacks is { } registry
|
||||
&& _dependencies.GpuDevice is { } gpu)
|
||||
{
|
||||
renderPacks = new RenderPackCatalogSource(
|
||||
registry,
|
||||
RenderPackCapabilityResolver.Resolve(gpu.Capabilities));
|
||||
}
|
||||
|
||||
return new SettingsDevToolsResult(_dependencies.Settings.ResolvedQuality)
|
||||
{
|
||||
RenderPacks = renderPacks,
|
||||
RenderPackSelection = _dependencies.Settings.Display.RenderPack,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,8 +82,23 @@ internal sealed class VulkanHostInputCameraCompositionFactory
|
|||
KeyBindings bindings) =>
|
||||
InputDispatcher.CreateDetached(keyboard, mouse, bindings);
|
||||
|
||||
public CameraController CreateCameraController() =>
|
||||
new(new OrbitCamera(), new FlyCamera());
|
||||
public CameraController CreateCameraController(
|
||||
float? initialOrbitDistanceMeters,
|
||||
float? initialOrbitYawDegrees,
|
||||
float? initialOrbitPitchDegrees)
|
||||
{
|
||||
var orbit = new OrbitCamera();
|
||||
if (initialOrbitDistanceMeters is { } distance)
|
||||
orbit.Distance = distance;
|
||||
if (initialOrbitYawDegrees is { } yaw)
|
||||
orbit.Yaw = DegreesToRadians(yaw);
|
||||
if (initialOrbitPitchDegrees is { } pitch)
|
||||
orbit.Pitch = DegreesToRadians(pitch);
|
||||
return new CameraController(orbit, new FlyCamera());
|
||||
}
|
||||
|
||||
private static float DegreesToRadians(float degrees) =>
|
||||
degrees * (MathF.PI / 180f);
|
||||
|
||||
public IFramebufferCameraTarget CreateCameraTarget(CameraController camera) =>
|
||||
new CameraFramebufferTarget(camera);
|
||||
|
|
|
|||
|
|
@ -78,7 +78,10 @@ internal interface IGameWindowWorldRenderPublication
|
|||
internal interface IWorldRenderCompositionFactory
|
||||
{
|
||||
WorldRegionData LoadRegion(IDatReaderWriter dats);
|
||||
void InitializeEnvironment(WorldEnvironmentController environment, Region region);
|
||||
void InitializeEnvironment(
|
||||
WorldEnvironmentController environment,
|
||||
Region region,
|
||||
IDatReaderWriter dats);
|
||||
/// <summary>
|
||||
/// Campaign V slice V6i-2: the terrain atlas built through
|
||||
/// <see cref="AcDream.App.Rendering.Gpu.IGpuDevice"/>. The raw-GL arm this
|
||||
|
|
@ -188,11 +191,13 @@ internal sealed class RetailWorldRenderCompositionFactory
|
|||
|
||||
public void InitializeEnvironment(
|
||||
WorldEnvironmentController environment,
|
||||
Region region)
|
||||
Region region,
|
||||
IDatReaderWriter dats)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(environment);
|
||||
ArgumentNullException.ThrowIfNull(region);
|
||||
environment.Initialize(region);
|
||||
ArgumentNullException.ThrowIfNull(dats);
|
||||
environment.Initialize(region, dats);
|
||||
}
|
||||
|
||||
public TerrainAtlas AcquireBackendNeutralTerrainAtlas(
|
||||
|
|
@ -452,7 +457,10 @@ internal sealed class WorldRenderCompositionPhase
|
|||
|
||||
WorldRegionData region = _factory.LoadRegion(content.Dats);
|
||||
Fault(WorldRenderCompositionPoint.RegionLoaded);
|
||||
_factory.InitializeEnvironment(_dependencies.Environment, region.Region);
|
||||
_factory.InitializeEnvironment(
|
||||
_dependencies.Environment,
|
||||
region.Region,
|
||||
content.Dats);
|
||||
Fault(WorldRenderCompositionPoint.EnvironmentInitialized);
|
||||
|
||||
// Campaign V slice V6i-2: the atlas builds through IGpuDevice on
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue