diff --git a/src/AcDream.App/Rendering/Wb/GlobalMeshBuffer.cs b/src/AcDream.App/Rendering/Wb/GlobalMeshBuffer.cs index 3441c66a..3e2c78e2 100644 --- a/src/AcDream.App/Rendering/Wb/GlobalMeshBuffer.cs +++ b/src/AcDream.App/Rendering/Wb/GlobalMeshBuffer.cs @@ -1,3 +1,4 @@ +using AcDream.Content; using Chorizite.Core.Render.Enums; using Silk.NET.OpenGL; using System; diff --git a/src/AcDream.App/Rendering/Wb/ObjectMeshManager.cs b/src/AcDream.App/Rendering/Wb/ObjectMeshManager.cs index 7d9368ef..c41ab98e 100644 --- a/src/AcDream.App/Rendering/Wb/ObjectMeshManager.cs +++ b/src/AcDream.App/Rendering/Wb/ObjectMeshManager.cs @@ -26,118 +26,6 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; namespace AcDream.App.Rendering.Wb { - /// - /// Vertex format for scenery mesh rendering: position, normal, UV. - /// - [StructLayout(LayoutKind.Sequential)] - public struct VertexPositionNormalTexture { - public Vector3 Position; - public Vector3 Normal; - public Vector2 UV; - - public static int Size => 8 * sizeof(float); // 3+3+2 = 8 floats = 32 bytes - - public VertexPositionNormalTexture(Vector3 position, Vector3 normal, Vector2 uv) { - Position = position; - Normal = normal; - UV = uv; - } - } - - /// - /// Staged data for a particle emitter to be created on the GL thread. - /// - public struct StagedEmitter { - public ParticleEmitter Emitter; - public uint PartIndex; - public Matrix4x4 Offset; - } - - /// - /// CPU-side mesh data prepared on a background thread. - /// Contains vertex data and per-batch index/texture info, but NO GPU resources. - /// - public class ObjectMeshData { - public ulong ObjectId { get; set; } - public bool IsSetup { get; set; } - public VertexPositionNormalTexture[] Vertices { get; set; } = Array.Empty(); - public List Batches { get; set; } = new(); - - /// - /// #125 (2026-06-12): GL upload-retry counter. A failed - /// (returns null from its - /// catch) used to be dropped permanently — the staged item was consumed, - /// no render data was produced, and the prepared data lingered in the CPU - /// cache where PrepareMeshDataAsync's cache-hit short-circuit - /// returned it without ever re-staging it for upload (session-sticky - /// invisible mesh, one [wb-error] line). The drain loop now re-stages a - /// failed upload for the NEXT frame up to times. The counter lives on the mesh-data object so - /// it resets to 0 naturally whenever the id is re-prepared (fresh object), - /// and bounds a deterministic GL failure to a few loud lines instead of a - /// silent permanent drop OR an unbounded per-frame retry storm. Retail - /// loads content synchronously and has no such failure mode — this - /// converges our async pipeline toward that guarantee. - /// - public int UploadAttempts; - - /// For EnvCell: the geometry of the cell itself. - public ObjectMeshData? EnvCellGeometry { get; set; } - - /// For Setup objects: parts with their local transforms. - public List<(ulong GfxObjId, Matrix4x4 Transform)> SetupParts { get; set; } = new(); - - /// Particle emitters from physics scripts. - public List ParticleEmitters { get; set; } = new(); - - /// Per-format texture atlas data (to be uploaded to GPU on main thread). - public Dictionary<(int Width, int Height, TextureFormat Format), List> TextureBatches { get; set; } = new(); - - /// Local bounding box. - public BoundingBox BoundingBox { get; set; } - - /// Approximate center point used for depth sorting / transparency ordering. - public Vector3 SortCenter { get; set; } - - /// DataID of a simpler GfxObj to use at long distance / low quality, or GfxObjDegradeInfo. - public uint DIDDegrade { get; set; } - - /// Sphere used for mouse selection. - public Sphere? SelectionSphere { get; set; } - - /// Edge line vertices for Environment wireframe rendering. - public Vector3[] EdgeLines { get; set; } = Array.Empty(); - } - - /// - /// CPU-side data for a single rendering batch (indices + texture reference). - /// - public class MeshBatchData { - public ushort[] Indices { get; set; } = Array.Empty(); - public (int Width, int Height, TextureFormat Format) TextureFormat { get; set; } - public TextureKey TextureKey { get; set; } - public int TextureIndex { get; set; } - public byte[] TextureData { get; set; } = Array.Empty(); - public PixelFormat? UploadPixelFormat { get; set; } - public PixelType? UploadPixelType { get; set; } - public DatReaderWriter.Enums.CullMode CullMode { get; set; } - } - - /// - /// CPU-side texture info for deduplication during background preparation. - /// - public class TextureBatchData { - public TextureKey Key { get; set; } - public byte[] TextureData { get; set; } = Array.Empty(); - public PixelFormat? UploadPixelFormat { get; set; } - public PixelType? UploadPixelType { get; set; } - public List Indices { get; set; } = new(); - public DatReaderWriter.Enums.CullMode CullMode { get; set; } - public bool IsTransparent { get; set; } - public bool IsAdditive { get; set; } - public bool HasWrappingUVs { get; set; } - } - /// /// GPU-side render data created on the main thread. /// diff --git a/src/AcDream.App/Rendering/Wb/WbMeshAdapter.cs b/src/AcDream.App/Rendering/Wb/WbMeshAdapter.cs index 8bbdd6bd..9440ba6c 100644 --- a/src/AcDream.App/Rendering/Wb/WbMeshAdapter.cs +++ b/src/AcDream.App/Rendering/Wb/WbMeshAdapter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using AcDream.Content; using AcDream.Core.Meshing; using AcDream.Core.Rendering; using DatReaderWriter; diff --git a/src/AcDream.Content/AcDream.Content.csproj b/src/AcDream.Content/AcDream.Content.csproj index 768639e7..1abed36e 100644 --- a/src/AcDream.Content/AcDream.Content.csproj +++ b/src/AcDream.Content/AcDream.Content.csproj @@ -12,6 +12,14 @@ exact versions (mirror AcDream.App.csproj — keep in lockstep). --> + + diff --git a/src/AcDream.Content/ObjectMeshData.cs b/src/AcDream.Content/ObjectMeshData.cs new file mode 100644 index 00000000..8bba1e0c --- /dev/null +++ b/src/AcDream.Content/ObjectMeshData.cs @@ -0,0 +1,125 @@ +using Chorizite.Core.Lib; +using Chorizite.Core.Render.Enums; +using DatReaderWriter.DBObjs; +using DatReaderWriter.Types; +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Runtime.InteropServices; +using BoundingBox = Chorizite.Core.Lib.BoundingBox; +using PixelFormat = Silk.NET.OpenGL.PixelFormat; +using PixelType = Silk.NET.OpenGL.PixelType; + +namespace AcDream.Content; + +/// +/// Vertex format for scenery mesh rendering: position, normal, UV. +/// +[StructLayout(LayoutKind.Sequential)] +public struct VertexPositionNormalTexture { + public Vector3 Position; + public Vector3 Normal; + public Vector2 UV; + + public static int Size => 8 * sizeof(float); // 3+3+2 = 8 floats = 32 bytes + + public VertexPositionNormalTexture(Vector3 position, Vector3 normal, Vector2 uv) { + Position = position; + Normal = normal; + UV = uv; + } +} + +/// +/// Staged data for a particle emitter to be created on the GL thread. +/// +public struct StagedEmitter { + public ParticleEmitter Emitter; + public uint PartIndex; + public Matrix4x4 Offset; +} + +/// +/// CPU-side mesh data prepared on a background thread. +/// Contains vertex data and per-batch index/texture info, but NO GPU resources. +/// +public class ObjectMeshData { + public ulong ObjectId { get; set; } + public bool IsSetup { get; set; } + public VertexPositionNormalTexture[] Vertices { get; set; } = Array.Empty(); + public List Batches { get; set; } = new(); + + /// + /// #125 (2026-06-12): GL upload-retry counter. A failed + /// (returns null from its + /// catch) used to be dropped permanently — the staged item was consumed, + /// no render data was produced, and the prepared data lingered in the CPU + /// cache where PrepareMeshDataAsync's cache-hit short-circuit + /// returned it without ever re-staging it for upload (session-sticky + /// invisible mesh, one [wb-error] line). The drain loop now re-stages a + /// failed upload for the NEXT frame up to times. The counter lives on the mesh-data object so + /// it resets to 0 naturally whenever the id is re-prepared (fresh object), + /// and bounds a deterministic GL failure to a few loud lines instead of a + /// silent permanent drop OR an unbounded per-frame retry storm. Retail + /// loads content synchronously and has no such failure mode — this + /// converges our async pipeline toward that guarantee. + /// + public int UploadAttempts; + + /// For EnvCell: the geometry of the cell itself. + public ObjectMeshData? EnvCellGeometry { get; set; } + + /// For Setup objects: parts with their local transforms. + public List<(ulong GfxObjId, Matrix4x4 Transform)> SetupParts { get; set; } = new(); + + /// Particle emitters from physics scripts. + public List ParticleEmitters { get; set; } = new(); + + /// Per-format texture atlas data (to be uploaded to GPU on main thread). + public Dictionary<(int Width, int Height, TextureFormat Format), List> TextureBatches { get; set; } = new(); + + /// Local bounding box. + public BoundingBox BoundingBox { get; set; } + + /// Approximate center point used for depth sorting / transparency ordering. + public Vector3 SortCenter { get; set; } + + /// DataID of a simpler GfxObj to use at long distance / low quality, or GfxObjDegradeInfo. + public uint DIDDegrade { get; set; } + + /// Sphere used for mouse selection. + public Sphere? SelectionSphere { get; set; } + + /// Edge line vertices for Environment wireframe rendering. + public Vector3[] EdgeLines { get; set; } = Array.Empty(); +} + +/// +/// CPU-side data for a single rendering batch (indices + texture reference). +/// +public class MeshBatchData { + public ushort[] Indices { get; set; } = Array.Empty(); + public (int Width, int Height, TextureFormat Format) TextureFormat { get; set; } + public TextureKey TextureKey { get; set; } + public int TextureIndex { get; set; } + public byte[] TextureData { get; set; } = Array.Empty(); + public PixelFormat? UploadPixelFormat { get; set; } + public PixelType? UploadPixelType { get; set; } + public DatReaderWriter.Enums.CullMode CullMode { get; set; } +} + +/// +/// CPU-side texture info for deduplication during background preparation. +/// +public class TextureBatchData { + public TextureKey Key { get; set; } + public byte[] TextureData { get; set; } = Array.Empty(); + public PixelFormat? UploadPixelFormat { get; set; } + public PixelType? UploadPixelType { get; set; } + public List Indices { get; set; } = new(); + public DatReaderWriter.Enums.CullMode CullMode { get; set; } + public bool IsTransparent { get; set; } + public bool IsAdditive { get; set; } + public bool HasWrappingUVs { get; set; } +}