From a5bd118e1c94345284f9d2915a5b364693aab8f3 Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Fri, 8 Mar 2024 19:14:41 +0100 Subject: [PATCH] SkinRenderer - Add Cape rendering --- .../Extensions/PckFileDataExtensions.cs | 4 +- PCK-Studio/Forms/Editor/CustomSkinEditor.cs | 4 +- PCK-Studio/MainForm.cs | 12 ++- PCK-Studio/Rendering/SkinRenderer.cs | 75 ++++++++++++++++++- 4 files changed, 87 insertions(+), 8 deletions(-) diff --git a/PCK-Studio/Extensions/PckFileDataExtensions.cs b/PCK-Studio/Extensions/PckFileDataExtensions.cs index 5adaa1b0..08f71957 100644 --- a/PCK-Studio/Extensions/PckFileDataExtensions.cs +++ b/PCK-Studio/Extensions/PckFileDataExtensions.cs @@ -73,8 +73,8 @@ namespace PckStudio.Extensions if (file.Filetype != PckFileType.SkinFile) throw new InvalidOperationException("File is not a skin file"); - if (file.Properties.Contains("CAPEPATH")) - Debug.WriteLine($"[{nameof(GetSkin)}] TODO: add cape texture/path."); + //if (file.Properties.Contains("CAPEPATH")) + // Debug.WriteLine($"[{nameof(GetSkin)}] TODO: add cape texture/path."); int skinId = file.GetSkinId(); diff --git a/PCK-Studio/Forms/Editor/CustomSkinEditor.cs b/PCK-Studio/Forms/Editor/CustomSkinEditor.cs index 67f85296..2da4efd7 100644 --- a/PCK-Studio/Forms/Editor/CustomSkinEditor.cs +++ b/PCK-Studio/Forms/Editor/CustomSkinEditor.cs @@ -68,10 +68,12 @@ namespace PckStudio.Forms.Editor private void LoadModelData() { + skinNameLabel.Text = _skin.Name; var boxProperties = _skin.AdditionalBoxes; var offsetProperties = _skin.PartOffsets; - skinNameLabel.Text = _skin.Name; + if (_skin.HasCape) + renderer3D1.CapeTexture = _skin.CapeTexture; foreach (SkinBOX box in boxProperties) { diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index 301817ba..c3d8a191 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -432,7 +432,17 @@ namespace PckStudio public void HandleSkinFile(PckFileData file) { - using CustomSkinEditor skinEditor = new CustomSkinEditor(file.GetSkin()); + var skin = file.GetSkin(); + if (file.Properties.Contains("CAPEPATH")) + { + string capePath = file.Properties.GetPropertyValue("CAPEPATH"); + if (currentPCK.TryGetFile(capePath, PckFileType.CapeFile, out var cape)) + { + skin.CapeTexture = cape.GetTexture(); + } + } + + using CustomSkinEditor skinEditor = new CustomSkinEditor(skin, currentPCK.HasVerionString); if (skinEditor.ShowDialog() == DialogResult.OK) { if (!TryGetLocFile(out var locFile)) diff --git a/PCK-Studio/Rendering/SkinRenderer.cs b/PCK-Studio/Rendering/SkinRenderer.cs index f73773dd..ddef0521 100644 --- a/PCK-Studio/Rendering/SkinRenderer.cs +++ b/PCK-Studio/Rendering/SkinRenderer.cs @@ -44,11 +44,11 @@ namespace PckStudio.Rendering /// The visible Texture on the renderer /// /// The visible Texture - [Description("The current Texture")] + [Description("The current skin texture")] [Category("Appearance")] public Image Texture { - get => _texture; + get => _skinImage; set { var args = new TextureChangingEventArgs(value); @@ -56,12 +56,29 @@ namespace PckStudio.Rendering OnTextureChanging(this, args); if (!args.Cancel) { - _texture = value; + _skinImage = value; TextureSize = value.Width == value.Height ? new Size(64, 64) : new Size(64, 32); } } } + [Description("The current cape texture")] + [Category("Appearance")] + public Image CapeTexture + { + get => _capeImage; + set + { + var args = new TextureChangingEventArgs(value); + Events[nameof(CapeTextureChanging)]?.DynamicInvoke(this, args); + OnCapeTextureChanging(this, args); + if (!args.Cancel) + { + _capeImage = value; + } + } + } + [Description("The Color used for outlines")] [Category("Appearance")] public Color OutlineColor { get; set; } @@ -94,6 +111,15 @@ namespace PckStudio.Rendering remove => Events.RemoveHandler(nameof(TextureChanging), value); } + [Description("Event that gets fired when the Texture is changing")] + [Category("Property Chnaged")] + [Browsable(true)] + public event EventHandler CapeTextureChanging + { + add => Events.AddHandler(nameof(CapeTextureChanging), value); + remove => Events.RemoveHandler(nameof(CapeTextureChanging), value); + } + [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public SkinANIM ANIM @@ -163,8 +189,10 @@ namespace PckStudio.Rendering private ShaderLibrary _shaders; private SkinANIM _anim; - private Image _texture; + private Image _skinImage; + private Image _capeImage; private Texture2D skinTexture; + private Texture2D capeTexture; private Texture2D armorTexture; #if USE_FRAMEBUFFER @@ -185,6 +213,8 @@ namespace PckStudio.Rendering private Dictionary meshStorage; private Dictionary offsetSpecificMeshStorage; + private CubeGroupMesh cape; + private CubeGroupMesh head; private CubeGroupMesh body; private CubeGroupMesh rightArm; @@ -230,6 +260,7 @@ namespace PckStudio.Rendering public SkinRenderer() : base() { InitializeSkinData(); + InitializeCapeData(); meshStorage = new Dictionary() { { "HEAD", head }, @@ -279,6 +310,8 @@ namespace PckStudio.Rendering cubeMesh.Initialize(layout); cubeMesh.UploadData(); } + cape.Initialize(layout); + cape.UploadData(); GLErrorCheck(); base.Init(); GLErrorCheck(); @@ -327,6 +360,12 @@ namespace PckStudio.Rendering leftLeg.AddCube(new(-2, 0, -2), new(4, 12, 4), new(0, 48), OverlayScale); } + private void InitializeCapeData() + { + cape ??= new CubeGroupMesh("Cape"); + cape.AddCube(new(-5, 0, -3), new(10, 16, 1), new(0, 0)); + } + private void InitializeArmorData() { const float armorInflation = 0.75f; @@ -417,6 +456,15 @@ namespace PckStudio.Rendering armorTexture.SetTexture(Resources.armor); GLErrorCheck(); + capeTexture = new Texture2D(0); + capeTexture.PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Bgra; + capeTexture.InternalPixelFormat = PixelInternalFormat.Rgba8; + capeTexture.MinFilter = TextureMinFilter.Nearest; + capeTexture.MagFilter = TextureMagFilter.Nearest; + capeTexture.WrapS = TextureWrapMode.Repeat; + capeTexture.WrapT = TextureWrapMode.Repeat; + GLErrorCheck(); + skinTexture = new Texture2D(0); skinTexture.PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Bgra; skinTexture.InternalPixelFormat = PixelInternalFormat.Rgba8; @@ -631,6 +679,17 @@ namespace PckStudio.Rendering GLErrorCheck(); } + protected virtual void OnCapeTextureChanging(object sender, TextureChangingEventArgs e) + { + if (e.NewTexture is null) + e.Cancel = true; + + if (e.Cancel) + return; + capeTexture.SetTexture(e.NewTexture); + GLErrorCheck(); + } + [Conditional("USE_FRAMEBUFFER")] private void InitializeFramebuffer() { @@ -982,6 +1041,14 @@ namespace PckStudio.Rendering RenderBodyPart(skinShader, legRightMatrix, transform, "LEG0", "PANTS0"); RenderBodyPart(skinShader, legLeftMatrix, transform, "LEG1", "PANTS1"); + if (_capeImage is not null) + { + skinShader.SetUniform2("u_TexSize", new Vector2(64, 32)); + capeTexture.Bind(); + Matrix4 partMatrix = Matrix4.CreateRotationY(MathHelper.DegreesToRadians(180f)) * Matrix4.CreateRotationX(MathHelper.DegreesToRadians((float)Math.Sin(Math.Abs(animationCurrentRotationAngle) * 0.25f) * 10f)); + RenderPart(skinShader, cape, partMatrix, transform); + } + // Armor rendering if (ShowArmor) {