diff --git a/zzre.core/rendering/DynamicMesh.cs b/zzre.core/rendering/DynamicMesh.cs index 72890fca..a1ca8b14 100644 --- a/zzre.core/rendering/DynamicMesh.cs +++ b/zzre.core/rendering/DynamicMesh.cs @@ -224,12 +224,7 @@ private void UpdateIndexBuffer(CommandList cl) if (uploadedPrimitiveCount < PrimitiveCount) { - var indices = new ushort[IndexPattern.Count * (PrimitiveCount - uploadedPrimitiveCount)]; - for (int i = uploadedPrimitiveCount; i < PrimitiveCount; i++) - { - for (int j = 0; j < IndexPattern.Count; j++) - indices[i * PrimitiveCount + j] = (ushort)(i * verticesPerPrimitive + IndexPattern[j]); - } + var indices = StaticMesh.GeneratePatternIndices(indexPattern, uploadedPrimitiveCount, PrimitiveCount, verticesPerPrimitive); cl.UpdateBuffer(indexBuffer, (uint)(uploadedPrimitiveCount * PrimitiveCount * sizeof(ushort)), indices); } } diff --git a/zzre.core/rendering/Mesh.cs b/zzre.core/rendering/StaticMesh.cs similarity index 84% rename from zzre.core/rendering/Mesh.cs rename to zzre.core/rendering/StaticMesh.cs index 5125f72f..a892eb99 100644 --- a/zzre.core/rendering/Mesh.cs +++ b/zzre.core/rendering/StaticMesh.cs @@ -7,7 +7,7 @@ namespace zzre.rendering; -public class Mesh : BaseDisposable, IVertexAttributeContainer +public class StaticMesh : BaseDisposable, IVertexAttributeContainer { public readonly record struct SubMesh(int IndexOffset, int IndexCount, int Material, int Section = 0) : IComparable { @@ -43,7 +43,7 @@ public class VertexAttribute throw new InvalidOperationException("Index buffer was not yet set on mesh"); public string Name { get; } - public Mesh(ITagContainer diContainer, string name) + public StaticMesh(ITagContainer diContainer, string name) { graphicsDevice = diContainer.GetTag(); resourceFactory = graphicsDevice.ResourceFactory; @@ -166,6 +166,37 @@ public void SetIndices(ReadOnlySpan indices) graphicsDevice.UpdateBuffer(buffer, 0u, indices); } + public void SetIndicesFromPattern(IReadOnlyList pattern) + { + if (VertexCount <= 0) + throw new InvalidOperationException("Cannot generate indices from pattern without vertices"); + var verticesPerPrimitive = pattern.Max() + 1; + var primitiveCount = VertexCount / verticesPerPrimitive; + var buffer = SetIndexCount(primitiveCount * pattern.Count, IndexFormat.UInt16); + var indices = GeneratePatternIndices(pattern, 0, primitiveCount, verticesPerPrimitive); + graphicsDevice.UpdateBuffer(buffer, 0u, indices); + } + + internal static ushort[] GeneratePatternIndices(IReadOnlyList pattern, + int primitiveStart, + int primitiveCount, + int verticesPerPrimitive) + { + if (pattern.Count == 0) + throw new ArgumentOutOfRangeException(nameof(pattern)); + if (primitiveStart < 0 || primitiveStart > primitiveCount) + throw new ArgumentOutOfRangeException(nameof(primitiveStart)); + if (primitiveStart == primitiveCount) + return Array.Empty(); + var indices = new ushort[pattern.Count * (primitiveCount - primitiveStart)]; + for (int i = primitiveStart; i < primitiveCount; i++) + { + for (int j = 0; j < pattern.Count; j++) + indices[i * pattern.Count + j] = (ushort)(i * verticesPerPrimitive + pattern[j]); + } + return indices; + } + public void AddSubMesh(SubMesh subMesh) { if (IndexCount <= 0) diff --git a/zzre/debug/DebugSkeletonRenderer.cs b/zzre/debug/DebugSkeletonRenderer.cs index c64e46b6..15c763b5 100644 --- a/zzre/debug/DebugSkeletonRenderer.cs +++ b/zzre/debug/DebugSkeletonRenderer.cs @@ -47,25 +47,24 @@ public class DebugSkeletonRenderer : BaseDisposable private readonly LocationBuffer locationBuffer; private readonly GraphicsDevice device; - private readonly DeviceBuffer vertexBuffer; - private readonly DeviceBuffer indexBuffer; - private readonly DeviceBuffer skinBuffer; - private readonly DeviceBuffer lineBuffer; + private readonly StaticMesh boneMesh; + private readonly StaticMesh.VertexAttribute boneColorAttribute; + private readonly DebugLineRenderer lineRenderer; private readonly IReadOnlyList boneDepths; private readonly DeviceBufferRange worldBufferRange; private DebugSkeletonRenderMode renderMode = DebugSkeletonRenderMode.Invisible; private int highlightedBoneI = -1; - public DebugSkinnedMaterial BoneMaterial { get; } + public DebugMaterial BoneMaterial { get; } public DebugMaterial SkinMaterial { get; } public DebugMaterial SkinHighlightedMaterial { get; } - public DebugLinesMaterial LinesMaterial { get; } - public Mesh Mesh { get; } + public DebugMaterial LinesMaterial => lineRenderer.Material; + public StaticMesh Mesh { get; } public Skeleton Skeleton { get; } public ref DebugSkeletonRenderMode RenderMode => ref renderMode; // reference for using the field with ImGui - public DebugSkeletonRenderer(ITagContainer diContainer, Mesh mesh, Skeleton skeleton) + public DebugSkeletonRenderer(ITagContainer diContainer, StaticMesh mesh, Skeleton skeleton) { Mesh = mesh; Skeleton = skeleton; @@ -78,20 +77,20 @@ void LinkTransformsFor(IStandardTransformMaterial m) m.LinkTransformsTo(camera); m.World.BufferRange = worldBufferRange; } - BoneMaterial = new DebugSkinnedMaterial(diContainer); + BoneMaterial = new DebugMaterial(diContainer) { IsSkinned = true }; LinkTransformsFor(BoneMaterial); BoneMaterial.Pose.Skeleton = skeleton; SkinMaterial = new(diContainer) { Color = DebugMaterial.ColorMode.SkinWeights }; LinkTransformsFor(SkinMaterial); SkinHighlightedMaterial = new(diContainer) { Color = DebugMaterial.ColorMode.SingleBoneWeight }; LinkTransformsFor(SkinHighlightedMaterial); - LinesMaterial = new DebugLinesMaterial(diContainer); + lineRenderer = new(diContainer); LinkTransformsFor(LinesMaterial); device = diContainer.GetTag(); - var vertices = Enumerable.Empty(); - var skinVertices = Enumerable.Empty(); - var indices = Enumerable.Empty(); + var vertices = Enumerable.Empty(); + var colors = Enumerable.Empty(); + var skinIndices = Enumerable.Empty(); // color as this is also 4 bytes foreach (var (bone, index) in skeleton.Bones.Indexed()) { if (bone.Parent == null) @@ -116,44 +115,22 @@ void LinkTransformsFor(IStandardTransformMaterial m) baseCenter + tangent + bitangent, baseCenter - tangent + bitangent, to - }.Select(p => new ColoredVertex(p, Colors[index % Colors.Length]))); - skinVertices = skinVertices.Concat(Enumerable.Repeat(new SkinVertex() - { - bone0 = unchecked((byte)Skeleton.Parents[index]), - weights = Vector4.UnitX - }, RhombusVertexCount)); - indices = indices.Concat(RhombusIndices.Select(i => (ushort)(i + index * RhombusVertexCount))); + }); + colors = colors.Concat(Enumerable.Repeat(Colors[index % Colors.Length], RhombusVertexCount)); + var indices = new IColor(unchecked((byte)Skeleton.Parents[index]), 0, 0, 0); + skinIndices = skinIndices.Concat(Enumerable.Repeat(indices, RhombusVertexCount)); } - - var vertexArray = vertices.ToArray(); - var skinVertexArray = skinVertices.ToArray(); - var indexArray = indices.ToArray(); - vertexBuffer = device.ResourceFactory.CreateBuffer(new BufferDescription( - (uint)vertexArray.Length * ColoredVertex.Stride, BufferUsage.VertexBuffer)); - skinBuffer = device.ResourceFactory.CreateBuffer(new BufferDescription( - (uint)skinVertexArray.Length * SkinVertex.Stride, BufferUsage.VertexBuffer)); - indexBuffer = device.ResourceFactory.CreateBuffer(new BufferDescription( - (uint)indexArray.Length * sizeof(ushort), BufferUsage.IndexBuffer)); - vertexBuffer.Name = $"DebugSkeleton Vertices {GetHashCode()}"; - skinBuffer.Name = $"DebugSkeleton Skin {GetHashCode()}"; - indexBuffer.Name = $"DebugSkeleton Indices {GetHashCode()}"; - device.UpdateBuffer(vertexBuffer, 0, vertexArray); - device.UpdateBuffer(skinBuffer, 0, skinVertexArray); - device.UpdateBuffer(indexBuffer, 0, indexArray); - - var lineVertices = new ColoredVertex[] - { - new ColoredVertex(Vector3.Zero, Colors[0]), - new ColoredVertex(Vector3.UnitX * LineLength, Colors[0]), - new ColoredVertex(Vector3.Zero, Colors[1]), - new ColoredVertex(Vector3.UnitY * LineLength, Colors[1]), - new ColoredVertex(Vector3.Zero, Colors[2]), - new ColoredVertex(Vector3.UnitZ * LineLength, Colors[2]) - }; - lineBuffer = device.ResourceFactory.CreateBuffer(new BufferDescription( - (uint)lineVertices.Length * ColoredVertex.Stride, BufferUsage.VertexBuffer)); - lineBuffer.Name = $"DebugSkeleton LineVertices {GetHashCode()}"; - device.UpdateBuffer(lineBuffer, 0, lineVertices); + boneMesh = new(diContainer, "Debug Skeleton Bones"); + boneMesh.Add("Pos", "inPos", vertices.ToArray()); + boneColorAttribute = boneMesh.Add("Color", "inColor", colors.ToArray()); + boneMesh.Add("Bone Weights", "inWeights", Enumerable.Repeat(Vector4.UnitX, boneMesh.VertexCount).ToArray()); + boneMesh.Add("Bone Indices", "inIndices", skinIndices.ToArray()); + boneMesh.SetIndicesFromPattern(RhombusIndices); + + lineRenderer.Reserve(3); + lineRenderer.Add(Colors[0], Vector3.Zero, Vector3.UnitX * LineLength); + lineRenderer.Add(Colors[1], Vector3.Zero, Vector3.UnitY * LineLength); + lineRenderer.Add(Colors[2], Vector3.Zero, Vector3.UnitZ * LineLength); var boneDepthsArr = new int[Skeleton.Bones.Count]; for (int i = 0; i < Skeleton.Bones.Count; i++) @@ -164,10 +141,8 @@ void LinkTransformsFor(IStandardTransformMaterial m) protected override void DisposeManaged() { base.DisposeManaged(); - vertexBuffer.Dispose(); - skinBuffer.Dispose(); - indexBuffer.Dispose(); - lineBuffer.Dispose(); + boneMesh.Dispose(); + lineRenderer.Dispose(); BoneMaterial.Dispose(); SkinMaterial.Dispose(); SkinHighlightedMaterial.Dispose(); @@ -187,17 +162,14 @@ public void Render(CommandList cl) // always draw bones when visible (BoneMaterial as IMaterial).Apply(cl); - cl.SetVertexBuffer(0, vertexBuffer); - cl.SetVertexBuffer(1, skinBuffer); - cl.SetIndexBuffer(indexBuffer, IndexFormat.UInt16); - cl.DrawIndexed(indexBuffer.SizeInBytes / sizeof(ushort)); + BoneMaterial.ApplyAttributes(cl, boneMesh); + cl.SetIndexBuffer(boneMesh.IndexBuffer, boneMesh.IndexFormat); + cl.DrawIndexed((uint)boneMesh.IndexCount); if (highlightedBoneI >= 0) { LinesMaterial.World.Ref = Skeleton.Bones[highlightedBoneI].LocalToWorld; - (LinesMaterial as IMaterial).Apply(cl); - cl.SetVertexBuffer(0, lineBuffer); - cl.Draw(lineBuffer.SizeInBytes / ColoredVertex.Stride); + lineRenderer.Render(cl); } } @@ -224,10 +196,8 @@ private void SetBoneAlpha(int boneI, byte alpha) // this is probably a terrible but also very lazy way of doing this for (int vertexI = 0; vertexI < RhombusVertexCount; vertexI++) { - var offset = - (boneI * RhombusVertexCount + vertexI) * ColoredVertex.Stride + - 3 * sizeof(float) + 3 * sizeof(byte); - device.UpdateBuffer(vertexBuffer, (uint)offset, alpha); + var offset = (boneI * RhombusVertexCount + vertexI) * 4 + 3; + device.UpdateBuffer(boneColorAttribute.DeviceBuffer, (uint)offset, alpha); } } diff --git a/zzre/materials/CommonStructs.cs b/zzre/materials/CommonStructs.cs deleted file mode 100644 index fdcdcaa4..00000000 --- a/zzre/materials/CommonStructs.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Numerics; -using System.Runtime.InteropServices; -using zzio; - -namespace zzre.materials; - -[StructLayout(LayoutKind.Sequential)] -public struct ColoredVertex -{ - public Vector3 pos; - public IColor color; - public static uint Stride = 3 * sizeof(float) + 4 * sizeof(byte); - - public ColoredVertex(Vector3 pos, IColor color) - { - this.pos = pos; - this.color = color; - } -} - -[StructLayout(LayoutKind.Sequential)] -public struct SkinVertex -{ - public Vector4 weights; - public byte bone0, bone1, bone2, bone3; - public static uint Stride = 4 * sizeof(float) + 4 * sizeof(byte); -} diff --git a/zzre/materials/DebugMaterial.cs b/zzre/materials/DebugMaterial.cs index e797d42f..0a96bd25 100644 --- a/zzre/materials/DebugMaterial.cs +++ b/zzre/materials/DebugMaterial.cs @@ -1,10 +1,32 @@ using System.Numerics; +using System.Runtime.InteropServices; using Veldrid; using zzio; using zzre.rendering; namespace zzre.materials; +public struct ColoredVertex +{ + public Vector3 pos; + public IColor color; + + public ColoredVertex(Vector3 pos, IColor color) + { + this.pos = pos; + this.color = color; + } + + public static uint Stride = sizeof(float) * 3 + sizeof(uint); +} + +public struct SkinVertex +{ + public Vector4 weights; + public byte bone0, bone1, bone2, bone3; +} + + public class DebugMaterial : MlangMaterial, IStandardTransformMaterial { public enum ColorMode : uint diff --git a/zzre/rendering/ClumpMesh.cs b/zzre/rendering/ClumpMesh.cs index b36d39ca..13f461b7 100644 --- a/zzre/rendering/ClumpMesh.cs +++ b/zzre/rendering/ClumpMesh.cs @@ -10,7 +10,7 @@ namespace zzre.rendering; -public class ClumpMesh : Mesh +public class ClumpMesh : StaticMesh { public RWGeometry Geometry { get; } public RWSkinPLG? Skin { get; } diff --git a/zzre/rendering/WorldMesh.cs b/zzre/rendering/WorldMesh.cs index 9a12328e..a104d712 100644 --- a/zzre/rendering/WorldMesh.cs +++ b/zzre/rendering/WorldMesh.cs @@ -12,7 +12,7 @@ namespace zzre.rendering; -public class WorldMesh : Mesh +public class WorldMesh : StaticMesh { public abstract class BaseSection {