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)
{