using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using UnityEngine; namespace CultMath.Unity; [StructLayout(LayoutKind.Sequential)] public readonly struct PlanetaryPageInputGpu { public PlanetaryPageInputGpu(Vector4 directionRadius, Vector4 sampling) { DirectionRadius = directionRadius; Sampling = sampling; } public readonly Vector4 DirectionRadius; public readonly Vector4 Sampling; } [StructLayout(LayoutKind.Sequential)] public readonly struct PlanetaryPageMetadataGpu { public PlanetaryPageMetadataGpu(Vector4 address, Vector4 layout, Vector4 bounds, Vector4 state) { Address = address; Layout = layout; Bounds = bounds; State = state; } public readonly Vector4 Address; public readonly Vector4 Layout; public readonly Vector4 Bounds; public readonly Vector4 State; } public readonly struct PlanetaryPageUpload { public PlanetaryPageUpload( PlanetaryPageInputGpu[] inputs, PlanetaryPageMetadataGpu[] metadata, int outputSampleCount, ulong contentVersion, ulong presentationVersion) { Inputs = inputs; Metadata = metadata; OutputSampleCount = outputSampleCount; ContentVersion = contentVersion; PresentationVersion = presentationVersion; } public PlanetaryPageInputGpu[] Inputs { get; } public PlanetaryPageMetadataGpu[] Metadata { get; } public int OutputSampleCount { get; } public ulong ContentVersion { get; } public ulong PresentationVersion { get; } } public static class PlanetaryPageUploadBuilder { public static PlanetaryPageUpload Build( in PlanetaryResidencySnapshot snapshot, int interiorSize, int borderSize, float radius) { if (!float.IsFinite(radius) || radius <= 0) throw new ArgumentOutOfRangeException(nameof(radius)); var inputs = new List(); var metadata = new PlanetaryPageMetadataGpu[snapshot.Tiles.Length]; foreach (var (resident, pageIndex) in snapshot.Tiles.Select((resident, index) => (resident, index))) { var layout = new PlanetaryPageLayout(resident.Tile, interiorSize, borderSize).Validate(); var content = PlanetaryGpuPageBuilder.BuildContent(layout, radius); var outputOffset = inputs.Count; foreach (var input in content.Inputs) { inputs.Add(new( ToUnity(input.DirectionRadius), ToUnity(input.Sampling))); } var commonMetadata = PlanetaryGpuPageBuilder.Metadata(content, outputOffset, resident.Blend); metadata[pageIndex] = new( ToUnity(commonMetadata.Address), ToUnity(commonMetadata.Layout), ToUnity(commonMetadata.Bounds), ToUnity(commonMetadata.State)); } return new(inputs.ToArray(), metadata, inputs.Count, snapshot.ContentVersion, snapshot.PresentationVersion); } private static Vector4 ToUnity(float4 value) => new(value.x, value.y, value.z, value.w); }