From e91012bd126b772bcbf5a755a8725b6164b70368 Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:47:38 +0100 Subject: [PATCH] Fixed Cube planes being mapped out of bound --- PCK-Studio/PckStudio.csproj | 1 + PCK-Studio/Rendering/CubeData.cs | 296 ++++++++++++++++++++++++ PCK-Studio/Rendering/CubeRenderGroup.cs | 177 +++----------- PCK-Studio/Rendering/SkinRenderer.cs | 7 +- 4 files changed, 335 insertions(+), 146 deletions(-) create mode 100644 PCK-Studio/Rendering/CubeData.cs diff --git a/PCK-Studio/PckStudio.csproj b/PCK-Studio/PckStudio.csproj index fe909545..d213516b 100644 --- a/PCK-Studio/PckStudio.csproj +++ b/PCK-Studio/PckStudio.csproj @@ -149,6 +149,7 @@ Resources.resx + diff --git a/PCK-Studio/Rendering/CubeData.cs b/PCK-Studio/Rendering/CubeData.cs new file mode 100644 index 00000000..d6eda8b6 --- /dev/null +++ b/PCK-Studio/Rendering/CubeData.cs @@ -0,0 +1,296 @@ +/* Copyright (c) 2023-present miku-666 + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1.The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +**/ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using OpenTK; + +namespace PckStudio.Rendering +{ + internal class CubeData + { + internal delegate void RefAction(ref T val); + + internal const int vertexCountPerCube = 24; + + internal bool ShouldRender { get; set; } = true; + + internal Vector3 Position + { + get => _position; + set + { + if (_position != value) + { + _position = value; + UpdateVertices(); + } + } + } + + internal Vector3 Size + { + get => _size; + set + { + if (_size != value) + { + _size = value; + UpdateVertices(); + } + } + } + + internal Vector2 Uv + { + get => _uv; + set + { + if (_uv != value) + { + _uv = value; + UpdateVertices(); + } + } + } + + internal float Scale + { + get => _scale; + set + { + if (_scale != value) + { + _scale = value; + UpdateVertices(); + } + } + } + + internal bool MirrorTexture + { + get => _mirrorTexture; + set + { + if (_mirrorTexture != value) + { + _mirrorTexture = value; + UpdateVertices(); + } + } + } + + internal bool FlipZMapping + { + get => _flipZMapping; + set + { + if (_flipZMapping != value) + { + _flipZMapping = value; + UpdateVertices(); + } + } + } + + private void UpdateVertices() + { + vertices = GetCubeVertexData(Position, Size, Uv, Scale, MirrorTexture, FlipZMapping); + } + + private Vector3 _position = Vector3.Zero; + private Vector3 _size = Vector3.One; + private Vector2 _uv = Vector2.Zero; + private float _scale = 1f; + private bool _mirrorTexture = false; + private bool _flipZMapping = false; + + private static uint[] indicesData = [ + // Face 1 (Back) + 0, 1, 2, 3, + // Face 2 (Front) + 4, 5, 6, 7, + // Face 3 (Top) + 8, 9, 10, 11, + // Face 4 (Bottom) + 12, 13, 14, 15, + // Face 5 (Left) + 16, 17, 18, 19, + // Face 6 (Right) + 20, 21, 22, 23, + ]; + + private TextureVertex[] vertices; + + /// + /// + /// + /// + /// + /// + /// + /// + /// Flips the bottom face mapping of the uv mapping + public CubeData(bool enabled, Vector3 position, Vector3 size, Vector2 uv, float scale, bool mirrorTexture, bool flipZMapping) + { + ShouldRender = enabled; + Position = position; + Size = size; + Uv = uv; + Scale = scale; + MirrorTexture = mirrorTexture; + FlipZMapping = flipZMapping; + UpdateVertices(); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// Flips the bottom face mapping of the uv mapping + public CubeData(Vector3 position, Vector3 size, Vector2 uv, float scale, bool mirrorTexture, bool flipZMapping) + : this(true, position, size, uv, scale, mirrorTexture, flipZMapping) + { + } + + internal enum CubeFace + { + Back, + Front, + Top, + Bottom, + Left, + Right, + } + + private static TextureVertex[] GetCubeVertexData(Vector3 position, Vector3 size, Vector2 uv, float scale, + bool mirrorTexture, bool flipZMapping) + { + int mirror = mirrorTexture ? 1 : 0; + List vertices = new List(); + + var back = new TextureVertex[] + { + // Back + new TextureVertex(new Vector3(position.X, size.Y + position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z * 2 + size.X + size.X * (1 - mirror), uv.Y + size.Z + size.Y), scale), + new TextureVertex(new Vector3(size.X + position.X, size.Y + position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z * 2 + size.X + size.X * mirror, uv.Y + size.Z + size.Y), scale), + new TextureVertex(new Vector3(size.X + position.X, position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z * 2 + size.X + size.X * mirror, uv.Y + size.Z), scale), + new TextureVertex(new Vector3(position.X, position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z * 2 + size.X + size.X * (1 - mirror), uv.Y + size.Z), scale) + }; + var front = new TextureVertex[] + { + // Front + new TextureVertex(new Vector3(position.X, size.Y + position.Y, position.Z), new Vector2(uv.X + size.Z + size.X * mirror, uv.Y + size.Z + size.Y), scale), + new TextureVertex(new Vector3(size.X + position.X, size.Y + position.Y, position.Z), new Vector2(uv.X + size.Z + size.X * (1 - mirror), uv.Y + size.Z + size.Y), scale), + new TextureVertex(new Vector3(size.X + position.X, position.Y, position.Z), new Vector2(uv.X + size.Z + size.X * (1 - mirror), uv.Y + size.Z), scale), + new TextureVertex(new Vector3(position.X, position.Y, position.Z), new Vector2(uv.X + size.Z + size.X * mirror, uv.Y + size.Z), scale), + }; + var top = new TextureVertex[] + { + // Top + new TextureVertex(new Vector3(position.X, position.Y, position.Z), new Vector2(uv.X + size.Z + size.X * mirror, uv.Y + size.Z), scale), + new TextureVertex(new Vector3(position.X, position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z + size.X * mirror, uv.Y), scale), + new TextureVertex(new Vector3(size.X + position.X, position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z + size.X * (1 - mirror), uv.Y), scale), + new TextureVertex(new Vector3(size.X + position.X, position.Y, position.Z), new Vector2(uv.X + size.Z + size.X * (1 - mirror), uv.Y + size.Z), scale), + }; + var bottom = new TextureVertex[] + { + // Bottom + new TextureVertex(new Vector3(position.X + size.X, size.Y + position.Y, position.Z), new Vector2(uv.X + size.Z + size.X + size.X * (1 - mirror), uv.Y + (flipZMapping ? size.Z : 0)), scale), + new TextureVertex(new Vector3(position.X + size.X, size.Y + position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z + size.X + size.X * (1 - mirror), uv.Y + (!flipZMapping ? size.Z : 0)), scale), + new TextureVertex(new Vector3(position.X, size.Y + position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z + size.X + size.X * mirror, uv.Y + (!flipZMapping ? size.Z : 0)), scale), + new TextureVertex(new Vector3(position.X, size.Y + position.Y, position.Z), new Vector2(uv.X + size.Z + size.X + size.X * mirror, uv.Y + (flipZMapping ? size.Z : 0)), scale), + }; + var left = new TextureVertex[] + { + // Left + new TextureVertex(new Vector3((1 - mirror) * size.X + position.X, position.Y, position.Z), new Vector2(uv.X + size.X + size.Z, uv.Y + size.Z), scale), + new TextureVertex(new Vector3((1 - mirror) * size.X + position.X, size.Y + position.Y, position.Z), new Vector2(uv.X + size.X + size.Z, uv.Y + size.Z + size.Y), scale), + new TextureVertex(new Vector3((1 - mirror) * size.X + position.X, size.Y + position.Y, size.Z + position.Z), new Vector2(uv.X + size.X + size.Z * 2, uv.Y + size.Z + size.Y), scale), + new TextureVertex(new Vector3((1 - mirror) * size.X + position.X, position.Y, size.Z + position.Z), new Vector2(uv.X + size.X + size.Z * 2, uv.Y + size.Z), scale), + }; + var right = new TextureVertex[] + { + // Right + new TextureVertex(new Vector3(mirror * size.X + position.X, position.Y, position.Z), new Vector2(uv.X + size.Z, uv.Y + size.Z), scale), + new TextureVertex(new Vector3(mirror * size.X + position.X, size.Y + position.Y, position.Z), new Vector2(uv.X + size.Z, uv.Y + size.Z + size.Y), scale), + new TextureVertex(new Vector3(mirror * size.X + position.X, size.Y + position.Y, size.Z + position.Z), new Vector2(uv.X, uv.Y + size.Z + size.Y), scale), + new TextureVertex(new Vector3(mirror * size.X + position.X, position.Y, size.Z + position.Z), new Vector2(uv.X, uv.Y + size.Z), scale), + }; + + vertices.AddRange(back); + vertices.AddRange(front); + vertices.AddRange(top); + vertices.AddRange(bottom); + vertices.AddRange(left); + vertices.AddRange(right); + + return vertices.ToArray(); + } + + internal TextureVertex[] GetVertices() + { + return vertices; + } + + internal Vector2[] GetMappedFaceTextureUv(CubeFace face) + { + var indices = GetIndices(); + var faceInices = indices.Skip((int)face * 4).Take(4).ToArray(); + var vertices = GetVertices(); + var uv0 = vertices[faceInices[0]].TexPosition; + var uv1 = vertices[faceInices[1]].TexPosition; + var uv2 = vertices[faceInices[2]].TexPosition; + var uv3 = vertices[faceInices[3]].TexPosition; + return [uv0, uv1, uv2, uv3]; + } + + internal uint[] GetIndices() + { + return indicesData; + } + + internal void SetFaceUv(CubeFace face, RefAction refAction) + { + var indices = GetIndices(); + var faceInices = indices.Skip((int)face * 4).Take(4).ToArray(); + var vertices = GetVertices(); + var uv0 = vertices[faceInices[0]].TexPosition; + refAction(ref uv0); + vertices[faceInices[0]].TexPosition = uv0; + + var uv1 = vertices[faceInices[1]].TexPosition; + refAction(ref uv1); + vertices[faceInices[1]].TexPosition = uv1; + + var uv2 = vertices[faceInices[2]].TexPosition; + refAction(ref uv2); + vertices[faceInices[2]].TexPosition = uv2; + + var uv3 = vertices[faceInices[3]].TexPosition; + refAction(ref uv3); + vertices[faceInices[3]].TexPosition = uv3; + } + } +} \ No newline at end of file diff --git a/PCK-Studio/Rendering/CubeRenderGroup.cs b/PCK-Studio/Rendering/CubeRenderGroup.cs index c94a1a55..a4260e63 100644 --- a/PCK-Studio/Rendering/CubeRenderGroup.cs +++ b/PCK-Studio/Rendering/CubeRenderGroup.cs @@ -29,148 +29,6 @@ namespace PckStudio.Rendering { internal class CubeRenderGroup : RenderGroup { - - private class CubeData - { - internal const int vertexCountPerCube = 24; - internal bool Enabled { get; set; } = true; - internal Vector3 Position { get; set; } = Vector3.Zero; - internal Vector3 Size { get; set; } = Vector3.One; - internal Vector2 Uv { get; set; } = Vector2.Zero; - internal float Scale { get; set; } = 1f; - internal bool MirrorTexture { get; set; } = false; - internal bool FlipZMapping { get; set; } = false; - - private static uint[] indicesData = new uint[] { - // Face 1 (Back) - 0, 1, 2, 3, - // Face 2 (Front) - 4, 5, 6, 7, - // Face 3 (Top) - 8, 9, 10, 11, - // Face 4 (Bottom) - 12, 13, 14, 15, - // Face 5 (Left) - 16, 17, 18, 19, - // Face 6 (Right) - 20, 21, 22, 23, - }; - - /// - /// - /// - /// - /// - /// - /// - /// - /// Flips the bottom face mapping of the uv mapping - public CubeData(bool enabled, Vector3 position, Vector3 size, Vector2 uv, float scale, bool mirrorTexture, bool flipZMapping) - { - Enabled = enabled; - Position = position; - Size = size; - Uv = uv; - Scale = scale; - MirrorTexture = mirrorTexture; - FlipZMapping = flipZMapping; - } - - /// - /// - /// - /// - /// - /// - /// - /// - /// Flips the bottom face mapping of the uv mapping - public CubeData(Vector3 position, Vector3 size, Vector2 uv, float scale, bool mirrorTexture, bool flipZMapping) - : this(true, position, size, uv, scale, mirrorTexture, flipZMapping) - { - } - - internal enum CubeFace - { - Back, - Front, - Top, - Bottom, - Left, - Right, - } - - internal static TextureVertex[] GetCubeVertexData(Vector3 position, Vector3 size, Vector2 uv, float scale = 1f, bool mirrorTexture = false, bool flipZMapping = false) - { - int mirror = mirrorTexture ? 1 : 0; - return - [ - // Back - new TextureVertex(new Vector3(position.X , size.Y + position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z * 2 + size.X + size.X * (1 - mirror), uv.Y + size.Z + size.Y), scale), - new TextureVertex(new Vector3(size.X + position.X, size.Y + position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z * 2 + size.X + size.X * mirror , uv.Y + size.Z + size.Y), scale), - new TextureVertex(new Vector3(size.X + position.X, position.Y , size.Z + position.Z), new Vector2(uv.X + size.Z * 2 + size.X + size.X * mirror , uv.Y + size.Z ), scale), - new TextureVertex(new Vector3(position.X , position.Y , size.Z + position.Z), new Vector2(uv.X + size.Z * 2 + size.X + size.X * (1 - mirror), uv.Y + size.Z ), scale), - - // Front - new TextureVertex(new Vector3(position.X , size.Y + position.Y, position.Z), new Vector2(uv.X + size.Z + size.X * mirror , uv.Y + size.Z + size.Y), scale), - new TextureVertex(new Vector3(size.X + position.X, size.Y + position.Y, position.Z), new Vector2(uv.X + size.Z + size.X * (1 - mirror), uv.Y + size.Z + size.Y), scale), - new TextureVertex(new Vector3(size.X + position.X, position.Y , position.Z), new Vector2(uv.X + size.Z + size.X * (1 - mirror), uv.Y + size.Z ), scale), - new TextureVertex(new Vector3(position.X , position.Y , position.Z), new Vector2(uv.X + size.Z + size.X * mirror , uv.Y + size.Z ), scale), - - // Top - new TextureVertex(new Vector3(position.X , position.Y, position.Z), new Vector2(uv.X + size.Z + size.X * mirror , uv.Y + size.Z), scale), - new TextureVertex(new Vector3(position.X , position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z + size.X * mirror , uv.Y ), scale), - new TextureVertex(new Vector3(size.X + position.X, position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z + size.X * (1 - mirror), uv.Y ), scale), - new TextureVertex(new Vector3(size.X + position.X, position.Y, position.Z), new Vector2(uv.X + size.Z + size.X * (1 - mirror), uv.Y + size.Z), scale), - - // Bottom - new TextureVertex(new Vector3(position.X + size.X, size.Y + position.Y, position.Z ), new Vector2(uv.X + size.Z + size.X + size.X * (1 - mirror), uv.Y + ( flipZMapping ? size.Z : 0)), scale), - new TextureVertex(new Vector3(position.X + size.X, size.Y + position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z + size.X + size.X * (1 - mirror), uv.Y + (!flipZMapping ? size.Z : 0)), scale), - new TextureVertex(new Vector3(position.X , size.Y + position.Y, size.Z + position.Z), new Vector2(uv.X + size.Z + size.X + size.X * mirror , uv.Y + (!flipZMapping ? size.Z : 0)), scale), - new TextureVertex(new Vector3(position.X , size.Y + position.Y, position.Z ), new Vector2(uv.X + size.Z + size.X + size.X * mirror , uv.Y + ( flipZMapping ? size.Z : 0)), scale), - - // Left - new TextureVertex(new Vector3((1 - mirror) * size.X + position.X, position.Y , position.Z ), new Vector2(uv.X + size.X + size.Z , uv.Y + size.Z ), scale), - new TextureVertex(new Vector3((1 - mirror) * size.X + position.X, size.Y + position.Y, position.Z ), new Vector2(uv.X + size.X + size.Z , uv.Y + size.Z + size.Y), scale), - new TextureVertex(new Vector3((1 - mirror) * size.X + position.X, size.Y + position.Y, size.Z + position.Z), new Vector2(uv.X + size.X + size.Z * 2, uv.Y + size.Z + size.Y), scale), - new TextureVertex(new Vector3((1 - mirror) * size.X + position.X, position.Y , size.Z + position.Z), new Vector2(uv.X + size.X + size.Z * 2, uv.Y + size.Z ), scale), - - // Right - new TextureVertex(new Vector3(mirror * size.X + position.X, position.Y , position.Z ), new Vector2(uv.X + size.Z, uv.Y + size.Z ), scale), - new TextureVertex(new Vector3(mirror * size.X + position.X, size.Y + position.Y, position.Z ), new Vector2(uv.X + size.Z, uv.Y + size.Z + size.Y), scale), - new TextureVertex(new Vector3(mirror * size.X + position.X, size.Y + position.Y, size.Z + position.Z), new Vector2(uv.X , uv.Y + size.Z + size.Y), scale), - new TextureVertex(new Vector3(mirror * size.X + position.X, position.Y , size.Z + position.Z), new Vector2(uv.X , uv.Y + size.Z ), scale), - ]; - } - - internal TextureVertex[] GetVertices() - { - return GetCubeVertexData(Position, Size, Uv, Scale, MirrorTexture, FlipZMapping); - } - - [Conditional("DEBUG")] - internal void GetMappedTextureUv(CubeFace face) - { - var indices = GetIndices(); - var faceInices = indices.Skip((int)face * 4).Take(4).ToArray(); - var vertices = GetVertices(); - var uv0 = vertices[faceInices[0]].TexPosition; - var uv1 = vertices[faceInices[1]].TexPosition; - var uv2 = vertices[faceInices[2]].TexPosition; - var uv3 = vertices[faceInices[3]].TexPosition; - Debug.WriteLine("----------"); - Debug.WriteLine(uv0); - Debug.WriteLine(uv1); - Debug.WriteLine(uv2); - Debug.WriteLine(uv3); - } - - internal uint[] GetIndices() - { - return indicesData; - } - } - private List cubes; internal CubeRenderGroup(string name) : base(name, PrimitiveType.Quads) @@ -197,7 +55,7 @@ namespace PckStudio.Rendering ResetBuffers(); foreach (var cube in cubes) { - if (!cube.Enabled) + if (!cube.ShouldRender) continue; vertices.AddRange(cube.GetVertices()); @@ -207,11 +65,24 @@ namespace PckStudio.Rendering } } + private void CheckAndFixUVFaveMapping(CubeData cube, CubeData.CubeFace face, Size textureSize) + { + if (cube.GetMappedFaceTextureUv(face).All(texVert => texVert.X >= textureSize.Width)) + { + CubeData.RefAction fixUV = (ref Vector2 uv) => + { + Debug.Write($"Old: {uv}; "); + uv.X %= textureSize.Width; + Debug.WriteLine($"Old: {uv};"); + }; + cube.SetFaceUv(face, fixUV); + } + } + internal void AddCube(Vector3 position, Vector3 size, Vector2 uv, float scale = 1f, bool mirrorTexture = false, bool flipZMapping = false) { var cube = new CubeData(position, size, uv, scale, mirrorTexture, flipZMapping); cubes.Add(cube); - //cube.GetMappedTextureUv(CubeData.CubeFace.Right); } internal void ReplaceCube(int index, Vector3 position, Vector3 size, Vector2 uv, float scale = 1f, bool mirrorTexture = false) @@ -233,8 +104,24 @@ namespace PckStudio.Rendering if (!cubes.IndexInRange(index)) throw new IndexOutOfRangeException(); - cubes[index].Enabled = enable; + cubes[index].ShouldRender = enable; Submit(); } + + internal void Validate(Size textureSize) + { + if (!textureSize.IsEmpty) + { + foreach (var cube in cubes) + { + CheckAndFixUVFaveMapping(cube, CubeData.CubeFace.Back, textureSize); + CheckAndFixUVFaveMapping(cube, CubeData.CubeFace.Front, textureSize); + CheckAndFixUVFaveMapping(cube, CubeData.CubeFace.Top, textureSize); + CheckAndFixUVFaveMapping(cube, CubeData.CubeFace.Bottom, textureSize); + CheckAndFixUVFaveMapping(cube, CubeData.CubeFace.Left, textureSize); + CheckAndFixUVFaveMapping(cube, CubeData.CubeFace.Right, textureSize); + } + } + } } } diff --git a/PCK-Studio/Rendering/SkinRenderer.cs b/PCK-Studio/Rendering/SkinRenderer.cs index 44055117..570144d1 100644 --- a/PCK-Studio/Rendering/SkinRenderer.cs +++ b/PCK-Studio/Rendering/SkinRenderer.cs @@ -100,6 +100,7 @@ namespace PckStudio.Rendering } private Vector2 UvTranslation = new Vector2(1f / 64); + private Size TextureSize = new Size(64, 64); private const float OverlayScale = 1.12f; private bool _IsLeftMouseDown; @@ -111,6 +112,7 @@ namespace PckStudio.Rendering { if (HasValidContext && _skinShader is not null) { + TextureSize = value.Size; UvTranslation = value.Width == value.Height ? new Vector2(1f / 64) : new Vector2(1f / 64, 1f / 32); var texture = new Texture2D(value); texture.Bind(0); @@ -263,7 +265,10 @@ namespace PckStudio.Rendering if (!additionalModelRenderGroups.ContainsKey(skinBox.Type)) throw new KeyNotFoundException(skinBox.Type); - additionalModelRenderGroups[skinBox.Type].AddSkinBox(skinBox); + CubeRenderGroup group = additionalModelRenderGroups[skinBox.Type]; + group.AddSkinBox(skinBox); + group.Validate(TextureSize); + group.Submit(); } [Conditional("DEBUG")]