diff --git a/PCK-Studio/App.config b/PCK-Studio/App.config index c3b1b2f6..732c8327 100644 --- a/PCK-Studio/App.config +++ b/PCK-Studio/App.config @@ -77,6 +77,9 @@ False + + True + diff --git a/PCK-Studio/Classes/Models/BackgroundTypes.cs b/PCK-Studio/Classes/Models/BackgroundTypes.cs deleted file mode 100644 index b460d046..00000000 --- a/PCK-Studio/Classes/Models/BackgroundTypes.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace PckStudio.Models -{ - public enum BackgroundTypes - { - Color, - Gradient, - Texture - } -} diff --git a/PCK-Studio/Classes/Models/Backgrounds.cs b/PCK-Studio/Classes/Models/Backgrounds.cs deleted file mode 100644 index 692896bc..00000000 --- a/PCK-Studio/Classes/Models/Backgrounds.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace PckStudio.Models -{ - public enum Backgrounds - { - LightStone, - DarkStone, - DaySky, - NightSky, - Sunset, - Transparent - } -} diff --git a/PCK-Studio/Classes/Models/Box.cs b/PCK-Studio/Classes/Models/Box.cs deleted file mode 100644 index 23d64a9d..00000000 --- a/PCK-Studio/Classes/Models/Box.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System; -using System.Drawing; - -namespace PckStudio.Models -{ - public class Box : Object3D - { - public override Image Image - { - set - { - SetImage(value); - } - } - - internal override MinecraftModelView Viewport - { - set - { - base.Viewport = value; - top.Viewport = value; - bottom.Viewport = value; - front.Viewport = value; - back.Viewport = value; - left.Viewport = value; - right.Viewport = value; - Update(); - } - } - - internal override void Update() - { - Matrix3D a = globalTransformation * localTransformation; - top.LocalTransformation = a * topLocalTransformation; - bottom.LocalTransformation = a * bottomLocalTransformation; - front.LocalTransformation = a * frontLocalTransformation; - back.LocalTransformation = a * backLocalTransformation; - left.LocalTransformation = a * leftLocalTransformation; - right.LocalTransformation = a * rightLocalTransformation; - } - - public Box(Image image, Rectangle srcTopBottom, Rectangle srcSides, Point3D origin, Effects effects = Effects.None) - { - this.effects = effects; - Origin = origin; - SetImage(image, srcTopBottom, srcSides); - } - - private void SetImage(Image image, Rectangle srcTopBottom, Rectangle srcSides) - { - int num = srcTopBottom.Width / 2; - int height = srcSides.Height; - int height2 = srcTopBottom.Height; - srcTop = new Rectangle(srcTopBottom.Location, new Size(num, height2)); - srcBottom = new Rectangle(srcTopBottom.X + num, srcTopBottom.Y, num, height2); - srcFront = new Rectangle(srcSides.X + height2, srcSides.Y, num, height); - srcBack = new Rectangle(srcSides.X + height2 + num + height2, srcSides.Y, num, height); - srcLeft = new Rectangle(srcSides.Location, new Size(height2, height)); - srcRight = new Rectangle(srcSides.X + height2 + num, srcSides.Y, height2, height); - SetImage(image); - } - - private void SetImage(Image image) - { - bool flag = (byte)(effects & Effects.FlipHorizontally) == 1; - bool flag2 = (byte)(effects & Effects.FlipVertically) == 2; - int width = srcFront.Width; - int height = srcFront.Height; - int width2 = srcLeft.Width; - top = new TexturePlane(image, flag2 ? srcBottom : srcTop, new Point3D(width * 0.5f, width2 * 0.5f, (float)(-(float)height) * 0.5f), new Point3D(0f, 1f, 0f), effects & Effects.FlipHorizontally); - bottom = new TexturePlane(image, flag2 ? srcTop : srcBottom, new Point3D(width / 2f, width2 / 2f, height / 2f), new Point3D(0f, -1f, 0f), effects & Effects.FlipHorizontally); - front = new TexturePlane(image, srcFront, new Point3D(width * 0.5f, height * 0.5f, (float)(-(float)width2) * 0.5f), new Point3D(0f, 0f, 1f), effects); - back = new TexturePlane(image, srcBack, new Point3D(width * 0.5f, height * 0.5f, (float)(-(float)width2) * 0.5f), new Point3D(0f, 0f, -1f), effects); - left = new TexturePlane(image, flag ? srcRight : srcLeft, new Point3D(width2 * 0.5f, height * 0.5f, (float)(-(float)width) * 0.5f), new Point3D(-1f, 0f, 0f), effects); - right = new TexturePlane(image, flag ? srcLeft : srcRight, new Point3D(width2 * 0.5f, height * 0.5f, (float)(-(float)width) * 0.5f), new Point3D(1f, 0f, 0f), effects); - top.Viewport = viewport; - bottom.Viewport = viewport; - front.Viewport = viewport; - back.Viewport = viewport; - left.Viewport = viewport; - right.Viewport = viewport; - } - - public override float HitTest(PointF location) - { - float num = -1000f; - float num2 = top.HitTest(location); - if (num2 > num) - { - num = num2; - } - num2 = bottom.HitTest(location); - if (num2 > num) - { - num = num2; - } - num2 = front.HitTest(location); - if (num2 > num) - { - num = num2; - } - num2 = back.HitTest(location); - if (num2 > num) - { - num = num2; - } - num2 = left.HitTest(location); - if (num2 > num) - { - num = num2; - } - num2 = right.HitTest(location); - if (num2 > num) - { - num = num2; - } - return num; - } - - private TexturePlane top; - - private TexturePlane bottom; - - private TexturePlane front; - - private TexturePlane back; - - private TexturePlane left; - - private TexturePlane right; - - private Rectangle srcTop; - - private Rectangle srcBottom; - - private Rectangle srcFront; - - private Rectangle srcBack; - - private Rectangle srcLeft; - - private Rectangle srcRight; - - private Matrix3D topLocalTransformation = Matrix3D.CreateRotationX(-1.57079637f); - - private Matrix3D bottomLocalTransformation = Matrix3D.CreateRotationX(-1.57079637f); - - private Matrix3D frontLocalTransformation = Matrix3D.Identity; - - private Matrix3D backLocalTransformation = Matrix3D.CreateRotationY(3.14159274f); - - private Matrix3D leftLocalTransformation = Matrix3D.CreateRotationY(-1.57079637f); - - private Matrix3D rightLocalTransformation = Matrix3D.CreateRotationY(1.57079637f); - - private Effects effects; - } -} diff --git a/PCK-Studio/Classes/Models/DefaultModels/ModelBase.cs b/PCK-Studio/Classes/Models/DefaultModels/ModelBase.cs deleted file mode 100644 index 66a759c9..00000000 --- a/PCK-Studio/Classes/Models/DefaultModels/ModelBase.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using PckStudio.Models; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Drawing; - -namespace PckStudio.Models -{ - public abstract class ModelBase - { - public ModelBase() - { } - - protected Image[] textures; - - public EventHandler OnUpdate; - protected const float OverlayScale = 1.16f; - - public Image[] Textures => textures; - - public event EventHandler Updatedx - { - add - { - EventHandler eventHandler = OnUpdate; - EventHandler eventHandler2; - do - { - eventHandler2 = eventHandler; - EventHandler value2 = (EventHandler)Delegate.Combine(eventHandler2, value); - eventHandler = Interlocked.CompareExchange(ref OnUpdate, value2, eventHandler2); - } - while (eventHandler != eventHandler2); - } - remove - { - EventHandler eventHandler = OnUpdate; - EventHandler eventHandler2; - do - { - eventHandler2 = eventHandler; - EventHandler value2 = (EventHandler)Delegate.Remove(eventHandler2, value); - eventHandler = Interlocked.CompareExchange(ref OnUpdate, value2, eventHandler2); - } - while (eventHandler != eventHandler2); - } - } - - protected void OnUpdated() - { - if (OnUpdate != null) - { - OnUpdate(this, EventArgs.Empty); - } - } - - public abstract void AddToModelView(MinecraftModelView modelView); - } -} diff --git a/PCK-Studio/Classes/Models/DefaultModels/Steve64x32Model.cs b/PCK-Studio/Classes/Models/DefaultModels/Steve64x32Model.cs deleted file mode 100644 index 0af00dfc..00000000 --- a/PCK-Studio/Classes/Models/DefaultModels/Steve64x32Model.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.IO; -using System.Drawing; -using PckStudio.Models; -using PckStudio.Properties; - -namespace PckStudio.Models -{ - internal class Steve64x32Model : ModelBase - { - public Steve64x32Model(Image texture) - { - textures = new Image[1] { texture }; - } - - public override void AddToModelView(MinecraftModelView modelView) - { - _ = Textures[0] ?? throw new NullReferenceException(nameof(Textures)); - Image source = Textures[0]; - Box head = new Box(source, new Rectangle( 8, 0, 16, 8), new Rectangle( 0, 8, 32, 8), new Point3D(0f, 0f, 0f)); - Box headOverlay = new Box(source, new Rectangle(40, 0, 16, 8), new Rectangle(32, 8, 32, 8), new Point3D(0f, 0f, 0f)); - headOverlay.Scale = OverlayScale; - - Box body = new Box(source, new Rectangle(20, 16, 16, 4), new Rectangle(16, 20, 24, 12), new Point3D(0f, 0f, 0f)); - - Box leftArm = new Box(source, new Rectangle(44, 16, 8, 4), new Rectangle(40, 20, 32, 12), new Point3D(0f, 4f, 0f)); - Box rightArm = new Box(source, new Rectangle(44, 16, 8, 4), new Rectangle(40, 20, 32, 12), new Point3D(0f, 4f, 0f)); - - Box leftLeg = new Box(source, new Rectangle(4, 16, 8, 4), new Rectangle(0, 20, 16, 12), new Point3D(0f, 6f, 0f)); - Box rightLeg = new Box(source, new Rectangle(4, 16, 8, 4), new Rectangle(0, 20, 16, 12), new Point3D(0f, 6f, 0f)); - - Object3DGroup headGroup = new Object3DGroup(); - - headGroup.RotationOrder = RotationOrders.XY; - headGroup.MinDegrees1 = -80f; - headGroup.MaxDegrees1 = 80f; - - headGroup.MinDegrees2 = -57f; - headGroup.MaxDegrees2 = 57f; - - headGroup.Add(head); - headGroup.Add(headOverlay); - - headGroup.Position = new Point3D(0f, 8f, 0f); - headGroup.Origin = new Point3D(0f, -4f, 0f); - headGroup.RotationOrder = RotationOrders.XY; - - body.Position = new Point3D(0f, 2f, 0f); - - leftArm.Position = new Point3D(6f, 6f, 0f); - leftArm.RotationOrder = RotationOrders.ZX; - leftArm.MinDegrees1 = 0f; - leftArm.MaxDegrees1 = 160f; - leftArm.MinDegrees2 = -170f; - leftArm.MaxDegrees2 = 60f; - - rightArm.Position = new Point3D(-6f, 6f, 0f); - rightArm.RotationOrder = RotationOrders.ZX; - rightArm.MinDegrees1 = -160f; - rightArm.MaxDegrees1 = 0f; - rightArm.MinDegrees2 = -170f; - rightArm.MaxDegrees2 = 60f; - - leftLeg.Position = new Point3D(2f, -4f, 0f); - leftLeg.RotationOrder = RotationOrders.ZX; - leftLeg.MinDegrees1 = 0f; - leftLeg.MaxDegrees1 = 70f; - leftLeg.MinDegrees2 = -110f; - leftLeg.MaxDegrees2 = 60f; - - rightLeg.Position = new Point3D(-2f, -4f, 0f); - rightLeg.RotationOrder = RotationOrders.ZX; - rightLeg.MinDegrees1 = -70f; - rightLeg.MaxDegrees1 = 0f; - rightLeg.MinDegrees2 = -110f; - rightLeg.MaxDegrees2 = 60f; - - modelView.AddDynamic(headGroup); - modelView.AddStatic(body); - modelView.AddDynamic(rightArm); - modelView.AddDynamic(leftArm); - modelView.AddDynamic(rightLeg); - modelView.AddDynamic(leftLeg); - } - - public override string ToString() => nameof(Steve64x32Model); - } -} diff --git a/PCK-Studio/Classes/Models/DefaultModels/Steve64x64Model.cs b/PCK-Studio/Classes/Models/DefaultModels/Steve64x64Model.cs deleted file mode 100644 index e7442333..00000000 --- a/PCK-Studio/Classes/Models/DefaultModels/Steve64x64Model.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Security.Policy; -using System.Text; -using System.Threading.Tasks; -using PckStudio.Internal; -using PckStudio.Models; - -namespace PckStudio.Classes.Models.DefaultModels -{ - internal class Steve64x64Model : ModelBase - { - SkinANIM _skinANIM; - public Steve64x64Model(Image texture, SkinANIM anim) - { - textures = new Image[1] { texture }; - _skinANIM = anim; - } - - public override void AddToModelView(MinecraftModelView modelView) - { - _ = Textures[0] ?? throw new NullReferenceException(nameof(Textures)); - Image source = Textures[0]; - - (int top, int side) armWidth = _skinANIM.GetFlag(SkinAnimFlag.SLIM_MODEL) ? (6, 14) : (8, 16); - - Box head = new Box(source, new Rectangle(8, 0, 16, 8), new Rectangle(0, 8, 32, 8), new Point3D(0f, 0f, 0f)); - Box headOverlay = new Box(source, new Rectangle(40, 0, 16, 8), new Rectangle(32, 8, 32, 8), new Point3D(0f, 0f, 0f)); - headOverlay.Scale = OverlayScale; - - Box body = new Box(source, new Rectangle(20, 16, 16, 4), new Rectangle(16, 20, 24, 12), new Point3D(0f, 0f, 0f)); - Box bodyOverlay = new Box(source, new Rectangle(20, 32, 16, 4), new Rectangle(16, 36, 24, 12), new Point3D(0f, 0f, 0f)); - bodyOverlay.Scale = OverlayScale; - - Box rightArm = new Box(source, new Rectangle(44, 16, armWidth.top, 4), new Rectangle(40, 20, armWidth.side, 12), new Point3D(0f, 4f, 0f)); - Box rightArmOverlay = new Box(source, new Rectangle(44, 32, armWidth.top, 4), new Rectangle(40, 36, armWidth.side, 12), new Point3D(0f, 4f, 0f)); - rightArmOverlay.Scale = OverlayScale; - - Box leftArm = new Box(source, new Rectangle(36, 48, armWidth.top, 4), new Rectangle(32, 52, armWidth.side, 12), new Point3D(0f, 4f, 0f)); - Box leftArmOverlay = new Box(source, new Rectangle(52, 48, armWidth.top, 4), new Rectangle(48, 52, armWidth.side, 12), new Point3D(0f, 4f, 0f)); - leftArmOverlay.Scale = OverlayScale; - - Box rightLeg = new Box(source, new Rectangle(4, 16, 8, 4), new Rectangle(0, 20, 16, 12), new Point3D(0f, 6f, 0f)); - Box rightLegOverlay = new Box(source, new Rectangle(4, 32, 8, 4), new Rectangle(0, 52, 16, 12), new Point3D(0f, 6f, 0f)); - rightLegOverlay.Scale = OverlayScale; - - Box leftLeg = new Box(source, new Rectangle(20, 48, 8, 4), new Rectangle(16, 52, 16, 12), new Point3D(0f, 6f, 0f)); - Box leftLegOverlay = new Box(source, new Rectangle( 4, 48, 8, 4), new Rectangle( 0, 52, 16, 12), new Point3D(0f, 6f, 0f)); - leftLegOverlay.Scale = OverlayScale; - - Object3DGroup headGroup = new Object3DGroup(); - Object3DGroup bodyGroup = new Object3DGroup(); - Object3DGroup leftArmGroup = new Object3DGroup(); - Object3DGroup rightArmGroup = new Object3DGroup(); - Object3DGroup leftLegGroup = new Object3DGroup(); - Object3DGroup rightLegGroup = new Object3DGroup(); - - headGroup.RotationOrder = RotationOrders.XY; - headGroup.MinDegrees1 = -80f; - headGroup.MaxDegrees1 = 80f; - - headGroup.MinDegrees2 = -57f; - headGroup.MaxDegrees2 = 57f; - - headGroup.Origin = new Point3D(0f, -4f, 0f); - headGroup.RotationOrder = RotationOrders.XY; - - headGroup.Position = new Point3D(0f, 8f, 0f); - headGroup.Add(head); - headGroup.Add(headOverlay); - - bodyGroup.Position = new Point3D(0f, 2f, 0f); - bodyGroup.Add(body); - bodyGroup.Add(bodyOverlay); - - leftArmGroup.Position = new Point3D(6f, 6f, 0f); - leftArmGroup.RotationOrder = RotationOrders.ZX; - leftArmGroup.MinDegrees1 = 0f; - leftArmGroup.MaxDegrees1 = 160f; - leftArmGroup.MinDegrees2 = -170f; - leftArmGroup.MaxDegrees2 = 60f; - leftArmGroup.Add(leftArm); - leftArmGroup.Add(leftArmOverlay); - - rightArmGroup.Position = new Point3D(-6f, 6f, 0f); - rightArmGroup.RotationOrder = RotationOrders.ZX; - rightArmGroup.MinDegrees1 = -160f; - rightArmGroup.MaxDegrees1 = 0f; - rightArmGroup.MinDegrees2 = -170f; - rightArmGroup.MaxDegrees2 = 60f; - rightArmGroup.Add(rightArm); - rightArmGroup.Add(rightArmOverlay); - - leftLegGroup.Position = new Point3D(2f, -4f, 0f); - leftLegGroup.RotationOrder = RotationOrders.ZX; - leftLegGroup.MinDegrees1 = 0f; - leftLegGroup.MaxDegrees1 = 70f; - leftLegGroup.MinDegrees2 = -110f; - leftLegGroup.MaxDegrees2 = 60f; - leftLegGroup.Add(leftLeg); - leftLegGroup.Add(leftLegOverlay); - - rightLegGroup.Position = new Point3D(-2f, -4f, 0f); - rightLegGroup.RotationOrder = RotationOrders.ZX; - rightLegGroup.MinDegrees1 = -70f; - rightLegGroup.MaxDegrees1 = 0f; - rightLegGroup.MinDegrees2 = -110f; - rightLegGroup.MaxDegrees2 = 60f; - rightLegGroup.Add(rightLeg); - rightLegGroup.Add(rightLegOverlay); - - modelView.AddDynamic(headGroup); - modelView.AddStatic(bodyGroup); - modelView.AddDynamic(rightArmGroup); - modelView.AddDynamic(leftArmGroup); - modelView.AddDynamic(rightLegGroup); - modelView.AddDynamic(leftLegGroup); - } - } -} diff --git a/PCK-Studio/Classes/Models/Effects.cs b/PCK-Studio/Classes/Models/Effects.cs deleted file mode 100644 index 418101b2..00000000 --- a/PCK-Studio/Classes/Models/Effects.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace PckStudio.Models -{ - [Flags] - public enum Effects : byte - { - None = 0, - FlipHorizontally = 1, - FlipVertically = 2 - } -} diff --git a/PCK-Studio/Classes/Models/Matrix3D.cs b/PCK-Studio/Classes/Models/Matrix3D.cs deleted file mode 100644 index 071528dd..00000000 --- a/PCK-Studio/Classes/Models/Matrix3D.cs +++ /dev/null @@ -1,177 +0,0 @@ -using System; - -namespace PckStudio.Models -{ - public struct Matrix3D - { - public Matrix3D(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44) - { - M11 = m11; - M12 = m12; - M13 = m13; - M14 = m14; - M21 = m21; - M22 = m22; - M23 = m23; - M24 = m24; - M31 = m31; - M32 = m32; - M33 = m33; - M34 = m34; - M41 = m41; - M42 = m42; - M43 = m43; - M44 = m44; - } - - public static Matrix3D CreateRotationX(float radians) - { - float num = (float)Math.Sin((double)radians); - float num2 = (float)Math.Cos((double)radians); - return new Matrix3D(1f, 0f, 0f, 0f, 0f, num2, -num, 0f, 0f, num, num2, 0f, 0f, 0f, 0f, 1f); - } - - public static Matrix3D CreateRotationX(float sin, float cos) - { - return new Matrix3D(1f, 0f, 0f, 0f, 0f, cos, -sin, 0f, 0f, sin, cos, 0f, 0f, 0f, 0f, 1f); - } - - public static Matrix3D CreateRotationY(float radians) - { - float num = (float)Math.Sin((double)radians); - float num2 = (float)Math.Cos((double)radians); - return new Matrix3D(num2, 0f, num, 0f, 0f, 1f, 0f, 0f, -num, 0f, num2, 0f, 0f, 0f, 0f, 1f); - } - - public static Matrix3D CreateRotationY(float sin, float cos) - { - return new Matrix3D(cos, 0f, sin, 0f, 0f, 1f, 0f, 0f, -sin, 0f, cos, 0f, 0f, 0f, 0f, 1f); - } - - public static Matrix3D CreateRotationZ(float radians) - { - float num = (float)Math.Sin((double)radians); - float num2 = (float)Math.Cos((double)radians); - return new Matrix3D(num2, -num, 0f, 0f, num, num2, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f); - } - - public static Matrix3D CreateRotationZ(float sin, float cos) - { - return new Matrix3D(cos, -sin, 0f, 0f, sin, cos, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f); - } - - public static Matrix3D CreateTranslation(float x, float y, float z) - { - return new Matrix3D(1f, 0f, 0f, x, 0f, 1f, 0f, y, 0f, 0f, 1f, z, 0f, 0f, 0f, 1f); - } - - public static Matrix3D CreateTranslation(Point3D point) - { - return new Matrix3D(1f, 0f, 0f, point.X, 0f, 1f, 0f, point.Y, 0f, 0f, 1f, point.Z, 0f, 0f, 0f, 1f); - } - - public static Matrix3D CreateScale(float s) - { - return new Matrix3D(s, 0f, 0f, 0f, 0f, s, 0f, 0f, 0f, 0f, s, 0f, 0f, 0f, 0f, 1f); - } - - public float Determinant - { - get - { - return M11 * M22 * M33 * M44 + M21 * M32 * M43 * M14 + M31 * M42 * M13 * M24 + M41 * M12 * M23 * M34 - M14 * M23 * M32 * M41 - M24 * M33 * M42 * M11 - M34 * M43 * M12 * M21 - M44 * M13 * M22 * M31; - } - } - - public static Matrix3D Identity - { - get - { - return new Matrix3D(1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f); - } - } - - public static Matrix3D Transpose(Matrix3D m) - { - return new Matrix3D(m.M11, m.M21, m.M31, m.M41, m.M12, m.M22, m.M32, m.M42, m.M13, m.M23, m.M33, m.M43, m.M14, m.M24, m.M34, m.M44); - } - - public static Matrix3D Invert(Matrix3D m) - { - float determinant = m.Determinant; - return new Matrix3D((m.M22 * m.M33 * m.M44 + m.M32 * m.M43 * m.M24 + m.M42 * m.M23 * m.M34 - m.M24 * m.M33 * m.M42 - m.M34 * m.M43 * m.M22 - m.M44 * m.M23 * m.M32) / determinant, -(m.M12 * m.M33 * m.M44 + m.M32 * m.M43 * m.M14 + m.M42 * m.M13 * m.M34 - m.M14 * m.M33 * m.M42 - m.M34 * m.M43 * m.M12 - m.M44 * m.M13 * m.M32) / determinant, (m.M12 * m.M23 * m.M44 + m.M22 * m.M43 * m.M14 + m.M42 * m.M13 * m.M24 - m.M14 * m.M23 * m.M42 - m.M24 * m.M43 * m.M12 - m.M44 * m.M13 * m.M22) / determinant, -(m.M12 * m.M23 * m.M34 + m.M22 * m.M33 * m.M14 + m.M32 * m.M13 * m.M24 - m.M14 * m.M23 * m.M32 - m.M24 * m.M33 * m.M12 - m.M34 * m.M13 * m.M22) / determinant, -(m.M21 * m.M33 * m.M44 + m.M31 * m.M43 * m.M24 + m.M41 * m.M23 * m.M34 - m.M24 * m.M33 * m.M41 - m.M34 * m.M43 * m.M21 - m.M44 * m.M23 * m.M31) / determinant, (m.M11 * m.M33 * m.M44 + m.M31 * m.M43 * m.M14 + m.M41 * m.M13 * m.M34 - m.M14 * m.M33 * m.M41 - m.M34 * m.M43 * m.M11 - m.M44 * m.M13 * m.M31) / determinant, -(m.M11 * m.M23 * m.M44 + m.M21 * m.M43 * m.M14 + m.M41 * m.M13 * m.M24 - m.M14 * m.M23 * m.M41 - m.M24 * m.M43 * m.M11 - m.M44 * m.M13 * m.M21) / determinant, (m.M11 * m.M23 * m.M34 + m.M21 * m.M33 * m.M14 + m.M31 * m.M13 * m.M24 - m.M14 * m.M23 * m.M31 - m.M24 * m.M33 * m.M11 - m.M34 * m.M13 * m.M21) / determinant, (m.M21 * m.M32 * m.M44 + m.M31 * m.M42 * m.M24 + m.M41 * m.M22 * m.M34 - m.M24 * m.M32 * m.M41 - m.M34 * m.M42 * m.M21 - m.M44 * m.M22 * m.M31) / determinant, -(m.M11 * m.M32 * m.M44 + m.M31 * m.M42 * m.M14 + m.M41 * m.M12 * m.M34 - m.M14 * m.M32 * m.M41 - m.M34 * m.M42 * m.M11 - m.M44 * m.M12 * m.M31) / determinant, (m.M11 * m.M32 * m.M44 + m.M21 * m.M42 * m.M14 + m.M41 * m.M12 * m.M24 - m.M14 * m.M22 * m.M41 - m.M24 * m.M42 * m.M11 - m.M44 * m.M12 * m.M21) / determinant, -(m.M11 * m.M22 * m.M34 + m.M21 * m.M32 * m.M14 + m.M31 * m.M12 * m.M24 - m.M14 * m.M22 * m.M31 - m.M24 * m.M32 * m.M11 - m.M34 * m.M12 * m.M21) / determinant, -(m.M21 * m.M32 * m.M43 + m.M31 * m.M42 * m.M23 + m.M41 * m.M22 * m.M33 - m.M23 * m.M32 * m.M41 - m.M33 * m.M42 * m.M21 - m.M43 * m.M22 * m.M31) / determinant, (m.M11 * m.M32 * m.M43 + m.M31 * m.M42 * m.M13 + m.M41 * m.M12 * m.M33 - m.M13 * m.M32 * m.M41 - m.M33 * m.M42 * m.M11 - m.M43 * m.M12 * m.M31) / determinant, -(m.M11 * m.M22 * m.M43 + m.M21 * m.M42 * m.M13 + m.M41 * m.M12 * m.M23 - m.M13 * m.M22 * m.M41 - m.M23 * m.M42 * m.M11 - m.M43 * m.M12 * m.M21) / determinant, (m.M11 * m.M22 * m.M33 + m.M21 * m.M32 * m.M13 + m.M31 * m.M12 * m.M23 - m.M13 * m.M22 * m.M31 - m.M23 * m.M32 * m.M11 - m.M33 * m.M12 * m.M21) / determinant); - } - - public static Matrix3D operator +(Matrix3D a, Matrix3D b) - { - return new Matrix3D(a.M11 + b.M11, a.M12 + b.M12, a.M13 + b.M13, a.M14 + b.M14, a.M21 + b.M21, a.M22 + b.M22, a.M23 + b.M23, a.M24 + b.M24, a.M31 + b.M31, a.M32 + b.M32, a.M33 + b.M33, a.M34 + b.M34, a.M41 + b.M41, a.M42 + b.M42, a.M43 + b.M43, a.M44 + b.M44); - } - - public static Matrix3D operator -(Matrix3D a, Matrix3D b) - { - return new Matrix3D(a.M11 - b.M11, a.M12 - b.M12, a.M13 - b.M13, a.M14 - b.M14, a.M21 - b.M21, a.M22 - b.M22, a.M23 - b.M23, a.M24 - b.M24, a.M31 - b.M31, a.M32 - b.M32, a.M33 - b.M33, a.M34 - b.M34, a.M41 - b.M41, a.M42 - b.M42, a.M43 - b.M43, a.M44 - b.M44); - } - - public static Matrix3D operator *(Matrix3D a, Matrix3D b) - { - return new Matrix3D(a.M11 * b.M11 + a.M12 * b.M21 + a.M13 * b.M31 + a.M14 * b.M41, a.M11 * b.M12 + a.M12 * b.M22 + a.M13 * b.M32 + a.M14 * b.M42, a.M11 * b.M13 + a.M12 * b.M23 + a.M13 * b.M33 + a.M14 * b.M43, a.M11 * b.M14 + a.M12 * b.M24 + a.M13 * b.M34 + a.M14 * b.M44, a.M21 * b.M11 + a.M22 * b.M21 + a.M23 * b.M31 + a.M24 * b.M41, a.M21 * b.M12 + a.M22 * b.M22 + a.M23 * b.M32 + a.M24 * b.M42, a.M21 * b.M13 + a.M22 * b.M23 + a.M23 * b.M33 + a.M24 * b.M43, a.M21 * b.M14 + a.M22 * b.M24 + a.M23 * b.M34 + a.M24 * b.M44, a.M31 * b.M11 + a.M32 * b.M21 + a.M33 * b.M31 + a.M34 * b.M41, a.M31 * b.M12 + a.M32 * b.M22 + a.M33 * b.M32 + a.M34 * b.M42, a.M31 * b.M13 + a.M32 * b.M23 + a.M33 * b.M33 + a.M34 * b.M43, a.M31 * b.M14 + a.M32 * b.M24 + a.M33 * b.M34 + a.M34 * b.M44, a.M41 * b.M11 + a.M42 * b.M21 + a.M43 * b.M31 + a.M44 * b.M41, a.M41 * b.M12 + a.M42 * b.M22 + a.M43 * b.M32 + a.M44 * b.M42, a.M41 * b.M13 + a.M42 * b.M23 + a.M43 * b.M33 + a.M44 * b.M43, a.M41 * b.M14 + a.M42 * b.M24 + a.M43 * b.M34 + a.M44 * b.M44); - } - - public static Point3D operator *(Matrix3D m, Point3D p) - { - return new Point3D(p.X * m.M11 + p.Y * m.M12 + p.Z * m.M13 + m.M14, p.X * m.M21 + p.Y * m.M22 + p.Z * m.M23 + m.M24, p.X * m.M31 + p.Y * m.M32 + p.Z * m.M33 + m.M34); - } - - public static Matrix3D operator +(Matrix3D m, float n) - { - return new Matrix3D(m.M11 + n, m.M12 + n, m.M13 + n, m.M14 + n, m.M21 + n, m.M22 + n, m.M23 + n, m.M24 + n, m.M31 + n, m.M32 + n, m.M33 + n, m.M34 + n, m.M41 + n, m.M42 + n, m.M43 + n, m.M44 + n); - } - - public static Matrix3D operator -(Matrix3D m, float n) - { - return new Matrix3D(m.M11 - n, m.M12 - n, m.M13 - n, m.M14 - n, m.M21 - n, m.M22 - n, m.M23 - n, m.M24 - n, m.M31 - n, m.M32 - n, m.M33 - n, m.M34 - n, m.M41 - n, m.M42 - n, m.M43 - n, m.M44 - n); - } - - public static Matrix3D operator *(Matrix3D m, float n) - { - return new Matrix3D(m.M11 * n, m.M12 * n, m.M13 * n, m.M14 * n, m.M21 * n, m.M22 * n, m.M23 * n, m.M24 * n, m.M31 * n, m.M32 * n, m.M33 * n, m.M34 * n, m.M41 * n, m.M42 * n, m.M43 * n, m.M44 * n); - } - - public static Matrix3D operator /(Matrix3D m, float n) - { - return new Matrix3D(m.M11 / n, m.M12 / n, m.M13 / n, m.M14 / n, m.M21 / n, m.M22 / n, m.M23 / n, m.M24 / n, m.M31 / n, m.M32 / n, m.M33 / n, m.M34 / n, m.M41 / n, m.M42 / n, m.M43 / n, m.M44 / n); - } - - public float M11; - - public float M12; - - public float M13; - - public float M14; - - public float M21; - - public float M22; - - public float M23; - - public float M24; - - public float M31; - - public float M32; - - public float M33; - - public float M34; - - public float M41; - - public float M42; - - public float M43; - - public float M44; - } -} diff --git a/PCK-Studio/Classes/Models/ModelView.Designer.cs b/PCK-Studio/Classes/Models/ModelView.Designer.cs deleted file mode 100644 index bfedcec8..00000000 --- a/PCK-Studio/Classes/Models/ModelView.Designer.cs +++ /dev/null @@ -1,71 +0,0 @@ - -namespace PckStudio.Models -{ - partial class MinecraftModelView - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - - - - protected override void Dispose(bool disposing) - { - if (disposing && this.components != null) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Component Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - - private void InitializeComponent() - { - components = new System.ComponentModel.Container(); - } - - - private PckStudio.Models.BackgroundTypes backgroundType; - - private System.Drawing.Brush backgroundBrush = new System.Drawing.SolidBrush(System.Drawing.Color.SkyBlue); - - private System.ComponentModel.BackgroundWorker downloader = new System.ComponentModel.BackgroundWorker(); - - private System.Drawing.Point mouseLastLocation; - - private PckStudio.Models.Object3D rotatingObject3D; - - private System.Drawing.Color backgroundColor = System.Drawing.Color.Transparent; - - private System.Drawing.Color backgroundGradientColor1 = System.Drawing.SystemColors.ControlDarkDark; - - private System.Drawing.Color backgroundGradientColor2 = System.Drawing.SystemColors.ControlLightLight; - - private static System.Drawing.Color textShadowColor = System.Drawing.Color.FromArgb(0x3F, 0x3F, 0x3F); - - private System.Drawing.Image backgroundTexture; - - internal PckStudio.Models.Matrix3D GlobalTransformation = PckStudio.Models.Matrix3D.Identity; - - private System.Collections.Generic.List texelList = new System.Collections.Generic.List(); - - private PckStudio.Models.TexelComparer texelComparer = new PckStudio.Models.TexelComparer(); - - private System.Collections.Generic.List object3DList = new System.Collections.Generic.List(); - - private System.Collections.Generic.List dynamicObject3DtList = new System.Collections.Generic.List(); - #endregion - } -} diff --git a/PCK-Studio/Classes/Models/ModelView.cs b/PCK-Studio/Classes/Models/ModelView.cs deleted file mode 100644 index 070e51ec..00000000 --- a/PCK-Studio/Classes/Models/ModelView.cs +++ /dev/null @@ -1,431 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.Drawing.Text; -using System.IO; -using System.Net; -using System.Threading; -using System.Windows.Forms; - -namespace PckStudio.Models -{ - public partial class MinecraftModelView : Control - { - private const int IsometricFOV = 46; - - internal float cameraZ = 31.4285717f; - - private int Fov = 70; - - private float scale = 1f; - - internal float RotationX; - - internal float RotationY; - - private bool perspective = true; - - private float PiBy180 = 0.0174532924f; - - protected override void OnBackColorChanged(EventArgs e) - { - base.OnBackColorChanged(e); - backgroundColor = BackColor; - UpdateBackgroundBrush(); - Invalidate(); - } - - [Browsable(true)] - [Category("Appearance")] - public System.Drawing.Color BackGradientColor1 - { - get - { - return backgroundGradientColor1; - } - set - { - backgroundGradientColor1 = value; - UpdateBackgroundBrush(); - Invalidate(); - } - } - - [Browsable(true)] - [Category("Appearance")] - public System.Drawing.Color BackGradientColor2 - { - get - { - return backgroundGradientColor2; - } - set - { - backgroundGradientColor2 = value; - UpdateBackgroundBrush(); - Invalidate(); - } - } - - [Browsable(true)] - [Category("Appearance")] - public new System.Drawing.Image BackgroundImage - { - get - { - return backgroundTexture; - } - set - { - backgroundTexture = value; - UpdateBackgroundBrush(); - Invalidate(); - } - } - - [Browsable(true)] - [Category("Appearance")] - public BackgroundTypes BackgroundType - { - get - { - return backgroundType; - } - set - { - backgroundType = value; - UpdateBackgroundBrush(); - Invalidate(); - } - } - - [Browsable(true)] - [Category("View")] - public ProjectionTypes Projection - { - get - { - return perspective ? ProjectionTypes.Perspective : ProjectionTypes.Isometric; - } - set - { - perspective = value == ProjectionTypes.Perspective; - SetupProjection(); - foreach (Object3D object3D in object3DList) - { - object3D.Update(); - } - Invalidate(); - } - } - - [Browsable(true)] - [Category("View")] - public int FOV - { - get - { - return Fov; - } - set - { - Fov = value; - SetupProjection(); - foreach (Object3D object3D in object3DList) - { - object3D.Update(); - } - Invalidate(); - } - } - - [Browsable(true)] - [Category("View")] - public int DegreesX - { - get - { - return (int)RotationX; - } - set - { - RotationX = value; - Matrix3D globalTransformation = Matrix3D.CreateRotationX(RotationX * PiBy180) * Matrix3D.CreateRotationY(RotationY * PiBy180); - foreach (Object3D object3D in object3DList) - { - object3D.GlobalTransformation = globalTransformation; - } - Invalidate(); - } - } - - [Browsable(true)] - [Category("View")] - public int DegreesY - { - get - { - return (int)RotationY; - } - set - { - RotationY = value; - Matrix3D globalTransformation = Matrix3D.CreateRotationX(RotationX * PiBy180) * Matrix3D.CreateRotationY(RotationY * PiBy180); - foreach (Object3D object3D in object3DList) - { - object3D.GlobalTransformation = globalTransformation; - } - Invalidate(); - } - } - - public ModelBase Model - { - set - { - Clear(); - value.AddToModelView(this); - Matrix3D globalTransformation = Matrix3D.CreateRotationX(RotationX * 3.14159274f / 180f) * Matrix3D.CreateRotationY(RotationY * 3.14159274f / 180f); - foreach (Object3D object3D in object3DList) - { - object3D.GlobalTransformation = globalTransformation; - } - Invalidate(); - } - } - - private void Clear() - { - texelList.Clear(); - object3DList.Clear(); - dynamicObject3DtList.Clear(); - rotatingObject3D = null; - } - - protected override void OnPaintBackground(PaintEventArgs pevent) - { - base.OnPaintBackground(pevent); - System.Drawing.Graphics graphics = pevent.Graphics; - graphics.CompositingQuality = CompositingQuality.HighSpeed; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed; - graphics.SmoothingMode = SmoothingMode.HighSpeed; - graphics.CompositingMode = CompositingMode.SourceCopy; - graphics.FillRectangle(backgroundBrush, ClientRectangle); - graphics.CompositingMode = CompositingMode.SourceOver; - } - - protected override void OnPaint(PaintEventArgs pe) - { - texelList.Sort(texelComparer); - System.Drawing.Graphics graphics = pe.Graphics; - graphics.TranslateTransform(Width / 2, Height / 2); - graphics.ScaleTransform(scale, -scale); - graphics.CompositingQuality = CompositingQuality.HighSpeed; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed; - graphics.SmoothingMode = SmoothingMode.HighSpeed; - graphics.CompositingMode = CompositingMode.SourceCopy; - for (int i = 0; i < texelList.Count; i++) - { - texelList[i].Draw(graphics); - } - } - - public System.Drawing.Image RenderToImage(System.Drawing.Size size, System.Drawing.RectangleF crop) - { - if (size.Width / size.Height != crop.Width / crop.Height) - { - throw new ArgumentException("Aspect ratio is ambiguous"); - } - System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(size.Width, size.Height); - using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap)) - { - System.Drawing.Size size2 = new System.Drawing.Size((int)(size.Width / crop.Width), (int)(size.Height / crop.Height)); - texelList.Sort(texelComparer); - graphics.TranslateTransform(-crop.Left * size2.Width, -crop.Top * size2.Height); - graphics.TranslateTransform(size2.Width / 2, size2.Height / 2); - float num = Math.Min(size2.Width, size2.Height) * 0.01f / (float)Math.Tan((perspective ? Fov : IsometricFOV) * 3.1415926535897931 / 360.0); - graphics.ScaleTransform(num, -num); - graphics.CompositingQuality = CompositingQuality.HighSpeed; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed; - graphics.SmoothingMode = SmoothingMode.HighSpeed; - graphics.Clear(System.Drawing.Color.Transparent); - for (int i = 0; i < texelList.Count; i++) - { - texelList[i].Draw(graphics); - } - } - return bitmap; - } - - private System.Drawing.Image RenderVersionText() - { - System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(0x154, 0x12); - Version version = new Version(Application.ProductVersion); - string s = string.Format("{0} {1}.{2}{3}", Application.ProductName, version.Major, version.Minor, (version.Build != 0) ? ("." + version.Build) : ""); - using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap)) - { - using (System.Drawing.Brush brush = new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb(0x7F, System.Drawing.Color.Gray))) - { - graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit; - graphics.DrawString(s, Font, brush, 1f, 1f); - graphics.DrawString(s, Font, System.Drawing.Brushes.White, 0f, 0f); - } - } - return bitmap; - } - - private void UpdateBackgroundBrush() - { - backgroundBrush = ((backgroundType == BackgroundTypes.Texture) ? new System.Drawing.TextureBrush(backgroundTexture) : ((backgroundType == BackgroundTypes.Gradient) ? new System.Drawing.Drawing2D.LinearGradientBrush(new System.Drawing.Point(0, 0), new System.Drawing.Point(0, System.Math.Max(1, base.Height)), backgroundGradientColor1, backgroundGradientColor2) : new System.Drawing.SolidBrush(backgroundColor))); - } - - public System.Drawing.Brush GetBackgroundBrush(System.Drawing.Size size) - { - if (backgroundType == BackgroundTypes.Texture) - { - return new System.Drawing.TextureBrush(backgroundTexture); - } - if (backgroundType != BackgroundTypes.Gradient) - { - return new System.Drawing.SolidBrush(backgroundColor); - } - return new LinearGradientBrush(new System.Drawing.Point(0, 0), new System.Drawing.Point(0, Math.Max(1, size.Height)), backgroundGradientColor1, backgroundGradientColor2); - } - - private void SetupProjection() - { - cameraZ = 2400f / Fov; - scale = Math.Min(Width, Height) * 0.01f / (float)Math.Tan((perspective ? Fov : IsometricFOV) * Math.PI / 360.0); - } - - protected override void OnResize(EventArgs e) - { - SetupProjection(); - UpdateBackgroundBrush(); - base.OnResize(e); - } - - internal void RemoveTexelsOf(TexturePlane texturePlane) - { - for (int i = 0; i < texelList.Count; i++) - { - if (texelList[i].TexturePlane == texturePlane) - { - texelList.RemoveAt(i); - i--; - } - } - } - - internal void AddTexel(Texel texel) - { - texelList.Add(texel); - } - - protected override void OnMouseDown(MouseEventArgs e) - { - base.OnMouseDown(e); - System.Drawing.PointF location = new System.Drawing.PointF((e.X - Width * 0.5f) / scale, -(e.Y - Height * 0.5f) / scale); - rotatingObject3D = null; - Object3D item = null; - float num = -1000f; - foreach (Object3D object3D in object3DList) - { - float num2 = object3D.HitTest(location); - if (num2 > num) - { - num = num2; - item = object3D; - } - } - if (num > -1000f && dynamicObject3DtList.Contains(item)) - { - rotatingObject3D = item; - } - mouseLastLocation = e.Location; - Invalidate(); - } - - protected override void OnMouseUp(MouseEventArgs e) - { - base.OnMouseUp(e); - rotatingObject3D = null; - } - - protected override void OnMouseMove(MouseEventArgs e) - { - base.OnMouseMove(e); - if (e.Button != MouseButtons.Left) - { - return; - } - if (rotatingObject3D != null) - { - rotatingObject3D.RotateByMouse((e.X - mouseLastLocation.X) * 400f / Height, (e.Y - mouseLastLocation.Y) * 400f / Height); - mouseLastLocation = e.Location; - Invalidate(); - return; - } - RotationY += (e.X - mouseLastLocation.X) * 400f / Height; - RotationX += (e.Y - mouseLastLocation.Y) * 400f / Height; - mouseLastLocation = e.Location; - Matrix3D globalTransformation = Matrix3D.CreateRotationX(RotationX * 3.14159274f / 180f) * Matrix3D.CreateRotationY(RotationY * 3.14159274f / 180f); - foreach (Object3D object3D in object3DList) - { - object3D.GlobalTransformation = globalTransformation; - } - Invalidate(); - } - - public void AddStatic(Object3D object3D) - { - object3D.Viewport = this; - object3DList.Add(object3D); - foreach (Object3D object3D2 in object3DList) - { - object3D2.Update(); - } - } - - public void AddDynamic(Object3D object3D) - { - AddStatic(object3D); - dynamicObject3DtList.Add(object3D); - } - - internal System.Drawing.PointF Point3DTo2D(Point3D point3D) - { - if (perspective) - { - return new System.Drawing.PointF(point3D.X * (-50f / (point3D.Z - cameraZ)), point3D.Y * (-50f / (point3D.Z - cameraZ))); - } - return new System.Drawing.PointF(point3D.X, point3D.Y); - } - - internal float GetZOrder(Point3D point3D) - { - if (perspective) - { - return point3D.X * point3D.X + point3D.Y * point3D.Y + (cameraZ - point3D.Z) * (cameraZ - point3D.Z); - } - return -point3D.Z; - } - - public MinecraftModelView() - { - SetStyle(ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); - InitializeComponent(); - texelComparer = new TexelComparer(); - } - - public MinecraftModelView(IContainer container) : this() - { - container.Add(this); - } - } -} diff --git a/PCK-Studio/Classes/Models/Object3D.cs b/PCK-Studio/Classes/Models/Object3D.cs deleted file mode 100644 index f9aa9f6a..00000000 --- a/PCK-Studio/Classes/Models/Object3D.cs +++ /dev/null @@ -1,461 +0,0 @@ -using System; -using System.Drawing; - -namespace PckStudio.Models -{ - public abstract class Object3D - { - public abstract Image Image { set; } - - public float Angle1 - { - get - { - return angle1; - } - set - { - angle1 = value; - OnUpdateRotation(); - } - } - - public float Angle2 - { - get - { - return angle2; - } - set - { - angle2 = value; - OnUpdateRotation(); - } - } - - public float MinAngle1 - { - get - { - return minAngle1; - } - set - { - minAngle1 = value; - } - } - - public float MinAngle2 - { - get - { - return minAngle2; - } - set - { - minAngle2 = value; - } - } - - public float MaxAngle1 - { - get - { - return maxAngle1; - } - set - { - maxAngle1 = value; - } - } - - public float MaxAngle2 - { - get - { - return maxAngle2; - } - set - { - maxAngle2 = value; - } - } - - public float AngleRange1 - { - get - { - return maxAngle1 - minAngle1; - } - set - { - minAngle1 = angle1 - value / 2f; - maxAngle1 = angle1 + value / 2f; - } - } - - public float AngleRange2 - { - get - { - return maxAngle2 - minAngle2; - } - set - { - minAngle2 = angle2 - value / 2f; - maxAngle2 = angle2 + value / 2f; - } - } - - public float MinDegrees1 - { - get - { - return minAngle1 / PIby180; - } - set - { - minAngle1 = value * PIby180; - } - } - - public float MinDegrees2 - { - get - { - return minAngle2 / PIby180; - } - set - { - minAngle2 = value * PIby180; - } - } - - public float MaxDegrees1 - { - get - { - return maxAngle1 / PIby180; - } - set - { - maxAngle1 = value * PIby180; - } - } - - public float MaxDegrees2 - { - get - { - return maxAngle2 / PIby180; - } - set - { - maxAngle2 = value * PIby180; - } - } - - public float DegreesRange1 - { - get - { - return AngleRange1 / PIby180; - } - set - { - AngleRange1 = value * PIby180; - } - } - - public float DegreesRange2 - { - get - { - return AngleRange2 / PIby180; - } - set - { - AngleRange2 = value * PIby180; - } - } - - public float Scale - { - get - { - return scaleTransformation.M11; - } - set - { - scaleTransformation = Matrix3D.CreateScale(value); - UpdateRotation(); - } - } - - public RotationOrders RotationOrder - { - get - { - return order; - } - set - { - order = value; - switch (order) - { - case RotationOrders.XY: - Rotate = new RotateMethod(RotateXY); - OnUpdateRotation = UpdateRotationXY; - return; - case RotationOrders.YX: - Rotate = new RotateMethod(RotateYX); - OnUpdateRotation = UpdateRotationYX; - return; - case RotationOrders.XZ: - Rotate = new RotateMethod(RotateXZ); - OnUpdateRotation = UpdateRotationXZ; - return; - case RotationOrders.ZX: - Rotate = new RotateMethod(RotateZX); - OnUpdateRotation = UpdateRotationZX; - return; - case RotationOrders.YZ: - Rotate = new RotateMethod(RotateYZ); - OnUpdateRotation = UpdateRotationYZ; - return; - case RotationOrders.ZY: - Rotate = new RotateMethod(RotateZY); - OnUpdateRotation = UpdateRotationZY; - return; - default: - return; - } - } - } - - internal virtual MinecraftModelView Viewport - { - set - { - viewport = value; - } - } - - public Point3D Origin - { - get - { - return new Point3D(-originTranslation.M14, -originTranslation.M24, -originTranslation.M34); - } - set - { - originTranslation = Matrix3D.CreateTranslation(-value.X, -value.Y, -value.Z); - UpdateRotation(); - } - } - - public Point3D Position - { - get - { - return new Point3D(positionTranslation.M14, positionTranslation.M24, positionTranslation.M34); - } - set - { - positionTranslation = Matrix3D.CreateTranslation(value); - UpdateRotation(); - Update(); - } - } - - internal abstract void Update(); - - public Matrix3D GlobalTransformation - { - get - { - return globalTransformation; - } - set - { - globalTransformation = value; - Update(); - } - } - - public Matrix3D LocalTransformation - { - get - { - return localTransformation; - } - set - { - localTransformation = value; - Update(); - } - } - - public void SetRotation(float angle1, float angle2) - { - this.angle1 = angle1; - this.angle2 = angle2; - OnUpdateRotation(); - } - - public void RotateByMouse(float deltaX, float deltaY) - { - if (Rotate != null) - { - Rotate(deltaX, deltaY); - Update(); - } - } - - private void CorrectAngles() - { - if (angle1 > maxAngle1) - { - angle1 = maxAngle1; - } - else if (angle1 < minAngle1) - { - angle1 = minAngle1; - } - if (angle2 > maxAngle2) - { - angle2 = maxAngle2; - return; - } - if (angle2 < minAngle2) - { - angle2 = minAngle2; - } - } - - public abstract float HitTest(PointF location); - - private void RotateXY(float delta1, float delta2) - { - angle1 += delta1 * PIby180; - angle2 += delta2 * PIby180 * (float)Math.Cos((double)(viewport.RotationY * PIby180)); - UpdateRotationXY(); - } - - private void RotateYX(float delta1, float delta2) - { - angle1 += delta1 * PIby180; - angle2 += delta2 * PIby180 * (float)Math.Cos(viewport.RotationY * 3.1415926535897931 / 180.0); - UpdateRotationYX(); - } - - private void RotateXZ(float delta1, float delta2) - { - angle1 += delta1 * PIby180 * (float)Math.Cos((double)(viewport.RotationY * PIby180)) + delta2 * PIby180 * (float)Math.Sin((double)(viewport.RotationY * PIby180)); - angle2 += delta2 * PIby180 * (float)Math.Cos((double)(viewport.RotationY * PIby180)) - delta1 * PIby180 * (float)Math.Sin((double)(viewport.RotationY * PIby180)); - UpdateRotationXZ(); - } - - private void RotateZX(float delta1, float delta2) - { - angle1 += delta1 * PIby180 * (float)Math.Cos((double)(viewport.RotationY * PIby180)) + delta2 * PIby180 * (float)Math.Sin((double)(viewport.RotationY * PIby180)); - angle2 += delta2 * PIby180 * (float)Math.Cos((double)(viewport.RotationY * PIby180)) - delta1 * PIby180 * (float)Math.Sin((double)(viewport.RotationY * PIby180)); - UpdateRotationZX(); - } - - private void RotateZY(float delta1, float delta2) - { - angle1 -= delta2 * PIby180; - angle2 += delta1 * PIby180; - UpdateRotationZY(); - } - - private void RotateYZ(float delta1, float delta2) - { - angle1 += delta1 * PIby180; - angle2 += delta2 * PIby180 * (float)Math.Sin((double)(viewport.RotationY * PIby180)); - UpdateRotationYZ(); - } - - private void UpdateRotationXY() - { - CorrectAngles(); - localRotation = Matrix3D.CreateRotationY(angle1) * Matrix3D.CreateRotationX(angle2); - UpdateRotation(); - } - - private void UpdateRotationYX() - { - CorrectAngles(); - localRotation = Matrix3D.CreateRotationX(angle2) * Matrix3D.CreateRotationY(angle1); - UpdateRotation(); - } - - private void UpdateRotationXZ() - { - CorrectAngles(); - localRotation = Matrix3D.CreateRotationZ(angle1) * Matrix3D.CreateRotationX(angle2); - UpdateRotation(); - } - - private void UpdateRotationZX() - { - CorrectAngles(); - localRotation = Matrix3D.CreateRotationX(angle2) * Matrix3D.CreateRotationZ(angle1); - UpdateRotation(); - } - - private void UpdateRotationZY() - { - CorrectAngles(); - localRotation = Matrix3D.CreateRotationY(angle2) * Matrix3D.CreateRotationZ(angle1); - UpdateRotation(); - } - - private void UpdateRotationYZ() - { - CorrectAngles(); - localRotation = Matrix3D.CreateRotationZ(angle2) * Matrix3D.CreateRotationY(angle1); - UpdateRotation(); - } - - private void UpdateRotation() - { - localTransformation = positionTranslation * localRotation * originTranslation * scaleTransformation; - } - - public const float PIby180 = 0.0174532924f; - - protected Matrix3D originTranslation = Matrix3D.Identity; - - protected Matrix3D positionTranslation = Matrix3D.Identity; - - protected Matrix3D scaleTransformation = Matrix3D.Identity; - - protected Matrix3D localRotation = Matrix3D.Identity; - - protected Matrix3D localTransformation = Matrix3D.Identity; - - protected Matrix3D globalTransformation = Matrix3D.Identity; - - private float angle1; - - private float angle2; - - private float maxAngle1 = (float)Math.PI; - private float minAngle1 = (float)-Math.PI; - - private float maxAngle2 = (float)Math.PI; - private float minAngle2 = (float)-Math.PI; - - private RotationOrders order; - - protected MinecraftModelView viewport; - - private RotateMethod Rotate; - - private Action OnUpdateRotation; - - private delegate void RotateMethod(float deltaX, float deltaY); - } -} diff --git a/PCK-Studio/Classes/Models/Object3DGroup.cs b/PCK-Studio/Classes/Models/Object3DGroup.cs deleted file mode 100644 index fc3cd524..00000000 --- a/PCK-Studio/Classes/Models/Object3DGroup.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace PckStudio.Models -{ - public class Object3DGroup : Object3D - { - internal override MinecraftModelView Viewport - { - set - { - base.Viewport = value; - foreach (Object3D object3D in objects) - { - object3D.Viewport = value; - } - } - } - - public override System.Drawing.Image Image - { - set - { - foreach (Object3D object3D in objects) - { - object3D.Image = value; - } - } - } - - internal override void Update() - { - Matrix3D globalTransformation = this.globalTransformation * localTransformation; - for (int i = 0; i < objects.Count; i++) - { - objects[i].GlobalTransformation = globalTransformation; - } - } - - public override float HitTest(System.Drawing.PointF location) - { - float num = -1000f; - foreach (Object3D object3D in objects) - { - float num2 = object3D.HitTest(location); - if (num2 > num) - { - num = num2; - } - } - return num; - } - - public void Add(Object3D object3D) - { - if (object3D == this) - { - throw new ArgumentException("Cannot add Object3D into itself."); - } - objects.Add(object3D); - } - - private List objects = new List(); - } -} diff --git a/PCK-Studio/Classes/Models/Point3D.cs b/PCK-Studio/Classes/Models/Point3D.cs deleted file mode 100644 index e69ebf0b..00000000 --- a/PCK-Studio/Classes/Models/Point3D.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; - -namespace PckStudio.Models -{ - public struct Point3D - { - public float X; - public float Y; - public float Z; - - public Point3D(float x, float y, float z) - { - (X, Y, Z) = (x, y, z); - } - - public static Point3D Zero => default(Point3D); - - public override string ToString() - { - return string.Format("({0};{1};{2})", X, Y, Z); - } - - public static Point3D operator +(Point3D a, Point3D b) => new Point3D(a.X + b.X, a.Y + b.Y, a.Z + b.Z); - - public static Point3D operator -(Point3D a, Point3D b) => new Point3D(a.X - b.X, a.Y - b.Y, a.Z - b.Z); - - public static Point3D operator *(Point3D p, float s) => new Point3D(p.X * s, p.Y * s, p.Z * s); - - public static Point3D operator /(Point3D p, float s) => new Point3D(p.X / s, p.Y / s, p.Z / s); - } -} diff --git a/PCK-Studio/Classes/Models/Positions.cs b/PCK-Studio/Classes/Models/Positions.cs deleted file mode 100644 index 004ba901..00000000 --- a/PCK-Studio/Classes/Models/Positions.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace PckStudio.Models -{ - public enum Positions - { - Default, - Outstretched, - Walking, - Running, - Sitting, - Zombie - } -} diff --git a/PCK-Studio/Classes/Models/ProjectionTypes.cs b/PCK-Studio/Classes/Models/ProjectionTypes.cs deleted file mode 100644 index 04d81550..00000000 --- a/PCK-Studio/Classes/Models/ProjectionTypes.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace PckStudio.Models -{ - public enum ProjectionTypes : byte - { - Perspective, - Isometric - } -} diff --git a/PCK-Studio/Classes/Models/RotationOrders.cs b/PCK-Studio/Classes/Models/RotationOrders.cs deleted file mode 100644 index 0ca2c041..00000000 --- a/PCK-Studio/Classes/Models/RotationOrders.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace PckStudio.Models -{ - public enum RotationOrders : byte - { - XY, - YX, - XZ, - ZX, - YZ, - ZY - } -} diff --git a/PCK-Studio/Classes/Models/Texel.cs b/PCK-Studio/Classes/Models/Texel.cs deleted file mode 100644 index 736bcb21..00000000 --- a/PCK-Studio/Classes/Models/Texel.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; - -namespace PckStudio.Models -{ - internal struct Texel - { - internal Texel(TexturePlane texturePlane, int x, int y, System.Drawing.Color color) - { - TexturePlane = texturePlane; - X = x; - Y = y; - this.color = color; - brush = new System.Drawing.SolidBrush(color); - pen = new System.Drawing.Pen(System.Drawing.Color.White, 0.01f); - } - - internal double Z - { - get - { - return TexturePlane.ZOrder[X + 1, Y + 1]; - } - } - - internal void Draw(System.Drawing.Graphics g) - { - System.Drawing.PointF[] points = new System.Drawing.PointF[] - { - TexturePlane.Points[X, Y], - TexturePlane.Points[X + 1, Y], - TexturePlane.Points[X + 1, Y + 1], - TexturePlane.Points[X, Y + 1] - }; - g.FillPolygon(brush, points); - } - - internal TexturePlane TexturePlane; - - internal int X; - - internal int Y; - - private System.Drawing.Color color; - - private System.Drawing.Brush brush; - - private System.Drawing.Pen pen; - } -} diff --git a/PCK-Studio/Classes/Models/TexelComparer.cs b/PCK-Studio/Classes/Models/TexelComparer.cs deleted file mode 100644 index d7187760..00000000 --- a/PCK-Studio/Classes/Models/TexelComparer.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace PckStudio.Models -{ - internal class TexelComparer : IComparer - { - public int Compare(Texel x, Texel y) - { - return -x.Z.CompareTo(y.Z); - } - - public TexelComparer() - { - } - } -} diff --git a/PCK-Studio/Classes/Models/TexturePlane.cs b/PCK-Studio/Classes/Models/TexturePlane.cs deleted file mode 100644 index 0b7b7edf..00000000 --- a/PCK-Studio/Classes/Models/TexturePlane.cs +++ /dev/null @@ -1,189 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.Drawing; - -namespace PckStudio.Models -{ - public class TexturePlane : Object3D - { - public override Image Image - { - set - { - Bitmap = (Bitmap)value; - } - } - - internal override MinecraftModelView Viewport - { - set - { - base.Viewport = value; - if (bitmap != null && value != null) - { - UpdateBitmap(); - } - } - } - - internal override void Update() - { - if (Points == null || viewport == null) - { - return; - } - Matrix3D m = globalTransformation * localTransformation * originTranslation; - for (int i = 0; i <= width; i++) - { - for (int j = 0; j <= height; j++) - { - Point3D point3D = m * new Point3D(i, j, 0f); - Points[i, j] = viewport.Point3DTo2D(point3D); - double num = (double)viewport.GetZOrder(point3D); - ZOrder[i, j] += num; - ZOrder[i + 1, j] += num; - ZOrder[i, j + 1] += num; - ZOrder[i + 1, j + 1] = num; - } - } - } - - private Bitmap Bitmap - { - set - { - if (viewport == null) - { - bitmap = value; - return; - } - texelList.Clear(); - if (bitmap != null) - { - viewport.RemoveTexelsOf(this); - Points = null; - } - bitmap = value; - if (bitmap != null) - { - UpdateBitmap(); - Update(); - } - } - } - - private void UpdateBitmap() - { - width = bitmap.Width; - height = bitmap.Height; - visibility = new bool[width, height]; - for (int i = 0; i < width; i++) - { - for (int j = 0; j < height; j++) - { - Color pixel = bitmap.GetPixel(i, j); - int num = flipHorizontally ? (width - i - 1) : i; - int num2 = flipVertically ? j : (height - j - 1); - if (pixel.A == 0) - { - visibility[num, num2] = false; - } - else - { - visibility[num, num2] = true; - Texel texel = new Texel(this, num, num2, pixel); - viewport.AddTexel(texel); - texelList.Add(texel); - } - } - } - Points = new PointF[width + 1, height + 1]; - ZOrder = new double[width + 2, height + 2]; - } - - public TexturePlane(Image bitmap, Rectangle srcRect, Point3D origin, Point3D normal, Effects effects) - { - Origin = origin; - this.normal = normal; - if (bitmap == null) - { - Bitmap = null; - return; - } - Bitmap bitmap2 = new Bitmap(srcRect.Width, srcRect.Height); - using (Graphics graphics = Graphics.FromImage(bitmap2)) - { - graphics.DrawImage(bitmap, new Rectangle(0, 0, bitmap2.Width, bitmap2.Height), srcRect, GraphicsUnit.Pixel); - } - flipHorizontally = (byte)(effects & Effects.FlipHorizontally) == 1; - flipVertically = (byte)(effects & Effects.FlipVertically) == 2; - Bitmap = bitmap2; - } - - public override float HitTest(PointF location) - { - if (Points == null) - { - return -1000f; - } - GraphicsPath graphicsPath = new GraphicsPath(); - graphicsPath.AddPolygon(new PointF[] - { - Points[0, 0], - Points[Points.GetLength(0) - 1, 0], - Points[Points.GetLength(0) - 1, Points.GetLength(1) - 1], - Points[0, Points.GetLength(1) - 1] - }); - Region region = new Region(graphicsPath); - if (region.IsVisible(location)) - { - for (int i = 0; i < Points.GetLength(0) - 1; i++) - { - for (int j = 0; j < Points.GetLength(1) - 1; j++) - { - if (visibility[i, j]) - { - graphicsPath.Reset(); - graphicsPath.AddPolygon(new PointF[] - { - Points[i, j], - Points[i + 1, j], - Points[i + 1, j + 1], - Points[i, j + 1] - }); - if (graphicsPath.IsVisible(location)) - { - return (globalTransformation * localTransformation * originTranslation * new Point3D(i, j, 0f)).Z; - } - } - } - } - } - return -1000f; - } - - private List texelList = new List(); - - internal PointF[,] Points; - - internal double[,] ZOrder; - - internal bool IsVisible = true; - - private bool[,] visibility; - - private Bitmap bitmap; - - private bool flipHorizontally; - - private bool flipVertically; - - private int width; - - private int height; - - private Point3D normal; - } -} diff --git a/PCK-Studio/Controls/CustomTabControl.cs b/PCK-Studio/Controls/CustomTabControl.cs new file mode 100644 index 00000000..a9e09f03 --- /dev/null +++ b/PCK-Studio/Controls/CustomTabControl.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Windows.Forms; + +using MetroFramework.Controls; +using MetroFramework.Drawing; + + +namespace PckStudio.Controls +{ + internal class CustomTabControl : MetroTabControl + { + private const string CloseChar = "×"; + private Size CloseButtonSize = new Size(7, 7); + private const int StartIndex = 1; + + [Browsable(true)] + public event EventHandler PageClosing; + + public CustomTabControl() + : base() + { + } + + private Rectangle GetCloseButtonArea(Rectangle tabArea) + { + Size closeBtnSz = CloseButtonSize; + var closeBtnPt = new Point( + tabArea.Right - closeBtnSz.Width, + tabArea.Top + 2 + (tabArea.Height - closeBtnSz.Height) / 2); + return new Rectangle(closeBtnPt, closeBtnSz); + } + + protected override void OnMouseClick(MouseEventArgs e) + { + base.OnMouseClick(e); + if (SelectedIndex < StartIndex) + return; + Rectangle tabArea = GetTabRect(SelectedIndex); + Rectangle buttonArea = GetCloseButtonArea(tabArea); + if (buttonArea.Contains(e.Location)) + { + var eventArg = new PageClosingEventArgs(TabPages[SelectedIndex]); + PageClosing?.Invoke(this, eventArg); + if (!eventArg.Cancel) + { + SelectedIndex -= 1; + TabPages.RemoveAt(SelectedIndex + 1); + } + } + } + + protected override void OnCustomPaintForeground(MetroPaintEventArgs e) + { + base.OnCustomPaintForeground(e); + if (SelectedIndex < StartIndex) + return; + // Draw Close button + Rectangle tabArea = GetTabRect(SelectedIndex); + + Rectangle buttonArea = GetCloseButtonArea(tabArea); + + e.Graphics.FillRectangle(MetroPaint.GetStyleBrush(Style), buttonArea); + e.Graphics.DrawString( + CloseChar, + Font, + new SolidBrush(MetroPaint.ForeColor.Title(Theme)), + buttonArea.Right - buttonArea.Width - 2, buttonArea.Top - 4); + } + + //protected override void OnPaintForeground(PaintEventArgs e) + //{ + // base.OnPaintForeground(e); + // for (int i = StartIndex; i < TabPages.Count; i++) + // { + // // Draw Close button + // Rectangle tabArea = GetTabRect(i); + + // Rectangle buttonArea = GetCloseButtonArea(tabArea); + + // e.Graphics.FillRectangle(MetroPaint.GetStyleBrush(Style), buttonArea); + // e.Graphics.DrawString( + // CloseChar, + // Font, + // new SolidBrush(MetroPaint.ForeColor.Title(Theme)), + // buttonArea.Right - buttonArea.Width - 2, buttonArea.Top - 4); + // } + //} + } +} \ No newline at end of file diff --git a/PCK-Studio/Controls/EditorControl.cs b/PCK-Studio/Controls/EditorControl.cs new file mode 100644 index 00000000..6a7259fa --- /dev/null +++ b/PCK-Studio/Controls/EditorControl.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using PckStudio.Interfaces; + +namespace PckStudio.Controls +{ + internal class EditorControl : UserControl, IEditor where T : class + { + public T EditorValue { get; } + + public ISaveContext SaveContext { get; } + + public EditorControl() + { + } + + protected EditorControl(T value, ISaveContext saveContext) + { + _ = value ?? throw new ArgumentNullException(nameof(value)); + EditorValue = value; + SaveContext = saveContext; + } + + protected override void OnControlRemoved(ControlEventArgs e) + { + if (SaveContext.AutoSave) + Save(); + base.OnControlRemoved(e); + } + + public void Save() => SaveContext.Save(EditorValue); + + public virtual void SaveAs() => throw new NotImplementedException(); + + public virtual void Close() => throw new NotImplementedException(); + + public virtual void UpdateView() => throw new NotImplementedException(); + } +} diff --git a/PCK-Studio/Controls/EditorForm.cs b/PCK-Studio/Controls/EditorForm.cs new file mode 100644 index 00000000..e492f697 --- /dev/null +++ b/PCK-Studio/Controls/EditorForm.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using MetroFramework.Forms; +using PckStudio.Interfaces; + +namespace PckStudio.Controls +{ + public class EditorForm : MetroForm where T : class + { + protected T EditorValue; + private readonly ISaveContext SaveContext; + + private EditorForm() + { + } + + protected EditorForm(T value, ISaveContext saveContext) + { + _ = value ?? throw new ArgumentNullException(nameof(value)); + EditorValue = value; + SaveContext = saveContext; + } + + protected void Save() => SaveContext.Save(EditorValue); + + protected override void OnFormClosing(FormClosingEventArgs e) + { + if (SaveContext.AutoSave) + Save(); + base.OnFormClosing(e); + } + } +} \ No newline at end of file diff --git a/PCK-Studio/Controls/PageClosingEventArgs.cs b/PCK-Studio/Controls/PageClosingEventArgs.cs new file mode 100644 index 00000000..ac8de3a4 --- /dev/null +++ b/PCK-Studio/Controls/PageClosingEventArgs.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace PckStudio.Controls +{ + internal class PageClosingEventArgs : CancelEventArgs + { + private readonly TabPage page; + public TabPage Page => page; + + public PageClosingEventArgs(TabPage page) + : base() + { + this.page = page; + } + } +} diff --git a/PCK-Studio/Controls/PckEditor.Designer.cs b/PCK-Studio/Controls/PckEditor.Designer.cs new file mode 100644 index 00000000..a5351572 --- /dev/null +++ b/PCK-Studio/Controls/PckEditor.Designer.cs @@ -0,0 +1,824 @@ +using System.Windows.Forms; + +namespace PckStudio.Controls +{ + partial class PckEditor + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.Windows.Forms.PictureBox logoPictureBox; + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PckEditor)); + this.pckFileLabel = new MetroFramework.Controls.MetroLabel(); + this.labelImageSize = new MetroFramework.Controls.MetroLabel(); + this.fileEntryCountLabel = new MetroFramework.Controls.MetroLabel(); + this.PropertiesTabControl = new MetroFramework.Controls.MetroTabControl(); + this.MetaTab = new MetroFramework.Controls.MetroTabPage(); + this.metroLabel2 = new MetroFramework.Controls.MetroLabel(); + this.entryTypeTextBox = new MetroFramework.Controls.MetroTextBox(); + this.entryDataTextBox = new MetroFramework.Controls.MetroTextBox(); + this.buttonEdit = new MetroFramework.Controls.MetroButton(); + this.metroLabel1 = new MetroFramework.Controls.MetroLabel(); + this.treeMeta = new System.Windows.Forms.TreeView(); + this.contextMenuMetaTree = new System.Windows.Forms.ContextMenuStrip(this.components); + this.addEntryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.addEntryToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.addBOXEntryToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.addANIMEntryToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.addMultipleEntriesToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.deleteEntryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.editAllEntriesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.label11 = new MetroFramework.Controls.MetroLabel(); + this.treeViewMain = new System.Windows.Forms.TreeView(); + this.contextMenuPCKEntries = new System.Windows.Forms.ContextMenuStrip(this.components); + this.createToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.folderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.skinToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.createAnimatedTextureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.audiopckToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.colourscolToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.CreateSkinsPCKToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.behavioursbinToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.entityMaterialsbinToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.importSkinsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.importSkinToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.importExtractedSkinsFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.addTextureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.addFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.exportToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.as3DSTextureFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.setFileTypeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.skinToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.capeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.textureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.languagesFileLOCToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.gameRulesFileGRFToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.audioPCKFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.coloursCOLFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.gameRulesHeaderGRHToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.skinsPCKToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.modelsFileBINToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.behavioursFileBINToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.entityMaterialsFileBINToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); + this.miscFunctionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.generateMipMapTextureToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.viewFileInfoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.correctSkinDecimalsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.setSubPCKEndiannessToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.bigEndianXbox360PS3WiiUToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.littleEndianPS4PSVitaSwitchToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.setModelContainerFormatToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.version1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.version2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.version3114ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.extractToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); + this.cloneFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.renameFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.replaceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.deleteFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.imageList = new System.Windows.Forms.ImageList(this.components); + this.addMultipleEntriesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.LittleEndianCheckBox = new MetroFramework.Controls.MetroCheckBox(); + this.previewPictureBox = new PckStudio.ToolboxItems.InterpolationPictureBox(); + logoPictureBox = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(logoPictureBox)).BeginInit(); + this.PropertiesTabControl.SuspendLayout(); + this.MetaTab.SuspendLayout(); + this.contextMenuMetaTree.SuspendLayout(); + this.contextMenuPCKEntries.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.previewPictureBox)).BeginInit(); + this.SuspendLayout(); + // + // logoPictureBox + // + resources.ApplyResources(logoPictureBox, "logoPictureBox"); + logoPictureBox.Name = "logoPictureBox"; + logoPictureBox.TabStop = false; + // + // pckFileLabel + // + this.pckFileLabel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20))))); + resources.ApplyResources(this.pckFileLabel, "pckFileLabel"); + this.pckFileLabel.Name = "pckFileLabel"; + this.pckFileLabel.Theme = MetroFramework.MetroThemeStyle.Dark; + // + // labelImageSize + // + resources.ApplyResources(this.labelImageSize, "labelImageSize"); + this.labelImageSize.Name = "labelImageSize"; + this.labelImageSize.Theme = MetroFramework.MetroThemeStyle.Dark; + // + // fileEntryCountLabel + // + resources.ApplyResources(this.fileEntryCountLabel, "fileEntryCountLabel"); + this.fileEntryCountLabel.Name = "fileEntryCountLabel"; + this.fileEntryCountLabel.Theme = MetroFramework.MetroThemeStyle.Dark; + // + // PropertiesTabControl + // + this.PropertiesTabControl.Controls.Add(this.MetaTab); + resources.ApplyResources(this.PropertiesTabControl, "PropertiesTabControl"); + this.PropertiesTabControl.Name = "PropertiesTabControl"; + this.PropertiesTabControl.SelectedIndex = 0; + this.PropertiesTabControl.Style = MetroFramework.MetroColorStyle.Silver; + this.PropertiesTabControl.Theme = MetroFramework.MetroThemeStyle.Dark; + this.PropertiesTabControl.UseSelectable = true; + // + // MetaTab + // + this.MetaTab.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.MetaTab.Controls.Add(this.metroLabel2); + this.MetaTab.Controls.Add(this.entryTypeTextBox); + this.MetaTab.Controls.Add(this.entryDataTextBox); + this.MetaTab.Controls.Add(this.buttonEdit); + this.MetaTab.Controls.Add(this.metroLabel1); + this.MetaTab.Controls.Add(this.treeMeta); + this.MetaTab.HorizontalScrollbarBarColor = true; + this.MetaTab.HorizontalScrollbarHighlightOnWheel = false; + this.MetaTab.HorizontalScrollbarSize = 10; + resources.ApplyResources(this.MetaTab, "MetaTab"); + this.MetaTab.Name = "MetaTab"; + this.MetaTab.Theme = MetroFramework.MetroThemeStyle.Dark; + this.MetaTab.VerticalScrollbarBarColor = true; + this.MetaTab.VerticalScrollbarHighlightOnWheel = false; + this.MetaTab.VerticalScrollbarSize = 10; + // + // metroLabel2 + // + resources.ApplyResources(this.metroLabel2, "metroLabel2"); + this.metroLabel2.Name = "metroLabel2"; + this.metroLabel2.Theme = MetroFramework.MetroThemeStyle.Dark; + // + // entryTypeTextBox + // + resources.ApplyResources(this.entryTypeTextBox, "entryTypeTextBox"); + // + // + // + this.entryTypeTextBox.CustomButton.Image = ((System.Drawing.Image)(resources.GetObject("resource.Image"))); + this.entryTypeTextBox.CustomButton.ImeMode = ((System.Windows.Forms.ImeMode)(resources.GetObject("resource.ImeMode"))); + this.entryTypeTextBox.CustomButton.Location = ((System.Drawing.Point)(resources.GetObject("resource.Location"))); + this.entryTypeTextBox.CustomButton.Name = ""; + this.entryTypeTextBox.CustomButton.Size = ((System.Drawing.Size)(resources.GetObject("resource.Size"))); + this.entryTypeTextBox.CustomButton.Style = MetroFramework.MetroColorStyle.Blue; + this.entryTypeTextBox.CustomButton.TabIndex = ((int)(resources.GetObject("resource.TabIndex"))); + this.entryTypeTextBox.CustomButton.Theme = MetroFramework.MetroThemeStyle.Light; + this.entryTypeTextBox.CustomButton.UseSelectable = true; + this.entryTypeTextBox.CustomButton.Visible = ((bool)(resources.GetObject("resource.Visible"))); + this.entryTypeTextBox.Lines = new string[0]; + this.entryTypeTextBox.MaxLength = 32767; + this.entryTypeTextBox.Name = "entryTypeTextBox"; + this.entryTypeTextBox.PasswordChar = '\0'; + this.entryTypeTextBox.ScrollBars = System.Windows.Forms.ScrollBars.None; + this.entryTypeTextBox.SelectedText = ""; + this.entryTypeTextBox.SelectionLength = 0; + this.entryTypeTextBox.SelectionStart = 0; + this.entryTypeTextBox.ShortcutsEnabled = true; + this.entryTypeTextBox.Theme = MetroFramework.MetroThemeStyle.Dark; + this.entryTypeTextBox.UseSelectable = true; + this.entryTypeTextBox.WaterMarkColor = System.Drawing.Color.FromArgb(((int)(((byte)(109)))), ((int)(((byte)(109)))), ((int)(((byte)(109))))); + this.entryTypeTextBox.WaterMarkFont = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Pixel); + // + // entryDataTextBox + // + resources.ApplyResources(this.entryDataTextBox, "entryDataTextBox"); + // + // + // + this.entryDataTextBox.CustomButton.Image = ((System.Drawing.Image)(resources.GetObject("resource.Image1"))); + this.entryDataTextBox.CustomButton.ImeMode = ((System.Windows.Forms.ImeMode)(resources.GetObject("resource.ImeMode1"))); + this.entryDataTextBox.CustomButton.Location = ((System.Drawing.Point)(resources.GetObject("resource.Location1"))); + this.entryDataTextBox.CustomButton.Name = ""; + this.entryDataTextBox.CustomButton.Size = ((System.Drawing.Size)(resources.GetObject("resource.Size1"))); + this.entryDataTextBox.CustomButton.Style = MetroFramework.MetroColorStyle.Blue; + this.entryDataTextBox.CustomButton.TabIndex = ((int)(resources.GetObject("resource.TabIndex1"))); + this.entryDataTextBox.CustomButton.Theme = MetroFramework.MetroThemeStyle.Light; + this.entryDataTextBox.CustomButton.UseSelectable = true; + this.entryDataTextBox.CustomButton.Visible = ((bool)(resources.GetObject("resource.Visible1"))); + this.entryDataTextBox.Lines = new string[0]; + this.entryDataTextBox.MaxLength = 32767; + this.entryDataTextBox.Name = "entryDataTextBox"; + this.entryDataTextBox.PasswordChar = '\0'; + this.entryDataTextBox.ScrollBars = System.Windows.Forms.ScrollBars.None; + this.entryDataTextBox.SelectedText = ""; + this.entryDataTextBox.SelectionLength = 0; + this.entryDataTextBox.SelectionStart = 0; + this.entryDataTextBox.ShortcutsEnabled = true; + this.entryDataTextBox.Theme = MetroFramework.MetroThemeStyle.Dark; + this.entryDataTextBox.UseSelectable = true; + this.entryDataTextBox.WaterMarkColor = System.Drawing.Color.FromArgb(((int)(((byte)(109)))), ((int)(((byte)(109)))), ((int)(((byte)(109))))); + this.entryDataTextBox.WaterMarkFont = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Pixel); + // + // buttonEdit + // + resources.ApplyResources(this.buttonEdit, "buttonEdit"); + this.buttonEdit.Name = "buttonEdit"; + this.buttonEdit.Theme = MetroFramework.MetroThemeStyle.Dark; + this.buttonEdit.UseSelectable = true; + this.buttonEdit.Click += new System.EventHandler(this.buttonEdit_Click); + // + // metroLabel1 + // + resources.ApplyResources(this.metroLabel1, "metroLabel1"); + this.metroLabel1.Name = "metroLabel1"; + this.metroLabel1.Theme = MetroFramework.MetroThemeStyle.Dark; + // + // treeMeta + // + this.treeMeta.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(13)))), ((int)(((byte)(13)))), ((int)(((byte)(13))))); + this.treeMeta.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.treeMeta.ContextMenuStrip = this.contextMenuMetaTree; + resources.ApplyResources(this.treeMeta, "treeMeta"); + this.treeMeta.ForeColor = System.Drawing.SystemColors.Window; + this.treeMeta.Name = "treeMeta"; + this.treeMeta.PathSeparator = "/"; + this.treeMeta.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeMeta_AfterSelect); + this.treeMeta.DoubleClick += new System.EventHandler(this.treeMeta_DoubleClick); + this.treeMeta.KeyDown += new System.Windows.Forms.KeyEventHandler(this.treeMeta_KeyDown); + // + // contextMenuMetaTree + // + this.contextMenuMetaTree.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.addEntryToolStripMenuItem, + this.addMultipleEntriesToolStripMenuItem1, + this.deleteEntryToolStripMenuItem, + this.editAllEntriesToolStripMenuItem}); + this.contextMenuMetaTree.Name = "contextMenuStrip1"; + resources.ApplyResources(this.contextMenuMetaTree, "contextMenuMetaTree"); + // + // addEntryToolStripMenuItem + // + this.addEntryToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.addEntryToolStripMenuItem1, + this.addBOXEntryToolStripMenuItem1, + this.addANIMEntryToolStripMenuItem1}); + resources.ApplyResources(this.addEntryToolStripMenuItem, "addEntryToolStripMenuItem"); + this.addEntryToolStripMenuItem.Name = "addEntryToolStripMenuItem"; + // + // addEntryToolStripMenuItem1 + // + this.addEntryToolStripMenuItem1.Name = "addEntryToolStripMenuItem1"; + resources.ApplyResources(this.addEntryToolStripMenuItem1, "addEntryToolStripMenuItem1"); + this.addEntryToolStripMenuItem1.Click += new System.EventHandler(this.addEntryToolStripMenuItem_Click); + // + // addBOXEntryToolStripMenuItem1 + // + this.addBOXEntryToolStripMenuItem1.Name = "addBOXEntryToolStripMenuItem1"; + resources.ApplyResources(this.addBOXEntryToolStripMenuItem1, "addBOXEntryToolStripMenuItem1"); + this.addBOXEntryToolStripMenuItem1.Click += new System.EventHandler(this.addBOXEntryToolStripMenuItem1_Click); + // + // addANIMEntryToolStripMenuItem1 + // + this.addANIMEntryToolStripMenuItem1.Name = "addANIMEntryToolStripMenuItem1"; + resources.ApplyResources(this.addANIMEntryToolStripMenuItem1, "addANIMEntryToolStripMenuItem1"); + this.addANIMEntryToolStripMenuItem1.Click += new System.EventHandler(this.addANIMEntryToolStripMenuItem1_Click); + // + // addMultipleEntriesToolStripMenuItem1 + // + this.addMultipleEntriesToolStripMenuItem1.Name = "addMultipleEntriesToolStripMenuItem1"; + resources.ApplyResources(this.addMultipleEntriesToolStripMenuItem1, "addMultipleEntriesToolStripMenuItem1"); + this.addMultipleEntriesToolStripMenuItem1.Click += new System.EventHandler(this.addMultipleEntriesToolStripMenuItem1_Click); + // + // deleteEntryToolStripMenuItem + // + this.deleteEntryToolStripMenuItem.Image = global::PckStudio.Properties.Resources.file_delete; + this.deleteEntryToolStripMenuItem.Name = "deleteEntryToolStripMenuItem"; + resources.ApplyResources(this.deleteEntryToolStripMenuItem, "deleteEntryToolStripMenuItem"); + this.deleteEntryToolStripMenuItem.Click += new System.EventHandler(this.deleteEntryToolStripMenuItem_Click); + // + // editAllEntriesToolStripMenuItem + // + this.editAllEntriesToolStripMenuItem.Name = "editAllEntriesToolStripMenuItem"; + resources.ApplyResources(this.editAllEntriesToolStripMenuItem, "editAllEntriesToolStripMenuItem"); + this.editAllEntriesToolStripMenuItem.Click += new System.EventHandler(this.editAllEntriesToolStripMenuItem_Click); + // + // label11 + // + resources.ApplyResources(this.label11, "label11"); + this.label11.Name = "label11"; + // + // treeViewMain + // + this.treeViewMain.AllowDrop = true; + this.treeViewMain.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(12)))), ((int)(((byte)(12)))), ((int)(((byte)(12))))); + this.treeViewMain.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.treeViewMain.ContextMenuStrip = this.contextMenuPCKEntries; + resources.ApplyResources(this.treeViewMain, "treeViewMain"); + this.treeViewMain.ForeColor = System.Drawing.Color.White; + this.treeViewMain.ImageList = this.imageList; + this.treeViewMain.LabelEdit = true; + this.treeViewMain.Name = "treeViewMain"; + this.treeViewMain.PathSeparator = "/"; + this.treeViewMain.BeforeLabelEdit += new System.Windows.Forms.NodeLabelEditEventHandler(this.treeViewMain_BeforeLabelEdit); + this.treeViewMain.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.treeViewMain_ItemDrag); + this.treeViewMain.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeViewMain_AfterSelect); + this.treeViewMain.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeViewMain_NodeMouseClick); + this.treeViewMain.DragDrop += new System.Windows.Forms.DragEventHandler(this.treeViewMain_DragDrop); + this.treeViewMain.DragEnter += new System.Windows.Forms.DragEventHandler(this.treeViewMain_DragEnter); + this.treeViewMain.DragOver += new System.Windows.Forms.DragEventHandler(this.treeViewMain_DragOver); + this.treeViewMain.DoubleClick += new System.EventHandler(this.treeViewMain_DoubleClick); + this.treeViewMain.KeyDown += new System.Windows.Forms.KeyEventHandler(this.treeViewMain_KeyDown); + // + // contextMenuPCKEntries + // + this.contextMenuPCKEntries.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.createToolStripMenuItem, + this.importSkinsToolStripMenuItem, + this.exportToolStripMenuItem, + this.setFileTypeToolStripMenuItem, + this.toolStripSeparator5, + this.miscFunctionsToolStripMenuItem, + this.extractToolStripMenuItem, + this.toolStripSeparator6, + this.cloneFileToolStripMenuItem, + this.renameFileToolStripMenuItem, + this.replaceToolStripMenuItem, + this.deleteFileToolStripMenuItem}); + this.contextMenuPCKEntries.Name = "contextMenuStrip1"; + resources.ApplyResources(this.contextMenuPCKEntries, "contextMenuPCKEntries"); + this.contextMenuPCKEntries.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuPCKEntries_Opening); + // + // createToolStripMenuItem + // + this.createToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.folderToolStripMenuItem, + this.skinToolStripMenuItem, + this.createAnimatedTextureToolStripMenuItem, + this.audiopckToolStripMenuItem, + this.colourscolToolStripMenuItem, + this.CreateSkinsPCKToolStripMenuItem1, + this.behavioursbinToolStripMenuItem, + this.entityMaterialsbinToolStripMenuItem}); + resources.ApplyResources(this.createToolStripMenuItem, "createToolStripMenuItem"); + this.createToolStripMenuItem.Name = "createToolStripMenuItem"; + // + // folderToolStripMenuItem + // + resources.ApplyResources(this.folderToolStripMenuItem, "folderToolStripMenuItem"); + this.folderToolStripMenuItem.Name = "folderToolStripMenuItem"; + this.folderToolStripMenuItem.Click += new System.EventHandler(this.folderToolStripMenuItem_Click); + // + // skinToolStripMenuItem + // + resources.ApplyResources(this.skinToolStripMenuItem, "skinToolStripMenuItem"); + this.skinToolStripMenuItem.Name = "skinToolStripMenuItem"; + this.skinToolStripMenuItem.Click += new System.EventHandler(this.createSkinToolStripMenuItem_Click); + // + // createAnimatedTextureToolStripMenuItem + // + resources.ApplyResources(this.createAnimatedTextureToolStripMenuItem, "createAnimatedTextureToolStripMenuItem"); + this.createAnimatedTextureToolStripMenuItem.Name = "createAnimatedTextureToolStripMenuItem"; + this.createAnimatedTextureToolStripMenuItem.Click += new System.EventHandler(this.createAnimatedTextureToolStripMenuItem_Click); + // + // audiopckToolStripMenuItem + // + this.audiopckToolStripMenuItem.Image = global::PckStudio.Properties.Resources.BINKA_ICON; + this.audiopckToolStripMenuItem.Name = "audiopckToolStripMenuItem"; + resources.ApplyResources(this.audiopckToolStripMenuItem, "audiopckToolStripMenuItem"); + this.audiopckToolStripMenuItem.Click += new System.EventHandler(this.audiopckToolStripMenuItem_Click); + // + // colourscolToolStripMenuItem + // + this.colourscolToolStripMenuItem.Image = global::PckStudio.Properties.Resources.COL_ICON; + this.colourscolToolStripMenuItem.Name = "colourscolToolStripMenuItem"; + resources.ApplyResources(this.colourscolToolStripMenuItem, "colourscolToolStripMenuItem"); + this.colourscolToolStripMenuItem.Click += new System.EventHandler(this.colourscolToolStripMenuItem_Click); + // + // CreateSkinsPCKToolStripMenuItem1 + // + this.CreateSkinsPCKToolStripMenuItem1.Image = global::PckStudio.Properties.Resources.SKINS_ICON; + this.CreateSkinsPCKToolStripMenuItem1.Name = "CreateSkinsPCKToolStripMenuItem1"; + resources.ApplyResources(this.CreateSkinsPCKToolStripMenuItem1, "CreateSkinsPCKToolStripMenuItem1"); + this.CreateSkinsPCKToolStripMenuItem1.Click += new System.EventHandler(this.CreateSkinsPCKToolStripMenuItem1_Click); + // + // behavioursbinToolStripMenuItem + // + this.behavioursbinToolStripMenuItem.Image = global::PckStudio.Properties.Resources.BEHAVIOURS_ICON; + this.behavioursbinToolStripMenuItem.Name = "behavioursbinToolStripMenuItem"; + resources.ApplyResources(this.behavioursbinToolStripMenuItem, "behavioursbinToolStripMenuItem"); + this.behavioursbinToolStripMenuItem.Click += new System.EventHandler(this.behavioursbinToolStripMenuItem_Click); + // + // entityMaterialsbinToolStripMenuItem + // + this.entityMaterialsbinToolStripMenuItem.Image = global::PckStudio.Properties.Resources.ENTITY_MATERIALS_ICON; + this.entityMaterialsbinToolStripMenuItem.Name = "entityMaterialsbinToolStripMenuItem"; + resources.ApplyResources(this.entityMaterialsbinToolStripMenuItem, "entityMaterialsbinToolStripMenuItem"); + this.entityMaterialsbinToolStripMenuItem.Click += new System.EventHandler(this.entityMaterialsbinToolStripMenuItem_Click); + // + // importSkinsToolStripMenuItem + // + this.importSkinsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.importSkinToolStripMenuItem, + this.importExtractedSkinsFolderToolStripMenuItem, + this.addTextureToolStripMenuItem, + this.addFileToolStripMenuItem}); + resources.ApplyResources(this.importSkinsToolStripMenuItem, "importSkinsToolStripMenuItem"); + this.importSkinsToolStripMenuItem.Name = "importSkinsToolStripMenuItem"; + // + // importSkinToolStripMenuItem + // + resources.ApplyResources(this.importSkinToolStripMenuItem, "importSkinToolStripMenuItem"); + this.importSkinToolStripMenuItem.Name = "importSkinToolStripMenuItem"; + this.importSkinToolStripMenuItem.Click += new System.EventHandler(this.importSkinToolStripMenuItem_Click); + // + // importExtractedSkinsFolderToolStripMenuItem + // + resources.ApplyResources(this.importExtractedSkinsFolderToolStripMenuItem, "importExtractedSkinsFolderToolStripMenuItem"); + this.importExtractedSkinsFolderToolStripMenuItem.Name = "importExtractedSkinsFolderToolStripMenuItem"; + this.importExtractedSkinsFolderToolStripMenuItem.Click += new System.EventHandler(this.importExtractedSkinsFolder); + // + // addTextureToolStripMenuItem + // + this.addTextureToolStripMenuItem.Image = global::PckStudio.Properties.Resources.AddTexture; + this.addTextureToolStripMenuItem.Name = "addTextureToolStripMenuItem"; + resources.ApplyResources(this.addTextureToolStripMenuItem, "addTextureToolStripMenuItem"); + this.addTextureToolStripMenuItem.Click += new System.EventHandler(this.addTextureToolStripMenuItem_Click); + // + // addFileToolStripMenuItem + // + this.addFileToolStripMenuItem.Image = global::PckStudio.Properties.Resources.blank; + this.addFileToolStripMenuItem.Name = "addFileToolStripMenuItem"; + resources.ApplyResources(this.addFileToolStripMenuItem, "addFileToolStripMenuItem"); + this.addFileToolStripMenuItem.Click += new System.EventHandler(this.addFileToolStripMenuItem_Click); + // + // exportToolStripMenuItem + // + this.exportToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.as3DSTextureFileToolStripMenuItem}); + this.exportToolStripMenuItem.Name = "exportToolStripMenuItem"; + resources.ApplyResources(this.exportToolStripMenuItem, "exportToolStripMenuItem"); + // + // as3DSTextureFileToolStripMenuItem + // + this.as3DSTextureFileToolStripMenuItem.Name = "as3DSTextureFileToolStripMenuItem"; + resources.ApplyResources(this.as3DSTextureFileToolStripMenuItem, "as3DSTextureFileToolStripMenuItem"); + this.as3DSTextureFileToolStripMenuItem.Click += new System.EventHandler(this.as3DSTextureFileToolStripMenuItem_Click); + // + // setFileTypeToolStripMenuItem + // + this.setFileTypeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.skinToolStripMenuItem1, + this.capeToolStripMenuItem, + this.textureToolStripMenuItem, + this.languagesFileLOCToolStripMenuItem, + this.gameRulesFileGRFToolStripMenuItem, + this.audioPCKFileToolStripMenuItem, + this.coloursCOLFileToolStripMenuItem, + this.gameRulesHeaderGRHToolStripMenuItem, + this.skinsPCKToolStripMenuItem, + this.modelsFileBINToolStripMenuItem, + this.behavioursFileBINToolStripMenuItem, + this.entityMaterialsFileBINToolStripMenuItem}); + this.setFileTypeToolStripMenuItem.Name = "setFileTypeToolStripMenuItem"; + resources.ApplyResources(this.setFileTypeToolStripMenuItem, "setFileTypeToolStripMenuItem"); + // + // skinToolStripMenuItem1 + // + this.skinToolStripMenuItem1.Image = global::PckStudio.Properties.Resources.SKIN_ICON; + this.skinToolStripMenuItem1.Name = "skinToolStripMenuItem1"; + resources.ApplyResources(this.skinToolStripMenuItem1, "skinToolStripMenuItem1"); + // + // capeToolStripMenuItem + // + this.capeToolStripMenuItem.Image = global::PckStudio.Properties.Resources.CAPE_ICON; + this.capeToolStripMenuItem.Name = "capeToolStripMenuItem"; + resources.ApplyResources(this.capeToolStripMenuItem, "capeToolStripMenuItem"); + // + // textureToolStripMenuItem + // + this.textureToolStripMenuItem.Image = global::PckStudio.Properties.Resources.TEXTURE_ICON; + this.textureToolStripMenuItem.Name = "textureToolStripMenuItem"; + resources.ApplyResources(this.textureToolStripMenuItem, "textureToolStripMenuItem"); + // + // languagesFileLOCToolStripMenuItem + // + this.languagesFileLOCToolStripMenuItem.Image = global::PckStudio.Properties.Resources.LOC_ICON; + this.languagesFileLOCToolStripMenuItem.Name = "languagesFileLOCToolStripMenuItem"; + resources.ApplyResources(this.languagesFileLOCToolStripMenuItem, "languagesFileLOCToolStripMenuItem"); + // + // gameRulesFileGRFToolStripMenuItem + // + this.gameRulesFileGRFToolStripMenuItem.Image = global::PckStudio.Properties.Resources.GRF_ICON; + this.gameRulesFileGRFToolStripMenuItem.Name = "gameRulesFileGRFToolStripMenuItem"; + resources.ApplyResources(this.gameRulesFileGRFToolStripMenuItem, "gameRulesFileGRFToolStripMenuItem"); + // + // audioPCKFileToolStripMenuItem + // + this.audioPCKFileToolStripMenuItem.Image = global::PckStudio.Properties.Resources.BINKA_ICON; + this.audioPCKFileToolStripMenuItem.Name = "audioPCKFileToolStripMenuItem"; + resources.ApplyResources(this.audioPCKFileToolStripMenuItem, "audioPCKFileToolStripMenuItem"); + // + // coloursCOLFileToolStripMenuItem + // + this.coloursCOLFileToolStripMenuItem.Image = global::PckStudio.Properties.Resources.COL_ICON; + this.coloursCOLFileToolStripMenuItem.Name = "coloursCOLFileToolStripMenuItem"; + resources.ApplyResources(this.coloursCOLFileToolStripMenuItem, "coloursCOLFileToolStripMenuItem"); + // + // gameRulesHeaderGRHToolStripMenuItem + // + this.gameRulesHeaderGRHToolStripMenuItem.Image = global::PckStudio.Properties.Resources.GRH_ICON; + this.gameRulesHeaderGRHToolStripMenuItem.Name = "gameRulesHeaderGRHToolStripMenuItem"; + resources.ApplyResources(this.gameRulesHeaderGRHToolStripMenuItem, "gameRulesHeaderGRHToolStripMenuItem"); + // + // skinsPCKToolStripMenuItem + // + this.skinsPCKToolStripMenuItem.Image = global::PckStudio.Properties.Resources.SKINS_ICON; + this.skinsPCKToolStripMenuItem.Name = "skinsPCKToolStripMenuItem"; + resources.ApplyResources(this.skinsPCKToolStripMenuItem, "skinsPCKToolStripMenuItem"); + // + // modelsFileBINToolStripMenuItem + // + this.modelsFileBINToolStripMenuItem.Image = global::PckStudio.Properties.Resources.MODELS_ICON; + this.modelsFileBINToolStripMenuItem.Name = "modelsFileBINToolStripMenuItem"; + resources.ApplyResources(this.modelsFileBINToolStripMenuItem, "modelsFileBINToolStripMenuItem"); + // + // behavioursFileBINToolStripMenuItem + // + this.behavioursFileBINToolStripMenuItem.Image = global::PckStudio.Properties.Resources.BEHAVIOURS_ICON; + this.behavioursFileBINToolStripMenuItem.Name = "behavioursFileBINToolStripMenuItem"; + resources.ApplyResources(this.behavioursFileBINToolStripMenuItem, "behavioursFileBINToolStripMenuItem"); + // + // entityMaterialsFileBINToolStripMenuItem + // + this.entityMaterialsFileBINToolStripMenuItem.Image = global::PckStudio.Properties.Resources.ENTITY_MATERIALS_ICON; + this.entityMaterialsFileBINToolStripMenuItem.Name = "entityMaterialsFileBINToolStripMenuItem"; + resources.ApplyResources(this.entityMaterialsFileBINToolStripMenuItem, "entityMaterialsFileBINToolStripMenuItem"); + // + // toolStripSeparator5 + // + this.toolStripSeparator5.Name = "toolStripSeparator5"; + resources.ApplyResources(this.toolStripSeparator5, "toolStripSeparator5"); + // + // miscFunctionsToolStripMenuItem + // + this.miscFunctionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.generateMipMapTextureToolStripMenuItem1, + this.viewFileInfoToolStripMenuItem, + this.correctSkinDecimalsToolStripMenuItem, + this.setSubPCKEndiannessToolStripMenuItem, + this.setModelContainerFormatToolStripMenuItem}); + this.miscFunctionsToolStripMenuItem.Name = "miscFunctionsToolStripMenuItem"; + resources.ApplyResources(this.miscFunctionsToolStripMenuItem, "miscFunctionsToolStripMenuItem"); + // + // generateMipMapTextureToolStripMenuItem1 + // + this.generateMipMapTextureToolStripMenuItem1.Name = "generateMipMapTextureToolStripMenuItem1"; + resources.ApplyResources(this.generateMipMapTextureToolStripMenuItem1, "generateMipMapTextureToolStripMenuItem1"); + this.generateMipMapTextureToolStripMenuItem1.Click += new System.EventHandler(this.generateMipMapTextureToolStripMenuItem_Click); + // + // viewFileInfoToolStripMenuItem + // + this.viewFileInfoToolStripMenuItem.Name = "viewFileInfoToolStripMenuItem"; + resources.ApplyResources(this.viewFileInfoToolStripMenuItem, "viewFileInfoToolStripMenuItem"); + this.viewFileInfoToolStripMenuItem.Click += new System.EventHandler(this.viewFileInfoToolStripMenuItem_Click); + // + // correctSkinDecimalsToolStripMenuItem + // + this.correctSkinDecimalsToolStripMenuItem.Name = "correctSkinDecimalsToolStripMenuItem"; + resources.ApplyResources(this.correctSkinDecimalsToolStripMenuItem, "correctSkinDecimalsToolStripMenuItem"); + this.correctSkinDecimalsToolStripMenuItem.Click += new System.EventHandler(this.correctSkinDecimalsToolStripMenuItem_Click); + // + // setSubPCKEndiannessToolStripMenuItem + // + this.setSubPCKEndiannessToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.bigEndianXbox360PS3WiiUToolStripMenuItem, + this.littleEndianPS4PSVitaSwitchToolStripMenuItem}); + this.setSubPCKEndiannessToolStripMenuItem.Name = "setSubPCKEndiannessToolStripMenuItem"; + resources.ApplyResources(this.setSubPCKEndiannessToolStripMenuItem, "setSubPCKEndiannessToolStripMenuItem"); + // + // bigEndianXbox360PS3WiiUToolStripMenuItem + // + this.bigEndianXbox360PS3WiiUToolStripMenuItem.Name = "bigEndianXbox360PS3WiiUToolStripMenuItem"; + resources.ApplyResources(this.bigEndianXbox360PS3WiiUToolStripMenuItem, "bigEndianXbox360PS3WiiUToolStripMenuItem"); + this.bigEndianXbox360PS3WiiUToolStripMenuItem.Click += new System.EventHandler(this.bigEndianToolStripMenuItem_Click); + // + // littleEndianPS4PSVitaSwitchToolStripMenuItem + // + this.littleEndianPS4PSVitaSwitchToolStripMenuItem.Name = "littleEndianPS4PSVitaSwitchToolStripMenuItem"; + resources.ApplyResources(this.littleEndianPS4PSVitaSwitchToolStripMenuItem, "littleEndianPS4PSVitaSwitchToolStripMenuItem"); + this.littleEndianPS4PSVitaSwitchToolStripMenuItem.Click += new System.EventHandler(this.littleEndianToolStripMenuItem_Click); + // + // setModelContainerFormatToolStripMenuItem + // + this.setModelContainerFormatToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.version1ToolStripMenuItem, + this.version2ToolStripMenuItem, + this.version3114ToolStripMenuItem}); + this.setModelContainerFormatToolStripMenuItem.Name = "setModelContainerFormatToolStripMenuItem"; + resources.ApplyResources(this.setModelContainerFormatToolStripMenuItem, "setModelContainerFormatToolStripMenuItem"); + // + // version1ToolStripMenuItem + // + this.version1ToolStripMenuItem.Name = "version1ToolStripMenuItem"; + resources.ApplyResources(this.version1ToolStripMenuItem, "version1ToolStripMenuItem"); + this.version1ToolStripMenuItem.Click += new System.EventHandler(this.setModelVersion1ToolStripMenuItem_Click); + // + // version2ToolStripMenuItem + // + this.version2ToolStripMenuItem.Name = "version2ToolStripMenuItem"; + resources.ApplyResources(this.version2ToolStripMenuItem, "version2ToolStripMenuItem"); + this.version2ToolStripMenuItem.Click += new System.EventHandler(this.setModelVersion2ToolStripMenuItem_Click); + // + // version3114ToolStripMenuItem + // + this.version3114ToolStripMenuItem.Name = "version3114ToolStripMenuItem"; + resources.ApplyResources(this.version3114ToolStripMenuItem, "version3114ToolStripMenuItem"); + this.version3114ToolStripMenuItem.Click += new System.EventHandler(this.setModelVersion3ToolStripMenuItem_Click); + // + // extractToolStripMenuItem + // + resources.ApplyResources(this.extractToolStripMenuItem, "extractToolStripMenuItem"); + this.extractToolStripMenuItem.Name = "extractToolStripMenuItem"; + this.extractToolStripMenuItem.Click += new System.EventHandler(this.extractToolStripMenuItem_Click); + // + // toolStripSeparator6 + // + this.toolStripSeparator6.Name = "toolStripSeparator6"; + resources.ApplyResources(this.toolStripSeparator6, "toolStripSeparator6"); + // + // cloneFileToolStripMenuItem + // + this.cloneFileToolStripMenuItem.Name = "cloneFileToolStripMenuItem"; + resources.ApplyResources(this.cloneFileToolStripMenuItem, "cloneFileToolStripMenuItem"); + this.cloneFileToolStripMenuItem.Click += new System.EventHandler(this.cloneFileToolStripMenuItem_Click); + // + // renameFileToolStripMenuItem + // + resources.ApplyResources(this.renameFileToolStripMenuItem, "renameFileToolStripMenuItem"); + this.renameFileToolStripMenuItem.Name = "renameFileToolStripMenuItem"; + this.renameFileToolStripMenuItem.Click += new System.EventHandler(this.renameFileToolStripMenuItem_Click); + // + // replaceToolStripMenuItem + // + resources.ApplyResources(this.replaceToolStripMenuItem, "replaceToolStripMenuItem"); + this.replaceToolStripMenuItem.Name = "replaceToolStripMenuItem"; + this.replaceToolStripMenuItem.Click += new System.EventHandler(this.replaceToolStripMenuItem_Click); + // + // deleteFileToolStripMenuItem + // + this.deleteFileToolStripMenuItem.Image = global::PckStudio.Properties.Resources.file_delete; + this.deleteFileToolStripMenuItem.Name = "deleteFileToolStripMenuItem"; + resources.ApplyResources(this.deleteFileToolStripMenuItem, "deleteFileToolStripMenuItem"); + this.deleteFileToolStripMenuItem.Click += new System.EventHandler(this.deleteFileToolStripMenuItem_Click); + // + // imageList + // + this.imageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit; + resources.ApplyResources(this.imageList, "imageList"); + this.imageList.TransparentColor = System.Drawing.Color.Transparent; + // + // addMultipleEntriesToolStripMenuItem + // + resources.ApplyResources(this.addMultipleEntriesToolStripMenuItem, "addMultipleEntriesToolStripMenuItem"); + this.addMultipleEntriesToolStripMenuItem.Name = "addMultipleEntriesToolStripMenuItem"; + // + // LittleEndianCheckBox + // + resources.ApplyResources(this.LittleEndianCheckBox, "LittleEndianCheckBox"); + this.LittleEndianCheckBox.BackColor = System.Drawing.Color.Transparent; + this.LittleEndianCheckBox.Name = "LittleEndianCheckBox"; + this.LittleEndianCheckBox.Style = MetroFramework.MetroColorStyle.White; + this.LittleEndianCheckBox.Theme = MetroFramework.MetroThemeStyle.Dark; + this.LittleEndianCheckBox.UseSelectable = true; + // + // previewPictureBox + // + resources.ApplyResources(this.previewPictureBox, "previewPictureBox"); + this.previewPictureBox.BackColor = System.Drawing.Color.Transparent; + this.previewPictureBox.BackgroundInterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default; + this.previewPictureBox.Image = global::PckStudio.Properties.Resources.NoImageFound; + this.previewPictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; + this.previewPictureBox.Name = "previewPictureBox"; + this.previewPictureBox.TabStop = false; + // + // PckEditor + // + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(18)))), ((int)(((byte)(18)))), ((int)(((byte)(18))))); + resources.ApplyResources(this, "$this"); + this.Controls.Add(this.previewPictureBox); + this.Controls.Add(this.LittleEndianCheckBox); + this.Controls.Add(this.pckFileLabel); + this.Controls.Add(this.labelImageSize); + this.Controls.Add(this.fileEntryCountLabel); + this.Controls.Add(this.PropertiesTabControl); + this.Controls.Add(this.label11); + this.Controls.Add(this.treeViewMain); + this.Controls.Add(logoPictureBox); + this.ForeColor = System.Drawing.Color.Transparent; + this.Name = "PckEditor"; + this.Load += new System.EventHandler(this.PckEditor_Load); + ((System.ComponentModel.ISupportInitialize)(logoPictureBox)).EndInit(); + this.PropertiesTabControl.ResumeLayout(false); + this.MetaTab.ResumeLayout(false); + this.MetaTab.PerformLayout(); + this.contextMenuMetaTree.ResumeLayout(false); + this.contextMenuPCKEntries.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.previewPictureBox)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private MetroFramework.Controls.MetroLabel pckFileLabel; + private MetroFramework.Controls.MetroLabel labelImageSize; + private MetroFramework.Controls.MetroLabel fileEntryCountLabel; + private MetroFramework.Controls.MetroTabControl PropertiesTabControl; + private MetroFramework.Controls.MetroTabPage MetaTab; + private System.Windows.Forms.TreeView treeMeta; + private MetroFramework.Controls.MetroLabel label11; + private System.Windows.Forms.TreeView treeViewMain; + private PckStudio.ToolboxItems.InterpolationPictureBox previewPictureBox; + private System.Windows.Forms.ContextMenuStrip contextMenuMetaTree; + private System.Windows.Forms.ToolStripMenuItem addEntryToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem addEntryToolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem addBOXEntryToolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem addANIMEntryToolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem addMultipleEntriesToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem deleteEntryToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem editAllEntriesToolStripMenuItem; + private System.Windows.Forms.ContextMenuStrip contextMenuPCKEntries; + private System.Windows.Forms.ToolStripMenuItem createToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem folderToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem skinToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem createAnimatedTextureToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem audiopckToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem colourscolToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem CreateSkinsPCKToolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem behavioursbinToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem entityMaterialsbinToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem importSkinsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem importSkinToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem importExtractedSkinsFolderToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem addTextureToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem addFileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem exportToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem as3DSTextureFileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem setFileTypeToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem skinToolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem capeToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem textureToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem languagesFileLOCToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem gameRulesFileGRFToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem audioPCKFileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem coloursCOLFileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem gameRulesHeaderGRHToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem skinsPCKToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem modelsFileBINToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem behavioursFileBINToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem entityMaterialsFileBINToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem miscFunctionsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem generateMipMapTextureToolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem viewFileInfoToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem correctSkinDecimalsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem extractToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem cloneFileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem renameFileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem replaceToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem deleteFileToolStripMenuItem; + private System.Windows.Forms.ImageList imageList; + private System.Windows.Forms.ToolStripMenuItem addMultipleEntriesToolStripMenuItem1; + private MetroFramework.Controls.MetroLabel metroLabel2; + private MetroFramework.Controls.MetroTextBox entryTypeTextBox; + private MetroFramework.Controls.MetroTextBox entryDataTextBox; + private MetroFramework.Controls.MetroButton buttonEdit; + private MetroFramework.Controls.MetroLabel metroLabel1; + private MetroFramework.Controls.MetroCheckBox LittleEndianCheckBox; + private System.Windows.Forms.ToolStripMenuItem setSubPCKEndiannessToolStripMenuItem; + private ToolStripMenuItem bigEndianXbox360PS3WiiUToolStripMenuItem; + private ToolStripMenuItem littleEndianPS4PSVitaSwitchToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem setModelContainerFormatToolStripMenuItem; + private ToolStripMenuItem version1ToolStripMenuItem; + private ToolStripMenuItem version2ToolStripMenuItem; + private ToolStripMenuItem version3114ToolStripMenuItem; + private ToolStripSeparator toolStripSeparator5; + private ToolStripSeparator toolStripSeparator6; + } +} diff --git a/PCK-Studio/Controls/PckEditor.cs b/PCK-Studio/Controls/PckEditor.cs new file mode 100644 index 00000000..dc461bac --- /dev/null +++ b/PCK-Studio/Controls/PckEditor.cs @@ -0,0 +1,2251 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using System.Drawing.Drawing2D; + +using MetroFramework.Forms; + +using OMI.Formats.Languages; +using OMI.Formats.Pck; +using OMI.Workers.Language; +using OMI.Workers.Pck; + +using OMI.Workers; +using OMI.Formats.Model; +using OMI.Workers.Model; +using OMI.Formats.GameRule; +using OMI.Workers.GameRule; +using OMI.Formats.Material; +using OMI.Workers.Material; +using OMI.Formats.Behaviour; +using OMI.Workers.Behaviour; +using OMI.Formats.Color; +using OMI.Workers.Color; + +using PckStudio.Core.Extensions; +using PckStudio.Forms.Editor; +using PckStudio.Forms.Additional_Popups; +using PckStudio.Forms.Additional_Popups.Animation; +using PckStudio.Interfaces; +using PckStudio.Internal; +using PckStudio.Popups; +using PckStudio.Properties; + +using PckStudio.Core.Deserializer; +using PckStudio.Core.Serializer; +using PckStudio.Core.Json; +using PckStudio.Core.FileFormats; +using PckStudio.Core.Skin; +using PckStudio.Rendering; +using PckStudio.Core; +using PckStudio.ModelSupport; +using PckStudio.Json; +using PckStudio.Core.IO.PckAudio; +using PckStudio.Core.IO._3DST; +using PckStudio.Core.Misc; + +namespace PckStudio.Controls +{ + internal partial class PckEditor : EditorControl + { + + private string _location = string.Empty; + + private readonly OMI.ByteOrder _originalEndianness; + private OMI.ByteOrder _currentEndianness; + private bool __modified = false; + private bool _wasModified + { + get => __modified; + set + { + if (__modified != value) + { + __modified = value; + _onModifiedChangeDelegate?.Invoke(value); + } + } + } + + private delegate void OnModifiedChangeDelegate(bool state); + private OnModifiedChangeDelegate _onModifiedChangeDelegate; + + private int _timesSaved = 0; + + private readonly Dictionary> _pckAssetTypeHandler; + + public PckEditor(PackInfo packInfo, ISaveContext saveContext) + : base(packInfo, saveContext) + { + InitializeComponent(); + _onModifiedChangeDelegate = OnModify; + _originalEndianness = packInfo.Endianness; + _currentEndianness = packInfo.Endianness; + + LittleEndianCheckBox.Visible = packInfo.AllowEndianSwap; + + treeViewMain.TreeViewNodeSorter = new PckNodeSorter(); + + skinToolStripMenuItem1.Click += (sender, e) => SetFileType(PckAssetType.SkinFile); + capeToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.CapeFile); + textureToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.TextureFile); + languagesFileLOCToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.LocalisationFile); + gameRulesFileGRFToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.GameRulesFile); + audioPCKFileToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.AudioFile); + coloursCOLFileToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.ColourTableFile); + gameRulesHeaderGRHToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.GameRulesHeader); + skinsPCKToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.SkinDataFile); + modelsFileBINToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.ModelsFile); + behavioursFileBINToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.BehavioursFile); + entityMaterialsFileBINToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.MaterialFile); + + imageList.Images.Add(Resources.ZZFolder); // Icon for folders + imageList.Images.Add(Resources.BINKA_ICON); // Icon for music cue file (audio.pck) + imageList.Images.Add(Resources.IMAGE_ICON); // Icon for images (unused for now) + imageList.Images.Add(Resources.LOC_ICON); // Icon for string localization files (languages.loc;localisation.loc) + imageList.Images.Add(Resources.PCK_ICON); // Icon for generic PCK files (*.pck) + imageList.Images.Add(Resources.ZUnknown); // Icon for Unknown formats + imageList.Images.Add(Resources.COL_ICON); // Icon for color palette files (colours.col) + imageList.Images.Add(Resources.SKINS_ICON); // Icon for Skin.pck archives (skins.pck) + imageList.Images.Add(Resources.MODELS_ICON); // Icon for Model files (models.bin) + imageList.Images.Add(Resources.GRF_ICON); // Icon for Game Rule files (*.grf) + imageList.Images.Add(Resources.GRH_ICON); // Icon for Game Rule Header files (*.grh) + imageList.Images.Add(Resources.INFO_ICON); // Icon for Info files (0) + imageList.Images.Add(Resources.SKIN_ICON); // Icon for Skin files (*.png) + imageList.Images.Add(Resources.CAPE_ICON); // Icon for Cape files (*.png) + imageList.Images.Add(Resources.TEXTURE_ICON); // Icon for Texture files (*.png;*.tga) + imageList.Images.Add(Resources.BEHAVIOURS_ICON); // Icon for Behaviour files (behaviours.bin) + imageList.Images.Add(Resources.ENTITY_MATERIALS_ICON); // Icon for Entity Material files (entityMaterials.bin) + + _pckAssetTypeHandler = new Dictionary>(15) + { + [PckAssetType.SkinFile] = HandleSkinFile, + [PckAssetType.CapeFile] = null, + [PckAssetType.TextureFile] = HandleTextureFile, + [PckAssetType.UIDataFile] = _ => throw new NotSupportedException("unused in-game"), + [PckAssetType.InfoFile] = null, + [PckAssetType.TexturePackInfoFile] = HandleInnerPckFile, + [PckAssetType.LocalisationFile] = HandleLocalisationFile, + [PckAssetType.GameRulesFile] = HandleGameRuleFile, + [PckAssetType.AudioFile] = HandleAudioFile, + [PckAssetType.ColourTableFile] = HandleColourFile, + [PckAssetType.GameRulesHeader] = HandleGameRuleFile, + [PckAssetType.SkinDataFile] = HandleInnerPckFile, + [PckAssetType.ModelsFile] = HandleModelsFile, + [PckAssetType.BehavioursFile] = HandleBehavioursFile, + [PckAssetType.MaterialFile] = HandleMaterialFile, + }; + } + + public new void Save() + { + base.Save(); + _timesSaved++; + _wasModified = false; + } + + public override void SaveAs() + { + using SaveFileDialog saveFileDialog = new SaveFileDialog + { + Filter = "PCK (Minecraft Console Package)|*.pck", + DefaultExt = ".pck", + }; + if (saveFileDialog.ShowDialog() == DialogResult.OK) + { + SaveTo(saveFileDialog.FileName); + pckFileLabel.Text = "Current PCK File: " + Path.GetFileName(_location); + } + } + + public override void Close() + { + if (_wasModified && MessageBox.Show("Save PCK?", "Modified PCK", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) + Save(); + } + + private void OnModify(bool state) + { + pckFileLabel.Text = state && !pckFileLabel.Text.StartsWith("*") ? "*" + pckFileLabel.Text : pckFileLabel.Text.Substring(1); + } + + public override void UpdateView() + { + BuildMainTreeView(); + } + + private void SaveTo(string filepath) + { + _location = filepath; + Save(); + } + + private void HandleInnerPckFile(PckAsset asset) + { + if (asset.Type != PckAssetType.SkinDataFile && asset.Type != PckAssetType.TexturePackInfoFile || asset.Size <= 0 || !Settings.Default.LoadSubPcks) + return; + + ISaveContext saveContext = new DelegatedSaveContext(false, (packInfo) => + { + if (packInfo.IsValid) + { + asset.SetData(new PckFileWriter(packInfo.File, _currentEndianness)); + _wasModified = true; + } + }); + + string caption = Path.GetFileName(asset.Filename); + string identifier = _location + Path.GetFileName(asset.Filename); + PckFile pckFile = asset.GetData(new PckFileReader(_originalEndianness)); + PackInfo packInfo = PackInfo.Create(pckFile, _originalEndianness, false); + + // TODO: may change to use a new tab page that will be closed when the main pck is closed + //Program.MainInstance.OpenNewPckTab(caption, identifier, packInfo, saveContext); + } + + private void HandleTextureFile(PckAsset asset) + { + _ = asset.IsMipmappedFile() && EditorValue.File.TryGetAsset(asset.GetNormalPath(), PckAssetType.TextureFile, out asset); + + if (asset.Size <= 0) + { + Trace.TraceInformation($"[{nameof(PckEditor)}:{nameof(HandleTextureFile)}] '{asset.Filename}' size is 0."); + return; + } + + ResourceLocation resourceLocation = ResourceLocation.GetFromPath(asset.Filename); + Debug.WriteLine("Handling Resource file: " + resourceLocation?.ToString()); + + switch (resourceLocation.Category) + { + case ResourceCategory.Unknown: + Debug.WriteLine($"Unknown Resource Category."); + break; + case ResourceCategory.MobEntityTextures: + case ResourceCategory.ItemEntityTextures: + { + string texturePath = asset.Filename.Substring(0, asset.Filename.Length - Path.GetExtension(asset.Filename).Length); + string[] modelNames = GameModelImporter.ModelMetaData.Where(kv => kv.Value.TextureLocations.Contains(texturePath)).Select(kv => kv.Key).ToArray(); + + if (modelNames.Length == 0) + { + MessageBox.Show("No Model info found"); + return; + } + + string modelName = modelNames[0]; + if (modelNames.Length > 1) + { + using ItemSelectionPopUp itemSelectionPopUp = new ItemSelectionPopUp(modelNames.ToArray()); + itemSelectionPopUp.ButtonText = "View"; + itemSelectionPopUp.LabelText = "Models:"; + if (itemSelectionPopUp.ShowDialog() != DialogResult.OK || !modelNames.IndexInRange(itemSelectionPopUp.SelectedIndex)) + { + return; + } + modelName = modelNames[itemSelectionPopUp.SelectedIndex]; + } + + Image texture = asset.GetTexture(); + string textureName = Path.GetFileName(texturePath); + + NamedData modelTexture = new NamedData(textureName, texture); + + bool hasCustomModel = false; + bool hasDefaultModel = TryGetDefaultEntityModel(modelName, out Model model); + if (EditorValue.File.TryGetAsset("models.bin", PckAssetType.ModelsFile, out PckAsset modelsAsset)) + { + ModelContainer models = modelsAsset.GetData(new ModelFileReader()); + hasCustomModel = models.ContainsModel(modelName); + if (hasCustomModel) + { + Debug.WriteLine($"Custom model for '{modelName}' found."); + model = models.GetModelByName(modelName); + } + } + if (!hasDefaultModel && !hasCustomModel) + { + MessageBox.Show(this, $"Not Model found for: {modelName}"); + return; + } + + ShowSimpleModelRender(model, modelTexture); + } + break; + + case ResourceCategory.ItemAnimation: + case ResourceCategory.BlockAnimation: + Animation animation = asset.GetDeserializedData(AnimationDeserializer.DefaultDeserializer); + string internalName = Path.GetFileNameWithoutExtension(asset.Filename); + IList textureInfos = resourceLocation.Category == ResourceCategory.ItemAnimation ? Tiles.ItemTileInfos : Tiles.BlockTileInfos; + string displayname = textureInfos.FirstOrDefault(p => p.InternalName == internalName)?.DisplayName ?? internalName; + + string[] specialTileNames = { "clock", "compass" }; + + ISaveContext saveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (animation) => + { + asset.SetSerializedData(animation, AnimationSerializer.DefaultSerializer); + }); + + using (AnimationEditor animationEditor = new AnimationEditor(animation, saveContext, displayname, !internalName.ToLower().EqualsAny(specialTileNames))) + { + if (animationEditor.ShowDialog(this) == DialogResult.OK) + { + _wasModified = true; + BuildMainTreeView(); + } + } + break; + case ResourceCategory.ParticleAtlas: + case ResourceCategory.MoonPhaseAtlas: + case ResourceCategory.ItemAtlas: + case ResourceCategory.BlockAtlas: + case ResourceCategory.BannerAtlas: + case ResourceCategory.PaintingAtlas: + case ResourceCategory.ExplosionAtlas: + case ResourceCategory.ExperienceOrbAtlas: + case ResourceCategory.MapIconAtlas: + case ResourceCategory.AdditionalMapIconsAtlas: + Atlas atlas = asset.GetDeserializedData(new AtlasDeserializer(resourceLocation)); + ColorContainer colorContainer = default; + if (EditorValue.File.TryGetAsset("colours.col", PckAssetType.ColourTableFile, out PckAsset colAsset)) + colorContainer = colAsset.GetData(new COLFileReader()); + + ITryGet tryGetAnimation = TryGet.FromDelegate((string key, out Animation animation) => + { + bool found = EditorValue.File.TryGetAsset(key + ".png", PckAssetType.TextureFile, out PckAsset foundAsset) || + EditorValue.File.TryGetAsset(key + ".tga", PckAssetType.TextureFile, out foundAsset); + if (found) + { + animation = foundAsset.GetDeserializedData(AnimationDeserializer.DefaultDeserializer); + return true; + } + animation = default; + return false; + }); + + ITryGet> tryGetAnimationSaveContext = TryGet> + .FromDelegate((string key, out ISaveContext animationSaveContext) => + { + bool found = EditorValue.File.TryGetAsset(key + ".png", PckAssetType.TextureFile, out PckAsset foundAsset) || + EditorValue.File.TryGetAsset(key + ".tga", PckAssetType.TextureFile, out foundAsset); + + if (found) + { + animationSaveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (animation) => + foundAsset.SetSerializedData(animation, AnimationSerializer.DefaultSerializer)); + return true; + } + + // you could validate the key(animationAssetPath) for validity. -miku + animationSaveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (animation) => + { + if (animation.FrameCount == 0) + { + Debug.WriteLine("New animation has 0 frames. Aborting saving."); + return; + } + PckAsset newAnimationAsset = EditorValue.File.CreateNewAsset(key + ".png", PckAssetType.TextureFile); + newAnimationAsset.SetSerializedData(animation, AnimationSerializer.DefaultSerializer); + BuildMainTreeView(); + }); + return true; + }); + + ISaveContext textureAtlasSaveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, atlas => asset.SetTexture(atlas)); + + var viewer = new TextureAtlasEditor(atlas, textureAtlasSaveContext, resourceLocation, colorContainer, tryGetAnimation, tryGetAnimationSaveContext); + if (viewer.ShowDialog(this) == DialogResult.OK) + { + _wasModified = true; + BuildMainTreeView(); + } + break; + default: + Debug.WriteLine($"Unhandled Resource Category: {resourceLocation.Category}"); + break; + } + } + + private void HandleGameRuleFile(PckAsset asset) + { + const string cDEFLATE = "PS3"; + const string cXMEM = "Xbox 360"; + const string cZLIB = "Other Platforms"; + + ItemSelectionPopUp dialog = new ItemSelectionPopUp(cZLIB, cDEFLATE, cXMEM); + dialog.LabelText = "Type"; + dialog.ButtonText = "Ok"; + if (dialog.ShowDialog() != DialogResult.OK) + return; + + GameRuleFile.CompressionType compressiontype = dialog.SelectedItem switch + { + cDEFLATE => GameRuleFile.CompressionType.Deflate, + cXMEM => GameRuleFile.CompressionType.XMem, + cZLIB => GameRuleFile.CompressionType.Zlib, + _ => GameRuleFile.CompressionType.Unknown + }; + + GameRuleFile grf = asset.GetData(new GameRuleFileReader(compressiontype)); + + ISaveContext saveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (gameRuleFile) => + { + asset.SetData(new GameRuleFileWriter(gameRuleFile)); + }); + + using GameRuleFileEditor grfEditor = new GameRuleFileEditor(grf, saveContext); + if (grfEditor.ShowDialog(this) == DialogResult.OK) + { + _wasModified = true; + UpdateRichPresence(); + } + } + + private void HandleAudioFile(PckAsset asset) + { + try + { + ISaveContext saveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (audioFile) => + { + asset.SetData(new PckAudioFileWriter(audioFile, _currentEndianness)); + }); + PckAudioFile audioFile = asset.GetData(new PckAudioFileReader(_originalEndianness)); + using AudioEditor audioEditor = new AudioEditor(audioFile, saveContext); + _wasModified = audioEditor.ShowDialog(this) == DialogResult.OK; + } + catch (OverflowException) + { + MessageBox.Show(this, $"Failed to open {asset.Filename}\n" + + "Try converting the file by using the \"Misc. Functions/Set PCK Endianness\" tool and try again.", + "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + catch (Exception ex) + { + MessageBox.Show($"Failed to open {asset.Filename}\n" + ex.Message, + "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void HandleLocalisationFile(PckAsset asset) + { + LOCFile locFile = asset.GetData(new LOCFileReader()); + ISaveContext saveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (locFile) => + { + asset.SetData(new LOCFileWriter(locFile, 2)); + }); + using LOCEditor locedit = new LOCEditor(locFile, saveContext); + _wasModified = locedit.ShowDialog(this) == DialogResult.OK; + UpdateRichPresence(); + } + + private void HandleColourFile(PckAsset asset) + { + ColorContainer colorContainer = asset.GetData(new COLFileReader()); + ISaveContext saveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (colorContainer) => + { + asset.SetData(new COLFileWriter(colorContainer)); + }); + using COLEditor diag = new COLEditor(colorContainer, saveContext); + _wasModified = diag.ShowDialog(this) == DialogResult.OK; + } + + private void HandleSkinFile(PckAsset asset) + { + Skin skin = asset.GetSkin(); + if (asset.HasProperty("CAPEPATH")) + { + string capeAssetPath = asset.GetProperty("CAPEPATH"); + if (EditorValue.File.TryGetAsset(capeAssetPath, PckAssetType.CapeFile, out PckAsset capeAsset)) + { + skin.CapeTexture = capeAsset.GetTexture(); + } + } + + ISaveContext saveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (customSkin) => + { + if (!TryGetLocFile(out LOCFile locFile)) + Debug.WriteLine("Failed to aquire loc file."); + asset.SetSkin(customSkin, locFile); + }); + + using CustomSkinEditor skinEditor = new CustomSkinEditor(skin, saveContext, EditorValue.File.HasVerionString); + if (skinEditor.ShowDialog() == DialogResult.OK) + { + entryDataTextBox.Text = entryTypeTextBox.Text = string.Empty; + _wasModified = true; + ReloadMetaTreeView(); + } + } + + private void HandleModelsFile(PckAsset asset) + { + ModelContainer modelContainer = asset.GetData(new ModelFileReader()); + if (modelContainer.ModelCount == 0) + { + MessageBox.Show("No models found.", "Empty Model file", MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + TryGetDelegate tryGetTexture = (string path, out Image img) => + { + bool found = EditorValue.File.TryGetAsset(path + ".png", PckAssetType.TextureFile, out PckAsset asset) || + EditorValue.File.TryGetAsset(path + ".tga", PckAssetType.TextureFile, out asset); + img = found ? asset.GetTexture() : default; + return found; + }; + + TrySetDelegate trySetTexture = (string path, Image img) => + { + bool found = EditorValue.File.TryGetAsset(path + ".png", PckAssetType.TextureFile, out PckAsset foundAsset) || + EditorValue.File.TryGetAsset(path + ".tga", PckAssetType.TextureFile, out foundAsset); + PckAsset asset = foundAsset ?? EditorValue.File.CreateNewAsset(path + ".png", PckAssetType.TextureFile); + asset.SetTexture(img); + return true; + }; + + bool hasMaterialAsset = EditorValue.File.TryGetAsset("entityMaterials.bin", PckAssetType.MaterialFile, out PckAsset entityMaterialAsset); + IReadOnlyDictionary entityMaterials = + hasMaterialAsset + ? entityMaterialAsset?.GetData(new MaterialFileReader()).ToDictionary(mat => mat.Name) + : new Dictionary(); + + ISaveContext saveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (modelContainer) => + { + asset.SetData(new ModelFileWriter(modelContainer, modelContainer.Version)); + }); + + var editor = new ModelEditor(modelContainer, saveContext, TryGetSet.FromDelegates(tryGetTexture, trySetTexture), TryGet.FromDelegate(entityMaterials.TryGetValue)); + if (editor.ShowDialog() == DialogResult.OK) + { + BuildMainTreeView(); + _wasModified = true; + return; + } + } + + private void HandleBehavioursFile(PckAsset asset) + { + BehaviourFile behaviourFile = asset.GetData(new BehavioursReader()); + ISaveContext saveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (behaviourFile) => + { + asset.SetData(new BehavioursWriter(behaviourFile)); + }); + using BehaviourEditor edit = new BehaviourEditor(behaviourFile, saveContext); + _wasModified = edit.ShowDialog(this) == DialogResult.OK; + } + + private void HandleMaterialFile(PckAsset asset) + { + MaterialContainer materials = asset.GetData(new MaterialFileReader()); + ISaveContext saveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (materials) => + { + asset.SetData(new MaterialFileWriter(materials)); + }); + using MaterialsEditor edit = new MaterialsEditor(materials, saveContext); + _wasModified = edit.ShowDialog(this) == DialogResult.OK; + } + + private void CheckForPasswordAndRemove() + { + if (EditorValue.File.TryGetAsset("0", PckAssetType.InfoFile, out PckAsset asset)) + { + asset.RemoveProperties("LOCK"); + } + } + + /// + /// wrapper that allows the use of in TreeNode.Nodes.Find(, ...) and TreeNode.Nodes.ContainsKey() + /// + /// + /// + /// new Created TreeNode + private static TreeNode CreateNode(string name, object tag = null) + { + TreeNode node = new TreeNode(name); + node.Name = name; + node.Tag = tag; + return node; + } + + private TreeNode BuildNodeTreeBySeperator(TreeNodeCollection root, string path, char seperator) + { + _ = root ?? throw new ArgumentNullException(nameof(root)); + if (!path.Contains(seperator)) + { + TreeNode finalNode = CreateNode(path); + root.Add(finalNode); + return finalNode; + } + string nodeText = path.Substring(0, path.IndexOf(seperator)); + string subPath = path.Substring(path.IndexOf(seperator) + 1); + + if (string.IsNullOrWhiteSpace(nodeText)) + { + return BuildNodeTreeBySeperator(root, subPath, seperator); + } + + bool alreadyExists = root.ContainsKey(nodeText); + TreeNode subNode = alreadyExists ? root[nodeText] : CreateNode(nodeText); + if (!alreadyExists) + root.Add(subNode); + return BuildNodeTreeBySeperator(subNode.Nodes, subPath, seperator); + } + + private void BuildPckTreeView(TreeNodeCollection root, PckFile pckFile) + { + foreach (PckAsset asset in pckFile.GetAssets()) + { + TreeNode node = BuildNodeTreeBySeperator(root, asset.Filename, '/'); + node.Tag = asset; + int nodeIconId = GetNodeIconId(asset.Type); + node.ImageIndex = nodeIconId; + node.SelectedImageIndex = nodeIconId; + } + } + + private void BuildMainTreeView() + { + // In case the Rename function was just used and the selected node name no longer matches the file name + string selectedNodeText = treeViewMain.SelectedNode is TreeNode node ? node.FullPath : string.Empty; + previewPictureBox.Image = Resources.NoImageFound; + treeMeta.Nodes.Clear(); + treeViewMain.Nodes.Clear(); + BuildPckTreeView(treeViewMain.Nodes, EditorValue.File); + treeViewMain.Sort(); + + TreeNode[] selectedNodes = treeViewMain.FindPath(selectedNodeText); + if (selectedNodes.Length > 0) + { + treeViewMain.SelectedNode = selectedNodes[0]; + } + } + + private int GetNodeIconId(PckAssetType type) + { + return type switch + { + PckAssetType.AudioFile => 1, + PckAssetType.LocalisationFile => 3, + PckAssetType.TexturePackInfoFile => 4, + PckAssetType.ColourTableFile => 6, + PckAssetType.ModelsFile => 8, + PckAssetType.SkinDataFile => 7, + PckAssetType.GameRulesFile => 9, + PckAssetType.GameRulesHeader => 10, + PckAssetType.InfoFile => 11, + PckAssetType.SkinFile => 12, + PckAssetType.CapeFile => 13, + PckAssetType.TextureFile => 14, + PckAssetType.BehavioursFile => 15, + PckAssetType.MaterialFile => 16, + // unknown file format + _ => 5, + }; + } + + private List GetAllChildNodes(TreeNodeCollection root) + { + List childNodes = new List(); + foreach (TreeNode node in root) + { + childNodes.Add(node); + if (node.Nodes.Count > 0) + { + childNodes.AddRange(GetAllChildNodes(node.Nodes)); + } + } + return childNodes; + } + + private bool TryGetLocFile(out LOCFile locFile) + { + if (!EditorValue.File.TryGetAsset("localisation.loc", PckAssetType.LocalisationFile, out PckAsset locAsset) && + !EditorValue.File.TryGetAsset("languages.loc", PckAssetType.LocalisationFile, out locAsset)) + { + locFile = null; + return false; + } + + try + { + locFile = locAsset.GetData(new LOCFileReader()); + return true; + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + } + locFile = null; + return false; + } + + private bool TrySetLocFile(in LOCFile locFile) + { + if (!EditorValue.File.TryGetAsset("localisation.loc", PckAssetType.LocalisationFile, out PckAsset locAsset) && + !EditorValue.File.TryGetAsset("languages.loc", PckAssetType.LocalisationFile, out locAsset)) + { + return false; + } + + try + { + locAsset.SetData(new LOCFileWriter(locFile, 2)); + return true; + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + } + return false; + } + + private void ReloadMetaTreeView() + { + treeMeta.Nodes.Clear(); + if (treeViewMain.SelectedNode is TreeNode node && + node.Tag is PckAsset asset) + { + foreach (KeyValuePair property in asset.GetProperties()) + { + treeMeta.Nodes.Add(CreateNode(property.Key, property)); + } + } + } + + private void UpdateRichPresence() + { + if (EditorValue is not null && + TryGetLocFile(out LOCFile locfile) && + locfile.HasLocEntry("IDS_DISPLAY_NAME") && + locfile.Languages.Contains("en-EN")) + { + RPC.SetPresence("Editing a Pack:", $" > {locfile.GetLocEntry("IDS_DISPLAY_NAME", "en-EN")}"); + return; + } + // default + RPC.SetPresence("An Open Source .PCK File Editor"); + } + + private static PckAsset CreateNewAudioAsset(bool isLittle, PckAudioFile audioFile) + { + PckAsset newAsset = new PckAsset("audio.pck", PckAssetType.AudioFile); + newAsset.SetData(new PckAudioFileWriter(audioFile, isLittle ? OMI.ByteOrder.LittleEndian : OMI.ByteOrder.BigEndian)); + return newAsset; + } + + private static PckAudioFile CreateNewAudioFile() + { + PckAudioFile audioFile = new PckAudioFile(); + audioFile.AddCategory(PckAudioFile.AudioCategory.EAudioType.Overworld); + audioFile.AddCategory(PckAudioFile.AudioCategory.EAudioType.Nether); + audioFile.AddCategory(PckAudioFile.AudioCategory.EAudioType.End); + return audioFile; + } + + private void addFileToolStripMenuItem_Click(object sender, EventArgs e) + { + using var ofd = new OpenFileDialog(); + // Suddenly, and randomly, this started throwing an exception because it wasn't formatted correctly? + // So now it's formatted correctly and now displays the file type name in the dialog. + ofd.Filter = "All files (*.*)|*.*"; + ofd.Multiselect = false; + + if (ofd.ShowDialog(this) == DialogResult.OK) + { + using AddFilePrompt diag = new AddFilePrompt("res/" + Path.GetFileName(ofd.FileName)); + if (diag.ShowDialog(this) == DialogResult.OK) + { + if (EditorValue.File.Contains(diag.Filepath, diag.Filetype)) + { + MessageBox.Show(this, $"'{diag.Filepath}' of type {diag.Filetype} already exists.", "Import failed", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + PckAsset asset = EditorValue.File.CreateNewAsset(diag.Filepath, diag.Filetype, () => File.ReadAllBytes(ofd.FileName)); + + BuildMainTreeView(); + _wasModified = true; + } + } + return; + } + + private void addTextureToolStripMenuItem_Click(object sender, EventArgs e) + { + using OpenFileDialog fileDialog = new OpenFileDialog(); + fileDialog.Filter = "Texture File(*.png,*.tga)|*.png;*.tga"; + if (fileDialog.ShowDialog(this) == DialogResult.OK) + { + using TextPrompt renamePrompt = new TextPrompt(Path.GetFileName(fileDialog.FileName)); + renamePrompt.LabelText = "Path"; + if (renamePrompt.ShowDialog(this) == DialogResult.OK && !string.IsNullOrEmpty(renamePrompt.NewText)) + { + if (EditorValue.File.Contains(renamePrompt.NewText, PckAssetType.TextureFile)) + { + MessageBox.Show(this, $"'{renamePrompt.NewText}' already exists.", "Import failed", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + PckAsset asset = EditorValue.File.CreateNewAsset(renamePrompt.NewText, PckAssetType.TextureFile, () => File.ReadAllBytes(fileDialog.FileName)); + BuildMainTreeView(); + _wasModified = true; + } + } + } + + [Obsolete("Refactor or remove this")] + private void importSkinToolStripMenuItem_Click(object sender, EventArgs e) + { + using (OpenFileDialog contents = new OpenFileDialog()) + { + contents.Title = "Select Extracted Skin File"; + contents.Filter = "Skin File (*.png)|*.png"; + + if (contents.ShowDialog() == DialogResult.OK) + { + string skinNameImport = Path.GetFileName(contents.FileName); + byte[] data = File.ReadAllBytes(contents.FileName); + PckAsset mfNew = EditorValue.File.CreateNewAsset(skinNameImport, PckAssetType.SkinFile); + mfNew.SetData(data); + string propertyFile = Path.GetFileNameWithoutExtension(contents.FileName) + ".txt"; + if (File.Exists(propertyFile)) + { + string[] txtProperties = File.ReadAllLines(propertyFile); + if ((txtProperties.Contains("DISPLAYNAMEID") && txtProperties.Contains("DISPLAYNAME")) || + txtProperties.Contains("THEMENAMEID") && txtProperties.Contains("THEMENAME") && + TryGetLocFile(out LOCFile locFile)) + { + // do stuff + //l.AddLocKey(locThemeId, locTheme); + //using (var stream = new MemoryStream()) + //{ + // LOCFileWriter.Write(stream, locFile); + // locdata.SetData(stream.ToArray()); + //} + } + + try + { + foreach (string prop in txtProperties) + { + string[] arg = prop.Split(':'); + if (arg.Length < 2) + continue; + string key = arg[0]; + string value = arg[1]; + if (key == "DISPLNAMEID" || key == "THEMENAMEID") + { + + } + mfNew.AddProperty(key, value); + } + _wasModified = true; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + } + } + } + } + + private void folderToolStripMenuItem_Click(object sender, EventArgs e) + { + TextPrompt folderNamePrompt = new TextPrompt(); + if (treeViewMain.SelectedNode is not null) + folderNamePrompt.contextLabel.Text = + $"New folder at the location of \"{( + !treeViewMain.SelectedNode.IsTagOfType() + ? "/" + treeViewMain.SelectedNode.FullPath + : treeViewMain.SelectedNode.Parent == null ? "/" : "/" + treeViewMain.SelectedNode.Parent.FullPath)}\""; + folderNamePrompt.OKButtonText = "Add"; + if (folderNamePrompt.ShowDialog(this) == DialogResult.OK) + { + TreeNode folerNode = CreateNode(folderNamePrompt.NewText); + folerNode.ImageIndex = 0; + folerNode.SelectedImageIndex = 0; + + TreeNodeCollection nodeCollection = treeViewMain.Nodes; + if (treeViewMain.SelectedNode is TreeNode node) + { + if (node.Tag is PckAsset asset && + asset.Type != PckAssetType.TexturePackInfoFile && + asset.Type != PckAssetType.SkinDataFile) + { + if (node.Parent is TreeNode parentNode) + { + nodeCollection = parentNode.Nodes; + } + } + else + nodeCollection = node.Nodes; + } + nodeCollection.Add(folerNode); + } + } + + private void SetFileType(PckAssetType type) + { + if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset)) + { + Debug.WriteLine($"Setting {asset.Type} to {type}"); + asset.Type = type; + int nodeIconId = GetNodeIconId(type); + treeViewMain.SelectedNode.ImageIndex = nodeIconId; + treeViewMain.SelectedNode.SelectedImageIndex = nodeIconId; + } + } + + private void treeViewMain_AfterSelect(object sender, TreeViewEventArgs e) + { + ReloadMetaTreeView(); + + entryTypeTextBox.Text = entryDataTextBox.Text = labelImageSize.Text = string.Empty; + buttonEdit.Visible = false; + + previewPictureBox.Image = Resources.NoImageFound; + viewFileInfoToolStripMenuItem.Visible = false; + + if (!e.Node.TryGetTagData(out PckAsset asset)) + { + return; + } + + viewFileInfoToolStripMenuItem.Visible = true; + if (asset.HasProperty("BOX")) + { + buttonEdit.Text = "EDIT BOXES"; + buttonEdit.Visible = true; + } + else if (asset.HasProperty("ANIM") && + asset.GetProperty("ANIM", s => SkinANIM.FromString(s) == (SkinAnimMask.RESOLUTION_64x64 | SkinAnimMask.SLIM_MODEL))) + { + buttonEdit.Text = "View Skin"; + buttonEdit.Visible = true; + } + + switch (asset.Type) + { + case PckAssetType.SkinFile: + case PckAssetType.CapeFile: + case PckAssetType.TextureFile: + { + Image img = asset.GetTexture(); + + previewPictureBox.Image = img; + labelImageSize.Text = $"{previewPictureBox.Image.Size.Width}x{previewPictureBox.Image.Size.Height}"; + + if (asset.Type != PckAssetType.TextureFile) + break; + + ResourceLocation resourceLocation = ResourceLocation.GetFromPath(asset.Filename); + if (resourceLocation is null || resourceLocation.Category == ResourceCategory.Unknown) + break; + + if (resourceLocation.Category == ResourceCategory.ItemAnimation || + resourceLocation.Category == ResourceCategory.BlockAnimation && + !asset.IsMipmappedFile()) + { + buttonEdit.Text = "EDIT TILE ANIMATION"; + buttonEdit.Visible = true; + break; + } + + buttonEdit.Text = "EDIT TEXTURE ATLAS"; + buttonEdit.Visible = true; + } + break; + + case PckAssetType.LocalisationFile: + buttonEdit.Text = "EDIT LOC"; + buttonEdit.Visible = true; + break; + + case PckAssetType.AudioFile: + buttonEdit.Text = "EDIT MUSIC CUES"; + buttonEdit.Visible = true; + break; + + case PckAssetType.ColourTableFile when asset.Filename == "colours.col": + buttonEdit.Text = "EDIT COLORS"; + buttonEdit.Visible = true; + break; + + case PckAssetType.BehavioursFile when asset.Filename == "behaviours.bin": + buttonEdit.Text = "EDIT BEHAVIOURS"; + buttonEdit.Visible = true; + break; + default: + buttonEdit.Visible = false; + break; + } + } + + private void treeViewMain_DoubleClick(object sender, EventArgs e) + { + if (treeViewMain.SelectedNode is TreeNode t && t.Tag is PckAsset asset) + { + if (asset.Size <= 0) + { + Trace.WriteLine($"'{asset.Filename}' has no data attached.", category: nameof(treeViewMain_DoubleClick)); + return; + } + _pckAssetTypeHandler[asset.Type]?.Invoke(asset); + } + } + + // Most of the code below is modified code from this link: + // https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.treeview.itemdrag?view=windowsdesktop-6.0 + // - MattNL + + private void treeViewMain_ItemDrag(object sender, ItemDragEventArgs e) + { + if (e.Button != MouseButtons.Left || e.Item is not TreeNode node) + return; + + if ((node.TryGetTagData(out PckAsset asset) && EditorValue.File.Contains(asset.Filename, asset.Type)) || node.Parent is TreeNode) + { + // TODO: add (mouse) scrolling while dragging item(s) + treeViewMain.DoDragDrop(node, DragDropEffects.Scroll | DragDropEffects.Move); + } + } + + private void treeViewMain_DragOver(object sender, DragEventArgs e) + { + Point dragLocation = new Point(e.X, e.Y); + TreeNode node = treeViewMain.GetNodeAt(treeViewMain.PointToClient(dragLocation)); + treeViewMain.SelectedNode = node.IsTagOfType() ? null : node; + } + + private void treeViewMain_DragEnter(object sender, DragEventArgs e) + { + e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : e.AllowedEffect; + BringToFront(); + Focus(); + treeViewMain.Focus(); + } + + private void treeViewMain_DragDrop(object sender, DragEventArgs e) + { + // Retrieve the client coordinates of the drop location. + Point dragLocation = new Point(e.X, e.Y); + Point targetPoint = treeViewMain.PointToClient(dragLocation); + + if (!treeViewMain.ClientRectangle.Contains(targetPoint)) + return; + + // Retrieve the node at the drop location. + TreeNode targetNode = treeViewMain.GetNodeAt(targetPoint); + + if (e.Data.GetDataPresent(DataFormats.FileDrop) && e.Data.GetData(DataFormats.FileDrop) is string[] filesDropped) + { + IEnumerable files = filesDropped.Where(File.Exists); + IEnumerable directoryFiles = filesDropped + .Where(f => (File.GetAttributes(f) & FileAttributes.Directory) != 0) + .SelectMany(dir => Directory.GetFiles(dir, "*.*", SearchOption.AllDirectories)); + + string baseDirectory = Path.GetDirectoryName(filesDropped.First()); + + IEnumerable importPaths = files.Concat(directoryFiles); + + ImportFiles(baseDirectory, importPaths, string.IsNullOrWhiteSpace(targetNode?.FullPath) ? string.Empty : targetNode?.FullPath); + return; + } + + string dataFormat = typeof(TreeNode).FullName; + + if (targetNode is null) + return; + + if (!e.Data.GetDataPresent(dataFormat)) + return; + + bool isTargetPckFile = targetNode.IsTagOfType(); + TreeNode draggedNode = e.Data.GetData(dataFormat) as TreeNode; + if (draggedNode == null) + { + Debug.WriteLine("Dragged node is null."); + return; + } + + if (targetNode.Equals(draggedNode)) + { + Debug.WriteLine("Dragged node was not moved."); + return; + } + + if (targetNode.Equals(draggedNode.Parent)) + { + Debug.WriteLine("target node is parent of dragged node... nothing done."); + return; + } + + if (draggedNode.Equals(targetNode.Parent)) + { + Debug.WriteLine("dragged node is parent of target node... nothing done."); + return; + } + + if (targetNode.Parent == null && isTargetPckFile && draggedNode.Parent == null) + { + Debug.WriteLine("target node is file and is in the root... nothing done."); + return; + } + + if ((targetNode.Parent?.Equals(draggedNode.Parent) ?? false) && isTargetPckFile) + { + Debug.WriteLine("target node and dragged node have the same parent... nothing done."); + return; + } + + Debug.WriteLine($"Target drop location is {(isTargetPckFile ? "file" : "folder")}."); + + // Retrieve the node that was dragged. + if (draggedNode.TryGetTagData(out PckAsset draggedAsset) && + targetNode.FullPath != draggedAsset.Filename) + { + Debug.WriteLine(draggedAsset.Filename + " was droped onto " + targetNode.FullPath); + string newFilePath = Path.Combine(isTargetPckFile + ? Path.GetDirectoryName(targetNode.FullPath) + : targetNode.FullPath, Path.GetFileName(draggedAsset.Filename)); + Debug.WriteLine("New filepath: " + newFilePath); + draggedAsset.Filename = newFilePath; + _wasModified = true; + BuildMainTreeView(); + return; + } + else + { + IEnumerable pckFiles = GetAllChildNodes(draggedNode.Nodes).Where(t => t.IsTagOfType()).Select(t => t.Tag as PckAsset); + string oldPath = draggedNode.FullPath; + string newPath = Path.Combine(isTargetPckFile ? Path.GetDirectoryName(targetNode.FullPath) : targetNode.FullPath, draggedNode.Text).Replace('\\', '/'); + foreach (PckAsset pckFile in pckFiles) + { + pckFile.Filename = Path.Combine(newPath, pckFile.Filename.Substring(oldPath.Length + 1)).Replace('\\', '/'); + } + _wasModified = true; + BuildMainTreeView(); + } + } + + private void ImportFiles(string baseDirectory, IEnumerable files, string prefix) + { + int fileCount = files.Count(); + int addedCount = 0; + int skippedFiles = 0; + int skipAttempts = 3; + int typeDuplication = 0; + PckAssetType lastSelectedAssetType = PckAssetType.SkinFile; + bool askForAssetType = true; + foreach (var filepath in files) + { + string assetPath = Path.Combine(prefix + filepath.Substring(baseDirectory.Length)).TrimStart('/', '\\'); + PckAssetType assetType = lastSelectedAssetType; + + if (askForAssetType) + { + using AddFilePrompt addFile = new AddFilePrompt(assetPath); + if (addFile.ShowDialog(this) != DialogResult.OK) + { + skippedFiles++; + skipAttempts--; + if (skipAttempts > 0) + continue; + + int remainingFileCount = fileCount - addedCount - skippedFiles; + DialogResult abortFurtherImport = MessageBox.Show($"Do you wan't to abort further file imports?\n{remainingFileCount} file(s) left.", "Abort further import", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); + if (abortFurtherImport == DialogResult.Yes) + { + skippedFiles += remainingFileCount; + break; + } + skipAttempts = 3; + continue; + } + + assetType = addFile.Filetype; + assetPath = addFile.Filepath; + + if (lastSelectedAssetType == assetType) + typeDuplication++; + lastSelectedAssetType = addFile.Filetype; + if (typeDuplication > 1) + { + DialogResult useSameTypeForRest = MessageBox.Show($"Do you want to import all remaining files as {lastSelectedAssetType}?", "Import all as", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); + if (useSameTypeForRest == DialogResult.Yes) + { + askForAssetType = false; + } + } + } + + if (EditorValue.File.Contains(filepath, assetType)) + { + if (askForAssetType) + MessageBox.Show(this, $"'{assetPath}' of type {assetType} already exists.\nSkiping file.", "File already exists", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1); + Debug.WriteLine($"'{assetPath}' of type {assetType} already exists.\nSkiping file."); + continue; + } + PckAsset importedAsset = EditorValue.File.CreateNewAsset(assetPath, assetType, () => File.ReadAllBytes(filepath)); + string propertyFile = filepath + ".txt"; + if (File.Exists(propertyFile)) + { + importedAsset.DeserializeProperties(File.ReadAllLines(propertyFile)); + } + addedCount++; + } + Trace.TraceInformation("[{0}] Imported {1} file(s).", nameof(ImportFiles), addedCount); + Trace.TraceInformation("[{0}] Skipped {1} file(s).", nameof(ImportFiles), skippedFiles); + if (addedCount > 0) + { + _wasModified = true; + BuildMainTreeView(); + } + } + + private IEnumerable GetEndingNodes(TreeNodeCollection collection) + { + List trailingNodes = new List(collection.Count); + foreach (TreeNode node in collection) + { + if (node.Nodes.Count > 0) + { + trailingNodes.AddRange(GetEndingNodes(node.Nodes)); + continue; + } + trailingNodes.Add(node); + } + return trailingNodes; + } + + private void ImportFiles(string[] files) + { + int addedCount = 0; + foreach (var file in files) + { + using AddFilePrompt addFile = new AddFilePrompt(Path.GetFileName(file)); + if (addFile.ShowDialog(this) != DialogResult.OK) + continue; + + if (EditorValue.File.Contains(addFile.Filepath, addFile.Filetype)) + { + MessageBox.Show(this, $"'{addFile.Filepath}' of type {addFile.Filetype} already exists.", "Import failed", MessageBoxButtons.OK, MessageBoxIcon.Warning); + continue; + } + EditorValue.File.CreateNewAsset(addFile.Filepath, addFile.Filetype, () => File.ReadAllBytes(file)); + addedCount++; + + BuildMainTreeView(); + _wasModified = true; + } + Trace.TraceInformation("[{0}] Imported {1} file(s).", nameof(ImportFiles), addedCount); + } + + private void createSkinToolStripMenuItem_Click(object sender, EventArgs e) + { + using (AddSkinPrompt addNewSkinDialog = new AddSkinPrompt()) + if (addNewSkinDialog.ShowDialog() == DialogResult.OK) + { + TryGetLocFile(out LOCFile locFile); + PckAsset skinAsset = addNewSkinDialog.NewSkin.CreateFile(locFile); + EditorValue.File.AddAsset(skinAsset); + + bool hasSkinsFolder = treeViewMain.Nodes.ContainsKey("Skins"); + if (hasSkinsFolder) + skinAsset.Filename = skinAsset.Filename.Insert(0, "Skins/"); // Then Skins folder + EditorValue.File.AddAsset(skinAsset); + + if (addNewSkinDialog.NewSkin.HasCape) + { + PckAsset capeFile = addNewSkinDialog.NewSkin.CreateCapeFile(); + if (hasSkinsFolder) + capeFile.Filename = capeFile.Filename.Insert(0, "Skins/"); // Then Skins folder + EditorValue.File.AddAsset(capeFile); + } + + TrySetLocFile(locFile); + _wasModified = true; + BuildMainTreeView(); + } + } + + private void createAnimatedTextureToolStripMenuItem_Click(object sender, EventArgs e) + { + using ChangeTile diag = new ChangeTile(); + if (diag.ShowDialog(this) != DialogResult.OK) + return; + + string animationFilepath = $"{ResourceLocation.GetPathFromCategory(diag.Category)}/{diag.SelectedTile.InternalName}.png"; + + if (EditorValue.File.Contains(animationFilepath, PckAssetType.TextureFile)) + { + MessageBox.Show(this, $"{diag.SelectedTile.DisplayName} is already present.", "File already present"); + return; + } + + Animation newAnimation = default; + ISaveContext saveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (animation) => + { + newAnimation = animation; + }); + + using AnimationEditor animationEditor = new AnimationEditor(Animation.CreateEmpty(), saveContext, diag.SelectedTile.DisplayName, !diag.SelectedTile.InternalName.EqualsAny("clock", "compass")); + if (animationEditor.ShowDialog() == DialogResult.OK && newAnimation is not null) + { + _wasModified = true; + PckAsset asset = EditorValue.File.CreateNewAsset(animationFilepath, PckAssetType.TextureFile); + asset.SetSerializedData(newAnimation, AnimationSerializer.DefaultSerializer); + BuildMainTreeView(); + ReloadMetaTreeView(); + } + } + + private void audiopckToolStripMenuItem_Click(object sender, EventArgs e) + { + if (EditorValue.File.Contains(PckAssetType.AudioFile)) + { + // the chance of this happening is really really slim but just in case + MessageBox.Show(this, "There is already an audio file in this PCK!", "Can't create audio.pck"); + return; + } + + if (string.IsNullOrEmpty(_location)) + { + MessageBox.Show(this, "You must save your pck before creating or opening a music cues PCK file", "Can't create audio.pck"); + return; + } + + PckAudioFile newAudioFile = CreateNewAudioFile(); + PckAsset newAudioAsset = CreateNewAudioAsset(LittleEndianCheckBox.Checked, newAudioFile); + + ISaveContext saveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (audioFile) => + { + newAudioAsset.SetData(new PckAudioFileWriter(audioFile, LittleEndianCheckBox.Checked ? OMI.ByteOrder.LittleEndian : OMI.ByteOrder.BigEndian)); + }); + + AudioEditor diag = new AudioEditor(newAudioFile, saveContext); + if (diag.ShowDialog(this) == DialogResult.OK) + { + EditorValue.File.AddAsset(newAudioAsset); + } + diag.Dispose(); + BuildMainTreeView(); + } + + private void colourscolToolStripMenuItem_Click(object sender, EventArgs e) + { + if (EditorValue.File.TryGetAsset("colours.col", PckAssetType.ColourTableFile, out _)) + { + MessageBox.Show(this, "A color table file already exists in this PCK and a new one cannot be created.", "Operation aborted"); + return; + } + PckAsset newColorAsset = EditorValue.File.CreateNewAsset("colours.col", PckAssetType.ColourTableFile); + newColorAsset.SetData(Resources.tu69colours); + BuildMainTreeView(); + } + + private void CreateSkinsPCKToolStripMenuItem1_Click(object sender, EventArgs e) + { + if (EditorValue.File.TryGetAsset("Skins.pck", PckAssetType.SkinDataFile, out _)) + { + MessageBox.Show(this, "A Skins.pck file already exists in this PCK and a new one cannot be created.", "Operation aborted"); + return; + } + + EditorValue.File.CreateNewAsset("Skins.pck", PckAssetType.SkinDataFile, new PckFileWriter(new PckFile(3, true), + LittleEndianCheckBox.Checked ? OMI.ByteOrder.LittleEndian : OMI.ByteOrder.BigEndian)); + + BuildMainTreeView(); + } + + private void behavioursbinToolStripMenuItem_Click(object sender, EventArgs e) + { + if (EditorValue.File.TryGetAsset("behaviours.bin", PckAssetType.BehavioursFile, out _)) + { + MessageBox.Show(this, "A behaviours file already exists in this PCK and a new one cannot be created.", "Operation aborted"); + return; + } + + EditorValue.File.CreateNewAsset("behaviours.bin", PckAssetType.BehavioursFile, new BehavioursWriter(new BehaviourFile())); + BuildMainTreeView(); + } + + private void entityMaterialsbinToolStripMenuItem_Click(object sender, EventArgs e) + { + if (EditorValue.File.TryGetAsset("entityMaterials.bin", PckAssetType.MaterialFile, out _)) + { + MessageBox.Show(this, "A behaviours file already exists in this PCK and a new one cannot be created.", "Operation aborted"); + return; + } + var materialContainer = new MaterialContainer(); + materialContainer.InitializeDefault(); + EditorValue.File.CreateNewAsset("entityMaterials.bin", PckAssetType.MaterialFile, new MaterialFileWriter(materialContainer)); + BuildMainTreeView(); + } + + [Obsolete("Refactor or remove this")] + private void importExtractedSkinsFolder(object sender, EventArgs e) + { + OpenFolderDialog contents = new OpenFolderDialog(); + if (contents.ShowDialog(Handle) == true) + { + //checks to make sure selected path exist + if (!Directory.Exists(contents.ResultPath)) + { + MessageBox.Show("Directory Lost"); + return; + } + // creates variable to indicate wether current pck skin structure is mashup or regular skin + bool hasSkinsPck = EditorValue.File.HasAsset("Skins.pck", PckAssetType.SkinDataFile); + + foreach (var fullfilename in Directory.GetFiles(contents.ResultPath, "*.png")) + { + string filename = Path.GetFileNameWithoutExtension(fullfilename); + // sets file type based on wether its a cape or skin + PckAssetType pckfiletype = filename.StartsWith("dlccape", StringComparison.OrdinalIgnoreCase) + ? PckAssetType.CapeFile + : PckAssetType.SkinFile; + string pckfilepath = (hasSkinsPck ? "Skins/" : string.Empty) + filename + ".png"; + + + PckAsset newFile = new PckAsset(pckfilepath, pckfiletype); + byte[] filedata = File.ReadAllBytes(fullfilename); + newFile.SetData(filedata); + + if (File.Exists(fullfilename + ".txt")) + { + string[] properties = File.ReadAllText(fullfilename + ".txt").Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); + foreach (string property in properties) + { + string[] param = property.Split(':'); + if (param.Length < 2) + continue; + newFile.AddProperty(param[0], param[1]); + //switch (param[0]) + //{ + // case "DISPLAYNAMEID": + // locNameId = param[1]; + // continue; + + // case "DISPLAYNAME": + // locName = param[1]; + // continue; + + // case "THEMENAMEID": + // locThemeId = param[1]; + // continue; + + // case "THEMENAME": + // locTheme = param[1]; + // continue; + //} + } + } + if (hasSkinsPck) + { + PckAsset skinsFileAsset = EditorValue.File.GetAsset("Skins.pck", PckAssetType.SkinDataFile); + using (var ms = new MemoryStream(skinsFileAsset.Data)) + { + //var reader = new PckFileReader(LittleEndianCheckBox.Checked ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian); + //var skinspck = reader.FromStream(ms); + //skinspck.Files.Add(newFile); + //ms.Position = 0; + //var writer = new PckFileWriter(skinspck, LittleEndianCheckBox.Checked ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian); + //writer.WriteToStream(ms); + //skinsfile.SetData(ms.ToArray()); + } + continue; + } + EditorValue.File.AddAsset(newFile); + } + BuildMainTreeView(); + _wasModified = true; + } + } + + private void as3DSTextureFileToolStripMenuItem_Click(object sender, EventArgs e) + { + if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset) && + asset.Type == PckAssetType.SkinFile) + { + SaveFileDialog saveFileDialog = new SaveFileDialog(); + saveFileDialog.Filter = "3DS Texture|*.3dst"; + saveFileDialog.DefaultExt = ".3dst"; + if (saveFileDialog.ShowDialog(this) == DialogResult.OK) + { + Image img = asset.GetTexture(); + var writer = new _3DSTextureWriter(img); + writer.WriteToFile(saveFileDialog.FileName); + } + } + } + + private void generateMipMapTextureToolStripMenuItem_Click(object sender, EventArgs e) + { + if (treeViewMain.SelectedNode.Tag is PckAsset asset && asset.Type == PckAssetType.TextureFile) + { + string textureDirectory = Path.GetDirectoryName(asset.Filename); + string textureName = Path.GetFileNameWithoutExtension(asset.Filename); + + if (asset.IsMipmappedFile()) + return; + + string textureExtension = Path.GetExtension(asset.Filename); + + using NumericPrompt numericPrompt = new NumericPrompt(0); + numericPrompt.Minimum = 1; + numericPrompt.Maximum = 4; // 5 is the presumed max MipMap level + numericPrompt.ToolTipText = "You can enter the amount of MipMap levels that you would like to generate. " + + "For example: if you enter 2, MipMapLevel1.png and MipMapLevel2.png will be generated"; + numericPrompt.TextLabel.Text = "Levels"; + + if (numericPrompt.ShowDialog(this) == DialogResult.OK) + { + for (int i = 2; i < 2 + numericPrompt.SelectedValueAsInt; i++) + { + string mippedPath = $"{textureDirectory}/{textureName}MipMapLevel{i}{textureExtension}"; + Debug.WriteLine(mippedPath); + if (EditorValue.File.HasAsset(mippedPath, PckAssetType.TextureFile)) + EditorValue.File.RemoveAsset(EditorValue.File.GetAsset(mippedPath, PckAssetType.TextureFile)); + PckAsset mipMappedAsset = new PckAsset(mippedPath, PckAssetType.TextureFile); + + Image originalTexture = asset.GetTexture(); + int newWidth = Math.Max(originalTexture.Width / (int)Math.Pow(2, i - 1), 1); + int newHeight = Math.Max(originalTexture.Height / (int)Math.Pow(2, i - 1), 1); + + Rectangle tileArea = new Rectangle(0, 0, newWidth, newHeight); + Image mippedTexture = new Bitmap(newWidth, newHeight); + using (Graphics gfx = Graphics.FromImage(mippedTexture)) + { + gfx.SmoothingMode = SmoothingMode.None; + gfx.InterpolationMode = InterpolationMode.NearestNeighbor; + gfx.PixelOffsetMode = PixelOffsetMode.HighQuality; + gfx.DrawImage(originalTexture, tileArea); + } + + mipMappedAsset.SetTexture(mippedTexture); + + EditorValue.File.InsertAsset(EditorValue.File.IndexOfAsset(asset) + i - 1, mipMappedAsset); + } + BuildMainTreeView(); + } + } + } + + private void viewFileInfoToolStripMenuItem_Click(object sender, EventArgs e) + { + if (treeViewMain.SelectedNode.Tag is PckAsset asset) + { + MessageBox.Show( + $"Asset path: {asset.Filename}" + + $"\nAsset type: {(int)asset.Type} ({asset.Type})" + + $"\nAsset size: {asset.Size}" + + $"\nProperties count: {asset.PropertyCount}" + , Path.GetFileName(asset.Filename) + " Asset info"); + } + } + + private void correctSkinDecimalsToolStripMenuItem_Click(object sender, EventArgs e) + { + if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset) && + asset.Type == PckAssetType.SkinFile) + { + foreach (KeyValuePair p in asset.GetProperties().ToList()) + { + if (p.Key == "BOX" || p.Key == "OFFSET") + asset.SetProperty(asset.GetPropertyIndex(p), new KeyValuePair(p.Key, p.Value.Replace(',', '.'))); + } + ReloadMetaTreeView(); + _wasModified = true; + } + } + + private void extractToolStripMenuItem_Click(object sender, EventArgs e) + { + TreeNode node = treeViewMain.SelectedNode; + + if (node == null) + { + MessageBox.Show(this, "The selected node was null. Please select a node and try again.", "Node not extracted"); + + return; + } + + if (node.Tag == null) + { + OpenFolderDialog dialog = new OpenFolderDialog(); + dialog.Title = @"Select destination folder"; + + if (dialog.ShowDialog(Handle) == true) + extractFolder(dialog.ResultPath); + } + else if (node.TryGetTagData(out PckAsset asset)) + { + using SaveFileDialog exFile = new SaveFileDialog(); + exFile.FileName = Path.GetFileName(asset.Filename); + exFile.Filter = Path.GetExtension(asset.Filename).Replace(".", string.Empty) + " File|*" + Path.GetExtension(asset.Filename); + if (exFile.ShowDialog(this) != DialogResult.OK || + // Makes sure chosen directory isn't null or whitespace AKA makes sure its usable + string.IsNullOrWhiteSpace(Path.GetDirectoryName(exFile.FileName))) + { + MessageBox.Show(this, "The chosen directory is invalid. Please choose a different one and try again.", "Node not extracted"); + + return; + } + + extractFile(exFile.FileName, asset); + } + + // Verification that file extraction path was successful + MessageBox.Show(this, $"\"{node.Text}\" successfully extracted"); + } + + private void extractFolder(string outPath) + { + TreeNode node = treeViewMain.SelectedNode; + + string selectedFolder = node.FullPath; + + foreach (PckAsset asset in EditorValue.File.GetAssets().Where(asset => asset.Filename.StartsWith(selectedFolder))) + { + extractFolderFile(outPath, asset); + } + } + + private void extractFolderFile(string outPath, PckAsset asset) + { + TreeNode node = treeViewMain.SelectedNode; + + // abb = "Abbreviated Path" + string abbPath = Path.GetDirectoryName(asset.Filename); + int startIndex = abbPath.IndexOf(node.Text); + abbPath = abbPath.Substring(startIndex, abbPath.Length - startIndex); + string finalPath = ($"{outPath}/{abbPath}/").Replace('\\', '/'); + + if (!Directory.Exists(finalPath)) + Directory.CreateDirectory(finalPath); + + extractFile(finalPath + "/" + Path.GetFileName(asset.Filename), asset); + } + + private void extractFile(string outFilePath, PckAsset asset) + { + File.WriteAllBytes(outFilePath, asset.Data); + if (asset.PropertyCount > 0) + { + File.WriteAllLines($"{outFilePath}.txt", asset.SerializeProperties()); + } + } + + private void cloneFileToolStripMenuItem_Click(object sender, EventArgs e) + { + TreeNode node = treeViewMain.SelectedNode; + if (node == null || !node.IsTagOfType()) + return; + string path = node.FullPath; + + using TextPrompt diag = new TextPrompt(node.Tag is null ? Path.GetFileName(node.FullPath) : node.FullPath); + diag.contextLabel.Text = $"Creating a clone of \"{path}\". Ensure that the path isn't yet."; + diag.OKButtonText = "Clone"; + + if (diag.ShowDialog(this) == DialogResult.OK) + { + if (node.Tag is PckAsset asset) + { + TreeNode newNode = new TreeNode(); + newNode.Text = Path.GetFileName(diag.NewText); + var newFile = new PckAsset(diag.NewText, asset.Type); + foreach (KeyValuePair property in asset.GetProperties()) + { + newFile.AddProperty(property); + } + newFile.SetData(asset.Data); + newFile.Filename = diag.NewText; + newNode.Tag = newFile; + newNode.ImageIndex = node.ImageIndex; + newNode.SelectedImageIndex = node.SelectedImageIndex; + + if (GetAllChildNodes(treeViewMain.Nodes).FirstOrDefault(n => n.FullPath == diag.NewText) is not null) + { + MessageBox.Show( + this, + $"A file with the path \"{diag.NewText}\" already exists. " + + $"Please try again with a different name.", + "Key already exists"); + return; + } + + TreeNodeCollection nodeCollection = node.Parent?.Nodes ?? treeViewMain.Nodes; + nodeCollection.Insert(node.Index + 1, newNode); + + EditorValue.File.InsertAsset(node.Index + 1, newFile); + BuildMainTreeView(); + _wasModified = true; + } + } + } + + private void renameFileToolStripMenuItem_Click(object sender, EventArgs e) + { + TreeNode node = treeViewMain.SelectedNode; + if (node == null) + return; + string path = node.FullPath; + + bool isFile = node.TryGetTagData(out PckAsset asset); + + using TextPrompt diag = new TextPrompt(isFile ? asset.Filename : Path.GetFileName(node.FullPath)); + + if (diag.ShowDialog(this) == DialogResult.OK) + { + if (isFile) + { + if (EditorValue.File.Contains(diag.NewText, asset.Type)) + { + MessageBox.Show(this, $"{diag.NewText} already exists", "File already exists"); + return; + } + asset.Filename = diag.NewText; + } + else // folders + { + node.Text = diag.NewText; + foreach (TreeNode childNode in GetAllChildNodes(node.Nodes)) + { + if (childNode.Tag is PckAsset folderAsset) + { + if (folderAsset.Filename == diag.NewText) + continue; + folderAsset.Filename = childNode.FullPath; + } + } + } + _wasModified = true; + BuildMainTreeView(); + } + } + + private void replaceToolStripMenuItem_Click(object sender, EventArgs e) + { + if (treeViewMain.SelectedNode.Tag is PckAsset asset) + { + using var ofd = new OpenFileDialog(); + // Suddenly, and randomly, this started throwing an exception because it wasn't formatted correctly? So now it's formatted correctly and now displays the file type name in the dialog. + + string extra_extensions = ""; + + switch (asset.Type) + { + case PckAssetType.TextureFile: + if (Path.GetExtension(asset.Filename) == ".png") + extra_extensions = ";*.tga"; + else if (Path.GetExtension(asset.Filename) == ".tga") + extra_extensions = ";*.png"; + break; + } + + string fileExt = Path.GetExtension(asset.Filename); + + ofd.Filter = $"{asset.Type} (*{fileExt}{extra_extensions})|*{fileExt}{extra_extensions}"; + if (ofd.ShowDialog(this) == DialogResult.OK) + { + string newFileExt = Path.GetExtension(ofd.FileName); + asset.SetData(File.ReadAllBytes(ofd.FileName)); + asset.Filename = asset.Filename.Replace(fileExt, newFileExt); + _wasModified = true; + BuildMainTreeView(); + } + return; + } + MessageBox.Show(this, "Can't replace a folder."); + } + + /// + /// Action to run before an asset will be deleted + /// + /// Asset to remove + /// True if the remove should be canceled, otherwise False + private bool BeforeFileRemove(PckAsset asset) + { + string itemPath = ResourceLocation.GetPathFromCategory(ResourceCategory.ItemAnimation); + + // warn the user about deleting compass.png and clock.png + if (asset.Type == PckAssetType.TextureFile && + (asset.Filename == itemPath + "/compass.png" || asset.Filename == itemPath + "/clock.png")) + { + if (MessageBox.Show(this, "Are you sure want to delete this file? If \"compass.png\" or \"clock.png\" are missing, your game will crash upon loading this pack.", "Warning", + MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) + return true; + } + + // remove loc key if its a skin/cape + if (asset.Type == PckAssetType.SkinFile || asset.Type == PckAssetType.CapeFile) + { + if (TryGetLocFile(out LOCFile locFile)) + { + if (asset.TryGetProperty("THEMENAMEID", out string value)) + locFile.RemoveLocKey(value); + if (asset.TryGetProperty("DISPLAYNAMEID", out value)) + locFile.RemoveLocKey(value); + TrySetLocFile(locFile); + } + } + return false; + } + + private void deleteFileToolStripMenuItem_Click(object sender, EventArgs e) + { + TreeNode node = treeViewMain.SelectedNode; + if (node == null) + return; + + string path = node.FullPath; + + if (node.TryGetTagData(out PckAsset asset)) + { + if (!BeforeFileRemove(asset) && EditorValue.File.RemoveAsset(asset)) + { + node.Remove(); + _wasModified = true; + } + } + else if (MessageBox.Show(this, "Are you sure want to delete this folder? All contents will be deleted", "Warning", + MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) + { + string pckFolderDir = node.FullPath; + EditorValue.File.RemoveAll(file => file.Filename.StartsWith(pckFolderDir) && !BeforeFileRemove(file)); + node.Remove(); + _wasModified = true; + } + } + + private void treeMeta_AfterSelect(object sender, TreeViewEventArgs e) + { + if (e.Node is TreeNode t && t.Tag is KeyValuePair property) + { + entryTypeTextBox.Text = property.Key; + entryDataTextBox.Text = property.Value; + } + } + + private void treeViewMain_KeyDown(object sender, KeyEventArgs e) + { + switch (e.KeyCode) + { + case Keys.Delete: + deleteFileToolStripMenuItem_Click(sender, e); + break; + case Keys.F2: + renameFileToolStripMenuItem_Click(sender, e); + break; + } + } + + private void treeViewMain_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e) + { + // for now name edits are done through the 'rename' context menu item + // TODO: add folder renaming + //e.CancelEdit = e.Node.Tag is PckAsset; + e.CancelEdit = true; + } + + private void editAllEntriesToolStripMenuItem_Click(object sender, EventArgs e) + { + if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset)) + { + IEnumerable props = asset.SerializeProperties(seperater: " "); + using (var input = new MultiTextPrompt(props)) + { + if (input.ShowDialog(this) == DialogResult.OK) + { + asset.ClearProperties(); + asset.DeserializeProperties(input.TextOutput); + ReloadMetaTreeView(); + _wasModified = true; + } + } + } + } + + private void treeMeta_DoubleClick(object sender, EventArgs e) + { + if (treeMeta.SelectedNode is TreeNode subnode && subnode.Tag is KeyValuePair property && + treeViewMain.SelectedNode is TreeNode node && node.Tag is PckAsset asset) + { + if (asset.HasProperty(property.Key)) + { + switch (property.Key) + { + case "ANIM" when asset.Type == PckAssetType.SkinFile: + try + { + using ANIMEditor diag = new ANIMEditor(SkinANIM.FromString(property.Value)); + if (diag.ShowDialog(this) == DialogResult.OK) + { + asset.SetProperty(asset.GetPropertyIndex(property), new KeyValuePair("ANIM", diag.ResultAnim.ToString())); + ReloadMetaTreeView(); + _wasModified = true; + } + return; + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + Trace.WriteLine("Invalid ANIM value: " + property.Value); + MessageBox.Show(this, "Failed to parse ANIM value, aborting to normal functionality. Please make sure the value only includes hexadecimal characters (0-9,A-F) and has no more than 8 characters."); + } + break; + + case "BOX" when asset.Type == PckAssetType.SkinFile: + try + { + using BoxEditor diag = new BoxEditor(property.Value, false); + if (diag.ShowDialog(this) == DialogResult.OK) + { + asset.SetProperty(asset.GetPropertyIndex(property), new KeyValuePair("BOX", diag.Result.ToString())); + ReloadMetaTreeView(); + _wasModified = true; + } + return; + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + Trace.WriteLine("Invalid BOX value: " + property.Value); + MessageBox.Show(this, "Failed to parse BOX value, aborting to normal functionality."); + } + break; + + default: + break; + + } + + using (AddPropertyPrompt addProperty = new AddPropertyPrompt(property)) + { + if (addProperty.ShowDialog(this) == DialogResult.OK) + { + asset.SetProperty(asset.GetPropertyIndex(property), addProperty.Property); + ReloadMetaTreeView(); + _wasModified = true; + } + } + } + } + } + + private void treeMeta_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyData == Keys.Delete) + deleteEntryToolStripMenuItem_Click(sender, e); + } + + private void addMultipleEntriesToolStripMenuItem1_Click(object sender, EventArgs e) + { + if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset)) + { + using var input = new MultiTextPrompt(); + if (input.ShowDialog(this) == DialogResult.OK) + { + asset.DeserializeProperties(input.TextOutput); + ReloadMetaTreeView(); + _wasModified = true; + } + } + } + + private void addBOXEntryToolStripMenuItem1_Click(object sender, EventArgs e) + { + if (treeViewMain.SelectedNode is TreeNode t && t.Tag is PckAsset asset) + { + using BoxEditor diag = new BoxEditor(SkinBOX.DefaultHead, false); + if (diag.ShowDialog(this) == DialogResult.OK) + { + asset.AddProperty("BOX", diag.Result); + ReloadMetaTreeView(); + _wasModified = true; + } + return; + } + } + + private void addANIMEntryToolStripMenuItem1_Click(object sender, EventArgs e) + { + if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset)) + { + using ANIMEditor diag = new ANIMEditor(SkinANIM.Empty); + if (diag.ShowDialog(this) == DialogResult.OK) + { + asset.AddProperty("ANIM", diag.ResultAnim); + ReloadMetaTreeView(); + _wasModified = true; + } + return; + } + } + + private void deleteEntryToolStripMenuItem_Click(object sender, EventArgs e) + { + if (treeMeta.SelectedNode is TreeNode t && t.Tag is KeyValuePair property && + treeViewMain.SelectedNode is TreeNode main && main.Tag is PckAsset asset && + asset.RemoveProperty(property)) + { + treeMeta.SelectedNode.Remove(); + _wasModified = true; + } + } + + private void addEntryToolStripMenuItem_Click(object sender, EventArgs e) + { + if (treeViewMain.SelectedNode is TreeNode t && + t.Tag is PckAsset asset) + { + using AddPropertyPrompt addProperty = new AddPropertyPrompt(); + if (addProperty.ShowDialog(this) == DialogResult.OK) + { + asset.AddProperty(addProperty.Property); + ReloadMetaTreeView(); + _wasModified = true; + } + } + } + + private static bool TryGetDefaultEntityModel(string modelName, out Model model) + { + if (!GameModelImporter.DefaultModels.TryGetValue(modelName, out DefaultModel defaultModel) || defaultModel is null) + { + model = default; + return false; + } + model = new Model(modelName, new Size((int)defaultModel.TextureSize.X, (int)defaultModel.TextureSize.Y)); + + foreach (DefaultPart defaultPart in defaultModel.Parts) + { + ModelPart modelPart = new ModelPart(defaultPart.Name, "", defaultPart.Translation, defaultPart.Rotation, System.Numerics.Vector3.Zero); + modelPart.AddBoxes(defaultPart.Boxes.Select(defaultBox => new ModelBox(defaultBox.Position, defaultBox.Size, defaultBox.Uv, defaultBox.Inflate, defaultBox.Mirror))); + model.AddPart(modelPart); + } + + return true; + } + + private void ShowSimpleModelRender(Model model, NamedData modelTexture) + { + MetroForm form = new MetroForm(); + form.Icon = Resources.ProjectLogo; + form.Theme = MetroFramework.MetroThemeStyle.Dark; + form.Style = MetroFramework.MetroColorStyle.Silver; + form.StartPosition = FormStartPosition.CenterParent; + form.Text = $"{model.Name} - {modelTexture.Name}"; + form.Size = new Size(600, 500); + form.MinimumSize = new Size(300, 300); + + void ExportToolStripItem_Click(object sender, EventArgs e) + { + GameModelImporter.Default.ExportSettings.CreateModelOutline = + MessageBox.Show( + $"Do you wish to have all model parts contained in a group called '{model.Name}'?", + "Group model parts", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes; + + using SaveFileDialog openFileDialog = new SaveFileDialog(); + openFileDialog.FileName = model.Name; + openFileDialog.Filter = GameModelImporter.Default.SupportedModelFileFormatsFilter; + + if (openFileDialog.ShowDialog(this) == DialogResult.OK) + { + var modelInfo = new GameModelInfo(model, new NamedData[1] { modelTexture }); + GameModelImporter.Default.Export(openFileDialog.FileName, modelInfo); + } + } + ToolStripItem exportToolStripItem = new ToolStripButton("Export"); + exportToolStripItem.Click += ExportToolStripItem_Click; + + MenuStrip menu = new MenuStrip(); + menu.BackColor = Color.FromArgb(35, 35, 35); + menu.ForeColor = Color.WhiteSmoke; + menu.Anchor = AnchorStyles.Top; + menu.Dock = DockStyle.Top; + menu.Items.Add(exportToolStripItem); + + ModelRenderer renderer = new ModelRenderer(); + form.Controls.Add(menu); + form.Controls.Add(renderer); + + renderer.VSync = true; + renderer.BackColor = Color.FromArgb(30, 30, 30); + renderer.Dock = DockStyle.Fill; + renderer.Texture = modelTexture.Value; + renderer.LoadModel(model); + renderer.ResetCamera(); + + form.ShowDialog(this); + + renderer.Dispose(); + form.Dispose(); + } + + private void PckEditor_Load(object sender, EventArgs e) + { + CheckForPasswordAndRemove(); + BuildMainTreeView(); + UpdateRichPresence(); + } + + private void SetEndianess(OMI.ByteOrder endianness) + { + LittleEndianCheckBox.Checked = endianness == OMI.ByteOrder.LittleEndian; + } + + private OMI.ByteOrder GetEndianess() + { + return LittleEndianCheckBox.Checked ? OMI.ByteOrder.LittleEndian : OMI.ByteOrder.BigEndian; + } + + private void buttonEdit_Click(object sender, EventArgs e) + { + treeViewMain_DoubleClick(sender, e); + } + + private void SetPckEndianness(OMI.ByteOrder endianness) + { + try + { + if (treeViewMain.SelectedNode.Tag is PckAsset asset && (asset.Type is PckAssetType.AudioFile || asset.Type is PckAssetType.SkinDataFile || asset.Type is PckAssetType.TexturePackInfoFile)) + { + IDataFormatReader reader = asset.Type is PckAssetType.AudioFile + ? new PckAudioFileReader(endianness == OMI.ByteOrder.BigEndian ? OMI.ByteOrder.LittleEndian : OMI.ByteOrder.BigEndian) + : new PckFileReader(endianness == OMI.ByteOrder.BigEndian ? OMI.ByteOrder.LittleEndian : OMI.ByteOrder.BigEndian); + object pck = reader.FromStream(new MemoryStream(asset.Data)); + + IDataFormatWriter writer = asset.Type is PckAssetType.AudioFile + ? new PckAudioFileWriter((PckAudioFile)pck, endianness) + : new PckFileWriter((PckFile)pck, endianness); + asset.SetData(writer); + _wasModified = true; + MessageBox.Show($"\"{asset.Filename}\" successfully converted to {(endianness == OMI.ByteOrder.LittleEndian ? "little" : "big")} endian.", "Converted PCK file"); + } + } + catch (OverflowException) + { + MessageBox.Show(this, $"File was not a valid {(endianness != OMI.ByteOrder.LittleEndian ? "little" : "big")} endian PCK File.", "Not a valid PCK file"); + return; + } + catch (Exception ex) + { + MessageBox.Show(this, ex.Message, "Not a valid PCK file"); + return; + } + } + + private void littleEndianToolStripMenuItem_Click(object sender, EventArgs e) => SetPckEndianness(OMI.ByteOrder.LittleEndian); + + private void bigEndianToolStripMenuItem_Click(object sender, EventArgs e) => SetPckEndianness(OMI.ByteOrder.BigEndian); + + private void SetModelVersion(int version) + { + if (treeViewMain.SelectedNode.Tag is PckAsset asset && asset.Type is PckAssetType.ModelsFile) + { + try + { + ModelContainer container = asset.GetData(new ModelFileReader()); + + if (container.Version == version) + { + MessageBox.Show( + this, + $"This model container is already Version {version + 1}.", + "Can't convert", MessageBoxButtons.OK, MessageBoxIcon.Error + ); + return; + } + + if (version == 2 && + MessageBox.Show( + this, + "Conversion to 1.14 models.bin format does not yet support parent declaration and may not be 100% accurate.\n" + + "Would you like to continue?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes + ) + { + return; + } + + if (container.Version > 1 && + MessageBox.Show( + this, + "Conversion from 1.14 models.bin format does not yet support parent parts and may not be 100% accurate.\n" + + "Would you like to continue?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes + ) + { + return; + } + + asset.SetData(new ModelFileWriter(container, version)); + _wasModified = true; + MessageBox.Show( + this, + $"\"{asset.Filename}\" successfully converted to Version {version + 1} format.", + "Converted model container file" + ); + } + catch (Exception ex) + { + MessageBox.Show(this, ex.Message, "Not a valid model container file."); + return; + } + } + } + + private void setModelVersion1ToolStripMenuItem_Click(object sender, EventArgs e) => SetModelVersion(0); + + private void setModelVersion2ToolStripMenuItem_Click(object sender, EventArgs e) => SetModelVersion(1); + + private void setModelVersion3ToolStripMenuItem_Click(object sender, EventArgs e) => SetModelVersion(2); + + private void treeViewMain_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) + { + if (e.Node is not null) + treeViewMain.SelectedNode = e.Node; + } + + private void contextMenuPCKEntries_Opening(object sender, System.ComponentModel.CancelEventArgs e) + { + correctSkinDecimalsToolStripMenuItem.Visible = false; + generateMipMapTextureToolStripMenuItem1.Visible = false; + setModelContainerFormatToolStripMenuItem.Visible = false; + setSubPCKEndiannessToolStripMenuItem.Visible = false; + exportToolStripMenuItem.Visible = false; + toolStripSeparator5.Visible = false; + toolStripSeparator6.Visible = false; + if (treeViewMain?.SelectedNode.TryGetTagData(out PckAsset asset) ?? false) + { + replaceToolStripMenuItem.Visible = true; + cloneFileToolStripMenuItem.Visible = true; + setFileTypeToolStripMenuItem.Visible = true; + toolStripSeparator5.Visible = true; + toolStripSeparator6.Visible = true; + + if (asset.Type == PckAssetType.SkinFile) + { + correctSkinDecimalsToolStripMenuItem.Visible = true; + exportToolStripMenuItem.Visible = true; + } + if (asset.Type == PckAssetType.TextureFile) + generateMipMapTextureToolStripMenuItem1.Visible = true; + if (asset.Type == PckAssetType.ModelsFile) + setModelContainerFormatToolStripMenuItem.Visible = true; + if (asset.Type == PckAssetType.SkinDataFile || asset.Type == PckAssetType.TexturePackInfoFile || asset.Type == PckAssetType.AudioFile) + setSubPCKEndiannessToolStripMenuItem.Visible = true; + } + else + { + replaceToolStripMenuItem.Visible = false; + cloneFileToolStripMenuItem.Visible = false; + setFileTypeToolStripMenuItem.Visible = false; + } + } + } +} \ No newline at end of file diff --git a/PCK-Studio/Controls/PckEditor.resx b/PCK-Studio/Controls/PckEditor.resx new file mode 100644 index 00000000..5e94f7c7 --- /dev/null +++ b/PCK-Studio/Controls/PckEditor.resx @@ -0,0 +1,2097 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + + + 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 + 8+BMiU9xSj9GDDCHwDUcMkHMV8I4YKwwEz0K5TTDbjg/NnbZmEsvwcYuuVQYpxwTXCyU8g2YMaMA9NIJ + QlbKc/bsWePhf9yV868cRwU+9urlV49ddc3mO2PQDmDbQrL1wvZLH2n1jwL0m3S/9BN9i3ENH0E3I+Ij + 165ePWaFyYNijmQzbk6y88LG0GHSNcktA2RXAwTAVlDG8CCv2hKBdbzbZhRPJilXFq4wuuJh8dIlYxYs + Xjhm/sL5Y+fMgz7wYKfjL5ulHyRZNmWXbKCcX4CWVvpbgeTVFkhq0j+BAmI8iTTZBwWAzyt9dNH16gP/ + HXPlvCvGzJs7Tx9M/ohfjp/5M3zskkuJl5c2/SoAuyjtI8ULoND/ZfgWuhdK9G0bxdkYVm1j0OlYdErs + wq+Zk/kS3sJXSkjy8rMGok+SZSlXQL8z3hvLkn6JT+7OLKZwXrZ0KSvWFSNio/3Wb/3Wb/3Wb/3Wb/3W + b/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3W + b/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3W + b/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb1uy/Yf/8P8D4rKD + rca4/zIAAAAASUVORK5CYII= + + + + + NoControl + + + 413, 0 + + + 190, 50 + + + Zoom + + + + 14 + + + logoPictureBox + + + System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 10 + + + 8, 27 + + + 241, 23 + + + 2 + + + pckFileLabel + + + MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 4 + + + Top, Right + + + True + + + 1369, 252 + + + 30, 19 + + + 19 + + + aaa + + + labelImageSize + + + MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 5 + + + Top, Right + + + True + + + 1347, 53 + + + 0, 0 + + + 17 + + + fileEntryCountLabel + + + MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 6 + + + Bottom, Right + + + True + + + 204, 144 + + + 0, 0 + + + 15 + + + metroLabel2 + + + MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + MetaTab + + + 2 + + + Bottom, Right + + + + + + NoControl + + + 128, 2 + + + 15, 15 + + + 1 + + + False + + + False + + + 215, 114 + + + 146, 20 + + + 21 + + + entryTypeTextBox + + + MetroFramework.Controls.MetroTextBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + MetaTab + + + 3 + + + Bottom, Right + + + + + + NoControl + + + 128, 2 + + + 15, 15 + + + 1 + + + False + + + False + + + 215, 146 + + + 146, 20 + + + 16 + + + entryDataTextBox + + + MetroFramework.Controls.MetroTextBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + MetaTab + + + 4 + + + Bottom, Right + + + 215, 172 + + + 146, 33 + + + 20 + + + buttonEdit + + + False + + + buttonEdit + + + MetroFramework.Controls.MetroButton, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + MetaTab + + + 5 + + + Bottom, Right + + + True + + + 266, 37 + + + 0, 0 + + + 13 + + + metroLabel1 + + + MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + MetaTab + + + 6 + + + 301, 19 + + + 160, 22 + + + Add Entry + + + 160, 22 + + + Add BOX Entry + + + 160, 22 + + + Add ANIM Entry + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAABSSURBVDhP5c0x + DsAgDENRxt7/wmkNSpRGf0CCCZAegxNMM7MlGMp3dIU6dxhKf/QMNxRogeQC8ivw5Vn7C0heJlFA+kL5 + jWAohxRkde4wnGftBS90axNmphIGAAAAAElFTkSuQmCC + + + + 181, 22 + + + Add Entry + + + 181, 22 + + + Add Multiple Entries + + + 181, 22 + + + Delete Entry + + + 181, 22 + + + Edit All Entries + + + 182, 92 + + + contextMenuMetaTree + + + System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Left + + + 5, 5 + + + 204, 229 + + + 0 + + + treeMeta + + + System.Windows.Forms.TreeView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + MetaTab + + + 7 + + + 4, 38 + + + 5, 5, 5, 5 + + + 724, 239 + + + 0 + + + Properties + + + MetaTab + + + MetroFramework.Controls.MetroTabPage, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + PropertiesTabControl + + + 0 + + + Bottom + + + 279, 270 + + + 732, 281 + + + 11 + + + PropertiesTabControl + + + MetroFramework.Controls.MetroTabControl, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 7 + + + True + + + True + + + 433, 71 + + + 0, 0 + + + 3 + + + label11 + + + MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 8 + + + 22, 20 + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xOdTWsmQAAABVSURBVDhPYxgc + 4P8Chv8YeKWUIFSaMPi/W+r//1MapOGTOixQ7UADsCkgAkO1jywDRIGxA8JQPlQ7PQyAaUTDUO30MACG + YZqhfKh24gGGzYMAMDAAAPvHncAZVkkSAAAAAElFTkSuQmCC + + + + 172, 22 + + + Folder + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xOdTWsmQAAAIkSURBVDhPpdLf + T1JxGMfxc1n8qtzcyglCWhFS1PLGHAgisDmktZZtabRSEYhDZ8xpiSWVpaSxLpoXyWquLvzV+oGZq+iy + /6Stm7qsm+DT830YMJw3rbO9Djs7z/P+wob03xcAyWbUwqLXotWgha1pDzPr1axl/y52uEHFrAY1z4l5 + sVsK0IK1UVMbaKQAOXhgN2tuKLHQTKtBh6M0XwmIxe1OtexjXZa9pA6dlnomlgXx7WoCo/1eTF3pwfRQ + gM3HLmD+Wh8yIwE8CgcwFznLJs67cLPPgeMmXW1gKRXCZjqGfCbBvi6kWH6OnoXMKFsd68fa2CW0Haqr + BpYnh5G7F8PGtIyV2yG2NhXHeuo6nioD5CI+pRMsG+nFYqSHVQKrt0LYKAcmhyCeX6Vklk0MsI9phQIK + Bfy07OfPSkAs/v7xDcViEd6OZ/C2LyOXHMb75Agtlk72nF6hdy/FEgrFP3yI2OVA7r6MXz+/04siPB3P + aXgJ75JhbFIgP5PAZwr42lcp8IJnioUCBcLVQHbQizfjQTr1Kj7cTbBIpw1R54mK/GwMXwjqaYWkzrVV + A4uDPry+QYGJIN7eUVjMcQyyvWrrQRxbM/GdA4+Dbjy57MJC0AmnUQ2XUYPZXjse+qvKi9vRHZLisUJx + WyB3m0sBkwZuvYr56A8j7LQs0B2S7LMg2n0EUY8ZdpMaDgo4mlSsq1lXo7w4fuZk6Sf861U5mS9J+gsp + e+98+xbVEAAAAABJRU5ErkJggg== + + + + 172, 22 + + + Skin + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAAI/SURBVDhPjZHt + b9JQFMbvv6IRCiYmU+cGpQXH5oACMkZvgQILG2Su7e2mE3l1cTMricaXEQtscVN0UYIaB8MZmW/ZFxP/ + KrzNpCHxi0+eL/ec53fuSQ7IHLqyXW+uwwj7lLBvQweu9N6Y/M65/h3iOmpNLL2hxaYj1bAEnxhXPkyB + TNe9/H76YS96rzOz0Z3lSQI1banX1uTLMfVkYetnMt/2LTRGMq1rwlv7SssJHnyLcbRp77csvLLdaF1l + HabVg+mElVg9cq//gOpJ+tmvVNRmiKsXUi8sPGUGPEWIshihiShlvN1meNoQoQ1R2jDfuBimCfHjJOsg + SrNXWIcRJwuQBFXJneXoOvL0NiGkzDtLrgJnKUIySp6L0MYYeVYWhUKYrAq+MG3WgGJolCfP1BGzI0zc + gfYcpNrlNHZ/SE9Ff4Ejn4vOjjIHDu7HI7RpjRsvsiOPN+7iRmVxqpkLakEANPf7ypyjnJzEQzEDegon + eS/t3grs3gw+Ki5iIAfJCgoMA7i4hWZU6TpmwCdlHr+7SvpoM1YR/VpO1wDQhRlQkzzZ0OVsmKwhby5k + 1cqnuX+tA1WZ4e3mUtiK/X/AcgBv9bUcx9YAXYOcrlPAm+fIIhyvIh/e6lhJYHiNHdX6AwAHPpcTPSWm + AVnWCh2mbeQpQEtN9tclpip78nBot37/i5KoIUY7rhIDOdaiIl+es5U4MkIZ8S15O4E/0YCB8HNbcuOh + mAGqxOQ5S4Q6f1yOF6CVp0w6gxfQ/ZdBnj/Cc21Sm8M0egAAAABJRU5ErkJggg== + + + + 172, 22 + + + Animated Texture + + + 172, 22 + + + Audio.pck + + + 172, 22 + + + Colours.col + + + 172, 22 + + + Skins.pck + + + 172, 22 + + + Behaviours.bin + + + 172, 22 + + + EntityMaterials.bin + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xOdTWsmQAAAA3SURBVDhPY/j/ + /z9FGKsgGIsCKWSMTQ0QYxUE45FmALpiYvFwMgAbxqIYG8YqCMajBhCJ/zMAAPGwpV/Xje8RAAAAAElF + TkSuQmCC + + + + 157, 22 + + + Create + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xOdTWsmQAAAIkSURBVDhPpdLf + T1JxGMfxc1n8qtzcyglCWhFS1PLGHAgisDmktZZtabRSEYhDZ8xpiSWVpaSxLpoXyWquLvzV+oGZq+iy + /6Stm7qsm+DT830YMJw3rbO9Djs7z/P+wob03xcAyWbUwqLXotWgha1pDzPr1axl/y52uEHFrAY1z4l5 + sVsK0IK1UVMbaKQAOXhgN2tuKLHQTKtBh6M0XwmIxe1OtexjXZa9pA6dlnomlgXx7WoCo/1eTF3pwfRQ + gM3HLmD+Wh8yIwE8CgcwFznLJs67cLPPgeMmXW1gKRXCZjqGfCbBvi6kWH6OnoXMKFsd68fa2CW0Haqr + BpYnh5G7F8PGtIyV2yG2NhXHeuo6nioD5CI+pRMsG+nFYqSHVQKrt0LYKAcmhyCeX6Vklk0MsI9phQIK + Bfy07OfPSkAs/v7xDcViEd6OZ/C2LyOXHMb75Agtlk72nF6hdy/FEgrFP3yI2OVA7r6MXz+/04siPB3P + aXgJ75JhbFIgP5PAZwr42lcp8IJnioUCBcLVQHbQizfjQTr1Kj7cTbBIpw1R54mK/GwMXwjqaYWkzrVV + A4uDPry+QYGJIN7eUVjMcQyyvWrrQRxbM/GdA4+Dbjy57MJC0AmnUQ2XUYPZXjse+qvKi9vRHZLisUJx + WyB3m0sBkwZuvYr56A8j7LQs0B2S7LMg2n0EUY8ZdpMaDgo4mlSsq1lXo7w4fuZk6Sf861U5mS9J+gsp + e+98+xbVEAAAAABJRU5ErkJggg== + + + + 228, 22 + + + Import Skin + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xOdTWsmQAAAEnSURBVDhPYxgc + 4P8Chv8YeKWUIFSaMPi/W+r//1MapOGTOixQ7UADkCS05Xjh2FhFEIydtIT+22uJAsX4wBimFqod04Bt + nTn/9/YV/T82rQGM93YXAfkl/1eVRYPl8RqwuTnn/5aW3P8r69L+r67P+7+mIf//rIKo/7s7i/7PyfT9 + PzvTC78BW6AGrKpN+7+2IReM5xTF/N/VWQA0wAdogA8BA4Ca//7799/VauH/TdUZ/7dVp//fA7Td3XLV + //+iwNgBYXwGbCiP+7+5Oun/9qai/5n2+v+zHAzAeG9HDnEGTIl3/D8tzuG/owLP/w5f2/9dPrYIjWgY + qh3VgAJnrf+5Lhr/HRV5/jvLcoExNs0gDNWOagBeDNMM5UO1Ew8wbB4EgIEBABiEccKRdcoAAAAAAElF + TkSuQmCC + + + + 228, 22 + + + Import Extracted Skins Folder + + + 228, 22 + + + Add Texture + + + 228, 22 + + + Add File + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xOdTWsmQAAABzSURBVDhPpYzB + DQAhCARp4hr3Txu254WTjYRb9cEmk/BgRjBVHTv85Twmgt77PcJEYIFrhIkAgWOEiSAGthEmgtbaD9fW + mBgpB4xywCgFxiMf5YDdrq3l5wjEjKtzTARMNlydY2IGot2ureVnRjkQmZbICyCi7XU5cfqKAAAAAElF + TkSuQmCC + + + + 157, 22 + + + Import + + + 186, 22 + + + Export as 3DS Texture + + + 157, 22 + + + Export + + + 222, 22 + + + Skin (.PNG) + + + 222, 22 + + + Cape (.PNG) + + + 222, 22 + + + Texture (.PNG) + + + 222, 22 + + + Languages File (.LOC) + + + 222, 22 + + + Game Rules File (.GRF) + + + 222, 22 + + + Music Cues File (audio.PCK) + + + 222, 22 + + + Colour Table File (.COL) + + + 222, 22 + + + Game Rules Header (.GRH) + + + 222, 22 + + + Skins PCK (.PCK) + + + 222, 22 + + + Models File (.BIN) + + + 222, 22 + + + Behaviours File (.BIN) + + + 222, 22 + + + Entity Materials File (.BIN) + + + 157, 22 + + + Set File Type + + + 154, 6 + + + 223, 22 + + + Generate MipMap Texture + + + 223, 22 + + + View File Info + + + 223, 22 + + + Correct Skin Decimals + + + 100, 22 + + + Big + + + 100, 22 + + + Little + + + 223, 22 + + + Set Endianness + + + 80, 22 + + + 1 + + + 80, 22 + + + 2 + + + 80, 22 + + + 3 + + + 223, 22 + + + Set Model Container version + + + 157, 22 + + + Misc. Functions + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAACYSURBVDhPpZBZ + CsQwDEOd5QK5/2E9qCBGXtopzMcDxxKyY3P3izmnm9kt0OlVvsVVVgOAtvduQ4KJdYbaGKOEFFOHamut + ENKaMlk75zi2QX1rUqDpkbEF/cGktb47ygb5ODA8hVArgsK1cx+EAE7LaB8+hb3QzDx942eAXrqjBOgR + MRkBfHeUADbe8ncANw4NhLwF33R3+wA6sV5/E8GOLwAAAABJRU5ErkJggg== + + + + 157, 22 + + + Extract + + + 154, 6 + + + 157, 22 + + + Clone + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAACVJREFUOE9jwAL+E8AkAbI0IYNRA0YNAIFRA8g0AKYJF0YCDAwAzhor1TRE/JoA + AAAASUVORK5CYII= + + + + 157, 22 + + + Rename + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAAC/SURBVDhPlVHB + DQMhDEOIfwfoOuzFoPxhAd5c6/SMAgq0tRQFmdgXfA5IKUkBMcbHPxyJCxVCkK7rm+EwaK1dQO9dClzO + WfpOTM7hy1oMGNvY4pucxNY2p6cAWzFw2oZuMmiJweGeHM634UdLg50YwD05vQ2fYoaoDTEMrJyIfw3R + 4qYQWUZgg6OwlDJyMH8LcwF2T8FZ5kYQb4Lde/9Et8S6Dy1z0LUGi7VpWGvl3Lw2V98ZrtwIUYktwwPn + 3AtE5NqX8pp0ZQAAAABJRU5ErkJggg== + + + + 157, 22 + + + Replace + + + 157, 22 + + + Delete + + + 158, 236 + + + contextMenuPCKEntries + + + System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Left + + + 0 + + + 204, 20 + + + 32, 32 + + + 5, 50 + + + 0 + + + 274, 501 + + + 20 + + + treeViewMain + + + System.Windows.Forms.TreeView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 9 + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAABSSURBVDhP5c0x + DsAgDENRxt7/wmkNSpRGf0CCCZAegxNMM7MlGMp3dIU6dxhKf/QMNxRogeQC8ivw5Vn7C0heJlFA+kL5 + jWAohxRkde4wnGftBS90axNmphIGAAAAAElFTkSuQmCC + + + + 181, 22 + + + Add Multiple Entries + + + Top, Right + + + True + + + 831, 0 + + + 173, 15 + + + 22 + + + Save as Switch/Vita/PS4 PCK + + + LittleEndianCheckBox + + + MetroFramework.Controls.MetroCheckBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 3 + + + Top, Bottom, Left, Right + + + None + + + NoControl + + + 285, 50 + + + 218, 218 + + + Zoom + + + 18 + + + previewPictureBox + + + PckStudio.ToolboxItems.InterpolationPictureBox, PCK-Studio, Version=7.0.0.2, Culture=neutral, PublicKeyToken=null + + + $this + + + 2 + + + True + + + None + + + 4, 38 + + + 5, 50, 5, 7 + + + 1016, 558 + + + addEntryToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + addEntryToolStripMenuItem1 + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + addBOXEntryToolStripMenuItem1 + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + addANIMEntryToolStripMenuItem1 + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + addMultipleEntriesToolStripMenuItem1 + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + deleteEntryToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + editAllEntriesToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + createToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + folderToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + skinToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + createAnimatedTextureToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + audiopckToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + colourscolToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + CreateSkinsPCKToolStripMenuItem1 + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + behavioursbinToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + entityMaterialsbinToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + importSkinsToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + importSkinToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + importExtractedSkinsFolderToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + addTextureToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + addFileToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + exportToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + as3DSTextureFileToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + setFileTypeToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + skinToolStripMenuItem1 + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + capeToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + textureToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + languagesFileLOCToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + gameRulesFileGRFToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + audioPCKFileToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + coloursCOLFileToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + gameRulesHeaderGRHToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + skinsPCKToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + modelsFileBINToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + behavioursFileBINToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + entityMaterialsFileBINToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripSeparator5 + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + miscFunctionsToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + generateMipMapTextureToolStripMenuItem1 + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + viewFileInfoToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + correctSkinDecimalsToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + setSubPCKEndiannessToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + bigEndianXbox360PS3WiiUToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + littleEndianPS4PSVitaSwitchToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + setModelContainerFormatToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + version1ToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + version2ToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + version3114ToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + extractToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripSeparator6 + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + cloneFileToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + renameFileToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + replaceToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + deleteFileToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + imageList + + + System.Windows.Forms.ImageList, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + addMultipleEntriesToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + PckEditor + + + PckStudio.Internal.EditorControl`1[[PckStudio.Internal.PackInfo, PCK-Studio, Version=7.0.0.2, Culture=neutral, PublicKeyToken=null]], PCK-Studio, Version=7.0.0.2, Culture=neutral, PublicKeyToken=null + + \ No newline at end of file diff --git a/PCK-Studio/Extensions/AnimationExtensions.cs b/PCK-Studio/Extensions/AnimationExtensions.cs deleted file mode 100644 index 81af938a..00000000 --- a/PCK-Studio/Extensions/AnimationExtensions.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Drawing; -using AnimatedGif; -using PckStudio.Internal; - -namespace PckStudio.Extensions -{ - internal static class AnimationExtensions - { - internal static Image CreateAnimationImage(this Animation animation) - { - if (animation.FrameCount == 0) - { - return null; - } - var ms = new System.IO.MemoryStream(); - var generateor = new AnimatedGifCreator(ms, GameConstants.GameTickInMilliseconds, 0); - foreach (Animation.Frame frame in animation.GetInterpolatedFrames()) - { - generateor.AddFrame(frame.Texture, frame.Ticks * GameConstants.GameTickInMilliseconds, GifQuality.Bit8); - } - ms.Position = 0; - return Image.FromStream(ms); - } - } -} diff --git a/PCK-Studio/Extensions/ImageLayoutDirection.cs b/PCK-Studio/Extensions/ImageLayoutDirection.cs deleted file mode 100644 index 7cfc23eb..00000000 --- a/PCK-Studio/Extensions/ImageLayoutDirection.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace PckStudio.Extensions -{ - internal enum ImageLayoutDirection - { - Horizontal, - Vertical - } -} diff --git a/PCK-Studio/Extensions/PckAssetExtensions.cs b/PCK-Studio/Extensions/PckAssetExtensions.cs deleted file mode 100644 index 08c3f96e..00000000 --- a/PCK-Studio/Extensions/PckAssetExtensions.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Text; -using System.Drawing; -using System.Collections.Generic; - -using OMI.Formats.Pck; -using OMI.Workers; - -using PckStudio.Interfaces; -using PckStudio.Internal.Deserializer; -using PckStudio.Internal.Serializer; - -namespace PckStudio.Extensions -{ - internal static class PckAssetExtensions - { - private const string MipMap = "MipMapLevel"; - - internal static PckAsset CreateNewAssetIf(this PckFile pck, bool condition, string filename, PckAssetType filetype, IDataFormatWriter writer) - { - if (condition) - { - return pck.CreateNewAsset(filename, filetype, writer); - } - return default; - } - - internal static PckAsset CreateNewAsset(this PckFile pck, string filename, PckAssetType filetype, IDataFormatWriter writer) - { - PckAsset asset = pck.CreateNewAsset(filename, filetype); - asset.SetData(writer); - return asset; - } - - internal static Image GetTexture(this PckAsset asset) - { - if (asset.Type != PckAssetType.SkinFile && - asset.Type != PckAssetType.CapeFile && - asset.Type != PckAssetType.TextureFile) - { - throw new Exception("Asset is not suitable to contain image data."); - } - return asset.GetDeserializedData(ImageDeserializer.DefaultDeserializer); - } - - internal static T GetDeserializedData(this PckAsset asset, IPckAssetDeserializer deserializer) - { - return deserializer.Deserialize(asset); - } - - internal static T GetData(this PckAsset asset, IDataFormatReader formatReader) where T : class - { - using var ms = new MemoryStream(asset.Data); - return formatReader.FromStream(ms); - } - - internal static void SetSerializedData(this PckAsset asset, T obj, IPckAssetSerializer serializer) - { - serializer.Serialize(obj, ref asset); - } - - internal static void SetData(this PckAsset asset, IDataFormatWriter formatWriter) - { - using (var stream = new MemoryStream()) - { - formatWriter.WriteToStream(stream); - asset.SetData(stream.ToArray()); - } - } - - internal static void SetTexture(this PckAsset asset, Image image) - { - if (asset.Type != PckAssetType.SkinFile && - asset.Type != PckAssetType.CapeFile && - asset.Type != PckAssetType.TextureFile) - { - throw new Exception("Asset is not suitable to contain image data."); - } - asset.SetSerializedData(image, ImageSerializer.DefaultSerializer); - } - - internal static bool IsMipmappedFile(this PckAsset asset) - { - // We only want to test the file name itself. ex: "terrainMipMapLevel2" - string name = Path.GetFileNameWithoutExtension(asset.Filename); - - // check if last character is a digit (0-9). If not return false - if (!char.IsDigit(name[name.Length - 1])) - return false; - - // If string does not end with MipMapLevel, then it's not MipMapped - if (!name.Remove(name.Length - 1, 1).EndsWith(MipMap)) - return false; - return true; - } - - internal static string GetNormalPath(this PckAsset asset) - { - if (!asset.IsMipmappedFile()) - return asset.Filename; - string ext = Path.GetExtension(asset.Filename); - return asset.Filename.Remove(asset.Filename.Length - (MipMap.Length + 1) - ext.Length) + ext; - } - - internal static void DeserializeProperties(this PckAsset asset, IEnumerable serializedData) - { - IEnumerable> lines = serializedData - .Select(line => line.Split([' '], 2)) - .Where (keyValue => keyValue.Length == 2) - .Select(keyValue => new KeyValuePair(keyValue[0].Replace(":", ""), keyValue[1])); - foreach (KeyValuePair kv in lines) - { - asset.AddProperty(kv); - } - } - - internal static IEnumerable SerializeProperties(this PckAsset asset, string seperater = ":") - { - IReadOnlyList> properties = asset.GetProperties(); - return properties.Select(property => property.Key + seperater + property.Value); - } - } -} diff --git a/PCK-Studio/External/API/Miles/Binka.cs b/PCK-Studio/External/API/Miles/Binka.cs index 16e6ee96..47000ef8 100644 --- a/PCK-Studio/External/API/Miles/Binka.cs +++ b/PCK-Studio/External/API/Miles/Binka.cs @@ -2,7 +2,7 @@ using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; -using PckStudio.Extensions; +using PckStudio.Core.Extensions; using PckStudio.Internal; using PckStudio.Internal.App; using SharpMSS; diff --git a/PCK-Studio/FileFormats/CSMBFile.cs b/PCK-Studio/FileFormats/CSMBFile.cs deleted file mode 100644 index b07d8f80..00000000 --- a/PCK-Studio/FileFormats/CSMBFile.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Drawing; -using System.IO; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace PckStudio.FileFormats -{ - #region File Structure - /* - Version - 4 bytes[int32] - NumberOfParts - 4 bytes[int32] - { - Part name length - 2 bytes[int16] - part name - x bytes - part parent - 4 bytes[int32] (HEAD=1, BODY=2, LEG0=3, LEG1=4, ARM0=5, ARM1=6) - Position-X - 4 bytes[float] - Position-Y - 4 bytes[float] - Position-Z - 4 bytes[float] - Size-X - 4 bytes[float] - Size-Y - 4 bytes[float] - Size-Z - 4 bytes[float] - UV-Y - 4 bytes[int32] - UV-X - 4 bytes[int32] - mirror texture - 1 byte[bool] - Hide with armour - 1 byte[bool] - inflation/scale value - 4 bytes[float] - } - NumberOfOffsets - 4 bytes[int32] - { - offset part - 4 bytes[int32] - vertical offset - 4 bytes[float] - } - */ - #endregion - class CSMBFile - { - public List Parts = new List(); - public List Offsets = new List(); - } - - public class CSMBPart - { - public string Name = "Partname"; - public CSMBParentPart Parent = 0; - public float posX, posY, posZ = 0.0f; - public float sizeX, sizeY, sizeZ = 0.0f; - public int uvX, uvY = 0; - public bool HideWArmour, MirrorTexture = false; - public float Inflation = 0.0f; - } - public class CSMBOffset - { - public CSMBOffsetPart offsetPart = 0; - public float VerticalOffset = 0.0f; - } - - public enum CSMBOffsetPart - { - HEAD = 0, - BODY = 1, - ARM0 = 2, - ARM1 = 3, - LEG0 = 4, - LEG1 = 5, - HEADWEAR = 6, - JACKET = 7, - SLEEVE0 = 8, - SLEEVE1 = 9, - PANTS0 = 10, - PANTS1 = 11, - WAIST = 12, - LEGGING0 = 13, - LEGGING1 = 14, - SOCK0 = 15, - SOCK1 = 16, - BOOT0 = 17, - BOOT1 = 18, - ARMARMOR1 = 19, - ARMARMOR0 = 20, - BODYARMOR = 21, - BELT = 22, - TOOL0 = 23, - TOOL1 = 24, - HELMET = 25, - SHOULDER0 = 26, - SHOULDER1 = 27, - CHEST = 28 - } - - public enum CSMBParentPart - { - HEAD = 0, - BODY = 1, - ARM0 = 2, - ARM1 = 3, - LEG0 = 4, - LEG1 = 5, - } -} diff --git a/PCK-Studio/Forms/Additional-Popups/AddSkinPrompt.Designer.cs b/PCK-Studio/Forms/Additional-Popups/AddSkinPrompt.Designer.cs index bd3df23c..52426b93 100644 --- a/PCK-Studio/Forms/Additional-Popups/AddSkinPrompt.Designer.cs +++ b/PCK-Studio/Forms/Additional-Popups/AddSkinPrompt.Designer.cs @@ -33,7 +33,6 @@ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddSkinPrompt)); System.Windows.Forms.Label label2; System.Windows.Forms.Label label1; - this.textTheme = new System.Windows.Forms.TextBox(); this.contextMenuSkin = new System.Windows.Forms.ContextMenuStrip(this.components); this.replaceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.contextMenuCape = new System.Windows.Forms.ContextMenuStrip(this.components); @@ -81,11 +80,6 @@ label1.ForeColor = System.Drawing.Color.White; label1.Name = "label1"; // - // textTheme - // - resources.ApplyResources(this.textTheme, "textTheme"); - this.textTheme.Name = "textTheme"; - // // contextMenuSkin // this.contextMenuSkin.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -289,6 +283,7 @@ // capePictureBox // resources.ApplyResources(this.capePictureBox, "capePictureBox"); + this.capePictureBox.BackgroundInterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default; this.capePictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.capePictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; this.capePictureBox.Name = "capePictureBox"; @@ -298,6 +293,7 @@ // skinPictureBox // resources.ApplyResources(this.skinPictureBox, "skinPictureBox"); + this.skinPictureBox.BackgroundInterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default; this.skinPictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.skinPictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; this.skinPictureBox.Name = "skinPictureBox"; @@ -343,7 +339,6 @@ } #endregion - private System.Windows.Forms.TextBox textTheme; private System.Windows.Forms.ContextMenuStrip contextMenuSkin; private System.Windows.Forms.ToolStripMenuItem replaceToolStripMenuItem; private System.Windows.Forms.ContextMenuStrip contextMenuCape; diff --git a/PCK-Studio/Forms/Additional-Popups/AddSkinPrompt.cs b/PCK-Studio/Forms/Additional-Popups/AddSkinPrompt.cs index 0fa628c5..a2f83a5c 100644 --- a/PCK-Studio/Forms/Additional-Popups/AddSkinPrompt.cs +++ b/PCK-Studio/Forms/Additional-Popups/AddSkinPrompt.cs @@ -8,127 +8,90 @@ using OMI.Formats.Languages; using OMI.Formats.Pck; using PckStudio.Internal; using PckStudio.Forms.Editor; -using PckStudio.Internal.IO._3DST; +using PckStudio.Core.IO._3DST; using PckStudio.Properties; using PckStudio.Forms; -using PckStudio.Extensions; +using PckStudio.Core.Extensions; +using System.Linq; +using System.Diagnostics; +using PckStudio.Core.Skin; +using PckStudio.Interfaces; +using PckStudio.Core; namespace PckStudio.Forms.Additional_Popups { public partial class AddSkinPrompt : MetroFramework.Forms.MetroForm { - public PckAsset SkinAsset => _skin; - public PckAsset CapeAsset => _cape; - public bool HasCape => _cape is not null; + public Skin NewSkin => newSkin; - private LOCFile currentLoc; - private PckAsset _skin = new PckAsset("dlcskinXYXYXYXY", PckAssetType.SkinFile); - private PckAsset _cape; - private SkinANIM _anim = SkinANIM.Empty; + private Skin newSkin; private Random rng = new Random(); - private eSkinType skinType; - - private enum eSkinType - { - Invalid = -1, - _64x64, - _64x32, - _64x64HD, - _64x32HD, - Custom, - } - - public AddSkinPrompt(LOCFile loc) + public AddSkinPrompt() { InitializeComponent(); - currentLoc = loc; + newSkin = new Skin("", new SkinANIM(SkinAnimMask.RESOLUTION_64x64), Resources.classic_template, Enumerable.Empty(), Enumerable.Empty()); } - private void CheckImage(Image img) + private void SetNewTexture(Image img) { - switch (img.Height) + Debug.Assert(img is not null, "Image is null."); + + if (img.Width != img.Height && img.Height != img.Width / 2) { - case 64: - _anim = _anim.SetFlag(SkinAnimFlag.RESOLUTION_64x64, true); - MessageBox.Show(this, "64x64 Skin Detected"); - skinType = eSkinType._64x64; - break; - case 32: - _anim = _anim.SetFlag(SkinAnimFlag.RESOLUTION_64x64 | SkinAnimFlag.SLIM_MODEL, false); - MessageBox.Show(this, "64x32 Skin Detected"); - skinType = eSkinType._64x32; - break; - default: - if (img.Width == img.Height) - { - _anim = _anim.SetFlag(SkinAnimFlag.RESOLUTION_64x64, true); - MessageBox.Show(this, "64x64 HD Skin Detected"); - skinType = eSkinType._64x64HD; - break; - } - - if (img.Height == img.Width / 2) - { - _anim = _anim.SetFlag(SkinAnimFlag.RESOLUTION_64x64 | SkinAnimFlag.SLIM_MODEL, false); - MessageBox.Show(this, "64x32 HD Skin Detected"); - skinType = eSkinType._64x32HD; - break; - } - - MessageBox.Show(this, "Not a Valid Skin File"); - skinType = eSkinType.Invalid; - return; + MessageBox.Show("The selected image does not suit a skin texture.", "Invalid image dimensions.", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; } + newSkin.Anim.SetFlag(SkinAnimFlag.RESOLUTION_64x64, img.Width == img.Height); - skinPictureBox.Image = img; + skinPictureBox.Image = newSkin.Texture = img; + labelSelectTexture.Visible = false; capePictureBox.Visible = true; buttonCape.Visible = true; capeLabel.Visible = true; buttonDone.Enabled = true; buttonAnimGen.Enabled = true; - labelSelectTexture.Visible = false; } private void DrawModel() { - bool isSlim = _anim.GetFlag(SkinAnimFlag.SLIM_MODEL); + bool isSlim = newSkin.Anim.GetFlag(SkinAnimFlag.SLIM_MODEL); Pen outlineColor = Pens.LightGray; Brush fillColor = Brushes.Gray; Image previewTexture = new Bitmap(displayBox.Width, displayBox.Height); using (Graphics g = Graphics.FromImage(previewTexture)) { - if(!_anim.GetFlag(SkinAnimFlag.HEAD_DISABLED)) + if(!newSkin.Anim.GetFlag(SkinAnimFlag.HEAD_DISABLED)) { //Head g.DrawRectangle(outlineColor, 70, 15, 40, 40); g.FillRectangle(fillColor, 71, 16, 39, 39); } - if (!_anim.GetFlag(SkinAnimFlag.BODY_DISABLED)) + if (!newSkin.Anim.GetFlag(SkinAnimFlag.BODY_DISABLED)) { //Body g.DrawRectangle(outlineColor, 70, 55, 40, 60); g.FillRectangle(fillColor, 71, 56, 39, 59); } - if (!_anim.GetFlag(SkinAnimFlag.RIGHT_ARM_DISABLED)) + if (!newSkin.Anim.GetFlag(SkinAnimFlag.RIGHT_ARM_DISABLED)) { //Arm0 g.DrawRectangle(outlineColor, isSlim ? 55 : 50, 55, isSlim ? 15 : 20, 60); g.FillRectangle(fillColor , isSlim ? 56 : 51, 56, isSlim ? 14 : 19, 59); } - if (!_anim.GetFlag(SkinAnimFlag.LEFT_ARM_DISABLED)) + if (!newSkin.Anim.GetFlag(SkinAnimFlag.LEFT_ARM_DISABLED)) { //Arm1 g.DrawRectangle(outlineColor, 110, 55, isSlim ? 15 : 20, 60); g.FillRectangle(fillColor, 111, 56, isSlim ? 14 : 19, 59); } - if (!_anim.GetFlag(SkinAnimFlag.RIGHT_LEG_DISABLED)) + if (!newSkin.Anim.GetFlag(SkinAnimFlag.RIGHT_LEG_DISABLED)) { //Leg0 g.DrawRectangle(outlineColor, 70, 115, 20, 60); g.FillRectangle(fillColor, 71, 116, 19, 59); } - if (!_anim.GetFlag(SkinAnimFlag.LEFT_LEG_DISABLED)) + if (!newSkin.Anim.GetFlag(SkinAnimFlag.LEFT_LEG_DISABLED)) { //Leg1 g.DrawRectangle(outlineColor, 90, 115, 20, 60); @@ -158,7 +121,7 @@ namespace PckStudio.Forms.Additional_Popups OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == DialogResult.OK) { - CheckImage(Image.FromFile(ofd.FileName)); + SetNewTexture(Image.FromFile(ofd.FileName).ReleaseFromFile()); } } @@ -188,12 +151,14 @@ namespace PckStudio.Forms.Additional_Popups using (FileStream fs = File.OpenRead(ofd.FileName)) { var reader = new _3DSTextureReader(); - CheckImage(reader.FromStream(fs)); + SetNewTexture(reader.FromStream(fs)); } textSkinName.Text = Path.GetFileNameWithoutExtension(ofd.FileName); return; } - CheckImage(Image.FromFile(ofd.FileName)); + + Image img = Image.FromFile(ofd.FileName).ReleaseFromFile(); + SetNewTexture(img); } } } @@ -219,15 +184,13 @@ namespace PckStudio.Forms.Additional_Popups ofd.Title = "Select a PNG File"; if (ofd.ShowDialog() == DialogResult.OK) { - var img = Image.FromFile(ofd.FileName); + Image img = Image.FromFile(ofd.FileName).ReleaseFromFile(); if (img.RawFormat != ImageFormat.Png && img.Width != img.Height * 2) { MessageBox.Show(this, "Not a Valid Cape File"); return; } - capePictureBox.Image = Image.FromFile(ofd.FileName); - _cape ??= new PckAsset("dlccapeXYXYXYXY", PckAssetType.CapeFile); - _cape.SetData(File.ReadAllBytes(ofd.FileName)); + newSkin.CapeTexture = capePictureBox.Image = img; contextMenuCape.Items[0].Text = "Replace"; capeLabel.Visible = false; contextMenuCape.Visible = true; @@ -237,43 +200,17 @@ namespace PckStudio.Forms.Additional_Popups private void CreateButton_Click(object sender, EventArgs e) { - if (!int.TryParse(textSkinID.Text, out int skinId)) + if (radioButtonManual.Checked) { - MessageBox.Show(this, "The Skin ID Must be a Unique 8 Digit Number Thats Not Already in Use", "Invalid Skin ID", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - string skinIdStr = skinId.ToString("d08"); - _skin.Filename = $"dlcskin{skinIdStr}.png"; - _skin.AddProperty("DISPLAYNAME", textSkinName.Text); - - if (currentLoc is not null) - { - string skinDisplayNameLocKey = $"IDS_dlcskin{skinIdStr}_DISPLAYNAME"; - _skin.AddProperty("DISPLAYNAMEID", skinDisplayNameLocKey); - currentLoc.AddLocKey(skinDisplayNameLocKey, textSkinName.Text); - } - - if (!string.IsNullOrEmpty(textThemeName.Text)) - { - _skin.AddProperty("THEMENAME", textThemeName.Text); - if (currentLoc is not null) + if (!int.TryParse(textSkinID.Text, out int skinId)) { - _skin.AddProperty("THEMENAMEID", $"IDS_dlcskin{skinIdStr}_THEMENAME"); - currentLoc.AddLocKey($"IDS_dlcskin{skinIdStr}_THEMENAME", textThemeName.Text); + MessageBox.Show("The Skin Id must be a unique 8 digit number that is not already in use", "Invalid Skin Id", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; } + newSkin.Identifier = new SkinIdentifier(skinId); } - _skin.AddProperty("ANIM", _anim); - _skin.AddProperty("GAME_FLAGS", "0x18"); - _skin.AddProperty("FREE", "1"); - - if (HasCape) - { - _cape.Filename = $"dlccape{skinIdStr}.png"; - _skin.AddProperty("CAPEPATH", _cape.Filename); - } - _skin.SetTexture(skinPictureBox.Image); + newSkin.MetaData = new SkinMetaData(textSkinName.Text, textThemeName.Text); DialogResult = DialogResult.OK; - Close(); } private void textSkinID_TextChanged(object sender, EventArgs e) @@ -284,24 +221,21 @@ namespace PckStudio.Forms.Additional_Popups private void CreateCustomModel_Click(object sender, EventArgs e) { - //Prompt for skin model generator - if (MessageBox.Show(this, "Create your own custom skin model?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1) != DialogResult.Yes) + if (MessageBox.Show("Create your own custom skin model?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1) != DialogResult.Yes) return; - _skin.SetTexture(Resources.classic_template); + newSkin.MetaData = new SkinMetaData(textSkinName.Text, textThemeName.Text); - using generateModel generate = new generateModel(_skin); + ISaveContext saveContext = new DelegatedSaveContext(Settings.Default.AutoSaveChanges, (customSkin) => newSkin = customSkin); - if (generate.ShowDialog() == DialogResult.OK) + using CustomSkinEditor customSkinEditor = new CustomSkinEditor(newSkin, saveContext); + + if (customSkinEditor.ShowDialog() == DialogResult.OK) { - displayBox.Image = generate.PreviewImage; + skinPictureBox.Image = newSkin.Texture; buttonDone.Enabled = true; labelSelectTexture.Visible = false; - if (skinType != eSkinType._64x64 && skinType != eSkinType._64x64HD) - { - buttonSkin.Location = new Point(buttonSkin.Location.X - skinPictureBox.Width, buttonSkin.Location.Y); - skinType = eSkinType._64x64; - } + DrawModel(); } } @@ -309,8 +243,8 @@ namespace PckStudio.Forms.Additional_Popups { if (radioButtonAuto.Checked) { - int num = rng.Next(100000, 99999999); - textSkinID.Text = num.ToString(); + newSkin.Identifier = new(rng.Next(100000, 99999999)); + textSkinID.Text = newSkin.Identifier.ToString(); textSkinID.Enabled = false; } } @@ -322,10 +256,10 @@ namespace PckStudio.Forms.Additional_Popups private void buttonAnimGen_Click(object sender, EventArgs e) { - using ANIMEditor diag = new ANIMEditor(_anim); + using ANIMEditor diag = new ANIMEditor(newSkin.Anim); if (diag.ShowDialog(this) == DialogResult.OK) { - _anim = diag.ResultAnim; + newSkin.Anim = diag.ResultAnim; DrawModel(); } } diff --git a/PCK-Studio/Forms/Additional-Popups/AddSkinPrompt.resx b/PCK-Studio/Forms/Additional-Popups/AddSkinPrompt.resx index 6e87bf23..4255bf1a 100644 --- a/PCK-Studio/Forms/Additional-Popups/AddSkinPrompt.resx +++ b/PCK-Studio/Forms/Additional-Popups/AddSkinPrompt.resx @@ -219,21 +219,6 @@ 19 - - 102, 78 - - - 239, 20 - - - 32 - - - textTheme - - - System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 17, 17 @@ -654,9 +639,6 @@ 4 - - False - 108, 259 diff --git a/PCK-Studio/Forms/Additional-Popups/Animation/ChangeTile.cs b/PCK-Studio/Forms/Additional-Popups/Animation/ChangeTile.cs index 58fdc3aa..de2fa054 100644 --- a/PCK-Studio/Forms/Additional-Popups/Animation/ChangeTile.cs +++ b/PCK-Studio/Forms/Additional-Popups/Animation/ChangeTile.cs @@ -1,14 +1,10 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Windows.Forms; -using MetroFramework.Controls; -using System.Xml.Linq; -using MetroFramework.Forms; -using PckStudio.Extensions; -using PckStudio.Internal; -using PckStudio.Internal.App; -using PckStudio.Internal.Json; +using PckStudio.Core; +using PckStudio.Core.Json; +using PckStudio.Json; +using PckStudio.Core.Extensions; namespace PckStudio.Forms.Additional_Popups.Animation { @@ -32,10 +28,8 @@ namespace PckStudio.Forms.Additional_Popups.Animation private void InitializeTreeviews() { - Profiler.Start(); GetTileDataToView(ResourceCategory.BlockAnimation); GetTileDataToView(ResourceCategory.ItemAnimation); - Profiler.Stop(); } public DialogResult ShowDialog(IWin32Window owner) diff --git a/PCK-Studio/Forms/Additional-Popups/EntityForms/AddEntry.cs b/PCK-Studio/Forms/Additional-Popups/EntityForms/AddEntry.cs index 1057ab70..9b76ad87 100644 --- a/PCK-Studio/Forms/Additional-Popups/EntityForms/AddEntry.cs +++ b/PCK-Studio/Forms/Additional-Popups/EntityForms/AddEntry.cs @@ -2,7 +2,8 @@ using System.Collections.Generic; using System.Windows.Forms; using PckStudio.Forms.Additional_Popups.Animation; -using PckStudio.Internal.Json; +using PckStudio.Core.Json; +using PckStudio.Json; namespace PckStudio.Forms.Additional_Popups.EntityForms diff --git a/PCK-Studio/Forms/Additional-Popups/ItemSelectionPopUp.cs b/PCK-Studio/Forms/Additional-Popups/ItemSelectionPopUp.cs index f84b95a5..c872cfdd 100644 --- a/PCK-Studio/Forms/Additional-Popups/ItemSelectionPopUp.cs +++ b/PCK-Studio/Forms/Additional-Popups/ItemSelectionPopUp.cs @@ -27,8 +27,11 @@ namespace PckStudio.Forms.Additional_Popups private void okBtn_Click(object sender, EventArgs e) { - if(ComboBox.SelectedIndex > -1) + if(ComboBox.SelectedIndex <= -1) + { cancelButton_Click(sender, e); + return; + } DialogResult = DialogResult.OK; } diff --git a/PCK-Studio/Forms/Additional-Popups/NumericPrompt.Designer.cs b/PCK-Studio/Forms/Additional-Popups/NumericPrompt.Designer.cs index 7bead21f..7c104732 100644 --- a/PCK-Studio/Forms/Additional-Popups/NumericPrompt.Designer.cs +++ b/PCK-Studio/Forms/Additional-Popups/NumericPrompt.Designer.cs @@ -31,8 +31,8 @@ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(NumericPrompt)); this.TextLabel = new System.Windows.Forms.Label(); this.OKButton = new System.Windows.Forms.Button(); - this.ContextLabel = new MetroFramework.Controls.MetroLabel(); this.ValueUpDown = new System.Windows.Forms.NumericUpDown(); + this.toolTipLabel = new MetroFramework.Controls.MetroLabel(); ((System.ComponentModel.ISupportInitialize)(this.ValueUpDown)).BeginInit(); this.SuspendLayout(); // @@ -50,26 +50,28 @@ this.OKButton.UseVisualStyleBackColor = true; this.OKButton.Click += new System.EventHandler(this.OKBtn_Click); // - // ContextLabel - // - resources.ApplyResources(this.ContextLabel, "ContextLabel"); - this.ContextLabel.FontSize = MetroFramework.MetroLabelSize.Small; - this.ContextLabel.Name = "ContextLabel"; - this.ContextLabel.Theme = MetroFramework.MetroThemeStyle.Dark; - this.ContextLabel.WrapToLine = true; - // // ValueUpDown // resources.ApplyResources(this.ValueUpDown, "ValueUpDown"); + this.ValueUpDown.BackColor = System.Drawing.SystemColors.WindowText; + this.ValueUpDown.ForeColor = System.Drawing.SystemColors.Window; this.ValueUpDown.Name = "ValueUpDown"; // + // toolTipLabel + // + resources.ApplyResources(this.toolTipLabel, "toolTipLabel"); + this.toolTipLabel.FontSize = MetroFramework.MetroLabelSize.Small; + this.toolTipLabel.Name = "toolTipLabel"; + this.toolTipLabel.Theme = MetroFramework.MetroThemeStyle.Dark; + this.toolTipLabel.WrapToLine = true; + // // NumericPrompt // this.AcceptButton = this.OKButton; resources.ApplyResources(this, "$this"); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.Controls.Add(this.ValueUpDown); - this.Controls.Add(this.ContextLabel); + this.Controls.Add(this.toolTipLabel); this.Controls.Add(this.OKButton); this.Controls.Add(this.TextLabel); this.MaximizeBox = false; @@ -89,7 +91,7 @@ #endregion public System.Windows.Forms.Button OKButton; public System.Windows.Forms.Label TextLabel; - public MetroFramework.Controls.MetroLabel ContextLabel; private System.Windows.Forms.NumericUpDown ValueUpDown; + private MetroFramework.Controls.MetroLabel toolTipLabel; } } \ No newline at end of file diff --git a/PCK-Studio/Forms/Additional-Popups/NumericPrompt.cs b/PCK-Studio/Forms/Additional-Popups/NumericPrompt.cs index 5ebf4bbf..5fad9a9b 100644 --- a/PCK-Studio/Forms/Additional-Popups/NumericPrompt.cs +++ b/PCK-Studio/Forms/Additional-Popups/NumericPrompt.cs @@ -6,23 +6,66 @@ namespace PckStudio { public partial class NumericPrompt : MetroForm { - public int SelectedValue => (int)ValueUpDown.Value; + public decimal SelectedValue => ValueUpDown.Value; + + public int SelectedValueAsInt => (int)SelectedValue; - public int Minimum { set => ValueUpDown.Minimum = value; } - public int Maximum { set => ValueUpDown.Maximum = value; } + public string ToolTipText + { + get => toolTipLabel.Text; + set => toolTipLabel.Text = value; + } + + public decimal ValueStep + { + get => ValueUpDown.Increment; + set => ValueUpDown.Increment = value; + } + + public int DecimalPlaces + { + get => ValueUpDown.DecimalPlaces; + set => ValueUpDown.DecimalPlaces = value; + } + + public decimal Minimum + { + get => ValueUpDown.Minimum; + set => ValueUpDown.Minimum = value; + } + + public decimal Maximum + { + get => ValueUpDown.Maximum; + set => ValueUpDown.Maximum = value; + } + + private NumericPrompt() + { + InitializeComponent(); + } public NumericPrompt(int initialValue) : this(initialValue, int.MinValue, int.MaxValue) { + } + public NumericPrompt(decimal initialValue, decimal minimum, decimal maximum) + : this() + { + Minimum = minimum; + Maximum = maximum; + ValueUpDown.Value = initialValue; } public NumericPrompt(int initialValue, int minimum, int maximum) + : this((decimal)initialValue, minimum, maximum) + { + } + + public NumericPrompt(float initialValue, float minimum, float maximum) + : this((decimal)initialValue, (decimal)minimum, (decimal)maximum) { - InitializeComponent(); - ValueUpDown.Value = initialValue; - Minimum = minimum; - Maximum = maximum; } private void OKBtn_Click(object sender, EventArgs e) @@ -32,9 +75,9 @@ namespace PckStudio private void RenamePrompt_Load(object sender, EventArgs e) { - if(string.IsNullOrEmpty(ContextLabel.Text)) + if (string.IsNullOrEmpty(toolTipLabel.Text)) { - ContextLabel.Visible = false; + toolTipLabel.Visible = false; Size = new System.Drawing.Size(264, 85); } } diff --git a/PCK-Studio/Forms/Additional-Popups/NumericPrompt.resx b/PCK-Studio/Forms/Additional-Popups/NumericPrompt.resx index 97fc650e..fd242b82 100644 --- a/PCK-Studio/Forms/Additional-Popups/NumericPrompt.resx +++ b/PCK-Studio/Forms/Additional-Popups/NumericPrompt.resx @@ -119,15 +119,18 @@ - Bottom + Bottom, Left True + + NoControl + - 19, 90 + 19, 38 34, 13 @@ -163,7 +166,7 @@ NoControl - 95, 118 + 83, 66 75, 23 @@ -186,38 +189,14 @@ 2 - - Top - - - 28, 27 - - - 208, 58 - - - 6 - - - TopCenter - - - ContextLabel - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - $this - - - 1 + + Bottom, Left, Right - 71, 88 + 71, 36 - 164, 20 + 141, 20 7 @@ -234,14 +213,47 @@ 0 + + False + + + 3, 11 + + + 235, 22 + + + 235, 22 + + + 6 + + + TopCenter + + + toolTipLabel + + + MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 1 + True 6, 13 + + GrowAndShrink + - 264, 150 + 241, 98 @@ -2749,6 +2761,12 @@ AP//AAA= + + 4, 2, 4, 2 + + + 0, 60, 0, 0 + CenterParent diff --git a/PCK-Studio/Forms/AppSettingsForm.Designer.cs b/PCK-Studio/Forms/AppSettingsForm.Designer.cs index 00ed901a..4fc1d0f8 100644 --- a/PCK-Studio/Forms/AppSettingsForm.Designer.cs +++ b/PCK-Studio/Forms/AppSettingsForm.Designer.cs @@ -63,7 +63,6 @@ this.Resizable = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Style = MetroFramework.MetroColorStyle.Black; - this.Text = "Application Settings"; this.Theme = MetroFramework.MetroThemeStyle.Dark; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.AppBehaviorSettingsForm_FormClosing); this.ResumeLayout(false); diff --git a/PCK-Studio/Forms/AppSettingsForm.cs b/PCK-Studio/Forms/AppSettingsForm.cs index f9aa41d5..3bbd5509 100644 --- a/PCK-Studio/Forms/AppSettingsForm.cs +++ b/PCK-Studio/Forms/AppSettingsForm.cs @@ -5,6 +5,8 @@ using System.Diagnostics; using System.Windows.Forms; using MetroFramework.Controls; using MetroFramework.Forms; +using PckStudio.Core.App; +using PckStudio.Internal.App; using PckStudio.Properties; namespace PckStudio.Forms @@ -12,57 +14,84 @@ namespace PckStudio.Forms public partial class AppSettingsForm : MetroForm { private ApplicationSettingsBase _applicationSettings; + internal const string keyToStringContextKey = "keyToString"; public AppSettingsForm() - : this(Settings.Default) + : this("Application Settings", Settings.Default, new Dictionary() + { + ["ShowRichPresence"] = "Show Rich Presence", + ["AutoSaveChanges"] = "Auto Save", + ["UseLittleEndianAsDefault"] = "Open as Little Endian", + ["AutoUpdate"] = "Auto Update", + ["LoadSubPcks"] = "Load Sub Pcks", + ["UsePrerelease"] = "Use Prerelease", + ["ValidateImageDimension"] = "Validate skin dimension", + }) { } - public AppSettingsForm(ApplicationSettingsBase applicationSettings) + public AppSettingsForm(string title, ApplicationSettingsBase applicationSettings, Dictionary keyToStringMap = null) { InitializeComponent(); + Text = title; _applicationSettings = applicationSettings; + if (keyToStringMap is not null && !_applicationSettings.Context.ContainsKey(SettingsManager.KeyToStringContextKeyConst)) + _applicationSettings.Context.Add(SettingsManager.KeyToStringContextKeyConst, keyToStringMap); LoadSettings(); } - private static Dictionary CheckBoxText = new Dictionary() + static bool ContextTryGetKeyToString(SettingsContext context, string key, out string value) { - ["ShowRichPresence"] = "Show Rich Presence", - ["AutoSaveChanges"] = "Auto Save", - ["UseLittleEndianAsDefault"] = "Open as Little Endian", - ["AutoUpdate"] = "Auto Update", - ["LoadSubPcks"] = "Load Sub Pcks", - ["UsePrerelease"] = "Use Prerelease", - }; - - private void CheckBox_CheckedChanged(object sender, EventArgs e) - { - if (sender is CheckBox checkBox && checkBox.Tag is string settingsKey && _applicationSettings[settingsKey] is bool) - { - _applicationSettings[settingsKey] = checkBox.Checked; - } + value = default; + return + context.ContainsKey(SettingsManager.KeyToStringContextKeyConst) && + context[SettingsManager.KeyToStringContextKeyConst] is Dictionary keyToString && + keyToString.TryGetValue(key, out value); } + static Control CreateCheckBox(SettingsPropertyValue propertyValue, SettingsBase settings) + { + var control = new MetroCheckBox + { + Name = propertyValue.Name, + Tag = propertyValue.Name, + Text = ContextTryGetKeyToString(settings.Context, propertyValue.Name, out string name) ? name : propertyValue.Name, + Checked = (bool)propertyValue.PropertyValue, + + AutoSize = true, + Theme = MetroFramework.MetroThemeStyle.Dark, + Style = MetroFramework.MetroColorStyle.White, + }; + + void CheckBox_CheckedChanged(object sender, EventArgs e) + { + if (sender is CheckBox checkBox && checkBox.Tag is string settingsKey && settings[settingsKey] is bool) + { + settings[settingsKey] = checkBox.Checked; + } + } + + control.CheckedChanged += CheckBox_CheckedChanged; + return control; + } + + delegate Control ControlCreateDelegate(SettingsPropertyValue propertyValue, SettingsBase settings); + + Dictionary _typeToControl = new Dictionary() + { + [typeof(bool)] = CreateCheckBox, + }; + private void LoadSettings() { foreach (SettingsPropertyValue item in _applicationSettings.PropertyValues) { Debug.WriteLine($"{item.Property.Name}: {item.Property.PropertyType}"); - if (!item.Property.Attributes.ContainsKey(typeof(UserScopedSettingAttribute)) || item.Property.PropertyType != typeof(bool)) + bool isUserScoped = item.Property.Attributes?.ContainsKey(typeof(UserScopedSettingAttribute)) ?? true; + if (!isUserScoped || !_typeToControl.ContainsKey(item.Property.PropertyType) || item.Property.IsReadOnly) continue; - var checkBox = new MetroCheckBox - { - Name = item.Name, - Tag = item.Name, - Text = CheckBoxText.ContainsKey(item.Name) ? CheckBoxText[item.Name] : item.Name, - Checked = (bool)item.PropertyValue, - - AutoSize = true, - Theme = MetroFramework.MetroThemeStyle.Dark, - Style = MetroFramework.MetroColorStyle.White, - }; - checkBox.CheckedChanged += CheckBox_CheckedChanged; - flowLayoutPanel.Controls.Add(checkBox); + Control control = _typeToControl[item.Property.PropertyType](item, _applicationSettings); + flowLayoutPanel.Controls.Add(control); } } diff --git a/PCK-Studio/Forms/Editor/ANIMEditor.cs b/PCK-Studio/Forms/Editor/ANIMEditor.cs index c379d7d2..27ef70d7 100644 --- a/PCK-Studio/Forms/Editor/ANIMEditor.cs +++ b/PCK-Studio/Forms/Editor/ANIMEditor.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using PckStudio.Internal; using PckStudio.Forms.Additional_Popups; using PckStudio.Properties; +using PckStudio.Core.Skin; namespace PckStudio.Forms.Editor { diff --git a/PCK-Studio/Forms/Editor/AnimationEditor.Designer.cs b/PCK-Studio/Forms/Editor/AnimationEditor.Designer.cs index 4fed8d2a..7a891d6a 100644 --- a/PCK-Studio/Forms/Editor/AnimationEditor.Designer.cs +++ b/PCK-Studio/Forms/Editor/AnimationEditor.Designer.cs @@ -319,7 +319,7 @@ | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.animationPictureBox.BlendColor = System.Drawing.Color.White; - this.animationPictureBox.BlendMode = PckStudio.Extensions.BlendMode.Multiply; + this.animationPictureBox.BlendMode = PckStudio.Core.Extensions.BlendMode.Multiply; this.animationPictureBox.Image = null; this.animationPictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; this.animationPictureBox.Location = new System.Drawing.Point(157, 88); diff --git a/PCK-Studio/Forms/Editor/AnimationEditor.cs b/PCK-Studio/Forms/Editor/AnimationEditor.cs index e5ba5639..a0f6cd02 100644 --- a/PCK-Studio/Forms/Editor/AnimationEditor.cs +++ b/PCK-Studio/Forms/Editor/AnimationEditor.cs @@ -29,39 +29,32 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PckStudio.Forms.Additional_Popups.Animation; -using PckStudio.Extensions; -using PckStudio.Properties; -using PckStudio.Internal; -using PckStudio.Internal.Deserializer; -using PckStudio.Internal.Serializer; +using PckStudio.Core.Extensions; +using PckStudio.Core.Deserializer; +using PckStudio.Core.Serializer; +using PckStudio.Core; +using PckStudio.Interfaces; +using PckStudio.Controls; namespace PckStudio.Forms.Editor { - public partial class AnimationEditor : MetroForm + public partial class AnimationEditor : EditorForm { - public Animation Result => _animation; + private bool _editable; - private Animation _animation; - private bool _isSpecialTile; - - private AnimationEditor() + internal AnimationEditor(Animation animation, ISaveContext saveContext, string displayName, bool editable = true) + : base(animation, saveContext) { InitializeComponent(); - toolStripSeparator1.Visible = saveToolStripMenuItem1.Visible = !Settings.Default.AutoSaveChanges; - } - - internal AnimationEditor(Animation animation, string displayName, bool isSpecialTile = false) - : this() - { - _ = animation ?? throw new ArgumentNullException(nameof(animation)); - _animation = animation; + saveToolStripMenuItem1.Available = !saveContext.AutoSave; + toolStripSeparator1.Available = !saveContext.AutoSave; tileLabel.Text = displayName; - _isSpecialTile = isSpecialTile; + _editable = editable; animationPictureBox.Image = animation.CreateAnimationImage(); } - internal AnimationEditor(Animation animation, string displayName, Color blendColor) - : this(animation, displayName) + internal AnimationEditor(Animation animation, ISaveContext saveContext, string displayName, Color blendColor) + : this(animation, saveContext, displayName) { animationPictureBox.UseBlendColor = true; animationPictureBox.BlendColor = blendColor; @@ -69,10 +62,9 @@ namespace PckStudio.Forms.Editor private void ValidateToolStrip() { - bulkAnimationSpeedToolStripMenuItem.Enabled = - importToolStripMenuItem.Enabled = - exportAsToolStripMenuItem.Enabled = - InterpolationCheckbox.Visible = !_isSpecialTile; + editToolStripMenuItem.Visible = + importToolStripMenuItem.Visible = + InterpolationCheckbox.Visible = _editable; } private void AnimationEditor_Load(object sender, EventArgs e) @@ -83,20 +75,20 @@ namespace PckStudio.Forms.Editor private void LoadAnimationTreeView() { - if (_animation is null) + if (EditorValue is null) { - AnimationStartStopBtn.Enabled = false; + AnimationStartStopBtn.Visible = false; return; } - AnimationStartStopBtn.Enabled = true; - InterpolationCheckbox.Checked = _animation.Interpolate; + AnimationStartStopBtn.Visible = true; + InterpolationCheckbox.Checked = EditorValue.Interpolate; TextureIcons.Images.Clear(); - TextureIcons.Images.AddRange(_animation.GetTextures().ToArray()); + TextureIcons.Images.AddRange(EditorValue.GetTextures().ToArray()); UpdateTreeView(); - animationPictureBox.Image ??= _animation.CreateAnimationImage(); + animationPictureBox.Image ??= EditorValue.CreateAnimationImage(); - if (_animation.FrameCount > 0) + if (EditorValue.FrameCount > 0) { animationPictureBox.Image.SelectActiveFrame(FrameDimension.Page, 0); } @@ -106,11 +98,11 @@ namespace PckStudio.Forms.Editor { frameTreeView.Nodes.Clear(); frameTreeView.Nodes.AddRange( - _animation.GetFrames() + EditorValue.GetFrames() .Select(frame => { - var imageIndex = _animation.GetTextureIndex(frame.Texture); - return new TreeNode($"for {frame.Ticks} ticks", imageIndex, imageIndex); + var imageIndex = EditorValue.GetTextureIndex(frame.Texture); + return new TreeNode($"for {frame.Ticks} tick(s)", imageIndex, imageIndex); }) .ToArray() ); @@ -122,7 +114,7 @@ namespace PckStudio.Forms.Editor { StopAnimation(); } - animationPictureBox.Image = _animation.GetFrame(frameTreeView.SelectedNode.Index).Texture; + animationPictureBox.Image = EditorValue.GetFrame(frameTreeView.SelectedNode.Index).Texture; } private void StopAnimation() @@ -139,9 +131,9 @@ namespace PckStudio.Forms.Editor return; } - if (_animation.FrameCount > 1) + if (EditorValue.FrameCount > 1) { - animationPictureBox.Image = _animation.CreateAnimationImage(); + animationPictureBox.Image = EditorValue.CreateAnimationImage(); animationPictureBox.Start(); AnimationStartStopBtn.Text = "Stop Animation"; } @@ -166,8 +158,9 @@ namespace PckStudio.Forms.Editor private void saveToolStripMenuItem1_Click(object sender, EventArgs e) { - if (!_isSpecialTile && _animation is not null && _animation.FrameCount > 0) + if (_editable && EditorValue is not null && EditorValue.FrameCount > 0) { + Save(); DialogResult = DialogResult.OK; return; } @@ -231,7 +224,7 @@ namespace PckStudio.Forms.Editor { int draggedIndex = draggedNode.Index; int targetIndex = targetNode.Index; - _animation.SwapFrames(draggedIndex, targetIndex); + EditorValue.SwapFrames(draggedIndex, targetIndex); UpdateTreeView(); } } @@ -255,8 +248,8 @@ namespace PckStudio.Forms.Editor private void treeView1_doubleClick(object sender, EventArgs e) { - Animation.Frame frame = _animation.GetFrame(frameTreeView.SelectedNode.Index); - using FrameEditor diag = new FrameEditor(frame.Ticks, _animation.GetTextureIndex(frame.Texture), TextureIcons); + Animation.Frame frame = EditorValue.GetFrame(frameTreeView.SelectedNode.Index); + using FrameEditor diag = new FrameEditor(frame.Ticks, EditorValue.GetTextureIndex(frame.Texture), TextureIcons); if (diag.ShowDialog(this) == DialogResult.OK) { /* Found a bug here. When passing the frame variable, @@ -266,7 +259,7 @@ namespace PckStudio.Forms.Editor * - Matt */ - _animation.SetFrame(frameTreeView.SelectedNode.Index, diag.FrameTextureIndex, diag.FrameTime); + EditorValue.SetFrame(frameTreeView.SelectedNode.Index, diag.FrameTextureIndex, diag.FrameTime); UpdateTreeView(); } } @@ -277,14 +270,14 @@ namespace PckStudio.Forms.Editor diag.SaveBtn.Text = "Add"; if (diag.ShowDialog(this) == DialogResult.OK) { - _animation.AddFrame(diag.FrameTextureIndex, _isSpecialTile ? Animation.MinimumFrameTime : diag.FrameTime); + EditorValue.AddFrame(diag.FrameTextureIndex, _editable ? diag.FrameTime : Animation.MinimumFrameTime); UpdateTreeView(); } } private void removeFrameToolStripMenuItem_Click(object sender, EventArgs e) { - if (frameTreeView.SelectedNode is TreeNode t && _animation.RemoveFrame(t.Index)) + if (frameTreeView.SelectedNode is TreeNode t && EditorValue.RemoveFrame(t.Index)) { frameTreeView.SelectedNode.Remove(); } @@ -297,7 +290,7 @@ namespace PckStudio.Forms.Editor { if (animationPictureBox.IsPlaying) animationPictureBox.Stop(); - _animation.SetFrameTicks(diag.Ticks); + EditorValue.SetFrameTicks(diag.Ticks); UpdateTreeView(); } diag.Dispose(); @@ -334,10 +327,10 @@ namespace PckStudio.Forms.Editor } try { - var img = Image.FromFile(textureFile); + Image img = Image.FromFile(textureFile).ReleaseFromFile(); JObject mcmeta = JObject.Parse(File.ReadAllText(fileDialog.FileName)); Animation javaAnimation = AnimationDeserializer.DefaultDeserializer.DeserializeJavaAnimation(mcmeta, img); - _animation = javaAnimation; + EditorValue = javaAnimation; LoadAnimationTreeView(); } catch (JsonException j_ex) @@ -354,11 +347,11 @@ namespace PckStudio.Forms.Editor fileDialog.Filter = "Animation Scripts (*.mcmeta)|*.png.mcmeta"; if (fileDialog.ShowDialog(this) == DialogResult.OK) { - JObject mcmeta = AnimationSerializer.SerializeJavaAnimation(_animation); + JObject mcmeta = AnimationSerializer.SerializeJavaAnimation(EditorValue); string jsondata = JsonConvert.SerializeObject(mcmeta, Formatting.Indented); string filename = fileDialog.FileName; File.WriteAllText(filename, jsondata); - Image finalTexture = AnimationSerializer.SerializeTexture(_animation); + Image finalTexture = AnimationSerializer.SerializeTexture(EditorValue); // removes ".mcmeta" from filename string texturePath = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename)); finalTexture.Save(texturePath); @@ -390,8 +383,8 @@ namespace PckStudio.Forms.Editor private void InterpolationCheckbox_CheckedChanged(object sender, EventArgs e) { - if (_animation is not null) - _animation.Interpolate = InterpolationCheckbox.Checked; + if (EditorValue is not null) + EditorValue.Interpolate = InterpolationCheckbox.Checked; } private void AnimationEditor_FormClosing(object sender, FormClosingEventArgs e) @@ -400,7 +393,7 @@ namespace PckStudio.Forms.Editor { animationPictureBox.Stop(); } - if (Settings.Default.AutoSaveChanges) + if (!saveToolStripMenuItem1.Available) { saveToolStripMenuItem1_Click(sender, EventArgs.Empty); } @@ -415,14 +408,14 @@ namespace PckStudio.Forms.Editor if (fileDialog.ShowDialog(this) != DialogResult.OK) return; - var gif = Image.FromFile(fileDialog.FileName); + Image gif = Image.FromFile(fileDialog.FileName).ReleaseFromFile(); if (!gif.RawFormat.Equals(ImageFormat.Gif)) { MessageBox.Show(this, "Selected file is not a gif", "Invalid file", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } - var oldResolution = _animation.GetFrame(0).Texture.Width; + var oldResolution = EditorValue.GetFrame(0).Texture.Width; FrameDimension dimension = new FrameDimension(gif.FrameDimensionsList[0]); int frameCount = gif.GetFrameCount(dimension); @@ -436,8 +429,8 @@ namespace PckStudio.Forms.Editor textures.Add(new Bitmap(gif, oldResolution, oldResolution)); } - _animation = new Animation(textures, initFramesFromTextures: true); - _animation.Interpolate = InterpolationCheckbox.Checked; + EditorValue = new Animation(textures, initFramesFromTextures: true); + EditorValue.Interpolate = InterpolationCheckbox.Checked; LoadAnimationTreeView(); } @@ -452,7 +445,7 @@ namespace PckStudio.Forms.Editor return; using Image img = Image.FromFile(ofd.FileName); IEnumerable textures = img.Split(ImageLayoutDirection.Vertical); - _animation = new Animation(textures, initFramesFromTextures: true); + EditorValue = new Animation(textures, initFramesFromTextures: true); LoadAnimationTreeView(); } @@ -465,7 +458,7 @@ namespace PckStudio.Forms.Editor }; if (fileDialog.ShowDialog(this) != DialogResult.OK) return; - _animation.CreateAnimationImage().Save(fileDialog.FileName); + EditorValue.CreateAnimationImage().Save(fileDialog.FileName); } private void frameTimeandTicksToolStripMenuItem_Click(object sender, EventArgs e) diff --git a/PCK-Studio/Forms/Editor/AudioEditor.cs b/PCK-Studio/Forms/Editor/AudioEditor.cs index cc37747c..05acd345 100644 --- a/PCK-Studio/Forms/Editor/AudioEditor.cs +++ b/PCK-Studio/Forms/Editor/AudioEditor.cs @@ -7,30 +7,23 @@ using System.Windows.Forms; using System.Security.Cryptography; using System.Text.RegularExpressions; using System.Diagnostics; - -using MetroFramework.Forms; using NAudio.Wave; - -using OMI.Formats.Pck; - -using PckStudio.FileFormats; -using PckStudio.Internal.IO.PckAudio; using PckStudio.Forms.Additional_Popups; using PckStudio.Properties; using PckStudio.External.API.Miles; -using PckStudio.Extensions; +using PckStudio.Core.Extensions; using PckStudio.Internal.App; +using PckStudio.Controls; +using PckStudio.Interfaces; +using PckStudio.Core.FileFormats; // Audio Editor by MattNL and Miku-666 namespace PckStudio.Forms.Editor { - public partial class AudioEditor : MetroForm + public partial class AudioEditor : EditorForm { public string defaultType = "yes"; - PckAudioFile _audioFile = null; - PckAsset _audioAsset; - bool _isLittleEndian = false; MainForm parent = null; private static readonly List Categories = new List @@ -52,7 +45,15 @@ namespace PckStudio.Forms.Editor */ }; - private string GetCategoryFromId(PckAudioFile.AudioCategory.EAudioType categoryId) + public AudioEditor(PckAudioFile audioFile, ISaveContext saveContext) + : base(audioFile, saveContext) + { + InitializeComponent(); + saveToolStripMenuItem1.Visible = !saveContext.AutoSave; + SetUpTree(); + } + + private string GetCategoryFromId(PckAudioFile.AudioCategory.EAudioType categoryId) => categoryId >= PckAudioFile.AudioCategory.EAudioType.Overworld && categoryId <= PckAudioFile.AudioCategory.EAudioType.BuildOff ? Categories[(int)categoryId] @@ -63,26 +64,12 @@ namespace PckStudio.Forms.Editor return (PckAudioFile.AudioCategory.EAudioType)Categories.IndexOf(category); } - public AudioEditor(PckAsset asset, bool isLittleEndian) - { - InitializeComponent(); - - saveToolStripMenuItem1.Visible = !Settings.Default.AutoSaveChanges; - - _isLittleEndian = isLittleEndian; - - _audioAsset = asset; - _audioFile = _audioAsset.GetData(new PckAudioFileReader(isLittleEndian ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian)); - - SetUpTree(); - } - public void SetUpTree() { treeView1.BeginUpdate(); treeView1.Nodes.Clear(); - foreach (PckAudioFile.AudioCategory category in _audioFile.Categories) + foreach (PckAudioFile.AudioCategory category in EditorValue.Categories) { // fix songs with directories using backslash instead of forward slash // Songs with a backslash instead of a forward slash would not play in RPCS3 @@ -92,7 +79,7 @@ namespace PckStudio.Forms.Editor if (category.AudioType == PckAudioFile.AudioCategory.EAudioType.Creative) { if (category.Name == "include_overworld" && - _audioFile.TryGetCategory(PckAudioFile.AudioCategory.EAudioType.Overworld, out PckAudioFile.AudioCategory overworldCategory)) + EditorValue.TryGetCategory(PckAudioFile.AudioCategory.EAudioType.Overworld, out PckAudioFile.AudioCategory overworldCategory)) { foreach (var name in category.SongNames.ToList()) { @@ -108,7 +95,7 @@ namespace PckStudio.Forms.Editor treeNode.Tag = category; treeView1.Nodes.Add(treeNode); } - playOverworldInCreative.Enabled = _audioFile.HasCategory(PckAudioFile.AudioCategory.EAudioType.Creative); + playOverworldInCreative.Enabled = EditorValue.HasCategory(PckAudioFile.AudioCategory.EAudioType.Creative); treeView1.EndUpdate(); } @@ -120,9 +107,9 @@ namespace PckStudio.Forms.Editor if (!parent.CreateDataFolder()) return; - string FileName = Path.Combine(parent.GetDataPath(), entry.Text + ".binka"); + string fileName = Path.Combine(parent.GetDataPath(), entry.Text + ".binka"); - if (File.Exists(FileName)) + if (File.Exists(fileName)) MessageBox.Show(this, $"\"{entry.Text}.binka\" exists in the \"Data\" folder", "File found"); else MessageBox.Show(this, $"\"{entry.Text}.binka\" does not exist in the \"Data\" folder. The game will crash when attempting to load this track.", "File missing"); @@ -144,7 +131,7 @@ namespace PckStudio.Forms.Editor private void addCategoryStripMenuItem_Click(object sender, EventArgs e) { - string[] available = Categories.FindAll(str => !_audioFile.HasCategory(GetCategoryId(str))).ToArray(); + string[] available = Categories.FindAll(str => !EditorValue.HasCategory(GetCategoryId(str))).ToArray(); if (available.Length == 0) { MessageBox.Show(this, "There are no more categories that could be added", "All possible categories are used"); @@ -154,8 +141,8 @@ namespace PckStudio.Forms.Editor if (add.ShowDialog(this) != DialogResult.OK) return; - _audioFile.AddCategory(GetCategoryId(add.SelectedItem)); - PckAudioFile.AudioCategory category = _audioFile.GetCategory(GetCategoryId(add.SelectedItem)); + EditorValue.AddCategory(GetCategoryId(add.SelectedItem)); + PckAudioFile.AudioCategory category = EditorValue.GetCategory(GetCategoryId(add.SelectedItem)); if (GetCategoryId(add.SelectedItem) == PckAudioFile.AudioCategory.EAudioType.Creative) { @@ -194,7 +181,7 @@ namespace PckStudio.Forms.Editor private void removeCategoryStripMenuItem_Click(object sender, EventArgs e) { if (treeView1.SelectedNode is TreeNode main && - _audioFile.RemoveCategory(GetCategoryId(treeView1.SelectedNode.Text))) + EditorValue.RemoveCategory(GetCategoryId(treeView1.SelectedNode.Text))) { if(GetCategoryId(treeView1.SelectedNode.Text) == PckAudioFile.AudioCategory.EAudioType.Creative) { @@ -370,18 +357,18 @@ namespace PckStudio.Forms.Editor private void saveToolStripMenuItem1_Click(object sender, EventArgs e) { - if (!_audioFile.HasCategory(PckAudioFile.AudioCategory.EAudioType.Overworld) || - !_audioFile.HasCategory(PckAudioFile.AudioCategory.EAudioType.Nether) || - !_audioFile.HasCategory(PckAudioFile.AudioCategory.EAudioType.End)) + if (!EditorValue.HasCategory(PckAudioFile.AudioCategory.EAudioType.Overworld) || + !EditorValue.HasCategory(PckAudioFile.AudioCategory.EAudioType.Nether) || + !EditorValue.HasCategory(PckAudioFile.AudioCategory.EAudioType.End)) { MessageBox.Show(this, "Your changes were not saved. The game will crash when loading your pack if the Overworld, Nether and End categories don't all exist with at least one valid song.", "Mandatory Categories Missing"); return; } - PckAudioFile.AudioCategory overworldCategory = _audioFile.GetCategory(PckAudioFile.AudioCategory.EAudioType.Overworld); + PckAudioFile.AudioCategory overworldCategory = EditorValue.GetCategory(PckAudioFile.AudioCategory.EAudioType.Overworld); bool songs_missing = false; - foreach (PckAudioFile.AudioCategory category in _audioFile.Categories) + foreach (PckAudioFile.AudioCategory category in EditorValue.Categories) { if (category.SongNames.Count < 1) { @@ -391,8 +378,8 @@ namespace PckStudio.Forms.Editor foreach(var song in category.SongNames) { - string FileName = Path.Combine(parent.GetDataPath(), song + ".binka"); - if (!File.Exists(FileName)) + string fileName = Path.Combine(parent.GetDataPath(), song + ".binka"); + if (!File.Exists(fileName)) { songs_missing = true; MessageBox.Show(this, "\"" + song + ".binka\" does not exist in the \"Data\" folder. The game will crash when attempting to load this track.", "File missing"); @@ -420,7 +407,7 @@ namespace PckStudio.Forms.Editor return; } - _audioAsset.SetData(new PckAudioFileWriter(_audioFile, _isLittleEndian ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian)); + Save(); DialogResult = DialogResult.OK; } @@ -444,7 +431,7 @@ namespace PckStudio.Forms.Editor if (dr != DialogResult.Yes) return; var totalSongList = new List(); - foreach (string song in _audioFile.Categories.SelectMany(cat => cat.SongNames)) + foreach (string song in EditorValue.Categories.SelectMany(cat => cat.SongNames)) { Console.WriteLine(song); totalSongList.Add(song); @@ -544,7 +531,7 @@ namespace PckStudio.Forms.Editor return; var totalSongList = new List(); - foreach (string song in _audioFile.Categories.SelectMany(cat => cat.SongNames)) + foreach (string song in EditorValue.Categories.SelectMany(cat => cat.SongNames)) { totalSongList.Add(song); } @@ -596,7 +583,7 @@ namespace PckStudio.Forms.Editor if (!(treeView1.SelectedNode is TreeNode t && t.Tag is PckAudioFile.AudioCategory category)) return; - string[] available = Categories.FindAll(str => !_audioFile.HasCategory(GetCategoryId(str))).ToArray(); + string[] available = Categories.FindAll(str => !EditorValue.HasCategory(GetCategoryId(str))).ToArray(); if (available.Length > 0) { using ItemSelectionPopUp add = new ItemSelectionPopUp(available); @@ -604,11 +591,11 @@ namespace PckStudio.Forms.Editor if (add.ShowDialog(this) != DialogResult.OK) return; - _audioFile.RemoveCategory(category.AudioType); + EditorValue.RemoveCategory(category.AudioType); - _audioFile.AddCategory(category.parameterType, GetCategoryId(add.SelectedItem), category.AudioType == PckAudioFile.AudioCategory.EAudioType.Overworld && playOverworldInCreative.Checked ? "include_overworld" : ""); + EditorValue.AddCategory(category.parameterType, GetCategoryId(add.SelectedItem), category.AudioType == PckAudioFile.AudioCategory.EAudioType.Overworld && playOverworldInCreative.Checked ? "include_overworld" : ""); - PckAudioFile.AudioCategory newCategory = _audioFile.GetCategory(GetCategoryId(add.SelectedItem)); + PckAudioFile.AudioCategory newCategory = EditorValue.GetCategory(GetCategoryId(add.SelectedItem)); category.SongNames.ForEach(c => newCategory.SongNames.Add(c)); @@ -628,7 +615,7 @@ namespace PckStudio.Forms.Editor return; string musicdir = Path.Combine(parent.GetDataPath(), "Music"); Directory.CreateDirectory(musicdir); - foreach (PckAudioFile.AudioCategory category in _audioFile.Categories) + foreach (PckAudioFile.AudioCategory category in EditorValue.Categories) { for (var i = 0; i < category.SongNames.Count; i++) // using standard for loop so the list can be modified { diff --git a/PCK-Studio/Forms/Editor/BehaviourEditor.Designer.cs b/PCK-Studio/Forms/Editor/BehaviourEditor.Designer.cs index ed133825..48a4202d 100644 --- a/PCK-Studio/Forms/Editor/BehaviourEditor.Designer.cs +++ b/PCK-Studio/Forms/Editor/BehaviourEditor.Designer.cs @@ -299,7 +299,6 @@ this.Style = MetroFramework.MetroColorStyle.Silver; this.Text = "Behaviour Editor"; this.Theme = MetroFramework.MetroThemeStyle.Dark; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.BehaviourEditor_FormClosing); this.metroContextMenu1.ResumeLayout(false); this.menuStrip.ResumeLayout(false); this.menuStrip.PerformLayout(); diff --git a/PCK-Studio/Forms/Editor/BehaviourEditor.cs b/PCK-Studio/Forms/Editor/BehaviourEditor.cs index c47957ee..e4cd6a63 100644 --- a/PCK-Studio/Forms/Editor/BehaviourEditor.cs +++ b/PCK-Studio/Forms/Editor/BehaviourEditor.cs @@ -1,75 +1,64 @@ using System; -using System.Collections.Generic; -using System.Drawing; -using System.Diagnostics; -using System.IO; using System.Linq; using System.Windows.Forms; -using MetroFramework.Forms; -using PckStudio.Forms.Additional_Popups.EntityForms; -using Newtonsoft.Json.Linq; +using System.Collections.Generic; using OMI.Formats.Behaviour; -using OMI.Workers.Behaviour; -using OMI.Formats.Pck; -using PckStudio.Properties; -using PckStudio.Internal; -using PckStudio.Extensions; -using PckStudio.Internal.Json; +using PckStudio.Controls; using PckStudio.Internal.App; +using PckStudio.Interfaces; +using PckStudio.Forms.Additional_Popups.EntityForms; +using PckStudio.Json; +using PckStudio.Core.Json; namespace PckStudio.Forms.Editor { - public partial class BehaviourEditor : MetroForm + // Behaviours File Format research by Miku and MattNL + public partial class BehaviourEditor : EditorForm { - // Behaviours File Format research by Miku and MattNL - private readonly PckAsset _asset; - BehaviourFile _behaviourFile; + private const string BehaviourEntryDataType = "behaviours"; + private readonly List BehaviourData = Entities.BehaviourInfos; - private readonly List BehaviourData = Entities.BehaviourInfos; + public BehaviourEditor(BehaviourFile behaviourFile, ISaveContext saveContext) + : base(behaviourFile, saveContext) + { + InitializeComponent(); - void SetUpTree() + saveToolStripMenuItem1.Visible = !saveContext.AutoSave; + + treeView1.ImageList = new ImageList(); + treeView1.ImageList.Images.AddRange(ApplicationScope.EntityImages); + treeView1.ImageList.ColorDepth = ColorDepth.Depth32Bit; + SetUpTree(); + } + + void SetUpTree() { treeView1.BeginUpdate(); treeView1.Nodes.Clear(); - foreach (var entry in _behaviourFile.entries) + foreach (BehaviourFile.RiderPositionOverride entry in EditorValue.entries) { - TreeNode EntryNode = new TreeNode(entry.name); + TreeNode entryNode = new TreeNode(entry.name); - var behaviour = BehaviourData.Find(b => b.InternalName == entry.name); - EntryNode.Text = behaviour.DisplayName; - EntryNode.ImageIndex = BehaviourData.IndexOf(behaviour); - EntryNode.SelectedImageIndex = EntryNode.ImageIndex; - EntryNode.Tag = entry; + EntityInfo behaviour = BehaviourData.Find(b => b.InternalName == entry.name); + entryNode.Text = behaviour.DisplayName; + entryNode.ImageIndex = BehaviourData.IndexOf(behaviour); + entryNode.SelectedImageIndex = entryNode.ImageIndex; + entryNode.Tag = entry; - foreach (var posOverride in entry.overrides) + foreach (BehaviourFile.RiderPositionOverride.PositionOverride posOverride in entry.overrides) { - TreeNode OverrideNode = new TreeNode("Position Override"); - OverrideNode.Tag = posOverride; - EntryNode.Nodes.Add(OverrideNode); - OverrideNode.ImageIndex = 103; - OverrideNode.SelectedImageIndex = OverrideNode.ImageIndex; + TreeNode overrideNode = new TreeNode("Position Override"); + overrideNode.Tag = posOverride; + entryNode.Nodes.Add(overrideNode); + overrideNode.ImageIndex = 103; + overrideNode.SelectedImageIndex = overrideNode.ImageIndex; } - treeView1.Nodes.Add(EntryNode); + treeView1.Nodes.Add(entryNode); } treeView1.EndUpdate(); } - public BehaviourEditor(PckAsset asset) - { - InitializeComponent(); - - saveToolStripMenuItem1.Visible = !Settings.Default.AutoSaveChanges; - - _asset = asset; - _behaviourFile = asset.GetData(new BehavioursReader()); - - treeView1.ImageList = new ImageList(); - treeView1.ImageList.Images.AddRange(ApplicationScope.EntityImages); - treeView1.ImageList.ColorDepth = ColorDepth.Depth32Bit; - SetUpTree(); - } - private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) { if (treeView1.SelectedNode is null) @@ -149,13 +138,13 @@ namespace PckStudio.Forms.Editor if (!(treeView1.SelectedNode.Tag is BehaviourFile.RiderPositionOverride entry)) return; - var diag = new AddEntry("behaviours", ApplicationScope.EntityImages); + var diag = new AddEntry(BehaviourEntryDataType, ApplicationScope.EntityImages); if (diag.ShowDialog(this) == DialogResult.OK) { if (string.IsNullOrEmpty(diag.SelectedEntity)) return; - if (_behaviourFile.entries.FindAll(behaviour => behaviour.name == diag.SelectedEntity).Count() > 0) + if (EditorValue.entries.FindAll(behaviour => behaviour.name == diag.SelectedEntity).Count() > 0) { MessageBox.Show(this, "You cannot have two entries for one entity. Please use the \"Add New Position Override\" tool to add multiple overrides for entities", "Error", MessageBoxButtons.OK); return; @@ -186,41 +175,46 @@ namespace PckStudio.Forms.Editor if (treeView1.SelectedNode.Tag is BehaviourFile.RiderPositionOverride.PositionOverride) treeView1.SelectedNode = treeView1.SelectedNode.Parent; - if (treeView1.SelectedNode.Tag is BehaviourFile.RiderPositionOverride) + if (treeView1.SelectedNode.Tag is BehaviourFile.RiderPositionOverride positionOverride) { - TreeNode OverrideNode = new TreeNode("Position Override"); - OverrideNode.Tag = new BehaviourFile.RiderPositionOverride.PositionOverride(); - OverrideNode.ImageIndex = 103; - OverrideNode.SelectedImageIndex = 103; - treeView1.SelectedNode.Nodes.Add(OverrideNode); - } + BehaviourFile.RiderPositionOverride.PositionOverride newPositionOverride = new BehaviourFile.RiderPositionOverride.PositionOverride(); + TreeNode overrideNode = new TreeNode("Position Override"); + overrideNode.Tag = newPositionOverride; + overrideNode.ImageIndex = 103; + overrideNode.SelectedImageIndex = 103; + treeView1.SelectedNode.Nodes.Add(overrideNode); + positionOverride.overrides.Add(newPositionOverride); + } } private void addNewEntryToolStripMenuItem_Click(object sender, EventArgs e) { - var diag = new AddEntry("behaviours", ApplicationScope.EntityImages); + var diag = new AddEntry(BehaviourEntryDataType, ApplicationScope.EntityImages); if(diag.ShowDialog(this) == DialogResult.OK) { if (string.IsNullOrEmpty(diag.SelectedEntity)) return; - if (_behaviourFile.entries.FindAll(behaviour => behaviour.name == diag.SelectedEntity).Count() > 0) + if (EditorValue.entries.FindAll(behaviour => behaviour.name == diag.SelectedEntity).Count() > 0) { MessageBox.Show(this, "You cannot have two entries for one entity. Please use the \"Add New Position Override\" tool to add multiple overrides for entities", "Error", MessageBoxButtons.OK); return; } - BehaviourFile.RiderPositionOverride NewOverride = new BehaviourFile.RiderPositionOverride(diag.SelectedEntity); + BehaviourFile.RiderPositionOverride newOverride = new BehaviourFile.RiderPositionOverride(diag.SelectedEntity); + EditorValue.entries.Add(newOverride); - TreeNode NewOverrideNode = new TreeNode(NewOverride.name); - NewOverrideNode.Tag = NewOverride; + TreeNode newOverrideNode = new TreeNode(newOverride.name); + newOverrideNode.Tag = newOverride; - EntityInfo behaviour = BehaviourData.Find(b => b.InternalName == NewOverride.name); - NewOverrideNode.Text = behaviour.DisplayName; - NewOverrideNode.ImageIndex = BehaviourData.IndexOf(behaviour); - NewOverrideNode.SelectedImageIndex = NewOverrideNode.ImageIndex; + // potentially null de-reference + EntityInfo behaviour = BehaviourData.Find(b => b.InternalName == newOverride.name); - treeView1.Nodes.Add(NewOverrideNode); - treeView1.SelectedNode = NewOverrideNode; + newOverrideNode.Text = behaviour.DisplayName; + newOverrideNode.ImageIndex = BehaviourData.IndexOf(behaviour); + newOverrideNode.SelectedImageIndex = newOverrideNode.ImageIndex; + + treeView1.Nodes.Add(newOverrideNode); + treeView1.SelectedNode = newOverrideNode; addNewPositionOverrideToolStripMenuItem_Click(sender, e); // adds a Position Override to the new Override } @@ -239,36 +233,8 @@ namespace PckStudio.Forms.Editor private void saveToolStripMenuItem1_Click(object sender, EventArgs e) { - _behaviourFile = new BehaviourFile(); - foreach (TreeNode node in treeView1.Nodes) - { - if(node.Tag is BehaviourFile.RiderPositionOverride entry) - { - entry.overrides.Clear(); - Console.WriteLine(); - foreach (TreeNode overrideNode in node.Nodes) - { - if(overrideNode.Tag is BehaviourFile.RiderPositionOverride.PositionOverride overrideEntry) - { - entry.overrides.Add(overrideEntry); - } - } - - _behaviourFile.entries.Add(entry); - } - } - - _asset.SetData(new BehavioursWriter(_behaviourFile)); - + Save(); DialogResult = DialogResult.OK; } - - private void BehaviourEditor_FormClosing(object sender, FormClosingEventArgs e) - { - if (Settings.Default.AutoSaveChanges) - { - saveToolStripMenuItem1_Click(sender, EventArgs.Empty); - } - } } } diff --git a/PCK-Studio/Forms/Editor/BoxEditor.cs b/PCK-Studio/Forms/Editor/BoxEditor.cs index 8af249bf..89443617 100644 --- a/PCK-Studio/Forms/Editor/BoxEditor.cs +++ b/PCK-Studio/Forms/Editor/BoxEditor.cs @@ -1,16 +1,17 @@ using System; using System.Windows.Forms; -using PckStudio.Internal; +using PckStudio.Core.Skin; using PckStudio.Properties; namespace PckStudio.Forms.Editor { public partial class BoxEditor : MetroFramework.Forms.MetroForm { - public string Result; + private SkinBOX result; + public SkinBOX Result => result; - public BoxEditor(string box, bool hasInflation) - : this(SkinBOX.FromString(box), hasInflation) + public BoxEditor(string formattedBoxString, bool hasInflation) + : this(SkinBOX.FromString(formattedBoxString), hasInflation) { } @@ -43,14 +44,14 @@ namespace PckStudio.Forms.Editor private void saveButton_Click(object sender, EventArgs e) { - Result = + result = SkinBOX.FromString( $"{parentComboBox.SelectedItem} " + $"{PosXUpDown.Value} {PosYUpDown.Value} {PosZUpDown.Value} " + $"{SizeXUpDown.Value} {SizeYUpDown.Value} {SizeZUpDown.Value} " + $"{uvXUpDown.Value} {uvYUpDown.Value} " + $"{Convert.ToInt32(armorCheckBox.Checked)} " + $"{Convert.ToInt32(mirrorCheckBox.Checked)} " + - $"{inflationUpDown.Value}"; + $"{inflationUpDown.Value}"); DialogResult = DialogResult.OK; } diff --git a/PCK-Studio/Forms/Editor/COLEditor.Designer.cs b/PCK-Studio/Forms/Editor/COLEditor.Designer.cs index 30338f00..ef808db5 100644 --- a/PCK-Studio/Forms/Editor/COLEditor.Designer.cs +++ b/PCK-Studio/Forms/Editor/COLEditor.Designer.cs @@ -547,7 +547,6 @@ namespace PckStudio.Forms.Editor this.Name = "COLEditor"; this.Style = MetroFramework.MetroColorStyle.Silver; this.Theme = MetroFramework.MetroThemeStyle.Dark; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.COLEditor_FormClosing); this.metroPanel1.ResumeLayout(false); this.metroPanel1.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.blueUpDown)).EndInit(); diff --git a/PCK-Studio/Forms/Editor/COLEditor.cs b/PCK-Studio/Forms/Editor/COLEditor.cs index 73966b8a..b36c01a7 100644 --- a/PCK-Studio/Forms/Editor/COLEditor.cs +++ b/PCK-Studio/Forms/Editor/COLEditor.cs @@ -8,32 +8,39 @@ using MetroFramework.Forms; using OMI.Formats.Color; using OMI.Formats.Pck; using OMI.Workers.Color; -using PckStudio.Extensions; +using PckStudio.Core.Extensions; using PckStudio.Properties; +using PckStudio.Controls; +using PckStudio.Interfaces; +using System.Collections.ObjectModel; namespace PckStudio.Forms.Editor { - public partial class COLEditor : MetroForm + public partial class COLEditor : EditorForm { ColorContainer _defaultColourfile; - ColorContainer _colourfile; string _clipboard_color = "#FFFFFF"; - private readonly PckAsset _asset; - List colorCache = new List(); List waterCache = new List(); List underwaterCache = new List(); List fogCache = new List(); - public COLEditor(PckAsset asset) + private static readonly ICollection PS4Biomes = new List + { + "bamboo_jungle", + "bamboo_jungle_hills", + "mesa_mutated", + "mega_spruce_taiga_mutated", + "mega_taiga_mutated" + }; + + public COLEditor(ColorContainer colorContainer, ISaveContext saveContext) + : base(colorContainer, saveContext) { InitializeComponent(); - saveToolStripMenuItem1.Visible = !Settings.Default.AutoSaveChanges; - - _asset = asset; - _colourfile = asset.GetData(new COLFileReader()); + saveToolStripMenuItem1.Visible = !saveContext.AutoSave; TU12ToolStripMenuItem.Click += (sender, e) => SetUpDefaultFile(sender, e, 0); TU13ToolStripMenuItem.Click += (sender, e) => SetUpDefaultFile(sender, e, 1); @@ -111,9 +118,9 @@ namespace PckStudio.Forms.Editor underwaterTreeView.Nodes.Clear(); fogTreeView.Nodes.Clear(); - ColorContainer temp = targetVersion ? _defaultColourfile : _colourfile; + ColorContainer temp = targetVersion ? _defaultColourfile : EditorValue; - List CurrentEntries = new List(); + List currentEntries = new List(); colorCache.Clear(); fogCache.Clear(); @@ -123,33 +130,33 @@ namespace PckStudio.Forms.Editor // fixes the duplicate entry bug if (targetVersion) { - foreach(ColorContainer.Color col in _colourfile.Colors) + foreach(ColorContainer.Color col in EditorValue.Colors) { if (_defaultColourfile.Colors.Find(c => c.Name == col.Name) == null) continue; - CurrentEntries.Add(col.Name); + currentEntries.Add(col.Name); AddEntry(colorTreeView, colorCache, col.Name, col); } } foreach (ColorContainer.Color col in temp.Colors) { - ColorContainer.Color entry = _colourfile.Colors.Find(color => color.Name == col.Name); - if (CurrentEntries.Contains(col.Name)) + ColorContainer.Color entry = EditorValue.Colors.Find(color => color.Name == col.Name); + if (currentEntries.Contains(col.Name)) continue; ColorContainer.Color color = entry ?? col; AddEntry(colorTreeView, colorCache, color.Name, color); } - CurrentEntries.Clear(); + currentEntries.Clear(); // fixes the duplicate entry bug if (targetVersion) { - foreach (ColorContainer.WaterColor col in _colourfile.WaterColors) + foreach (ColorContainer.WaterColor col in EditorValue.WaterColors) { if (_defaultColourfile.WaterColors.Find(c => c.Name == col.Name) == null) continue; - ColorContainer.WaterColor entry = _colourfile.WaterColors.Find(color => color.Name == col.Name); + ColorContainer.WaterColor entry = EditorValue.WaterColors.Find(color => color.Name == col.Name); ColorContainer.WaterColor color = entry ?? col; AddEntry(waterTreeView, waterCache, color.Name, color); AddEntry(underwaterTreeView, underwaterCache, color.Name, color); @@ -159,8 +166,8 @@ namespace PckStudio.Forms.Editor foreach (ColorContainer.WaterColor col in temp.WaterColors) { - ColorContainer.WaterColor entry = _colourfile.WaterColors.Find(color => color.Name == col.Name); - if (CurrentEntries.Contains(col.Name)) + ColorContainer.WaterColor entry = EditorValue.WaterColors.Find(color => color.Name == col.Name); + if (currentEntries.Contains(col.Name)) continue; ColorContainer.WaterColor color = entry ?? col; AddEntry(waterTreeView, waterCache, color.Name, color); @@ -201,14 +208,14 @@ namespace PckStudio.Forms.Editor fogTreeView.SelectedNode = null; var colorEntry = (ColorContainer.Color)colorTreeView.SelectedNode.Tag; - var color = colorEntry.ColorPallette.ToArgb(); + Color color = colorEntry.ColorPallette; SetUpValueChanged(false); alphaUpDown.Visible = false; alphaLabel.Visible = false; - redUpDown.Value = color >> 16 & 0xff; - greenUpDown.Value = color >> 8 & 0xff; - blueUpDown.Value = color & 0xff; - pictureBox1.BackColor = Color.FromArgb(0xff << 24 | color); + redUpDown.Value = color.R; + greenUpDown.Value = color.G; + blueUpDown.Value = color.B; + pictureBox1.BackColor = Color.FromArgb(0xff, color); colorTextbox.Text = ColorTranslator.ToHtml(colorEntry.ColorPallette).TrimStart('#'); SetUpValueChanged(true); } @@ -226,15 +233,17 @@ namespace PckStudio.Forms.Editor fogTreeView.SelectedNode = null; var colorEntry = (ColorContainer.WaterColor)waterTreeView.SelectedNode.Tag; - int color = colorEntry.SurfaceColor.ToArgb(); + Color color = colorEntry.SurfaceColor; SetUpValueChanged(false); + + alphaUpDown.Value = color.A; + redUpDown.Value = color.R; + greenUpDown.Value = color.G; + blueUpDown.Value = color.B; + alphaUpDown.Enabled = true; alphaUpDown.Visible = true; alphaLabel.Visible = true; - alphaUpDown.Value = color >> 24 & 0xff; - redUpDown.Value = color >> 16 & 0xff; - greenUpDown.Value = color >> 8 & 0xff; - blueUpDown.Value = color & 0xff; pictureBox1.BackColor = colorEntry.SurfaceColor; colorTextbox.Text = ColorTranslator.ToHtml(colorEntry.SurfaceColor).TrimStart('#'); SetUpValueChanged(true); @@ -253,14 +262,14 @@ namespace PckStudio.Forms.Editor fogTreeView.SelectedNode = null; var colorEntry = (ColorContainer.WaterColor)underwaterTreeView.SelectedNode.Tag; - int color = colorEntry.UnderwaterColor.ToArgb(); + Color color = colorEntry.UnderwaterColor; SetUpValueChanged(false); alphaUpDown.Visible = false; alphaLabel.Visible = false; - redUpDown.Value = color >> 16 & 0xff; - greenUpDown.Value = color >> 8 & 0xff; - blueUpDown.Value = color & 0xff; - pictureBox1.BackColor = Color.FromArgb(255, Color.FromArgb(0xff << 24 | color)); + redUpDown.Value = color.R; + greenUpDown.Value = color.G; + blueUpDown.Value = color.B; + pictureBox1.BackColor = Color.FromArgb(0xff, color); colorTextbox.Text = ColorTranslator.ToHtml(colorEntry.UnderwaterColor).TrimStart('#'); SetUpValueChanged(true); } @@ -278,22 +287,21 @@ namespace PckStudio.Forms.Editor underwaterTreeView.SelectedNode = null; var colorEntry = (ColorContainer.WaterColor)fogTreeView.SelectedNode.Tag; - int color = colorEntry.FogColor.ToArgb(); + Color color = colorEntry.FogColor; SetUpValueChanged(false); alphaUpDown.Visible = false; alphaLabel.Visible = false; - redUpDown.Value = color >> 16 & 0xff; - greenUpDown.Value = color >> 8 & 0xff; - blueUpDown.Value = color & 0xff; - pictureBox1.BackColor = Color.FromArgb(255, Color.FromArgb(0xff << 24 | color)); + redUpDown.Value = color.R; + greenUpDown.Value = color.G; + blueUpDown.Value = color.B; + pictureBox1.BackColor = Color.FromArgb(0xff, color); colorTextbox.Text = ColorTranslator.ToHtml(colorEntry.FogColor).TrimStart('#'); SetUpValueChanged(true); } private void saveToolStripMenuItem1_Click(object sender, EventArgs e) { - _asset.SetData(new COLFileWriter(_colourfile)); - + Save(); DialogResult = DialogResult.OK; } @@ -485,14 +493,14 @@ namespace PckStudio.Forms.Editor } else { - ColorContainer.WaterColor WaterEntry = _defaultColourfile.WaterColors.Find(color => color.Name == node.Text); + ColorContainer.WaterColor waterEntry = _defaultColourfile.WaterColors.Find(color => color.Name == node.Text); - if (WaterEntry == null) + if (waterEntry == null) return; color = - tab == waterTab ? WaterEntry.SurfaceColor : - tab == underwaterTab ? WaterEntry.UnderwaterColor : WaterEntry.FogColor; + tab == waterTab ? waterEntry.SurfaceColor : + tab == underwaterTab ? waterEntry.UnderwaterColor : waterEntry.FogColor; if (tab == waterTab) { @@ -523,52 +531,52 @@ namespace PckStudio.Forms.Editor fogTreeView.Nodes.Clear(); if (!string.IsNullOrEmpty(metroTextBox1.Text)) { - foreach (TreeNode _node in colorCache) + foreach (TreeNode node in colorCache) { - if (_node.Text.ToLower().Contains(metroTextBox1.Text.ToLower())) + if (node.Text.ToLower().Contains(metroTextBox1.Text.ToLower())) { - colorTreeView.Nodes.Add((TreeNode)_node.Clone()); + colorTreeView.Nodes.Add((TreeNode)node.Clone()); } } - foreach (TreeNode _node in waterCache) + foreach (TreeNode node in waterCache) { - if (_node.Text.ToLower().Contains(metroTextBox1.Text.ToLower())) + if (node.Text.ToLower().Contains(metroTextBox1.Text.ToLower())) { - waterTreeView.Nodes.Add((TreeNode)_node.Clone()); + waterTreeView.Nodes.Add((TreeNode)node.Clone()); } } - foreach (TreeNode _node in underwaterCache) + foreach (TreeNode node in underwaterCache) { - if (_node.Text.ToLower().Contains(metroTextBox1.Text.ToLower())) + if (node.Text.ToLower().Contains(metroTextBox1.Text.ToLower())) { - underwaterTreeView.Nodes.Add((TreeNode)_node.Clone()); + underwaterTreeView.Nodes.Add((TreeNode)node.Clone()); } } - foreach (TreeNode _node in fogCache) + foreach (TreeNode node in fogCache) { - if (_node.Text.ToLower().Contains(metroTextBox1.Text.ToLower())) + if (node.Text.ToLower().Contains(metroTextBox1.Text.ToLower())) { - fogTreeView.Nodes.Add((TreeNode)_node.Clone()); + fogTreeView.Nodes.Add((TreeNode)node.Clone()); } } } else { - foreach (TreeNode _node in colorCache) + foreach (TreeNode node in colorCache) { - colorTreeView.Nodes.Add((TreeNode)_node.Clone()); + colorTreeView.Nodes.Add((TreeNode)node.Clone()); } - foreach (TreeNode _node in waterCache) + foreach (TreeNode node in waterCache) { - waterTreeView.Nodes.Add((TreeNode)_node.Clone()); + waterTreeView.Nodes.Add((TreeNode)node.Clone()); } - foreach (TreeNode _node in underwaterCache) + foreach (TreeNode node in underwaterCache) { - underwaterTreeView.Nodes.Add((TreeNode)_node.Clone()); + underwaterTreeView.Nodes.Add((TreeNode)node.Clone()); } - foreach (TreeNode _node in fogCache) + foreach (TreeNode node in fogCache) { - fogTreeView.Nodes.Add((TreeNode)_node.Clone()); + fogTreeView.Nodes.Add((TreeNode)node.Clone()); } } //enables redrawing tree after all objects have been added @@ -588,14 +596,6 @@ namespace PckStudio.Forms.Editor colorTextbox.Text = _clipboard_color; } - private void COLEditor_FormClosing(object sender, FormClosingEventArgs e) - { - if (Settings.Default.AutoSaveChanges) - { - saveToolStripMenuItem1_Click(sender, EventArgs.Empty); - } - } - private void colorTextbox_KeyPress(object sender, KeyPressEventArgs e) { string hexCheck = "0123456789abcdefABCDEF\b"; @@ -605,21 +605,12 @@ namespace PckStudio.Forms.Editor private void stripPS4BiomesToolStripMenuItem_Click(object sender, EventArgs e) { - if(_colourfile.WaterColors.Count > 0) + if(EditorValue.WaterColors.Count > 0) { - List PS4Biomes = new List - { - "bamboo_jungle", - "bamboo_jungle_hills", - "mesa_mutated", - "mega_spruce_taiga_mutated", - "mega_taiga_mutated" - }; - - foreach (ColorContainer.WaterColor col in _colourfile.WaterColors.ToList()) + foreach (ColorContainer.WaterColor col in EditorValue.WaterColors.ToList()) { if (PS4Biomes.Contains(col.Name)) - _colourfile.WaterColors.Remove(col); + EditorValue.WaterColors.Remove(col); } SetUpTable(false); @@ -640,12 +631,12 @@ namespace PckStudio.Forms.Editor entry.Name = prompt.NewText; entry.ColorPallette = Color.FromArgb(0xFFFFFF); - if(_colourfile.Colors.Find(c => c.Name == entry.Name) != null) + if(EditorValue.Colors.Find(c => c.Name == entry.Name) != null) { MessageBox.Show(this, $"\"{entry.Name}\" already exists in this color table", "Color not added"); } - _colourfile.Colors.Add(entry); + EditorValue.Colors.Add(entry); AddEntry(colorTreeView, colorCache, entry.Name, entry); } } @@ -659,7 +650,7 @@ namespace PckStudio.Forms.Editor && entry != null && entry.Tag is ColorContainer.Color color) { - _colourfile.Colors.Remove(color); + EditorValue.Colors.Remove(color); RemoveEntry(entry, colorCache); } } diff --git a/PCK-Studio/Forms/Editor/CustomSkinEditor.Designer.cs b/PCK-Studio/Forms/Editor/CustomSkinEditor.Designer.cs new file mode 100644 index 00000000..6f4df1c4 --- /dev/null +++ b/PCK-Studio/Forms/Editor/CustomSkinEditor.Designer.cs @@ -0,0 +1,446 @@ +namespace PckStudio.Forms.Editor +{ + partial class CustomSkinEditor + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.Windows.Forms.GroupBox groupBox1; + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CustomSkinEditor)); + this.sizeLabel = new System.Windows.Forms.Label(); + this.positionLabel = new System.Windows.Forms.Label(); + this.uvLabel = new System.Windows.Forms.Label(); + this.importTextureButton = new MetroFramework.Controls.MetroButton(); + this.exportTextureButton = new MetroFramework.Controls.MetroButton(); + this.skinPartTabContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.createToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.cloneToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.deleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.generateUvTextureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.buttonDone = new MetroFramework.Controls.MetroButton(); + this.importSkinButton = new MetroFramework.Controls.MetroButton(); + this.exportSkinButton = new MetroFramework.Controls.MetroButton(); + this.outlineColorButton = new MetroFramework.Controls.MetroButton(); + this.generateTextureCheckBox = new MetroFramework.Controls.MetroCheckBox(); + this.showArmorCheckbox = new MetroFramework.Controls.MetroCheckBox(); + this.skinPartListBox = new System.Windows.Forms.ListBox(); + this.captureScreenshotButton = new MetroFramework.Controls.MetroButton(); + this.showToolsCheckBox = new MetroFramework.Controls.MetroCheckBox(); + this.skinNameLabel = new MetroFramework.Controls.MetroLabel(); + this.metroTabControl1 = new MetroFramework.Controls.MetroTabControl(); + this.skinPartsTabPage = new System.Windows.Forms.TabPage(); + this.skinOffsetsTabPage = new System.Windows.Forms.TabPage(); + this.offsetListBox = new System.Windows.Forms.ListBox(); + this.offsetTabContextMenu = new MetroFramework.Controls.MetroContextMenu(this.components); + this.addOffsetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.removeOffsetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.renderer3D1 = new PckStudio.Rendering.SkinRenderer(); + this.uvPictureBox = new PckStudio.ToolboxItems.InterpolationPictureBox(); + this.centerSelectionCheckbox = new MetroFramework.Controls.MetroCheckBox(); + this.textureSizeLabel = new System.Windows.Forms.Label(); + this.renderSettingsButton = new MetroFramework.Controls.MetroButton(); + this.exportTemplateButton = new MetroFramework.Controls.MetroButton(); + this.animEditorButton = new MetroFramework.Controls.MetroButton(); + groupBox1 = new System.Windows.Forms.GroupBox(); + groupBox1.SuspendLayout(); + this.skinPartTabContextMenu.SuspendLayout(); + this.metroTabControl1.SuspendLayout(); + this.skinPartsTabPage.SuspendLayout(); + this.skinOffsetsTabPage.SuspendLayout(); + this.offsetTabContextMenu.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.uvPictureBox)).BeginInit(); + this.SuspendLayout(); + // + // groupBox1 + // + resources.ApplyResources(groupBox1, "groupBox1"); + groupBox1.Controls.Add(this.sizeLabel); + groupBox1.Controls.Add(this.positionLabel); + groupBox1.Controls.Add(this.uvLabel); + groupBox1.ForeColor = System.Drawing.SystemColors.Control; + groupBox1.Name = "groupBox1"; + groupBox1.TabStop = false; + // + // sizeLabel + // + resources.ApplyResources(this.sizeLabel, "sizeLabel"); + this.sizeLabel.ForeColor = System.Drawing.Color.White; + this.sizeLabel.Name = "sizeLabel"; + // + // positionLabel + // + resources.ApplyResources(this.positionLabel, "positionLabel"); + this.positionLabel.ForeColor = System.Drawing.Color.White; + this.positionLabel.Name = "positionLabel"; + // + // uvLabel + // + resources.ApplyResources(this.uvLabel, "uvLabel"); + this.uvLabel.ForeColor = System.Drawing.Color.White; + this.uvLabel.Name = "uvLabel"; + // + // importTextureButton + // + resources.ApplyResources(this.importTextureButton, "importTextureButton"); + this.importTextureButton.ForeColor = System.Drawing.Color.White; + this.importTextureButton.Name = "importTextureButton"; + this.importTextureButton.Theme = MetroFramework.MetroThemeStyle.Dark; + this.importTextureButton.UseSelectable = true; + this.importTextureButton.Click += new System.EventHandler(this.importTextureButton_Click); + // + // exportTextureButton + // + resources.ApplyResources(this.exportTextureButton, "exportTextureButton"); + this.exportTextureButton.ForeColor = System.Drawing.Color.White; + this.exportTextureButton.Name = "exportTextureButton"; + this.exportTextureButton.Theme = MetroFramework.MetroThemeStyle.Dark; + this.exportTextureButton.UseSelectable = true; + this.exportTextureButton.Click += new System.EventHandler(this.exportTextureButton_Click); + // + // skinPartTabContextMenu + // + this.skinPartTabContextMenu.ImageScalingSize = new System.Drawing.Size(20, 20); + this.skinPartTabContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.createToolStripMenuItem, + this.cloneToolStripMenuItem, + this.deleteToolStripMenuItem, + this.generateUvTextureToolStripMenuItem}); + this.skinPartTabContextMenu.Name = "contextMenuStrip1"; + resources.ApplyResources(this.skinPartTabContextMenu, "skinPartTabContextMenu"); + // + // createToolStripMenuItem + // + resources.ApplyResources(this.createToolStripMenuItem, "createToolStripMenuItem"); + this.createToolStripMenuItem.Name = "createToolStripMenuItem"; + this.createToolStripMenuItem.Click += new System.EventHandler(this.createToolStripMenuItem_Click); + // + // cloneToolStripMenuItem + // + resources.ApplyResources(this.cloneToolStripMenuItem, "cloneToolStripMenuItem"); + this.cloneToolStripMenuItem.Name = "cloneToolStripMenuItem"; + this.cloneToolStripMenuItem.Click += new System.EventHandler(this.cloneToolStripMenuItem_Click); + // + // deleteToolStripMenuItem + // + resources.ApplyResources(this.deleteToolStripMenuItem, "deleteToolStripMenuItem"); + this.deleteToolStripMenuItem.Name = "deleteToolStripMenuItem"; + this.deleteToolStripMenuItem.Click += new System.EventHandler(this.deleteToolStripMenuItem_Click); + // + // generateUvTextureToolStripMenuItem + // + resources.ApplyResources(this.generateUvTextureToolStripMenuItem, "generateUvTextureToolStripMenuItem"); + this.generateUvTextureToolStripMenuItem.Name = "generateUvTextureToolStripMenuItem"; + this.generateUvTextureToolStripMenuItem.Click += new System.EventHandler(this.generateUvTextureToolStripMenuItem_Click); + // + // buttonDone + // + resources.ApplyResources(this.buttonDone, "buttonDone"); + this.buttonDone.DialogResult = System.Windows.Forms.DialogResult.OK; + this.buttonDone.ForeColor = System.Drawing.Color.White; + this.buttonDone.Name = "buttonDone"; + this.buttonDone.Theme = MetroFramework.MetroThemeStyle.Dark; + this.buttonDone.UseSelectable = true; + this.buttonDone.Click += new System.EventHandler(this.buttonDone_Click); + // + // importSkinButton + // + resources.ApplyResources(this.importSkinButton, "importSkinButton"); + this.importSkinButton.ForeColor = System.Drawing.Color.White; + this.importSkinButton.Name = "importSkinButton"; + this.importSkinButton.Theme = MetroFramework.MetroThemeStyle.Dark; + this.importSkinButton.UseSelectable = true; + this.importSkinButton.Click += new System.EventHandler(this.importSkinButton_Click); + // + // exportSkinButton + // + resources.ApplyResources(this.exportSkinButton, "exportSkinButton"); + this.exportSkinButton.ForeColor = System.Drawing.Color.White; + this.exportSkinButton.Name = "exportSkinButton"; + this.exportSkinButton.Theme = MetroFramework.MetroThemeStyle.Dark; + this.exportSkinButton.UseSelectable = true; + this.exportSkinButton.Click += new System.EventHandler(this.exportSkinButton_Click); + // + // outlineColorButton + // + resources.ApplyResources(this.outlineColorButton, "outlineColorButton"); + this.outlineColorButton.ForeColor = System.Drawing.Color.White; + this.outlineColorButton.Name = "outlineColorButton"; + this.outlineColorButton.Theme = MetroFramework.MetroThemeStyle.Dark; + this.outlineColorButton.UseSelectable = true; + this.outlineColorButton.Click += new System.EventHandler(this.outlineColorButton_Click); + // + // generateTextureCheckBox + // + resources.ApplyResources(this.generateTextureCheckBox, "generateTextureCheckBox"); + this.generateTextureCheckBox.Name = "generateTextureCheckBox"; + this.generateTextureCheckBox.Theme = MetroFramework.MetroThemeStyle.Dark; + this.generateTextureCheckBox.UseSelectable = true; + // + // showArmorCheckbox + // + resources.ApplyResources(this.showArmorCheckbox, "showArmorCheckbox"); + this.showArmorCheckbox.Name = "showArmorCheckbox"; + this.showArmorCheckbox.Theme = MetroFramework.MetroThemeStyle.Dark; + this.showArmorCheckbox.UseSelectable = true; + this.showArmorCheckbox.CheckedChanged += new System.EventHandler(this.showArmorCheckbox_CheckedChanged); + // + // skinPartListBox + // + this.skinPartListBox.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.skinPartListBox.ContextMenuStrip = this.skinPartTabContextMenu; + resources.ApplyResources(this.skinPartListBox, "skinPartListBox"); + this.skinPartListBox.FormattingEnabled = true; + this.skinPartListBox.Name = "skinPartListBox"; + this.skinPartListBox.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended; + this.skinPartListBox.Tag = ""; + this.skinPartListBox.MouseClick += new System.Windows.Forms.MouseEventHandler(this.skinPartListBox_MouseClick); + this.skinPartListBox.SelectedIndexChanged += new System.EventHandler(this.skinPartListBox_SelectedIndexChanged); + this.skinPartListBox.DoubleClick += new System.EventHandler(this.skinPartListBox_DoubleClick); + this.skinPartListBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.skinPartListBox_KeyUp); + // + // captureScreenshotButton + // + resources.ApplyResources(this.captureScreenshotButton, "captureScreenshotButton"); + this.captureScreenshotButton.ForeColor = System.Drawing.Color.White; + this.captureScreenshotButton.Name = "captureScreenshotButton"; + this.captureScreenshotButton.Theme = MetroFramework.MetroThemeStyle.Dark; + this.captureScreenshotButton.UseSelectable = true; + this.captureScreenshotButton.Click += new System.EventHandler(this.captureScreenshotButton_Click); + // + // showToolsCheckBox + // + resources.ApplyResources(this.showToolsCheckBox, "showToolsCheckBox"); + this.showToolsCheckBox.Name = "showToolsCheckBox"; + this.showToolsCheckBox.Theme = MetroFramework.MetroThemeStyle.Dark; + this.showToolsCheckBox.UseSelectable = true; + // + // skinNameLabel + // + resources.ApplyResources(this.skinNameLabel, "skinNameLabel"); + this.skinNameLabel.Name = "skinNameLabel"; + this.skinNameLabel.Theme = MetroFramework.MetroThemeStyle.Dark; + // + // metroTabControl1 + // + resources.ApplyResources(this.metroTabControl1, "metroTabControl1"); + this.metroTabControl1.Controls.Add(this.skinPartsTabPage); + this.metroTabControl1.Controls.Add(this.skinOffsetsTabPage); + this.metroTabControl1.Multiline = true; + this.metroTabControl1.Name = "metroTabControl1"; + this.metroTabControl1.SelectedIndex = 0; + this.metroTabControl1.Style = MetroFramework.MetroColorStyle.Pink; + this.metroTabControl1.Theme = MetroFramework.MetroThemeStyle.Dark; + this.metroTabControl1.UseSelectable = true; + // + // skinPartsTabPage + // + this.skinPartsTabPage.Controls.Add(this.skinPartListBox); + resources.ApplyResources(this.skinPartsTabPage, "skinPartsTabPage"); + this.skinPartsTabPage.Name = "skinPartsTabPage"; + // + // skinOffsetsTabPage + // + this.skinOffsetsTabPage.Controls.Add(this.offsetListBox); + resources.ApplyResources(this.skinOffsetsTabPage, "skinOffsetsTabPage"); + this.skinOffsetsTabPage.Name = "skinOffsetsTabPage"; + // + // offsetListBox + // + this.offsetListBox.ContextMenuStrip = this.offsetTabContextMenu; + resources.ApplyResources(this.offsetListBox, "offsetListBox"); + this.offsetListBox.FormattingEnabled = true; + this.offsetListBox.Name = "offsetListBox"; + this.offsetListBox.DoubleClick += new System.EventHandler(this.offsetListBox_DoubleClick); + // + // offsetTabContextMenu + // + this.offsetTabContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.addOffsetToolStripMenuItem, + this.removeOffsetToolStripMenuItem}); + this.offsetTabContextMenu.Name = "offsetTabContextMenu"; + resources.ApplyResources(this.offsetTabContextMenu, "offsetTabContextMenu"); + this.offsetTabContextMenu.Theme = MetroFramework.MetroThemeStyle.Dark; + // + // addOffsetToolStripMenuItem + // + this.addOffsetToolStripMenuItem.Name = "addOffsetToolStripMenuItem"; + resources.ApplyResources(this.addOffsetToolStripMenuItem, "addOffsetToolStripMenuItem"); + this.addOffsetToolStripMenuItem.Click += new System.EventHandler(this.addOffsetToolStripMenuItem_Click); + // + // removeOffsetToolStripMenuItem + // + this.removeOffsetToolStripMenuItem.Name = "removeOffsetToolStripMenuItem"; + resources.ApplyResources(this.removeOffsetToolStripMenuItem, "removeOffsetToolStripMenuItem"); + this.removeOffsetToolStripMenuItem.Click += new System.EventHandler(this.removeOffsetToolStripMenuItem_Click); + // + // renderer3D1 + // + resources.ApplyResources(this.renderer3D1, "renderer3D1"); + this.renderer3D1.Animate = true; + this.renderer3D1.BackColor = System.Drawing.Color.DimGray; + this.renderer3D1.CapeTexture = null; + this.renderer3D1.CenterOnSelect = false; + this.renderer3D1.GuideLineColor = System.Drawing.Color.Empty; + this.renderer3D1.HighlightlingColor = System.Drawing.Color.Aqua; + this.renderer3D1.MouseSensetivity = 0.01F; + this.renderer3D1.Name = "renderer3D1"; + this.renderer3D1.RefreshRate = 60; + this.renderer3D1.SelectedIndex = -1; + this.renderer3D1.SelectedIndices = new int[] { + -1}; + this.renderer3D1.ShowArmor = false; + this.renderer3D1.ShowBoundingBox = false; + this.renderer3D1.ShowGuideLines = false; + this.renderer3D1.Texture = null; + this.renderer3D1.VSync = true; + this.renderer3D1.TextureChanging += new System.EventHandler(this.renderer3D1_TextureChanging); + // + // uvPictureBox + // + resources.ApplyResources(this.uvPictureBox, "uvPictureBox"); + this.uvPictureBox.BackgroundInterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; + this.uvPictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; + this.uvPictureBox.Name = "uvPictureBox"; + this.uvPictureBox.TabStop = false; + // + // centerSelectionCheckbox + // + resources.ApplyResources(this.centerSelectionCheckbox, "centerSelectionCheckbox"); + this.centerSelectionCheckbox.Name = "centerSelectionCheckbox"; + this.centerSelectionCheckbox.Theme = MetroFramework.MetroThemeStyle.Dark; + this.centerSelectionCheckbox.UseSelectable = true; + this.centerSelectionCheckbox.CheckedChanged += new System.EventHandler(this.centerSelectionCheckbox_CheckedChanged); + // + // textureSizeLabel + // + resources.ApplyResources(this.textureSizeLabel, "textureSizeLabel"); + this.textureSizeLabel.ForeColor = System.Drawing.Color.White; + this.textureSizeLabel.Name = "textureSizeLabel"; + // + // renderSettingsButton + // + resources.ApplyResources(this.renderSettingsButton, "renderSettingsButton"); + this.renderSettingsButton.Name = "renderSettingsButton"; + this.renderSettingsButton.Theme = MetroFramework.MetroThemeStyle.Dark; + this.renderSettingsButton.UseSelectable = true; + this.renderSettingsButton.Click += new System.EventHandler(this.renderSettingsButton_Click); + // + // exportTemplateButton + // + resources.ApplyResources(this.exportTemplateButton, "exportTemplateButton"); + this.exportTemplateButton.ForeColor = System.Drawing.Color.White; + this.exportTemplateButton.Name = "exportTemplateButton"; + this.exportTemplateButton.Theme = MetroFramework.MetroThemeStyle.Dark; + this.exportTemplateButton.UseSelectable = true; + this.exportTemplateButton.Click += new System.EventHandler(this.exportTemplateButton_Click); + // + // animEditorButton + // + resources.ApplyResources(this.animEditorButton, "animEditorButton"); + this.animEditorButton.Name = "animEditorButton"; + this.animEditorButton.Theme = MetroFramework.MetroThemeStyle.Dark; + this.animEditorButton.UseSelectable = true; + this.animEditorButton.Click += new System.EventHandler(this.animEditorButton_Click); + // + // CustomSkinEditor + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.exportTextureButton); + this.Controls.Add(this.importTextureButton); + this.Controls.Add(this.textureSizeLabel); + this.Controls.Add(groupBox1); + this.Controls.Add(this.showToolsCheckBox); + this.Controls.Add(this.centerSelectionCheckbox); + this.Controls.Add(this.showArmorCheckbox); + this.Controls.Add(this.generateTextureCheckBox); + this.Controls.Add(this.outlineColorButton); + this.Controls.Add(this.uvPictureBox); + this.Controls.Add(this.animEditorButton); + this.Controls.Add(this.exportTemplateButton); + this.Controls.Add(this.renderSettingsButton); + this.Controls.Add(this.metroTabControl1); + this.Controls.Add(this.skinNameLabel); + this.Controls.Add(this.captureScreenshotButton); + this.Controls.Add(this.renderer3D1); + this.Controls.Add(this.exportSkinButton); + this.Controls.Add(this.importSkinButton); + this.Controls.Add(this.buttonDone); + this.Name = "CustomSkinEditor"; + this.Style = MetroFramework.MetroColorStyle.Silver; + this.Theme = MetroFramework.MetroThemeStyle.Dark; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.CustomSkinEditor_FormClosing); + groupBox1.ResumeLayout(false); + groupBox1.PerformLayout(); + this.skinPartTabContextMenu.ResumeLayout(false); + this.metroTabControl1.ResumeLayout(false); + this.skinPartsTabPage.ResumeLayout(false); + this.skinOffsetsTabPage.ResumeLayout(false); + this.offsetTabContextMenu.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.uvPictureBox)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.ContextMenuStrip skinPartTabContextMenu; + private System.Windows.Forms.ToolStripMenuItem createToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem cloneToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem deleteToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem generateUvTextureToolStripMenuItem; + private MetroFramework.Controls.MetroButton buttonDone; + private MetroFramework.Controls.MetroButton outlineColorButton; + private MetroFramework.Controls.MetroButton exportSkinButton; + private MetroFramework.Controls.MetroButton importSkinButton; + private PckStudio.ToolboxItems.InterpolationPictureBox uvPictureBox; + private MetroFramework.Controls.MetroButton importTextureButton; + private MetroFramework.Controls.MetroButton exportTextureButton; + private MetroFramework.Controls.MetroCheckBox generateTextureCheckBox; + private MetroFramework.Controls.MetroCheckBox showArmorCheckbox; + private Rendering.SkinRenderer renderer3D1; + private System.Windows.Forms.ListBox skinPartListBox; + private MetroFramework.Controls.MetroButton captureScreenshotButton; + private MetroFramework.Controls.MetroCheckBox showToolsCheckBox; + private MetroFramework.Controls.MetroLabel skinNameLabel; + private MetroFramework.Controls.MetroTabControl metroTabControl1; + private System.Windows.Forms.TabPage skinPartsTabPage; + private System.Windows.Forms.TabPage skinOffsetsTabPage; + private System.Windows.Forms.ListBox offsetListBox; + private MetroFramework.Controls.MetroContextMenu offsetTabContextMenu; + private System.Windows.Forms.ToolStripMenuItem addOffsetToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem removeOffsetToolStripMenuItem; + private MetroFramework.Controls.MetroCheckBox centerSelectionCheckbox; + private System.Windows.Forms.Label positionLabel; + private System.Windows.Forms.Label sizeLabel; + private System.Windows.Forms.Label uvLabel; + private System.Windows.Forms.Label textureSizeLabel; + private MetroFramework.Controls.MetroButton renderSettingsButton; + private MetroFramework.Controls.MetroButton exportTemplateButton; + private MetroFramework.Controls.MetroButton animEditorButton; + } +} \ No newline at end of file diff --git a/PCK-Studio/Forms/Editor/CustomSkinEditor.cs b/PCK-Studio/Forms/Editor/CustomSkinEditor.cs new file mode 100644 index 00000000..8b39c40d --- /dev/null +++ b/PCK-Studio/Forms/Editor/CustomSkinEditor.cs @@ -0,0 +1,481 @@ +using System; +using System.Linq; +using System.Text; +using System.Drawing; +using System.Diagnostics; +using System.Windows.Forms; +using System.Drawing.Imaging; +using System.Drawing.Drawing2D; +using System.Collections.Generic; + +using PckStudio.Controls; +using PckStudio.Properties; +using PckStudio.Forms.Additional_Popups; + +using PckStudio.Core.Skin; +using PckStudio.Core.Extensions; +using PckStudio.Interfaces; +using PckStudio.ModelSupport; +using PckStuido.ModelSupport.Extension; + +namespace PckStudio.Forms.Editor +{ + public partial class CustomSkinEditor : EditorForm + { + private const float cOffsetMaximum = 100_000f; + private Random _rng; + private bool _inflateOverlayParts; + private bool _allowInflate; + + private BindingSource _skinPartListBindingSource; + private BindingSource _skinOffsetListBindingSource; + + private Core.App.SettingsManager _settingsManager; + + private static GraphicsConfig _graphicsConfig = new GraphicsConfig() + { + InterpolationMode = InterpolationMode.NearestNeighbor, + PixelOffsetMode = PixelOffsetMode.HighQuality, + }; + + private CustomSkinEditor() : this(null, null) + { } + + public CustomSkinEditor(Skin skin, ISaveContext saveContext, bool inflateOverlayParts = false, bool allowInflate = false) + : base(skin, saveContext) + { + InitializeComponent(); + InitializeRenderSettings(); + _rng = new Random(); + _skinPartListBindingSource = new BindingSource(renderer3D1.ModelData, null); + skinPartListBox.DataSource = _skinPartListBindingSource; + skinPartListBox.DisplayMember = "Type"; + _allowInflate = allowInflate; + _inflateOverlayParts = inflateOverlayParts; + } + + private void InitializeRenderSettings() + { + _settingsManager = Core.App.SettingsManager.CreateSettings(); + _settingsManager.AddSetting("shouldAnimate" , true , "Animate skin" , state => renderer3D1.Animate = state); + _settingsManager.AddSetting("lockMouse" , true , "Lock mouse when paning/rotating", state => renderer3D1.LockMousePosition = state); + _settingsManager.AddSetting("showGuidelines" , false, "Show guidelines" , state => renderer3D1.ShowGuideLines = state); + _settingsManager.AddSetting("showBoundingBox", false, "Show Bounding Box" , state => renderer3D1.ShowBoundingBox = state); + } + + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + renderer3D1.Initialize(_inflateOverlayParts); + renderer3D1.GuideLineColor = Color.LightCoral; + skinNameLabel.Text = EditorValue.MetaData.Name; + if (EditorValue.HasCape) + renderer3D1.CapeTexture = EditorValue.CapeTexture; + LoadModelData(); + } + + protected override bool ProcessDialogKey(Keys keyData) + { + if (keyData == Keys.A) + { + using var animeditor = new ANIMEditor(EditorValue.Anim); + if (animeditor.ShowDialog() == DialogResult.OK) + { + renderer3D1.ANIM = EditorValue.Anim = animeditor.ResultAnim; + skinPartListBox_SelectedIndexChanged(this, EventArgs.Empty); + } + return true; + } + return base.ProcessDialogKey(keyData); + } + + private void LoadModelData() + { + SkinModel modelInfo = EditorValue.Model; + + List boxProperties = modelInfo.AdditionalBoxes; + List offsetProperties = modelInfo.PartOffsets; + + renderer3D1.ANIM = EditorValue.Anim; + + renderer3D1.ModelData.Clear(); + foreach (SkinBOX box in boxProperties) + { + renderer3D1.ModelData.Add(box); + } + renderer3D1.ResetOffsets(); + foreach (SkinPartOffset offset in offsetProperties) + { + renderer3D1.SetPartOffset(offset); + } + + if (EditorValue.Texture is not null) + { + renderer3D1.Texture = EditorValue.Texture; + } + + if (EditorValue.Texture is null && renderer3D1.Texture is not null) + { + EditorValue.Texture = renderer3D1.Texture; + } + + _skinOffsetListBindingSource = new BindingSource(renderer3D1.GetOffsets().ToArray(), null); + offsetListBox.DataSource = _skinOffsetListBindingSource; + offsetListBox.DisplayMember = "Type"; + offsetListBox.ValueMember = "Value"; + + _skinPartListBindingSource.ResetBindings(false); + _skinOffsetListBindingSource.ResetBindings(false); + } + + private void GenerateUVTextureMap(SkinBOX skinBox) + { + if (EditorValue?.Texture is null) + { + Trace.TraceWarning($"[{nameof(CustomSkinEditor)}@{nameof(GenerateUVTextureMap)}] Failed to generate uv for {skinBox}. Reason: Model.Texture was null"); + return; + } + using (Graphics graphics = Graphics.FromImage(EditorValue.Texture)) + { + graphics.ApplyConfig(_graphicsConfig); + int argb = _rng.Next(unchecked((int)0xFF000000), -1); + var color = Color.FromArgb(argb); + Brush brush = new SolidBrush(color); + graphics.FillPath(brush, skinBox.GetUVGraphicsPath()); + } + renderer3D1.Texture = EditorValue.Texture; + } + + private void createToolStripMenuItem_Click(object sender, EventArgs e) + { + var boxEditor = new BoxEditor(SkinBOX.DefaultHead, _allowInflate); + if (boxEditor.ShowDialog() == DialogResult.OK) + { + SkinBOX newBox = boxEditor.Result; + renderer3D1.ModelData.Add(newBox); + EditorValue.Model.AdditionalBoxes.Add(newBox); + _skinPartListBindingSource.ResetBindings(false); + if (generateTextureCheckBox.Checked) + GenerateUVTextureMap(newBox); + } + } + + private void exportTextureButton_Click(object sender, EventArgs e) + { + if (EditorValue?.Texture is null) + { + Trace.TraceWarning($"[{nameof(CustomSkinEditor)}@{nameof(exportTextureButton_Click)}] Failed to export texture. Reason: skin.Model.Texture was null"); + return; + } + using SaveFileDialog saveFileDialog = new SaveFileDialog(); + saveFileDialog.Filter = "PNG Image Files | *.png"; + if (saveFileDialog.ShowDialog() == DialogResult.OK) + { + EditorValue.Texture.Save(saveFileDialog.FileName, ImageFormat.Png); + } + } + + private void importTextureButton_Click(object sender, EventArgs e) + { + OpenFileDialog openFileDialog = new OpenFileDialog(); + openFileDialog.Filter = "PNG Image Files | *.png"; + openFileDialog.Title = "Select Skin Texture"; + + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + generateTextureCheckBox.Checked = false; + renderer3D1.Texture = Image.FromFile(openFileDialog.FileName).ReleaseFromFile(); + } + } + + private void buttonDone_Click(object sender, EventArgs e) + { + EditorValue.Model.AdditionalBoxes.Clear(); + EditorValue.Model.AdditionalBoxes.AddRange(renderer3D1.ModelData); + EditorValue.Model.PartOffsets.Clear(); + EditorValue.Model.PartOffsets.AddRange(renderer3D1.GetOffsets()); + // just in case they're not the same instance + EditorValue.Anim = renderer3D1.ANIM; + DialogResult = DialogResult.OK; + } + + private void exportSkinButton_Click(object sender, EventArgs e) + { + SaveFileDialog saveFileDialog = new SaveFileDialog(); + saveFileDialog.Title = "Save Model File"; + saveFileDialog.Filter = SkinModelImporter.Default.SupportedModelFileFormatsFilter; + saveFileDialog.FileName = EditorValue.MetaData.Name.TrimEnd(new char[] { '\n', '\r' }).Replace(' ', '_'); + if (saveFileDialog.ShowDialog() == DialogResult.OK) + SkinModelImporter.Default.Export(saveFileDialog.FileName, EditorValue.GetModelInfo()); + } + + private void importSkinButton_Click(object sender, EventArgs e) + { + OpenFileDialog openFileDialog = new OpenFileDialog(); + openFileDialog.Title = "Select Model File"; + openFileDialog.Filter = SkinModelImporter.Default.SupportedModelFileFormatsFilter; + if (MessageBox.Show("Import custom model project file? Your current work will be lost!", "", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1) == DialogResult.Yes && openFileDialog.ShowDialog() == DialogResult.OK) + { + SkinModelInfo modelInfo = SkinModelImporter.Default.Import(openFileDialog.FileName); + if (modelInfo is not null) + { + EditorValue.SetModelInfo(modelInfo); + LoadModelData(); + } + } + } + + private void cloneToolStripMenuItem_Click(object sender, EventArgs e) + { + if (skinPartListBox.SelectedItem is SkinBOX box) + { + SkinBOX clone = box; + renderer3D1.ModelData.Add(clone); + EditorValue.Model.AdditionalBoxes.Add(clone); + _skinPartListBindingSource.ResetBindings(false); + } + } + + private void deleteToolStripMenuItem_Click(object sender, EventArgs e) + { + if (skinPartListBox.SelectedItem is SkinBOX box) + { + renderer3D1.ModelData.Remove(box); + EditorValue.Model.AdditionalBoxes.Remove(box); + _skinPartListBindingSource.ResetBindings(false); + } + } + + private void CustomSkinEditor_FormClosing(object sender, FormClosingEventArgs e) + { + renderer3D1.Dispose(); + } + + private void outlineColorButton_Click(object sender, EventArgs e) + { + ColorDialog colorDialog = new ColorDialog(); + colorDialog.SolidColorOnly = true; + if (colorDialog.ShowDialog() == DialogResult.OK) + { + renderer3D1.GuideLineColor = colorDialog.Color; + skinPartListBox_SelectedIndexChanged(sender, e); + } + } + + private void renderer3D1_TextureChanging(object sender, Rendering.TextureChangingEventArgs e) + { + Image texture = e.NewTexture; + // Skins can only be a 1:1 ratio (base 64x64) or a 2:1 ratio (base 64x32) + if (Settings.Default.ValidateImageDimension && texture.Width != texture.Height && texture.Height != texture.Width / 2) + { + e.Cancel = true; + MessageBox.Show("The selected image does not suit a skin texture.", "Invalid image dimensions.", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + uvPictureBox.Image = EditorValue.Texture = texture; + textureSizeLabel.Text = $"{texture.Width}x{texture.Height}"; + } + + private void skinPartListBox_DoubleClick(object sender, EventArgs e) + { + if (skinPartListBox.SelectedItem is SkinBOX box) + { + var boxEditor = new BoxEditor(box, _allowInflate); + if (boxEditor.ShowDialog() == DialogResult.OK) + { + renderer3D1.ModelData[skinPartListBox.SelectedIndex] = boxEditor.Result; + _skinPartListBindingSource.ResetItem(skinPartListBox.SelectedIndex); + } + } + } + + // TODO: fixed outline rendering + private void skinPartListBox_SelectedIndexChanged(object sender, EventArgs e) + { + int scale = 1; + renderer3D1.SelectedIndices = skinPartListBox.SelectedIndices.Cast().ToArray(); + StringBuilder uv_sb = new StringBuilder(); + StringBuilder size_sb = new StringBuilder(); + StringBuilder pos_sb = new StringBuilder(); + foreach (SkinBOX b in skinPartListBox.SelectedItems.Cast()) + { + uv_sb.Append(b.UV); + uv_sb.Append(", "); + size_sb.Append(b.Size); + size_sb.Append(", "); + pos_sb.Append(b.Pos); + pos_sb.Append(", "); + } + + uvLabel.Text = $"UV: {uv_sb}"; + sizeLabel.Text = $"Size: {size_sb}"; + positionLabel.Text = $"Position: {pos_sb}"; + + // TODO: highlight all selected boxes + if (skinPartListBox.SelectedItem is SkinBOX box) + { + + Image uvArea = EditorValue.Texture.GetArea(Rectangle.Truncate(new RectangleF(box.UV.X, box.UV.Y, box.Size.X * 2 + box.Size.Z * 2, box.Size.Z + box.Size.Y))); + + Bitmap refImg = new Bitmap(1, 1); + + using (var g = Graphics.FromImage(refImg)) + { + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.DrawImage(uvArea, new Rectangle(0, 0, 1, 1)); + } + + Color avgColor = refImg.GetPixel(0, 0); + renderer3D1.HighlightlingColor = avgColor.Inversed(); + + Size scaleSize = new Size(EditorValue.Texture.Width * scale, EditorValue.Texture.Height * scale); + uvPictureBox.Image = new Bitmap(scaleSize.Width, scaleSize.Height); + using (Graphics g = Graphics.FromImage(uvPictureBox.Image)) + { + GraphicsPath graphicsPath = box.GetUVGraphicsPath(new System.Numerics.Vector2(scaleSize.Width * renderer3D1.TillingFactor.X, scaleSize.Height * renderer3D1.TillingFactor.Y)); + var brush = new SolidBrush(Color.FromArgb(127, avgColor.GreyScaled())); + g.ApplyConfig(_graphicsConfig); + g.DrawImage(EditorValue.Texture, new Rectangle(Point.Empty, scaleSize), new Rectangle(Point.Empty, EditorValue.Texture.Size), GraphicsUnit.Pixel); + g.FillPath(brush, graphicsPath); + } + uvPictureBox.Invalidate(); + } + } + + private void captureScreenshotButton_Click(object sender, EventArgs e) + { + using SaveFileDialog saveFileDialog = new SaveFileDialog() + { + Filter = "PNG|*.png" + }; + if (saveFileDialog.ShowDialog() == DialogResult.OK) + { + renderer3D1.GetThumbnail().Save(saveFileDialog.FileName, ImageFormat.Png); + } + } + + private void showArmorCheckbox_CheckedChanged(object sender, EventArgs e) + { + renderer3D1.ShowArmor = showArmorCheckbox.Checked; + } + + private void skinPartListBox_KeyUp(object sender, KeyEventArgs e) + { + switch (e.KeyCode) + { + case Keys.Delete: + deleteToolStripMenuItem_Click(sender, e); + break; + case Keys.Escape: + ClearSelection(); + break; + default: + break; + } + } + + private void ReloadOffsetList() + { + _skinOffsetListBindingSource = new BindingSource(renderer3D1.GetOffsets().ToArray(), null); + offsetListBox.DataSource = _skinOffsetListBindingSource; + _skinOffsetListBindingSource.ResetBindings(false); + } + + private void addOffsetToolStripMenuItem_Click(object sender, EventArgs e) + { + var offsets = renderer3D1.GetOffsets().Select(offset => offset.Type).ToList(); + string[] available = SkinPartOffset.ValidModelOffsetTypes.Where(s => !offsets.Contains(s)).ToArray(); + using ItemSelectionPopUp typeSelection = new ItemSelectionPopUp(available); + using NumericPrompt valuePrompt = new NumericPrompt(0f, -cOffsetMaximum, cOffsetMaximum); + valuePrompt.DecimalPlaces = 1; + valuePrompt.ValueStep = (decimal)0.1f; + if (typeSelection.ShowDialog() == DialogResult.OK && valuePrompt.ShowDialog() == DialogResult.OK) + { + renderer3D1.SetPartOffset(typeSelection.SelectedItem, (float)valuePrompt.SelectedValue); + ReloadOffsetList(); + } + } + + private void removeOffsetToolStripMenuItem_Click(object sender, EventArgs e) + { + if (offsetListBox.SelectedItem is not SkinPartOffset offset) + return; + renderer3D1.SetPartOffset(offset.Type, 0f); + ReloadOffsetList(); + } + + private void offsetListBox_DoubleClick(object sender, EventArgs e) + { + if (offsetListBox.SelectedItem is not SkinPartOffset offset) + return; + + using NumericPrompt valuePrompt = new NumericPrompt(offset.Value, -cOffsetMaximum, cOffsetMaximum); + valuePrompt.ToolTipText = "Set new Value for " + offset.Type; + valuePrompt.DecimalPlaces = 1; + valuePrompt.ValueStep = (decimal)0.1f; + if (valuePrompt.ShowDialog() == DialogResult.OK) + { + renderer3D1.SetPartOffset(offset.Type, (float)valuePrompt.SelectedValue); + ReloadOffsetList(); + } + } + + private void skinPartListBox_MouseClick(object sender, MouseEventArgs e) + { + if (skinPartListBox.IndexFromPoint(e.X, e.Y) == -1) + ClearSelection(); + } + + private void ClearSelection() + { + skinPartListBox.ClearSelected(); + uvPictureBox.Image = EditorValue.Texture; + } + + + private void centerSelectionCheckbox_CheckedChanged(object sender, EventArgs e) + { + renderer3D1.CenterOnSelect = centerSelectionCheckbox.Checked; + } + + private void generateUvTextureToolStripMenuItem_Click(object sender, EventArgs e) + { + if (skinPartListBox.SelectedItem is SkinBOX skinBox) + { + GenerateUVTextureMap(skinBox); + } + } + + private void renderSettingsButton_Click(object sender, EventArgs e) + { + using AppSettingsForm settingsForm = new AppSettingsForm("Render Settings", _settingsManager.GetSettings()); + settingsForm.ShowDialog(); + } + + private string SanitizeModelFilename(in string modelFilename) + { + return string.IsNullOrWhiteSpace(modelFilename) ? "template" : modelFilename.TrimEnd(new char[] { '\n', '\r' }).Replace(' ', '_'); + } + + private void exportTemplateButton_Click(object sender, EventArgs e) + { + Image templateTexture = Resources.classic_template; + SkinAnimMask templateAnimMask = SkinAnimMask.RESOLUTION_64x64; + + SaveFileDialog saveFileDialog = new SaveFileDialog(); + saveFileDialog.Title = "Save Template Model"; + saveFileDialog.Filter = SkinModelImporter.Default.SupportedModelFileFormatsFilter; + saveFileDialog.FileName = SanitizeModelFilename(EditorValue.MetaData.Name); + if (saveFileDialog.ShowDialog() == DialogResult.OK) + { + SkinModelInfo modelInfo = new SkinModelInfo(templateTexture, templateAnimMask, new SkinModel()); + SkinModelImporter.Default.Export(saveFileDialog.FileName, modelInfo); + } + } + + private void animEditorButton_Click(object sender, EventArgs e) + { + ProcessDialogKey(Keys.A); + } + } +} \ No newline at end of file diff --git a/PCK-Studio/Forms/Skins-And-Textures/generateModel.ja.resx b/PCK-Studio/Forms/Editor/CustomSkinEditor.ja.resx similarity index 100% rename from PCK-Studio/Forms/Skins-And-Textures/generateModel.ja.resx rename to PCK-Studio/Forms/Editor/CustomSkinEditor.ja.resx diff --git a/PCK-Studio/Forms/Skins-And-Textures/generateModel.resx b/PCK-Studio/Forms/Editor/CustomSkinEditor.resx similarity index 85% rename from PCK-Studio/Forms/Skins-And-Textures/generateModel.resx rename to PCK-Studio/Forms/Editor/CustomSkinEditor.resx index da2157ab..e76b2020 100644 --- a/PCK-Studio/Forms/Skins-And-Textures/generateModel.resx +++ b/PCK-Studio/Forms/Editor/CustomSkinEditor.resx @@ -117,175 +117,205 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + False + + + Left + + + Top, Right + - + True - - + NoControl - - 23, 459 + + 6, 47 - - 38, 13 + + 3, 3, 3, 3 - - 137 + + 33, 19 - - Parent - - - label6 - - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 19 - - - False - - - True - - - NoControl - - - 691, 357 - - - 44, 13 - - - 127 - - - Position - - - label5 - - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 28 - - - False - - - True - - - NoControl - - - 691, 259 - - - 27, 13 - - + 142 - + Size - - label3 + + sizeLabel - + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - $this + + groupBox1 - - 27 + + 0 - - False - - + + Top, Right + + True - + NoControl - - 654, 236 + + 6, 76 - - 22, 13 + + 3, 3, 3, 3 - + + 50, 19 + + + 127 + + + Position + + + positionLabel + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 1 + + + Top, Right + + + True + + + NoControl + + + 6, 21 + + + 3, 3, 3, 3 + + + 28, 19 + + 131 - + UV - - label7 + + uvLabel - + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + + groupBox1 + + + 2 + + + 19, 276 + + + 3, 3, 3, 0 + + + 161, 117 + + + 170 + + + Porperties + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + $this - - 22 + + 5 - - False - - - True + + Left - - NoControl + + 23, 249 - - 655, 56 + + 61, 21 - - 128, 13 + + 128 - - 113 + + Import - - Texture Mapping Preview + + importTextureButton - - labelTextureMappingPreview + + MetroFramework.Controls.MetroButton, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - + $this - - 16 + + 3 - + + Left + + + 90, 249 + + + 61, 21 + + + 114 + + + Export + + + exportTextureButton + + + MetroFramework.Controls.MetroButton, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 2 + + 17, 17 @@ -297,10 +327,10 @@ - 151, 26 + 201, 26 - Create + Add Cube @@ -318,7 +348,7 @@ - 151, 26 + 201, 26 Clone @@ -333,12 +363,12 @@ - 151, 26 + 201, 26 Delete - + iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAAFhSURBVFhH7ZY/ @@ -351,32 +381,29 @@ rkJggg== - - 151, 26 + + 201, 26 - - Change Color + + Re-generate UV Texture - - 152, 108 + + 202, 108 - - contextMenuStrip1 + + skinPartTabContextMenu - + System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Flat - - - NoControl + + Bottom, Right - 654, 676 + 627, 553 - 130, 22 + 250, 21 111 @@ -388,661 +415,106 @@ buttonDone - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + MetroFramework.Controls.MetroButton, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a $this - 26 - - - True - - - NoControl - - - 289, 647 - - - 33, 13 - - - 102 - - - View: - - - labelView - - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 25 - - - Flat - - - NoControl - - - 554, 642 - - - 89, 23 - - - 100 - - - Rotate Right - - - rotateRightBtn - - - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 24 - - - Flat - - - NoControl - - - 194, 643 - - - 89, 23 - - - 101 - - - Rotate Left - - - rotateLeftBtn - - - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 23 - - - 4, 22 - - - 3, 3, 3, 3 - - - 116, 132 - - - 1 - - - Armor - - - tabArmor - - - System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tabBody - - - 0 - - - 2 - - - Left - - - 58, 99 - - - 43, 20 - - - 85 - - - 0 - - - offsetArms - - - System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - myTablePanel2 - - - 0 - - - Left - - - True - - - NoControl - - - 3, 103 - - - 38, 13 - - - 90 - - - ARMS - - - label14 - - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - myTablePanel2 - - - 1 - - - Left - - - 58, 36 - - - 43, 20 - - - 83 - - - 0 - - - offsetBody - - - System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - myTablePanel2 - - - 2 - - - Left - - - 58, 67 - - - 43, 20 - - - 84 - - - 0 - - - offsetLegs - - - System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - myTablePanel2 - - - 3 - - - Left - - - True - - - NoControl - - - 3, 9 - - - 37, 13 - - - 87 - - - HEAD - - - label10 - - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - myTablePanel2 - - - 4 - - - Left - - - True - - - NoControl - - - 3, 71 - - - 35, 13 - - - 89 - - - LEGS - - - label13 - - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - myTablePanel2 - - - 5 - - - Left - - - 58, 5 - - - 43, 20 - - - 86 - - - 0 - - - offsetHead - - - System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - myTablePanel2 - - - 6 - - - Left - - - True - - - NoControl - - - 3, 40 - - - 37, 13 - - - 88 - - - BODY - - - label12 - - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - myTablePanel2 - - - 7 - - - Fill - - - 3, 3 - - - 4 - - - 110, 126 - - - 146 - - - myTablePanel2 - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tabPage1 - - - 0 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="offsetArms" Row="3" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="label14" Row="3" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="offsetBody" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="offsetLegs" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="label10" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="label13" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="offsetHead" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="label12" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,50,Percent,50" /><Rows Styles="Percent,25,Percent,25,Percent,25,Percent,25" /></TableLayoutSettings> - - - 4, 22 - - - 3, 3, 3, 3 - - - 116, 132 - - - 0 - - - Body - - - tabPage1 - - - System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tabBody - - - 1 - - - Fill - - - 3, 16 - - - 124, 158 - - - 144 - - - tabBody - - - System.Windows.Forms.TabControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - groupBox1 - - - 0 - - - 654, 459 - - - 130, 177 - - - 139 - - - OFFSETS - - - groupBox1 - - - System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - 21 - - HEAD + + Bottom, Left - - BODY + + 27, 553 - - ARM0 + + 75, 21 - - ARM1 + + 96 - - LEG0 + + Import Skin - - LEG1 + + importSkinButton - - 23, 484 - - - 114, 21 - - - 134 - - - comboParent - - - System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 18 - - - Flat - - - NoControl - - - 722, 206 - - - 61, 21 - - - 114 - - - EXPORT - - - buttonEXPORT - - - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 15 - - - Flat - - - NoControl - - - 655, 206 - - - 61, 21 - - - 128 - - - IMPORT - - - buttonIMPORT - - - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 20 - - - NoControl - - - 655, 72 - - - 128, 128 - - - Zoom - - - 112 - - - uvPictureBox - - - PckStudio.ToolboxItems.InterpolationPictureBox, PCK-Studio, Version=7.0.0.2, Culture=neutral, PublicKeyToken=null - - - $this - - - 17 - - - NoControl - - - 194, 56 - - - 449, 580 - - - StretchImage - - - 98 - - - displayBox - - - System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 13 - - - 23, 511 - - - 114, 21 - - - 146 - - - Load Template - - - buttonTemplate - - + MetroFramework.Controls.MetroButton, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - + $this - - 12 + + 20 + + + Bottom, Left + + + 105, 553 + + + 75, 21 + + + 97 + + + Export skin + + + exportSkinButton + + + MetroFramework.Controls.MetroButton, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 19 + + + Left + + + 19, 429 + + + 161, 21 + + + 145 + + + Set Outline Color + + + False + + + outlineColorButton + + + MetroFramework.Controls.MetroButton, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 10 + + + Left True - 23, 556 + 22, 399 140, 15 @@ -1063,338 +535,470 @@ $this - 11 - - - True - - - 23, 577 - - - 84, 15 - - - 148 - - - Guide Lines - - - checkGuide - - - MetroFramework.Controls.MetroCheckBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - $this - - - 10 - - - True - - - 23, 598 - - - 129, 15 - - - 149 - - - Show Armor Offsets - - - checkBoxArmor - - - MetroFramework.Controls.MetroCheckBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - $this - - 9 - - 658, 275 + + Left - - 119, 20 + + True - - 150 + + 23, 532 - - Center + + 89, 15 - - SizeXUpDown + + 149 - - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Show Armor - + + showArmorCheckbox + + + MetroFramework.Controls.MetroCheckBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + $this - + 8 - - 658, 301 + + Fill - - 119, 20 + + 0, 0 - - 151 + + 242, 446 - - Center + + 0 - - SizeYUpDown + + skinPartListBox - - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + System.Windows.Forms.ListBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + + skinPartsTabPage + + + 0 + + + Bottom, Right + + + 510, 553 + + + 111, 21 + + + 163 + + + Capture Screenshot + + + captureScreenshotButton + + + MetroFramework.Controls.MetroButton, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + $this - - 7 + + 17 - - 658, 327 + + Left - - 119, 20 + + True - - 152 + + 23, 511 - - Center + + 82, 15 - - SizeZUpDown + + 164 - - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Show Tools - + + showToolsCheckBox + + + MetroFramework.Controls.MetroCheckBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + $this - + 6 - - 682, 233 + + Top, Left, Right - - 43, 20 + + True - - 156 + + 364, 36 - - TextureXUpDown + + 73, 19 - - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 165 - + + nameLabel + + + skinNameLabel + + + MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + $this - - 5 + + 16 - - 731, 234 + + Top, Right - - 43, 20 + + 4, 38 - - 157 + + 242, 446 - - TextureYUpDown + + 0 - - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Parts - - $this + + skinPartsTabPage - - 4 + + System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 657, 425 + + metroTabControl1 - - 120, 20 + + 0 - - 160 + + 204, 17 + + + 152, 22 - - Center + + Add Offset - - PosZUpDown + + 152, 22 - - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Remove Offset - - $this + + 153, 48 - + + offsetTabContextMenu + + + MetroFramework.Controls.MetroContextMenu, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + Fill + + + 0, 0 + + + 242, 446 + + + 0 + + + offsetListBox + + + System.Windows.Forms.ListBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + skinOffsetsTabPage + + + 0 + + + 4, 38 + + + 242, 446 + + 1 - - 658, 399 + + Offset - - 119, 20 + + skinOffsetsTabPage - - 159 + + System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Center + + metroTabControl1 - - PosYUpDown + + 1 - - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 627, 59 - + + 250, 488 + + + 1 + + + metroTabControl1 + + + MetroFramework.Controls.MetroTabControl, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + $this - - 2 + + 15 - - 658, 373 + + Top, Bottom, Left, Right - - 119, 20 + + 190, 59 - - 158 + + 431, 484 - - Center + + 167 - - PosXUpDown + + renderer3D1 - - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + PckStudio.Rendering.SkinRenderer, PCK-Studio, Version=7.0.0.2, Culture=neutral, PublicKeyToken=null - + $this - - 3 + + 18 - - Part + + Left - - 40 + + Zoom - - X + + NoControl - - Center + + 23, 63 - - 30 + + 160, 160 - - Y + + Zoom - - Center + + 112 - - 30 + + uvPictureBox - - Z + + PckStudio.ToolboxItems.InterpolationPictureBox, PCK-Studio, Version=7.0.0.2, Culture=neutral, PublicKeyToken=null - - Center - - - 30 - - - Width - - - Center - - - Height - - - Center - - - Length - - - Center - - - U - - - Center - - - 25 - - - V - - - Center - - - 25 - - - 23, 59 - - - 165, 378 - - - 132 - - - listViewBoxes - - - System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - + $this - + + 11 + + + Left + + + True + + + 22, 465 + + + 108, 15 + + + 162 + + + Center on select + + + centerSelectionCheckbox + + + MetroFramework.Controls.MetroCheckBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 7 + + + Left + + + True + + + NoControl + + + 129, 226 + + + 51, 13 + + + 171 + + + (TexSize) + + + textureSizeLabel + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + Bottom, Right + + + 290, 553 + + + 94, 21 + + + 175 + + + Render settings + + + renderSettingsButton + + + MetroFramework.Controls.MetroButton, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + 14 + + Bottom, Left + + + 190, 553 + + + 94, 21 + + + 176 + + + Export template + + + exportTemplateButton + + + MetroFramework.Controls.MetroButton, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 13 + + + Bottom, Right + + + 390, 553 + + + 114, 21 + + + 177 + + + Open anim editor + + + animEditorButton + + + MetroFramework.Controls.MetroButton, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 12 + True @@ -1405,7 +1009,7 @@ 6, 13 - 806, 721 + 900, 600 @@ -3913,17 +3517,14 @@ AP//AAA= - - 1114, 1000 - - 753, 707 + 900, 600 CenterParent - Model Generator + Custom Skin Editor createToolStripMenuItem @@ -3943,70 +3544,28 @@ System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - changeColorToolStripMenuItem + + generateUvTextureToolStripMenuItem - + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Part + + addOffsetToolStripMenuItem - - System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - X + + removeOffsetToolStripMenuItem - - System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Y - - - System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Z - - - System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - _Width - - - System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - _Height - - - System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Length - - - System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - U - - - System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - V - - - System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - generateModel + CustomSkinEditor - MetroFramework.Forms.MetroForm, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + PckStudio.Internal.EditorForm`1[[PckStudio.Internal.Skin.Skin, PCK-Studio, Version=7.0.0.2, Culture=neutral, PublicKeyToken=null]], PCK-Studio, Version=7.0.0.2, Culture=neutral, PublicKeyToken=null \ No newline at end of file diff --git a/PCK-Studio/Forms/Editor/GameRuleFileEditor.Designer.cs b/PCK-Studio/Forms/Editor/GameRuleFileEditor.Designer.cs index d7e8c3de..aad86e7f 100644 --- a/PCK-Studio/Forms/Editor/GameRuleFileEditor.Designer.cs +++ b/PCK-Studio/Forms/Editor/GameRuleFileEditor.Designer.cs @@ -327,7 +327,6 @@ this.Style = MetroFramework.MetroColorStyle.Silver; this.Text = "GRF Editor"; this.Theme = MetroFramework.MetroThemeStyle.Dark; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.GameRuleFileEditor_FormClosing); this.Load += new System.EventHandler(this.OnLoad); this.MessageContextMenu.ResumeLayout(false); this.DetailContextMenu.ResumeLayout(false); diff --git a/PCK-Studio/Forms/Editor/GameRuleFileEditor.cs b/PCK-Studio/Forms/Editor/GameRuleFileEditor.cs index 0abbcf56..46afaa18 100644 --- a/PCK-Studio/Forms/Editor/GameRuleFileEditor.cs +++ b/PCK-Studio/Forms/Editor/GameRuleFileEditor.cs @@ -20,28 +20,21 @@ using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using PckStudio.Forms.Additional_Popups.Grf; -using PckStudio.Internal.Misc; using OMI.Formats.GameRule; -using PckStudio.Properties; using PckStudio.ToolboxItems; +using PckStudio.Controls; +using PckStudio.Interfaces; +using PckStudio.Internal; namespace PckStudio.Forms.Editor { - public partial class GameRuleFileEditor : MetroFramework.Forms.MetroForm + public partial class GameRuleFileEditor : EditorForm { - private GameRuleFile _file; - - public GameRuleFile Result => _file; - - private GameRuleFileEditor() + public GameRuleFileEditor(GameRuleFile gameRuleFile, ISaveContext saveContext) + : base(gameRuleFile, saveContext) { InitializeComponent(); - saveToolStripMenuItem.Visible = !Settings.Default.AutoSaveChanges; - } - - public GameRuleFileEditor(GameRuleFile gameRuleFile) : this() - { - _file = gameRuleFile; + saveToolStripMenuItem.Visible = !saveContext.AutoSave; } private void OnLoad(object sender, EventArgs e) @@ -52,7 +45,7 @@ namespace PckStudio.Forms.Editor private void LoadGameRuleTree(TreeNodeCollection root, GameRuleFile.GameRule parentRule) { - foreach (GameRuleFile.GameRule rule in parentRule.ChildRules) + foreach (GameRuleFile.GameRule rule in parentRule.GetRules()) { TreeNode node = new TreeNode(rule.Name); node.Tag = rule; @@ -64,16 +57,16 @@ namespace PckStudio.Forms.Editor private void ReloadGameRuleTree() { GrfTreeView.Nodes.Clear(); - if (_file is not null) + if (EditorValue is not null) { SetCompressionLevel(); - LoadGameRuleTree(GrfTreeView.Nodes, _file.Root); + LoadGameRuleTree(GrfTreeView.Nodes, EditorValue.Root); } } private void SetCompressionLevel() { - switch (_file.Header.CompressionLevel) + switch (EditorValue.Header.CompressionLevel) { case GameRuleFile.CompressionLevel.None: noneToolStripMenuItem.Checked = true; @@ -100,7 +93,7 @@ namespace PckStudio.Forms.Editor { GrfParametersTreeView.Nodes.Clear(); if (GrfTreeView.SelectedNode is TreeNode t && t.Tag is GameRuleFile.GameRule rule) - foreach (KeyValuePair param in rule.Parameters) + foreach (KeyValuePair param in rule.GetParameters()) { GrfParametersTreeView.Nodes.Add(new TreeNode($"{param.Key}: {param.Value}") { Tag = param}); } @@ -114,12 +107,12 @@ namespace PckStudio.Forms.Editor AddParameter prompt = new AddParameter(); if (prompt.ShowDialog(this) == DialogResult.OK) { - if (grfTag.Parameters.ContainsKey(prompt.ParameterName)) + if (grfTag.ContainsParameter(prompt.ParameterName)) { MessageBox.Show(this, "Can't add detail that already exists.", "Error"); return; } - grfTag.Parameters.Add(prompt.ParameterName, prompt.ParameterValue); + grfTag.AddParameter(prompt.ParameterName, prompt.ParameterValue); ReloadParameterTreeView(); } } @@ -128,7 +121,7 @@ namespace PckStudio.Forms.Editor { if (GrfTreeView.SelectedNode is TreeNode t && t.Tag is GameRuleFile.GameRule rule && GrfParametersTreeView.SelectedNode is TreeNode paramNode && paramNode.Tag is KeyValuePair pair && - rule.Parameters.ContainsKey(pair.Key) && rule.Parameters.Remove(pair.Key)) + rule.ContainsParameter(pair.Key) && rule.RemoveParameter(pair.Key)) { ReloadParameterTreeView(); return; @@ -150,7 +143,7 @@ namespace PckStudio.Forms.Editor AddParameter prompt = new AddParameter(param.Key, param.Value, false); if (prompt.ShowDialog(this) == DialogResult.OK) { - rule.Parameters[prompt.ParameterName] = prompt.ParameterValue; + rule.SetParameter(prompt.ParameterName, prompt.ParameterValue); ReloadParameterTreeView(); } } @@ -161,7 +154,7 @@ namespace PckStudio.Forms.Editor bool isValidNode = GrfTreeView.SelectedNode is TreeNode t && t.Tag is GameRuleFile.GameRule; GameRuleFile.GameRule parentRule = isValidNode ? GrfTreeView.SelectedNode.Tag as GameRuleFile.GameRule - : _file.Root; + : EditorValue.Root; TreeNodeCollection root = isValidNode ? GrfTreeView.SelectedNode.Nodes @@ -192,9 +185,9 @@ namespace PckStudio.Forms.Editor private bool RemoveTag(GameRuleFile.GameRule rule) { _ = rule.Parent ?? throw new ArgumentNullException(nameof(rule.Parent)); - foreach (GameRuleFile.GameRule subTag in rule.ChildRules.ToList()) + foreach (GameRuleFile.GameRule subTag in rule.GetRules().ToList()) return RemoveTag(subTag); - return rule.Parent.ChildRules.Remove(rule); + return rule.Parent.RemoveRule(rule); } private void GrfTreeView_KeyDown(object sender, KeyEventArgs e) @@ -205,11 +198,12 @@ namespace PckStudio.Forms.Editor private void saveToolStripMenuItem_Click(object sender, EventArgs e) { - if (_file.Header.unknownData[3] != 0) + if (EditorValue.Header.unknownData[3] != 0) { MessageBox.Show(this, "World grf saving is currently unsupported"); return; } + Save(); DialogResult = DialogResult.OK; MessageBox.Show("Saved!"); } @@ -222,51 +216,43 @@ namespace PckStudio.Forms.Editor private void noneToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - _file.Header.CompressionLevel = GameRuleFile.CompressionLevel.None; + EditorValue.Header.CompressionLevel = GameRuleFile.CompressionLevel.None; } private void compressedToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - _file.Header.CompressionLevel = GameRuleFile.CompressionLevel.Compressed; + EditorValue.Header.CompressionLevel = GameRuleFile.CompressionLevel.Compressed; } private void compressedRLEToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - _file.Header.CompressionLevel = GameRuleFile.CompressionLevel.CompressedRle; + EditorValue.Header.CompressionLevel = GameRuleFile.CompressionLevel.CompressedRle; } private void compressedRLECRCToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - _file.Header.CompressionLevel = GameRuleFile.CompressionLevel.CompressedRleCrc; + EditorValue.Header.CompressionLevel = GameRuleFile.CompressionLevel.CompressedRleCrc; } private void wiiUPSVitaToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - _file.Header.CompressionType = GameRuleFile.CompressionType.Zlib; + EditorValue.Header.CompressionType = GameRuleFile.CompressionType.Zlib; } private void pS3ToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - _file.Header.CompressionType = GameRuleFile.CompressionType.Deflate; + EditorValue.Header.CompressionType = GameRuleFile.CompressionType.Deflate; } private void xbox360ToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (sender is ToolStripRadioButtonMenuItem radioButton && radioButton.Checked) - _file.Header.CompressionType = GameRuleFile.CompressionType.XMem; - } - - private void GameRuleFileEditor_FormClosing(object sender, FormClosingEventArgs e) - { - if (Settings.Default.AutoSaveChanges) - { - saveToolStripMenuItem_Click(sender, EventArgs.Empty); - } + EditorValue.Header.CompressionType = GameRuleFile.CompressionType.XMem; } } } diff --git a/PCK-Studio/Forms/Editor/LOCEditor.Designer.cs b/PCK-Studio/Forms/Editor/LOCEditor.Designer.cs index 999fb412..e3fd7b1e 100644 --- a/PCK-Studio/Forms/Editor/LOCEditor.Designer.cs +++ b/PCK-Studio/Forms/Editor/LOCEditor.Designer.cs @@ -34,6 +34,7 @@ this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); this.addDisplayIDToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.deleteDisplayIDToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.copyIDToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.GridContextMenu = new MetroFramework.Controls.MetroContextMenu(this.components); this.addLanguageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.removeLanguageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -43,10 +44,10 @@ this.locSort = new System.Windows.Forms.TableLayoutPanel(); this.buttonReplaceAll = new System.Windows.Forms.Button(); this.dataGridViewLocEntryData = new System.Windows.Forms.DataGridView(); - this.textBoxReplaceAll = new System.Windows.Forms.TextBox(); - this.treeViewLocKeys = new System.Windows.Forms.TreeView(); this.Language = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.DisplayName = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.textBoxReplaceAll = new System.Windows.Forms.TextBox(); + this.treeViewLocKeys = new System.Windows.Forms.TreeView(); this.contextMenuStrip1.SuspendLayout(); this.GridContextMenu.SuspendLayout(); this.menuStrip.SuspendLayout(); @@ -58,7 +59,8 @@ // this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.addDisplayIDToolStripMenuItem, - this.deleteDisplayIDToolStripMenuItem}); + this.deleteDisplayIDToolStripMenuItem, + this.copyIDToolStripMenuItem}); this.contextMenuStrip1.Name = "contextMenuStrip1"; resources.ApplyResources(this.contextMenuStrip1, "contextMenuStrip1"); // @@ -74,6 +76,12 @@ resources.ApplyResources(this.deleteDisplayIDToolStripMenuItem, "deleteDisplayIDToolStripMenuItem"); this.deleteDisplayIDToolStripMenuItem.Click += new System.EventHandler(this.deleteDisplayIDToolStripMenuItem_Click); // + // copyIDToolStripMenuItem + // + this.copyIDToolStripMenuItem.Name = "copyIDToolStripMenuItem"; + resources.ApplyResources(this.copyIDToolStripMenuItem, "copyIDToolStripMenuItem"); + this.copyIDToolStripMenuItem.Click += new System.EventHandler(this.copyIDToolStripMenuItem_Click); + // // GridContextMenu // this.GridContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -162,6 +170,18 @@ this.dataGridViewLocEntryData.RowHeadersVisible = false; this.dataGridViewLocEntryData.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellEndEdit); // + // Language + // + this.Language.FillWeight = 15F; + resources.ApplyResources(this.Language, "Language"); + this.Language.Name = "Language"; + this.Language.ReadOnly = true; + // + // DisplayName + // + resources.ApplyResources(this.DisplayName, "DisplayName"); + this.DisplayName.Name = "DisplayName"; + // // textBoxReplaceAll // resources.ApplyResources(this.textBoxReplaceAll, "textBoxReplaceAll"); @@ -180,18 +200,6 @@ this.treeViewLocKeys.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeViewLocKeys_AfterSelect); this.treeViewLocKeys.KeyDown += new System.Windows.Forms.KeyEventHandler(this.treeView1_KeyDown); // - // Language - // - this.Language.FillWeight = 15F; - resources.ApplyResources(this.Language, "Language"); - this.Language.Name = "Language"; - this.Language.ReadOnly = true; - // - // DisplayName - // - resources.ApplyResources(this.DisplayName, "DisplayName"); - this.DisplayName.Name = "DisplayName"; - // // LOCEditor // resources.ApplyResources(this, "$this"); @@ -200,7 +208,6 @@ this.Name = "LOCEditor"; this.Style = MetroFramework.MetroColorStyle.Silver; this.Theme = MetroFramework.MetroThemeStyle.Dark; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.LOCEditor_FormClosing); this.Load += new System.EventHandler(this.LOCEditor_Load); this.contextMenuStrip1.ResumeLayout(false); this.GridContextMenu.ResumeLayout(false); @@ -231,5 +238,6 @@ private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem; private System.Windows.Forms.DataGridViewTextBoxColumn Language; private System.Windows.Forms.DataGridViewTextBoxColumn DisplayName; + private System.Windows.Forms.ToolStripMenuItem copyIDToolStripMenuItem; } } \ No newline at end of file diff --git a/PCK-Studio/Forms/Editor/LOCEditor.cs b/PCK-Studio/Forms/Editor/LOCEditor.cs index 28a13436..0937cedc 100644 --- a/PCK-Studio/Forms/Editor/LOCEditor.cs +++ b/PCK-Studio/Forms/Editor/LOCEditor.cs @@ -4,34 +4,27 @@ using System.Data; using System.Linq; using System.Collections.Generic; using System.Windows.Forms; -using MetroFramework.Forms; -using PckStudio.Internal.Misc; +using PckStudio.Internal; using PckStudio.Forms.Additional_Popups.Loc; using OMI.Formats.Languages; -using OMI.Workers.Language; -using OMI.Formats.Pck; -using PckStudio.Properties; -using PckStudio.Extensions; +using PckStudio.Interfaces; +using PckStudio.Controls; namespace PckStudio.Forms.Editor { - public partial class LOCEditor : MetroForm + public partial class LOCEditor : EditorForm { - LOCFile _currentLoc; - PckAsset _asset; - - public LOCEditor(PckAsset asset) + public LOCEditor(LOCFile locFile, ISaveContext context) + : base(locFile, context) { InitializeComponent(); - _asset = asset; - _currentLoc = asset.GetData(new LOCFileReader()); - saveToolStripMenuItem.Visible = !Settings.Default.AutoSaveChanges; + saveToolStripMenuItem.Visible = !context.AutoSave; } private void LOCEditor_Load(object sender, EventArgs e) { RPC.SetPresence("LOC Editor", "Editing localization File."); - foreach(string locKey in _currentLoc.LocKeys.Keys) + foreach(string locKey in EditorValue.LocKeys.Keys) treeViewLocKeys.Nodes.Add(locKey); } @@ -39,7 +32,7 @@ namespace PckStudio.Forms.Editor { TreeNode node = e.Node; if (node == null || - !_currentLoc.LocKeys.ContainsKey(node.Text)) + !EditorValue.LocKeys.ContainsKey(node.Text)) { MessageBox.Show(this, "Selected Node does not seem to be in the loc file"); return; @@ -53,7 +46,7 @@ namespace PckStudio.Forms.Editor { prompt.OKButtonText = "Add"; if (prompt.ShowDialog(this) == DialogResult.OK && - _currentLoc.AddLocKey(prompt.NewText, "")) + EditorValue.AddLocKey(prompt.NewText, "")) { treeViewLocKeys.Nodes.Add(prompt.NewText); } @@ -62,7 +55,7 @@ namespace PckStudio.Forms.Editor private void deleteDisplayIDToolStripMenuItem_Click(object sender, EventArgs e) { - if (treeViewLocKeys.SelectedNode is TreeNode t && _currentLoc.RemoveLocKey(t.Text)) + if (treeViewLocKeys.SelectedNode is TreeNode t && EditorValue.RemoveLocKey(t.Text)) { treeViewLocKeys.SelectedNode.Remove(); ReloadTranslationTable(); @@ -81,7 +74,7 @@ namespace PckStudio.Forms.Editor string locKey = treeViewLocKeys.SelectedNode.Text; string language = row.Cells[0].Value.ToString(); string value = row.Cells[1].Value.ToString(); - _currentLoc.SetLocEntry(locKey, language, value); + EditorValue.SetLocEntry(locKey, language, value); } private void treeView1_KeyDown(object sender, KeyEventArgs e) @@ -97,7 +90,7 @@ namespace PckStudio.Forms.Editor dataGridViewLocEntryData.Rows[i].Cells[1].Value = textBoxReplaceAll.Text; } - _currentLoc.SetLocEntry(treeViewLocKeys.SelectedNode.Text, textBoxReplaceAll.Text); + EditorValue.SetLocEntry(treeViewLocKeys.SelectedNode.Text, textBoxReplaceAll.Text); } private void ReloadTranslationTable() @@ -105,7 +98,7 @@ namespace PckStudio.Forms.Editor dataGridViewLocEntryData.Rows.Clear(); if (treeViewLocKeys.SelectedNode is null) return; - foreach (KeyValuePair locEntry in _currentLoc.GetLocEntries(treeViewLocKeys.SelectedNode.Text)) + foreach (KeyValuePair locEntry in EditorValue.GetLocEntries(treeViewLocKeys.SelectedNode.Text)) dataGridViewLocEntryData.Rows.Add(locEntry.Key, locEntry.Value); } @@ -113,7 +106,7 @@ namespace PckStudio.Forms.Editor { foreach (var lang in LOCFile.ValidLanguages) { - if (_currentLoc.Languages.Contains(lang)) + if (EditorValue.Languages.Contains(lang)) continue; yield return lang; } @@ -126,23 +119,20 @@ namespace PckStudio.Forms.Editor using (var dialog = new AddLanguage(avalibleLang)) if (dialog.ShowDialog(this) == DialogResult.OK) { - _currentLoc.AddLanguage(dialog.SelectedLanguage); + EditorValue.AddLanguage(dialog.SelectedLanguage); ReloadTranslationTable(); } } private void saveToolStripMenuItem_Click(object sender, EventArgs e) { - _asset.SetData(new LOCFileWriter(_currentLoc, 2)); + Save(); DialogResult = DialogResult.OK; } - private void LOCEditor_FormClosing(object sender, FormClosingEventArgs e) + private void copyIDToolStripMenuItem_Click(object sender, EventArgs e) { - if (Settings.Default.AutoSaveChanges) - { - saveToolStripMenuItem_Click(sender, EventArgs.Empty); - } + Clipboard.SetText(treeViewLocKeys.SelectedNode.Text); } } } diff --git a/PCK-Studio/Forms/Editor/LOCEditor.resx b/PCK-Studio/Forms/Editor/LOCEditor.resx index 73b694cc..63d454b7 100644 --- a/PCK-Studio/Forms/Editor/LOCEditor.resx +++ b/PCK-Studio/Forms/Editor/LOCEditor.resx @@ -133,8 +133,14 @@ Delete Display ID + + 162, 22 + + + Copy ID + - 163, 48 + 163, 70 contextMenuStrip1 @@ -2890,6 +2896,12 @@ System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + copyIDToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + addLanguageToolStripMenuItem @@ -2930,6 +2942,6 @@ LOCEditor - MetroFramework.Forms.MetroForm, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + PckStudio.Controls.EditorForm`1[[OMI.Formats.Languages.LOCFile, OMI Filetypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], PCK-Studio, Version=7.0.0.2, Culture=neutral, PublicKeyToken=null \ No newline at end of file diff --git a/PCK-Studio/Forms/Editor/MaterialsEditor.cs b/PCK-Studio/Forms/Editor/MaterialsEditor.cs index befbcb69..b1d17523 100644 --- a/PCK-Studio/Forms/Editor/MaterialsEditor.cs +++ b/PCK-Studio/Forms/Editor/MaterialsEditor.cs @@ -1,94 +1,72 @@ using System; using System.Collections.Generic; -using System.Drawing; -using System.Diagnostics; -using System.IO; using System.Linq; using System.Windows.Forms; -using MetroFramework.Forms; -using Newtonsoft.Json.Linq; -using OMI.Formats.Pck; using OMI.Formats.Material; -using OMI.Workers.Material; -using PckStudio.Internal; -using PckStudio.Extensions; -using PckStudio.Internal.Json; +using PckStudio.Controls; +using PckStudio.Core.Extensions; +using PckStudio.Core.Json; using PckStudio.Internal.App; +using PckStudio.Interfaces; +using PckStudio.Json; namespace PckStudio.Forms.Editor { - public partial class MaterialsEditor : MetroForm + // Materials File Format research by PhoenixARC + public partial class MaterialsEditor : EditorForm { - // Materials File Format research by PhoenixARC - private readonly PckAsset _asset; - MaterialContainer _materialFile; - private readonly List MaterialData = Entities.BehaviourInfos; - private bool showInvalidEntries; + private bool ShowInvalidEntries; - //Holds invalid entries so they can be added back to the material file on save should the user decide to hide them - List hiddenInvalidEntries = new List(); + public MaterialsEditor(MaterialContainer materials, ISaveContext saveContext) + : base(materials, saveContext) + { + InitializeComponent(); + if (EditorValue.HasInvalidEntries()) + { + DialogResult dr = MessageBox.Show(this, "Unsupported entities were found in this file. Would you like to display them?", "Invalid data found", MessageBoxButtons.YesNo); - void SetUpTree() + ShowInvalidEntries = dr == DialogResult.Yes; + } + + treeView1.ImageList = new ImageList(); + ApplicationScope.EntityImages.ToList().ForEach(treeView1.ImageList.Images.Add); + treeView1.ImageList.ColorDepth = ColorDepth.Depth32Bit; + UpdateTreeview(); + } + + void UpdateTreeview() { treeView1.BeginUpdate(); treeView1.Nodes.Clear(); - foreach (MaterialContainer.Material entry in _materialFile) + foreach (MaterialContainer.Material entry in EditorValue) { - TreeNode EntryNode = new TreeNode(entry.Name); + TreeNode entryNode = new TreeNode(entry.Name); + // index for invalid entry + entryNode.ImageIndex = 127; + entryNode.SelectedImageIndex = 127; + entryNode.Tag = entry; EntityInfo material = MaterialData.Find(m => m.InternalName == entry.Name); - if(material != null) - { - EntryNode.Text = material.DisplayName; - EntryNode.ImageIndex = MaterialData.IndexOf(material); - EntryNode.Tag = entry; - } + // check for invalid material entry - else + if (material is null) { - EntryNode.ImageIndex = 127; // icon for invalid entry - EntryNode.Text += " (Invalid)"; - - if (!showInvalidEntries) - { - hiddenInvalidEntries.Add(entry); + entryNode.Text += " (Invalid)"; + if (!ShowInvalidEntries) continue; - } - } - - EntryNode.SelectedImageIndex = EntryNode.ImageIndex; - - treeView1.Nodes.Add(EntryNode); + } + else + { + entryNode.Text = material.DisplayName; + entryNode.SelectedImageIndex = entryNode.ImageIndex = MaterialData.IndexOf(material); + } + treeView1.Nodes.Add(entryNode); } treeView1.EndUpdate(); } - public MaterialsEditor(PckAsset asset) - { - InitializeComponent(); - _asset = asset; - - using (var stream = new MemoryStream(asset.Data)) - { - var reader = new MaterialFileReader(); - _materialFile = reader.FromStream(stream); - - if (_materialFile.HasInvalidEntries()) - { - DialogResult dr = MessageBox.Show(this, "Unsupported entities were found in this file. Would you like to display them?", "Invalid data found", MessageBoxButtons.YesNo); - - showInvalidEntries = dr == DialogResult.Yes; - } - - treeView1.ImageList = new ImageList(); - ApplicationScope.EntityImages.ToList().ForEach(treeView1.ImageList.Images.Add); - treeView1.ImageList.ColorDepth = ColorDepth.Depth32Bit; - SetUpTree(); - } - } - private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) { if (e.Node == null) @@ -106,10 +84,11 @@ namespace PckStudio.Forms.Editor } private void removeToolStripMenuItem_Click(object sender, EventArgs e) { - if (treeView1.SelectedNode == null) - return; - - treeView1.SelectedNode.Remove(); + if (treeView1?.SelectedNode?.Tag is MaterialContainer.Material material) + { + EditorValue.Remove(material); + UpdateTreeview(); + } } private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) @@ -125,23 +104,7 @@ namespace PckStudio.Forms.Editor private void saveToolStripMenuItem1_Click(object sender, EventArgs e) { - _materialFile = new MaterialContainer(); - - foreach (TreeNode node in treeView1.Nodes) - { - if(node.Tag is MaterialContainer.Material entry) - { - _materialFile.Add(entry); - } - } - - foreach (MaterialContainer.Material mat in hiddenInvalidEntries) - { - _materialFile.Add(mat); - } - - _asset.SetData(new MaterialFileWriter(_materialFile)); - + Save(); DialogResult = DialogResult.OK; } @@ -153,21 +116,15 @@ namespace PckStudio.Forms.Editor { if (string.IsNullOrEmpty(diag.SelectedEntity)) return; - if (_materialFile.FindAll(mat => mat.Name == diag.SelectedEntity).Count() > 0) + if (EditorValue.FindAll(mat => mat.Name == diag.SelectedEntity).Count() > 0) { - MessageBox.Show(this, "You cannot have two entries for one entity. Please use the \"Add New Position Override\" tool to add multiple overrides for entities", "Error", MessageBoxButtons.OK); + MessageBox.Show(this, "You cannot have two entries for one entity.", "Error", MessageBoxButtons.OK); return; } var newEntry = new MaterialContainer.Material(diag.SelectedEntity, "entity_alphatest"); - TreeNode newEntryNode = new TreeNode(newEntry.Name); - newEntryNode.Tag = newEntry; - - EntityInfo material = MaterialData.Find(m => m.InternalName == newEntry.Name); - newEntryNode.Text = material.DisplayName; - newEntryNode.ImageIndex = MaterialData.IndexOf(material); - newEntryNode.SelectedImageIndex = newEntryNode.ImageIndex; - treeView1.Nodes.Add(newEntryNode); + EditorValue.Add(newEntry); + UpdateTreeview(); } } diff --git a/PCK-Studio/Forms/Editor/ModelEditor.Designer.cs b/PCK-Studio/Forms/Editor/ModelEditor.Designer.cs new file mode 100644 index 00000000..1f4b62a3 --- /dev/null +++ b/PCK-Studio/Forms/Editor/ModelEditor.Designer.cs @@ -0,0 +1,254 @@ +namespace PckStudio.Forms.Editor +{ + partial class ModelEditor + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.modelTreeView = new System.Windows.Forms.TreeView(); + this.modelContextMenu = new MetroFramework.Controls.MetroContextMenu(this.components); + this.exportToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.removeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.importToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.viewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.showModelBoundsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.modelViewport = new PckStudio.Rendering.ModelRenderer(); + this.namedTexturesTreeView = new System.Windows.Forms.TreeView(); + this.textureImageList = new System.Windows.Forms.ImageList(this.components); + this.modelContextMenu.SuspendLayout(); + this.menuStrip1.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // modelTreeView + // + this.modelTreeView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.modelTreeView.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20))))); + this.modelTreeView.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.modelTreeView.ContextMenuStrip = this.modelContextMenu; + this.modelTreeView.ForeColor = System.Drawing.SystemColors.Window; + this.modelTreeView.HideSelection = false; + this.modelTreeView.Location = new System.Drawing.Point(3, 3); + this.modelTreeView.Name = "modelTreeView"; + this.modelTreeView.PathSeparator = "."; + this.tableLayoutPanel1.SetRowSpan(this.modelTreeView, 2); + this.modelTreeView.Size = new System.Drawing.Size(287, 440); + this.modelTreeView.TabIndex = 0; + this.modelTreeView.BeforeSelect += new System.Windows.Forms.TreeViewCancelEventHandler(this.modelTreeView_BeforeSelect); + // + // modelContextMenu + // + this.modelContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.exportToolStripMenuItem, + this.editToolStripMenuItem, + this.removeToolStripMenuItem}); + this.modelContextMenu.Name = "modelContextMenu"; + this.modelContextMenu.Size = new System.Drawing.Size(118, 70); + // + // exportToolStripMenuItem + // + this.exportToolStripMenuItem.Name = "exportToolStripMenuItem"; + this.exportToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.exportToolStripMenuItem.Text = "Export"; + this.exportToolStripMenuItem.Click += new System.EventHandler(this.exportToolStripMenuItem_Click); + // + // editToolStripMenuItem + // + this.editToolStripMenuItem.Name = "editToolStripMenuItem"; + this.editToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.editToolStripMenuItem.Text = "Edit"; + this.editToolStripMenuItem.Visible = false; + // + // removeToolStripMenuItem + // + this.removeToolStripMenuItem.Name = "removeToolStripMenuItem"; + this.removeToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.removeToolStripMenuItem.Text = "Remove"; + this.removeToolStripMenuItem.Visible = false; + this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeToolStripMenuItem_Click); + // + // menuStrip1 + // + this.menuStrip1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20))))); + this.menuStrip1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.fileToolStripMenuItem, + this.viewToolStripMenuItem}); + this.menuStrip1.Location = new System.Drawing.Point(20, 60); + this.menuStrip1.Name = "menuStrip1"; + this.menuStrip1.Size = new System.Drawing.Size(660, 24); + this.menuStrip1.TabIndex = 1; + this.menuStrip1.Text = "menuStrip1"; + // + // fileToolStripMenuItem + // + this.fileToolStripMenuItem.BackColor = System.Drawing.Color.Transparent; + this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.importToolStripMenuItem1, + this.saveToolStripMenuItem}); + this.fileToolStripMenuItem.ForeColor = System.Drawing.SystemColors.Control; + this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); + this.fileToolStripMenuItem.Text = "File"; + // + // importToolStripMenuItem1 + // + this.importToolStripMenuItem1.Name = "importToolStripMenuItem1"; + this.importToolStripMenuItem1.Size = new System.Drawing.Size(110, 22); + this.importToolStripMenuItem1.Text = "Import"; + this.importToolStripMenuItem1.Click += new System.EventHandler(this.importToolStripMenuItem1_Click); + // + // saveToolStripMenuItem + // + this.saveToolStripMenuItem.Name = "saveToolStripMenuItem"; + this.saveToolStripMenuItem.Size = new System.Drawing.Size(110, 22); + this.saveToolStripMenuItem.Text = "Save"; + this.saveToolStripMenuItem.Click += new System.EventHandler(this.saveToolStripMenuItem_Click); + // + // viewToolStripMenuItem + // + this.viewToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.showModelBoundsToolStripMenuItem}); + this.viewToolStripMenuItem.ForeColor = System.Drawing.SystemColors.Control; + this.viewToolStripMenuItem.Name = "viewToolStripMenuItem"; + this.viewToolStripMenuItem.Size = new System.Drawing.Size(44, 20); + this.viewToolStripMenuItem.Text = "View"; + // + // showModelBoundsToolStripMenuItem + // + this.showModelBoundsToolStripMenuItem.CheckOnClick = true; + this.showModelBoundsToolStripMenuItem.Name = "showModelBoundsToolStripMenuItem"; + this.showModelBoundsToolStripMenuItem.Size = new System.Drawing.Size(183, 22); + this.showModelBoundsToolStripMenuItem.Text = "Show Model Bounds"; + this.showModelBoundsToolStripMenuItem.CheckedChanged += new System.EventHandler(this.showModelBoundsToolStripMenuItem_CheckedChanged); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.modelViewport, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.namedTexturesTreeView, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.modelTreeView, 0, 0); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(20, 84); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 60F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 40F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(660, 446); + this.tableLayoutPanel1.TabIndex = 2; + // + // modelViewport + // + this.modelViewport.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(30)))), ((int)(((byte)(30))))); + this.modelViewport.Dock = System.Windows.Forms.DockStyle.Fill; + this.modelViewport.Location = new System.Drawing.Point(296, 3); + this.modelViewport.MouseSensetivity = 0.01F; + this.modelViewport.Name = "modelViewport"; + this.modelViewport.RefreshRate = 120; + this.modelViewport.RenderModelBounds = false; + this.modelViewport.Size = new System.Drawing.Size(361, 261); + this.modelViewport.TabIndex = 1; + this.modelViewport.VSync = true; + // + // namedTexturesTreeView + // + this.namedTexturesTreeView.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20))))); + this.namedTexturesTreeView.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.namedTexturesTreeView.Dock = System.Windows.Forms.DockStyle.Fill; + this.namedTexturesTreeView.ForeColor = System.Drawing.SystemColors.Window; + this.namedTexturesTreeView.FullRowSelect = true; + this.namedTexturesTreeView.HideSelection = false; + this.namedTexturesTreeView.ImageIndex = 0; + this.namedTexturesTreeView.ImageList = this.textureImageList; + this.namedTexturesTreeView.Location = new System.Drawing.Point(296, 270); + this.namedTexturesTreeView.Name = "namedTexturesTreeView"; + this.namedTexturesTreeView.SelectedImageIndex = 0; + this.namedTexturesTreeView.ShowLines = false; + this.namedTexturesTreeView.ShowPlusMinus = false; + this.namedTexturesTreeView.ShowRootLines = false; + this.namedTexturesTreeView.Size = new System.Drawing.Size(361, 173); + this.namedTexturesTreeView.TabIndex = 2; + this.namedTexturesTreeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.namedTexturesTreeView_AfterSelect); + // + // textureImageList + // + this.textureImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit; + this.textureImageList.ImageSize = new System.Drawing.Size(36, 36); + this.textureImageList.TransparentColor = System.Drawing.Color.Transparent; + // + // ModelEditor + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(700, 550); + this.Controls.Add(this.tableLayoutPanel1); + this.Controls.Add(this.menuStrip1); + this.MainMenuStrip = this.menuStrip1; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.MinimumSize = new System.Drawing.Size(700, 550); + this.Name = "ModelEditor"; + this.Style = MetroFramework.MetroColorStyle.Silver; + this.Text = "Model Editor"; + this.Theme = MetroFramework.MetroThemeStyle.Dark; + this.modelContextMenu.ResumeLayout(false); + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); + this.tableLayoutPanel1.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TreeView modelTreeView; + private MetroFramework.Controls.MetroContextMenu modelContextMenu; + private System.Windows.Forms.ToolStripMenuItem exportToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem removeToolStripMenuItem; + private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem importToolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private Rendering.ModelRenderer modelViewport; + private System.Windows.Forms.TreeView namedTexturesTreeView; + private System.Windows.Forms.ImageList textureImageList; + private System.Windows.Forms.ToolStripMenuItem viewToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem showModelBoundsToolStripMenuItem; + } +} \ No newline at end of file diff --git a/PCK-Studio/Forms/Editor/ModelEditor.cs b/PCK-Studio/Forms/Editor/ModelEditor.cs new file mode 100644 index 00000000..124fa073 --- /dev/null +++ b/PCK-Studio/Forms/Editor/ModelEditor.cs @@ -0,0 +1,342 @@ +using System; +using System.IO; +using System.Data; +using System.Linq; +using System.Drawing; +using System.Diagnostics; +using System.Windows.Forms; +using System.Collections.Generic; + +using OMI.Formats.Model; +using MetroFramework.Forms; + +using PckStudio.Controls; +using PckStudio.Interfaces; +using OMI.Formats.Material; +using PckStudio.ModelSupport; +using PckStudio.Core.Json; +using PckStudio.Core.Extensions; +using PckStudio.Internal.App; +using PckStudio.Core; + +namespace PckStudio.Forms.Editor +{ + public partial class ModelEditor : EditorForm + { + private readonly ITryGetSet _textures; + private readonly ITryGet _tryGetEntityMaterial; + + public ModelEditor(ModelContainer models, ISaveContext saveContext, ITryGetSet tryGetSetTextures, ITryGet tryGetEntityMaterial) + : base(models, saveContext) + { + InitializeComponent(); + _textures = tryGetSetTextures; + _tryGetEntityMaterial = tryGetEntityMaterial; + modelTreeView.ImageList = new ImageList + { + ColorDepth = ColorDepth.Depth32Bit, + ImageSize = new Size(32, 32) + }; + modelTreeView.ImageList.Images.AddRange(ApplicationScope.EntityImages); + } + + private const int InvalidImageIndex = 127; + // TODO: move to json file. -miku + private static Dictionary ModelImageIndex = new Dictionary() + { + ["bat"] = 3, + ["blaze"] = 4, + ["boat"] = 5, + ["cat"] = 6, + ["spider"] = 107, + ["chicken"] = 9, + ["cod"] = 10, + ["cow"] = 12, + ["creeper"] = 13, + ["creeper_head"] = 13, + ["dolphin"] = 14, + ["horse.v2"] = 110, + ["guardian"] = 109, + ["bed"] = 108, + ["dragon"] = 21, + ["dragon_head"] = 21, + ["enderman"] = 23, + ["ghast"] = 34, + ["irongolem"] = 40, + ["lavaslime"] = 46, + ["llama"] = 44, + ["llamaspit"] = 45, + ["minecart"] = 47, + ["ocelot"] = 50, + ["parrot"] = 53, + ["phantom"] = 54, + ["pig"] = 55, + ["pigzombie"] = 94, + ["polarbear"] = 57, + ["rabbit"] = 60, + ["sheep"] = 63, + ["sheep.sheared"] = 113, + ["shulker"] = 64, + ["silverfish"] = 66, + ["skeleton"] = 67, + ["skeleton_head"] = 67, + ["skeleton.stray"] = 77, + ["skeleton.wither"] = 89, + ["skeleton_wither_head"] = 89, + ["slime"] = 115, + ["slime.armor"] = 116, + + ["snowgolem"] = 71, + ["squid"] = 76, + ["trident"] = 80, + ["turtle"] = 82, + ["villager"] = 84, + ["villager.witch"] = 87, + + ["vex"] = 83, + ["evoker"] = 25, + ["vindicator"] = 25, + ["witherBoss"] = 88, + ["wolf"] = 91, + ["zombie"] = 92, + ["zombie_head"] = 92, + ["zombie.husk"] = 39, + ["zombie.villager"] = 95, + ["zombie.drowned"] = 17, + ["endermite"] = 24, + ["pufferfish.small"] = 111, + ["pufferfish.mid"] = 112, + ["pufferfish.large"] = 59, + ["salmon"] = 62, + ["stray.armor"] = 118, + ["stray_armor"] = 118, + ["tropicalfish_a"] = 81, + ["tropicalfish_b"] = 81, + ["mooshroom"] = 48, + ["witherBoss.armor"] = 90, + + // 1.14 models + ["panda"] = 52, + ["ravager"] = 61, + ["pillager"] = 56, + ["villager_v2"] = 101, + ["zombie.villager_v2"] = 102, + }; + + private static int GetModelImageIndex(string name) => ModelImageIndex.TryGetValue(name, out int index) ? index : InvalidImageIndex; + + private class ModelNode : TreeNode + { + private Model _model; + public Model Model => _model; + + private ModelNode(Model model) + : base(model.Name) + { + _model = model; + ImageIndex = GetModelImageIndex(model.Name); + SelectedImageIndex = GetModelImageIndex(model.Name); + Nodes.AddRange(GetModelPartNodes(_model.GetParts()).ToArray()); + } + private static IEnumerable GetModelPartNodes(IEnumerable parts) => parts.Select(ModelPartNode.Create); + + internal static ModelNode Create(Model model) => new ModelNode(model); + } + + private class ModelPartNode : TreeNode + { + private ModelPart _part; + + public ModelPart Part => _part; + + private ModelPartNode(ModelPart part) + : base($"{part.Name} Pivot:{part.Translation * -1} Rot:{part.Rotation + part.AdditionalRotation} ") + { + _part = part; + ImageIndex = 126; + SelectedImageIndex = 126; + Nodes.AddRange(GetModelBoxNodes(part.GetBoxes()).ToArray()); + } + private static IEnumerable GetModelBoxNodes(IEnumerable boxes) => boxes.Select(ModelBoxNode.Create); + + internal static ModelPartNode Create(ModelPart part) => new ModelPartNode(part); + } + + private class ModelBoxNode : TreeNode + { + private ModelBox _modelBox; + public ModelBox Box => _modelBox; + private ModelBoxNode(ModelBox modelBox) + : base($"Box: pos:{modelBox.Position} size:{modelBox.Size}") + { + ImageIndex = 126; + SelectedImageIndex = 126; + _modelBox = modelBox; + } + + internal static ModelBoxNode Create(ModelBox modelBox) => new ModelBoxNode(modelBox); + } + + private class NamedTextureTreeNode : TreeNode + { + private readonly NamedData _namedTexture; + + public NamedTextureTreeNode(NamedData namedTexture) + : base(namedTexture.Name) + { + Tag = namedTexture; + _namedTexture = namedTexture; + } + + public Image GetTexture() => _namedTexture.Value; + } + + private void LoadModels() + { + modelTreeView.Nodes.Clear(); + modelTreeView.Nodes.AddRange(EditorValue.Select(ModelNode.Create).ToArray()); + } + + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + LoadModels(); + } + + private void exportToolStripMenuItem_Click(object sender, EventArgs e) + { + if (modelTreeView.SelectedNode is ModelNode modelNode) + { + Model model = modelNode.Model; + Debug.Write(model.Name + "; "); + Debug.WriteLine(model.TextureSize); + + GameModelImporter.Default.ExportSettings.CreateModelOutline = + MessageBox.Show( + $"Do you wish to have all model parts contained in a group called '{model.Name}'?", + "Group model parts", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes; + + using SaveFileDialog openFileDialog = new SaveFileDialog(); + openFileDialog.FileName = model.Name; + openFileDialog.Filter = GameModelImporter.Default.SupportedModelFileFormatsFilter; + + if (openFileDialog.ShowDialog(this) == DialogResult.OK) + { + IEnumerable> textures = GetModelTextures(model.Name); + var modelInfo = new GameModelInfo(model, textures); + GameModelImporter.Default.Export(openFileDialog.FileName, modelInfo); + } + } + } + + private void modelTreeView_BeforeSelect(object sender, TreeViewCancelEventArgs e) + { + exportToolStripMenuItem.Visible = e.Node is ModelNode; + removeToolStripMenuItem.Visible = e.Node is ModelNode; + editToolStripMenuItem.Visible = e.Node is ModelBoxNode; + //removeToolStripMenuItem.Visible = e.Node is ModelPartNode || e.Node is ModelBoxNode; + if (e.Node is ModelNode modelNode && modelNode.Model.Name != modelViewport.CurrentModelName) + { + NamedData[] textures = GetModelTextures(modelNode.Model.Name).ToArray(); + + textureImageList.Images.Clear(); + namedTexturesTreeView.Nodes.Clear(); + + foreach ((int i, NamedData item) in textures.enumerate()) + { + textureImageList.Images.Add(item.Value); + namedTexturesTreeView.Nodes.Add(new NamedTextureTreeNode(item) { ImageIndex = i, SelectedImageIndex = i }); + } + if (textures.Length != 0) + modelViewport.Texture = textures[0].Value; + + modelViewport.LoadModel(modelNode.Model); + if (GameModelImporter.ModelMetaData.TryGetValue(modelNode.Model.Name, out JsonModelMetaData modelMetaData) && !string.IsNullOrEmpty(modelMetaData.MaterialName) && + _tryGetEntityMaterial.TryGet(modelMetaData.MaterialName, out MaterialContainer.Material entityMaterial) || + _tryGetEntityMaterial.TryGet(modelNode.Model.Name, out entityMaterial)) + { + modelViewport.SetModelMaterial(entityMaterial); + } + modelViewport.ResetCamera(); + } + if (e.Node is ModelPartNode modelPartNode && modelPartNode.Parent is ModelNode parentNode && modelViewport.CurrentModelName == parentNode.Model.Name) + { + modelViewport.Highlight(modelPartNode.Part); + } + + if (e.Node is ModelBoxNode modelBoxNode && modelBoxNode.Parent is ModelPartNode parentPartNode && parentPartNode.Parent is ModelNode parentNode1 && + modelViewport.CurrentModelName == parentNode1.Model.Name) + { + modelViewport.Highlight(modelBoxNode.Box, parentPartNode.Part); + } + } + + private IEnumerable> GetModelTextures(string modelName) + { + if (!GameModelImporter.ModelMetaData.ContainsKey(modelName) || GameModelImporter.ModelMetaData[modelName]?.TextureLocations?.Length <= 0) + yield break; + foreach (var textureLocation in GameModelImporter.ModelMetaData[modelName].TextureLocations) + { + if (_textures.TryGet(textureLocation, out Image img)) + yield return new NamedData(Path.GetFileName(textureLocation), img); + } + yield break; + } + + private void importToolStripMenuItem1_Click(object sender, EventArgs e) + { + OpenFileDialog fileDialog = new OpenFileDialog(); + fileDialog.Filter = GameModelImporter.Default.SupportedModelFileFormatsFilter; + fileDialog.Title = "Select model"; + if (fileDialog.ShowDialog() == DialogResult.OK) + { + GameModelInfo modelInfo = GameModelImporter.Default.Import(fileDialog.FileName); + if (modelInfo is null) + { + MessageBox.Show("Import failed.", ProductName); + return; + } + + //if (models.Version < modelInfo.ModelVersion) + //{ + // MessageBox.Show("Model container version does not match with the model version.", ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); + // return; + //} + + EditorValue.SetModel(modelInfo.Model); + + foreach (NamedData texture in modelInfo.Textures) + { + _textures.TrySet(texture.Name, texture.Value); + } + + LoadModels(); + } + } + + private void saveToolStripMenuItem_Click(object sender, EventArgs e) + { + Save(); + DialogResult = DialogResult.OK; + } + + private void namedTexturesTreeView_AfterSelect(object sender, TreeViewEventArgs e) + { + if (namedTexturesTreeView.SelectedNode is NamedTextureTreeNode namedTextureNode) + modelViewport.Texture = namedTextureNode.GetTexture(); + } + + private void showModelBoundsToolStripMenuItem_CheckedChanged(object sender, EventArgs e) + { + modelViewport.RenderModelBounds = showModelBoundsToolStripMenuItem.Checked; + } + + private void removeToolStripMenuItem_Click(object sender, EventArgs e) + { + if (modelTreeView?.SelectedNode is ModelNode modelNode && EditorValue.Remove(modelNode.Model)) + { + modelNode.Remove(); + } + } + } +} diff --git a/PCK-Studio/Forms/Editor/ModelEditor.resx b/PCK-Studio/Forms/Editor/ModelEditor.resx new file mode 100644 index 00000000..3a001628 --- /dev/null +++ b/PCK-Studio/Forms/Editor/ModelEditor.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 178, 17 + + + 293, 17 + + \ No newline at end of file diff --git a/PCK-Studio/Forms/Editor/TextureAtlasEditor.Designer.cs b/PCK-Studio/Forms/Editor/TextureAtlasEditor.Designer.cs index a9e55d22..4d888daa 100644 --- a/PCK-Studio/Forms/Editor/TextureAtlasEditor.Designer.cs +++ b/PCK-Studio/Forms/Editor/TextureAtlasEditor.Designer.cs @@ -36,6 +36,7 @@ this.viewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.applyColorMaskToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.playAnimationsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.allowGroupsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.originalPictureBox = new PckStudio.ToolboxItems.InterpolationPictureBox(); this.selectTilePictureBox = new PckStudio.ToolboxItems.AnimationPictureBox(); @@ -102,7 +103,8 @@ // this.viewToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.applyColorMaskToolStripMenuItem, - this.playAnimationsToolStripMenuItem}); + this.playAnimationsToolStripMenuItem, + this.allowGroupsToolStripMenuItem}); this.viewToolStripMenuItem.ForeColor = System.Drawing.SystemColors.Control; this.viewToolStripMenuItem.Name = "viewToolStripMenuItem"; this.viewToolStripMenuItem.Size = new System.Drawing.Size(44, 20); @@ -114,7 +116,7 @@ this.applyColorMaskToolStripMenuItem.CheckOnClick = true; this.applyColorMaskToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; this.applyColorMaskToolStripMenuItem.Name = "applyColorMaskToolStripMenuItem"; - this.applyColorMaskToolStripMenuItem.Size = new System.Drawing.Size(168, 22); + this.applyColorMaskToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.applyColorMaskToolStripMenuItem.Text = "Apply Color Mask"; this.applyColorMaskToolStripMenuItem.CheckedChanged += new System.EventHandler(this.applyColorMaskToolStripMenuItem_CheckedChanged); // @@ -124,10 +126,20 @@ this.playAnimationsToolStripMenuItem.CheckOnClick = true; this.playAnimationsToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; this.playAnimationsToolStripMenuItem.Name = "playAnimationsToolStripMenuItem"; - this.playAnimationsToolStripMenuItem.Size = new System.Drawing.Size(168, 22); + this.playAnimationsToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.playAnimationsToolStripMenuItem.Text = "Play Animations"; this.playAnimationsToolStripMenuItem.CheckedChanged += new System.EventHandler(this.playAnimationsToolStripMenuItem_CheckedChanged); // + // allowGroupsToolStripMenuItem + // + this.allowGroupsToolStripMenuItem.Checked = true; + this.allowGroupsToolStripMenuItem.CheckOnClick = true; + this.allowGroupsToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + this.allowGroupsToolStripMenuItem.Name = "allowGroupsToolStripMenuItem"; + this.allowGroupsToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.allowGroupsToolStripMenuItem.Text = "Allow Groups"; + this.allowGroupsToolStripMenuItem.CheckedChanged += new System.EventHandler(this.allowGroupsToolStripMenuItem_CheckedChanged); + // // tableLayoutPanel1 // this.tableLayoutPanel1.AutoSize = true; @@ -171,6 +183,7 @@ | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.originalPictureBox.BackColor = System.Drawing.Color.Transparent; + this.originalPictureBox.BackgroundInterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default; this.originalPictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; this.originalPictureBox.Location = new System.Drawing.Point(217, 3); this.originalPictureBox.Name = "originalPictureBox"; @@ -187,8 +200,9 @@ | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.selectTilePictureBox.BackColor = System.Drawing.Color.Transparent; + this.selectTilePictureBox.BackgroundInterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default; this.selectTilePictureBox.BlendColor = System.Drawing.Color.White; - this.selectTilePictureBox.BlendMode = PckStudio.Extensions.BlendMode.Multiply; + this.selectTilePictureBox.BlendMode = PckStudio.Core.Extensions.BlendMode.Multiply; this.tableLayoutPanel1.SetColumnSpan(this.selectTilePictureBox, 2); this.selectTilePictureBox.Image = null; this.selectTilePictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; @@ -384,5 +398,6 @@ private MetroFramework.Controls.MetroTrackBar colorSlider; private MetroFramework.Controls.MetroLabel colorSliderLabel; private MetroFramework.Controls.MetroButton extractButton; + private System.Windows.Forms.ToolStripMenuItem allowGroupsToolStripMenuItem; } } \ No newline at end of file diff --git a/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs b/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs index 58865e18..e10c37b1 100644 --- a/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs +++ b/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs @@ -21,53 +21,61 @@ using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; -using System.IO; using System.Linq; using System.Windows.Forms; -using MetroFramework.Forms; - using OMI.Formats.Color; -using OMI.Formats.Pck; using OMI.Workers.Color; - -using PckStudio.Extensions; +using PckStudio.Controls; +using PckStudio.Core; +using PckStudio.Core.Extensions; +using PckStudio.Core.Json; +using PckStudio.Interfaces; using PckStudio.Internal; -using PckStudio.Internal.Deserializer; -using PckStudio.Internal.Json; -using PckStudio.Internal.Serializer; +using PckStudio.Properties; namespace PckStudio.Forms.Editor { - internal partial class TextureAtlasEditor : MetroForm + internal partial class TextureAtlasEditor : EditorForm { - private Image _atlasTexture; - public Image FinalTexture => DialogResult == DialogResult.OK ? _atlasTexture : null; - - private readonly PckFile _pckFile; - private ColorContainer _colourTable; - private readonly Size _tileAreaSize; - private readonly int _rowCount; - private readonly int _columnCount; - private readonly ResourceLocation _resourceLocation; - private readonly List _tiles; + private readonly ITryGet _tryGetAnimation; + private readonly ITryGet> _tryGetAnimationSaveContext; + private readonly ColorContainer _colourTable; + private readonly ResourceCategory _resourceLocationCategory; + private readonly Atlas _atlas; private AtlasTile _selectedTile; - // the "parent" tile for tiles that share name; i.e. parts of water_flow - private AtlasTile dataTile; - private sealed class AtlasTile + public TextureAtlasEditor(Atlas atlas, ISaveContext saveContext, ResourceLocation resourceLocation, ColorContainer colorContainer, + ITryGet tryGetAnimation, ITryGet> tryGetAnimationSaveContext) + : base(atlas, saveContext) { - internal readonly int Index; - internal readonly Rectangle Area; - internal readonly JsonTileInfo Tile; - internal readonly Image Texture; + InitializeComponent(); - public AtlasTile(int index, Rectangle area, JsonTileInfo tile, Image texture) + _ = atlas ?? throw new ArgumentNullException(nameof(atlas)); + _ = resourceLocation ?? throw new ArgumentNullException(nameof(resourceLocation)); + _atlas = atlas; + Text = _atlas.Name; + originalPictureBox.Image = atlas; + + _colourTable = colorContainer ?? AppResourceManager.Default.GetData(Resources.tu69colours, new COLFileReader()); + _tryGetAnimation = tryGetAnimation; + _tryGetAnimationSaveContext = tryGetAnimationSaveContext; + _resourceLocationCategory = resourceLocation.Category; + + SelectedIndex = 0; + + animationButton.Enabled = + _resourceLocationCategory == ResourceCategory.BlockAtlas || + _resourceLocationCategory == ResourceCategory.ItemAtlas; + + // this is directly based on Java's source code for handling enchanted hits + // the particle is assigned a random grayscale color between roughly 154 and 230 + // since critical hit is the only particle with this distinction, we just need to check the atlas type + if (_resourceLocationCategory == ResourceCategory.ParticleAtlas) { - Index = index; - Area = area; - Tile = tile; - Texture = texture; + colorSlider.Minimum = 154; + colorSlider.Maximum = 230; + colorSlider.Value = colorSlider.Maximum; } } @@ -76,11 +84,11 @@ namespace PckStudio.Forms.Editor set { if (value < 0) { - value += _tiles.Count; + value += _atlas.TileCount; } - else if (value >= _tiles.Count) + else if (value >= _atlas.TileCount) { - value -= _tiles.Count; + value -= _atlas.TileCount; } SetImageDisplayed(value); } @@ -94,104 +102,18 @@ namespace PckStudio.Forms.Editor PixelOffsetMode = PixelOffsetMode.HighQuality }; - public TextureAtlasEditor(PckFile pckFile, ResourceLocation resourceLocation, Image atlas) - { - InitializeComponent(); - - if (!AcquireColorTable(pckFile)) - { - MessageBox.Show("Failed to acquire color information", "Acquire failure", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); - return; - } - - _atlasTexture = atlas; - _tileAreaSize = resourceLocation.GetTileArea(atlas.Size); - _pckFile = pckFile; - _rowCount = atlas.Width / _tileAreaSize.Width; - _columnCount = atlas.Height / _tileAreaSize.Height; - _resourceLocation = resourceLocation; - List tileInfos = resourceLocation.Category switch - { - ResourceCategory.BlockAtlas => Tiles.BlockTileInfos, - ResourceCategory.ItemAtlas => Tiles.ItemTileInfos, - ResourceCategory.ParticleAtlas => Tiles.ParticleTileInfos, - ResourceCategory.MapIconAtlas => Tiles.MapIconTileInfos, - ResourceCategory.AdditionalMapIconsAtlas => Tiles.AdditionalMapIconTileInfos, - ResourceCategory.MoonPhaseAtlas => Tiles.MoonPhaseTileInfos, - ResourceCategory.ExperienceOrbAtlas => Tiles.ExperienceOrbTileInfos, - ResourceCategory.ExplosionAtlas => Tiles.ExplosionTileInfos, - ResourceCategory.PaintingAtlas => Tiles.PaintingTileInfos, - ResourceCategory.BannerAtlas => Tiles.BannerTileInfos, - _ => null, - }; - - originalPictureBox.Image = new Bitmap(atlas); - - IEnumerable images = atlas.Split(_tileAreaSize, _imageLayout); - - AtlasTile MakeTile((int index, Image value) p) - { - int i = p.index; - JsonTileInfo tileInfo = tileInfos.IndexInRange(i) ? tileInfos[i] : null; - - Rectangle atlasArea = GetAtlasArea(i, tileInfo?.TileWidth ?? 1, tileInfo?.TileHeight ?? 1, _rowCount, _columnCount, _tileAreaSize, _imageLayout); - - // get texture for tiles that are not 1x1 tiles - Point selectedPoint = GetSelectedPoint(i, _rowCount, _columnCount, _imageLayout); - - var textureLocation = new Point(selectedPoint.X * _tileAreaSize.Width, selectedPoint.Y * _tileAreaSize.Height); - var textureSize = new Size(tileInfos[i].TileWidth * _tileAreaSize.Width, tileInfos[i].TileHeight * _tileAreaSize.Height); - var textureArea = new Rectangle(textureLocation, textureSize); - - Image texture = tileInfos.IndexInRange(i) ? atlas.GetArea(textureArea) : p.value; - return new AtlasTile(i, atlasArea, tileInfo, texture); - } - - _tiles = new List(images.enumerate().Select(MakeTile)); - - SelectedIndex = 0; - - animationButton.Enabled = - _resourceLocation.Category == ResourceCategory.BlockAtlas || - _resourceLocation.Category == ResourceCategory.ItemAtlas; - - // this is directly based on Java's source code for handling enchanted hits - // the particle is assigned a random grayscale color between roughly 154 and 230 - // since critical hit is the only particle with this distinction, we just need to check the atlas type - if (_resourceLocation.Category == ResourceCategory.ParticleAtlas) - { - colorSlider.Minimum = 154; - colorSlider.Maximum = 230; - colorSlider.Value = colorSlider.Maximum; - } - } - - private bool AcquireColorTable(PckFile pckFile) - { - if (pckFile.TryGetAsset("colours.col", PckAssetType.ColourTableFile, out PckAsset colAsset) && - colAsset.Size > 0) - { - using var ms = new MemoryStream(colAsset.Data); - var reader = new COLFileReader(); - _colourTable = reader.FromStream(ms); - return true; - } - _colourTable = null; - return false; - } - private void UpdateAtlasDisplay() { using (var g = Graphics.FromImage(originalPictureBox.Image)) { g.ApplyConfig(_graphicsConfig); g.Clear(Color.Transparent); - g.DrawImage(_atlasTexture, 0, 0, _atlasTexture.Width, _atlasTexture.Height); + Image image = EditorValue; + g.DrawImage(image, 0, 0, image.Width, image.Height); SolidBrush brush = new SolidBrush(Color.FromArgb(127, Color.White)); - g.FillRectangle(brush, _selectedTile.Area); + g.FillRectangle(brush, allowGroupsToolStripMenuItem.Checked ? _atlas.GetTileArea(_selectedTile) : _selectedTile.GetArea(_atlas.TileSize)); } - originalPictureBox.Invalidate(); } @@ -213,51 +135,42 @@ namespace PckStudio.Forms.Editor selectTilePictureBox.Stop(); selectTilePictureBox.UseBlendColor = false; selectTilePictureBox.Image = null; + _selectedTile = _atlas[index]; - if (_tiles is null || !_tiles.IndexInRange(index) || (_selectedTile = _tiles[index]) is null) + if (_selectedTile is null) return; UpdateAtlasDisplay(); - dataTile = _selectedTile; - if (string.IsNullOrEmpty(dataTile.Tile.DisplayName) && !string.IsNullOrEmpty(dataTile.Tile.InternalName)) - { - dataTile = _tiles.Find(t => t.Tile.InternalName == _selectedTile.Tile.InternalName); - } - - selectTilePictureBox.Image = dataTile.Texture; + selectTilePictureBox.Image = _selectedTile.Texture; selectTilePictureBox.BlendColor = GetBlendColor(); selectTilePictureBox.UseBlendColor = applyColorMaskToolStripMenuItem.Checked; - tileNameLabel.Text = $"{dataTile.Tile.DisplayName}"; - internalTileNameLabel.Text = $"{dataTile.Tile.InternalName}"; + JsonTileInfo tileInfo = _selectedTile.GetUserDataOfType(); - if (animationButton.Enabled) + tileNameLabel.Text = $"{tileInfo?.DisplayName}"; + internalTileNameLabel.Text = $"{tileInfo?.InternalName}"; + if (animationButton.Enabled && (_resourceLocationCategory == ResourceCategory.ItemAtlas || _resourceLocationCategory == ResourceCategory.BlockAtlas)) { - PckAsset animationAsset; - ResourceCategory animationResourceCategory = _resourceLocation.Category == ResourceCategory.ItemAtlas ? ResourceCategory.ItemAnimation : ResourceCategory.BlockAnimation; + ResourceCategory animationResourceCategory = _resourceLocationCategory == ResourceCategory.ItemAtlas ? ResourceCategory.ItemAnimation : ResourceCategory.BlockAnimation; - string animationAssetPath = $"{ResourceLocation.GetPathFromCategory(animationResourceCategory)}/{dataTile.Tile.InternalName}"; - bool hasAnimation = - _pckFile.TryGetValue($"{animationAssetPath}.png", PckAssetType.TextureFile, out animationAsset) || - _pckFile.TryGetValue($"{animationAssetPath}.tga", PckAssetType.TextureFile, out animationAsset); + string animationAssetPath = $"{ResourceLocation.GetPathFromCategory(animationResourceCategory)}/{tileInfo.InternalName}"; + bool hasAnimation = _tryGetAnimation.TryGet(animationAssetPath, out Animation animation); animationButton.Text = hasAnimation ? "Edit Animation" : "Create Animation"; - // asset size check dont have to be done here the deserializer handles it. -Miku if (playAnimationsToolStripMenuItem.Checked && hasAnimation) { - Animation animation = animationAsset.GetDeserializedData(AnimationDeserializer.DefaultDeserializer); - selectTilePictureBox.Image = animation.CreateAnimationImage(); + selectTilePictureBox.Image = animation.CreateAnimationImage(selectTilePictureBox.BlendColor); selectTilePictureBox.Start(); } } - setColorButton.Enabled = dataTile.Tile.AllowCustomColour; + setColorButton.Enabled = tileInfo.AllowCustomColour; - variantComboBox.Enabled = variantComboBox.Visible = dataTile.Tile.HasColourEntry && dataTile.Tile.ColourEntry?.Variants?.Length > 1; + variantComboBox.Enabled = variantComboBox.Visible = tileInfo.HasColourEntry && tileInfo.ColourEntry?.Variants?.Length > 1; if (variantComboBox.Enabled) { - if (dataTile.Tile.ColourEntry.IsWaterColour) + if (tileInfo.ColourEntry.IsWaterColour) { foreach (ColorContainer.WaterColor col in _colourTable.WaterColors) { @@ -267,11 +180,34 @@ namespace PckStudio.Forms.Editor } // TODO: only add variants that are available in the color table - variantComboBox.Items.AddRange(dataTile.Tile.ColourEntry.Variants); + variantComboBox.Items.AddRange(tileInfo.ColourEntry.Variants.Where(colorName => _colourTable.Colors.Any(c => c.Name == colorName) || _colourTable.WaterColors.Any(c => c.Name == colorName)).ToArray()); if (variantComboBox.Items.Count > 0) variantComboBox.SelectedIndex = 0; } + + if (_selectedTile.IsPartOfGroup && allowGroupsToolStripMenuItem.Checked) + { + AtlasGroup group = _selectedTile.GetGroup(); + tileNameLabel.Text = $"{group.Name}"; + internalTileNameLabel.Text = string.Empty; + if (group.IsAnimation()) + { + animationButton.Enabled = true; + animationButton.Text = "Edit as Animation"; + if (playAnimationsToolStripMenuItem.Checked) + { + selectTilePictureBox.UseBlendColor = false; + selectTilePictureBox.Image = _atlas.GetAnimationFromGroup(group).CreateAnimationImage(selectTilePictureBox.BlendColor); + selectTilePictureBox.Start(); + return; + } + } + if (group.IsLargeTile()) + { + selectTilePictureBox.Image = _atlas.GetTileTexture(_selectedTile); + } + } } private static int GetSelectedImageIndex( @@ -344,6 +280,7 @@ namespace PckStudio.Forms.Editor default: break; } + Debug.WriteLine(result); return GetSelectedIndex(result.X, result.Y, rowCount, columnCount, imageLayout); } @@ -357,47 +294,31 @@ namespace PckStudio.Forms.Editor }; } - private static Rectangle GetAtlasArea(int index, int tileWidth, int tileHeight, int rowCount, int columnCount, Size size, ImageLayoutDirection imageLayout) - { - Point p = GetSelectedPoint(index, rowCount, columnCount, imageLayout); - var ap = new Point(p.X * size.Width, p.Y * size.Height); - return new Rectangle(ap, new Size(size.Width * tileWidth, size.Height * tileHeight)); - } - - private static Point GetSelectedPoint(int index, int rowCount, int columnCount, ImageLayoutDirection imageLayout) - { - int y = Math.DivRem(index, rowCount, out int x); - if (imageLayout == ImageLayoutDirection.Vertical) - x = Math.DivRem(index, columnCount, out y); - return new Point(x, y); - } - private void SetTile(Image texture) { - if (texture.Size != _tileAreaSize) - texture = texture.Resize(_tileAreaSize, _graphicsConfig); - - using (var g = Graphics.FromImage(_atlasTexture)) + if (_selectedTile.IsPartOfGroup) { - g.ApplyConfig(_graphicsConfig); - g.Fill(dataTile.Area, Color.Transparent); - g.DrawImage(texture, dataTile.Area); + AtlasGroup group = _selectedTile.GetGroup(); + _atlas.SetGroup(group, texture); + selectTilePictureBox.Image = _atlas.GetTileTexture(_selectedTile); + UpdateAtlasDisplay(); + return; } - AtlasTile tile = _selectedTile != dataTile ? dataTile : _selectedTile; - _tiles[tile.Index] = new AtlasTile(tile.Index, tile.Area, tile.Tile, texture); + if (texture.Size != _atlas.TileSize) + texture = texture.Resize(_atlas.TileSize, _graphicsConfig); + + _selectedTile.Texture = texture; selectTilePictureBox.Image = texture; UpdateAtlasDisplay(); } private Color GetBlendColor() { - if (dataTile.Tile.HasColourEntry && dataTile.Tile.ColourEntry is not null) + if (_selectedTile.TryGetUserDataOfType(out JsonTileInfo tileInfo) && tileInfo.HasColourEntry) { - Color col = FindBlendColorByKey(dataTile.Tile.ColourEntry.DefaultName); - return col; + return FindBlendColorByKey(tileInfo.ColourEntry.DefaultName); } - return Color.White; } @@ -413,7 +334,7 @@ namespace PckStudio.Forms.Editor var final_color = Color.FromArgb(colorSlider.Value, colorSlider.Value, colorSlider.Value); // Enchanted hits are modified critical hit particles - if (dataTile.Tile.InternalName == "enchanted_hit") + if (_selectedTile.TryGetUserDataOfType(out JsonTileInfo tileInfo) && tileInfo.InternalName == "enchanted_hit") { // This is directly based on Java's source code for handling enchanted hits // it just multiplies the red by 0.3 and green by .8 of the color assigned to the critical hit particle @@ -428,28 +349,36 @@ namespace PckStudio.Forms.Editor if (colorKey == "experience_orb" || colorKey == "critical_hit") return GetSpecificBlendColor(colorKey); - if (dataTile.Tile.HasColourEntry && dataTile.Tile.ColourEntry is not null) + if (!_selectedTile.TryGetUserDataOfType(out JsonTileInfo tileInfo) || !tileInfo.HasColourEntry) { - // basic way to check for classic water colors - if(!dataTile.Tile.ColourEntry.IsWaterColour || colorKey.StartsWith("Water_")) + Debug.WriteLine("Could not find: " + colorKey); + return Color.White; + } + + // basic way to check for classic water colors + if (!tileInfo.ColourEntry.IsWaterColour || colorKey.StartsWith("Water_")) + { + if (_colourTable.Colors.FirstOrDefault(entry => entry.Name == colorKey) is ColorContainer.Color color) { - if (_colourTable.Colors.FirstOrDefault(entry => entry.Name == colorKey) is ColorContainer.Color color) - { - return color.ColorPallette; - } - } - else if (_colourTable.WaterColors.FirstOrDefault(entry => entry.Name == colorKey) is ColorContainer.WaterColor waterColor) - { - return waterColor.SurfaceColor; + return color.ColorPallette; } } + else if (_colourTable.WaterColors.FirstOrDefault(entry => entry.Name == colorKey) is ColorContainer.WaterColor waterColor) + { + return waterColor.SurfaceColor; + } Debug.WriteLine("Could not find: " + colorKey); return Color.White; } + // TODO(null): check for large tile and get skip length protected override bool ProcessDialogKey(Keys keyData) { + int up = -_atlas.Rows; + int down = _atlas.Rows; + int left = -1; + int right = 1; switch (keyData) { case Keys.R: @@ -457,16 +386,16 @@ namespace PckStudio.Forms.Editor SelectedIndex = _selectedTile.Index; return true; case Keys.Left: - SelectedIndex = _selectedTile.Index - 1; + SelectedIndex = _selectedTile.Index + left; return true; case Keys.Right: - SelectedIndex = _selectedTile.Index + 1; + SelectedIndex = _selectedTile.Index + right; return true; case Keys.Up: - SelectedIndex = _selectedTile.Index - _rowCount; + SelectedIndex = _selectedTile.Index + up; return true; case Keys.Down: - SelectedIndex = _selectedTile.Index + _rowCount; + SelectedIndex = _selectedTile.Index + down; return true; } @@ -482,8 +411,8 @@ namespace PckStudio.Forms.Editor int index = GetSelectedImageIndex( originalPictureBox.Size, - _atlasTexture.Size, - _tileAreaSize, + ((Image)_atlas).Size, + _atlas.TileSize, e.Location, originalPictureBox.SizeMode, _imageLayout); @@ -504,28 +433,43 @@ namespace PckStudio.Forms.Editor if (fileDialog.ShowDialog(this) == DialogResult.OK) { - var img = Image.FromFile(fileDialog.FileName); + Image img = Image.FromFile(fileDialog.FileName).ReleaseFromFile(); SetTile(img); } } private void saveToolStripMenuItem_Click(object sender, EventArgs e) { + Save(); DialogResult = DialogResult.OK; } private void animationButton_Click(object sender, EventArgs e) { - ResourceCategory animationResourceCategory = _resourceLocation.Category == ResourceCategory.ItemAtlas ? ResourceCategory.ItemAnimation : ResourceCategory.BlockAnimation; - string animationAssetPath = $"{ResourceLocation.GetPathFromCategory(animationResourceCategory)}/{_selectedTile.Tile.InternalName}.png"; - PckAsset asset = _pckFile.GetOrCreate(animationAssetPath, PckAssetType.TextureFile); + if (_selectedTile.IsPartOfGroup) + { + AtlasGroup group = _selectedTile.GetGroup(); + Animation anim = _atlas.GetAnimationFromGroup(group); + ISaveContext saveContext = new DelegatedSaveContext(false, (animation) => + { + //! TODO(null): Test for functionallity + _atlas.SetGroupTilesFromAnimation(group, animation); + }); + var aEditor = new AnimationEditor(anim, saveContext, group.Name, false); + aEditor.ShowDialog(this); + return; + } + JsonTileInfo tileInfo = _selectedTile.GetUserDataOfType(); + ResourceCategory animationResourceCategory = _resourceLocationCategory == ResourceCategory.ItemAtlas ? ResourceCategory.ItemAnimation : ResourceCategory.BlockAnimation; + string animationAssetPath = $"{ResourceLocation.GetPathFromCategory(animationResourceCategory)}/{tileInfo.InternalName}"; + bool hasAnimation = _tryGetAnimation.TryGet(animationAssetPath, out Animation animation); + bool isValidAnimationSaveContext = _tryGetAnimationSaveContext.TryGet(animationAssetPath, out ISaveContext animationSaveContext); - Animation animation = asset.GetDeserializedData(AnimationDeserializer.DefaultDeserializer); + Debug.Assert(isValidAnimationSaveContext, "Couldn't get valid animation save context."); - var animationEditor = new AnimationEditor(animation, _selectedTile.Tile.DisplayName); + var animationEditor = new AnimationEditor(hasAnimation ? animation : Animation.CreateEmpty(), animationSaveContext, tileInfo.DisplayName); if (animationEditor.ShowDialog(this) == DialogResult.OK) { - asset.SetSerializedData(animationEditor.Result, AnimationSerializer.DefaultSerializer); // so animations can automatically update upon saving SelectedIndex = _selectedTile.Index; } @@ -533,25 +477,44 @@ namespace PckStudio.Forms.Editor private void extractTileToolStripMenuItem_Click(object sender, EventArgs e) { + string filename = GetSanitizedFilename(); SaveFileDialog saveFileDialog = new SaveFileDialog() { Filter = "Tile Texture|*.png", - FileName = _selectedTile.Tile.InternalName + FileName = filename }; if (saveFileDialog.ShowDialog(this) == DialogResult.OK) { - dataTile.Texture.Save(saveFileDialog.FileName, ImageFormat.Png); + _atlas.GetTileTexture(_selectedTile).Save(saveFileDialog.FileName, ImageFormat.Png); + //Process.Start("explorer.exe", $"{saveFileDialog.FileName}"); } } + private string GetSanitizedFilename() + { + if (_selectedTile.IsPartOfGroup) + { + AtlasGroup group = _selectedTile.GetGroup(); + return group.Name.Replace(' ', '_').Trim().ToLower(); + } + if (_selectedTile.TryGetUserDataOfType(out JsonTileInfo tileInfo) && !string.IsNullOrWhiteSpace(tileInfo.InternalName)) + return tileInfo.InternalName; + return "tile"; + } + private void variantComboBox_SelectedIndexChanged(object sender, EventArgs e) { - if (dataTile.Tile.ColourEntry is not null && variantComboBox.SelectedItem is not null) + if (_selectedTile.TryGetUserDataOfType(out JsonTileInfo tileInfo) && variantComboBox.SelectedItem is not null) { string colorKey = variantComboBox.SelectedItem.ToString(); - - selectTilePictureBox.BlendColor = FindBlendColorByKey(colorKey); - selectTilePictureBox.Image = dataTile.Texture; + Color blendColor = FindBlendColorByKey(colorKey); + if (_selectedTile.IsPartOfGroup && _selectedTile.GetGroup().IsAnimation()) + { + selectTilePictureBox.Image = _atlas.GetAnimationFromGroup(_selectedTile.GetGroup()).CreateAnimationImage(blendColor); + selectTilePictureBox.Start(); + return; + } + selectTilePictureBox.BlendColor = blendColor; } } @@ -573,35 +536,18 @@ namespace PckStudio.Forms.Editor private void setColorButton_Click(object sender, EventArgs e) { - ColorDialog colorPick = new ColorDialog(); - colorPick.AllowFullOpen = true; - colorPick.AnyColor = true; - colorPick.SolidColorOnly = true; + ColorDialog colorPick = new ColorDialog + { + AllowFullOpen = true, + AnyColor = true, + SolidColorOnly = true, + CustomColors = GameConstants.DyeColors.Select(ColorExtensions.ToBGR).ToArray() + }; - //Debug.Assert(Color.FromArgb(0xf9fffe).ToBGR() == 0xfefff9); // White - //Debug.Assert(Color.FromArgb(0xf9801d).ToBGR() == 0x1d80f9); // Orange - //Debug.Assert(Color.FromArgb(0xc74ebd).ToBGR() == 0xbd4ec7); // Magenta - //Debug.Assert(Color.FromArgb(0x3ab3da).ToBGR() == 0xdab33a); // Light Blue - //Debug.Assert(Color.FromArgb(0xfed83d).ToBGR() == 0x3dd8fe); // Yellow - //Debug.Assert(Color.FromArgb(0x80c71f).ToBGR() == 0x1fc780); // Lime - //Debug.Assert(Color.FromArgb(0xf38baa).ToBGR() == 0xaa8bf3); // Pink - //Debug.Assert(Color.FromArgb(0x474f52).ToBGR() == 0x524f47); // Gray - //Debug.Assert(Color.FromArgb(0x9d9d97).ToBGR() == 0x979d9d); // Light Gray - //Debug.Assert(Color.FromArgb(0x169c9c).ToBGR() == 0x9c9c16); // Cyan - //Debug.Assert(Color.FromArgb(0x8932b8).ToBGR() == 0xb83289); // Purple - //Debug.Assert(Color.FromArgb(0x3c44aa).ToBGR() == 0xaa443c); // Blue - //Debug.Assert(Color.FromArgb(0x835432).ToBGR() == 0x325483); // Brown - //Debug.Assert(Color.FromArgb(0x5e7c16).ToBGR() == 0x167c5e); // Green - //Debug.Assert(Color.FromArgb(0xb02e26).ToBGR() == 0x262eb0); // Red - //Debug.Assert(Color.FromArgb(0x1d1d21).ToBGR() == 0x211d1d); // Black - - colorPick.CustomColors = GameConstants.DyeColors.Select(c => c.ToBGR()).ToArray(); - if (colorPick.ShowDialog(this) != DialogResult.OK) return; selectTilePictureBox.BlendColor = colorPick.Color; - selectTilePictureBox.Image = dataTile.Texture; variantComboBox.Enabled = false; clearColorButton.Enabled = true; } @@ -610,7 +556,7 @@ namespace PckStudio.Forms.Editor { variantComboBox.Enabled = true; - variantComboBox_SelectedIndexChanged(sender, e); + selectTilePictureBox.BlendColor = Color.White; clearColorButton.Enabled = false; } @@ -618,7 +564,11 @@ namespace PckStudio.Forms.Editor private void colorSlider_ValueChanged(object sender, EventArgs e) { selectTilePictureBox.BlendColor = GetBlendColor(); - selectTilePictureBox.Image = dataTile.Texture; + } + + private void allowGroupsToolStripMenuItem_CheckedChanged(object sender, EventArgs e) + { + SelectedIndex = _selectedTile.Index; } } } \ No newline at end of file diff --git a/PCK-Studio/Forms/Features/CemuPanel.cs b/PCK-Studio/Forms/Features/CemuPanel.cs index b89fa199..de85ef9b 100644 --- a/PCK-Studio/Forms/Features/CemuPanel.cs +++ b/PCK-Studio/Forms/Features/CemuPanel.cs @@ -16,14 +16,14 @@ * 3. This notice may not be removed or altered from any source distribution. **/ using System; -using System.Xml; using System.IO; +using System.Xml; using System.Linq; -using System.Windows.Forms; -using PckStudio.Extensions; -using PckStudio.Internal.Misc; using System.Diagnostics; +using System.Windows.Forms; +using PckStudio.Core.Misc; using PckStudio.Properties; +using PckStudio.Core.Extensions; namespace PckStudio.Forms.Features { diff --git a/PCK-Studio/Forms/Skins-And-Textures/AdvancedOptions.cs b/PCK-Studio/Forms/Skins-And-Textures/AdvancedOptions.cs index 863353b7..9d56174b 100644 --- a/PCK-Studio/Forms/Skins-And-Textures/AdvancedOptions.cs +++ b/PCK-Studio/Forms/Skins-And-Textures/AdvancedOptions.cs @@ -2,13 +2,11 @@ using OMI; using OMI.Formats.Pck; using OMI.Workers.Pck; -using PckStudio.Extensions; +using PckStudio.Core.Extensions; using System; using System.Collections.Generic; using System.Data; using System.Diagnostics; -using System.Drawing; -using System.IO; using System.Linq; using System.Windows.Forms; @@ -20,11 +18,11 @@ namespace PckStudio.Popups { set { - _endianness = value ? Endianness.LittleEndian : Endianness.BigEndian; + _endianness = value ? ByteOrder.LittleEndian : ByteOrder.BigEndian; } } private readonly PckFile _pckFile; - private Endianness _endianness; + private ByteOrder _endianness; public AdvancedOptions(PckFile pckFile) { @@ -54,9 +52,7 @@ namespace PckStudio.Popups { try { - var reader = new PckFileReader(_endianness); - using var ms = new MemoryStream(asset.Data); - PckFile subPCK = reader.FromStream(ms); + PckFile subPCK = asset.GetData(new PckFileReader(_endianness)); applyBulkProperties(subPCK.GetAssets(), index); asset.SetData(new PckFileWriter(subPCK, _endianness)); } diff --git a/PCK-Studio/Forms/Skins-And-Textures/SkinPreview.Designer.cs b/PCK-Studio/Forms/Skins-And-Textures/SkinPreview.Designer.cs deleted file mode 100644 index b7b3f5ef..00000000 --- a/PCK-Studio/Forms/Skins-And-Textures/SkinPreview.Designer.cs +++ /dev/null @@ -1,75 +0,0 @@ - -namespace PckStudio.Forms -{ - partial class SkinPreview - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SkinPreview)); - this.ModelView = new PckStudio.Models.MinecraftModelView(this.components); - this.SuspendLayout(); - // - // ModelView - // - this.ModelView.BackColor = System.Drawing.Color.DarkGray; - this.ModelView.BackGradientColor1 = System.Drawing.SystemColors.ActiveCaptionText; - this.ModelView.BackGradientColor2 = System.Drawing.SystemColors.ActiveCaptionText; - this.ModelView.BackgroundType = PckStudio.Models.BackgroundTypes.Color; - this.ModelView.DegreesX = 0; - this.ModelView.DegreesY = 0; - this.ModelView.Dock = System.Windows.Forms.DockStyle.Fill; - this.ModelView.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.ModelView.ForeColor = System.Drawing.Color.Black; - this.ModelView.FOV = 90; - this.ModelView.Location = new System.Drawing.Point(0, 0); - this.ModelView.Name = "ModelView"; - this.ModelView.Projection = PckStudio.Models.ProjectionTypes.Perspective; - this.ModelView.Size = new System.Drawing.Size(418, 568); - this.ModelView.TabIndex = 1; - this.ModelView.Text = "PCK Model View"; - // - // SkinPreview - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(418, 568); - this.Controls.Add(this.ModelView); - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.Name = "SkinPreview"; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "SkinPreview"; - this.Load += new System.EventHandler(this.SkinPreview_Load); - this.ResumeLayout(false); - - } - - #endregion - - private PckStudio.Models.MinecraftModelView ModelView; - } -} \ No newline at end of file diff --git a/PCK-Studio/Forms/Skins-And-Textures/SkinPreview.cs b/PCK-Studio/Forms/Skins-And-Textures/SkinPreview.cs deleted file mode 100644 index 1be7abce..00000000 --- a/PCK-Studio/Forms/Skins-And-Textures/SkinPreview.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Drawing; -using System.Windows.Forms; -using PckStudio.Classes.Models.DefaultModels; -using PckStudio.Internal; -using PckStudio.Models; - -namespace PckStudio.Forms -{ - public partial class SkinPreview : Form - { - Image _texture; - ModelBase _model; - - public SkinPreview(Image img, SkinANIM anim, ModelBase model = null) - { - InitializeComponent(); - _texture = img; - - _model = model ?? new Steve64x32Model(_texture); - if (img.Width == 64 && img.Height == 64) - { - _model = model ?? new Steve64x64Model(_texture, anim); - } - } - - private void SkinPreview_Load(object sender, EventArgs e) => RenderModel(_texture); - - public void RenderModel(Image source) - { - _model.AddToModelView(ModelView); - } - } -} diff --git a/PCK-Studio/Forms/Skins-And-Textures/generateModel.Designer.cs b/PCK-Studio/Forms/Skins-And-Textures/generateModel.Designer.cs deleted file mode 100644 index 3639d52c..00000000 --- a/PCK-Studio/Forms/Skins-And-Textures/generateModel.Designer.cs +++ /dev/null @@ -1,642 +0,0 @@ -namespace PckStudio.Forms -{ - partial class generateModel - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - System.Windows.Forms.Label label6; - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(generateModel)); - System.Windows.Forms.Label label5; - System.Windows.Forms.Label label3; - System.Windows.Forms.Label label7; - System.Windows.Forms.Label labelTextureMappingPreview; - this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); - this.createToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.cloneToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.deleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.changeColorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.buttonDone = new System.Windows.Forms.Button(); - this.labelView = new System.Windows.Forms.Label(); - this.rotateRightBtn = new System.Windows.Forms.Button(); - this.rotateLeftBtn = new System.Windows.Forms.Button(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.tabBody = new System.Windows.Forms.TabControl(); - this.tabArmor = new System.Windows.Forms.TabPage(); - this.tabPage1 = new System.Windows.Forms.TabPage(); - this.myTablePanel2 = new System.Windows.Forms.TableLayoutPanel(); - this.offsetArms = new System.Windows.Forms.TextBox(); - this.label14 = new System.Windows.Forms.Label(); - this.offsetBody = new System.Windows.Forms.TextBox(); - this.offsetLegs = new System.Windows.Forms.TextBox(); - this.label10 = new System.Windows.Forms.Label(); - this.label13 = new System.Windows.Forms.Label(); - this.offsetHead = new System.Windows.Forms.TextBox(); - this.label12 = new System.Windows.Forms.Label(); - this.comboParent = new System.Windows.Forms.ComboBox(); - this.buttonEXPORT = new System.Windows.Forms.Button(); - this.buttonIMPORT = new System.Windows.Forms.Button(); - this.uvPictureBox = new PckStudio.ToolboxItems.InterpolationPictureBox(); - this.displayBox = new System.Windows.Forms.PictureBox(); - this.buttonTemplate = new MetroFramework.Controls.MetroButton(); - this.generateTextureCheckBox = new MetroFramework.Controls.MetroCheckBox(); - this.checkGuide = new MetroFramework.Controls.MetroCheckBox(); - this.checkBoxArmor = new MetroFramework.Controls.MetroCheckBox(); - this.SizeXUpDown = new System.Windows.Forms.NumericUpDown(); - this.SizeYUpDown = new System.Windows.Forms.NumericUpDown(); - this.SizeZUpDown = new System.Windows.Forms.NumericUpDown(); - this.TextureXUpDown = new System.Windows.Forms.NumericUpDown(); - this.TextureYUpDown = new System.Windows.Forms.NumericUpDown(); - this.PosZUpDown = new System.Windows.Forms.NumericUpDown(); - this.PosYUpDown = new System.Windows.Forms.NumericUpDown(); - this.PosXUpDown = new System.Windows.Forms.NumericUpDown(); - this.Part = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.X = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.Y = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.Z = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this._Width = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this._Height = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.Length = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.U = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.V = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.listViewBoxes = new System.Windows.Forms.ListView(); - label6 = new System.Windows.Forms.Label(); - label5 = new System.Windows.Forms.Label(); - label3 = new System.Windows.Forms.Label(); - label7 = new System.Windows.Forms.Label(); - labelTextureMappingPreview = new System.Windows.Forms.Label(); - this.contextMenuStrip1.SuspendLayout(); - this.groupBox1.SuspendLayout(); - this.tabBody.SuspendLayout(); - this.tabPage1.SuspendLayout(); - this.myTablePanel2.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.uvPictureBox)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.displayBox)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.SizeXUpDown)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.SizeYUpDown)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.SizeZUpDown)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.TextureXUpDown)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.TextureYUpDown)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.PosZUpDown)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.PosYUpDown)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.PosXUpDown)).BeginInit(); - this.SuspendLayout(); - // - // label6 - // - resources.ApplyResources(label6, "label6"); - label6.ForeColor = System.Drawing.Color.White; - label6.Name = "label6"; - // - // label5 - // - resources.ApplyResources(label5, "label5"); - label5.ForeColor = System.Drawing.Color.White; - label5.Name = "label5"; - // - // label3 - // - resources.ApplyResources(label3, "label3"); - label3.ForeColor = System.Drawing.Color.White; - label3.Name = "label3"; - // - // label7 - // - resources.ApplyResources(label7, "label7"); - label7.ForeColor = System.Drawing.Color.White; - label7.Name = "label7"; - // - // labelTextureMappingPreview - // - resources.ApplyResources(labelTextureMappingPreview, "labelTextureMappingPreview"); - labelTextureMappingPreview.ForeColor = System.Drawing.Color.White; - labelTextureMappingPreview.Name = "labelTextureMappingPreview"; - // - // contextMenuStrip1 - // - this.contextMenuStrip1.ImageScalingSize = new System.Drawing.Size(20, 20); - this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.createToolStripMenuItem, - this.cloneToolStripMenuItem, - this.deleteToolStripMenuItem, - this.changeColorToolStripMenuItem}); - this.contextMenuStrip1.Name = "contextMenuStrip1"; - resources.ApplyResources(this.contextMenuStrip1, "contextMenuStrip1"); - // - // createToolStripMenuItem - // - resources.ApplyResources(this.createToolStripMenuItem, "createToolStripMenuItem"); - this.createToolStripMenuItem.Name = "createToolStripMenuItem"; - this.createToolStripMenuItem.Click += new System.EventHandler(this.createToolStripMenuItem_Click); - // - // cloneToolStripMenuItem - // - resources.ApplyResources(this.cloneToolStripMenuItem, "cloneToolStripMenuItem"); - this.cloneToolStripMenuItem.Name = "cloneToolStripMenuItem"; - this.cloneToolStripMenuItem.Click += new System.EventHandler(this.cloneToolStripMenuItem_Click); - // - // deleteToolStripMenuItem - // - resources.ApplyResources(this.deleteToolStripMenuItem, "deleteToolStripMenuItem"); - this.deleteToolStripMenuItem.Name = "deleteToolStripMenuItem"; - this.deleteToolStripMenuItem.Click += new System.EventHandler(this.deleteToolStripMenuItem_Click); - // - // changeColorToolStripMenuItem - // - resources.ApplyResources(this.changeColorToolStripMenuItem, "changeColorToolStripMenuItem"); - this.changeColorToolStripMenuItem.Name = "changeColorToolStripMenuItem"; - this.changeColorToolStripMenuItem.Click += new System.EventHandler(this.changeColorToolStripMenuItem_Click); - // - // buttonDone - // - this.buttonDone.DialogResult = System.Windows.Forms.DialogResult.OK; - resources.ApplyResources(this.buttonDone, "buttonDone"); - this.buttonDone.ForeColor = System.Drawing.Color.White; - this.buttonDone.Name = "buttonDone"; - this.buttonDone.UseVisualStyleBackColor = true; - this.buttonDone.Click += new System.EventHandler(this.buttonDone_Click); - // - // labelView - // - resources.ApplyResources(this.labelView, "labelView"); - this.labelView.ForeColor = System.Drawing.Color.White; - this.labelView.Name = "labelView"; - // - // rotateRightBtn - // - resources.ApplyResources(this.rotateRightBtn, "rotateRightBtn"); - this.rotateRightBtn.ForeColor = System.Drawing.Color.White; - this.rotateRightBtn.Name = "rotateRightBtn"; - this.rotateRightBtn.UseVisualStyleBackColor = true; - this.rotateRightBtn.Click += new System.EventHandler(this.rotateRightBtn_Click); - // - // rotateLeftBtn - // - resources.ApplyResources(this.rotateLeftBtn, "rotateLeftBtn"); - this.rotateLeftBtn.ForeColor = System.Drawing.Color.White; - this.rotateLeftBtn.Name = "rotateLeftBtn"; - this.rotateLeftBtn.UseVisualStyleBackColor = true; - this.rotateLeftBtn.Click += new System.EventHandler(this.rotateLeftBtn_Click); - // - // groupBox1 - // - this.groupBox1.Controls.Add(this.tabBody); - this.groupBox1.ForeColor = System.Drawing.Color.White; - resources.ApplyResources(this.groupBox1, "groupBox1"); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.TabStop = false; - // - // tabBody - // - this.tabBody.Controls.Add(this.tabArmor); - this.tabBody.Controls.Add(this.tabPage1); - resources.ApplyResources(this.tabBody, "tabBody"); - this.tabBody.Name = "tabBody"; - this.tabBody.SelectedIndex = 0; - // - // tabArmor - // - this.tabArmor.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(17)))), ((int)(((byte)(17)))), ((int)(((byte)(17))))); - resources.ApplyResources(this.tabArmor, "tabArmor"); - this.tabArmor.Name = "tabArmor"; - // - // tabPage1 - // - this.tabPage1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(17)))), ((int)(((byte)(17)))), ((int)(((byte)(17))))); - this.tabPage1.Controls.Add(this.myTablePanel2); - resources.ApplyResources(this.tabPage1, "tabPage1"); - this.tabPage1.Name = "tabPage1"; - // - // myTablePanel2 - // - resources.ApplyResources(this.myTablePanel2, "myTablePanel2"); - this.myTablePanel2.Controls.Add(this.offsetArms, 1, 3); - this.myTablePanel2.Controls.Add(this.label14, 0, 3); - this.myTablePanel2.Controls.Add(this.offsetBody, 1, 1); - this.myTablePanel2.Controls.Add(this.offsetLegs, 1, 2); - this.myTablePanel2.Controls.Add(this.label10, 0, 0); - this.myTablePanel2.Controls.Add(this.label13, 0, 2); - this.myTablePanel2.Controls.Add(this.offsetHead, 1, 0); - this.myTablePanel2.Controls.Add(this.label12, 0, 1); - this.myTablePanel2.Name = "myTablePanel2"; - // - // offsetArms - // - resources.ApplyResources(this.offsetArms, "offsetArms"); - this.offsetArms.Name = "offsetArms"; - this.offsetArms.TextChanged += new System.EventHandler(this.offsetHead_TextChanged); - // - // label14 - // - resources.ApplyResources(this.label14, "label14"); - this.label14.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(192))))); - this.label14.Name = "label14"; - // - // offsetBody - // - resources.ApplyResources(this.offsetBody, "offsetBody"); - this.offsetBody.Name = "offsetBody"; - this.offsetBody.TextChanged += new System.EventHandler(this.offsetHead_TextChanged); - // - // offsetLegs - // - resources.ApplyResources(this.offsetLegs, "offsetLegs"); - this.offsetLegs.Name = "offsetLegs"; - this.offsetLegs.TextChanged += new System.EventHandler(this.offsetHead_TextChanged); - // - // label10 - // - resources.ApplyResources(this.label10, "label10"); - this.label10.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); - this.label10.Name = "label10"; - // - // label13 - // - resources.ApplyResources(this.label13, "label13"); - this.label13.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(0)))), ((int)(((byte)(64))))); - this.label13.Name = "label13"; - // - // offsetHead - // - resources.ApplyResources(this.offsetHead, "offsetHead"); - this.offsetHead.Name = "offsetHead"; - this.offsetHead.TextChanged += new System.EventHandler(this.offsetHead_TextChanged); - // - // label12 - // - resources.ApplyResources(this.label12, "label12"); - this.label12.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(64)))), ((int)(((byte)(0))))); - this.label12.Name = "label12"; - // - // comboParent - // - this.comboParent.FormattingEnabled = true; - this.comboParent.Items.AddRange(new object[] { - resources.GetString("comboParent.Items"), - resources.GetString("comboParent.Items1"), - resources.GetString("comboParent.Items2"), - resources.GetString("comboParent.Items3"), - resources.GetString("comboParent.Items4"), - resources.GetString("comboParent.Items5")}); - resources.ApplyResources(this.comboParent, "comboParent"); - this.comboParent.Name = "comboParent"; - this.comboParent.SelectedValueChanged += new System.EventHandler(this.comboParent_SelectedIndexChanged); - // - // buttonEXPORT - // - resources.ApplyResources(this.buttonEXPORT, "buttonEXPORT"); - this.buttonEXPORT.ForeColor = System.Drawing.Color.White; - this.buttonEXPORT.Name = "buttonEXPORT"; - this.buttonEXPORT.UseVisualStyleBackColor = true; - this.buttonEXPORT.Click += new System.EventHandler(this.buttonEXPORT_Click); - // - // buttonIMPORT - // - resources.ApplyResources(this.buttonIMPORT, "buttonIMPORT"); - this.buttonIMPORT.ForeColor = System.Drawing.Color.White; - this.buttonIMPORT.Name = "buttonIMPORT"; - this.buttonIMPORT.UseVisualStyleBackColor = true; - this.buttonIMPORT.Click += new System.EventHandler(this.buttonIMPORT_Click); - // - // uvPictureBox - // - this.uvPictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - resources.ApplyResources(this.uvPictureBox, "uvPictureBox"); - this.uvPictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; - this.uvPictureBox.Name = "uvPictureBox"; - this.uvPictureBox.TabStop = false; - // - // displayBox - // - this.displayBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(50)))), ((int)(((byte)(50))))); - this.displayBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - resources.ApplyResources(this.displayBox, "displayBox"); - this.displayBox.Name = "displayBox"; - this.displayBox.TabStop = false; - // - // buttonTemplate - // - resources.ApplyResources(this.buttonTemplate, "buttonTemplate"); - this.buttonTemplate.Name = "buttonTemplate"; - this.buttonTemplate.Theme = MetroFramework.MetroThemeStyle.Dark; - this.buttonTemplate.UseSelectable = true; - this.buttonTemplate.Click += new System.EventHandler(this.buttonTemplate_Click); - // - // generateTextureCheckBox - // - resources.ApplyResources(this.generateTextureCheckBox, "generateTextureCheckBox"); - this.generateTextureCheckBox.Name = "generateTextureCheckBox"; - this.generateTextureCheckBox.Theme = MetroFramework.MetroThemeStyle.Dark; - this.generateTextureCheckBox.UseSelectable = true; - // - // checkGuide - // - resources.ApplyResources(this.checkGuide, "checkGuide"); - this.checkGuide.Name = "checkGuide"; - this.checkGuide.Theme = MetroFramework.MetroThemeStyle.Dark; - this.checkGuide.UseSelectable = true; - this.checkGuide.CheckedChanged += new System.EventHandler(this.Render); - // - // checkBoxArmor - // - resources.ApplyResources(this.checkBoxArmor, "checkBoxArmor"); - this.checkBoxArmor.Name = "checkBoxArmor"; - this.checkBoxArmor.Theme = MetroFramework.MetroThemeStyle.Dark; - this.checkBoxArmor.UseSelectable = true; - this.checkBoxArmor.CheckedChanged += new System.EventHandler(this.Render); - // - // SizeXUpDown - // - this.SizeXUpDown.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(17)))), ((int)(((byte)(17)))), ((int)(((byte)(17))))); - this.SizeXUpDown.DecimalPlaces = 1; - this.SizeXUpDown.ForeColor = System.Drawing.SystemColors.Menu; - resources.ApplyResources(this.SizeXUpDown, "SizeXUpDown"); - this.SizeXUpDown.Name = "SizeXUpDown"; - this.SizeXUpDown.ValueChanged += new System.EventHandler(this.SizeXUpDown_ValueChanged); - // - // SizeYUpDown - // - this.SizeYUpDown.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(17)))), ((int)(((byte)(17)))), ((int)(((byte)(17))))); - this.SizeYUpDown.DecimalPlaces = 1; - this.SizeYUpDown.ForeColor = System.Drawing.SystemColors.Menu; - resources.ApplyResources(this.SizeYUpDown, "SizeYUpDown"); - this.SizeYUpDown.Name = "SizeYUpDown"; - this.SizeYUpDown.ValueChanged += new System.EventHandler(this.SizeYUpDown_ValueChanged); - // - // SizeZUpDown - // - this.SizeZUpDown.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(17)))), ((int)(((byte)(17)))), ((int)(((byte)(17))))); - this.SizeZUpDown.DecimalPlaces = 1; - this.SizeZUpDown.ForeColor = System.Drawing.SystemColors.Menu; - resources.ApplyResources(this.SizeZUpDown, "SizeZUpDown"); - this.SizeZUpDown.Name = "SizeZUpDown"; - this.SizeZUpDown.ValueChanged += new System.EventHandler(this.SizeZUpDown_ValueChanged); - // - // TextureXUpDown - // - this.TextureXUpDown.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(17)))), ((int)(((byte)(17)))), ((int)(((byte)(17))))); - this.TextureXUpDown.ForeColor = System.Drawing.SystemColors.Menu; - resources.ApplyResources(this.TextureXUpDown, "TextureXUpDown"); - this.TextureXUpDown.Maximum = new decimal(new int[] { - 64, - 0, - 0, - 0}); - this.TextureXUpDown.Name = "TextureXUpDown"; - this.TextureXUpDown.ValueChanged += new System.EventHandler(this.TextureXUpDown_ValueChanged); - // - // TextureYUpDown - // - this.TextureYUpDown.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(17)))), ((int)(((byte)(17)))), ((int)(((byte)(17))))); - this.TextureYUpDown.ForeColor = System.Drawing.SystemColors.Menu; - resources.ApplyResources(this.TextureYUpDown, "TextureYUpDown"); - this.TextureYUpDown.Maximum = new decimal(new int[] { - 64, - 0, - 0, - 0}); - this.TextureYUpDown.Name = "TextureYUpDown"; - this.TextureYUpDown.ValueChanged += new System.EventHandler(this.TextureYUpDown_ValueChanged); - // - // PosZUpDown - // - this.PosZUpDown.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(17)))), ((int)(((byte)(17)))), ((int)(((byte)(17))))); - this.PosZUpDown.DecimalPlaces = 1; - this.PosZUpDown.ForeColor = System.Drawing.SystemColors.Menu; - resources.ApplyResources(this.PosZUpDown, "PosZUpDown"); - this.PosZUpDown.Minimum = new decimal(new int[] { - 100, - 0, - 0, - -2147483648}); - this.PosZUpDown.Name = "PosZUpDown"; - this.PosZUpDown.ValueChanged += new System.EventHandler(this.PosZUpDown_ValueChanged); - // - // PosYUpDown - // - this.PosYUpDown.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(17)))), ((int)(((byte)(17)))), ((int)(((byte)(17))))); - this.PosYUpDown.DecimalPlaces = 1; - this.PosYUpDown.ForeColor = System.Drawing.SystemColors.Menu; - resources.ApplyResources(this.PosYUpDown, "PosYUpDown"); - this.PosYUpDown.Minimum = new decimal(new int[] { - 100, - 0, - 0, - -2147483648}); - this.PosYUpDown.Name = "PosYUpDown"; - this.PosYUpDown.ValueChanged += new System.EventHandler(this.PosYUpDown_ValueChanged); - // - // PosXUpDown - // - this.PosXUpDown.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(17)))), ((int)(((byte)(17)))), ((int)(((byte)(17))))); - this.PosXUpDown.DecimalPlaces = 1; - this.PosXUpDown.ForeColor = System.Drawing.SystemColors.Menu; - resources.ApplyResources(this.PosXUpDown, "PosXUpDown"); - this.PosXUpDown.Minimum = new decimal(new int[] { - 100, - 0, - 0, - -2147483648}); - this.PosXUpDown.Name = "PosXUpDown"; - this.PosXUpDown.ValueChanged += new System.EventHandler(this.PosXUpDown_ValueChanged); - // - // Part - // - resources.ApplyResources(this.Part, "Part"); - // - // X - // - resources.ApplyResources(this.X, "X"); - // - // Y - // - resources.ApplyResources(this.Y, "Y"); - // - // Z - // - resources.ApplyResources(this.Z, "Z"); - // - // _Width - // - resources.ApplyResources(this._Width, "_Width"); - // - // _Height - // - resources.ApplyResources(this._Height, "_Height"); - // - // Length - // - resources.ApplyResources(this.Length, "Length"); - // - // U - // - resources.ApplyResources(this.U, "U"); - // - // V - // - resources.ApplyResources(this.V, "V"); - // - // listViewBoxes - // - this.listViewBoxes.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.listViewBoxes.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.Part, - this.X, - this.Y, - this.Z, - this._Width, - this._Height, - this.Length, - this.U, - this.V}); - this.listViewBoxes.ContextMenuStrip = this.contextMenuStrip1; - this.listViewBoxes.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); - this.listViewBoxes.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; - this.listViewBoxes.HideSelection = false; - this.listViewBoxes.LabelEdit = true; - resources.ApplyResources(this.listViewBoxes, "listViewBoxes"); - this.listViewBoxes.MultiSelect = false; - this.listViewBoxes.Name = "listViewBoxes"; - this.listViewBoxes.UseCompatibleStateImageBehavior = false; - this.listViewBoxes.View = System.Windows.Forms.View.Details; - this.listViewBoxes.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged); - this.listViewBoxes.Click += new System.EventHandler(this.listView1_Click); - this.listViewBoxes.DoubleClick += new System.EventHandler(this.listView1_DoubleClick); - this.listViewBoxes.KeyDown += new System.Windows.Forms.KeyEventHandler(this.delStuffUsingDelKey); - // - // generateModel - // - resources.ApplyResources(this, "$this"); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.PosZUpDown); - this.Controls.Add(this.PosYUpDown); - this.Controls.Add(this.PosXUpDown); - this.Controls.Add(this.TextureYUpDown); - this.Controls.Add(this.TextureXUpDown); - this.Controls.Add(this.SizeZUpDown); - this.Controls.Add(this.SizeYUpDown); - this.Controls.Add(this.SizeXUpDown); - this.Controls.Add(this.checkBoxArmor); - this.Controls.Add(this.checkGuide); - this.Controls.Add(this.generateTextureCheckBox); - this.Controls.Add(this.buttonTemplate); - this.Controls.Add(this.displayBox); - this.Controls.Add(this.listViewBoxes); - this.Controls.Add(this.buttonEXPORT); - this.Controls.Add(labelTextureMappingPreview); - this.Controls.Add(this.uvPictureBox); - this.Controls.Add(this.comboParent); - this.Controls.Add(label6); - this.Controls.Add(this.buttonIMPORT); - this.Controls.Add(this.groupBox1); - this.Controls.Add(label7); - this.Controls.Add(this.rotateLeftBtn); - this.Controls.Add(this.rotateRightBtn); - this.Controls.Add(this.labelView); - this.Controls.Add(this.buttonDone); - this.Controls.Add(label3); - this.Controls.Add(label5); - this.MaximizeBox = false; - this.Name = "generateModel"; - this.Style = MetroFramework.MetroColorStyle.Silver; - this.Theme = MetroFramework.MetroThemeStyle.Dark; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.generateModel_FormClosing); - this.Load += new System.EventHandler(this.generateModel_Load); - this.SizeChanged += new System.EventHandler(this.generateModel_SizeChanged); - this.contextMenuStrip1.ResumeLayout(false); - this.groupBox1.ResumeLayout(false); - this.tabBody.ResumeLayout(false); - this.tabPage1.ResumeLayout(false); - this.myTablePanel2.ResumeLayout(false); - this.myTablePanel2.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.uvPictureBox)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.displayBox)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.SizeXUpDown)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.SizeYUpDown)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.SizeZUpDown)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.TextureXUpDown)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.TextureYUpDown)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.PosZUpDown)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.PosYUpDown)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.PosXUpDown)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; - private System.Windows.Forms.ToolStripMenuItem createToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem cloneToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem deleteToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem changeColorToolStripMenuItem; - private System.Windows.Forms.Button buttonDone; - private System.Windows.Forms.PictureBox displayBox; - private PckStudio.ToolboxItems.InterpolationPictureBox uvPictureBox; - private System.Windows.Forms.Button buttonIMPORT; - private System.Windows.Forms.Button buttonEXPORT; - private System.Windows.Forms.ComboBox comboParent; - private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.TabControl tabBody; - private System.Windows.Forms.TabPage tabPage1; - private System.Windows.Forms.TableLayoutPanel myTablePanel2; - private System.Windows.Forms.TextBox offsetArms; - private System.Windows.Forms.Label label14; - private System.Windows.Forms.TextBox offsetBody; - private System.Windows.Forms.TextBox offsetLegs; - private System.Windows.Forms.Label label10; - private System.Windows.Forms.Label label13; - private System.Windows.Forms.TextBox offsetHead; - private System.Windows.Forms.Label label12; - private System.Windows.Forms.TabPage tabArmor; - private System.Windows.Forms.Button rotateLeftBtn; - private System.Windows.Forms.Button rotateRightBtn; - private System.Windows.Forms.Label labelView; - private MetroFramework.Controls.MetroButton buttonTemplate; - private MetroFramework.Controls.MetroCheckBox generateTextureCheckBox; - private MetroFramework.Controls.MetroCheckBox checkGuide; - private MetroFramework.Controls.MetroCheckBox checkBoxArmor; - private System.Windows.Forms.NumericUpDown SizeXUpDown; - private System.Windows.Forms.NumericUpDown SizeYUpDown; - private System.Windows.Forms.NumericUpDown SizeZUpDown; - private System.Windows.Forms.NumericUpDown TextureXUpDown; - private System.Windows.Forms.NumericUpDown TextureYUpDown; - private System.Windows.Forms.NumericUpDown PosZUpDown; - private System.Windows.Forms.NumericUpDown PosYUpDown; - private System.Windows.Forms.NumericUpDown PosXUpDown; - private System.Windows.Forms.ColumnHeader Part; - private System.Windows.Forms.ColumnHeader X; - private System.Windows.Forms.ColumnHeader Y; - private System.Windows.Forms.ColumnHeader Z; - private System.Windows.Forms.ColumnHeader _Width; - private System.Windows.Forms.ColumnHeader _Height; - private System.Windows.Forms.ColumnHeader Length; - private System.Windows.Forms.ColumnHeader U; - private System.Windows.Forms.ColumnHeader V; - private System.Windows.Forms.ListView listViewBoxes; - } -} \ No newline at end of file diff --git a/PCK-Studio/Forms/Skins-And-Textures/generateModel.cs b/PCK-Studio/Forms/Skins-And-Textures/generateModel.cs deleted file mode 100644 index 6f125949..00000000 --- a/PCK-Studio/Forms/Skins-And-Textures/generateModel.cs +++ /dev/null @@ -1,1304 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.Linq; -using System.Windows.Forms; -using System.Collections; -using System.IO; -using System.Text.RegularExpressions; - -using Newtonsoft.Json; -using MetroFramework.Forms; -using OMI.Formats.Pck; -using PckStudio.Internal; -using PckStudio.Extensions; -using System.Runtime.CompilerServices; -using System.Diagnostics; -using System.Text; - -namespace PckStudio.Forms -{ - public partial class generateModel : MetroForm - { - private Image _previewImage; - public Image PreviewImage => _previewImage; - - private ViewDirection direction = ViewDirection.front; - - private enum ViewDirection - { - front, - right, - back, - left, - } - - private PckAsset _asset; - private SkinANIM _ANIM; - - private static Color _backgroundColor = Color.FromArgb(0xff, 0x50, 0x50, 0x50); - private static GraphicsConfig _graphicsConfig = new GraphicsConfig() - { - InterpolationMode = InterpolationMode.NearestNeighbor, - PixelOffsetMode = PixelOffsetMode.HighQuality, - }; - - private static readonly string[] ValidModelBoxTypes = new string[] - { - // Base 64x32 Parts - "HEAD", - "BODY", - "ARM0", - "ARM1", - "LEG0", - "LEG1", - - // 64x64 Overlay Parts - "HEADWEAR", - "JACKET", - "SLEEVE0", - "SLEEVE1", - "WAIST", - "PANTS0", - "PANTS1", - - // Armor Parts - "BODYARMOR", - "ARMARMOR0", - "ARMARMOR1", - "BELT", - "LEGGING0", - "LEGGING1", - "SOCK0", - "SOCK1", - "BOOT0", - "BOOT1" - }; - - private static readonly string[] ValidModelOffsetTypes = new string[] - { - // Body Offsets - "HEAD", - "BODY", - "ARM0", - "ARM1", - "LEG0", - "LEG1", - - // Armor Offsets - "HELMET", - "CHEST", "BODYARMOR", - "SHOULDER0", "ARMARMOR0", - "SHOULDER1", "ARMARMOR0", - "BELT", - "LEGGING0", - "LEGGING1", - "SOCK0", "BOOT0", - "SOCK1", "BOOT1", - - "TOOL0", - "TOOL1", - }; - - List modelBoxes = new List(); - List modelOffsets = new List(); - - private class ModelOffset - { - public string Name; - public float YOffset; - - public ModelOffset(string name, float yOffset) - { - Name = name; - YOffset = yOffset; - } - public (string, string) ToProperty() - { - string value = $"{Name} Y {YOffset}"; - return ("OFFSET", value.Replace(',','.')); - } - } - - public generateModel(PckAsset asset) - { - MessageBox.Show(this, "This feature is now considered deprecated and will no longer recieve updates. A better alternative is currently under development. Use at your own risk.", "Deprecated Feature", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); - InitializeComponent(); - - _asset = asset; - if (asset.Size > 0) - { - using (var ms = new MemoryStream(asset.Data)) - { - uvPictureBox.Image = Image.FromStream(ms); - } - } - comboParent.Items.Clear(); - comboParent.Items.AddRange(ValidModelBoxTypes); - LoadData(asset); - } - private static readonly Regex sWhitespace = new Regex(@"\s+"); - public static string ReplaceWhitespace(string input, string replacement) - { - return sWhitespace.Replace(input, replacement); - } - - private void LoadData(PckAsset asset) - { - comboParent.Enabled = asset.GetMultipleProperties("BOX").All(kv => { - var box = SkinBOX.FromString(kv.Value); - if (ValidModelBoxTypes.Contains(box.Type)) - { - modelBoxes.Add(box); - return true; - } - return false; - }); - asset.GetMultipleProperties("OFFSET").All(kv => { - string[] offset = ReplaceWhitespace(kv.Value, ",").TrimEnd('\n', '\r', ' ').Split(','); - if (offset.Length < 3) - return false; - string name = offset[0]; - if (offset[1] != "Y") - return false; - float value = float.Parse(offset[2]); - if (ValidModelOffsetTypes.Contains(name)) - { - modelOffsets.Add(new ModelOffset(name, value)); - return true; - } - return false; - }); - - _ANIM = asset.GetProperty("ANIM", SkinANIM.FromString); - UpdateListView(); - Rerender(); - } - - //Rename model part/item - private void listView1_DoubleClick_1(object sender, EventArgs e) - { - listViewBoxes.SelectedItems[0].BeginEdit(); - } - - private void Rerender([CallerMemberName] string caller = default!) - { - Debug.WriteLine($"Call from {caller}", category: nameof(Rerender)); - Render(this, EventArgs.Empty); - if (generateTextureCheckBox.Checked) - GenerateUVTextureMap(); - } - - // Graphic Rendering - // Builds an image based on the view - private void Render(object sender, EventArgs e) - { - buttonTemplate.Enabled = listViewBoxes.Items.Count == 0; - OrganizesZLayer(); - Bitmap bitmapModelPreview = new Bitmap(displayBox.Width, displayBox.Height); // Creates Model Display layer - using (Graphics graphics = Graphics.FromImage(bitmapModelPreview)) - { - graphics.ApplyConfig(_graphicsConfig); - graphics.Clear(_backgroundColor); - - float headbodyY = (displayBox.Height / 2) + 25; // 25 - float armY = (displayBox.Height / 2) + 35; // -60; - float legY = (displayBox.Height / 2) + 85; // -80; - float groundLevel = (displayBox.Height / 2) + 145; - graphics.DrawLine(Pens.White, 0, groundLevel, displayBox.Width, groundLevel); - float renderScale = uvPictureBox.Image.Width / 64; // used for displaying larger graphics properly; 64 is the base skin width for all models - - // Chooses Render settings based on current direction - foreach (ListViewItem listViewItem in listViewBoxes.Items) - { - if (!(listViewItem.Tag is SkinBOX part)) - continue; - float x = displayBox.Width / 2; - float y = 0; - - switch (direction) - { - case ViewDirection.front: - { - //Sets X & Y based on model part class - // listViewItem.Text -> part.Type - // listViewItem.SubItems[1] -> part.Pos.X - // listViewItem.SubItems[2] -> part.Pos.Y - // listViewItem.SubItems[3] -> part.Pos.Z - // listViewItem.SubItems[4] -> part.Size.X - // listViewItem.SubItems[5] -> part.Size.Y - // listViewItem.SubItems[6] -> part.Size.Z - // listViewItem.SubItems[7] -> part.U - // listViewItem.SubItems[8] -> part.V - switch (part.Type) - { - case "HEAD": - case "HEADWEAR": - case "HELMET": - y = headbodyY + int.Parse(offsetHead.Text) * 5; - break; - case "BODY": - case "JACKET": - case "CHEST": - case "BODYARMOR": - case "BELT": - case "WAIST": - y = headbodyY + int.Parse(offsetBody.Text) * 5; - break; - - case "ARM0": - case "ARMARMOR0": - case "SLEEVE0": - case "SHOULDER0": - x -= 25; - y = armY + int.Parse(offsetArms.Text) * 5; - break; - - case "ARM1": - case "ARMARMOR1": - case "SLEEVE1": - case "SHOULDER1": - x += 25; - y = armY + int.Parse(offsetArms.Text) * 5; - break; - - case "LEG0": - case "PANTS0": - case "SOCK0": - case "LEGGING0": - case "BOOT0": - x -= 10; - y = legY + int.Parse(offsetLegs.Text) * 5; - break; - - case "LEG1": - case "PANTS1": - case "SOCK1": - case "LEGGING1": - case "BOOT1": - x += 10; - y = legY + int.Parse(offsetLegs.Text) * 5; - break; - } - - // Maps imported Texture if texture generation is disabled - if (!generateTextureCheckBox.Checked) - { - RectangleF destRect = new RectangleF( - x + part.Pos.X * 5, - y + part.Pos.Y * 5, - part.Size.X * 5, - part.Size.Y * 5); - RectangleF srcRect = new RectangleF( - (part.UV.X + part.Size.Z) * renderScale, - (part.UV.Y + part.Size.Z) * renderScale, - part.Size.X * renderScale, - part.Size.Y * renderScale); - graphics.DrawImage(uvPictureBox.Image, destRect, srcRect, GraphicsUnit.Pixel); - } - else - { - graphics.FillRectangle(new SolidBrush(listViewItem.ForeColor), x + part.Pos.X * 5, y + part.Pos.Y * 5, part.Size.X * 5, part.Size.Y * 5); - } - - break; - } - - case ViewDirection.left: - { - //Sets X & Y based on model part class - switch (part.Type) - { - case "HEAD": - case "HEADWEAR": - case "HELMET": - y = headbodyY + int.Parse(offsetHead.Text) * 5; - break; - case "BODY": - case "JACKET": - case "CHEST": - case "BODYARMOR": - case "BELT": - case "WAIST": - y = headbodyY + int.Parse(offsetBody.Text) * 5; - break; - - case "ARM0": - case "ARMARMOR0": - case "SLEEVE0": - case "SHOULDER0": - y = armY + int.Parse(offsetArms.Text) * 5; - break; - - case "ARM1": - case "ARMARMOR1": - case "SLEEVE1": - case "SHOULDER1": - y = armY + int.Parse(offsetArms.Text) * 5; - break; - - case "LEG0": - case "PANTS0": - case "SOCK0": - case "LEGGING0": - case "BOOT0": - y = legY + int.Parse(offsetLegs.Text) * 5; - break; - - case "LEG1": - case "PANTS1": - case "SOCK1": - case "LEGGING1": - case "BOOT1": - y = legY + int.Parse(offsetLegs.Text) * 5; - break; - } - - // Maps imported Texture if auto texture is disabled - if (!generateTextureCheckBox.Checked) - { - RectangleF destRect = new RectangleF( - x + part.Pos.Z * 5, - y + part.Pos.Y * 5, - part.Size.Z * 5, - part.Size.Y * 5); - RectangleF srcRect = new RectangleF( - (part.UV.X + part.Size.Z + part.Size.X) * renderScale, - (part.UV.Y + part.Size.Z) * renderScale, - part.Size.Z * renderScale, - part.Size.Y * renderScale); - graphics.DrawImage(uvPictureBox.Image, destRect, srcRect, GraphicsUnit.Pixel); - } - else - { - //Draws Part - graphics.FillRectangle(new SolidBrush(listViewItem.ForeColor), x + part.Pos.Z * 5, y + part.Pos.Y * 5, part.Size.Z * 5, part.Size.Y * 5); - } - bitmapModelPreview.RotateFlip(RotateFlipType.RotateNoneFlipX); - break; - } - - case ViewDirection.back: - { - //Sets X & Y based on model part class - switch (part.Type) - { - case "HEAD": - case "HEADWEAR": - case "HELMET": - y = headbodyY + int.Parse(offsetHead.Text) * 5; - break; - case "BODY": - case "JACKET": - case "CHEST": - case "BODYARMOR": - case "BELT": - case "WAIST": - y = headbodyY + int.Parse(offsetBody.Text) * 5; - break; - - case "ARM0": - case "ARMARMOR0": - case "SLEEVE0": - case "SHOULDER0": - x -= 25; - y = armY + int.Parse(offsetArms.Text) * 5; - break; - - case "ARM1": - case "ARMARMOR1": - case "SLEEVE1": - case "SHOULDER1": - x += 25; - y = armY + int.Parse(offsetArms.Text) * 5; - break; - - case "LEG0": - case "PANTS0": - case "SOCK0": - case "LEGGING0": - case "BOOT0": - x -= 10; - y = legY + int.Parse(offsetLegs.Text) * 5; - break; - - case "LEG1": - case "PANTS1": - case "SOCK1": - case "LEGGING1": - case "BOOT1": - x += 10; - y = legY + int.Parse(offsetLegs.Text) * 5; - break; - } - - //Maps imported Texture if auto texture is disabled - if (!generateTextureCheckBox.Checked) - { - RectangleF destRect = new RectangleF( - x + part.Pos.X * 5, - y + part.Pos.Y * 5, - part.Size.X * 5, - part.Size.Y * 5); - RectangleF srcRect = new RectangleF( - (part.UV.X + part.Size.Z * 2 + part.Size.X) * renderScale, - (part.UV.Y + part.Size.Z) * renderScale, - part.Size.X * renderScale, - part.Size.Y * renderScale); - graphics.DrawImage(uvPictureBox.Image, destRect, srcRect, GraphicsUnit.Pixel); - } - else - { - //Draws Part - graphics.FillRectangle(new SolidBrush(listViewItem.ForeColor), x + part.Pos.X * 5, y + part.Pos.Y * 5, part.Size.X * 5, part.Size.Y * 5); - } - bitmapModelPreview.RotateFlip(RotateFlipType.RotateNoneFlipX); - break; - } - - case ViewDirection.right: - //Sets X & Y based on model part class - switch (part.Type) - { - case "HEAD": - case "HEADWEAR": - case "HELMET": - y = headbodyY + int.Parse(offsetHead.Text) * 5; - break; - case "BODY": - case "JACKET": - case "CHEST": - case "BODYARMOR": - case "BELT": - case "WAIST": - y = headbodyY + int.Parse(offsetBody.Text) * 5; - break; - - case "ARM0": - case "ARMARMOR0": - case "SLEEVE0": - case "SHOULDER0": - y = armY + int.Parse(offsetArms.Text) * 5; - break; - - case "ARM1": - case "ARMARMOR1": - case "SLEEVE1": - case "SHOULDER1": - y = armY + int.Parse(offsetArms.Text) * 5; - break; - - case "LEG0": - case "PANTS0": - case "SOCK0": - case "LEGGING0": - case "BOOT0": - y = legY + int.Parse(offsetLegs.Text) * 5; - break; - - case "LEG1": - case "PANTS1": - case "SOCK1": - case "LEGGING1": - case "BOOT1": - y = legY + int.Parse(offsetLegs.Text) * 5; - break; - } - //Maps imported Texture if auto texture is disabled - if (!generateTextureCheckBox.Checked) - { - RectangleF destRect = new RectangleF( - x + part.Pos.Z * 5, - y + part.Pos.Y * 5, - part.Size.Z * 5, - part.Size.Y * 5); - RectangleF srcRect = new RectangleF( - (part.UV.X + part.Size.Z + part.Size.X) * renderScale, - (part.UV.Y + part.Size.Z) * renderScale, - part.Size.Z * renderScale, - part.Size.Y * renderScale); - graphics.DrawImage(uvPictureBox.Image, destRect, srcRect, GraphicsUnit.Pixel); - } - else - { - //Draws Part - graphics.FillRectangle(new SolidBrush(listViewItem.ForeColor), x + part.Pos.Z * 5, y + part.Pos.Y * 5, part.Size.Z * 5, part.Size.Y * 5); - } - break; - } - } - - if (checkBoxArmor.Checked) - DrawArmorOffsets(graphics); - // draw last to be on top - if (checkGuide.Checked) - DrawGuideLines(graphics); - } - displayBox.Image = bitmapModelPreview; - } - - private void GenerateUVTextureMap() - { - Random rng = new Random(); - using (Graphics graphics = Graphics.FromImage(uvPictureBox.Image)) - { - graphics.ApplyConfig(_graphicsConfig); - foreach (SkinBOX part in modelBoxes) - { - float width = part.Size.X * 2; - float height = part.Size.Y * 2; - float length = part.Size.Z * 2; - float u = part.UV.X * 2; - float v = part.UV.Y * 2; - int argb = rng.Next(-16777216, -1); // 0xFF000000 - 0xFFFFFFFF - var color = Color.FromArgb(argb); - Brush brush = new SolidBrush(color); - graphics.FillRectangle(brush, u + length, v, width, length); - graphics.FillRectangle(brush, u + length + width, v, width, length); - graphics.FillRectangle(brush, u, length + v, length, height); - graphics.FillRectangle(brush, u + length, v + length, width, height); - graphics.FillRectangle(brush, u + length + width, v + length, width, height); - graphics.FillRectangle(brush, u + length + width * 2, v + length, length, height); - } - } - uvPictureBox.Invalidate(); - } - - // Checks and sets Z layering - private void OrganizesZLayer() - { - foreach (ListViewItem listViewItem in listViewBoxes.Items) - listViewItem.SubItems.Add("unchecked"); - - float surfaceCenter = displayBox.Width / 2; - - switch (direction) - { - case ViewDirection.front: - { - foreach (ListViewItem listViewItemCurrent in listViewBoxes.Items) - { - if (listViewItemCurrent.SubItems[9].Text == "unchecked") - { - float x = 0; - if (listViewItemCurrent.Text == "HEAD") - x = surfaceCenter; - else if (listViewItemCurrent.Text == "BODY") - x = surfaceCenter; - else if (listViewItemCurrent.Text == "ARM0") - x = 178; - else if (listViewItemCurrent.Text == "ARM1") - x = 228; - else if (listViewItemCurrent.Text == "LEG0") - x = 193; - else if (listViewItemCurrent.Text == "LEG1") - x = 213; - - bool flag = false; - int index = listViewItemCurrent.Index; - foreach (ListViewItem listViewItemComparing in listViewBoxes.Items) - { - var val1 = double.Parse(listViewItemCurrent.SubItems[3].Text) + double.Parse(listViewItemCurrent.SubItems[6].Text); - var val2 = double.Parse(listViewItemComparing.SubItems[3].Text) + double.Parse(listViewItemComparing.SubItems[6].Text); - if (listViewItemComparing.SubItems[9].Text == "unchecked" && - val1 < val2) - { - if (listViewItemComparing.Index < listViewBoxes.Items.Count + 1) - { - index = listViewItemComparing.Index + 1; - flag = true; - } - } - } - listViewItemCurrent.SubItems[9].Text = "checked"; - if (flag) - { - ListViewItem listViewItem2 = (ListViewItem)listViewItemCurrent.Clone(); - listViewBoxes.Items.Insert(index, listViewItem2); - listViewItemCurrent.Remove(); - } - } - } - } - break; - case ViewDirection.right: - { - int checkedItems = 0; - do - { - foreach (ListViewItem listViewItemCurrent in listViewBoxes.Items) - { - if (listViewItemCurrent.SubItems[listViewItemCurrent.SubItems.Count - 1].Text == "unchecked") - { - float x = 0; - if (listViewItemCurrent.Text == "HEAD") - x = surfaceCenter; - else if (listViewItemCurrent.Text == "BODY") - x = surfaceCenter; - else if (listViewItemCurrent.Text == "ARM0") - x = 178; - else if (listViewItemCurrent.Text == "ARM1") - x = 228; - else if (listViewItemCurrent.Text == "LEG0") - x = 193; - else if (listViewItemCurrent.Text == "LEG1") - x = 213; - bool flag = false; - int index = listViewItemCurrent.Index; - foreach (ListViewItem listViewItem2 in listViewBoxes.Items) - { - if (listViewItem2.SubItems[9].Text == "unchecked") - { - int y = 0; - if (listViewItem2.Text == "HEAD") - y = (int)surfaceCenter; - else if (listViewItem2.Text == "BODY") - y = (int)surfaceCenter; - else if (listViewItem2.Text == "ARM0") - y = 178; - else if (listViewItem2.Text == "ARM1") - y = 228; - else if (listViewItem2.Text == "LEG0") - y = 193; - else if (listViewItem2.Text == "LEG1") - y = 213; - if ((int)double.Parse(listViewItemCurrent.SubItems[1].Text) + (int)double.Parse(listViewItemCurrent.SubItems[4].Text) - x > (int)double.Parse(listViewItem2.SubItems[1].Text) + (int)double.Parse(listViewItem2.SubItems[4].Text) + y && listViewItem2.Index + 1 < this.listViewBoxes.Items.Count + 1) - { - index = listViewItem2.Index + 1; - flag = true; - } - } - } - listViewItemCurrent.SubItems[9].Text = "checked"; - checkedItems += 1; - if (flag) - { - ListViewItem listViewItem2 = (ListViewItem)listViewItemCurrent.Clone(); - listViewBoxes.Items.Insert(index, listViewItem2); - if (listViewBoxes.SelectedItems.Count != 0) - { - //if (selected.Index == listViewItem1.Index) - //{ - // selected = listViewItem2; - //} - } - listViewItemCurrent.Remove(); - } - } - else - { - checkedItems += 1; - } - } - } while (checkedItems < listViewBoxes.Items.Count); - } - break; - case ViewDirection.back: - { - int checkedItems = 0; - do - { - foreach (ListViewItem listViewItemCurrent in listViewBoxes.Items) - { - if (listViewItemCurrent.SubItems[listViewItemCurrent.SubItems.Count - 1].Text == "unchecked") - { - bool flag = false; - int index = listViewItemCurrent.Index; - foreach (ListViewItem listViewItemComparing in listViewBoxes.Items) - { - if (listViewItemComparing.SubItems[9].Text == "unchecked" && (int)double.Parse(listViewItemCurrent.SubItems[3].Text) + (int)double.Parse(listViewItemCurrent.SubItems[6].Text) > (int)double.Parse(listViewItemComparing.SubItems[3].Text) + (int)double.Parse(listViewItemComparing.SubItems[6].Text)) - { - if (listViewItemComparing.Index < listViewBoxes.Items.Count + 1) - { - index = listViewItemComparing.Index + 1; - flag = true; - } - } - } - listViewItemCurrent.SubItems[9].Text = "checked"; - checkedItems += 1; - if (flag) - { - ListViewItem listViewItem2 = (ListViewItem)listViewItemCurrent.Clone(); - listViewBoxes.Items.Insert(index, listViewItem2); - if (listViewBoxes.SelectedItems.Count != 0) - { - //if (selected.Index == listViewItemCurrent.Index) - //{ - // selected = listViewItem2; - //} - } - listViewItemCurrent.Remove(); - } - } - else - { - checkedItems += 1; - } - } - } while (checkedItems < listViewBoxes.Items.Count); - } - break; - case ViewDirection.left: - { - int checkedItems = 0; - do - { - foreach (ListViewItem listViewItemCurrent in listViewBoxes.Items) - { - if (listViewItemCurrent.SubItems[listViewItemCurrent.SubItems.Count - 1].Text == "unchecked") - { - float x = 0; - if (listViewItemCurrent.Text == "HEAD") - x = surfaceCenter; - else if (listViewItemCurrent.Text == "BODY") - x = surfaceCenter; - else if (listViewItemCurrent.Text == "ARM0") - x = 178; - else if (listViewItemCurrent.Text == "ARM1") - x = 228; - else if (listViewItemCurrent.Text == "LEG0") - x = 193; - else if (listViewItemCurrent.Text == "LEG1") - x = 213; - bool flag = false; - int index = listViewItemCurrent.Index; - foreach (ListViewItem listViewItem2 in listViewBoxes.Items) - { - if (listViewItem2.SubItems[9].Text == "unchecked") - { - int y = 0; - if (listViewItem2.Text == "HEAD") - y = (int)surfaceCenter; - else if (listViewItem2.Text == "BODY") - y = (int)surfaceCenter; - else if (listViewItem2.Text == "ARM0") - y = 178; - else if (listViewItem2.Text == "ARM1") - y = 228; - else if (listViewItem2.Text == "LEG0") - y = 193; - else if (listViewItem2.Text == "LEG1") - y = 213; - if ((int)double.Parse(listViewItemCurrent.SubItems[1].Text) + (int)double.Parse(listViewItemCurrent.SubItems[4].Text) + x < (int)double.Parse(listViewItem2.SubItems[1].Text) + (int)double.Parse(listViewItem2.SubItems[4].Text) + y && listViewItem2.Index + 1 < this.listViewBoxes.Items.Count + 1) - { - index = listViewItem2.Index + 1; - flag = true; - } - } - } - listViewItemCurrent.SubItems[9].Text = "checked"; - checkedItems += 1; - if (flag == true) - { - ListViewItem listViewItem2 = (ListViewItem)listViewItemCurrent.Clone(); - listViewBoxes.Items.Insert(index, listViewItem2); - if (listViewBoxes.SelectedItems.Count != 0) - { - //if (selected.Index == listViewItem1.Index) - //{ - // selected = listViewItem2; - //} - } - listViewItemCurrent.Remove(); - } - } - else - { - checkedItems += 1; - } - } - } while (checkedItems < listViewBoxes.Items.Count); - } - break; - default: - break; - } - } - - private void DrawGuideLines(Graphics g) - { - Point center = new Point(displayBox.Height / 2, displayBox.Width / 2); - int headbodyY = center.Y + 25; //25 - int legY = center.Y + 85; // - 80; - bool isSide = direction == ViewDirection.left || direction == ViewDirection.right; - if (!isSide) - { - g.DrawLine(Pens.Red, 0, headbodyY + float.Parse(offsetHead.Text) * 5, displayBox.Width, headbodyY + float.Parse(offsetHead.Text) * 5); - g.DrawLine(Pens.Green, 0, headbodyY + float.Parse(offsetBody.Text) * 5, displayBox.Width, headbodyY + float.Parse(offsetBody.Text) * 5); - g.DrawLine(Pens.Blue, 0, headbodyY + float.Parse(offsetArms.Text) * 5, displayBox.Width, headbodyY + float.Parse(offsetArms.Text) * 5); - g.DrawLine(Pens.Purple, 0, legY + float.Parse(offsetLegs.Text) * 5, displayBox.Width, legY + float.Parse(offsetLegs.Text) * 5); - } - g.DrawLine(Pens.Red, center.X, 0, center.X, displayBox.Height); - g.DrawLine(Pens.Blue, center.X + 30, 0, center.X + 30, displayBox.Height); - g.DrawLine(Pens.Blue, center.X - 30, 0, center.X - 30, displayBox.Height); - g.DrawLine(Pens.Purple, center.X - 10, 0, center.X - 10, displayBox.Height); - g.DrawLine(Pens.Purple, center.X + 10, 0, center .X + 10, displayBox.Height); - } - - private void DrawArmorOffsets(Graphics g) - { - int centerPointHeight = displayBox.Height / 2; - int centerPointWidth = displayBox.Width / 2; - int headbodyY = centerPointHeight + 25; //25 - int armY = centerPointHeight + 35; // - 60; - int legY = centerPointHeight + 85; // - 80; - SolidBrush semiTransBrush = new SolidBrush(Color.FromArgb(80, 50, 50, 75)); - g.FillRectangle(semiTransBrush, centerPointWidth, (float)(headbodyY - 40 /*+ offsetHelmet.Value * 5*/), 40, 40); // Helmet - bool isSide = direction == ViewDirection.left || direction == ViewDirection.right; - if (isSide) - { - g.FillRectangle(semiTransBrush, centerPointWidth - 10, headbodyY, 20, 60); // Chest - g.FillRectangle(semiTransBrush, centerPointWidth - 10, (float)(legY + 40 /*+ offsetBoots.Value * 5*/), 20, 20); // Boots - g.FillRectangle(semiTransBrush, centerPointWidth - 10, (float)(legY /*+ offsetPants.Value * 5*/), 20, 40); // Pants - g.FillRectangle(semiTransBrush, centerPointWidth - 5, (float)(armY + 45 /*+ offsetTool.Value * 5*/), 10, 10); // Tools - } - else - { - g.FillRectangle(semiTransBrush, centerPointWidth - 20, headbodyY, 40, 60); // Chest - g.FillRectangle(semiTransBrush, centerPointWidth - 35, (float)(armY + 45 /*+ offsetTool.Value * 5*/), 10, 10); // Tool0 - g.FillRectangle(semiTransBrush, centerPointWidth + 25, (float)(armY + 45 /*+ offsetTool.Value * 5*/), 10, 10); // Tool1 - g.FillRectangle(semiTransBrush, centerPointWidth - 20, (float)(legY /*+ offsetPants.Value * 5*/), 20, 40); // Pants0 - g.FillRectangle(semiTransBrush, centerPointWidth, (float)(legY /*+ offsetPants.Value * 5*/), 20, 40); // Pants1 - g.FillRectangle(semiTransBrush, centerPointWidth - 20, (float)(legY + 40 /*+ offsetBoots.Value * 5*/), 20, 20); // Boot0 - g.FillRectangle(semiTransBrush, centerPointWidth, (float)(legY + 40 /*+ offsetBoots.Value * 5*/), 20, 20); // Boot1 - } - - } - - private void generateModel_Load(object sender, EventArgs e) - { - if (Screen.PrimaryScreen.Bounds.Height >= 780 && Screen.PrimaryScreen.Bounds.Width >= 1080) - return; - - Rerender(); - } - - private void createToolStripMenuItem_Click(object sender, EventArgs e) - { - modelBoxes.Add(SkinBOX.Empty); - UpdateListView(); - Rerender(); - } - - private void listView1_SelectedIndexChanged(object sender, EventArgs e) - { - changeColorToolStripMenuItem.Visible = false; - if (listViewBoxes.SelectedItems.Count != 0 && listViewBoxes.SelectedItems[0].Tag is SkinBOX) - { - changeColorToolStripMenuItem.Visible = true; - var part = listViewBoxes.SelectedItems[0].Tag as SkinBOX; - //graphics.DrawRectangle(Pens.Yellow, x + (float)double.Parse(this.selected.SubItems[3].Text) * 5 - 1, y + (float)double.Parse(this.selected.SubItems[2].Text) * 5 - 1, (float)double.Parse(this.selected.SubItems[6].Text) * 5 + 2, (float)double.Parse(this.selected.SubItems[5].Text) * 5 + 2); - //graphics.DrawRectangle(Pens.Black, x + (float)double.Parse(this.selected.SubItems[3].Text) * 5, y + (float)double.Parse(this.selected.SubItems[2].Text) * 5, (float)double.Parse(this.selected.SubItems[6].Text) * 5, (float)double.Parse(this.selected.SubItems[5].Text) * 5); - comboParent.Text = part.Type; - PosXUpDown.Value = (decimal)part.Pos.X; - PosYUpDown.Value = (decimal)part.Pos.Y; - PosZUpDown.Value = (decimal)part.Pos.Z; - SizeXUpDown.Value = (decimal)part.Size.X; - SizeYUpDown.Value = (decimal)part.Size.Y; - SizeZUpDown.Value = (decimal)part.Size.Z; - TextureXUpDown.Value = (decimal)part.UV.X; - TextureYUpDown.Value = (decimal)part.UV.Y; - Rerender(); - } - } - - - //Changes Item Model Class - private void comboParent_SelectedIndexChanged(object sender, EventArgs e) - { - if (listViewBoxes.SelectedItems.Count != 0 && - listViewBoxes.SelectedItems[0].Tag is SkinBOX part) - { - part.Type = comboParent.Text; - buttonIMPORT.Enabled = true; - buttonEXPORT.Enabled = true; - SizeXUpDown.Enabled = true; - SizeYUpDown.Enabled = true; - SizeZUpDown.Enabled = true; - PosXUpDown.Enabled = true; - PosYUpDown.Enabled = true; - PosZUpDown.Enabled = true; - TextureXUpDown.Enabled = true; - TextureYUpDown.Enabled = true; - } - Rerender(); - } - - private void SizeXUpDown_ValueChanged(object sender, EventArgs e) - { - if (listViewBoxes.SelectedItems.Count != 0 && - listViewBoxes.SelectedItems[0].Tag is SkinBOX part) - { - part.Size.X = (float)SizeXUpDown.Value; - } - UpdateListView(); - Rerender(); - } - - private void SizeYUpDown_ValueChanged(object sender, EventArgs e) - { - if (listViewBoxes.SelectedItems.Count != 0 && - listViewBoxes.SelectedItems[0].Tag is SkinBOX part) - { - part.Size.Y = (float)SizeYUpDown.Value; - } - UpdateListView(); - Rerender(); - } - - private void SizeZUpDown_ValueChanged(object sender, EventArgs e) - { - if (listViewBoxes.SelectedItems.Count != 0 && - listViewBoxes.SelectedItems[0].Tag is SkinBOX part) - { - part.Size.Z = (float)SizeZUpDown.Value; - } - UpdateListView(); - Rerender(); - } - - private void PosXUpDown_ValueChanged(object sender, EventArgs e) - { - if (listViewBoxes.SelectedItems.Count != 0 && - listViewBoxes.SelectedItems[0].Tag is SkinBOX part) - { - part.Pos.X = (float)PosXUpDown.Value; - } - UpdateListView(); - Rerender(); - } - - - private void PosYUpDown_ValueChanged(object sender, EventArgs e) - { - if (listViewBoxes.SelectedItems.Count != 0 && - listViewBoxes.SelectedItems[0].Tag is SkinBOX part) - { - part.Pos.Y = (float)PosYUpDown.Value; - } - UpdateListView(); - Rerender(); - } - - - private void PosZUpDown_ValueChanged(object sender, EventArgs e) - { - if (listViewBoxes.SelectedItems.Count != 0 && - listViewBoxes.SelectedItems[0].Tag is SkinBOX part) - { - part.Pos.Z = (float)PosZUpDown.Value; - } - UpdateListView(); - Rerender(); - } - - private void rotateRightBtn_Click(object sender, EventArgs e) - { - if (direction == ViewDirection.front) - direction = ViewDirection.left; - else - --direction; - labelView.Text = $"View: {direction}"; - Rerender(); - } - - private void rotateLeftBtn_Click(object sender, EventArgs e) - { - if (direction == ViewDirection.left) - direction = ViewDirection.front; - else - ++direction; - labelView.Text = $"View: {direction}"; - Rerender(); - } - - - //Sets Texture X-Offset - private void TextureXUpDown_ValueChanged(object sender, EventArgs e) - { - if (listViewBoxes.SelectedItems.Count != 0 && - listViewBoxes.SelectedItems[0].Tag is SkinBOX part) - { - part.UV.X = (int)TextureXUpDown.Value; - } - UpdateListView(); - Rerender(); - } - - - //Sets texture Y-Offset - private void TextureYUpDown_ValueChanged(object sender, EventArgs e) - { - if (listViewBoxes.SelectedItems.Count != 0 && - listViewBoxes.SelectedItems[0].Tag is SkinBOX part) - { - part.UV.Y = (int)TextureYUpDown.Value; - } - UpdateListView(); - Rerender(); - } - - - //Export Current Skin Texture - private void buttonEXPORT_Click(object sender, EventArgs e) - { - Bitmap bitmap = new Bitmap(uvPictureBox.Image, 64, 64); - using SaveFileDialog saveFileDialog = new SaveFileDialog(); - saveFileDialog.Filter = "PNG Image Files | *.png"; - if (saveFileDialog.ShowDialog(this) == DialogResult.OK) - { - bitmap.Save(saveFileDialog.FileName, ImageFormat.Png); - } - } - - - //Imports Skin Texture - private void buttonIMPORT_Click(object sender, EventArgs e) - { - OpenFileDialog openFileDialog = new OpenFileDialog(); - openFileDialog.Filter = "PNG Image Files | *.png"; - openFileDialog.Title = "Select Skin Texture"; - - if (openFileDialog.ShowDialog(this) == DialogResult.OK) // skins can only be a 1:1 ratio (base 64x64) or a 2:1 ratio (base 64x32) - { - using (var img = Image.FromFile(openFileDialog.FileName)) - { - if ((img.Width == img.Height || img.Height == img.Width / 2)) - { - generateTextureCheckBox.Checked = false; - using (Graphics graphics = Graphics.FromImage(uvPictureBox.Image)) - { - graphics.ApplyConfig(_graphicsConfig); - graphics.DrawImage(img, 0, 0, img.Width, img.Height); - } - uvPictureBox.Invalidate(); - Rerender(); - } - else - { - MessageBox.Show(this, "Not a valid skin file", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - } - } - - // Creates Model Data and Finalizes - private void buttonDone_Click(object sender, EventArgs e) - { - foreach (SkinBOX part in modelBoxes) - { - _asset.AddProperty("BOX", part); - } - - //Bitmap bitmap2 = new Bitmap(64, 64); - //using (Graphics graphics = Graphics.FromImage(bitmap2)) - //{ - // graphics.ApplyConfig(_graphicsConfig); - // graphics.DrawImage(uvPictureBox.Image, 0, 0, 64, 64); - //} - _previewImage = new Bitmap(displayBox.Width, displayBox.Height); - Close(); - } - - // Renders model after texture change - private void texturePreview_BackgroundImageChanged(object sender, EventArgs e) - { - Rerender(); - } - - // Trigger Dialog to select model part/item color - private void listView1_DoubleClick(object sender, EventArgs e) - { - ColorDialog colorDialog = new ColorDialog(); - if (colorDialog.ShowDialog(this) == DialogResult.OK) - listViewBoxes.SelectedItems[0].ForeColor = colorDialog.Color; - Rerender(); - } - - - //Re-renders head with updated x-offset - private void offsetHead_TextChanged(object sender, EventArgs e) - { - Rerender(); - } - - - //Re-renders body with updated x-offset - private void offsetBody_TextAlignChanged(object sender, EventArgs e) - { - Rerender(); - } - - - //Loads in model template(Steve) - private void buttonTemplate_Click(object sender, EventArgs e) - { - modelBoxes.Add(SkinBOX.FromString("HEAD -4 -8 -4 8 8 8 0 0 0 0 0")); - modelBoxes.Add(SkinBOX.FromString("BODY -4 0 -2 8 12 4 16 16 0 0 0")); - modelBoxes.Add(SkinBOX.FromString("ARM0 -3 -2 -2 4 12 4 40 16 0 0 0")); - modelBoxes.Add(SkinBOX.FromString("ARM1 -1 -2 -2 4 12 4 40 16 0 1 0")); - modelBoxes.Add(SkinBOX.FromString("LEG0 -2 0 -2 4 12 4 0 16 0 0 0")); - modelBoxes.Add(SkinBOX.FromString("LEG1 -2 0 -2 4 12 4 0 16 0 1 0")); - comboParent.Enabled = true; - UpdateListView(); - Rerender(); - } - - private void UpdateListView() - { - listViewBoxes.Items.Clear(); - foreach (SkinBOX part in modelBoxes) - { - ListViewItem listViewItem = new ListViewItem(part.Type); - listViewItem.Tag = part; - listViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(listViewItem, part.Pos.X.ToString())); - listViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(listViewItem, part.Pos.Y.ToString())); - listViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(listViewItem, part.Pos.Z.ToString())); - listViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(listViewItem, part.Size.X.ToString())); - listViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(listViewItem, part.Size.Y.ToString())); - listViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(listViewItem, part.Size.Z.ToString())); - listViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(listViewItem, part.UV.X.ToString())); - listViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(listViewItem, part.UV.Y.ToString())); - listViewBoxes.Items.Add(listViewItem); - } - } - - private void cloneToolStripMenuItem_Click(object sender, EventArgs e) - { - try - { - ListViewItem listViewItem = new ListViewItem(); - ListViewItem selected = listViewBoxes.SelectedItems[0]; - listViewItem.Text = selected.Text; - listViewItem.Tag = selected.Tag; - int num = 0; - foreach (ListViewItem.ListViewSubItem subItem in selected.SubItems) - { - if (num > 0) - listViewItem.SubItems.Add(subItem.Text); - ++num; - } - listViewBoxes.Items.Add(listViewItem); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - MessageBox.Show(this, "Please Select a Part"); - } - } - - private void deleteToolStripMenuItem_Click(object sender, EventArgs e) - { - if (listViewBoxes.SelectedItems[0] == null) - return; - listViewBoxes.SelectedItems[0].Remove(); - Rerender(); - } - - private void changeColorToolStripMenuItem_Click(object sender, EventArgs e) - { - ColorDialog colorDialog = new ColorDialog(); - if (colorDialog.ShowDialog(this) == DialogResult.OK) - listViewBoxes.SelectedItems[0].ForeColor = colorDialog.Color; - Rerender(); - } - - //Re-renders tool with updated x-offset - private void offsetTool_TextChanged(object sender, EventArgs e) - { - Rerender(); - } - - //Re-renders helmet with updated x-offset - private void offsetHelmet_TextChanged(object sender, EventArgs e) - { - Rerender(); - } - - //Re-renders pants with updated x-offset - private void offsetPants_TextChanged(object sender, EventArgs e) - { - Rerender(); - } - - //Re-renders leggings with updated x-offset - private void offsetLeggings_TextChanged(object sender, EventArgs e) - { - Rerender(); - } - - //Re-renders boots with updated x-offset - private void offsetBoots_TextChanged(object sender, EventArgs e) - { - Rerender(); - } - - //Item Selection - private void listView1_Click(object sender, EventArgs e) - { - if (listViewBoxes.SelectedItems.Count != 0 && listViewBoxes.SelectedItems[0] != null && - listViewBoxes.SelectedItems[0].Tag is SkinBOX part) - { - comboParent.Text = part.Type; - PosXUpDown.Value = (decimal)part.Pos.X; - PosYUpDown.Value = (decimal)part.Pos.Y; - PosZUpDown.Value = (decimal)part.Pos.Z; - SizeXUpDown.Value = (decimal)part.Size.X; - SizeYUpDown.Value = (decimal)part.Size.Y; - SizeZUpDown.Value = (decimal)part.Size.Z; - TextureXUpDown.Value = (decimal)part.UV.X; - TextureYUpDown.Value = (decimal)part.UV.Y; - SizeXUpDown.Enabled = true; - SizeYUpDown.Enabled = true; - SizeZUpDown.Enabled = true; - PosXUpDown.Enabled = true; - PosYUpDown.Enabled = true; - PosZUpDown.Enabled = true; - TextureXUpDown.Enabled = true; - TextureYUpDown.Enabled = true; - comboParent.Enabled = true; - return; - } - SizeXUpDown.Enabled = false; - SizeYUpDown.Enabled = false; - SizeZUpDown.Enabled = false; - PosXUpDown.Enabled = false; - PosYUpDown.Enabled = false; - PosZUpDown.Enabled = false; - TextureXUpDown.Enabled = false; - TextureYUpDown.Enabled = false; - comboParent.Enabled = false; - Rerender(); - } - - //currently scrapped - private void generateModel_FormClosing(object sender, FormClosingEventArgs e) - {/* - if (MessageBox.Show("You done here?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) - { - e.Cancel = true; - return; - } - e.Cancel = false;*/ - } - - private void delStuffUsingDelKey(object sender, KeyEventArgs e) - { - if (e.KeyCode == Keys.Delete && listViewBoxes.SelectedItems.Count != 0 && - listViewBoxes.SelectedItems[0].Tag is SkinBOX part) - { - if (modelBoxes.Remove(part)) - listViewBoxes.SelectedItems[0].Remove(); - Rerender(); - } - } - - private void generateModel_SizeChanged(object sender, EventArgs e) - { - Rerender(); - } - } -} \ No newline at end of file diff --git a/PCK-Studio/Internal/App/ApplicationBuildInfo.cs b/PCK-Studio/Internal/App/ApplicationBuildInfo.cs deleted file mode 100644 index f7a0007f..00000000 --- a/PCK-Studio/Internal/App/ApplicationBuildInfo.cs +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (c) 2023-present miku-666, MattNL - * 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.IO; -using System.Reflection; - -namespace PckStudio.Internal.App -{ - static internal class ApplicationBuildInfo - { - // this is to specify which build release this is. This is manually updated for now - // TODO: add different chars for different configurations - private const string BuildType = "c"; - private static System.Globalization.Calendar _buildCalendar; - private static DateTime date = new FileInfo(Assembly.GetExecutingAssembly().Location).LastWriteTime; - private static string _betaBuildVersion; - - public static string BetaBuildVersion - { - get - { - // adopted Minecraft Java Edition Snapshot format (YYwWWn) - // to keep track of work in progress features and builds - _buildCalendar ??= new System.Globalization.CultureInfo("en-US").Calendar; - return _betaBuildVersion ??= string.Format("#{0}w{1}{2}", - date.ToString("yy"), - _buildCalendar.GetWeekOfYear(date, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Monday), - BuildType); - } - } - } -} diff --git a/PCK-Studio/Internal/App/Profiler.cs b/PCK-Studio/Internal/App/Profiler.cs deleted file mode 100644 index 1de57454..00000000 --- a/PCK-Studio/Internal/App/Profiler.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* 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.Diagnostics; -using System.Runtime.CompilerServices; - -namespace PckStudio.Internal.App -{ - internal static class Profiler - { - private static Stopwatch _stopwatch = new Stopwatch(); - - [Conditional("DEBUG")] - internal static void Start([CallerMemberName] string caller = default!, [CallerFilePath] string source = default!, [CallerLineNumber] int line = default!) - { - Debug.WriteLine($"Stopwatch starts", category: nameof(Profiler)); - Debug.WriteLine($"{source}@{caller}:{line}", category: nameof(Profiler)); - _stopwatch.Restart(); - } - - [Conditional("DEBUG")] - internal static void Stop([CallerMemberName] string caller = default!, [CallerFilePath] string source = default!, [CallerLineNumber] int line = default!) - { - _stopwatch.Stop(); - Debug.WriteLine($"{caller} took {_stopwatch.ElapsedMilliseconds}ms", category: nameof(Profiler)); - } - - } -} diff --git a/PCK-Studio/Internal/AppResourceManager.cs b/PCK-Studio/Internal/AppResourceManager.cs new file mode 100644 index 00000000..2f1d2fe9 --- /dev/null +++ b/PCK-Studio/Internal/AppResourceManager.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Resources; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using OMI.Workers; +using PckStudio.Properties; + +namespace PckStudio.Internal +{ + internal sealed class AppResourceManager + { + public static readonly AppResourceManager Default = new AppResourceManager(Resources.ResourceManager, Resources.Culture); + private ResourceManager _resourceManager; + private readonly CultureInfo _culture; + + public AppResourceManager(ResourceManager resourceManager, CultureInfo culture) + { + _resourceManager = resourceManager ?? throw new ArgumentNullException(nameof(resourceManager)); + _culture = culture; + } + + public T GetData(byte[] rawData, IDataFormatReader dataFormatReader) where T : class + { + _ = rawData ?? throw new ArgumentNullException(nameof(rawData)); + _ = dataFormatReader ?? throw new ArgumentNullException(nameof(dataFormatReader)); + + T result = default; + using (Stream resourceStream = new MemoryStream(rawData)) + { + result = dataFormatReader.FromStream(resourceStream); + } + return result; + } + + public T GetDataFromResource(string name, IDataFormatReader dataFormatReader) where T : class + { + return GetData((byte[])_resourceManager.GetObject(name, _culture), dataFormatReader); + } + } +} diff --git a/PCK-Studio/Internal/App/ApplicationScope.cs b/PCK-Studio/Internal/ApplicationScope.cs similarity index 51% rename from PCK-Studio/Internal/App/ApplicationScope.cs rename to PCK-Studio/Internal/ApplicationScope.cs index c6b9762f..8f3c9e9c 100644 --- a/PCK-Studio/Internal/App/ApplicationScope.cs +++ b/PCK-Studio/Internal/ApplicationScope.cs @@ -3,12 +3,13 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; using PckStudio.Properties; -using PckStudio.Extensions; +using PckStudio.Core.Extensions; using System.Globalization; -using PckStudio.Internal.Json; -using PckStudio.Internal.Misc; +using PckStudio.Core.Json; +using PckStudio.Core.Misc; using System.Threading.Tasks; using System.Windows.Forms; +using PckStudio.Json; namespace PckStudio.Internal.App { @@ -25,30 +26,26 @@ namespace PckStudio.Internal.App internal static void Initialize() { - Profiler.Start(); - { - _entityImages ??= Resources.entities_atlas.SplitHorizontal(32).ToArray(); - DataCacher ??= new FileCacher(Program.AppDataCache); - _ = Tiles.JsonBlockData; - _ = Tiles.JsonItemData; - _ = Tiles.JsonParticleData; - _ = Tiles.JsonMoonPhaseData; - _ = Tiles.JsonExplosionData; - _ = Tiles.JsonMapIconData; - _ = Tiles.JsonExperienceOrbData; - _ = Tiles.JsonPaintingData; - _ = Tiles.BlockImageList; - _ = Tiles.ItemImageList; - _ = Tiles.ParticleImageList; - _ = Tiles.ExplosionImageList; - _ = Tiles.MapIconImageList; - _ = Tiles.ExperienceOrbImageList; - _ = Tiles.MoonPhaseImageList; - _ = Tiles.PaintingImageList; - CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; - Task.Run(GetContributors); - } - Profiler.Stop(); + _entityImages ??= Resources.entities_atlas.SplitHorizontal(32).ToArray(); + DataCacher ??= new FileCacher(Program.AppDataCache); + _ = Tiles.JsonBlockData; + _ = Tiles.JsonItemData; + _ = Tiles.JsonParticleData; + _ = Tiles.JsonMoonPhaseData; + _ = Tiles.JsonExplosionData; + _ = Tiles.JsonMapIconData; + _ = Tiles.JsonExperienceOrbData; + _ = Tiles.JsonPaintingData; + _ = Tiles.BlockImageList; + _ = Tiles.ItemImageList; + _ = Tiles.ParticleImageList; + _ = Tiles.ExplosionImageList; + _ = Tiles.MapIconImageList; + _ = Tiles.ExperienceOrbImageList; + _ = Tiles.MoonPhaseImageList; + _ = Tiles.PaintingImageList; + CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; + Task.Run(GetContributors); } internal static void GetContributors() diff --git a/PCK-Studio/Internal/App/CommitInfo.cs b/PCK-Studio/Internal/CommitInfo.cs similarity index 100% rename from PCK-Studio/Internal/App/CommitInfo.cs rename to PCK-Studio/Internal/CommitInfo.cs diff --git a/PCK-Studio/Internal/Json/Entities.cs b/PCK-Studio/Internal/Entities.cs similarity index 92% rename from PCK-Studio/Internal/Json/Entities.cs rename to PCK-Studio/Internal/Entities.cs index a0729112..3ade10d4 100644 --- a/PCK-Studio/Internal/Json/Entities.cs +++ b/PCK-Studio/Internal/Entities.cs @@ -4,12 +4,11 @@ using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Windows.Forms; using Newtonsoft.Json; -using PckStudio.Extensions; using PckStudio.Properties; +using PckStudio.Core.Json; -namespace PckStudio.Internal.Json +namespace PckStudio.Json { internal class JsonEntities { diff --git a/PCK-Studio/Internal/GameConstants.cs b/PCK-Studio/Internal/GameConstants.cs deleted file mode 100644 index 72abeb67..00000000 --- a/PCK-Studio/Internal/GameConstants.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace PckStudio.Internal -{ - internal static class GameConstants - { - - public const int GameTickInMilliseconds = 50; - - // See: https://minecraft.fandom.com/wiki/Dye#Color_values for more information. - public static readonly Color[] DyeColors = [ - Color.FromArgb(0xf9fffe), // White - Color.FromArgb(0xf9801d), // Orange - Color.FromArgb(0xc74ebd), // Magenta - Color.FromArgb(0x3ab3da), // Light Blue - Color.FromArgb(0xfed83d), // Yellow - Color.FromArgb(0x80c71f), // Lime - Color.FromArgb(0xf38baa), // Pink - Color.FromArgb(0x474f52), // Gray - Color.FromArgb(0x9d9d97), // Light Gray - Color.FromArgb(0x169c9c), // Cyan - Color.FromArgb(0x8932b8), // Purple - Color.FromArgb(0x3c44aa), // Blue - Color.FromArgb(0x835432), // Brown - Color.FromArgb(0x5e7c16), // Green - Color.FromArgb(0xb02e26), // Red - Color.FromArgb(0x1d1d21), // Black - ]; - } -} diff --git a/PCK-Studio/Internal/IO/CSMB/CSMBFileReader.cs b/PCK-Studio/Internal/IO/CSMB/CSMBFileReader.cs deleted file mode 100644 index c8c41aaa..00000000 --- a/PCK-Studio/Internal/IO/CSMB/CSMBFileReader.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.IO; -using System.Text; -using OMI; -using OMI.Workers; -using PckStudio.FileFormats; - -namespace PckStudio.Internal.IO.CSMB -{ - internal class CSMBFileReader : IDataFormatReader, IDataFormatReader - { - private CSMBFileReader() - { } - - public CSMBFile FromFile(string filename) - { - throw new System.NotImplementedException(); - } - - public CSMBFile FromStream(Stream stream) - { - CSMBFile csmbFile = new CSMBFile(); - using (var reader = new EndiannessAwareBinaryReader(stream, Encoding.ASCII, leaveOpen: true, Endianness.LittleEndian)) - { - reader.ReadInt32(); - int numOfParts = reader.ReadInt32(); - for (int i = 0; i < numOfParts; i++) - { - CSMBPart part = new CSMBPart(); - part.Name = ReadString(reader); - part.Parent = (CSMBParentPart)reader.ReadInt32(); - part.posX = reader.ReadSingle(); - part.posY = reader.ReadSingle(); - part.posZ = reader.ReadSingle(); - part.sizeX = reader.ReadSingle(); - part.sizeY = reader.ReadSingle(); - part.sizeZ = reader.ReadSingle(); - part.uvX = reader.ReadInt32(); - part.uvY = reader.ReadInt32(); - part.MirrorTexture = reader.ReadBoolean(); - part.HideWArmour = reader.ReadBoolean(); - part.Inflation = reader.ReadSingle(); - csmbFile.Parts.Add(part); - } - int numOfOffsets = reader.ReadInt32(); - for (int i = 0; i < numOfOffsets; i++) - { - CSMBOffset offset = new CSMBOffset(); - offset.offsetPart = (CSMBOffsetPart)reader.ReadInt32(); - offset.VerticalOffset = reader.ReadSingle(); - csmbFile.Offsets.Add(offset); - } - } - return csmbFile; - } - - private string ReadString(EndiannessAwareBinaryReader reader) - { - ushort strlen = reader.ReadUInt16(); - return reader.ReadString(strlen); - } - - object IDataFormatReader.FromStream(Stream stream) => FromStream(stream); - - object IDataFormatReader.FromFile(string filename) => FromFile(filename); - } -} diff --git a/PCK-Studio/Internal/IO/CSMB/CSMBFileWriter.cs b/PCK-Studio/Internal/IO/CSMB/CSMBFileWriter.cs deleted file mode 100644 index b572b092..00000000 --- a/PCK-Studio/Internal/IO/CSMB/CSMBFileWriter.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.IO; -using System.Text; -using PckStudio.FileFormats; -using OMI.Workers; -using OMI; - -namespace PckStudio.Internal.IO.CSMB -{ - internal class CSMBFileWriter : IDataFormatWriter - { - CSMBFile _CSMB; - - public CSMBFileWriter(CSMBFile csmb) - { - _CSMB = csmb; - } - - public void WriteToFile(string filename) - { - using (FileStream fs = File.OpenWrite(filename)) - { - WriteToStream(fs); - } - } - - public void WriteToStream(Stream stream) - { - using (var writer = new EndiannessAwareBinaryWriter(stream, Encoding.ASCII, leaveOpen: true, Endianness.LittleEndian)) - { - writer.Write(0); - writer.Write(_CSMB.Parts.Count); - foreach (CSMBPart part in _CSMB.Parts) - { - writer.Write((short)part.Name.Length); - writer.WriteString(part.Name); - writer.Write((int)part.Parent); - writer.Write(part.posX); - writer.Write(part.posY); - writer.Write(part.posZ); - writer.Write(part.sizeX); - writer.Write(part.sizeY); - writer.Write(part.sizeZ); - writer.Write(part.uvX); - writer.Write(part.uvY); - writer.Write(part.MirrorTexture); - writer.Write(part.HideWArmour); - writer.Write(part.Inflation); - } - writer.Write(_CSMB.Offsets.Count); - foreach (CSMBOffset offset in _CSMB.Offsets) - { - writer.Write((int)offset.offsetPart); - writer.Write(offset.VerticalOffset); - } - } - } - } -} diff --git a/PCK-Studio/Internal/PckNodeSorter.cs b/PCK-Studio/Internal/PckNodeSorter.cs index 934bc1be..174cd4f2 100644 --- a/PCK-Studio/Internal/PckNodeSorter.cs +++ b/PCK-Studio/Internal/PckNodeSorter.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.Windows.Forms; using OMI.Formats.Pck; -using PckStudio.Extensions; +using PckStudio.Core.Extensions; namespace PckStudio.Internal { diff --git a/PCK-Studio/Internal/ResourceLocation.cs b/PCK-Studio/Internal/ResourceLocation.cs deleted file mode 100644 index 89b9601b..00000000 --- a/PCK-Studio/Internal/ResourceLocation.cs +++ /dev/null @@ -1,125 +0,0 @@ -/* Copyright (c) 2024-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.Drawing; -using System.Linq; - -namespace PckStudio.Internal -{ - internal sealed class ResourceLocation - { - private static List ResourceGroups = new List(); - private static readonly ResourceLocation Unknown = new ResourceLocation(string.Empty, ResourceCategory.Unknown, 1); - - private static readonly Dictionary _categoryLookUp = new Dictionary() - { - ["textures/items"] = new ResourceLocation("textures/items", ResourceCategory.ItemAnimation, 16, isGroup: true), - ["textures/blocks"] = new ResourceLocation("textures/blocks", ResourceCategory.BlockAnimation, 16, isGroup: true), - ["terrain.png"] = new ResourceLocation("terrain.png", ResourceCategory.BlockAtlas, 16), - ["items.png"] = new ResourceLocation("items.png", ResourceCategory.ItemAtlas, 16), - ["particles.png"] = new ResourceLocation("particles.png", ResourceCategory.ParticleAtlas, 16), - ["item/banner/Banner_Atlas.png"] = new ResourceLocation("item/banner/Banner_Atlas.png", ResourceCategory.BannerAtlas, new Size(6, 7), TillingMode.WidthAndHeight), - ["art/kz.png"] = new ResourceLocation("art/kz.png", ResourceCategory.PaintingAtlas, 16), - ["misc/explosion.png"] = new ResourceLocation("misc/explosion.png", ResourceCategory.ExplosionAtlas, 4), - ["item/xporb.png"] = new ResourceLocation("item/xporb.png", ResourceCategory.ExperienceOrbAtlas, 4), - ["terrain/moon_phases.png"] = new ResourceLocation("terrain/moon_phases.png", ResourceCategory.MoonPhaseAtlas, 4), - ["misc/mapicons.png"] = new ResourceLocation("misc/mapicons.png", ResourceCategory.MapIconAtlas, 4), - ["misc/additionalmapicons.png"] = new ResourceLocation("misc/additionalmapicons.png", ResourceCategory.AdditionalMapIconsAtlas, 4), - }; - - public static string GetPathFromCategory(ResourceCategory category) - { - return category switch - { - ResourceCategory.ItemAnimation => _categoryLookUp["textures/items"].ToString(), - ResourceCategory.BlockAnimation => _categoryLookUp["textures/blocks"].ToString(), - ResourceCategory.BlockAtlas => _categoryLookUp["terrain.png"].ToString(), - ResourceCategory.ItemAtlas => _categoryLookUp["items.png"].ToString(), - ResourceCategory.ParticleAtlas => _categoryLookUp["particles.png"].ToString(), - ResourceCategory.BannerAtlas => _categoryLookUp["item/banner/Banner_Atlas.png"].ToString(), - ResourceCategory.PaintingAtlas => _categoryLookUp["art/kz.png"].ToString(), - ResourceCategory.ExplosionAtlas => _categoryLookUp["misc/explosion.png"].ToString(), - ResourceCategory.ExperienceOrbAtlas => _categoryLookUp["item/xporb.png"].ToString(), - ResourceCategory.MoonPhaseAtlas => _categoryLookUp["terrain/moon_phases.png"].ToString(), - ResourceCategory.MapIconAtlas => _categoryLookUp["misc/mapicons.png"].ToString(), - ResourceCategory.AdditionalMapIconsAtlas => _categoryLookUp["misc/additionalmapicons.png"].ToString(), - _ => string.Empty - }; - } - - public static ResourceCategory GetCategoryFromPath(string path) => GetFromPath(path).Category; - - public static ResourceLocation GetFromPath(string path) - { - if (string.IsNullOrWhiteSpace(path) || !path.StartsWith("res/")) - return Unknown; - string categoryPath = path.Substring("res/".Length); - if (_categoryLookUp.ContainsKey(categoryPath)) - return _categoryLookUp[categoryPath]; - return ResourceGroups.Where(group => categoryPath.StartsWith(group.Path)).FirstOrDefault() ?? Unknown; - } - - public enum TillingMode - { - Width, - Height, - WidthAndHeight - } - - public readonly string Path; - public readonly ResourceCategory Category; - public readonly Size TillingFactor; - public readonly TillingMode Tilling; - public readonly bool IsGroup; - - public Size GetTileArea(Size imgSize) - { - int tileFactorWidth = Math.Max(1, TillingFactor.Width); - int tileFactorHeight = Math.Max(1, TillingFactor.Height); - return Tilling switch - { - TillingMode.Width => new Size(imgSize.Width / tileFactorWidth, imgSize.Width / tileFactorHeight), - TillingMode.Height => new Size(imgSize.Height / tileFactorWidth, imgSize.Height / tileFactorHeight), - TillingMode.WidthAndHeight => new Size(imgSize.Width / tileFactorWidth, imgSize.Height / tileFactorHeight), - _ => Size.Empty, - }; - } - - private ResourceLocation(string path, ResourceCategory category, int tillingFactor, TillingMode tilling = TillingMode.Width, bool isGroup = false) - : this(path, category, new Size(tillingFactor, tillingFactor), tilling, isGroup) - { - } - - private ResourceLocation(string path, ResourceCategory category, Size tillingFactor, TillingMode tilling = TillingMode.Width, bool isGroup = false) - { - Path = path; - Category = category; - TillingFactor = tillingFactor; - Tilling = tilling; - IsGroup = isGroup; - if (isGroup) - ResourceGroups.Add(this); - } - - public override string ToString() - { - return "res/" + Path; - } - } -} diff --git a/PCK-Studio/Internal/Misc/RichPresenceClient.cs b/PCK-Studio/Internal/RichPresenceClient.cs similarity index 97% rename from PCK-Studio/Internal/Misc/RichPresenceClient.cs rename to PCK-Studio/Internal/RichPresenceClient.cs index a9590095..533fbe82 100644 --- a/PCK-Studio/Internal/Misc/RichPresenceClient.cs +++ b/PCK-Studio/Internal/RichPresenceClient.cs @@ -2,11 +2,10 @@ using System.Diagnostics; using DiscordRPC; using PckStudio.Internal; -using PckStudio.Properties; using DiscordRPC.Logging; -using PckStudio.Internal.App; +using PckStudio.Properties; -namespace PckStudio.Internal.Misc +namespace PckStudio.Internal { // https://github.com/BullyWiiPlaza/Minecraft-Wii-U-Mod-Injector/blob/main/Minecraft%20Wii%20U%20Mod%20Injector/Helpers/DiscordRpc.cs static class RPC diff --git a/PCK-Studio/Internal/SettingsManager.cs b/PCK-Studio/Internal/SettingsManager.cs new file mode 100644 index 00000000..c08f452a --- /dev/null +++ b/PCK-Studio/Internal/SettingsManager.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PckStudio.Properties; + +namespace PckStudio.Internal +{ + internal static class SettingsManager + { + internal static Core.App.SettingsManager Default { get; } = new Core.App.SettingsManager(Settings.Default, isReadOnly: true); + } +} diff --git a/PCK-Studio/Internal/SkinBOX.cs b/PCK-Studio/Internal/SkinBOX.cs deleted file mode 100644 index c324b6ec..00000000 --- a/PCK-Studio/Internal/SkinBOX.cs +++ /dev/null @@ -1,117 +0,0 @@ -/* Copyright (c) 2023-present miku-666, MattNL - * 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.Numerics; - -namespace PckStudio.Internal -{ - public class SkinBOX : ICloneable, IEquatable - { - public static readonly SkinBOX Empty = new SkinBOX("HEAD", new Vector3(-4, -8, -4), new Vector3(8), Vector2.Zero); - - public string Type; - public Vector3 Pos; - public Vector3 Size; - public Vector2 UV; - public bool HideWithArmor; - public bool Mirror; - public float Scale; - - public SkinBOX(string type, Vector3 pos, Vector3 size, Vector2 uv, - bool hideWithArmor = false, bool mirror = false, float scale = 0.0f) - { - Type = type; - Pos = pos; - Size = size; - UV = uv; - HideWithArmor = hideWithArmor; - Mirror = mirror; - Scale = scale; - } - - public static SkinBOX FromString(string value) - { - var arguments = value.Split(' '); - if (arguments.Length < 9) - { - throw new ArgumentException("Arguments must have at least a length of 9"); - } - string type = arguments[0]; - Vector3 pos = TryGetVector3(arguments, 1); - Vector3 size = TryGetVector3(arguments, 4); - Vector2 uv = TryGetVector2(arguments, 7); - var skinBox = new SkinBOX(type, pos, size, uv); - if (arguments.Length >= 10) - skinBox.HideWithArmor = arguments[9] == "1"; - if (arguments.Length >= 11) - skinBox.Mirror = arguments[10] == "1"; - if (arguments.Length >= 12) - float.TryParse(arguments[11], out skinBox.Scale); - return skinBox; - } - - public ValueTuple ToProperty() - { - return new ValueTuple("BOX", ToString()); - } - - public override string ToString() - { - return - $"{Type} {Pos.X} {Pos.Y} {Pos.Z} {Size.X} {Size.Y} {Size.Z} {UV.X} {UV.Y} {Convert.ToInt32(HideWithArmor)} {Convert.ToInt32(Mirror)} {Scale}" - .Replace(',', '.'); - } - - private static Vector2 TryGetVector2(string[] arguments, int startIndex) - { - float.TryParse(arguments[startIndex], out float x); - float.TryParse(arguments[startIndex + 1], out float y); - return new Vector2(x, y); - } - - private static Vector3 TryGetVector3(string[] arguments, int startIndex) - { - Vector2 xy = TryGetVector2(arguments, startIndex); - float.TryParse(arguments[startIndex + 2], out float z); - return new Vector3(xy, z); - } - - public override int GetHashCode() - { - return Type.GetHashCode() % Pos.GetHashCode() * UV.GetHashCode() % Size.GetHashCode(); - } - - public override bool Equals(object obj) - { - return obj is SkinBOX box && Equals(box); - } - - public bool Equals(SkinBOX other) - { - return Type.Equals(other.Type) && - Pos.Equals(other.Pos) && - Size.Equals(other.Size) && - UV.Equals(other.UV); - } - - public object Clone() - { - return new SkinBOX((string)Type.Clone(), Pos, Size, UV, HideWithArmor, Mirror, Scale); - } - } -} diff --git a/PCK-Studio/MainForm.Designer.cs b/PCK-Studio/MainForm.Designer.cs index 8c9e1cd4..c9bcfaff 100644 --- a/PCK-Studio/MainForm.Designer.cs +++ b/PCK-Studio/MainForm.Designer.cs @@ -28,60 +28,11 @@ /// private void InitializeComponent() { - this.components = new System.ComponentModel.Container(); - System.Windows.Forms.PictureBox logoPictureBox; - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); System.Windows.Forms.ToolStripSeparator toolStripSeparator2; System.Windows.Forms.ToolStripSeparator toolStripSeparator4; this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); - this.contextMenuPCKEntries = new System.Windows.Forms.ContextMenuStrip(this.components); - this.createToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.folderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.skinToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.createAnimatedTextureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.audiopckToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.colourscolToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.CreateSkinsPCKToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.behavioursbinToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.entityMaterialsbinToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.importSkinsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.importSkinToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.importExtractedSkinsFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.addTextureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.addFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.exportToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.as3DSTextureFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.setFileTypeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.skinToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.capeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.textureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.languagesFileLOCToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.gameRulesFileGRFToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.audioPCKFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.coloursCOLFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.gameRulesHeaderGRHToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.skinsPCKToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.modelsFileBINToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.behavioursFileBINToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.entityMaterialsFileBINToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); - this.generateMipMapTextureToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.viewFileInfoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.correctSkinDecimalsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.setSubPCKEndiannessToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.bigEndianXbox360PS3WiiUToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.littleEndianPS4PSVitaSwitchToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.setModelContainerFormatToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.version1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.version2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.version3114ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); - this.extractToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.cloneFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.renameFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.replaceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.deleteFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.menuStrip = new System.Windows.Forms.MenuStrip(); this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.newToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -92,9 +43,10 @@ this.recentlyOpenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.packSettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.fullBoxSupportToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.saveToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.closeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.closeAllToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.quickChangeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -121,60 +73,24 @@ this.joinDevelopmentDiscordToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.trelloBoardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.contextMenuMetaTree = new System.Windows.Forms.ContextMenuStrip(this.components); - this.addEntryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.addEntryToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.addBOXEntryToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.addANIMEntryToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.addMultipleEntriesToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.deleteEntryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.editAllEntriesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.tabControl = new MetroFramework.Controls.MetroTabControl(); - this.openTab = new MetroFramework.Controls.MetroTabPage(); - this.pckOpen = new System.Windows.Forms.PictureBox(); - this.label5 = new MetroFramework.Controls.MetroLabel(); + this.tabControl = new PckStudio.Controls.CustomTabControl(); + this.StartPage = new MetroFramework.Controls.MetroTabPage(); this.labelVersion = new MetroFramework.Controls.MetroLabel(); + this.label5 = new MetroFramework.Controls.MetroLabel(); this.ChangelogRichTextBox = new System.Windows.Forms.RichTextBox(); + this.pckOpen = new System.Windows.Forms.PictureBox(); this.editorTab = new MetroFramework.Controls.MetroTabPage(); - this.pckFileLabel = new MetroFramework.Controls.MetroLabel(); - this.labelImageSize = new MetroFramework.Controls.MetroLabel(); - this.fileEntryCountLabel = new MetroFramework.Controls.MetroLabel(); - this.PropertiesTabControl = new MetroFramework.Controls.MetroTabControl(); - this.MetaTab = new MetroFramework.Controls.MetroTabPage(); - this.metroLabel2 = new MetroFramework.Controls.MetroLabel(); - this.treeMeta = new System.Windows.Forms.TreeView(); - this.entryTypeTextBox = new MetroFramework.Controls.MetroTextBox(); - this.entryDataTextBox = new MetroFramework.Controls.MetroTextBox(); - this.buttonEdit = new MetroFramework.Controls.MetroButton(); - this.metroLabel1 = new MetroFramework.Controls.MetroLabel(); this.label11 = new MetroFramework.Controls.MetroLabel(); - this.treeViewMain = new System.Windows.Forms.TreeView(); - this.imageList = new System.Windows.Forms.ImageList(this.components); - this.previewPictureBox = new PckStudio.ToolboxItems.InterpolationPictureBox(); - this.LittleEndianCheckBox = new MetroFramework.Controls.MetroCheckBox(); - logoPictureBox = new System.Windows.Forms.PictureBox(); toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); - ((System.ComponentModel.ISupportInitialize)(logoPictureBox)).BeginInit(); - this.contextMenuPCKEntries.SuspendLayout(); this.menuStrip.SuspendLayout(); - this.contextMenuMetaTree.SuspendLayout(); this.tabControl.SuspendLayout(); - this.openTab.SuspendLayout(); + this.StartPage.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pckOpen)).BeginInit(); this.editorTab.SuspendLayout(); - this.PropertiesTabControl.SuspendLayout(); - this.MetaTab.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.previewPictureBox)).BeginInit(); this.SuspendLayout(); // - // logoPictureBox - // - resources.ApplyResources(logoPictureBox, "logoPictureBox"); - logoPictureBox.Name = "logoPictureBox"; - logoPictureBox.TabStop = false; - // // toolStripSeparator1 // toolStripSeparator1.Name = "toolStripSeparator1"; @@ -195,332 +111,10 @@ this.toolStripSeparator3.Name = "toolStripSeparator3"; resources.ApplyResources(this.toolStripSeparator3, "toolStripSeparator3"); // - // contextMenuPCKEntries - // - this.contextMenuPCKEntries.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.createToolStripMenuItem, - this.importSkinsToolStripMenuItem, - this.exportToolStripMenuItem, - this.setFileTypeToolStripMenuItem, - this.toolStripSeparator5, - this.generateMipMapTextureToolStripMenuItem1, - this.viewFileInfoToolStripMenuItem, - this.correctSkinDecimalsToolStripMenuItem, - this.setSubPCKEndiannessToolStripMenuItem, - this.setModelContainerFormatToolStripMenuItem, - this.toolStripSeparator6, - this.extractToolStripMenuItem, - this.cloneFileToolStripMenuItem, - this.renameFileToolStripMenuItem, - this.replaceToolStripMenuItem, - this.deleteFileToolStripMenuItem}); - this.contextMenuPCKEntries.Name = "contextMenuStrip1"; - resources.ApplyResources(this.contextMenuPCKEntries, "contextMenuPCKEntries"); - this.contextMenuPCKEntries.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuPCKEntries_Opening); - // - // createToolStripMenuItem - // - this.createToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.folderToolStripMenuItem, - this.skinToolStripMenuItem, - this.createAnimatedTextureToolStripMenuItem, - this.audiopckToolStripMenuItem, - this.colourscolToolStripMenuItem, - this.CreateSkinsPCKToolStripMenuItem1, - this.behavioursbinToolStripMenuItem, - this.entityMaterialsbinToolStripMenuItem}); - resources.ApplyResources(this.createToolStripMenuItem, "createToolStripMenuItem"); - this.createToolStripMenuItem.Name = "createToolStripMenuItem"; - // - // folderToolStripMenuItem - // - resources.ApplyResources(this.folderToolStripMenuItem, "folderToolStripMenuItem"); - this.folderToolStripMenuItem.Name = "folderToolStripMenuItem"; - this.folderToolStripMenuItem.Click += new System.EventHandler(this.folderToolStripMenuItem_Click); - // - // skinToolStripMenuItem - // - resources.ApplyResources(this.skinToolStripMenuItem, "skinToolStripMenuItem"); - this.skinToolStripMenuItem.Name = "skinToolStripMenuItem"; - this.skinToolStripMenuItem.Click += new System.EventHandler(this.createSkinToolStripMenuItem_Click); - // - // createAnimatedTextureToolStripMenuItem - // - resources.ApplyResources(this.createAnimatedTextureToolStripMenuItem, "createAnimatedTextureToolStripMenuItem"); - this.createAnimatedTextureToolStripMenuItem.Name = "createAnimatedTextureToolStripMenuItem"; - this.createAnimatedTextureToolStripMenuItem.Click += new System.EventHandler(this.createAnimatedTextureToolStripMenuItem_Click); - // - // audiopckToolStripMenuItem - // - this.audiopckToolStripMenuItem.Image = global::PckStudio.Properties.Resources.BINKA_ICON; - this.audiopckToolStripMenuItem.Name = "audiopckToolStripMenuItem"; - resources.ApplyResources(this.audiopckToolStripMenuItem, "audiopckToolStripMenuItem"); - this.audiopckToolStripMenuItem.Click += new System.EventHandler(this.audiopckToolStripMenuItem_Click); - // - // colourscolToolStripMenuItem - // - this.colourscolToolStripMenuItem.Image = global::PckStudio.Properties.Resources.COL_ICON; - this.colourscolToolStripMenuItem.Name = "colourscolToolStripMenuItem"; - resources.ApplyResources(this.colourscolToolStripMenuItem, "colourscolToolStripMenuItem"); - this.colourscolToolStripMenuItem.Click += new System.EventHandler(this.colourscolToolStripMenuItem_Click); - // - // CreateSkinsPCKToolStripMenuItem1 - // - this.CreateSkinsPCKToolStripMenuItem1.Image = global::PckStudio.Properties.Resources.SKINS_ICON; - this.CreateSkinsPCKToolStripMenuItem1.Name = "CreateSkinsPCKToolStripMenuItem1"; - resources.ApplyResources(this.CreateSkinsPCKToolStripMenuItem1, "CreateSkinsPCKToolStripMenuItem1"); - this.CreateSkinsPCKToolStripMenuItem1.Click += new System.EventHandler(this.CreateSkinsPCKToolStripMenuItem1_Click); - // - // behavioursbinToolStripMenuItem - // - this.behavioursbinToolStripMenuItem.Image = global::PckStudio.Properties.Resources.BEHAVIOURS_ICON; - this.behavioursbinToolStripMenuItem.Name = "behavioursbinToolStripMenuItem"; - resources.ApplyResources(this.behavioursbinToolStripMenuItem, "behavioursbinToolStripMenuItem"); - this.behavioursbinToolStripMenuItem.Click += new System.EventHandler(this.behavioursbinToolStripMenuItem_Click); - // - // entityMaterialsbinToolStripMenuItem - // - this.entityMaterialsbinToolStripMenuItem.Image = global::PckStudio.Properties.Resources.ENTITY_MATERIALS_ICON; - this.entityMaterialsbinToolStripMenuItem.Name = "entityMaterialsbinToolStripMenuItem"; - resources.ApplyResources(this.entityMaterialsbinToolStripMenuItem, "entityMaterialsbinToolStripMenuItem"); - this.entityMaterialsbinToolStripMenuItem.Click += new System.EventHandler(this.entityMaterialsbinToolStripMenuItem_Click); - // - // importSkinsToolStripMenuItem - // - this.importSkinsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.importSkinToolStripMenuItem, - this.importExtractedSkinsFolderToolStripMenuItem, - this.addTextureToolStripMenuItem, - this.addFileToolStripMenuItem}); - resources.ApplyResources(this.importSkinsToolStripMenuItem, "importSkinsToolStripMenuItem"); - this.importSkinsToolStripMenuItem.Name = "importSkinsToolStripMenuItem"; - // - // importSkinToolStripMenuItem - // - resources.ApplyResources(this.importSkinToolStripMenuItem, "importSkinToolStripMenuItem"); - this.importSkinToolStripMenuItem.Name = "importSkinToolStripMenuItem"; - this.importSkinToolStripMenuItem.Click += new System.EventHandler(this.importSkinToolStripMenuItem_Click); - // - // importExtractedSkinsFolderToolStripMenuItem - // - resources.ApplyResources(this.importExtractedSkinsFolderToolStripMenuItem, "importExtractedSkinsFolderToolStripMenuItem"); - this.importExtractedSkinsFolderToolStripMenuItem.Name = "importExtractedSkinsFolderToolStripMenuItem"; - this.importExtractedSkinsFolderToolStripMenuItem.Click += new System.EventHandler(this.importExtractedSkinsFolder); - // - // addTextureToolStripMenuItem - // - this.addTextureToolStripMenuItem.Image = global::PckStudio.Properties.Resources.AddTexture; - this.addTextureToolStripMenuItem.Name = "addTextureToolStripMenuItem"; - resources.ApplyResources(this.addTextureToolStripMenuItem, "addTextureToolStripMenuItem"); - this.addTextureToolStripMenuItem.Click += new System.EventHandler(this.addTextureToolStripMenuItem_Click); - // - // addFileToolStripMenuItem - // - this.addFileToolStripMenuItem.Image = global::PckStudio.Properties.Resources.blank; - this.addFileToolStripMenuItem.Name = "addFileToolStripMenuItem"; - resources.ApplyResources(this.addFileToolStripMenuItem, "addFileToolStripMenuItem"); - this.addFileToolStripMenuItem.Click += new System.EventHandler(this.addFileToolStripMenuItem_Click); - // - // exportToolStripMenuItem - // - this.exportToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.as3DSTextureFileToolStripMenuItem}); - this.exportToolStripMenuItem.Name = "exportToolStripMenuItem"; - resources.ApplyResources(this.exportToolStripMenuItem, "exportToolStripMenuItem"); - // - // as3DSTextureFileToolStripMenuItem - // - this.as3DSTextureFileToolStripMenuItem.Name = "as3DSTextureFileToolStripMenuItem"; - resources.ApplyResources(this.as3DSTextureFileToolStripMenuItem, "as3DSTextureFileToolStripMenuItem"); - this.as3DSTextureFileToolStripMenuItem.Click += new System.EventHandler(this.as3DSTextureFileToolStripMenuItem_Click); - // - // setFileTypeToolStripMenuItem - // - this.setFileTypeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.skinToolStripMenuItem1, - this.capeToolStripMenuItem, - this.textureToolStripMenuItem, - this.languagesFileLOCToolStripMenuItem, - this.gameRulesFileGRFToolStripMenuItem, - this.audioPCKFileToolStripMenuItem, - this.coloursCOLFileToolStripMenuItem, - this.gameRulesHeaderGRHToolStripMenuItem, - this.skinsPCKToolStripMenuItem, - this.modelsFileBINToolStripMenuItem, - this.behavioursFileBINToolStripMenuItem, - this.entityMaterialsFileBINToolStripMenuItem}); - this.setFileTypeToolStripMenuItem.Name = "setFileTypeToolStripMenuItem"; - resources.ApplyResources(this.setFileTypeToolStripMenuItem, "setFileTypeToolStripMenuItem"); - // - // skinToolStripMenuItem1 - // - this.skinToolStripMenuItem1.Name = "skinToolStripMenuItem1"; - resources.ApplyResources(this.skinToolStripMenuItem1, "skinToolStripMenuItem1"); - // - // capeToolStripMenuItem - // - this.capeToolStripMenuItem.Name = "capeToolStripMenuItem"; - resources.ApplyResources(this.capeToolStripMenuItem, "capeToolStripMenuItem"); - // - // textureToolStripMenuItem - // - this.textureToolStripMenuItem.Name = "textureToolStripMenuItem"; - resources.ApplyResources(this.textureToolStripMenuItem, "textureToolStripMenuItem"); - // - // languagesFileLOCToolStripMenuItem - // - this.languagesFileLOCToolStripMenuItem.Name = "languagesFileLOCToolStripMenuItem"; - resources.ApplyResources(this.languagesFileLOCToolStripMenuItem, "languagesFileLOCToolStripMenuItem"); - // - // gameRulesFileGRFToolStripMenuItem - // - this.gameRulesFileGRFToolStripMenuItem.Name = "gameRulesFileGRFToolStripMenuItem"; - resources.ApplyResources(this.gameRulesFileGRFToolStripMenuItem, "gameRulesFileGRFToolStripMenuItem"); - // - // audioPCKFileToolStripMenuItem - // - this.audioPCKFileToolStripMenuItem.Name = "audioPCKFileToolStripMenuItem"; - resources.ApplyResources(this.audioPCKFileToolStripMenuItem, "audioPCKFileToolStripMenuItem"); - // - // coloursCOLFileToolStripMenuItem - // - this.coloursCOLFileToolStripMenuItem.Name = "coloursCOLFileToolStripMenuItem"; - resources.ApplyResources(this.coloursCOLFileToolStripMenuItem, "coloursCOLFileToolStripMenuItem"); - // - // gameRulesHeaderGRHToolStripMenuItem - // - this.gameRulesHeaderGRHToolStripMenuItem.Name = "gameRulesHeaderGRHToolStripMenuItem"; - resources.ApplyResources(this.gameRulesHeaderGRHToolStripMenuItem, "gameRulesHeaderGRHToolStripMenuItem"); - // - // skinsPCKToolStripMenuItem - // - this.skinsPCKToolStripMenuItem.Name = "skinsPCKToolStripMenuItem"; - resources.ApplyResources(this.skinsPCKToolStripMenuItem, "skinsPCKToolStripMenuItem"); - // - // modelsFileBINToolStripMenuItem - // - this.modelsFileBINToolStripMenuItem.Name = "modelsFileBINToolStripMenuItem"; - resources.ApplyResources(this.modelsFileBINToolStripMenuItem, "modelsFileBINToolStripMenuItem"); - // - // behavioursFileBINToolStripMenuItem - // - this.behavioursFileBINToolStripMenuItem.Name = "behavioursFileBINToolStripMenuItem"; - resources.ApplyResources(this.behavioursFileBINToolStripMenuItem, "behavioursFileBINToolStripMenuItem"); - // - // entityMaterialsFileBINToolStripMenuItem - // - this.entityMaterialsFileBINToolStripMenuItem.Name = "entityMaterialsFileBINToolStripMenuItem"; - resources.ApplyResources(this.entityMaterialsFileBINToolStripMenuItem, "entityMaterialsFileBINToolStripMenuItem"); - // - // toolStripSeparator5 - // - this.toolStripSeparator5.Name = "toolStripSeparator5"; - resources.ApplyResources(this.toolStripSeparator5, "toolStripSeparator5"); - // - // generateMipMapTextureToolStripMenuItem1 - // - this.generateMipMapTextureToolStripMenuItem1.Name = "generateMipMapTextureToolStripMenuItem1"; - resources.ApplyResources(this.generateMipMapTextureToolStripMenuItem1, "generateMipMapTextureToolStripMenuItem1"); - this.generateMipMapTextureToolStripMenuItem1.Click += new System.EventHandler(this.generateMipMapTextureToolStripMenuItem_Click); - // - // viewFileInfoToolStripMenuItem - // - this.viewFileInfoToolStripMenuItem.Name = "viewFileInfoToolStripMenuItem"; - resources.ApplyResources(this.viewFileInfoToolStripMenuItem, "viewFileInfoToolStripMenuItem"); - this.viewFileInfoToolStripMenuItem.Click += new System.EventHandler(this.viewFileInfoToolStripMenuItem_Click); - // - // correctSkinDecimalsToolStripMenuItem - // - this.correctSkinDecimalsToolStripMenuItem.Name = "correctSkinDecimalsToolStripMenuItem"; - resources.ApplyResources(this.correctSkinDecimalsToolStripMenuItem, "correctSkinDecimalsToolStripMenuItem"); - this.correctSkinDecimalsToolStripMenuItem.Click += new System.EventHandler(this.correctSkinDecimalsToolStripMenuItem_Click); - // - // setSubPCKEndiannessToolStripMenuItem - // - this.setSubPCKEndiannessToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.bigEndianXbox360PS3WiiUToolStripMenuItem, - this.littleEndianPS4PSVitaSwitchToolStripMenuItem}); - this.setSubPCKEndiannessToolStripMenuItem.Name = "setSubPCKEndiannessToolStripMenuItem"; - resources.ApplyResources(this.setSubPCKEndiannessToolStripMenuItem, "setSubPCKEndiannessToolStripMenuItem"); - // - // bigEndianXbox360PS3WiiUToolStripMenuItem - // - this.bigEndianXbox360PS3WiiUToolStripMenuItem.Name = "bigEndianXbox360PS3WiiUToolStripMenuItem"; - resources.ApplyResources(this.bigEndianXbox360PS3WiiUToolStripMenuItem, "bigEndianXbox360PS3WiiUToolStripMenuItem"); - this.bigEndianXbox360PS3WiiUToolStripMenuItem.Click += new System.EventHandler(this.bigEndianToolStripMenuItem_Click); - // - // littleEndianPS4PSVitaSwitchToolStripMenuItem - // - this.littleEndianPS4PSVitaSwitchToolStripMenuItem.Name = "littleEndianPS4PSVitaSwitchToolStripMenuItem"; - resources.ApplyResources(this.littleEndianPS4PSVitaSwitchToolStripMenuItem, "littleEndianPS4PSVitaSwitchToolStripMenuItem"); - this.littleEndianPS4PSVitaSwitchToolStripMenuItem.Click += new System.EventHandler(this.littleEndianToolStripMenuItem_Click); - // - // setModelContainerFormatToolStripMenuItem - // - this.setModelContainerFormatToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.version1ToolStripMenuItem, - this.version2ToolStripMenuItem, - this.version3114ToolStripMenuItem}); - this.setModelContainerFormatToolStripMenuItem.Name = "setModelContainerFormatToolStripMenuItem"; - resources.ApplyResources(this.setModelContainerFormatToolStripMenuItem, "setModelContainerFormatToolStripMenuItem"); - // - // version1ToolStripMenuItem - // - this.version1ToolStripMenuItem.Name = "version1ToolStripMenuItem"; - resources.ApplyResources(this.version1ToolStripMenuItem, "version1ToolStripMenuItem"); - this.version1ToolStripMenuItem.Click += new System.EventHandler(this.setModelVersion1ToolStripMenuItem_Click); - // - // version2ToolStripMenuItem - // - this.version2ToolStripMenuItem.Name = "version2ToolStripMenuItem"; - resources.ApplyResources(this.version2ToolStripMenuItem, "version2ToolStripMenuItem"); - this.version2ToolStripMenuItem.Click += new System.EventHandler(this.setModelVersion2ToolStripMenuItem_Click); - // - // version3114ToolStripMenuItem - // - this.version3114ToolStripMenuItem.Name = "version3114ToolStripMenuItem"; - resources.ApplyResources(this.version3114ToolStripMenuItem, "version3114ToolStripMenuItem"); - this.version3114ToolStripMenuItem.Click += new System.EventHandler(this.setModelVersion3ToolStripMenuItem_Click); - // - // toolStripSeparator6 - // - this.toolStripSeparator6.Name = "toolStripSeparator6"; - resources.ApplyResources(this.toolStripSeparator6, "toolStripSeparator6"); - // - // extractToolStripMenuItem - // - resources.ApplyResources(this.extractToolStripMenuItem, "extractToolStripMenuItem"); - this.extractToolStripMenuItem.Name = "extractToolStripMenuItem"; - this.extractToolStripMenuItem.Click += new System.EventHandler(this.extractToolStripMenuItem_Click); - // - // cloneFileToolStripMenuItem - // - this.cloneFileToolStripMenuItem.Name = "cloneFileToolStripMenuItem"; - resources.ApplyResources(this.cloneFileToolStripMenuItem, "cloneFileToolStripMenuItem"); - this.cloneFileToolStripMenuItem.Click += new System.EventHandler(this.cloneFileToolStripMenuItem_Click); - // - // renameFileToolStripMenuItem - // - resources.ApplyResources(this.renameFileToolStripMenuItem, "renameFileToolStripMenuItem"); - this.renameFileToolStripMenuItem.Name = "renameFileToolStripMenuItem"; - this.renameFileToolStripMenuItem.Click += new System.EventHandler(this.renameFileToolStripMenuItem_Click); - // - // replaceToolStripMenuItem - // - resources.ApplyResources(this.replaceToolStripMenuItem, "replaceToolStripMenuItem"); - this.replaceToolStripMenuItem.Name = "replaceToolStripMenuItem"; - this.replaceToolStripMenuItem.Click += new System.EventHandler(this.replaceToolStripMenuItem_Click); - // - // deleteFileToolStripMenuItem - // - resources.ApplyResources(this.deleteFileToolStripMenuItem, "deleteFileToolStripMenuItem"); - this.deleteFileToolStripMenuItem.Name = "deleteFileToolStripMenuItem"; - this.deleteFileToolStripMenuItem.Click += new System.EventHandler(this.deleteFileToolStripMenuItem_Click); - // // menuStrip // resources.ApplyResources(this.menuStrip, "menuStrip"); - this.menuStrip.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(13)))), ((int)(((byte)(13)))), ((int)(((byte)(13))))); + this.menuStrip.BackColor = System.Drawing.Color.Transparent; this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.fileToolStripMenuItem, this.editToolStripMenuItem, @@ -537,10 +131,11 @@ toolStripSeparator2, this.recentlyOpenToolStripMenuItem, toolStripSeparator4, - this.closeToolStripMenuItem, this.packSettingsToolStripMenuItem, - this.saveToolStripMenuItem1, this.saveToolStripMenuItem, + this.saveAsToolStripMenuItem, + this.closeToolStripMenuItem, + this.closeAllToolStripMenuItem, this.exitToolStripMenuItem}); this.fileToolStripMenuItem.ForeColor = System.Drawing.Color.Silver; this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; @@ -599,17 +194,18 @@ resources.ApplyResources(this.fullBoxSupportToolStripMenuItem, "fullBoxSupportToolStripMenuItem"); this.fullBoxSupportToolStripMenuItem.CheckedChanged += new System.EventHandler(this.fullBoxSupportToolStripMenuItem_CheckedChanged); // - // saveToolStripMenuItem1 - // - resources.ApplyResources(this.saveToolStripMenuItem1, "saveToolStripMenuItem1"); - this.saveToolStripMenuItem1.Name = "saveToolStripMenuItem1"; - this.saveToolStripMenuItem1.Click += new System.EventHandler(this.savePCK); - // // saveToolStripMenuItem // resources.ApplyResources(this.saveToolStripMenuItem, "saveToolStripMenuItem"); this.saveToolStripMenuItem.Name = "saveToolStripMenuItem"; - this.saveToolStripMenuItem.Click += new System.EventHandler(this.saveAsPCK); + this.saveToolStripMenuItem.Click += new System.EventHandler(this.saveToolStripMenuItem_Click); + // + // saveAsToolStripMenuItem + // + this.saveAsToolStripMenuItem.Image = global::PckStudio.Properties.Resources.Save; + this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem"; + resources.ApplyResources(this.saveAsToolStripMenuItem, "saveAsToolStripMenuItem"); + this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.saveAsToolStripMenuItem_Click); // // closeToolStripMenuItem // @@ -617,6 +213,11 @@ this.closeToolStripMenuItem.Name = "closeToolStripMenuItem"; this.closeToolStripMenuItem.Click += new System.EventHandler(this.closeToolStripMenuItem_Click); // + // closeAllToolStripMenuItem + // + this.closeAllToolStripMenuItem.Name = "closeAllToolStripMenuItem"; + resources.ApplyResources(this.closeAllToolStripMenuItem, "closeAllToolStripMenuItem"); + // // exitToolStripMenuItem // resources.ApplyResources(this.exitToolStripMenuItem, "exitToolStripMenuItem"); @@ -809,93 +410,63 @@ this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem"; this.settingsToolStripMenuItem.Click += new System.EventHandler(this.settingsToolStripMenuItem_Click); // - // contextMenuMetaTree - // - this.contextMenuMetaTree.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.addEntryToolStripMenuItem, - this.addMultipleEntriesToolStripMenuItem1, - this.deleteEntryToolStripMenuItem, - this.editAllEntriesToolStripMenuItem}); - this.contextMenuMetaTree.Name = "contextMenuStrip1"; - resources.ApplyResources(this.contextMenuMetaTree, "contextMenuMetaTree"); - // - // addEntryToolStripMenuItem - // - this.addEntryToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.addEntryToolStripMenuItem1, - this.addBOXEntryToolStripMenuItem1, - this.addANIMEntryToolStripMenuItem1}); - resources.ApplyResources(this.addEntryToolStripMenuItem, "addEntryToolStripMenuItem"); - this.addEntryToolStripMenuItem.Name = "addEntryToolStripMenuItem"; - // - // addEntryToolStripMenuItem1 - // - this.addEntryToolStripMenuItem1.Name = "addEntryToolStripMenuItem1"; - resources.ApplyResources(this.addEntryToolStripMenuItem1, "addEntryToolStripMenuItem1"); - this.addEntryToolStripMenuItem1.Click += new System.EventHandler(this.addEntryToolStripMenuItem_Click_1); - // - // addBOXEntryToolStripMenuItem1 - // - this.addBOXEntryToolStripMenuItem1.Name = "addBOXEntryToolStripMenuItem1"; - resources.ApplyResources(this.addBOXEntryToolStripMenuItem1, "addBOXEntryToolStripMenuItem1"); - this.addBOXEntryToolStripMenuItem1.Click += new System.EventHandler(this.addBOXEntryToolStripMenuItem1_Click); - // - // addANIMEntryToolStripMenuItem1 - // - this.addANIMEntryToolStripMenuItem1.Name = "addANIMEntryToolStripMenuItem1"; - resources.ApplyResources(this.addANIMEntryToolStripMenuItem1, "addANIMEntryToolStripMenuItem1"); - this.addANIMEntryToolStripMenuItem1.Click += new System.EventHandler(this.addANIMEntryToolStripMenuItem1_Click); - // - // addMultipleEntriesToolStripMenuItem1 - // - resources.ApplyResources(this.addMultipleEntriesToolStripMenuItem1, "addMultipleEntriesToolStripMenuItem1"); - this.addMultipleEntriesToolStripMenuItem1.Name = "addMultipleEntriesToolStripMenuItem1"; - this.addMultipleEntriesToolStripMenuItem1.Click += new System.EventHandler(this.addMultipleEntriesToolStripMenuItem1_Click); - // - // deleteEntryToolStripMenuItem - // - resources.ApplyResources(this.deleteEntryToolStripMenuItem, "deleteEntryToolStripMenuItem"); - this.deleteEntryToolStripMenuItem.Name = "deleteEntryToolStripMenuItem"; - this.deleteEntryToolStripMenuItem.Click += new System.EventHandler(this.deleteEntryToolStripMenuItem_Click); - // - // editAllEntriesToolStripMenuItem - // - this.editAllEntriesToolStripMenuItem.Name = "editAllEntriesToolStripMenuItem"; - resources.ApplyResources(this.editAllEntriesToolStripMenuItem, "editAllEntriesToolStripMenuItem"); - this.editAllEntriesToolStripMenuItem.Click += new System.EventHandler(this.editAllEntriesToolStripMenuItem_Click); - // // tabControl // - this.tabControl.Controls.Add(this.openTab); - this.tabControl.Controls.Add(this.editorTab); + this.tabControl.Controls.Add(this.StartPage); resources.ApplyResources(this.tabControl, "tabControl"); + this.tabControl.DrawMode = System.Windows.Forms.TabDrawMode.OwnerDrawFixed; this.tabControl.Name = "tabControl"; this.tabControl.SelectedIndex = 0; this.tabControl.Style = MetroFramework.MetroColorStyle.Silver; this.tabControl.TabStop = false; this.tabControl.Theme = MetroFramework.MetroThemeStyle.Dark; this.tabControl.UseSelectable = true; - this.tabControl.Selecting += new System.Windows.Forms.TabControlCancelEventHandler(this.tabControl_Selecting); + this.tabControl.PageClosing += new System.EventHandler(this.tabControl_PageClosing); + this.tabControl.SelectedIndexChanged += new System.EventHandler(this.tabControl_SelectedIndexChanged); // - // openTab + // StartPage // - this.openTab.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(18)))), ((int)(((byte)(18)))), ((int)(((byte)(18))))); - this.openTab.Controls.Add(this.pckOpen); - this.openTab.Controls.Add(this.label5); - this.openTab.Controls.Add(this.labelVersion); - this.openTab.Controls.Add(this.ChangelogRichTextBox); - this.openTab.ForeColor = System.Drawing.Color.Transparent; - this.openTab.HorizontalScrollbarBarColor = true; - this.openTab.HorizontalScrollbarHighlightOnWheel = false; - this.openTab.HorizontalScrollbarSize = 10; - resources.ApplyResources(this.openTab, "openTab"); - this.openTab.Name = "openTab"; - this.openTab.Style = MetroFramework.MetroColorStyle.Black; - this.openTab.Theme = MetroFramework.MetroThemeStyle.Dark; - this.openTab.UseStyleColors = true; - this.openTab.VerticalScrollbarBarColor = false; - this.openTab.VerticalScrollbarHighlightOnWheel = false; - this.openTab.VerticalScrollbarSize = 10; + this.StartPage.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(18)))), ((int)(((byte)(18)))), ((int)(((byte)(18))))); + this.StartPage.Controls.Add(this.labelVersion); + this.StartPage.Controls.Add(this.label5); + this.StartPage.Controls.Add(this.ChangelogRichTextBox); + this.StartPage.Controls.Add(this.pckOpen); + this.StartPage.ForeColor = System.Drawing.Color.Transparent; + this.StartPage.HorizontalScrollbarBarColor = true; + this.StartPage.HorizontalScrollbarHighlightOnWheel = false; + this.StartPage.HorizontalScrollbarSize = 10; + resources.ApplyResources(this.StartPage, "StartPage"); + this.StartPage.Name = "StartPage"; + this.StartPage.Style = MetroFramework.MetroColorStyle.Black; + this.StartPage.Theme = MetroFramework.MetroThemeStyle.Dark; + this.StartPage.UseStyleColors = true; + this.StartPage.VerticalScrollbarBarColor = false; + this.StartPage.VerticalScrollbarHighlightOnWheel = false; + this.StartPage.VerticalScrollbarSize = 10; + // + // labelVersion + // + resources.ApplyResources(this.labelVersion, "labelVersion"); + this.labelVersion.ForeColor = System.Drawing.Color.White; + this.labelVersion.Name = "labelVersion"; + this.labelVersion.Theme = MetroFramework.MetroThemeStyle.Dark; + // + // label5 + // + resources.ApplyResources(this.label5, "label5"); + this.label5.BackColor = System.Drawing.Color.Transparent; + this.label5.ForeColor = System.Drawing.Color.White; + this.label5.Name = "label5"; + this.label5.Theme = MetroFramework.MetroThemeStyle.Dark; + // + // ChangelogRichTextBox + // + this.ChangelogRichTextBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(13)))), ((int)(((byte)(13)))), ((int)(((byte)(13))))); + this.ChangelogRichTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None; + resources.ApplyResources(this.ChangelogRichTextBox, "ChangelogRichTextBox"); + this.ChangelogRichTextBox.ForeColor = System.Drawing.Color.White; + this.ChangelogRichTextBox.Name = "ChangelogRichTextBox"; + this.ChangelogRichTextBox.ReadOnly = true; // // pckOpen // @@ -910,42 +481,11 @@ this.pckOpen.MouseEnter += new System.EventHandler(this.OpenPck_MouseEnter); this.pckOpen.MouseLeave += new System.EventHandler(this.OpenPck_MouseLeave); // - // label5 - // - resources.ApplyResources(this.label5, "label5"); - this.label5.BackColor = System.Drawing.Color.Transparent; - this.label5.ForeColor = System.Drawing.Color.White; - this.label5.Name = "label5"; - this.label5.Theme = MetroFramework.MetroThemeStyle.Dark; - // - // labelVersion - // - resources.ApplyResources(this.labelVersion, "labelVersion"); - this.labelVersion.ForeColor = System.Drawing.Color.White; - this.labelVersion.Name = "labelVersion"; - this.labelVersion.Theme = MetroFramework.MetroThemeStyle.Dark; - // - // ChangelogRichTextBox - // - this.ChangelogRichTextBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(13)))), ((int)(((byte)(13)))), ((int)(((byte)(13))))); - this.ChangelogRichTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None; - resources.ApplyResources(this.ChangelogRichTextBox, "ChangelogRichTextBox"); - this.ChangelogRichTextBox.ForeColor = System.Drawing.Color.White; - this.ChangelogRichTextBox.Name = "ChangelogRichTextBox"; - this.ChangelogRichTextBox.ReadOnly = true; - // // editorTab // this.editorTab.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(18)))), ((int)(((byte)(18)))), ((int)(((byte)(18))))); resources.ApplyResources(this.editorTab, "editorTab"); - this.editorTab.Controls.Add(this.pckFileLabel); - this.editorTab.Controls.Add(this.labelImageSize); - this.editorTab.Controls.Add(this.fileEntryCountLabel); - this.editorTab.Controls.Add(this.PropertiesTabControl); this.editorTab.Controls.Add(this.label11); - this.editorTab.Controls.Add(this.treeViewMain); - this.editorTab.Controls.Add(logoPictureBox); - this.editorTab.Controls.Add(this.previewPictureBox); this.editorTab.ForeColor = System.Drawing.Color.Transparent; this.editorTab.HorizontalScrollbarBarColor = true; this.editorTab.HorizontalScrollbarHighlightOnWheel = false; @@ -957,202 +497,16 @@ this.editorTab.VerticalScrollbarHighlightOnWheel = false; this.editorTab.VerticalScrollbarSize = 0; // - // pckFileLabel - // - resources.ApplyResources(this.pckFileLabel, "pckFileLabel"); - this.pckFileLabel.Name = "pckFileLabel"; - this.pckFileLabel.Theme = MetroFramework.MetroThemeStyle.Dark; - // - // labelImageSize - // - resources.ApplyResources(this.labelImageSize, "labelImageSize"); - this.labelImageSize.Name = "labelImageSize"; - this.labelImageSize.Theme = MetroFramework.MetroThemeStyle.Dark; - // - // fileEntryCountLabel - // - resources.ApplyResources(this.fileEntryCountLabel, "fileEntryCountLabel"); - this.fileEntryCountLabel.Name = "fileEntryCountLabel"; - this.fileEntryCountLabel.Theme = MetroFramework.MetroThemeStyle.Dark; - // - // PropertiesTabControl - // - resources.ApplyResources(this.PropertiesTabControl, "PropertiesTabControl"); - this.PropertiesTabControl.Controls.Add(this.MetaTab); - this.PropertiesTabControl.Name = "PropertiesTabControl"; - this.PropertiesTabControl.SelectedIndex = 0; - this.PropertiesTabControl.Style = MetroFramework.MetroColorStyle.Silver; - this.PropertiesTabControl.Theme = MetroFramework.MetroThemeStyle.Dark; - this.PropertiesTabControl.UseSelectable = true; - // - // MetaTab - // - this.MetaTab.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); - this.MetaTab.Controls.Add(this.metroLabel2); - this.MetaTab.Controls.Add(this.treeMeta); - this.MetaTab.Controls.Add(this.entryTypeTextBox); - this.MetaTab.Controls.Add(this.entryDataTextBox); - this.MetaTab.Controls.Add(this.buttonEdit); - this.MetaTab.Controls.Add(this.metroLabel1); - this.MetaTab.HorizontalScrollbarBarColor = true; - this.MetaTab.HorizontalScrollbarHighlightOnWheel = false; - this.MetaTab.HorizontalScrollbarSize = 10; - resources.ApplyResources(this.MetaTab, "MetaTab"); - this.MetaTab.Name = "MetaTab"; - this.MetaTab.Theme = MetroFramework.MetroThemeStyle.Dark; - this.MetaTab.VerticalScrollbarBarColor = true; - this.MetaTab.VerticalScrollbarHighlightOnWheel = false; - this.MetaTab.VerticalScrollbarSize = 10; - // - // metroLabel2 - // - resources.ApplyResources(this.metroLabel2, "metroLabel2"); - this.metroLabel2.Name = "metroLabel2"; - this.metroLabel2.Theme = MetroFramework.MetroThemeStyle.Dark; - // - // treeMeta - // - this.treeMeta.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(13)))), ((int)(((byte)(13)))), ((int)(((byte)(13))))); - this.treeMeta.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.treeMeta.ContextMenuStrip = this.contextMenuMetaTree; - resources.ApplyResources(this.treeMeta, "treeMeta"); - this.treeMeta.ForeColor = System.Drawing.SystemColors.Window; - this.treeMeta.Name = "treeMeta"; - this.treeMeta.PathSeparator = "/"; - this.treeMeta.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeMeta_AfterSelect); - this.treeMeta.DoubleClick += new System.EventHandler(this.treeMeta_DoubleClick); - this.treeMeta.KeyDown += new System.Windows.Forms.KeyEventHandler(this.treeMeta_KeyDown); - // - // entryTypeTextBox - // - resources.ApplyResources(this.entryTypeTextBox, "entryTypeTextBox"); - // - // - // - this.entryTypeTextBox.CustomButton.Image = ((System.Drawing.Image)(resources.GetObject("resource.Image"))); - this.entryTypeTextBox.CustomButton.ImeMode = ((System.Windows.Forms.ImeMode)(resources.GetObject("resource.ImeMode"))); - this.entryTypeTextBox.CustomButton.Location = ((System.Drawing.Point)(resources.GetObject("resource.Location"))); - this.entryTypeTextBox.CustomButton.Name = ""; - this.entryTypeTextBox.CustomButton.Size = ((System.Drawing.Size)(resources.GetObject("resource.Size"))); - this.entryTypeTextBox.CustomButton.Style = MetroFramework.MetroColorStyle.Blue; - this.entryTypeTextBox.CustomButton.TabIndex = ((int)(resources.GetObject("resource.TabIndex"))); - this.entryTypeTextBox.CustomButton.Theme = MetroFramework.MetroThemeStyle.Light; - this.entryTypeTextBox.CustomButton.UseSelectable = true; - this.entryTypeTextBox.CustomButton.Visible = ((bool)(resources.GetObject("resource.Visible"))); - this.entryTypeTextBox.Lines = new string[0]; - this.entryTypeTextBox.MaxLength = 32767; - this.entryTypeTextBox.Name = "entryTypeTextBox"; - this.entryTypeTextBox.PasswordChar = '\0'; - this.entryTypeTextBox.ScrollBars = System.Windows.Forms.ScrollBars.None; - this.entryTypeTextBox.SelectedText = ""; - this.entryTypeTextBox.SelectionLength = 0; - this.entryTypeTextBox.SelectionStart = 0; - this.entryTypeTextBox.ShortcutsEnabled = true; - this.entryTypeTextBox.Theme = MetroFramework.MetroThemeStyle.Dark; - this.entryTypeTextBox.UseSelectable = true; - this.entryTypeTextBox.WaterMarkColor = System.Drawing.Color.FromArgb(((int)(((byte)(109)))), ((int)(((byte)(109)))), ((int)(((byte)(109))))); - this.entryTypeTextBox.WaterMarkFont = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Pixel); - // - // entryDataTextBox - // - resources.ApplyResources(this.entryDataTextBox, "entryDataTextBox"); - // - // - // - this.entryDataTextBox.CustomButton.Image = ((System.Drawing.Image)(resources.GetObject("resource.Image1"))); - this.entryDataTextBox.CustomButton.ImeMode = ((System.Windows.Forms.ImeMode)(resources.GetObject("resource.ImeMode1"))); - this.entryDataTextBox.CustomButton.Location = ((System.Drawing.Point)(resources.GetObject("resource.Location1"))); - this.entryDataTextBox.CustomButton.Name = ""; - this.entryDataTextBox.CustomButton.Size = ((System.Drawing.Size)(resources.GetObject("resource.Size1"))); - this.entryDataTextBox.CustomButton.Style = MetroFramework.MetroColorStyle.Blue; - this.entryDataTextBox.CustomButton.TabIndex = ((int)(resources.GetObject("resource.TabIndex1"))); - this.entryDataTextBox.CustomButton.Theme = MetroFramework.MetroThemeStyle.Light; - this.entryDataTextBox.CustomButton.UseSelectable = true; - this.entryDataTextBox.CustomButton.Visible = ((bool)(resources.GetObject("resource.Visible1"))); - this.entryDataTextBox.Lines = new string[0]; - this.entryDataTextBox.MaxLength = 32767; - this.entryDataTextBox.Name = "entryDataTextBox"; - this.entryDataTextBox.PasswordChar = '\0'; - this.entryDataTextBox.ScrollBars = System.Windows.Forms.ScrollBars.None; - this.entryDataTextBox.SelectedText = ""; - this.entryDataTextBox.SelectionLength = 0; - this.entryDataTextBox.SelectionStart = 0; - this.entryDataTextBox.ShortcutsEnabled = true; - this.entryDataTextBox.Theme = MetroFramework.MetroThemeStyle.Dark; - this.entryDataTextBox.UseSelectable = true; - this.entryDataTextBox.WaterMarkColor = System.Drawing.Color.FromArgb(((int)(((byte)(109)))), ((int)(((byte)(109)))), ((int)(((byte)(109))))); - this.entryDataTextBox.WaterMarkFont = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Pixel); - // - // buttonEdit - // - resources.ApplyResources(this.buttonEdit, "buttonEdit"); - this.buttonEdit.Name = "buttonEdit"; - this.buttonEdit.Theme = MetroFramework.MetroThemeStyle.Dark; - this.buttonEdit.UseSelectable = true; - this.buttonEdit.Click += new System.EventHandler(this.treeViewMain_DoubleClick); - // - // metroLabel1 - // - resources.ApplyResources(this.metroLabel1, "metroLabel1"); - this.metroLabel1.Name = "metroLabel1"; - this.metroLabel1.Theme = MetroFramework.MetroThemeStyle.Dark; - // // label11 // resources.ApplyResources(this.label11, "label11"); this.label11.Name = "label11"; // - // treeViewMain - // - this.treeViewMain.AllowDrop = true; - resources.ApplyResources(this.treeViewMain, "treeViewMain"); - this.treeViewMain.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(12)))), ((int)(((byte)(12)))), ((int)(((byte)(12))))); - this.treeViewMain.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.treeViewMain.ContextMenuStrip = this.contextMenuPCKEntries; - this.treeViewMain.ForeColor = System.Drawing.Color.White; - this.treeViewMain.ImageList = this.imageList; - this.treeViewMain.LabelEdit = true; - this.treeViewMain.Name = "treeViewMain"; - this.treeViewMain.PathSeparator = "/"; - this.treeViewMain.BeforeLabelEdit += new System.Windows.Forms.NodeLabelEditEventHandler(this.treeViewMain_BeforeLabelEdit); - this.treeViewMain.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.treeViewMain_ItemDrag); - this.treeViewMain.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeViewMain_AfterSelect); - this.treeViewMain.DragDrop += new System.Windows.Forms.DragEventHandler(this.treeViewMain_DragDrop); - this.treeViewMain.DragEnter += new System.Windows.Forms.DragEventHandler(this.treeViewMain_DragEnter); - this.treeViewMain.DragOver += new System.Windows.Forms.DragEventHandler(this.treeViewMain_DragOver); - this.treeViewMain.DoubleClick += new System.EventHandler(this.treeViewMain_DoubleClick); - this.treeViewMain.KeyDown += new System.Windows.Forms.KeyEventHandler(this.treeViewMain_KeyDown); - this.treeViewMain.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeViewMain_NodeMouseClick); - // - // imageList - // - this.imageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit; - resources.ApplyResources(this.imageList, "imageList"); - this.imageList.TransparentColor = System.Drawing.Color.Transparent; - // - // previewPictureBox - // - resources.ApplyResources(this.previewPictureBox, "previewPictureBox"); - this.previewPictureBox.BackColor = System.Drawing.Color.Transparent; - this.previewPictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; - this.previewPictureBox.Name = "previewPictureBox"; - this.previewPictureBox.TabStop = false; - // - // LittleEndianCheckBox - // - resources.ApplyResources(this.LittleEndianCheckBox, "LittleEndianCheckBox"); - this.LittleEndianCheckBox.BackColor = System.Drawing.Color.Transparent; - this.LittleEndianCheckBox.Name = "LittleEndianCheckBox"; - this.LittleEndianCheckBox.Style = MetroFramework.MetroColorStyle.White; - this.LittleEndianCheckBox.Theme = MetroFramework.MetroThemeStyle.Dark; - this.LittleEndianCheckBox.UseSelectable = true; - // // MainForm // this.ApplyImageInvert = true; resources.ApplyResources(this, "$this"); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.LittleEndianCheckBox); this.Controls.Add(this.menuStrip); this.Controls.Add(this.tabControl); this.DisplayHeader = false; @@ -1164,21 +518,14 @@ this.Theme = MetroFramework.MetroThemeStyle.Dark; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing); this.Load += new System.EventHandler(this.MainForm_Load); - ((System.ComponentModel.ISupportInitialize)(logoPictureBox)).EndInit(); - this.contextMenuPCKEntries.ResumeLayout(false); this.menuStrip.ResumeLayout(false); this.menuStrip.PerformLayout(); - this.contextMenuMetaTree.ResumeLayout(false); this.tabControl.ResumeLayout(false); - this.openTab.ResumeLayout(false); - this.openTab.PerformLayout(); + this.StartPage.ResumeLayout(false); + this.StartPage.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.pckOpen)).EndInit(); this.editorTab.ResumeLayout(false); this.editorTab.PerformLayout(); - this.PropertiesTabControl.ResumeLayout(false); - this.MetaTab.ResumeLayout(false); - this.MetaTab.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.previewPictureBox)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -1188,88 +535,31 @@ private System.Windows.Forms.MenuStrip menuStrip; private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem; - private System.Windows.Forms.ContextMenuStrip contextMenuPCKEntries; - private System.Windows.Forms.ToolStripMenuItem extractToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem renameFileToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem replaceToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem deleteFileToolStripMenuItem; - private System.Windows.Forms.ContextMenuStrip contextMenuMetaTree; - private System.Windows.Forms.ToolStripMenuItem addEntryToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem deleteEntryToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem addMultipleEntriesToolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem saveAsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem newToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem quickChangeToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem1; - private System.Windows.Forms.ToolStripMenuItem importSkinsToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem importSkinToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem exportToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem importExtractedSkinsFolderToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem createToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem folderToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem skinToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem createAnimatedTextureToolStripMenuItem; - private MetroFramework.Controls.MetroTabControl tabControl; + private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem; + private PckStudio.Controls.CustomTabControl tabControl; private MetroFramework.Controls.MetroTabPage editorTab; - private MetroFramework.Controls.MetroCheckBox LittleEndianCheckBox; private MetroFramework.Controls.MetroLabel label11; - private System.Windows.Forms.ToolStripMenuItem audiopckToolStripMenuItem; - private System.Windows.Forms.TreeView treeViewMain; - private MetroFramework.Controls.MetroTabControl PropertiesTabControl; - private System.Windows.Forms.TreeView treeMeta; - private MetroFramework.Controls.MetroLabel metroLabel1; - private MetroFramework.Controls.MetroLabel metroLabel2; - private MetroFramework.Controls.MetroTextBox entryDataTextBox; - private MetroFramework.Controls.MetroLabel fileEntryCountLabel; - private PckStudio.ToolboxItems.InterpolationPictureBox previewPictureBox; - private MetroFramework.Controls.MetroLabel labelImageSize; - private MetroFramework.Controls.MetroButton buttonEdit; private System.Windows.Forms.ToolStripMenuItem skinPackToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem texturePackToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem mashUpPackToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem closeToolStripMenuItem; - private System.Windows.Forms.ImageList imageList; - private MetroFramework.Controls.MetroTextBox entryTypeTextBox; - private MetroFramework.Controls.MetroTabPage MetaTab; - private System.Windows.Forms.ToolStripMenuItem cloneFileToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem setFileTypeToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem skinToolStripMenuItem1; - private System.Windows.Forms.ToolStripMenuItem capeToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem textureToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem languagesFileLOCToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem gameRulesFileGRFToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem audioPCKFileToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem coloursCOLFileToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem gameRulesHeaderGRHToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem skinsPCKToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem modelsFileBINToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem behavioursFileBINToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem entityMaterialsFileBINToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem addTextureToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem as3DSTextureFileToolStripMenuItem; - private MetroFramework.Controls.MetroTabPage openTab; + private System.Windows.Forms.ToolStripMenuItem closeAllToolStripMenuItem; + private MetroFramework.Controls.MetroTabPage StartPage; private System.Windows.Forms.PictureBox pckOpen; private MetroFramework.Controls.MetroLabel label5; private MetroFramework.Controls.MetroLabel labelVersion; private System.Windows.Forms.RichTextBox ChangelogRichTextBox; - private System.Windows.Forms.ToolStripMenuItem colourscolToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem miscToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem CreateSkinsPCKToolStripMenuItem1; - private System.Windows.Forms.ToolStripMenuItem editAllEntriesToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem addFileToolStripMenuItem; - private MetroFramework.Controls.MetroLabel pckFileLabel; - private System.Windows.Forms.ToolStripMenuItem behavioursbinToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem entityMaterialsbinToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem convertMusicFilesToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem wavBinkaToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem binkaWavToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem openPckManagerToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem packSettingsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem fullBoxSupportToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem addEntryToolStripMenuItem1; - private System.Windows.Forms.ToolStripMenuItem addBOXEntryToolStripMenuItem1; - private System.Windows.Forms.ToolStripMenuItem addANIMEntryToolStripMenuItem1; private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem videosToolStripMenuItem; @@ -1291,18 +581,6 @@ private System.Windows.Forms.ToolStripMenuItem trelloBoardToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem recentlyOpenToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator5; - private System.Windows.Forms.ToolStripMenuItem generateMipMapTextureToolStripMenuItem1; - private System.Windows.Forms.ToolStripMenuItem viewFileInfoToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem correctSkinDecimalsToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem setSubPCKEndiannessToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem bigEndianXbox360PS3WiiUToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem littleEndianPS4PSVitaSwitchToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem setModelContainerFormatToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem version1ToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem version2ToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem version3114ToolStripMenuItem; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator6; } } diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index 687dd1d8..300609d0 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -1,74 +1,40 @@ using System; -using System.Collections.Generic; -using System.Drawing; using System.IO; using System.Linq; -using System.Windows.Forms; -using System.Drawing.Drawing2D; using System.Diagnostics; -using System.Drawing.Imaging; +using System.Windows.Forms; +using System.Collections.Generic; using System.Text.RegularExpressions; using OMI.Formats.Pck; -using OMI.Formats.Model; using OMI.Formats.GameRule; -using OMI.Formats.Material; -using OMI.Formats.Behaviour; using OMI.Formats.Languages; -using OMI.Workers; using OMI.Workers.Pck; using OMI.Workers.GameRule; using OMI.Workers.Language; -using OMI.Workers.Model; -using OMI.Workers.Behaviour; -using OMI.Workers.Material; using PckStudio.Properties; -using PckStudio.FileFormats; using PckStudio.Forms; -using PckStudio.Forms.Editor; -using PckStudio.Forms.Additional_Popups.Animation; using PckStudio.Forms.Additional_Popups; -using PckStudio.Internal.Misc; -using PckStudio.Internal.IO.PckAudio; -using PckStudio.Internal.IO._3DST; -using PckStudio.Internal; +using PckStudio.Core.Misc; using PckStudio.Forms.Features; -using PckStudio.Extensions; +using PckStudio.Core.Extensions; using PckStudio.Popups; using PckStudio.External.API.Miles; -using PckStudio.Internal.Json; -using PckStudio.Internal.Deserializer; -using PckStudio.Internal.Serializer; using PckStudio.Internal.App; +using PckStudio.Interfaces; +using PckStudio.Controls; +using PckStudio.Internal; +using PckStudio.Core; +using PckStudio.Core.App; namespace PckStudio { public partial class MainForm : MetroFramework.Forms.MetroForm { private PckManager PckManager = null; - string saveLocation; - PckFile currentPCK = null; + private Dictionary openTabPages = new Dictionary(); - bool __modified = false; - bool wasModified - { - get => __modified; - set - { - if (__modified == value) - return; - __modified = value; - pckFileLabel.Text = !pckFileLabel.Text.StartsWith("*") && __modified ? "*" + pckFileLabel.Text : pckFileLabel.Text.Substring(1); - } - } - - bool isTemplateFile = false; - - bool isSelectingTab = false; - - readonly Dictionary> pckFileTypeHandler; - - public MainForm() + public MainForm() { InitializeComponent(); @@ -79,133 +45,186 @@ namespace PckStudio ChangelogRichTextBox.Text = Resources.CHANGELOG; pckOpen.AllowDrop = true; - - treeViewMain.TreeViewNodeSorter = new PckNodeSorter(); - - skinToolStripMenuItem1.Click += (sender, e) => SetFileType(PckAssetType.SkinFile); - capeToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.CapeFile); - textureToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.TextureFile); - languagesFileLOCToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.LocalisationFile); - gameRulesFileGRFToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.GameRulesFile); - audioPCKFileToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.AudioFile); - coloursCOLFileToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.ColourTableFile); - gameRulesHeaderGRHToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.GameRulesHeader); - skinsPCKToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.SkinDataFile); - modelsFileBINToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.ModelsFile); - behavioursFileBINToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.BehavioursFile); - entityMaterialsFileBINToolStripMenuItem.Click += (sender, e) => SetFileType(PckAssetType.MaterialFile); - - - pckFileTypeHandler = new Dictionary>(15) - { - [PckAssetType.SkinFile] = HandleSkinFile, - [PckAssetType.CapeFile] = null, - [PckAssetType.TextureFile] = HandleTextureFile, - [PckAssetType.UIDataFile] = _ => throw new NotSupportedException("unused in-game"), - [PckAssetType.InfoFile] = null, - [PckAssetType.TexturePackInfoFile] = null, // HandleInnerPckFile, - [PckAssetType.LocalisationFile] = HandleLocalisationFile, - [PckAssetType.GameRulesFile] = HandleGameRuleFile, - [PckAssetType.AudioFile] = HandleAudioFile, - [PckAssetType.ColourTableFile] = HandleColourFile, - [PckAssetType.GameRulesHeader] = HandleGameRuleFile, - [PckAssetType.SkinDataFile] = null, // HandleInnerPckFile, - [PckAssetType.ModelsFile] = null, //HandleModelsFile, // Note: Uncomment when implemented - [PckAssetType.BehavioursFile] = HandleBehavioursFile, - [PckAssetType.MaterialFile] = HandleMaterialFile, - }; } - // TODO: decide on how to handle embedded pck files - private void HandleInnerPckFile(PckAsset asset) + public void LoadPckFromFile(IEnumerable filepaths) { - if (Settings.Default.LoadSubPcks && - (asset.Type == PckAssetType.SkinDataFile || asset.Type == PckAssetType.TexturePackInfoFile) && - asset.Size > 0 && treeViewMain.SelectedNode.Nodes.Count == 0) - { - try - { - PckFile subPCKfile = asset.GetData(new PckFileReader(LittleEndianCheckBox.Checked ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian)); - BuildPckTreeView(treeViewMain.SelectedNode.Nodes, subPCKfile); - treeViewMain.SelectedNode.ExpandAll(); - } - catch (OverflowException ex) - { - MessageBox.Show(this, "Failed to open pck\n" + - "Try checking the 'Open/Save as Switch/Vita/PS4/Xbox One pck' checkbox in the upper right corner.", - "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - Debug.WriteLine(ex.Message); - } - return; - } - treeViewMain.SelectedNode.Nodes.Clear(); - treeViewMain.SelectedNode.Collapse(); + foreach (string filepath in filepaths) + { + LoadPckFromFile(filepath); + } } - public void InitPckFromFile(string filepath) + public void LoadPckFromFile(string filepath) + { + AddEditorPage(filepath); + } + + internal void OpenNewPckTab(string caption, string identifier, PackInfo packInfo, ISaveContext saveContext) { - saveLocation = filepath; - } + if (openTabPages.ContainsKey(identifier)) + { + tabControl.SelectTab(openTabPages[identifier]); + return; + } + var editor = new PckEditor(packInfo, saveContext); + AddPage(caption, identifier, editor); + } - public void LoadPckFromFile(string filepath) + private void AddEditorPage(string caption, string identifier, PackInfo packInfo, ISaveContext saveContext = null) + { + saveContext ??= GetDefaultSaveContext("./new.pck", "PCK (Minecraft Console Package)"); + var editor = new PckEditor(packInfo, saveContext); + AddPage(caption, identifier, editor); + } + + private PckFile ReadPck(string filePath, OMI.ByteOrder byteOrder) + { + var pckReader = new PckFileReader(byteOrder); + return pckReader.FromFile(filePath); + } + + private bool TryOpenPck(string filepath, out PackInfo packInfo) + { + if (!File.Exists(filepath) || !filepath.EndsWith(".pck")) + { + packInfo = PackInfo.Empty; + return false; + } + try + { + OMI.ByteOrder byteOrder = OMI.ByteOrder.BigEndian; + PckFile pckFile = ReadPck(filepath, byteOrder); + packInfo = PackInfo.Create(pckFile, byteOrder, true); + return packInfo.IsValid; + } + catch (OverflowException) + { + try + { + // if failed, attempt again in the reverse. THEN throw an error if failed + OMI.ByteOrder byteOrder = OMI.ByteOrder.LittleEndian; + PckFile pckFile = ReadPck(filepath, byteOrder); + packInfo = PackInfo.Create(pckFile, byteOrder, true); + return packInfo.IsValid; + } + catch (OverflowException ex) + { + MessageBox.Show(this, "Failed to open pck", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + Debug.WriteLine(ex.Message); + } + } + catch + { + MessageBox.Show(this, "Failed to open pck. There's two common reasons for this:\n" + + "1. The file is audio/music cues PCK file. Please use the specialized editor while inside of a pck file.\n" + + "2. We're aware of an issue where a pck file might fail to load because it contains multiple entries with the same path.", + "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + packInfo = PackInfo.Empty; + return false; + } + + private void AddEditorPage(string filepath) + { + if (!File.Exists(filepath) && !filepath.EndsWith(".pck")) + { + Trace.TraceError($"[{nameof(AddEditorPage)}] Invalid filepath({filepath})"); + return; + } + + if (openTabPages.ContainsKey(filepath)) + { + tabControl.SelectTab(openTabPages[filepath]); + return; + } + SaveToRecentFiles(filepath); + + if (TryOpenPck(filepath, out PackInfo packInfo)) + { + ISaveContext saveContext = GetDefaultSaveContext(filepath, "PCK (Minecraft Console Package)"); + var editor = new PckEditor(packInfo, saveContext); + TabPage page = AddPage(Path.GetFileName(filepath), filepath, editor); + return; + } + MessageBox.Show(string.Format("Failed to load {0}", Path.GetFileName(filepath)), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + private static ISaveContext GetDefaultSaveContext(string filepath, string description) + { + return new DelegatedFileSaveContext(filepath, false, new FileDialogFilter(description, "*"+Path.GetExtension(filepath)),(packInfo, stream) => new PckFileWriter(packInfo.File, packInfo.Endianness).WriteToStream(stream)); + } + + private TabPage AddPage(string caption, string identifier, Control control) + { + identifier ??= caption; + if (openTabPages.ContainsKey(identifier)) + return openTabPages[identifier]; + control.Dock = DockStyle.Fill; + var page = new TabPage(caption); + page.Name = identifier; + page.Controls.Add(control); + tabControl.TabPages.Add(page); + tabControl.SelectTab(page); + return page; + } + + private bool TryGetEditor(TabPage page, out IEditor editor) + { + if (page.Controls[0] is IEditor outEditor) + { + editor = outEditor; + return true; + } + editor = default; + return false; + } + + private bool TryGetCurrentEditor(out IEditor editor) => TryGetEditor(tabControl.SelectedTab, out editor); + + private void MainForm_Load(object sender, EventArgs e) { - CheckSaveState(); - treeViewMain.Nodes.Clear(); - currentPCK = OpenPck(filepath); - if (currentPCK == null) - { - MessageBox.Show(this, string.Format("Failed to load {0}", Path.GetFileName(filepath)), "Error"); - return; - } - - CheckForPasswordAndRemove(); - LoadEditorTab(); - } - - private void MainForm_Load(object sender, EventArgs e) - { - SettingsManager.Default.RegisterPropertyChangedCallback(nameof(Settings.Default.UseLittleEndianAsDefault), state => - { - LittleEndianCheckBox.Checked = state; - }); - SettingsManager.Default.RegisterPropertyChangedCallback(nameof(Settings.Default.LoadSubPcks), () => - { - if (currentPCK is not null) - { - BuildMainTreeView(); - } - }); - - imageList.Images.Add(Resources.ZZFolder); // Icon for folders - imageList.Images.Add(Resources.BINKA_ICON); // Icon for music cue file (audio.pck) - imageList.Images.Add(Resources.IMAGE_ICON); // Icon for images (unused for now) - imageList.Images.Add(Resources.LOC_ICON); // Icon for string localization files (languages.loc;localisation.loc) - imageList.Images.Add(Resources.PCK_ICON); // Icon for generic PCK files (*.pck) - imageList.Images.Add(Resources.ZUnknown); // Icon for Unknown formats - imageList.Images.Add(Resources.COL_ICON); // Icon for color palette files (colours.col) - imageList.Images.Add(Resources.SKINS_ICON); // Icon for Skin.pck archives (skins.pck) - imageList.Images.Add(Resources.MODELS_ICON); // Icon for Model files (models.bin) - imageList.Images.Add(Resources.GRF_ICON); // Icon for Game Rule files (*.grf) - imageList.Images.Add(Resources.GRH_ICON); // Icon for Game Rule Header files (*.grh) - imageList.Images.Add(Resources.INFO_ICON); // Icon for Info files (0) - imageList.Images.Add(Resources.SKIN_ICON); // Icon for Skin files (*.png) - imageList.Images.Add(Resources.CAPE_ICON); // Icon for Cape files (*.png) - imageList.Images.Add(Resources.TEXTURE_ICON); // Icon for Texture files (*.png;*.tga) - imageList.Images.Add(Resources.BEHAVIOURS_ICON); // Icon for Behaviour files (behaviours.bin) - imageList.Images.Add(Resources.ENTITY_MATERIALS_ICON); // Icon for Entity Material files (entityMaterials.bin) - LoadRecentFileList(); - - isSelectingTab = true; - tabControl.SelectTab(0); - isSelectingTab = false; - - UpdateRichPresence(); - - if (!string.IsNullOrWhiteSpace(saveLocation)) - LoadPckFromFile(saveLocation); } + private void MainForm_FormClosing(object sender, FormClosingEventArgs e) + { + PckManager?.Close(); + closeAllToolStripMenuItem_Click(sender, e); + } + + private void closeAllToolStripMenuItem_Click(object sender, EventArgs e) + { + foreach (TabPage tab in tabControl.TabPages) + { + CloseTab(tabControl.TabPages, tab); + } + closeAllToolStripMenuItem.Visible = false; + } + + private void CloseTab(TabControl.TabPageCollection collection, TabPage page) + { + if (TryGetEditor(page, out IEditor editor)) + { + editor.Close(); + RemoveOpenFile(page); + collection.Remove(page); + } + } + + private void RemoveOpenFile() + { + RemoveOpenFile(tabControl.SelectedTab); + } + + private void RemoveOpenFile(TabPage page) + { + if (openTabPages.ContainsKey(page.Name)) + { + openTabPages.Remove(page.Name); + } + } + private void LoadRecentFileList() { Settings.Default.RecentFiles ??= new System.Collections.Specialized.StringCollection(); @@ -226,7 +245,7 @@ namespace PckStudio { Settings.Default.RecentFiles.Clear(); LoadRecentFileList(); - } + } recentlyOpenToolStripMenuItem.DropDownItems.Add(new ToolStripSeparator()); recentlyOpenToolStripMenuItem.DropDownItems.Add("Clear", null, clearRecentFileList); } @@ -261,12 +280,6 @@ namespace PckStudio LoadRecentFileList(); } - private void MainForm_FormClosing(object sender, FormClosingEventArgs e) - { - PckManager?.Close(); - CheckSaveState(); - } - private void openPckManagerToolStripMenuItem_Click(object sender, EventArgs e) { PckManager ??= new PckManager(); @@ -291,1202 +304,29 @@ namespace PckStudio } } - private PckFile ReadPck(string filePath, bool isLittleEndian) - { - var pckReader = new PckFileReader(isLittleEndian ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian); - return pckReader.FromFile(filePath); - } - - private PckFile OpenPck(string filePath) - { - isTemplateFile = false; - saveLocation = filePath; - SaveToRecentFiles(filePath); - PckFile pck; - try - { - pck = ReadPck(filePath, LittleEndianCheckBox.Checked); - return pck; - } - catch (OverflowException c) - { - try - { - // if failed, attempt again in the reverse. THEN throw an error if failed - pck = ReadPck(filePath, !LittleEndianCheckBox.Checked); - LittleEndianCheckBox.Checked = !LittleEndianCheckBox.Checked; - return pck; - } - catch (OverflowException ex) - { - MessageBox.Show(this, "Failed to open pck\n" + - $"Try {(LittleEndianCheckBox.Checked ? "unchecking" : "checking")} the 'Open/Save as Switch/Vita/PS4/Xbox One pck' check box in the upper right corner.", - "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - Debug.WriteLine(ex.Message); - } - } - catch - { - MessageBox.Show(this, "Failed to open pck. There's two common reasons for this:\n" + - "1. The file is audio/music cues PCK file. Please use the specialized editor while inside of a pck file.\n" + - "2. We're aware of an issue where a pck file might fail to load because it contains multiple entries with the same path.", - "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - return null; - } - - private void CheckForPasswordAndRemove() - { - if (currentPCK.TryGetAsset("0", PckAssetType.InfoFile, out PckAsset asset)) - { - asset.RemoveProperties("LOCK"); - } - } - - private void LoadEditorTab() - { - fileEntryCountLabel.Text = "Files:" + currentPCK.AssetCount; - if (isTemplateFile) - pckFileLabel.Text = "Unsaved File!"; - else - pckFileLabel.Text = Path.GetFileName(saveLocation); - treeViewMain.Enabled = treeMeta.Enabled = true; - closeToolStripMenuItem.Visible = true; - fullBoxSupportToolStripMenuItem.Checked = currentPCK.HasVerionString; - packSettingsToolStripMenuItem.Visible = true; - - saveToolStripMenuItem.Enabled = true; - saveToolStripMenuItem1.Enabled = true; - quickChangeToolStripMenuItem.Enabled = true; - BuildMainTreeView(); - isSelectingTab = true; - tabControl.SelectTab(1); - isSelectingTab = false; - UpdateRichPresence(); - } - - private void CloseEditorTab() - { - isSelectingTab = true; - tabControl.SelectTab(0); - isSelectingTab = false; - currentPCK = null; - wasModified = false; - isTemplateFile = false; - saveLocation = string.Empty; - previewPictureBox.Image = Resources.NoImageFound; - treeViewMain.Nodes.Clear(); - treeMeta.Nodes.Clear(); - treeViewMain.Enabled = false; - treeMeta.Enabled = false; - saveToolStripMenuItem.Enabled = false; - saveToolStripMenuItem1.Enabled = false; - quickChangeToolStripMenuItem.Enabled = false; - closeToolStripMenuItem.Visible = false; - packSettingsToolStripMenuItem.Visible = false; - fileEntryCountLabel.Text = string.Empty; - pckFileLabel.Text = string.Empty; - UpdateRichPresence(); - } - - private void UpdateRichPresence() - { - if (currentPCK is not null && - TryGetLocFile(out LOCFile locfile) && - locfile.HasLocEntry("IDS_DISPLAY_NAME") && - locfile.Languages.Contains("en-EN")) - { - RPC.SetPresence($"Editing a Pack: {locfile.GetLocEntry("IDS_DISPLAY_NAME", "en-EN")}"); - return; - } - // default - RPC.SetPresence("An Open Source .PCK File Editor"); - } - - /// - /// wrapper that allows the use of in TreeNode.Nodes.Find(, ...) and TreeNode.Nodes.ContainsKey() - /// - /// - /// - /// new Created TreeNode - public static TreeNode CreateNode(string name, object tag = null) - { - TreeNode node = new TreeNode(name); - node.Name = name; - node.Tag = tag; - return node; - } - - private TreeNode BuildNodeTreeBySeperator(TreeNodeCollection root, string path, char seperator) - { - _ = root ?? throw new ArgumentNullException(nameof(root)); - if (!path.Contains(seperator)) - { - TreeNode finalNode = CreateNode(path); - root.Add(finalNode); - return finalNode; - } - string nodeText = path.Substring(0, path.IndexOf(seperator)); - string subPath = path.Substring(path.IndexOf(seperator) + 1); - - if (string.IsNullOrWhiteSpace(nodeText)) - { - return BuildNodeTreeBySeperator(root, subPath, seperator); - } - - bool alreadyExists = root.ContainsKey(nodeText); - TreeNode subNode = alreadyExists ? root[nodeText] : CreateNode(nodeText); - if (!alreadyExists) - root.Add(subNode); - return BuildNodeTreeBySeperator(subNode.Nodes, subPath, seperator); - } - - private void BuildPckTreeView(TreeNodeCollection root, PckFile pckFile) - { - foreach (PckAsset asset in pckFile.GetAssets()) - { - // fix any file paths that may be incorrect - //if (file.Filename.StartsWith(parentPath)) - // file.Filename = file.Filename.Remove(0, parentPath.Length); - TreeNode node = BuildNodeTreeBySeperator(root, asset.Filename, '/'); - node.Tag = asset; - SetNodeIcon(node, asset.Type); - } - } - - private void BuildMainTreeView() - { - // In case the Rename function was just used and the selected node name no longer matches the file name - string selectedNodeText = treeViewMain.SelectedNode is TreeNode node ? node.FullPath : string.Empty; - previewPictureBox.Image = Resources.NoImageFound; - treeMeta.Nodes.Clear(); - treeViewMain.Nodes.Clear(); - BuildPckTreeView(treeViewMain.Nodes, currentPCK); - - //if (isTemplateFile && currentPCK.HasAsset("Skins.pck", PckAssetType.SkinDataFile)) - //{ - // TreeNode skinsNode = treeViewMain.Nodes.Find("Skins.pck", false).FirstOrDefault(); - // TreeNode folderNode = CreateNode("Skins"); - // folderNode.ImageIndex = 0; - // folderNode.SelectedImageIndex = 0; - // if (!skinsNode.Nodes.ContainsKey("Skins")) - // skinsNode.Nodes.Add(folderNode); - //} - treeViewMain.Sort(); - - TreeNode[] selectedNodes = treeViewMain.FindPath(selectedNodeText); - if (selectedNodes.Length > 0) - { - treeViewMain.SelectedNode = selectedNodes[0]; - } - } - - private void HandleTextureFile(PckAsset asset) - { - _ = asset.IsMipmappedFile() && currentPCK.TryGetValue(asset.GetNormalPath(), PckAssetType.TextureFile, out asset); - - if (asset.Size <= 0) - { - Debug.WriteLine($"'{asset.Filename}' size is 0.", category: nameof(HandleTextureFile)); - return; - } - - ResourceLocation resourceLocation = ResourceLocation.GetFromPath(asset.Filename); - Debug.WriteLine("Handling Resource file: " + resourceLocation?.ToString()); - - switch (resourceLocation.Category) - { - case ResourceCategory.Unknown: - Debug.WriteLine($"Unknown Resource Category."); - break; - case ResourceCategory.ItemAnimation: - case ResourceCategory.BlockAnimation: - Animation animation = asset.GetDeserializedData(AnimationDeserializer.DefaultDeserializer); - string internalName = Path.GetFileNameWithoutExtension(asset.Filename); - IList textureInfos = resourceLocation.Category == ResourceCategory.ItemAnimation ? Tiles.ItemTileInfos : Tiles.BlockTileInfos; - string displayname = textureInfos.FirstOrDefault(p => p.InternalName == internalName)?.DisplayName ?? internalName; - - string[] specialTileNames = { "clock", "compass" }; - using (AnimationEditor animationEditor = new AnimationEditor(animation, displayname, internalName.ToLower().EqualsAny(specialTileNames))) - { - if (animationEditor.ShowDialog(this) == DialogResult.OK) - { - wasModified = true; - asset.SetSerializedData(animationEditor.Result, AnimationSerializer.DefaultSerializer); - BuildMainTreeView(); - } - } - break; - case ResourceCategory.ItemAtlas: - case ResourceCategory.BlockAtlas: - case ResourceCategory.ParticleAtlas: - case ResourceCategory.BannerAtlas: - case ResourceCategory.PaintingAtlas: - case ResourceCategory.ExplosionAtlas: - case ResourceCategory.ExperienceOrbAtlas: - case ResourceCategory.MoonPhaseAtlas: - case ResourceCategory.MapIconAtlas: - case ResourceCategory.AdditionalMapIconsAtlas: - Image img = asset.GetTexture(); - var viewer = new TextureAtlasEditor(currentPCK, resourceLocation, img); - if (viewer.ShowDialog(this) == DialogResult.OK) - { - Image texture = viewer.FinalTexture; - asset.SetTexture(texture); - wasModified = true; - BuildMainTreeView(); - } - break; - default: - Debug.WriteLine($"Unhandled Resource Category: {resourceLocation.Category}"); - break; - } - } - - private void HandleGameRuleFile(PckAsset asset) - { - const string use_deflate = "PS3"; - const string use_xmem = "Xbox 360"; - const string use_zlib = "Other Platforms"; - - ItemSelectionPopUp dialog = new ItemSelectionPopUp(use_zlib, use_deflate, use_xmem); - dialog.LabelText = "Type"; - dialog.ButtonText = "Ok"; - if (dialog.ShowDialog() != DialogResult.OK) - return; - - GameRuleFile.CompressionType compressiontype = dialog.SelectedItem switch - { - use_deflate => GameRuleFile.CompressionType.Deflate, - use_xmem => GameRuleFile.CompressionType.XMem, - use_zlib => GameRuleFile.CompressionType.Zlib, - _ => GameRuleFile.CompressionType.Unknown - }; - - GameRuleFile grf = asset.GetData(new GameRuleFileReader(compressiontype)); - - using GameRuleFileEditor grfEditor = new GameRuleFileEditor(grf); - if (grfEditor.ShowDialog(this) == DialogResult.OK) - { - asset.SetData(new GameRuleFileWriter(grfEditor.Result)); - wasModified = true; - UpdateRichPresence(); - } - } - - private void HandleAudioFile(PckAsset asset) - { - try - { - using AudioEditor audioEditor = new AudioEditor(asset, LittleEndianCheckBox.Checked); - wasModified = audioEditor.ShowDialog(this) == DialogResult.OK; - } - catch (OverflowException) - { - MessageBox.Show(this, $"Failed to open {asset.Filename}\n" + - "Try converting the file by using the \"Misc. Functions/Set PCK Endianness\" tool and try again.", - "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - catch (Exception ex) - { - MessageBox.Show($"Failed to open {asset.Filename}\n" + ex.Message, - "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - - private void HandleLocalisationFile(PckAsset asset) - { - using LOCEditor locedit = new LOCEditor(asset); - wasModified = locedit.ShowDialog(this) == DialogResult.OK; - UpdateRichPresence(); - } - - private void HandleColourFile(PckAsset asset) - { - using COLEditor diag = new COLEditor(asset); - wasModified = diag.ShowDialog(this) == DialogResult.OK; - } - - public void HandleSkinFile(PckAsset asset) - { - if (asset.HasProperty("BOX")) - { - using generateModel generate = new generateModel(asset); - if (generate.ShowDialog(this) == DialogResult.OK) - { - entryDataTextBox.Text = entryTypeTextBox.Text = string.Empty; - wasModified = true; - ReloadMetaTreeView(); - } - return; - } - - Image img = asset.GetTexture(); - using var skinViewer = new SkinPreview(img, asset.GetProperty("ANIM", SkinANIM.FromString)); - skinViewer.ShowDialog(this); - } - - public void HandleModelsFile(PckAsset asset) - { - MessageBox.Show(this, "Models.bin support has not been implemented. You can use the Spark Editor for the time being to edit these files.", "Not implemented yet."); - } - - public void HandleBehavioursFile(PckAsset asset) - { - using BehaviourEditor edit = new BehaviourEditor(asset); - wasModified = edit.ShowDialog(this) == DialogResult.OK; - } - - public void HandleMaterialFile(PckAsset asset) - { - using MaterialsEditor edit = new MaterialsEditor(asset); - wasModified = edit.ShowDialog(this) == DialogResult.OK; - } - - private void treeViewMain_AfterSelect(object sender, TreeViewEventArgs e) - { - ReloadMetaTreeView(); - - entryTypeTextBox.Text = entryDataTextBox.Text = labelImageSize.Text = string.Empty; - buttonEdit.Visible = false; - - previewPictureBox.Image = Resources.NoImageFound; - viewFileInfoToolStripMenuItem.Visible = false; - - if (e.Node.TryGetTagData(out PckAsset asset)) - { - viewFileInfoToolStripMenuItem.Visible = true; - if (asset.HasProperty("BOX")) - { - buttonEdit.Text = "EDIT BOXES"; - buttonEdit.Visible = true; - } - else if (asset.HasProperty("ANIM") && - asset.GetProperty("ANIM", s => SkinANIM.FromString(s) == (SkinAnimMask.RESOLUTION_64x64 | SkinAnimMask.SLIM_MODEL))) - { - buttonEdit.Text = "View Skin"; - buttonEdit.Visible = true; - } - - switch (asset.Type) - { - case PckAssetType.SkinFile: - case PckAssetType.CapeFile: - case PckAssetType.TextureFile: - { - Image img = asset.GetTexture(); - - if (img.RawFormat != ImageFormat.Jpeg || img.RawFormat != ImageFormat.Png) - { - img = new Bitmap(img); - } - - try - { - previewPictureBox.Image = img; - labelImageSize.Text = $"{previewPictureBox.Image.Size.Width}x{previewPictureBox.Image.Size.Height}"; - } - catch (Exception ex) - { - labelImageSize.Text = ""; - previewPictureBox.Image = Resources.NoImageFound; - Debug.WriteLine("Not a supported image format. Setting back to default"); - Debug.WriteLine(string.Format("An error occured of type: {0} with message: {1}", ex.GetType(), ex.Message), "Exception"); - } - - if (asset.Type != PckAssetType.TextureFile) - break; - - ResourceLocation resourceLocation = ResourceLocation.GetFromPath(asset.Filename); - if (resourceLocation is null || resourceLocation.Category == ResourceCategory.Unknown) - break; - - if (resourceLocation.Category == ResourceCategory.ItemAnimation || - resourceLocation.Category == ResourceCategory.BlockAnimation && - !asset.IsMipmappedFile()) - { - buttonEdit.Text = "EDIT TILE ANIMATION"; - buttonEdit.Visible = true; - break; - } - - buttonEdit.Text = "EDIT TEXTURE ATLAS"; - buttonEdit.Visible = true; - } - break; - - case PckAssetType.LocalisationFile: - buttonEdit.Text = "EDIT LOC"; - buttonEdit.Visible = true; - break; - - case PckAssetType.AudioFile: - buttonEdit.Text = "EDIT MUSIC CUES"; - buttonEdit.Visible = true; - break; - - case PckAssetType.ColourTableFile when asset.Filename == "colours.col": - buttonEdit.Text = "EDIT COLORS"; - buttonEdit.Visible = true; - break; - - case PckAssetType.BehavioursFile when asset.Filename == "behaviours.bin": - buttonEdit.Text = "EDIT BEHAVIOURS"; - buttonEdit.Visible = true; - break; - default: - buttonEdit.Visible = false; - break; - } - } - } - - private void extractFile(string outFilePath, PckAsset asset) + private void tabControl_PageClosing(object sender, PageClosingEventArgs e) { - File.WriteAllBytes(outFilePath, asset.Data); - if (asset.PropertyCount > 0) - { - File.WriteAllLines($"{outFilePath}.txt", asset.SerializeProperties()); - } - } + if (TryGetEditor(e.Page, out IEditor editor)) + { + editor.Close(); + RemoveOpenFile(); + } + } - private void extractFolderFile(string outPath, PckAsset asset) + private void tabControl_SelectedIndexChanged(object sender, EventArgs e) { - TreeNode node = treeViewMain.SelectedNode; + closeToolStripMenuItem.Visible = tabControl.SelectedIndex > 0; + closeAllToolStripMenuItem.Visible = tabControl.SelectedIndex == 0 && tabControl.TabCount > 1; + saveToolStripMenuItem.Visible = tabControl.SelectedIndex > 0; + saveAsToolStripMenuItem.Visible = tabControl.SelectedIndex > 0; - // abb = "Abbreviated Path" - string abbPath = Path.GetDirectoryName(asset.Filename); - int startIndex = abbPath.IndexOf(node.Text); - abbPath = abbPath.Substring(startIndex, abbPath.Length - startIndex); - string finalPath = ($"{outPath}/{abbPath}/").Replace('\\', '/'); - - if (!Directory.Exists(finalPath)) - Directory.CreateDirectory(finalPath); - - extractFile(finalPath + "/" + Path.GetFileName(asset.Filename), asset); - } - - private void extractFolder(string outPath) - { - TreeNode node = treeViewMain.SelectedNode; - - string selectedFolder = node.FullPath; - - foreach (PckAsset asset in currentPCK.GetAssets().Where(asset => asset.Filename.StartsWith(selectedFolder))) + if (tabControl.SelectedIndex == 0) { - extractFolderFile(outPath, asset); - } - } - - private void extractToolStripMenuItem_Click(object sender, EventArgs e) - { - TreeNode node = treeViewMain.SelectedNode; - - if (node == null) - { - MessageBox.Show(this, "The selected node was null. Please select a node and try again.", "Node not extracted"); - - return; - } - - if (node.Tag == null) - { - OpenFolderDialog dialog = new OpenFolderDialog(); - dialog.Title = @"Select destination folder"; - - if (dialog.ShowDialog(Handle) == true) - extractFolder(dialog.ResultPath); - } - else if (node.TryGetTagData(out PckAsset asset)) - { - using SaveFileDialog exFile = new SaveFileDialog(); - exFile.FileName = Path.GetFileName(asset.Filename); - exFile.Filter = Path.GetExtension(asset.Filename).Replace(".", string.Empty) + " File|*" + Path.GetExtension(asset.Filename); - if (exFile.ShowDialog(this) != DialogResult.OK || - // Makes sure chosen directory isn't null or whitespace AKA makes sure its usable - string.IsNullOrWhiteSpace(Path.GetDirectoryName(exFile.FileName))) - { - MessageBox.Show(this, "The chosen directory is invalid. Please choose a different one and try again.", "Node not extracted"); - - return; - } - - extractFile(exFile.FileName, asset); - } - - // Verification that file extraction path was successful - MessageBox.Show(this, $"\"{node.Text}\" successfully extracted"); - } - - private void SaveTemplate() - { - using SaveFileDialog saveFileDialog = new SaveFileDialog(); - saveFileDialog.Filter = "PCK (Minecraft Console Package)|*.pck"; - saveFileDialog.DefaultExt = ".pck"; - if (saveFileDialog.ShowDialog(this) == DialogResult.OK) - { - Save(saveFileDialog.FileName); - saveLocation = saveFileDialog.FileName; - SaveToRecentFiles(saveFileDialog.FileName); - pckFileLabel.Text = Path.GetFileName(saveLocation); - isTemplateFile = false; - } - } - - private void Save(string filePath) - { - var writer = new PckFileWriter(currentPCK, LittleEndianCheckBox.Checked ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian); - writer.WriteToFile(filePath); - wasModified = false; - MessageBox.Show(this, "Saved Pck file", "File Saved"); - } - - private void replaceToolStripMenuItem_Click(object sender, EventArgs e) - { - if (treeViewMain.SelectedNode.Tag is PckAsset asset) - { - using var ofd = new OpenFileDialog(); - // Suddenly, and randomly, this started throwing an exception because it wasn't formatted correctly? So now it's formatted correctly and now displays the file type name in the dialog. - - string extra_extensions = ""; - - switch (asset.Type) - { - case PckAssetType.TextureFile: - if (Path.GetExtension(asset.Filename) == ".png") - extra_extensions = ";*.tga"; - else if (Path.GetExtension(asset.Filename) == ".tga") - extra_extensions = ";*.png"; - break; - } - - string fileExt = Path.GetExtension(asset.Filename); - - ofd.Filter = $"{asset.Type} (*{fileExt}{extra_extensions})|*{fileExt}{extra_extensions}"; - if (ofd.ShowDialog(this) == DialogResult.OK) - { - string newFileExt = Path.GetExtension(ofd.FileName); - asset.SetData(File.ReadAllBytes(ofd.FileName)); - asset.Filename = asset.Filename.Replace(fileExt, newFileExt); - wasModified = true; - BuildMainTreeView(); - } - return; - } - MessageBox.Show(this, "Can't replace a folder."); - } - - /// - /// Action to run before an asset will be deleted - /// - /// Asset to remove - /// True if the remove should be canceled, otherwise False - private bool BeforeFileRemove(PckAsset asset) - { - string itemPath = ResourceLocation.GetPathFromCategory(ResourceCategory.ItemAnimation); - - // warn the user about deleting compass.png and clock.png - if (asset.Type == PckAssetType.TextureFile && - (asset.Filename == itemPath + "/compass.png" || asset.Filename == itemPath + "/clock.png")) - { - if (MessageBox.Show(this, "Are you sure want to delete this file? If \"compass.png\" or \"clock.png\" are missing, your game will crash upon loading this pack.", "Warning", - MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) - return true; - } - - // remove loc key if its a skin/cape - if (asset.Type == PckAssetType.SkinFile || asset.Type == PckAssetType.CapeFile) - { - if (TryGetLocFile(out LOCFile locFile)) - { - if (asset.TryGetProperty("THEMENAMEID", out string value)) - locFile.RemoveLocKey(value); - if (asset.TryGetProperty("DISPLAYNAMEID", out value)) - locFile.RemoveLocKey(value); - TrySetLocFile(locFile); - } - } - return false; - } - - private void deleteFileToolStripMenuItem_Click(object sender, EventArgs e) - { - TreeNode node = treeViewMain.SelectedNode; - if (node == null) - return; - - string path = node.FullPath; - - if (node.TryGetTagData(out PckAsset asset)) - { - if (!BeforeFileRemove(asset) && currentPCK.RemoveAsset(asset)) - { - node.Remove(); - wasModified = true; - } - } - else if (MessageBox.Show(this, "Are you sure want to delete this folder? All contents will be deleted", "Warning", - MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) - { - string pckFolderDir = node.FullPath; - currentPCK.RemoveAll(file => file.Filename.StartsWith(pckFolderDir) && !BeforeFileRemove(file)); - node.Remove(); - wasModified = true; - } - } - - private void renameFileToolStripMenuItem_Click(object sender, EventArgs e) - { - TreeNode node = treeViewMain.SelectedNode; - if (node == null) - return; - string path = node.FullPath; - - bool isFile = node.TryGetTagData(out PckAsset asset); - - using TextPrompt diag = new TextPrompt(isFile ? asset.Filename : Path.GetFileName(node.FullPath)); - - if (diag.ShowDialog(this) == DialogResult.OK) - { - if (isFile) - { - if (currentPCK.Contains(diag.NewText, asset.Type)) - { - MessageBox.Show(this, $"{diag.NewText} already exists", "File already exists"); - return; - } - asset.Filename = diag.NewText; - } - else // folders - { - node.Text = diag.NewText; - foreach (TreeNode childNode in GetAllChildNodes(node.Nodes)) - { - if (childNode.Tag is PckAsset folderAsset) - { - if (folderAsset.Filename == diag.NewText) - continue; - folderAsset.Filename = childNode.FullPath; - } - } - } - wasModified = true; - BuildMainTreeView(); - } - } - - private void createSkinToolStripMenuItem_Click(object sender, EventArgs e) - { - LOCFile locFile = null; - TryGetLocFile(out locFile); - using AddSkinPrompt add = new AddSkinPrompt(locFile); - if (add.ShowDialog(this) == DialogResult.OK) - { - //if (currentPCK.HasAsset("Skins.pck", PckAssetType.SkinDataFile)) // Prioritize Skins.pck - //{ - // TreeNode subPCK = treeViewMain.Nodes.Find("Skins.pck", false).FirstOrDefault(); - // if (subPCK.Nodes.ContainsKey("Skins")) add.SkinAsset.Filename = add.SkinAsset.Filename.Insert(0, "Skins/"); - // add.SkinAsset.Filename = add.SkinAsset.Filename.Insert(0, "Skins.pck/"); - // TreeNode newNode = new TreeNode(Path.GetFileName(add.SkinAsset.Filename)); - // newNode.Tag = add.SkinAsset; - // SetNodeIcon(newNode, PckAssetType.SkinFile); - // subPCK.Nodes.Add(newNode); - // RebuildSubPCK(newNode.FullPath); - //} - //else - { - if (treeViewMain.Nodes.ContainsKey("Skins")) - add.SkinAsset.Filename = add.SkinAsset.Filename.Insert(0, "Skins/"); // Then Skins folder - currentPCK.AddAsset(add.SkinAsset); - } - if (add.HasCape) - { - //if (currentPCK.HasAsset("Skins.pck", PckAssetType.SkinDataFile)) // Prioritize Skins.pck - //{ - // TreeNode subPCK = treeViewMain.Nodes.Find("Skins.pck", false).FirstOrDefault(); - // if (subPCK.Nodes.ContainsKey("Skins")) add.CapeAsset.Filename = add.CapeAsset.Filename.Insert(0, "Skins/"); - // add.CapeAsset.Filename = add.CapeAsset.Filename.Insert(0, "Skins.pck/"); - // TreeNode newNode = new TreeNode(Path.GetFileName(add.CapeAsset.Filename)); - // newNode.Tag = add.CapeAsset; - // SetNodeIcon(newNode, PckAssetType.SkinFile); - // subPCK.Nodes.Add(newNode); - // RebuildSubPCK(newNode.FullPath); - //} - //else - { - if (treeViewMain.Nodes.ContainsKey("Skins")) - add.CapeAsset.Filename = add.CapeAsset.Filename.Insert(0, "Skins/"); // Then Skins folder - currentPCK.AddAsset(add.CapeAsset); - } - } - - TrySetLocFile(locFile); - wasModified = true; - BuildMainTreeView(); - } - } - - private static PckAsset CreateNewAudioFile(bool isLittle) - { - PckAudioFile audioPck = new PckAudioFile(); - audioPck.AddCategory(PckAudioFile.AudioCategory.EAudioType.Overworld); - audioPck.AddCategory(PckAudioFile.AudioCategory.EAudioType.Nether); - audioPck.AddCategory(PckAudioFile.AudioCategory.EAudioType.End); - PckAsset newAsset = new PckAsset("audio.pck", PckAssetType.AudioFile); - newAsset.SetData(new PckAudioFileWriter(audioPck, isLittle ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian)); - return newAsset; - } - - private void audiopckToolStripMenuItem_Click(object sender, EventArgs e) - { - if (currentPCK.Contains(PckAssetType.AudioFile)) - { - // the chance of this happening is really really slim but just in case - MessageBox.Show(this, "There is already an audio file in this PCK!", "Can't create audio.pck"); - return; - } - if (string.IsNullOrEmpty(saveLocation)) - { - MessageBox.Show(this, "You must save your pck before creating or opening a music cues PCK file", "Can't create audio.pck"); - return; - } - - PckAsset asset = CreateNewAudioFile(LittleEndianCheckBox.Checked); - AudioEditor diag = new AudioEditor(asset, LittleEndianCheckBox.Checked); - if (diag.ShowDialog(this) == DialogResult.OK) - { - currentPCK.AddAsset(asset); - } - diag.Dispose(); - BuildMainTreeView(); - } - - private void createAnimatedTextureToolStripMenuItem_Click(object sender, EventArgs e) - { - using ChangeTile diag = new ChangeTile(); - if (diag.ShowDialog(this) != DialogResult.OK) - return; - - string animationFilepath = $"{ResourceLocation.GetPathFromCategory(diag.Category)}/{diag.SelectedTile.InternalName}.png"; - - if (currentPCK.Contains(animationFilepath, PckAssetType.TextureFile)) - { - MessageBox.Show(this, $"{diag.SelectedTile.DisplayName} is already present.", "File already present"); - return; - } - - using AnimationEditor animationEditor = new AnimationEditor(Animation.CreateEmpty(), diag.SelectedTile.DisplayName, diag.SelectedTile.InternalName.EqualsAny("clock", "compass")); - if (animationEditor.ShowDialog() == DialogResult.OK) - { - wasModified = true; - PckAsset asset = currentPCK.CreateNewAsset(animationFilepath, PckAssetType.TextureFile); - asset.SetSerializedData(animationEditor.Result, AnimationSerializer.DefaultSerializer); - BuildMainTreeView(); - ReloadMetaTreeView(); - } - } - - private void treeViewMain_DoubleClick(object sender, EventArgs e) - { - if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset)) - { - if (asset.Size <= 0) - { - Trace.WriteLine($"'{asset.Filename}' has no data attached.", category: nameof(treeViewMain_DoubleClick)); - return; - } - pckFileTypeHandler[asset.Type]?.Invoke(asset); - } - } - - private void treeMeta_AfterSelect(object sender, TreeViewEventArgs e) - { - if (e.Node is TreeNode t && t.Tag is KeyValuePair property) - { - entryTypeTextBox.Text = property.Key; - entryDataTextBox.Text = property.Value; - } - } - - private void treeMeta_DoubleClick(object sender, EventArgs e) - { - if (treeMeta.SelectedNode is TreeNode subnode && subnode.Tag is KeyValuePair property && - treeViewMain.SelectedNode is TreeNode node && node.Tag is PckAsset asset) - { - if (asset.HasProperty(property.Key)) - { - switch (property.Key) - { - case "ANIM" when asset.Type == PckAssetType.SkinFile: - try - { - using ANIMEditor diag = new ANIMEditor(SkinANIM.FromString(property.Value)); - if (diag.ShowDialog(this) == DialogResult.OK) - { - asset.SetProperty(asset.GetPropertyIndex(property), new KeyValuePair("ANIM", diag.ResultAnim.ToString())); - ReloadMetaTreeView(); - wasModified = true; - } - return; - } - catch (Exception ex) - { - Debug.WriteLine(ex.Message); - Trace.WriteLine("Invalid ANIM value: " + property.Value); - MessageBox.Show(this, "Failed to parse ANIM value, aborting to normal functionality. Please make sure the value only includes hexadecimal characters (0-9,A-F) and has no more than 8 characters."); - } - break; - - case "BOX" when asset.Type == PckAssetType.SkinFile: - try - { - using BoxEditor diag = new BoxEditor(property.Value, false); - if (diag.ShowDialog(this) == DialogResult.OK) - { - asset.SetProperty(asset.GetPropertyIndex(property), new KeyValuePair("BOX", diag.Result.ToString())); - ReloadMetaTreeView(); - wasModified = true; - } - return; - } - catch (Exception ex) - { - Debug.WriteLine(ex.Message); - Trace.WriteLine("Invalid BOX value: " + property.Value); - MessageBox.Show(this, "Failed to parse BOX value, aborting to normal functionality."); - } - break; - - default: - break; - - } - - using (AddPropertyPrompt addProperty = new AddPropertyPrompt(property)) - { - if (addProperty.ShowDialog(this) == DialogResult.OK) - { - asset.SetProperty(asset.GetPropertyIndex(property), addProperty.Property); - ReloadMetaTreeView(); - wasModified = true; - } - } - } - } - } - - private void cloneFileToolStripMenuItem_Click(object sender, EventArgs e) - { - TreeNode node = treeViewMain.SelectedNode; - if (node == null || !node.IsTagOfType()) - return; - string path = node.FullPath; - - using TextPrompt diag = new TextPrompt(node.Tag is null ? Path.GetFileName(node.FullPath) : node.FullPath); - diag.contextLabel.Text = $"Creating a clone of \"{path}\". Ensure that the path isn't yet."; - diag.OKButtonText = "Clone"; - - if (diag.ShowDialog(this) == DialogResult.OK) - { - if (node.Tag is PckAsset asset) - { - TreeNode newNode = new TreeNode(); - newNode.Text = Path.GetFileName(diag.NewText); - var newFile = new PckAsset(diag.NewText, asset.Type); - foreach (KeyValuePair property in asset.GetProperties()) - { - newFile.AddProperty(property); - } - newFile.SetData(asset.Data); - newFile.Filename = diag.NewText; - newNode.Tag = newFile; - newNode.ImageIndex = node.ImageIndex; - newNode.SelectedImageIndex = node.SelectedImageIndex; - - if (GetAllChildNodes(treeViewMain.Nodes).FirstOrDefault(n => n.FullPath == diag.NewText) is not null) - { - MessageBox.Show( - this, - $"A file with the path \"{diag.NewText}\" already exists. " + - $"Please try again with a different name.", - "Key already exists"); - return; - } - - TreeNodeCollection nodeCollection = node.Parent?.Nodes ?? treeViewMain.Nodes; - nodeCollection.Insert(node.Index + 1, newNode); - - currentPCK.InsertAsset(node.Index + 1, newFile); - BuildMainTreeView(); - wasModified = true; - } - } - } - - private void deleteEntryToolStripMenuItem_Click(object sender, EventArgs e) - { - if (treeMeta.SelectedNode is TreeNode t && t.Tag is KeyValuePair property && - treeViewMain.SelectedNode is TreeNode main && main.Tag is PckAsset asset && - asset.RemoveProperty(property)) - { - treeMeta.SelectedNode.Remove(); - wasModified = true; - } - } - - private void ReloadMetaTreeView() - { - treeMeta.Nodes.Clear(); - if (treeViewMain.SelectedNode is TreeNode node && - node.Tag is PckAsset asset) - { - foreach (KeyValuePair property in asset.GetProperties()) - { - treeMeta.Nodes.Add(CreateNode(property.Key, property)); - } - } - } - - private void addEntryToolStripMenuItem_Click_1(object sender, EventArgs e) - { - if (treeViewMain.SelectedNode is TreeNode t && - t.Tag is PckAsset asset) - { - using AddPropertyPrompt addProperty = new AddPropertyPrompt(); - if (addProperty.ShowDialog(this) == DialogResult.OK) - { - asset.AddProperty(addProperty.Property); - ReloadMetaTreeView(); - wasModified = true; - } - } - } - - #region drag and drop for main tree node - - // Most of the code below is modified code from this link: - // https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.treeview.itemdrag?view=windowsdesktop-6.0 - // - MattNL - - private void treeViewMain_ItemDrag(object sender, ItemDragEventArgs e) - { - if (e.Button != MouseButtons.Left || e.Item is not TreeNode node) - return; - - if ((node.TryGetTagData(out PckAsset asset) && currentPCK.Contains(asset.Filename, asset.Type)) || node.Parent is TreeNode) - { - // TODO: add (mouse) scrolling while dragging item(s) - treeViewMain.DoDragDrop(node, DragDropEffects.Scroll | DragDropEffects.Move); + RPC.SetPresence("An Open Source .PCK File Editor"); } } - private void treeViewMain_DragOver(object sender, DragEventArgs e) - { - Point dragLocation = new Point(e.X, e.Y); - TreeNode node = treeViewMain.GetNodeAt(treeViewMain.PointToClient(dragLocation)); - treeViewMain.SelectedNode = node.IsTagOfType() ? null : node; - } - - private void treeViewMain_DragEnter(object sender, DragEventArgs e) - { - e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : e.AllowedEffect; - BringToFront(); - FocusMe(); - treeViewMain.Focus(); - } - - private void treeViewMain_DragDrop(object sender, DragEventArgs e) - { - // Retrieve the client coordinates of the drop location. - Point dragLocation = new Point(e.X, e.Y); - Point targetPoint = treeViewMain.PointToClient(dragLocation); - - if (!treeViewMain.ClientRectangle.Contains(targetPoint)) - return; - - // Retrieve the node at the drop location. - TreeNode targetNode = treeViewMain.GetNodeAt(targetPoint); - - if (e.Data.GetDataPresent(DataFormats.FileDrop) && e.Data.GetData(DataFormats.FileDrop) is string[] filesDropped) - { - IEnumerable files = filesDropped.Where(File.Exists); - IEnumerable directoryFiles = filesDropped - .Where(f => (File.GetAttributes(f) & FileAttributes.Directory) != 0) - .SelectMany(dir => Directory.GetFiles(dir, "*.*", SearchOption.AllDirectories)); - - string baseDirectory = Path.GetDirectoryName(filesDropped.First()); - - IEnumerable importPaths = files.Concat(directoryFiles); - - ImportFiles(baseDirectory, importPaths, string.IsNullOrWhiteSpace(targetNode?.FullPath) ? string.Empty : targetNode?.FullPath); - return; - } - - string dataFormat = typeof(TreeNode).FullName; - - if (targetNode is null) - return; - - if (!e.Data.GetDataPresent(dataFormat)) - return; - - bool isTargetPckFile = targetNode.IsTagOfType(); - TreeNode draggedNode = e.Data.GetData(dataFormat) as TreeNode; - if (draggedNode == null) - { - Debug.WriteLine("Dragged node is null."); - return; - } - - if (targetNode.Equals(draggedNode)) - { - Debug.WriteLine("Dragged node was not moved."); - return; - } - - if (targetNode.Equals(draggedNode.Parent)) - { - Debug.WriteLine("target node is parent of dragged node... nothing done."); - return; - } - - if (draggedNode.Equals(targetNode.Parent)) - { - Debug.WriteLine("dragged node is parent of target node... nothing done."); - return; - } - - if (targetNode.Parent == null && isTargetPckFile && draggedNode.Parent == null) - { - Debug.WriteLine("target node is file and is in the root... nothing done."); - return; - } - - if ((targetNode.Parent?.Equals(draggedNode.Parent) ?? false) && isTargetPckFile) - { - Debug.WriteLine("target node and dragged node have the same parent... nothing done."); - return; - } - - Debug.WriteLine($"Target drop location is {(isTargetPckFile ? "file" : "folder")}."); - - // Retrieve the node that was dragged. - if (draggedNode.TryGetTagData(out PckAsset draggedAsset) && - targetNode.FullPath != draggedAsset.Filename) - { - Debug.WriteLine(draggedAsset.Filename + " was droped onto " + targetNode.FullPath); - string newFilePath = Path.Combine(isTargetPckFile - ? Path.GetDirectoryName(targetNode.FullPath) - : targetNode.FullPath, Path.GetFileName(draggedAsset.Filename)); - Debug.WriteLine("New filepath: " + newFilePath); - draggedAsset.Filename = newFilePath; - wasModified = true; - BuildMainTreeView(); - return; - } - else - { - IEnumerable pckFiles = GetAllChildNodes(draggedNode.Nodes).Where(t => t.IsTagOfType()).Select(t => t.Tag as PckAsset); - string oldPath = draggedNode.FullPath; - string newPath = Path.Combine(isTargetPckFile ? Path.GetDirectoryName(targetNode.FullPath) : targetNode.FullPath, draggedNode.Text).Replace('\\', '/'); - foreach (PckAsset pckFile in pckFiles) - { - pckFile.Filename = Path.Combine(newPath, pckFile.Filename.Substring(oldPath.Length + 1)).Replace('\\', '/'); - } - wasModified = true; - BuildMainTreeView(); - } - } - - IEnumerable GetAllChildNodes(TreeNodeCollection root) - { - List childNodes = new List(root.Count); - foreach (TreeNode childNode in root) - { - childNodes.Add(childNode); - childNodes.AddRange(GetAllChildNodes(childNode.Nodes)); - } - return childNodes; - } - - private void ImportFiles(string baseDirectory, IEnumerable files, string prefix) - { - int fileCount = files.Count(); - int addedCount = 0; - int skippedFiles = 0; - int skipAttempts = 3; - int typeDuplication = 0; - PckAssetType lastSelectedAssetType = PckAssetType.SkinFile; - bool askForAssetType = true; - foreach (var filepath in files) - { - string assetPath = Path.Combine(prefix + filepath.Substring(baseDirectory.Length)).TrimStart('/', '\\'); - PckAssetType assetType = lastSelectedAssetType; - - if (askForAssetType) - { - using AddFilePrompt addFile = new AddFilePrompt(assetPath); - if (addFile.ShowDialog(this) != DialogResult.OK) - { - skippedFiles++; - skipAttempts--; - if (skipAttempts > 0) - continue; - - int remainingFileCount = fileCount - addedCount - skippedFiles; - DialogResult abortFurtherImport = MessageBox.Show($"Do you wan't to abort further file imports?\n{remainingFileCount} file(s) left.", "Abort further import", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); - if (abortFurtherImport == DialogResult.Yes) - { - skippedFiles += remainingFileCount; - break; - } - skipAttempts = 3; - continue; - } - - assetType = addFile.Filetype; - assetPath = addFile.Filepath; - - if (lastSelectedAssetType == assetType) - typeDuplication++; - lastSelectedAssetType = addFile.Filetype; - if (typeDuplication > 1) - { - DialogResult useSameTypeForRest = MessageBox.Show($"Do you want to import all remaining files as {lastSelectedAssetType}?", "Import all as", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); - if (useSameTypeForRest == DialogResult.Yes) - { - askForAssetType = false; - } - } - } - - if (currentPCK.Contains(filepath, assetType)) - { - if (askForAssetType) - MessageBox.Show(this, $"'{assetPath}' of type {assetType} already exists.\nSkiping file.", "File already exists", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1); - Debug.WriteLine($"'{assetPath}' of type {assetType} already exists.\nSkiping file."); - continue; - } - PckAsset importedAsset = currentPCK.CreateNewAsset(assetPath, assetType, () => File.ReadAllBytes(filepath)); - string propertyFile = filepath + ".txt"; - if (File.Exists(propertyFile)) - { - importedAsset.DeserializeProperties(File.ReadAllLines(propertyFile)); - } - addedCount++; - } - Trace.TraceInformation("[{0}] Imported {1} file(s).", nameof(ImportFiles), addedCount); - Trace.TraceInformation("[{0}] Skipped {1} file(s).", nameof(ImportFiles), skippedFiles); - if (addedCount > 0) - { - wasModified = true; - BuildMainTreeView(); - } - } - - #endregion - - private PckFile InitializePack(int packId, int packVersion, string packName, bool createSkinsPCK) + private static PckFile InitializePack(int packId, int packVersion, string packName, bool createSkinsPCK) { var pack = new PckFile(3); @@ -1498,38 +338,35 @@ namespace PckStudio locFile.InitializeDefault(packName); pack.CreateNewAsset("localisation.loc", PckAssetType.LocalisationFile, new LOCFileWriter(locFile, 2)); - pack.CreateNewAssetIf(createSkinsPCK, "Skins.pck", PckAssetType.SkinDataFile, new PckFileWriter(new PckFile(3, true), - LittleEndianCheckBox.Checked - ? OMI.Endianness.LittleEndian - : OMI.Endianness.BigEndian)); + pack.CreateNewAssetIf(createSkinsPCK, "Skins.pck", PckAssetType.SkinDataFile, new PckFileWriter(new PckFile(3, true), OMI.ByteOrder.BigEndian)); return pack; } - private PckFile InitializeTexturePack(int packId, int packVersion, string packName, string res, bool createSkinsPCK) + private static PckFile InitializeTexturePack(int packId, int packVersion, string packName, string res, bool createSkinsPCK) { PckFile pack = InitializePack(packId, packVersion, packName, createSkinsPCK); PckFile infoPCK = new PckFile(3); - pack.GetAsset("localisation.loc", PckAssetType.LocalisationFile).Filename = "languages.loc"; + pack.GetAsset("localisation.loc", PckAssetType.LocalisationFile).Filename = "languages.loc"; PckAsset iconAsset = infoPCK.CreateNewAsset("icon.png", PckAssetType.TextureFile); - iconAsset.SetTexture(Resources.TexturePackIcon); + iconAsset.SetTexture(Core.Properties.Resources.TexturePackIcon); PckAsset comparisonAsset = infoPCK.CreateNewAsset("comparison.png", PckAssetType.TextureFile); - comparisonAsset.SetTexture(Resources.Comparison); + comparisonAsset.SetTexture(Core.Properties.Resources.Comparison); PckAsset texturepackInfoAsset = pack.CreateNewAsset($"{res}/{res}Info.pck", PckAssetType.TexturePackInfoFile); texturepackInfoAsset.AddProperty("PACKID", "0"); texturepackInfoAsset.AddProperty("DATAPATH", $"{res}Data.pck"); - texturepackInfoAsset.SetData(new PckFileWriter(infoPCK, LittleEndianCheckBox.Checked ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian)); + texturepackInfoAsset.SetData(new PckFileWriter(infoPCK, OMI.ByteOrder.BigEndian)); return pack; } - private PckFile InitializeMashUpPack(int packId, int packVersion, string packName, string res) + private static PckFile InitializeMashUpPack(int packId, int packVersion, string packName, string res) { PckFile pack = InitializeTexturePack(packId, packVersion, packName, res, true); PckAsset gameRuleAsset = pack.CreateNewAsset("GameRules.grf", PckAssetType.GameRulesFile); @@ -1554,66 +391,57 @@ namespace PckStudio return pack; } - private void skinPackToolStripMenuItem_Click(object sender, EventArgs e) - { - CheckSaveState(); - TextPrompt namePrompt = new TextPrompt(); - namePrompt.OKButtonText = "Ok"; - if (namePrompt.ShowDialog(this) == DialogResult.OK) - { - currentPCK = InitializePack(new Random().Next(8000, 16777215), 0, namePrompt.NewText, false); // 16777215 being the uint24 max value - MarkTemplateFile(); - LoadEditorTab(); - } - } - - private void texturePackToolStripMenuItem_Click(object sender, EventArgs e) - { - CheckSaveState(); - CreateTexturePackPrompt packPrompt = new CreateTexturePackPrompt(); - if (packPrompt.ShowDialog(this) == DialogResult.OK) + private void skinPackToolStripMenuItem_Click(object sender, EventArgs e) + { + TextPrompt namePrompt = new TextPrompt(); + namePrompt.OKButtonText = "Ok"; + if (namePrompt.ShowDialog(this) == DialogResult.OK) { - currentPCK = InitializeTexturePack(new Random().Next(8000, 16777215), 0, packPrompt.PackName, packPrompt.PackRes, packPrompt.CreateSkinsPck); // 16777215 being the uint24 max value - MarkTemplateFile(); - LoadEditorTab(); + PckFile skinPck = InitializePack(new Random().Next(8000, GameConstants.MAX_PACK_ID), 0, namePrompt.NewText, true); + PackInfo packInfo = PackInfo.Create(skinPck, OMI.ByteOrder.BigEndian, true); + AddEditorPage("Unsaved skin pack", "Unsaved skin pack", packInfo); + } + } + + private void texturePackToolStripMenuItem_Click(object sender, EventArgs e) + { + var packPrompt = new CreateTexturePackPrompt(); + if (packPrompt.ShowDialog() == DialogResult.OK) + { + PckFile texturePackPck = InitializeTexturePack(new Random().Next(8000, GameConstants.MAX_PACK_ID), 0, packPrompt.PackName, packPrompt.PackRes, packPrompt.CreateSkinsPck); + PackInfo packInfo = PackInfo.Create(texturePackPck, OMI.ByteOrder.BigEndian, true); + AddEditorPage("Unsaved texture pack", "Unsaved texture pack", packInfo); } } private void mashUpPackToolStripMenuItem_Click(object sender, EventArgs e) - { - CheckSaveState(); - CreateTexturePackPrompt packPrompt = new CreateTexturePackPrompt(); - if (packPrompt.ShowDialog(this) == DialogResult.OK) - { - currentPCK = InitializeMashUpPack(new Random().Next(8000, 16777215), 0, packPrompt.PackName, packPrompt.PackRes); // 16777215 being the uint24 max value - MarkTemplateFile(); - LoadEditorTab(); - } - } - - private void MarkTemplateFile() { - isTemplateFile = true; - wasModified = true; - saveLocation = string.Empty; + var packPrompt = new CreateTexturePackPrompt(); + if (packPrompt.ShowDialog() == DialogResult.OK) + { + PckFile mashUpPck = InitializeMashUpPack(new Random().Next(8000, GameConstants.MAX_PACK_ID), 0, packPrompt.PackName, packPrompt.PackRes); + PackInfo packInfo = PackInfo.Create(mashUpPck, OMI.ByteOrder.BigEndian, true); + AddEditorPage("Unsaved mash-up pack", "Unsaved mash-up pack", packInfo); + } } private void quickChangeToolStripMenuItem_Click(object sender, EventArgs e) { - using AdvancedOptions advanced = new AdvancedOptions(currentPCK); - advanced.IsLittleEndian = LittleEndianCheckBox.Checked; - if (advanced.ShowDialog(this) == DialogResult.OK) - { - wasModified = true; - BuildMainTreeView(); - } - } + if (TryGetCurrentEditor(out IEditor editor)) + { + using AdvancedOptions advanced = new AdvancedOptions(editor.EditorValue.File); + advanced.IsLittleEndian = editor.EditorValue.Endianness == OMI.ByteOrder.LittleEndian; + if (advanced.ShowDialog() == DialogResult.OK) + { + editor.UpdateView(); + } + } + } private void closeToolStripMenuItem_Click(object sender, EventArgs e) { - CheckSaveState(); - CloseEditorTab(); - } + CloseTab(tabControl.TabPages, tabControl.SelectedTab); + } private void aboutToolStripMenuItem_Click(object sender, EventArgs e) { @@ -1621,31 +449,10 @@ namespace PckStudio info.ShowDialog(this); } - private void treeViewMain_KeyDown(object sender, KeyEventArgs e) - { - switch (e.KeyCode) - { - case Keys.Delete: - deleteFileToolStripMenuItem_Click(sender, e); - break; - case Keys.F2: - renameFileToolStripMenuItem_Click(sender, e); - break; - } - } - - private void treeViewMain_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e) - { - // for now name edits are done through the 'rename' context menu item - // TODO: add folder renaming - //e.CancelEdit = e.Node.Tag is PckFile.FileData; - e.CancelEdit = true; - } - - [Obsolete("Move this")] + [Obsolete("ReMove this")] public string GetDataPath() { - return Path.Combine(Path.GetDirectoryName(saveLocation), "Data"); + return ""; } [Obsolete("Move this")] @@ -1668,228 +475,31 @@ namespace PckStudio return true; } - private void treeMeta_KeyDown(object sender, KeyEventArgs e) - { - if (e.KeyData == Keys.Delete) - deleteEntryToolStripMenuItem_Click(sender, e); - } - - private bool TryGetLocFile(out LOCFile locFile) - { - if (!currentPCK.TryGetAsset("localisation.loc", PckAssetType.LocalisationFile, out PckAsset locAsset) && - !currentPCK.TryGetAsset("languages.loc", PckAssetType.LocalisationFile, out locAsset)) - { - locFile = null; - return false; - } + private void howToMakeABasicSkinPackToolStripMenuItem_Click(object sender, EventArgs e) => Process.Start("https://www.youtube.com/watch?v=A43aHRHkKxk"); - try - { - locFile = locAsset.GetData(new LOCFileReader()); - return true; - } - catch (Exception ex) - { - Debug.WriteLine(ex.Message); - } - locFile = null; - return false; - } + private void howToMakeACustomSkinModelToolStripMenuItem_Click(object sender, EventArgs e) => Process.Start("https://www.youtube.com/watch?v=pEC_ug55lag"); - private bool TrySetLocFile(in LOCFile locFile) - { - if (!currentPCK.TryGetAsset("localisation.loc", PckAssetType.LocalisationFile, out PckAsset locAsset) && - !currentPCK.TryGetAsset("languages.loc", PckAssetType.LocalisationFile, out locAsset)) - { - return false; - } + private void howToMakeCustomSkinModelsbedrockToolStripMenuItem_Click(object sender, EventArgs e) => Process.Start("https://www.youtube.com/watch?v=6z8NTogw5x4"); - try - { - locAsset.SetData(new LOCFileWriter(locFile, 2)); - return true; - } - catch (Exception ex) - { - Debug.WriteLine(ex.Message); - } - return false; - } + private void howToMakeCustomMusicToolStripMenuItem_Click(object sender, EventArgs e) => Process.Start("https://www.youtube.com/watch?v=v6EYr4zc7rI"); - [Obsolete("Refactor or remove this")] - private void importExtractedSkinsFolder(object sender, EventArgs e) - { - OpenFolderDialog contents = new OpenFolderDialog(); - if (contents.ShowDialog(Handle) == true && Directory.Exists(contents.ResultPath)) - { - string filepath = treeViewMain.SelectedNode?.FullPath ?? ""; - if (treeViewMain.SelectedNode is not null && treeViewMain.SelectedNode.IsTagOfType()) - filepath = treeViewMain.SelectedNode.Parent?.FullPath ?? ""; + private void howToInstallPcksDirectlyToWiiUToolStripMenuItem_Click(object sender, EventArgs e) => Process.Start("https://www.youtube.com/watch?v=hRQagnEplec"); - foreach (var fullfilename in Directory.GetFiles(contents.ResultPath, "dlc*.png")) - { - string filename = Path.GetFileName(fullfilename); - // only accept skin or cape named files - if (!filename.StartsWith("dlcskin") && !filename.StartsWith("dlccape")) - continue; - // sets file type based on wether its a cape or skin - PckAssetType pckfiletype = filename.StartsWith("dlccape", StringComparison.OrdinalIgnoreCase) - ? PckAssetType.CapeFile - : PckAssetType.SkinFile; - string pckfilepath = Path.Combine(filepath, filename); + private void pckCenterReleaseToolStripMenuItem_Click(object sender, EventArgs e) => Process.Start("https://www.youtube.com/watch?v=E_6bXSh6yqw"); - if (currentPCK.Contains(pckfilepath, pckfiletype)) - { - Trace.TraceInformation("[{0}] {1} already exists.", nameof(importExtractedSkinsFolder), pckfilepath); - continue; - } + private void howPCKsWorkToolStripMenuItem_Click(object sender, EventArgs e) => Process.Start("https://www.youtube.com/watch?v=hTlImrRrCKQ"); - PckAsset newAsset = currentPCK.CreateNewAsset(pckfilepath, pckfiletype); - byte[] filedata = File.ReadAllBytes(fullfilename); - newAsset.SetData(filedata); + private void toPhoenixARCDeveloperToolStripMenuItem_Click(object sender, EventArgs e) => Process.Start("https://cash.app/$PhoenixARC"); - if (File.Exists(fullfilename + ".txt")) - { - string[] propertiesFileContent = File.ReadAllLines(fullfilename + ".txt"); - newAsset.DeserializeProperties(propertiesFileContent); - } - } - BuildMainTreeView(); - wasModified = true; - } - } + private void toNobledezJackToolStripMenuItem_Click(object sender, EventArgs e) => Process.Start("https://www.paypal.me/realnobledez"); - [Obsolete("Refactor or remove this")] - private void importSkinToolStripMenuItem_Click(object sender, EventArgs e) - { - using (OpenFileDialog contents = new OpenFileDialog()) - { - contents.Title = "Select Extracted Skin File"; - contents.Filter = "Skin File (*.png)|*.png"; + private void forMattNLContributorToolStripMenuItem_Click(object sender, EventArgs e) => Process.Start("https://ko-fi.com/mattnl"); - if (contents.ShowDialog(this) == DialogResult.OK) - { - string skinNameImport = Path.GetFileName(contents.FileName); - byte[] data = File.ReadAllBytes(contents.FileName); + private void joinDevelopmentDiscordToolStripMenuItem_Click(object sender, EventArgs e) => Process.Start("https://discord.gg/aJtZNFVQTv"); - if (currentPCK.Contains(skinNameImport, PckAssetType.SkinFile)) - { - Trace.TraceInformation("[{0}] {1} already exists.", nameof(importExtractedSkinsFolder), skinNameImport); - return; - } + private void trelloBoardToolStripMenuItem_Click(object sender, EventArgs e) => Process.Start("https://trello.com/b/0XLNOEbe/pck-studio"); - PckAsset importSkinAsset = currentPCK.CreateNewAsset(skinNameImport, PckAssetType.SkinFile); - importSkinAsset.SetData(data); - string propertyFile = contents.FileName + ".txt"; - if (File.Exists(propertyFile)) - { - string[] txtProperties = File.ReadAllLines(propertyFile); - importSkinAsset.DeserializeProperties(txtProperties); - - // Because extracting/exporting an assest doesn't export - // the actual loc value we just get an undefined loc key. - // That's why why remove them after deserializing. - // - Miku - importSkinAsset.RemoveProperty("DISPLAYNAMEID"); - importSkinAsset.RemoveProperty("THEMENAMEID"); - BuildMainTreeView(); - wasModified = true; - } - } - } - } - - private void folderToolStripMenuItem_Click(object sender, EventArgs e) - { - TextPrompt folderNamePrompt = new TextPrompt(); - if (treeViewMain.SelectedNode is not null) - folderNamePrompt.contextLabel.Text = - $"New folder at the location of \"{( - !treeViewMain.SelectedNode.IsTagOfType() - ? "/" + treeViewMain.SelectedNode.FullPath - : treeViewMain.SelectedNode.Parent == null ? "/" : "/" + treeViewMain.SelectedNode.Parent.FullPath)}\""; - folderNamePrompt.OKButtonText = "Add"; - if (folderNamePrompt.ShowDialog(this) == DialogResult.OK) - { - TreeNode folerNode = CreateNode(folderNamePrompt.NewText); - folerNode.ImageIndex = 0; - folerNode.SelectedImageIndex = 0; - - TreeNodeCollection nodeCollection = treeViewMain.Nodes; - if (treeViewMain.SelectedNode is TreeNode node) - { - if (node.Tag is PckAsset asset && - asset.Type != PckAssetType.TexturePackInfoFile && - asset.Type != PckAssetType.SkinDataFile) - { - if (node.Parent is TreeNode parentNode) - { - nodeCollection = parentNode.Nodes; - } - } - else - nodeCollection = node.Nodes; - } - nodeCollection.Add(folerNode); - } - } - - private void howToMakeABasicSkinPackToolStripMenuItem_Click(object sender, EventArgs e) - { - Process.Start("https://www.youtube.com/watch?v=A43aHRHkKxk"); - } - - private void howToMakeACustomSkinModelToolStripMenuItem_Click(object sender, EventArgs e) - { - Process.Start("https://www.youtube.com/watch?v=pEC_ug55lag"); - } - - private void howToMakeCustomSkinModelsbedrockToolStripMenuItem_Click(object sender, EventArgs e) - { - Process.Start("https://www.youtube.com/watch?v=6z8NTogw5x4"); - } - - private void howToMakeCustomMusicToolStripMenuItem_Click(object sender, EventArgs e) - { - Process.Start("https://www.youtube.com/watch?v=v6EYr4zc7rI"); - } - - private void howToInstallPcksDirectlyToWiiUToolStripMenuItem_Click(object sender, EventArgs e) - { - Process.Start("https://www.youtube.com/watch?v=hRQagnEplec"); - } - - private void pckCenterReleaseToolStripMenuItem_Click(object sender, EventArgs e) - { - Process.Start("https://www.youtube.com/watch?v=E_6bXSh6yqw"); - } - - private void howPCKsWorkToolStripMenuItem_Click(object sender, EventArgs e) - { - Process.Start("https://www.youtube.com/watch?v=hTlImrRrCKQ"); - } - - private void toPhoenixARCDeveloperToolStripMenuItem_Click(object sender, EventArgs e) - { - Process.Start("https://cash.app/$PhoenixARC"); - } - - private void toNobledezJackToolStripMenuItem_Click(object sender, EventArgs e) - { - Process.Start("https://www.paypal.me/realnobledez"); - } - - private void forMattNLContributorToolStripMenuItem_Click(object sender, EventArgs e) - { - Process.Start("https://ko-fi.com/mattnl"); - } - - private void joinDevelopmentDiscordToolStripMenuItem_Click(object sender, EventArgs e) - { - Process.Start("https://discord.gg/aJtZNFVQTv"); - } - - private void OpenPck_MouseEnter(object sender, EventArgs e) + private void OpenPck_MouseEnter(object sender, EventArgs e) { pckOpen.Image = Resources.pckOpen; } @@ -1899,21 +509,6 @@ namespace PckStudio pckOpen.Image = Resources.pckClosed; } - private void CheckSaveState() - { - if (currentPCK is not null && - wasModified && - MessageBox.Show(this, "Save PCK?", "Unsaved PCK", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1) == DialogResult.Yes) - { - if (isTemplateFile || string.IsNullOrEmpty(saveLocation)) - { - SaveTemplate(); - return; - } - Save(saveLocation); - } - } - private void OpenPck_DragEnter(object sender, DragEventArgs e) { pckOpen.Image = Resources.pckDrop; @@ -1925,10 +520,8 @@ namespace PckStudio private void OpenPck_DragDrop(object sender, DragEventArgs e) { - string[] filepaths = (string[])e.Data.GetData(DataFormats.FileDrop, false); - if (filepaths.Length > 1) - MessageBox.Show(this, "Only one pck file at a time is currently supported"); - LoadPckFromFile(filepaths[0]); + if (e.Data.GetData(DataFormats.FileDrop, false) is string[] filepaths) + LoadPckFromFile(filepaths); } private void OpenPck_DragLeave(object sender, EventArgs e) @@ -1941,337 +534,21 @@ namespace PckStudio openToolStripMenuItem_Click(sender, e); } - private void savePCK(object sender, EventArgs e) + private void saveToolStripMenuItem_Click(object sender, EventArgs e) { - if (!string.IsNullOrEmpty(saveLocation)) - Save(saveLocation); - if (string.IsNullOrWhiteSpace(saveLocation) || isTemplateFile) - SaveTemplate(); - } - - private void saveAsPCK(object sender, EventArgs e) - { - SaveTemplate(); - } - - private void SetNodeIcon(TreeNode node, PckAssetType type) - { - switch (type) - { - case PckAssetType.AudioFile: - node.ImageIndex = 1; - node.SelectedImageIndex = 1; - break; - case PckAssetType.LocalisationFile: - node.ImageIndex = 3; - node.SelectedImageIndex = 3; - break; - case PckAssetType.TexturePackInfoFile: - goto default; - //node.ImageIndex = 4; - //node.SelectedImageIndex = 4; - //break; - case PckAssetType.ColourTableFile: - node.ImageIndex = 6; - node.SelectedImageIndex = 6; - break; - case PckAssetType.ModelsFile: - goto default; - //node.ImageIndex = 8; - //node.SelectedImageIndex = 8; - //break; - case PckAssetType.SkinDataFile: - goto default; - //node.ImageIndex = 7; - //node.SelectedImageIndex = 7; - //break; - case PckAssetType.GameRulesFile: - node.ImageIndex = 9; - node.SelectedImageIndex = 9; - break; - case PckAssetType.GameRulesHeader: - node.ImageIndex = 10; - node.SelectedImageIndex = 10; - break; - case PckAssetType.InfoFile: - node.ImageIndex = 11; - node.SelectedImageIndex = 11; - break; - case PckAssetType.SkinFile: - node.ImageIndex = 12; - node.SelectedImageIndex = 12; - break; - case PckAssetType.CapeFile: - node.ImageIndex = 13; - node.SelectedImageIndex = 13; - break; - case PckAssetType.TextureFile: - node.ImageIndex = 14; - node.SelectedImageIndex = 14; - break; - case PckAssetType.BehavioursFile: - node.ImageIndex = 15; - node.SelectedImageIndex = 15; - break; - case PckAssetType.MaterialFile: - node.ImageIndex = 16; - node.SelectedImageIndex = 16; - break; - default: // unknown file format - node.ImageIndex = 5; - node.SelectedImageIndex = 5; - break; - } - } - - private void SetFileType(PckAssetType type) - { - if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset)) - { - Debug.WriteLine($"Setting {asset.Type} to {type}"); - asset.Type = type; - SetNodeIcon(treeViewMain.SelectedNode, type); - } - } - - private void addTextureToolStripMenuItem_Click(object sender, EventArgs e) - { - using OpenFileDialog fileDialog = new OpenFileDialog(); - fileDialog.Filter = "Texture File(*.png,*.tga)|*.png;*.tga"; - if (fileDialog.ShowDialog(this) == DialogResult.OK) - { - using TextPrompt renamePrompt = new TextPrompt(Path.GetFileName(fileDialog.FileName)); - renamePrompt.LabelText = "Path"; - if (renamePrompt.ShowDialog(this) == DialogResult.OK && !string.IsNullOrEmpty(renamePrompt.NewText)) - { - if (currentPCK.Contains(renamePrompt.NewText, PckAssetType.TextureFile)) - { - MessageBox.Show(this, $"'{renamePrompt.NewText}' already exists.", "Import failed", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return; - } - PckAsset asset = currentPCK.CreateNewAsset(renamePrompt.NewText, PckAssetType.TextureFile, () => File.ReadAllBytes(fileDialog.FileName)); - BuildMainTreeView(); - wasModified = true; - } - } - } - - private void viewFileInfoToolStripMenuItem_Click(object sender, EventArgs e) - { - if (treeViewMain.SelectedNode.Tag is PckAsset asset) - { - MessageBox.Show(this, - "File path: " + asset.Filename + - "\nAssigned File type: " + (int)asset.Type + " (" + asset.Type + ")" + - "\nFile size: " + asset.Size + - "\nProperties count: " + asset.PropertyCount - , Path.GetFileName(asset.Filename) + " file info"); - } - } - - private void generateMipMapTextureToolStripMenuItem_Click(object sender, EventArgs e) - { - if (treeViewMain.SelectedNode.Tag is PckAsset asset && asset.Type == PckAssetType.TextureFile) - { - string textureDirectory = Path.GetDirectoryName(asset.Filename); - string textureName = Path.GetFileNameWithoutExtension(asset.Filename); - - if (asset.IsMipmappedFile()) - return; - - string textureExtension = Path.GetExtension(asset.Filename); - - using NumericPrompt numericPrompt = new NumericPrompt(0); - numericPrompt.Minimum = 1; - numericPrompt.Maximum = 4; // 5 is the presumed max MipMap level - numericPrompt.ContextLabel.Text = "You can enter the amount of MipMap levels that you would like to generate. " + - "For example: if you enter 2, MipMapLevel1.png and MipMapLevel2.png will be generated"; - numericPrompt.TextLabel.Text = "Levels"; - - if (numericPrompt.ShowDialog(this) == DialogResult.OK) - { - for (int i = 2; i < 2 + numericPrompt.SelectedValue; i++) - { - string mippedPath = $"{textureDirectory}/{textureName}MipMapLevel{i}{textureExtension}"; - Debug.WriteLine(mippedPath); - if (currentPCK.HasAsset(mippedPath, PckAssetType.TextureFile)) - currentPCK.RemoveAsset(currentPCK.GetAsset(mippedPath, PckAssetType.TextureFile)); - PckAsset mipMappedAsset = new PckAsset(mippedPath, PckAssetType.TextureFile); - - Image originalTexture = asset.GetTexture(); - int newWidth = Math.Max(originalTexture.Width / (int)Math.Pow(2, i - 1), 1); - int newHeight = Math.Max(originalTexture.Height / (int)Math.Pow(2, i - 1), 1); - - Rectangle tileArea = new Rectangle(0, 0, newWidth, newHeight); - Image mippedTexture = new Bitmap(newWidth, newHeight); - using (Graphics gfx = Graphics.FromImage(mippedTexture)) - { - gfx.SmoothingMode = SmoothingMode.None; - gfx.InterpolationMode = InterpolationMode.NearestNeighbor; - gfx.PixelOffsetMode = PixelOffsetMode.HighQuality; - gfx.DrawImage(originalTexture, tileArea); - } - - mipMappedAsset.SetTexture(mippedTexture); - - currentPCK.InsertAsset(currentPCK.IndexOfAsset(asset) + i - 1, mipMappedAsset); - } - BuildMainTreeView(); - } - } - } - - private void colourscolToolStripMenuItem_Click(object sender, EventArgs e) - { - if (currentPCK.TryGetAsset("colours.col", PckAssetType.ColourTableFile, out _)) - { - MessageBox.Show(this, "A color table file already exists in this PCK and a new one cannot be created.", "Operation aborted"); - return; - } - PckAsset newColorAsset = currentPCK.CreateNewAsset("colours.col", PckAssetType.ColourTableFile); - newColorAsset.SetData(Resources.tu69colours); - BuildMainTreeView(); - } - - private void tabControl_Selecting(object sender, TabControlCancelEventArgs e) - { - e.Cancel = !isSelectingTab; - } - - private void as3DSTextureFileToolStripMenuItem_Click(object sender, EventArgs e) - { - if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset) && - asset.Type == PckAssetType.SkinFile) - { - SaveFileDialog saveFileDialog = new SaveFileDialog(); - saveFileDialog.Filter = "3DS Texture|*.3dst"; - saveFileDialog.DefaultExt = ".3dst"; - if (saveFileDialog.ShowDialog(this) == DialogResult.OK) - { - Image img = asset.GetTexture(); - var writer = new _3DSTextureWriter(img); - writer.WriteToFile(saveFileDialog.FileName); - } - } - } - - private void addMultipleEntriesToolStripMenuItem1_Click(object sender, EventArgs e) - { - if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset)) - { - using var input = new MultiTextPrompt(); - if (input.ShowDialog(this) == DialogResult.OK) - { - asset.DeserializeProperties(input.TextOutput); - ReloadMetaTreeView(); - wasModified = true; - } + if (TryGetCurrentEditor(out IEditor editor)) + { + editor.Save(); } - } + } - private void correctSkinDecimalsToolStripMenuItem_Click(object sender, EventArgs e) + private void saveAsToolStripMenuItem_Click(object sender, EventArgs e) { - if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset) && - asset.Type == PckAssetType.SkinFile) - { - foreach (KeyValuePair p in asset.GetProperties().ToList()) - { - if (p.Key == "BOX" || p.Key == "OFFSET") - asset.SetProperty(asset.GetPropertyIndex(p), new KeyValuePair(p.Key, p.Value.Replace(',', '.'))); - } - ReloadMetaTreeView(); - wasModified = true; - } - } - - private void CreateSkinsPCKToolStripMenuItem1_Click(object sender, EventArgs e) - { - if (currentPCK.TryGetAsset("Skins.pck", PckAssetType.SkinDataFile, out _)) - { - MessageBox.Show(this, "A Skins.pck file already exists in this PCK and a new one cannot be created.", "Operation aborted"); - return; - } - - currentPCK.CreateNewAsset("Skins.pck", PckAssetType.SkinDataFile, new PckFileWriter(new PckFile(3, true), - LittleEndianCheckBox.Checked ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian)); - - BuildMainTreeView(); - } - - private void editAllEntriesToolStripMenuItem_Click(object sender, EventArgs e) - { - if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset)) - { - IEnumerable props = asset.SerializeProperties(seperater:" "); - using (var input = new MultiTextPrompt(props)) - { - if (input.ShowDialog(this) == DialogResult.OK) - { - asset.ClearProperties(); - asset.DeserializeProperties(input.TextOutput); - ReloadMetaTreeView(); - wasModified = true; - } - } - } - } - - private void addFileToolStripMenuItem_Click(object sender, EventArgs e) - { - using var ofd = new OpenFileDialog(); - // Suddenly, and randomly, this started throwing an exception because it wasn't formatted correctly? - // So now it's formatted correctly and now displays the file type name in the dialog. - ofd.Filter = "All files (*.*)|*.*"; - ofd.Multiselect = false; - - if (ofd.ShowDialog(this) == DialogResult.OK) - { - using AddFilePrompt diag = new AddFilePrompt("res/" + Path.GetFileName(ofd.FileName)); - if (diag.ShowDialog(this) == DialogResult.OK) - { - if (currentPCK.Contains(diag.Filepath, diag.Filetype)) - { - MessageBox.Show(this, $"'{diag.Filepath}' of type {diag.Filetype} already exists.", "Import failed", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return; - } - PckAsset asset = currentPCK.CreateNewAsset(diag.Filepath, diag.Filetype, () => File.ReadAllBytes(ofd.FileName)); - - BuildMainTreeView(); - wasModified = true; - } - } - return; - } - - private void behavioursbinToolStripMenuItem_Click(object sender, EventArgs e) - { - if (currentPCK.TryGetAsset("behaviours.bin", PckAssetType.BehavioursFile, out _)) - { - MessageBox.Show(this, "A behaviours file already exists in this PCK and a new one cannot be created.", "Operation aborted"); - return; - } - - currentPCK.CreateNewAsset("behaviours.bin", PckAssetType.BehavioursFile, new BehavioursWriter(new BehaviourFile())); - BuildMainTreeView(); - } - - private void entityMaterialsbinToolStripMenuItem_Click(object sender, EventArgs e) - { - if (currentPCK.TryGetAsset("entityMaterials.bin", PckAssetType.MaterialFile, out _)) - { - MessageBox.Show(this, "A behaviours file already exists in this PCK and a new one cannot be created.", "Operation aborted"); - return; - } - var materialContainer = new MaterialContainer(); - materialContainer.InitializeDefault(); - currentPCK.CreateNewAsset("entityMaterials.bin", PckAssetType.MaterialFile, new MaterialFileWriter(materialContainer)); - BuildMainTreeView(); - } - - private void trelloBoardToolStripMenuItem_Click(object sender, EventArgs e) - { - Process.Start("https://trello.com/b/0XLNOEbe/pck-studio"); - } + if (TryGetCurrentEditor(out IEditor editor)) + { + editor.SaveAs(); + } + } private void wavBinkaToolStripMenuItem_Click(object sender, EventArgs e) { @@ -2291,7 +568,7 @@ namespace PckStudio ButtonText = "OK" }; - if(dialog.ShowDialog(this) == DialogResult.OK) + if (dialog.ShowDialog(this) == DialogResult.OK) { BinkaConverter.ToBinka( fileDialog.FileNames, @@ -2318,8 +595,11 @@ namespace PckStudio private void fullBoxSupportToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { - currentPCK.SetVersion(fullBoxSupportToolStripMenuItem.Checked); - } + if (TryGetCurrentEditor(out IEditor editor)) + { + editor.EditorValue.File.SetVersion(fullBoxSupportToolStripMenuItem.Checked); + } + } private void settingsToolStripMenuItem_Click(object sender, EventArgs e) { @@ -2327,36 +607,6 @@ namespace PckStudio appSettings.ShowDialog(this); } - private void addBOXEntryToolStripMenuItem1_Click(object sender, EventArgs e) - { - if (treeViewMain.SelectedNode is TreeNode t && t.Tag is PckAsset asset) - { - using BoxEditor diag = new BoxEditor(SkinBOX.Empty, false); - if (diag.ShowDialog(this) == DialogResult.OK) - { - asset.AddProperty("BOX", diag.Result); - ReloadMetaTreeView(); - wasModified = true; - } - return; - } - } - - private void addANIMEntryToolStripMenuItem1_Click(object sender, EventArgs e) - { - if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset)) - { - using ANIMEditor diag = new ANIMEditor(SkinANIM.Empty); - if (diag.ShowDialog(this) == DialogResult.OK) - { - asset.AddProperty("ANIM", diag.ResultAnim); - ReloadMetaTreeView(); - wasModified = true; - } - return; - } - } - private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e) { Updater.UpdateToLatest(); @@ -2367,149 +617,5 @@ namespace PckStudio PckManager?.Close(); Application.Exit(); } - - private void SetPckEndianness(OMI.Endianness endianness) - { - try - { - if (treeViewMain.SelectedNode.Tag is PckAsset asset && (asset.Type is PckAssetType.AudioFile || asset.Type is PckAssetType.SkinDataFile || asset.Type is PckAssetType.TexturePackInfoFile)) - { - IDataFormatReader reader = asset.Type is PckAssetType.AudioFile - ? new PckAudioFileReader(endianness == OMI.Endianness.BigEndian ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian) - : new PckFileReader(endianness == OMI.Endianness.BigEndian ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian); - object pck = reader.FromStream(new MemoryStream(asset.Data)); - - IDataFormatWriter writer = asset.Type is PckAssetType.AudioFile - ? new PckAudioFileWriter((PckAudioFile)pck, endianness) - : new PckFileWriter((PckFile)pck, endianness); - asset.SetData(writer); - wasModified = true; - MessageBox.Show($"\"{asset.Filename}\" successfully converted to {(endianness == OMI.Endianness.LittleEndian ? "little" : "big")} endian.", "Converted PCK file"); - } - } - catch (OverflowException) - { - MessageBox.Show(this, $"File was not a valid {(endianness != OMI.Endianness.LittleEndian ? "little" : "big")} endian PCK File.", "Not a valid PCK file"); - return; - } - catch (Exception ex) - { - MessageBox.Show(this, ex.Message, "Not a valid PCK file"); - return; - } - } - - private void littleEndianToolStripMenuItem_Click(object sender, EventArgs e) => SetPckEndianness(OMI.Endianness.LittleEndian); - - private void bigEndianToolStripMenuItem_Click(object sender, EventArgs e) => SetPckEndianness(OMI.Endianness.BigEndian); - - private void SetModelVersion(int version) - { - if (treeViewMain.SelectedNode.Tag is PckAsset asset && asset.Type is PckAssetType.ModelsFile) - { - try - { - ModelContainer container = asset.GetData(new ModelFileReader()); - - if (container.Version == version) - { - MessageBox.Show( - this, - $"This model container is already Version {version + 1}.", - "Can't convert", MessageBoxButtons.OK, MessageBoxIcon.Error - ); - return; - } - - if (version == 2 && - MessageBox.Show( - this, - "Conversion to 1.14 models.bin format does not yet support parent declaration and may not be 100% accurate.\n" + - "Would you like to continue?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes - ) - { - return; - } - - if (container.Version > 1 && - MessageBox.Show( - this, - "Conversion from 1.14 models.bin format does not yet support parent parts and may not be 100% accurate.\n" + - "Would you like to continue?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes - ) - { - return; - } - - asset.SetData(new ModelFileWriter(container, version)); - wasModified = true; - MessageBox.Show( - this, - $"\"{asset.Filename}\" successfully converted to Version {version + 1} format.", - "Converted model container file" - ); - } - catch (Exception ex) - { - MessageBox.Show(this, ex.Message, "Not a valid model container file."); - return; - } - } - } - - private void setModelVersion1ToolStripMenuItem_Click(object sender, EventArgs e) => SetModelVersion(0); - - private void setModelVersion2ToolStripMenuItem_Click(object sender, EventArgs e) => SetModelVersion(1); - - private void setModelVersion3ToolStripMenuItem_Click(object sender, EventArgs e) => SetModelVersion(2); - - private void contextMenuPCKEntries_Opening(object sender, System.ComponentModel.CancelEventArgs e) - { - if (treeViewMain?.SelectedNode == null) - { - e.Cancel = true; - return; - } - - correctSkinDecimalsToolStripMenuItem.Visible = false; - generateMipMapTextureToolStripMenuItem1.Visible = false; - setModelContainerFormatToolStripMenuItem.Visible = false; - setSubPCKEndiannessToolStripMenuItem.Visible = false; - exportToolStripMenuItem.Visible = false; - toolStripSeparator5.Visible = false; - toolStripSeparator6.Visible = false; - if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset)) - { - replaceToolStripMenuItem.Visible = true; - cloneFileToolStripMenuItem.Visible = true; - setFileTypeToolStripMenuItem.Visible = true; - toolStripSeparator5.Visible = true; - toolStripSeparator6.Visible = true; - - if (asset.Type == PckAssetType.SkinFile) - { - correctSkinDecimalsToolStripMenuItem.Visible = true; - exportToolStripMenuItem.Visible = true; - } - if (asset.Type == PckAssetType.TextureFile) - generateMipMapTextureToolStripMenuItem1.Visible = true; - if (asset.Type == PckAssetType.ModelsFile) - setModelContainerFormatToolStripMenuItem.Visible = true; - if (asset.Type == PckAssetType.SkinDataFile || asset.Type == PckAssetType.TexturePackInfoFile || asset.Type == PckAssetType.AudioFile) - setSubPCKEndiannessToolStripMenuItem.Visible = true; - } - else - { - replaceToolStripMenuItem.Visible = false; - cloneFileToolStripMenuItem.Visible = false; - setFileTypeToolStripMenuItem.Visible = false; - } - } - - private void treeViewMain_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) - { - if (e.Node is not null) - treeViewMain.SelectedNode = e.Node; - } - } + } } \ No newline at end of file diff --git a/PCK-Studio/MainForm.resx b/PCK-Studio/MainForm.resx index 53da4286..b1bb4ce0 100644 --- a/PCK-Studio/MainForm.resx +++ b/PCK-Studio/MainForm.resx @@ -117,701 +117,10 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - False - - - - - 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 - 8+BMiU9xSj9GDDCHwDUcMkHMV8I4YKwwEz0K5TTDbjg/NnbZmEsvwcYuuVQYpxwTXCyU8g2YMaMA9NIJ - QlbKc/bsWePhf9yV868cRwU+9urlV49ddc3mO2PQDmDbQrL1wvZLH2n1jwL0m3S/9BN9i3ENH0E3I+Ij - 165ePWaFyYNijmQzbk6y88LG0GHSNcktA2RXAwTAVlDG8CCv2hKBdbzbZhRPJilXFq4wuuJh8dIlYxYs - Xjhm/sL5Y+fMgz7wYKfjL5ulHyRZNmWXbKCcX4CWVvpbgeTVFkhq0j+BAmI8iTTZBwWAzyt9dNH16gP/ - HXPlvCvGzJs7Tx9M/ohfjp/5M3zskkuJl5c2/SoAuyjtI8ULoND/ZfgWuhdK9G0bxdkYVm1j0OlYdErs - wq+Zk/kS3sJXSkjy8rMGok+SZSlXQL8z3hvLkn6JT+7OLKZwXrZ0KSvWFSNio/3Wb/3Wb/3Wb/3Wb/3W - b/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3W - b/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3W - b/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb/3Wb1uy/Yf/8P8D4rKD - rca4/zIAAAAASUVORK5CYII= - - - - - NoControl - - - 413, 0 - - - 190, 50 - - - Zoom - - - - 14 - - - logoPictureBox - - - System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - editorTab - - - 8 - False + 202, 6 @@ -819,671 +128,27 @@ False - 183, 6 + 167, 6 False - 183, 6 + 167, 6 202, 6 - - 116, 17 - - - 224, 324 - - - contextMenuPCKEntries - - - System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xOdTWsmQAAAA3SURBVDhPY/j/ - /z9FGKsgGIsCKWSMTQ0QYxUE45FmALpiYvFwMgAbxqIYG8YqCMajBhCJ/zMAAPGwpV/Xje8RAAAAAElF - TkSuQmCC - - - - 223, 22 - - - Create - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xOdTWsmQAAABVSURBVDhPYxgc - 4P8Chv8YeKWUIFSaMPi/W+r//1MapOGTOixQ7UADsCkgAkO1jywDRIGxA8JQPlQ7PQyAaUTDUO30MACG - YZqhfKh24gGGzYMAMDAAAPvHncAZVkkSAAAAAElFTkSuQmCC - - - - 172, 22 - - - Folder - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xOdTWsmQAAAIkSURBVDhPpdLf - T1JxGMfxc1n8qtzcyglCWhFS1PLGHAgisDmktZZtabRSEYhDZ8xpiSWVpaSxLpoXyWquLvzV+oGZq+iy - /6Stm7qsm+DT830YMJw3rbO9Djs7z/P+wob03xcAyWbUwqLXotWgha1pDzPr1axl/y52uEHFrAY1z4l5 - sVsK0IK1UVMbaKQAOXhgN2tuKLHQTKtBh6M0XwmIxe1OtexjXZa9pA6dlnomlgXx7WoCo/1eTF3pwfRQ - gM3HLmD+Wh8yIwE8CgcwFznLJs67cLPPgeMmXW1gKRXCZjqGfCbBvi6kWH6OnoXMKFsd68fa2CW0Haqr - BpYnh5G7F8PGtIyV2yG2NhXHeuo6nioD5CI+pRMsG+nFYqSHVQKrt0LYKAcmhyCeX6Vklk0MsI9phQIK - Bfy07OfPSkAs/v7xDcViEd6OZ/C2LyOXHMb75Agtlk72nF6hdy/FEgrFP3yI2OVA7r6MXz+/04siPB3P - aXgJ75JhbFIgP5PAZwr42lcp8IJnioUCBcLVQHbQizfjQTr1Kj7cTbBIpw1R54mK/GwMXwjqaYWkzrVV - A4uDPry+QYGJIN7eUVjMcQyyvWrrQRxbM/GdA4+Dbjy57MJC0AmnUQ2XUYPZXjse+qvKi9vRHZLisUJx - WyB3m0sBkwZuvYr56A8j7LQs0B2S7LMg2n0EUY8ZdpMaDgo4mlSsq1lXo7w4fuZk6Sf861U5mS9J+gsp - e+98+xbVEAAAAABJRU5ErkJggg== - - - - 172, 22 - - - Skin - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAAI/SURBVDhPjZHt - b9JQFMbvv6IRCiYmU+cGpQXH5oACMkZvgQILG2Su7e2mE3l1cTMricaXEQtscVN0UYIaB8MZmW/ZFxP/ - KrzNpCHxi0+eL/ec53fuSQ7IHLqyXW+uwwj7lLBvQweu9N6Y/M65/h3iOmpNLL2hxaYj1bAEnxhXPkyB - TNe9/H76YS96rzOz0Z3lSQI1banX1uTLMfVkYetnMt/2LTRGMq1rwlv7SssJHnyLcbRp77csvLLdaF1l - HabVg+mElVg9cq//gOpJ+tmvVNRmiKsXUi8sPGUGPEWIshihiShlvN1meNoQoQ1R2jDfuBimCfHjJOsg - SrNXWIcRJwuQBFXJneXoOvL0NiGkzDtLrgJnKUIySp6L0MYYeVYWhUKYrAq+MG3WgGJolCfP1BGzI0zc - gfYcpNrlNHZ/SE9Ff4Ejn4vOjjIHDu7HI7RpjRsvsiOPN+7iRmVxqpkLakEANPf7ypyjnJzEQzEDegon - eS/t3grs3gw+Ki5iIAfJCgoMA7i4hWZU6TpmwCdlHr+7SvpoM1YR/VpO1wDQhRlQkzzZ0OVsmKwhby5k - 1cqnuX+tA1WZ4e3mUtiK/X/AcgBv9bUcx9YAXYOcrlPAm+fIIhyvIh/e6lhJYHiNHdX6AwAHPpcTPSWm - AVnWCh2mbeQpQEtN9tclpip78nBot37/i5KoIUY7rhIDOdaiIl+es5U4MkIZ8S15O4E/0YCB8HNbcuOh - mAGqxOQ5S4Q6f1yOF6CVp0w6gxfQ/ZdBnj/Cc21Sm8M0egAAAABJRU5ErkJggg== - - - - 172, 22 - - - Animated Texture - - - 172, 22 - - - Audio.pck - - - 172, 22 - - - Colours.col - - - 172, 22 - - - Skins.pck - - - 172, 22 - - - Behaviours.bin - - - 172, 22 - - - EntityMaterials.bin - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xOdTWsmQAAABzSURBVDhPpYzB - DQAhCARp4hr3Txu254WTjYRb9cEmk/BgRjBVHTv85Twmgt77PcJEYIFrhIkAgWOEiSAGthEmgtbaD9fW - mBgpB4xywCgFxiMf5YDdrq3l5wjEjKtzTARMNlydY2IGot2ureVnRjkQmZbICyCi7XU5cfqKAAAAAElF - TkSuQmCC - - - - 223, 22 - - - Import - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xOdTWsmQAAAIkSURBVDhPpdLf - T1JxGMfxc1n8qtzcyglCWhFS1PLGHAgisDmktZZtabRSEYhDZ8xpiSWVpaSxLpoXyWquLvzV+oGZq+iy - /6Stm7qsm+DT830YMJw3rbO9Djs7z/P+wob03xcAyWbUwqLXotWgha1pDzPr1axl/y52uEHFrAY1z4l5 - sVsK0IK1UVMbaKQAOXhgN2tuKLHQTKtBh6M0XwmIxe1OtexjXZa9pA6dlnomlgXx7WoCo/1eTF3pwfRQ - gM3HLmD+Wh8yIwE8CgcwFznLJs67cLPPgeMmXW1gKRXCZjqGfCbBvi6kWH6OnoXMKFsd68fa2CW0Haqr - BpYnh5G7F8PGtIyV2yG2NhXHeuo6nioD5CI+pRMsG+nFYqSHVQKrt0LYKAcmhyCeX6Vklk0MsI9phQIK - Bfy07OfPSkAs/v7xDcViEd6OZ/C2LyOXHMb75Agtlk72nF6hdy/FEgrFP3yI2OVA7r6MXz+/04siPB3P - aXgJ75JhbFIgP5PAZwr42lcp8IJnioUCBcLVQHbQizfjQTr1Kj7cTbBIpw1R54mK/GwMXwjqaYWkzrVV - A4uDPry+QYGJIN7eUVjMcQyyvWrrQRxbM/GdA4+Dbjy57MJC0AmnUQ2XUYPZXjse+qvKi9vRHZLisUJx - WyB3m0sBkwZuvYr56A8j7LQs0B2S7LMg2n0EUY8ZdpMaDgo4mlSsq1lXo7w4fuZk6Sf861U5mS9J+gsp - e+98+xbVEAAAAABJRU5ErkJggg== - - - - 228, 22 - - - Import Skin - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xOdTWsmQAAAEnSURBVDhPYxgc - 4P8Chv8YeKWUIFSaMPi/W+r//1MapOGTOixQ7UADkCS05Xjh2FhFEIydtIT+22uJAsX4wBimFqod04Bt - nTn/9/YV/T82rQGM93YXAfkl/1eVRYPl8RqwuTnn/5aW3P8r69L+r67P+7+mIf//rIKo/7s7i/7PyfT9 - PzvTC78BW6AGrKpN+7+2IReM5xTF/N/VWQA0wAdogA8BA4Ca//7799/VauH/TdUZ/7dVp//fA7Td3XLV - //+iwNgBYXwGbCiP+7+5Oun/9qai/5n2+v+zHAzAeG9HDnEGTIl3/D8tzuG/owLP/w5f2/9dPrYIjWgY - qh3VgAJnrf+5Lhr/HRV5/jvLcoExNs0gDNWOagBeDNMM5UO1Ew8wbB4EgIEBABiEccKRdcoAAAAAAElF - TkSuQmCC - - - - 228, 22 - - - Import Extracted Skins Folder - - - 228, 22 - - - Add Texture - - - 228, 22 - - - Add File - - - 223, 22 - - - Export - - - 186, 22 - - - Export as 3DS Texture - - - 223, 22 - - - Set File Type - - - 222, 22 - - - Skin (.PNG) - - - 222, 22 - - - Cape (.PNG) - - - 222, 22 - - - Texture (.PNG) - - - 222, 22 - - - Languages File (.LOC) - - - 222, 22 - - - Game Rules File (.GRF) - - - 222, 22 - - - Music Cues File (audio.PCK) - - - 222, 22 - - - Colour Table File (.COL) - - - 222, 22 - - - Game Rules Header (.GRH) - - - 222, 22 - - - Skins PCK (.PCK) - - - 222, 22 - - - Models File (.BIN) - - - 222, 22 - - - Behaviours File (.BIN) - - - 222, 22 - - - Entity Materials File (.BIN) - - - 220, 6 - - - 223, 22 - - - Generate MipMap Texture - - - 223, 22 - - - View File Info - - - 223, 22 - - - Correct Skin Decimals - - - 223, 22 - - - Set SubPCK Endianness - - - 250, 22 - - - Big Endian (Xbox 360/PS3/Wii U) - - - 250, 22 - - - Little Endian (PS4/PS Vita/Switch) - - - 223, 22 - - - Set Model Container Format - - - 216, 22 - - - Version 1 (Pre 1.13) - - - 216, 22 - - - Version 2 (1.13) - - - 216, 22 - - - Version 3 (1.14 [PS4 ONLY]) - - - 220, 6 - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAACYSURBVDhPpZBZ - CsQwDEOd5QK5/2E9qCBGXtopzMcDxxKyY3P3izmnm9kt0OlVvsVVVgOAtvduQ4KJdYbaGKOEFFOHamut - ENKaMlk75zi2QX1rUqDpkbEF/cGktb47ygb5ODA8hVArgsK1cx+EAE7LaB8+hb3QzDx942eAXrqjBOgR - MRkBfHeUADbe8ncANw4NhLwF33R3+wA6sV5/E8GOLwAAAABJRU5ErkJggg== - - - - 223, 22 - - - Extract - - - 223, 22 - - - Clone - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAACVJREFUOE9jwAL+E8AkAbI0IYNRA0YNAIFRA8g0AKYJF0YCDAwAzhor1TRE/JoA - AAAASUVORK5CYII= - - - - 223, 22 - - - Rename - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAAC/SURBVDhPlVHB - DQMhDEOIfwfoOuzFoPxhAd5c6/SMAgq0tRQFmdgXfA5IKUkBMcbHPxyJCxVCkK7rm+EwaK1dQO9dClzO - WfpOTM7hy1oMGNvY4pucxNY2p6cAWzFw2oZuMmiJweGeHM634UdLg50YwD05vQ2fYoaoDTEMrJyIfw3R - 4qYQWUZgg6OwlDJyMH8LcwF2T8FZ5kYQb4Lde/9Et8S6Dy1z0LUGi7VpWGvl3Lw2V98ZrtwIUYktwwPn - 3AtE5NqX8pp0ZQAAAABJRU5ErkJggg== - - - - 223, 22 - - - Replace - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAACESURBVDhPlY0B - DoAgDAP3Dj7r09WTkqGUgJfUxtrOmHFEnL0U76FBqW8PZXmk/9uONEsIb3gsNRzoL/+R5hWC759mGsbQ - DnzdZbhmiSvhLsM1S1wJdxmuWeJKuMtwzRJXwl2Ga5a4Eu4yXLPElXCX4Zol/WCl6YGdI62n2Zv2cSXV - byIunLh7mD2ySLcAAAAASUVORK5CYII= - - - - 223, 22 - - - Delete - 17, 17 + Top, Left, Right - - False - None - - - iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4yMfEgaZUAAADuSURBVFhH7ZbB - CsMgEERDbv5A/v83e2jNTmCKGdegJk0heHgUn7vrKBQyxRj/iivJPM9WMTWjc45wJeAwhAghVJEG1nkl - XNkziLCvtteXphFCfQ08nOi+4kvTeFL1NfBQ/BLuefjS9NkAADOwPnpNX14UADBEaV4mNnkygN34Y/1v - AgeWZXll9So2eTLAEVm9ik2a7g1Qgn9t9bvFV/4gAOZdHgB1RPeUEeAZAeBr0d4R4JIACuqI7ikjwDMD - tDACNAfo/Sou0fQ9wGKvoQfO8i61W6SkTXi+XtLLgOwcFSna3It3c+LKO3HlfcRpBa3JBjU5E8DiAAAA - AElFTkSuQmCC - - - - 186, 22 - - - New - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4yMfEgaZUAAABGSURBVDhPYxgc - 4P8Chv8YeKWUIFSaMPi/W+r//1MapOGTOixQ7UADsCkgAkO1jxoAAtgkicFQ7cPCAGLB////wXgwAQYG - AOrUrx4HdAXuAAAAAElFTkSuQmCC - - - - Control+O - - - 186, 22 - - - Open - - - - iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAT - rAAAE6wBzl+vrgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAHkSURBVFhH1ZfN - KwVRGIevBRslZUtZsPG1kEhZ21hYKfkTpMTCwoqF4l+QNbKysraU8rW1ZEEUpcg3v2fMYXLn471zz+12 - n3q6c8685z3vzJy65xRqhT45LidyytheWTKD8lR+efJEDkgTTP4kGXgj9+ROThlLDnI9SlMR7sm3ZCMd - ZUKObUnOYzrS6JHuyX1M7iDXrSR3Nx1JsGgI4tX5hpzkZo5EWLkE8f18Q05yM0cipRYwG2qhIgW8h1qo - SAHEooXYAliR93I5aBUXMCy5Pxe0ivFSwKv8lGMyWkCLvAjbizKOsguABcmNOzkdXhO8G14fyAYZB/fR - QmIBddJNdh7+noW/FNUukyAGLSQWANHXjR/SfZY0XHxb0EontQAYkm/SJV2TWRxKYi9l1t9uZgGwLgm6 - lvV0ZNAs9yVjHuSoTMJUAOthRrYGLRss0E1J8hc5JeMwFZAXCl+VTMDaWZL/qWgBjnnJAmaiFToimD/B - iGwKWvmYlM/yKmj9YSqARUTQRtDKT4fs/Ln8xVQANwki2De1UUDVt2RuU8oGslKb0i460uAQQSBbaR9F - kMNty4/oyILDA4cI9yZ4dXy/PDLWPTk5+6UJiuAQwUAf8uTmyaOwY2LRsHLzyNjUg0iVKBS+AWAi5w3z - cKwSAAAAAElFTkSuQmCC - - - - 186, 22 - - - Recently open - - - - iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAAJ10AACddAWJ4eeMAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwa - AAADaElEQVR4Xu2bO49NURiGx/1OhCiERhQKFZ2CBAlxvyv8BtHTKTUKkaCViFuCiEQoFESiICiUKgoR - BZGgcHmfYpKTPe+aOWfvb629JftJnmbOmf2t7519XXvNWE9PT09PGZbKE/K8vCZv1vCK3C7/K+bIs/K7 - /BvgH3lc/hcsk0+la6SJbLPzsMu/lK6BpqYC2CLfyG/ytlwuW2GxfCHd4JvKIXBMVtktf8rB73LeKM5C - +UwODmTQT/K+rJ7ghpGT4DZZxTWPX2VR5ssnsjqQca9LAook1Ty+ksWYKx9JNxC8IWfISCZrnp9vlkWY - Ldmt3UDwjpwlI9kpf0hX75fcJ4tAYzToBoIPJAFFMtlfHk/KIrBLs2u7QSCHBIdGJFM1j0dldqbLq9IN - ALkSRJ/wJtvtB80ewDR5Sbri+FwukpEM2zxmDYDmL0pXGLn0cBcYySjNY9YATktXFHM0P9Wlzv08WwAb - 5W/pir6VPPxEMlXzfO4+yxbAPekKvpMrZCTDNA/u8ywBcFLjBqNa7L1cKSMZtnlw38kSwCbpiu2QkYzS - PLjvHZHhHJCu2DwZxajNc0Vy380SABt1xRhEBHXu7VMBHJbh5Ayg7oMNd6Pud7IEwEZdsaYB1G0eUgEc - kuGkAmAQdWnSPPAw5n43SwBs1BWrG0DT5qETAdSZ5YloHlIBHJThRAUQ1TzMlG47WQJgo67YKAFENg+p - ALhnCScVAIMYhujmgek4t70sAaTuBIcJIEfz0IkApprtzdU8pALYL8OpE0DO5oHZZrftLAHwSqpaiOZS - 9wGjPtjUoWgAS+RnOVjornSUaB6KBgDMCfDKm5eOvH52s0ClmgcWX7g6TQ+t2uQ+5qukAtgri1O6eeCt - k6tXPIA2modOBNBW85AKYI8sQpvNA/ORrnaRANpuHloLoAvNA0ty3BgiL7UT6ErzUDyALjUPqQB2yXC6 - 1jwskG484QF0sXkoEgDLT1P39uhWbZZilXRj2irDYO2tKzIuCyba4ox0Y1orw2DhsSsy6Gv5WPKEWF3e - Gi01qEVNN5aPssnLmgnckq5QVz0nQ2HJOakzB8DhQMKucBf8IKPXKE1gvfwi3QDalNmqDbIIq+VD6QbS - hqxIXSOLs06ekhfkZVn3n6FGkRrUoia1GUNPT09Pz+iMjf0D9wsBsNeAg5QAAAAASUVORK5CYII= - - - - 186, 22 - - - Close - - - False - - - 186, 22 - - - Pack Settings - - - False - - - False - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4yMfEgaZUAAADfSURBVDhPYxg8 - QLt++3yTGbf/Fm599P/Nh49wfPXxq/+rTt37f+Dak/8gOSBgAGEMANIMxGBFyAasPf/0v8GE8//z1t8C - y4HU4DIALIluwLpLL+HiMANAGKoNAWASCavv/n/57gPcgOvP3oENOXj7NViOoAFGU6791+k4ghWD5Aga - QCyGakMAkODcU89R/I8Ng9TgNADk14dPn/8/c+kqVgySgwUqVBsCwAx49urN/zsPHmPFIDmaGvAXJInN - 38gYasBfqDYE0K7dOn/Wvut/sfkdGYPUgJI9VNuAAwYGAGn6yvdevWgPAAAAAElFTkSuQmCC - - - - Control+S - - - 186, 22 - - - Save - - - False - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4yMfEgaZUAAADfSURBVDhPYxg8 - IEt7+/x6k9t/lxQ++v/2zUc4vnv11f+Dq+79v3DgyX+QHBAwgDAGAGkGYrAiZAOOrX36v9zg/P95ebfA - ciA1uAwAS6IbcGLdS7g4zAAQhmpDAJjEjIS7/1+//AA34MH1d2BDLh98DZYjaECN0bX/BTpHsGKQHEED - iMVQbQgAEtw39zmK/7FhkBqcBoD8+vjh8//nz1zFikFysECFakMAmAEvnr35f//OY6wYJEdTA/6CJLH5 - GxlDDfgL1YYAWdpb52+bdf0vNr8jY5AaULKHahtwwMAAAPeIxBbbnvcfAAAAAElFTkSuQmCC - - - - Control+Shift+S - - - 186, 22 - - - Save As - - - - iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - wQAADsEBuJFr7QAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAEkSURBVFhH7ZfN - asJAFEbzEoo/b6QU36a6LhR8IzdKlVJoQTd24WuUtpuu9Dsjs5FI594ZCEQPHHBg7s2XxISb6k4CE7mW - v/KYKHtf5IPMYi7rDmDxWbrgzGnwJx/lQKbC3qmklh5jaYbLTjGNvFBLj1VYGfmRFPfDykdP0uM7rIxQ - iLm4+7QmAI8jmikVwE0rAizkVnbDykiJABycHp/SHKJEgI7cS/ocpOmd8l+AjYx7Un2XycSia3gCfMhk - YlEOl7eAV3MyJQLsJD0a+xNyyRt9DLNoTYA3+Xr+aaNUAHefxgPEkcwyjF4ylPT4CisjDBEU5wylM0mP - ZVgZ4aOCYkZrQuSM5SPpgo8KGuT4JLPgo4K5ntG67gB1spfL7j7zW6GqTtAaslLCb2cpAAAAAElFTkSu - QmCC - - - - 186, 22 - - - Exit - - - 37, 20 - - - File - - - 39, 20 - - - Edit - - - - iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAL - DAAACwwBP0AiyAAAA6pJREFUeF7tms9vDVEYhouqpFZVRFpdd+cPkFphQeKPqIUfSVl0Y9OQWNpXE/ak - SEhYkEjZUFZERCxtCaKKWKDe787jpNftmTlzz4x0rvMkb3Lzzfu9c8690zkz0+lLJBKJRCKRqIOVlZUx - 6Yb0WSqL9dyUxolrFhq4Tf6DFMtHaYzY5qBB2y9fFdeIbQ4adDeHvY8lYpsDA3dQDoY2B+XmwLgdlIOh - zUG5OTBuB+VgaHNQbg6M20E5GNoclP8N2l/M+r3eKHc9IWNV6/d6I+x6QqYq1+/1RvH1hEy9cNj7KL6e - wNizME0/+HoWpukHX8/CNP3gK8NeWq13IivVStT+aPUjz6R0S/pmDUXQ5qBcG+zGQbmIr5LNaZK2YmQe - lA5K56V70hvpu9QGdgfl2mA3DsqrsTHaWO9KNvYD0iD2RKIIHS7T0h5pA6XGY3NhTtOU/Mj0h7fSFem4 - ZGfbXdIWbOsWGyNjtTGfkK5KNpcW2PzgC4Y2B+XaYDcOysHQ5gdfMLQ5KNcGu3FQDoY2P/jKMEGr9e7L - SrUStT9a/eDrWZimH3x18Ez6kX3M5af0PPtYPUzTD74qeS0dJnumVclnBu9+6UWrUiGWnQu+KrBHUGek - AaIte6N0X/LxUNqE3fz90jHpnVQJRPvBF8ttaZjINlQfkeyXfSktSA+kV5IdKSPY2lB9WLojRUOkH3yx - XCCuMiwzi46DOD/4YrHDfyuR0SjL7kzfW3AsRPrBVwUniYzGsrLIeIj0g68KFoiMRll2nqgEIv3gi+WX - dITIaJR1iMxoiPSDL5aLxFWGZWbRcRDnB18M9ixxB3EdaJvdrp6WnkhfkH0+JXlvt7Vtu2TP9qIgzg++ - GOaI6kDbRqW8y1y7XB7F3oG2zbZcERDlB18ZHkmXpLOSPVEeIqoN1e2XD7nGty9hzSNB9SHpqHROuiw9 - lkpBlB98ZeinNRf57LAPZYq2XOTbnNnDodUPvmBoK0TWp1lHEIu0FYI/GNr84AuGtkJkXc46glimrRD8 - wdDmB18wtBUia5kvIPi1OPzB0OYHXzC0FSJrY/4Eyr4gEXoStHU+lLpOgp9o9SOTvVBUBluKbEmypcmW - qLxl0Ja4IszjHqKsRvVtUswyOE+UH5nGJbud7ZZZojrQNrsQyvsSii6E5lqu7rDb6d1E5SOjvSl2Xerm - fSG7XF3zaZChbQPSlLQo2YnRZL+k1db85Q1t2ykF/cv+L5akeSls8olEIpFIJP4T+vp+A8lMcFIN42ej - AAAAAElFTkSuQmCC - - - - 62, 20 - - - Tools - - - - iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAL - DAAACwwBP0AiyAAAAeRJREFUeF7tzjGOIzEMAEH//9N3SaEzwzLH2plAFTZEUq/jOI7jOI5f+beZM8/l - n9s481z+uY0zz+Wf2zjzHP4VeRtnIt/HPyJv40zk+/hH5G2ciXwf/4i8jTOR/467kW/jG5H3cSfybXwj - 8j7uRL6Nb0Tex53It/GNyL9jb+RlxsasWWYs8pw9kZcZG7NmmbHIc/ZEXmZszJplxiLP2RN5mbExa5YZ - izxnT+RlxiK/5VnkZcYiz9kTeZmxyG95FnmZschz9kReZizyW55FXmYs8pw9kZcZi/yWZ5GXGYs8Z0/k - bZyJvMxY5Dl7Im/jTORlxiLP2RN5G2ciLzMWec6eyNs4E3mZschz9kS+zLqPPF9mLPKcPZEvs+4jz5cZ - izxnT+TLrPvI82XGIs/ZE/ky6z7yfJmxyHP2RL7MusiXWRd5zp7Il1kX+TLrIs/ZE/mxfDPynD2RH8s3 - I8/ZE/mxfDPynD2RH8s3I8/ZE/ky6yJfZl3kOXsiX2Zd5Musi/w79kb+mvHIXzMeeR93In/NeOSvGY+8 - jzuRb+MbkfdxJ/JtfCPy33E38jbORL6Pf0TexpnI9/GPyNs4E/k+/hF5G2ciP4d/bePMc/nnNs48l39u - 48xz+ec2zhzHcRzHcVz0ev0HFtq118xXwn0AAAAASUVORK5CYII= - - - - 60, 20 - - - Help - - - 24, 44 - - - 1016, 24 - - - 2 - - - MainMenuStrip - - - menuStrip - - - System.Windows.Forms.MenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 3 - 151, 22 @@ -1502,12 +167,165 @@ Mash-Up Pack + + + iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4yMfEgaZUAAADuSURBVFhH7ZbB + CsMgEERDbv5A/v83e2jNTmCKGdegJk0heHgUn7vrKBQyxRj/iivJPM9WMTWjc45wJeAwhAghVJEG1nkl + XNkziLCvtteXphFCfQ08nOi+4kvTeFL1NfBQ/BLuefjS9NkAADOwPnpNX14UADBEaV4mNnkygN34Y/1v + AgeWZXll9So2eTLAEVm9ik2a7g1Qgn9t9bvFV/4gAOZdHgB1RPeUEeAZAeBr0d4R4JIACuqI7ikjwDMD + tDACNAfo/Sou0fQ9wGKvoQfO8i61W6SkTXi+XtLLgOwcFSna3It3c+LKO3HlfcRpBa3JBjU5E8DiAAAA + AElFTkSuQmCC + + + + 170, 22 + + + New + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4yMfEgaZUAAABGSURBVDhPYxgc + 4P8Chv8YeKWUIFSaMPi/W+r//1MapOGTOixQ7UADsCkgAkO1jxoAAtgkicFQ7cPCAGLB////wXgwAQYG + AOrUrx4HdAXuAAAAAElFTkSuQmCC + + + + Ctrl+O + + + 170, 22 + + + Open + + + + iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAT + qwAAE6sBnBsJ0QAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAHkSURBVFhH1ZfN + KwVRGIevBRslZUtZsPG1kEhZ21hYKfkTpMTCwoqF4l+QNbKysraU8rW1ZEEUpcg3v2fMYXLn471zz+12 + n3q6c8685z3vzJy65xRqhT45LidyytheWTKD8lR+efJEDkgTTP4kGXgj9+ROThlLDnI9SlMR7sm3ZCMd + ZUKObUnOYzrS6JHuyX1M7iDXrSR3Nx1JsGgI4tX5hpzkZo5EWLkE8f18Q05yM0cipRYwG2qhIgW8h1qo + SAHEooXYAliR93I5aBUXMCy5Pxe0ivFSwKv8lGMyWkCLvAjbizKOsguABcmNOzkdXhO8G14fyAYZB/fR + QmIBddJNdh7+noW/FNUukyAGLSQWANHXjR/SfZY0XHxb0EontQAYkm/SJV2TWRxKYi9l1t9uZgGwLgm6 + lvV0ZNAs9yVjHuSoTMJUAOthRrYGLRss0E1J8hc5JeMwFZAXCl+VTMDaWZL/qWgBjnnJAmaiFToimD/B + iGwKWvmYlM/yKmj9YSqARUTQRtDKT4fs/Ln8xVQANwki2De1UUDVt2RuU8oGslKb0i460uAQQSBbaR9F + kMNty4/oyILDA4cI9yZ4dXy/PDLWPTk5+6UJiuAQwUAf8uTmyaOwY2LRsHLzyNjUg0iVKBS+AWAi5w3z + cKwSAAAAAElFTkSuQmCC + + + + 170, 22 + + + Recently open + 160, 22 Full box support + + 170, 22 + + + Pack Settings + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4yMfEgaZUAAADfSURBVDhPYxg8 + IEt7+/x6k9t/lxQ++v/2zUc4vnv11f+Dq+79v3DgyX+QHBAwgDAGAGkGYrAiZAOOrX36v9zg/P95ebfA + ciA1uAwAS6IbcGLdS7g4zAAQhmpDAJjEjIS7/1+//AA34MH1d2BDLh98DZYjaECN0bX/BTpHsGKQHEED + iMVQbQgAEtw39zmK/7FhkBqcBoD8+vjh8//nz1zFikFysECFakMAmAEvnr35f//OY6wYJEdTA/6CJLH5 + GxlDDfgL1YYAWdpb52+bdf0vNr8jY5AaULKHahtwwMAAAPeIxBbbnvcfAAAAAElFTkSuQmCC + + + + Ctrl+Shift+S + + + 170, 22 + + + Save + + + + False + + + 170, 22 + + + Save As + + + False + + + + iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAn + WwAAJ1sB4ns9eAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANoSURBVHhe7Zs7 + j01RGIbH/U6EKIRGFAoVnYIECXG/K/wG0dMpNQqRoJWIW4KIRCgURKIgKJQqChEFkaBweZ9ikpM975o5 + Z+9vrb0l+0meZs6Z/a3vnX1de81YT09PT08ZlsoT8ry8Jm/W8IrcLv8r5siz8rv8G+AfeVz+FyyTT6Vr + pIlss/Owy7+UroGmpgLYIt/Ib/K2XC5bYbF8Id3gm8ohcExW2S1/ysHvct4ozkL5TA4OZNBP8r6snuCG + kZPgNlnFNY9fZVHmyyeyOpBxr0sCiiTVPL6SxZgrH0k3ELwhZ8hIJmuen2+WRZgt2a3dQPCOnCUj2Sl/ + SFfvl9wni0BjNOgGgg8kAUUy2V8eT8oisEuza7tBIIcEh0YkUzWPR2V2psur0g0AuRJEn/Am2+0HzR7A + NHlJuuL4XC6SkQzbPGYNgOYvSlcYufRwFxjJKM1j1gBOS1cUczQ/1aXO/TxbABvlb+mKvpU8/EQyVfN8 + 7j7LFsA96Qq+kytkJMM0D+7zLAFwUuMGo1rsvVwpIxm2eXDfyRLAJumK7ZCRjNI8uO8dkeEckK7YPBnF + qM1zRXLfzRIAG3XFGEQEde7tUwEcluHkDKDugw13o+53sgTARl2xpgHUbR5SARyS4aQCYBB1adI88DDm + fjdLAGzUFasbQNPmoRMB1JnliWgeUgEclOFEBRDVPMyUbjtZAmCjrtgoAUQ2D6kAuGcJJxUAgxiG6OaB + 6Ti3vSwBpO4EhwkgR/PQiQCmmu3N1TykAtgvw6kTQM7mgdlmt+0sAfBKqlqI5lL3AaM+2NShaABL5Gc5 + WOiudJRoHooGAMwJ8Mqbl468fnazQKWaBxZfuDpND63a5D7mq6QC2CuLU7p54K2Tq1c8gDaah04E0Fbz + kApgjyxCm80D85GudpEA2m4eWgugC80DS3LcGCIvtRPoSvNQPIAuNQ+pAHbJcLrWPCyQbjzhAXSxeSgS + AMtPU/f26FZtlmKVdGPaKsNg7a0rMi4LJtrijHRjWivDYOGxKzLoa/lY8oRYXd4aLTWoRU03lo+yycua + CdySrlBXPSdDYck5qTMHwOFAwq5wF/wgo9coTWC9/CLdANqU2aoNsgir5UPpBtKGrEhdI4uzTp6SF+Rl + WfefoUaRGtSiJrUZQ09PT0/P6IyN/QP3CwGw14CDlAAAAABJRU5ErkJggg== + + + + 170, 22 + + + Close + + + False + + + 170, 22 + + + Close all + + + + iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAEkSURBVFhH7ZfN + asJAFEbzEoo/b6QU36a6LhR8IzdKlVJoQTd24WuUtpuu9Dsjs5FI594ZCEQPHHBg7s2XxISb6k4CE7mW + v/KYKHtf5IPMYi7rDmDxWbrgzGnwJx/lQKbC3qmklh5jaYbLTjGNvFBLj1VYGfmRFPfDykdP0uM7rIxQ + iLm4+7QmAI8jmikVwE0rAizkVnbDykiJABycHp/SHKJEgI7cS/ocpOmd8l+AjYx7Un2XycSia3gCfMhk + YlEOl7eAV3MyJQLsJD0a+xNyyRt9DLNoTYA3+Xr+aaNUAHefxgPEkcwyjF4ylPT4CisjDBEU5wylM0mP + ZVgZ4aOCYkZrQuSM5SPpgo8KGuT4JLPgo4K5ntG67gB1spfL7j7zW6GqTtAaslLCb2cpAAAAAElFTkSu + QmCC + + + + 170, 22 + + + Exit + + + 37, 20 + + + File + False @@ -1657,7 +475,7 @@ - Control+Q + Ctrl+Q 192, 22 @@ -1665,10 +483,16 @@ Quick Change + + 39, 20 + + + Edit + iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAA - rgAAAK4B+ff3XQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAHrSURBVFhH7dZB + qAAAAKgBefSzxgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAHrSURBVFhH7dZB KCVxAMfxhyinTbQHXOyFLW1JbW1tkshBIuHi4LxtOWhbm/ZkLw6iOEgpJyUHJScUUqK4bBSrlCthV3bb k13f3zP/Z+b5z/PGvMfl/epTM/znP795b95/JpJJEilHD/p8tCMfaUkF/uL/A5aQlujKdYJ52K5eDqAx DUh5PkGTq4hfOqEx6ygIIAvWvMUYJrAJTb7h7MswqmGSjT1oXBDnaIYnRbiC7QA3jSmGSSV0HxwFcI1D @@ -1686,12 +510,6 @@ Pck Manager - - 161, 22 - - - Audio Converter - 145, 22 @@ -1704,6 +522,40 @@ Binka -> Wav + + 161, 22 + + + Audio Converter + + + + iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAL + DAAACwwBP0AiyAAAA6pJREFUeF7tms9vDVEYhouqpFZVRFpdd+cPkFphQeKPqIUfSVl0Y9OQWNpXE/ak + SEhYkEjZUFZERCxtCaKKWKDe787jpNftmTlzz4x0rvMkb3Lzzfu9c8690zkz0+lLJBKJRCKRqIOVlZUx + 6Yb0WSqL9dyUxolrFhq4Tf6DFMtHaYzY5qBB2y9fFdeIbQ4adDeHvY8lYpsDA3dQDoY2B+XmwLgdlIOh + zUG5OTBuB+VgaHNQbg6M20E5GNoclP8N2l/M+r3eKHc9IWNV6/d6I+x6QqYq1+/1RvH1hEy9cNj7KL6e + wNizME0/+HoWpukHX8/CNP3gK8NeWq13IivVStT+aPUjz6R0S/pmDUXQ5qBcG+zGQbmIr5LNaZK2YmQe + lA5K56V70hvpu9QGdgfl2mA3DsqrsTHaWO9KNvYD0iD2RKIIHS7T0h5pA6XGY3NhTtOU/Mj0h7fSFem4 + ZGfbXdIWbOsWGyNjtTGfkK5KNpcW2PzgC4Y2B+XaYDcOysHQ5gdfMLQ5KNcGu3FQDoY2P/jKMEGr9e7L + SrUStT9a/eDrWZimH3x18Ez6kX3M5af0PPtYPUzTD74qeS0dJnumVclnBu9+6UWrUiGWnQu+KrBHUGek + AaIte6N0X/LxUNqE3fz90jHpnVQJRPvBF8ttaZjINlQfkeyXfSktSA+kV5IdKSPY2lB9WLojRUOkH3yx + XCCuMiwzi46DOD/4YrHDfyuR0SjL7kzfW3AsRPrBVwUniYzGsrLIeIj0g68KFoiMRll2nqgEIv3gi+WX + dITIaJR1iMxoiPSDL5aLxFWGZWbRcRDnB18M9ixxB3EdaJvdrp6WnkhfkH0+JXlvt7Vtu2TP9qIgzg++ + GOaI6kDbRqW8y1y7XB7F3oG2zbZcERDlB18ZHkmXpLOSPVEeIqoN1e2XD7nGty9hzSNB9SHpqHROuiw9 + lkpBlB98ZeinNRf57LAPZYq2XOTbnNnDodUPvmBoK0TWp1lHEIu0FYI/GNr84AuGtkJkXc46glimrRD8 + wdDmB18wtBUia5kvIPi1OPzB0OYHXzC0FSJrY/4Eyr4gEXoStHU+lLpOgp9o9SOTvVBUBluKbEmypcmW + qLxl0Ja4IszjHqKsRvVtUswyOE+UH5nGJbud7ZZZojrQNrsQyvsSii6E5lqu7rDb6d1E5SOjvSl2Xerm + fSG7XF3zaZChbQPSlLQo2YnRZL+k1db85Q1t2ykF/cv+L5akeSls8olEIpFIJP4T+vp+A8lMcFIN42ej + AAAAAElFTkSuQmCC + + + + 62, 20 + + + Tools + iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO @@ -2217,20 +1069,6 @@ About - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAKdJREFUOE+1 - jzEKwzAQBNUEXKQIBOwifcgTUvkDbt2p9qP0Ev1E31FYkVXOx2FLRRYWi7NnTnZ/z/MxZPY7aguhbZlq - myQafL+ubRINshCwnO0kFqi3HkpwWOf7DkC1RBfvx9slV4ElscqbxBiz9/4nwOBIQjCEUL7FswhwDYAp - JVMiN0oYs/ILiCXRIGHOwVQBoiXsKSgjJdzaBMpQ0g3KEOoG++PcBx9PFJGNjU4vAAAAAElFTkSuQmCC - - - - 205, 22 - - - Tutorials - 312, 22 @@ -2273,6 +1111,38 @@ How PCKs work + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAKdJREFUOE+1 + jzEKwzAQBNUEXKQIBOwifcgTUvkDbt2p9qP0Ev1E31FYkVXOx2FLRRYWi7NnTnZ/z/MxZPY7aguhbZlq + myQafL+ubRINshCwnO0kFqi3HkpwWOf7DkC1RBfvx9slV4ElscqbxBiz9/4nwOBIQjCEUL7FswhwDYAp + JVMiN0oYs/ILiCXRIGHOwVQBoiXsKSgjJdzaBMpQ0g3KEOoG++PcBx9PFJGNjU4vAAAAAElFTkSuQmCC + + + + 205, 22 + + + Tutorials + + + 233, 22 + + + Nobledez (Original Developer) + + + 233, 22 + + + PhoenixARC (Developer) + + + 233, 22 + + + MattNL (Other Developer) + iVBORw0KGgoAAAANSUhEUgAAAgAAAAIBCAYAAAA/JAdfAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAN @@ -2571,24 +1441,6 @@ Support a Developer - - 233, 22 - - - Nobledez (Original Developer) - - - 233, 22 - - - PhoenixARC (Developer) - - - 233, 22 - - - MattNL (Other Developer) - iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO @@ -3045,159 +1897,67 @@ Settings - - 298, 17 - - - 182, 92 - - - contextMenuMetaTree - - - System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - + - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAABSSURBVDhP5c0x - DsAgDENRxt7/wmkNSpRGf0CCCZAegxNMM7MlGMp3dIU6dxhKf/QMNxRogeQC8ivw5Vn7C0heJlFA+kL5 - jWAohxRkde4wnGftBS90axNmphIGAAAAAElFTkSuQmCC + iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAL + DAAACwwBP0AiyAAAAeRJREFUeF7tzjGOIzEMAEH//9N3SaEzwzLH2plAFTZEUq/jOI7jOI5f+beZM8/l + n9s481z+uY0zz+Wf2zjzHP4VeRtnIt/HPyJv40zk+/hH5G2ciXwf/4i8jTOR/467kW/jG5H3cSfybXwj + 8j7uRL6Nb0Tex53It/GNyL9jb+RlxsasWWYs8pw9kZcZG7NmmbHIc/ZEXmZszJplxiLP2RN5mbExa5YZ + izxnT+RlxiK/5VnkZcYiz9kTeZmxyG95FnmZschz9kReZizyW55FXmYs8pw9kZcZi/yWZ5GXGYs8Z0/k + bZyJvMxY5Dl7Im/jTORlxiLP2RN5G2ciLzMWec6eyNs4E3mZschz9kS+zLqPPF9mLPKcPZEvs+4jz5cZ + izxnT+TLrPvI82XGIs/ZE/ky6z7yfJmxyHP2RL7MusiXWRd5zp7Il1kX+TLrIs/ZE/mxfDPynD2RH8s3 + I8/ZE/mxfDPynD2RH8s3I8/ZE/ky6yJfZl3kOXsiX2Zd5Musi/w79kb+mvHIXzMeeR93In/NeOSvGY+8 + jzuRb+MbkfdxJ/JtfCPy33E38jbORL6Pf0TexpnI9/GPyNs4E/k+/hF5G2ciP4d/bePMc/nnNs48l39u + 48xz+ec2zhzHcRzHcVz0ev0HFtq118xXwn0AAAAASUVORK5CYII= - - 181, 22 + + 60, 20 - - Add Entry + + Help - - 160, 22 + + 14, 3 - - Add Entry + + 0, 6, 60, 0 - - 160, 22 + + 326, 24 - - Add BOX Entry - - - 160, 22 - - - Add ANIM Entry - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAABSSURBVDhP5c0x - DsAgDENRxt7/wmkNSpRGf0CCCZAegxNMM7MlGMp3dIU6dxhKf/QMNxRogeQC8ivw5Vn7C0heJlFA+kL5 - jWAohxRkde4wnGftBS90axNmphIGAAAAAElFTkSuQmCC - - - - 181, 22 - - - Add Multiple Entries - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAACESURBVDhPlY0B - DoAgDAP3Dj7r09WTkqGUgJfUxtrOmHFEnL0U76FBqW8PZXmk/9uONEsIb3gsNRzoL/+R5hWC759mGsbQ - DnzdZbhmiSvhLsM1S1wJdxmuWeJKuMtwzRJXwl2Ga5a4Eu4yXLPElXCX4Zol/WCl6YGdI62n2Zv2cSXV - byIunLh7mD2ySLcAAAAASUVORK5CYII= - - - - 181, 22 - - - Delete Entry - - - 181, 22 - - - Edit All Entries - - - openTab - - - MetroFramework.Controls.MetroTabPage, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - tabControl - - - 0 - - - editorTab - - - MetroFramework.Controls.MetroTabPage, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - tabControl - - - 1 - - - Fill - - - 20, 30 - - - 0, 0, 0, 0 - - - 1024, 600 - - - 0 - - - tabControl - - - MetroFramework.Controls.MetroTabControl, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - $this - - - 4 - - - pckOpen - - - System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - openTab - - + 2 - - label5 + + MainMenuStrip - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + menuStrip - - openTab + + System.Windows.Forms.MenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 3 + + $this + + + 0 + + + True + + + 18, 11 + + + 116, 19 + + + 11 + + + PCK Studio: 1.3.3.7 labelVersion @@ -3206,10 +1966,64 @@ MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - openTab + StartPage - 4 + 2 + + + Top, Right + + + True + + + 572, 11 + + + 81, 19 + + + 23 + + + Whats New? + + + MiddleCenter + + + label5 + + + MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + StartPage + + + 3 + + + Right + + + Segoe UI, 8.25pt + + + 593, 0 + + + 0, 0, 30, 30 + + + 423, 558 + + + 22 + + + ChangelogRichTextBox @@ -3218,34 +2032,10 @@ System.Windows.Forms.RichTextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - openTab + StartPage - 5 - - - 4, 38 - - - 18, 30, 20, 5 - - - 1016, 558 - - - 1 - - - openTab - - - MetroFramework.Controls.MetroTabPage, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - tabControl - - - 0 + 4 None @@ -4238,13 +3028,13 @@ NoControl - 18, 30 + 0, 0 20, 20, 20, 20 - 534, 523 + 534, 558 Zoom @@ -4259,628 +3049,64 @@ System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - openTab + StartPage - 2 - - - Top, Right - - - True - - - 572, 11 - - - 81, 19 - - - 23 - - - Whats New? - - - MiddleCenter - - - label5 - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - openTab - - - 3 - - - True - - - 18, 11 - - - 116, 19 - - - 11 - - - PCK Studio: 1.3.3.7 - - - labelVersion - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - openTab - - - 4 - - - Right - - - Segoe UI, 8.25pt - - - 573, 30 - - - 0, 0, 30, 30 - - - 423, 523 - - - 22 - - - - - - ChangelogRichTextBox - - - System.Windows.Forms.RichTextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - openTab - - 5 - - True - - - None - - - pckFileLabel - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - editorTab - - - 2 - - - labelImageSize - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - editorTab - - - 3 - - - fileEntryCountLabel - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - editorTab - - - 4 - - - PropertiesTabControl - - - MetroFramework.Controls.MetroTabControl, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - editorTab - - - 5 - - - label11 - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - editorTab - - - 6 - - - treeViewMain - - - System.Windows.Forms.TreeView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - editorTab - - - 7 - - - previewPictureBox - - - PckStudio.ToolboxItems.InterpolationPictureBox, PCK-Studio, Version=7.0.0.0, Culture=neutral, PublicKeyToken=null - - - editorTab - - - 9 - - + 4, 38 - - 5, 50, 5, 7 - - + 1016, 558 - + 0 - - editorTab + + Start Page - + + StartPage + + MetroFramework.Controls.MetroTabPage, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - + tabControl - + + 0 + + + Fill + + + 20, 30 + + + 0, 0, 0, 0 + + + 1024, 600 + + + 0 + + + tabControl + + + PckStudio.Controls.CustomTabControl, PCK-Studio, Version=7.0.0.2, Culture=neutral, PublicKeyToken=null + + + $this + + 1 - - 3, 17 - - - 332, 23 - - - 2 - - - pckFileLabel - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - editorTab - - - 2 - - - Top, Right - - - True - - - 935, 252 - - - 0, 0 - - - 19 - - - labelImageSize - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - editorTab - - - 3 - - - Top, Right - - - True - - - 913, 53 - - - 0, 0 - - - 17 - - - fileEntryCountLabel - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - editorTab - - - 4 - - - Top, Bottom, Right - - - MetaTab - - - MetroFramework.Controls.MetroTabPage, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - PropertiesTabControl - - - 0 - - - 338, 277 - - - 671, 282 - - - 11 - - - PropertiesTabControl - - - MetroFramework.Controls.MetroTabControl, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - editorTab - - - 5 - - - metroLabel2 - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - MetaTab - - - 2 - - - treeMeta - - - System.Windows.Forms.TreeView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - MetaTab - - - 3 - - - entryTypeTextBox - - - MetroFramework.Controls.MetroTextBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - MetaTab - - - 4 - - - entryDataTextBox - - - MetroFramework.Controls.MetroTextBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - MetaTab - - - 5 - - - buttonEdit - - - MetroFramework.Controls.MetroButton, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - MetaTab - - - 6 - - - metroLabel1 - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - MetaTab - - - 7 - - - 4, 38 - - - 3, 3, 3, 3 - - - 663, 240 - - - 0 - - - Properties - - - MetaTab - - - MetroFramework.Controls.MetroTabPage, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - PropertiesTabControl - - - 0 - - - Top, Right - - - True - - - 288, 119 - - - 0, 0 - - - 15 - - - metroLabel2 - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - MetaTab - - - 2 - - - Left - - - False - - - 3, 3 - - - 204, 234 - - - 0 - - - treeMeta - - - System.Windows.Forms.TreeView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - MetaTab - - - 3 - - - Top, Right - - - - - - NoControl - - - 199, 1 - - - 21, 21 - - - 1 - - - False - - - False - - - 283, 119 - - - 186, 23 - - - 21 - - - entryTypeTextBox - - - MetroFramework.Controls.MetroTextBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - MetaTab - - - 4 - - - Top, Right - - - - - - NoControl - - - 199, 1 - - - 21, 21 - - - 1 - - - False - - - False - - - 283, 151 - - - 186, 23 - - - 16 - - - entryDataTextBox - - - MetroFramework.Controls.MetroTextBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - MetaTab - - - 5 - - - Bottom, Right - - - 283, 180 - - - 186, 60 - - - 20 - - - buttonEdit - - - False - - - buttonEdit - - - MetroFramework.Controls.MetroButton, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - MetaTab - - - 6 - - - Top, Right - - - True - - - 288, 68 - - - 0, 0 - - - 13 - - - metroLabel1 - - - MetroFramework.Controls.MetroLabel, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - MetaTab - - - 7 + + None True @@ -4907,113 +3133,26 @@ editorTab - 6 - - - Top, Bottom, Left, Right - - - False - - - 0 - - - 467, 14 - - - 32, 32 - - - 5, 50 - - - 0, 0, 0, 0 - - - 0 - - - 330, 501 - - - 10 - - - treeViewMain - - - System.Windows.Forms.TreeView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - editorTab - - - 7 - - - Top, Right - - - None - - - NoControl - - - 345, 50 - - - 231, 218 - - - Zoom - - - 18 - - - previewPictureBox - - - PckStudio.ToolboxItems.InterpolationPictureBox, PCK-Studio, Version=7.0.0.0, Culture=neutral, PublicKeyToken=null - - - editorTab - - - 9 - - - Top, Right - - - True - - - 826, 49 - - - 207, 15 - - - 21 - - - Open/Save as Switch/Vita/PS4/Xbox One PCK - - - LittleEndianCheckBox - - - MetroFramework.Controls.MetroCheckBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - $this - - 2 + + 4, 38 + + + 5, 50, 5, 7 + + + 1016, 558 + + + 0 + + + editorTab + + + MetroFramework.Controls.MetroTabPage, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + True @@ -7568,282 +5707,6 @@ System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - createToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - folderToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - skinToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - createAnimatedTextureToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - audiopckToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - colourscolToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - CreateSkinsPCKToolStripMenuItem1 - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - behavioursbinToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - entityMaterialsbinToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - importSkinsToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - importSkinToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - importExtractedSkinsFolderToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - addTextureToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - addFileToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - exportToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - as3DSTextureFileToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - setFileTypeToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - skinToolStripMenuItem1 - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - capeToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - textureToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - languagesFileLOCToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - gameRulesFileGRFToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - audioPCKFileToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - coloursCOLFileToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - gameRulesHeaderGRHToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - skinsPCKToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - modelsFileBINToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - behavioursFileBINToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - entityMaterialsFileBINToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripSeparator5 - - - System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - generateMipMapTextureToolStripMenuItem1 - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - viewFileInfoToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - correctSkinDecimalsToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - setSubPCKEndiannessToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - bigEndianXbox360PS3WiiUToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - littleEndianPS4PSVitaSwitchToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - setModelContainerFormatToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - version1ToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - version2ToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - version3114ToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripSeparator6 - - - System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - extractToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - cloneFileToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - renameFileToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - replaceToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - deleteFileToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - fileToolStripMenuItem @@ -7898,24 +5761,30 @@ System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - saveToolStripMenuItem1 - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - saveToolStripMenuItem System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + saveAsToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + closeToolStripMenuItem System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + closeAllToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + exitToolStripMenuItem @@ -8072,58 +5941,10 @@ System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - addEntryToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - addEntryToolStripMenuItem1 - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - addBOXEntryToolStripMenuItem1 - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - addANIMEntryToolStripMenuItem1 - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - addMultipleEntriesToolStripMenuItem1 - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - deleteEntryToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - editAllEntriesToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - imageList - - - System.Windows.Forms.ImageList, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - MainForm MetroFramework.Forms.MetroForm, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - + \ No newline at end of file diff --git a/PCK-Studio/PckStudio.csproj b/PCK-Studio/PckStudio.csproj index 30f83256..a19172de 100644 --- a/PCK-Studio/PckStudio.csproj +++ b/PCK-Studio/PckStudio.csproj @@ -108,6 +108,7 @@ Properties\app.manifest + @@ -135,10 +136,22 @@ - - - - + + Component + + + UserControl + + + Form + + + + UserControl + + + PckEditor.cs + Form @@ -151,32 +164,39 @@ ContributorsForm.cs - - - - - - - - - - - - - - - - - - - - - + + Form + + + ModelEditor.cs + + + + + + + + True True Resources.resx + + UserControl + + + ModelRenderer.cs + + + UserControl + + + UserControl + + + SkinRenderer.cs + Component @@ -193,11 +213,6 @@ Component - - - - - Form @@ -210,75 +225,19 @@ AppSettingsForm.cs - Form TextureAtlasEditor.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Component - - - ModelView.cs - - - - - - - - - - - UserControl CemuPanel.cs - - - - - - - - Form @@ -310,7 +269,6 @@ MultiTextPrompt.cs - Component @@ -411,17 +369,11 @@ MainForm.cs - + Form - - generateModel.cs - - - Form - - - SkinPreview.cs + + CustomSkinEditor.cs Form @@ -441,16 +393,20 @@ AudioEditor.cs - - + + PckEditor.cs + FilterPrompt.cs ContributorsForm.cs + + ModelEditor.cs + CemuPanel.cs @@ -554,14 +510,12 @@ MainForm.cs Designer - - generateModel.cs + + CustomSkinEditor.cs - - generateModel.cs - - - SkinPreview.cs + + CustomSkinEditor.cs + Designer AnimationEditor.cs @@ -578,6 +532,12 @@ Designer Resources.Designer.cs + + ModelRenderer.cs + + + SkinRenderer.cs + GithubUserPanel.cs @@ -609,6 +569,18 @@ + + + + + + + + + + + + @@ -665,6 +637,8 @@ + + @@ -684,17 +658,11 @@ 1.0.5 - - 1.9.2 - 5.8.0-alpha0098 compile; runtime; build; native; contentfiles; analyzers; buildtransitive all - - 1.2.1.24 - 1.2.0.3 @@ -733,6 +701,18 @@ + + {345eabed-f0d1-4d04-b409-babdef747352} + PckStudio.Core + + + {b1e19d0f-6dd5-4d91-9b45-9818759ca8ef} + PckStudio.Rendering + + + {43bcacd7-5405-4499-9b45-e1435ac03c26} + PckStuido.ModelSupport + {693AEBC1-293D-4DF0-BCAE-26A1099FE7BB} OMI Filetype Library diff --git a/PCK-Studio/Program.cs b/PCK-Studio/Program.cs index 64c19d7e..5d11a7d5 100644 --- a/PCK-Studio/Program.cs +++ b/PCK-Studio/Program.cs @@ -2,8 +2,11 @@ using System.Diagnostics; using System.IO; using System.Windows.Forms; -using PckStudio.Internal.Misc; using PckStudio.Internal.App; +using System.Linq; +using PckStudio.Internal; +using PckStudio.Core.App; +using PckStudio.Properties; namespace PckStudio @@ -26,15 +29,17 @@ namespace PckStudio [STAThread] static void Main(string[] args) { - Updater.Initialize(RawProjectUrl); + Updater.Initialize(RawProjectUrl, Settings.Default.AutoUpdate); ApplicationScope.Initialize(); Trace.TraceInformation("Startup"); RPC.Initialize(); MainInstance = new MainForm(); Updater.SetOwner(MainInstance); - if (args.Length > 0 && File.Exists(args[0]) && args[0].EndsWith(".pck")) - MainInstance.InitPckFromFile(args[0]); + if (args.Length > 0) + { + MainInstance.LoadPckFromFile(args.Where(arg => File.Exists(arg) && arg.EndsWith(".pck"))); + } Application.ApplicationExit += (sender, e) => { RPC.Deinitialize(); }; MainInstance.FocusMe(); Application.Run(MainInstance); diff --git a/PCK-Studio/Properties/Resources.Designer.cs b/PCK-Studio/Properties/Resources.Designer.cs index 27cbbf9d..58faab03 100644 --- a/PCK-Studio/Properties/Resources.Designer.cs +++ b/PCK-Studio/Properties/Resources.Designer.cs @@ -70,16 +70,6 @@ namespace PckStudio.Properties { } } - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap additional_map_icons_atlas { - get { - object obj = ResourceManager.GetObject("additional_map_icons_atlas", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -93,51 +83,19 @@ namespace PckStudio.Properties { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap ARROW { + public static System.Drawing.Bitmap armor { get { - object obj = ResourceManager.GetObject("ARROW", resourceCulture); + object obj = ResourceManager.GetObject("armor", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } - /// - /// Looks up a localized string similar to { - /// "COMMENT_1": "JSON by MattNL", - /// "entries": [ - /// { - /// "internalName": "base", - /// "displayName": "Base", - /// "hasColourEntry": true, - /// "colourEntry": { - /// "defaultName": "Banner_White", - /// "variants": [ - /// "Banner_Black", - /// "Banner_Blue", - /// "Banner_Brown", - /// "Banner_Cyan", - /// "Banner_Gray", - /// "Banner_Green", - /// "Banner_Light_Blue", - /// "Banner_Lime", - /// "Banner_Magenta", - /// "Banner_Orange", - /// "Banner_Pink", - /// "Banner_Purple", - /// "Banner_Red", - /// "Ban [rest of string was truncated]";. - /// - public static string bannerData { - get { - return ResourceManager.GetString("bannerData", resourceCulture); - } - } - /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap banners_atlas { + public static System.Drawing.Bitmap ARROW { get { - object obj = ResourceManager.GetObject("banners_atlas", resourceCulture); + object obj = ResourceManager.GetObject("ARROW", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -192,38 +150,6 @@ namespace PckStudio.Properties { } } - /// - /// Looks up a localized string similar to { - /// "COMMENT_1": "Tile data research by MattNL", - /// "COMMENT_2": "JSON by PhoenixARC, MattNL, and NessieHax (Miku-666)", - /// "entries": [ - /// { - /// "internalName": "grass_top", - /// "displayName": "Grass Block (Top)", - /// "hasColourEntry": true, - /// "colourEntry": { - /// "defaultName": "Grass_Common", - /// "variants": [ - /// "Grass_Common", - /// "Grass_Mesa", - /// "Grass_Swamp1", - /// "Grass_Swamp2" - /// ] - /// } - /// }, - /// { - /// "internalName": "stone", - /// "displayName": "Stone" - /// }, - /// { - /// "internalName": [rest of string was truncated]";. - /// - public static string blockData { - get { - return ResourceManager.GetString("blockData", resourceCulture); - } - } - /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -235,9 +161,8 @@ namespace PckStudio.Properties { } /// - /// Looks up a localized string similar to 7.0 (IN DEVELOPMENT) + /// Looks up a localized string similar to 7.0.0.0 ///==================== - ///Some features may be completely missing or incomplete at this point in time! /// ///-Added .3dst (3DS Texture) support ///-Semi-added Sub-Pck editing @@ -248,7 +173,8 @@ namespace PckStudio.Properties { ///-Massive codebase overhaul and optimization lead by miku-666 (aka NessieHax)!!! ///-Some UI redesigned by yaboiFoxx ///-Improved the changelog! - ///-New icons for each o [rest of string was truncated]";. + ///-New icons for each of the file types, with unique image icons for skin, texture, and cape files + ///-Added the abili [rest of string was truncated]";. /// public static string CHANGELOG { get { @@ -299,9 +225,9 @@ namespace PckStudio.Properties { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap Comparison { + public static System.Drawing.Bitmap DefaultSkyTexture { get { - object obj = ResourceManager.GetObject("Comparison", resourceCulture); + object obj = ResourceManager.GetObject("DefaultSkyTexture", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -446,88 +372,6 @@ namespace PckStudio.Properties { } } - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap experience_orbs_atlas { - get { - object obj = ResourceManager.GetObject("experience_orbs_atlas", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized string similar to { - /// "COMMENT_1": "JSON by MattNL", - /// "entries": [ - /// { - /// "internalName": "experience_orb_0", - /// "displayName": "Experience Orb (Size 1)", - /// "hasColourEntry": true, - /// "colourEntry": { - /// "defaultName": "experience_orb", - /// "variants": ["experience_orb"] - /// } - /// }, - /// { - /// "internalName": "experience_orb_1", - /// "displayName": "Experience Orb (Size 2)", - /// "hasColourEntry": true, - /// "colourEntry": { - /// "defaultName": "experience_orb", - /// "variants": ["experience_orb"] - /// } - /// }, - /// { - /// " [rest of string was truncated]";. - /// - public static string experienceOrbData { - get { - return ResourceManager.GetString("experienceOrbData", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to { - /// "COMMENT_1": "JSON by MattNL", - /// "entries": [ - /// { - /// "internalName": "explosion_0", - /// "displayName": "Explosion (Stage 1)", - /// "hasColourEntry": true, - /// "colourEntry": { - /// "defaultName": "Particle_Explode", - /// "variants": [ - /// "Particle_Explode", - /// "Particle_HugeExplosion" - /// ] - /// } - /// }, - /// { - /// "internalName": "explosion_1", - /// "displayName": "Explosion (Stage 2)", - /// "hasColourEntry": true, - /// "colourEntry": { - /// "defaultName": "Particle_Explode", - /// "variants": [ - /// [rest of string was truncated]";. - /// - public static string explosionData { - get { - return ResourceManager.GetString("explosionData", resourceCulture); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap explosions_atlas { - get { - object obj = ResourceManager.GetObject("explosions_atlas", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -608,6 +452,47 @@ namespace PckStudio.Properties { } } + /// + /// Looks up a localized string similar to #version 330 core + /// + ///layout(location = 0) out vec4 color; + /// + ///uniform sampler2D screenTexture; + /// + ///in vec2 texCoords; + /// + ///void main() + ///{ + /// vec3 texColor = texture(screenTexture, texCoords).rgb; + /// color = vec4(texColor, 1.0); + ///}. + /// + public static string framebufferFragmentShader { + get { + return ResourceManager.GetString("framebufferFragmentShader", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to #version 330 core + /// + ///layout(location = 0) in vec4 a_PosAndTexCoord; + /// + ///out vec2 texCoords; + /// + ///void main() + ///{ + /// vec2 pos = a_PosAndTexCoord.xy; + /// texCoords = a_PosAndTexCoord.zw; + /// gl_Position = vec4(pos, 0.0, 1.0); + ///};. + /// + public static string framebufferVertexShader { + get { + return ResourceManager.GetString("framebufferVertexShader", resourceCulture); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -658,44 +543,6 @@ namespace PckStudio.Properties { } } - /// - /// Looks up a localized string similar to { - /// "COMMENT_1": "Tile data research by MattNL", - /// "COMMENT_2": "JSON by PhoenixARC, MattNL, and NessieHax (Miku-666)", - /// "entries": [ - /// { - /// "internalName": "helmetCloth", - /// "displayName": "Leather Cap", - /// "hasColourEntry": true, - /// "colourEntry": { - /// "hasCustomColour": true, - /// "defaultName": "Armour_Default_Leather_Colour", - /// "variants": [ "Armour_Default_Leather_Colour" ] - /// } - /// }, - /// { - /// "internalName": "helmetChain", - /// "displayName": "Chain Helmet" - /// }, - /// { - /// "internalName": " [rest of string was truncated]";. - /// - public static string itemData { - get { - return ResourceManager.GetString("itemData", resourceCulture); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap items_atlas { - get { - object obj = ResourceManager.GetObject("items_atlas", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -706,53 +553,6 @@ namespace PckStudio.Properties { } } - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap map_icons_atlas { - get { - object obj = ResourceManager.GetObject("map_icons_atlas", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized string similar to { - /// "COMMENT_1": "JSON by MattNL", - /// "entries": [ - /// { - /// "internalName": "player_1", - /// "displayName": "Player 1" - /// }, - /// { - /// "internalName": "player_2", - /// "displayName": "Player 2" - /// }, - /// { - /// "internalName": "player_3", - /// "displayName": "Player 3" - /// }, - /// { - /// "internalName": "player_4", - /// "displayName": "Player 4" - /// }, - /// { - /// "internalName": "target_x", - /// "displayName": "Unused" - /// }, - /// { - /// "internalName": "target_point", - /// "displayName": "Target Point (Unused)" - /// }, - /// { - /// [rest of string was truncated]";. - /// - public static string mapIconData { - get { - return ResourceManager.GetString("mapIconData", resourceCulture); - } - } - /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -763,50 +563,6 @@ namespace PckStudio.Properties { } } - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap moon_phases_atlas { - get { - object obj = ResourceManager.GetObject("moon_phases_atlas", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized string similar to { - /// "COMMENT_1": "JSON by MattNL", - /// "entries": [ - /// { - /// "internalName": "moon_phase_0", - /// "displayName": "Full Moon" - /// }, - /// { - /// "internalName": "moon_phase_1", - /// "displayName": "Waning Gibbous" - /// }, - /// { - /// "internalName": "moon_phase_2", - /// "displayName": "Last Quarter" - /// }, - /// { - /// "internalName": "moon_phase_3", - /// "displayName": "Waning Crescent" - /// }, - /// { - /// "internalName": "moon_phase_4", - /// "displayName": "New Moon" - /// }, - /// { - /// "internalName": "moon_phase_5", - /// "displayName": [rest of string was truncated]";. - /// - public static string moonPhaseData { - get { - return ResourceManager.GetString("moonPhaseData", resourceCulture); - } - } - /// /// Looks up a localized resource of type System.Byte[]. /// @@ -847,88 +603,6 @@ namespace PckStudio.Properties { } } - /// - /// Looks up a localized string similar to { - /// "COMMENT_1": "JSON by MattNL", - /// "entries": [ - /// { - /// "internalName": "Kebab", - /// "displayName": "\"Kebab med tre pepperoni\" by Kristoffer Zetterstrand" - /// }, - /// { - /// "internalName": "Aztec", - /// "displayName": "\"de_aztec\" by Kristoffer Zetterstrand" - /// }, - /// { - /// "internalName": "Alban", - /// "displayName": "\"Albanian\" by Kristoffer Zetterstrand" - /// }, - /// { - /// "internalName": "Aztec2", - /// "displayName": "\"de_aztec\" by Kristoffer Zetterstrand" - /// }, - /// { - /// "internalName": "Bomb", - /// "disp [rest of string was truncated]";. - /// - public static string paintingData { - get { - return ResourceManager.GetString("paintingData", resourceCulture); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap paintings_atlas { - get { - object obj = ResourceManager.GetObject("paintings_atlas", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized string similar to { - /// "COMMENT_1": "JSON by MattNL", - /// "entries": [ - /// { - /// "internalName": "generic_0", - /// "displayName": "Generic (Stage 1)", - /// "hasColourEntry": true, - /// "colourEntry": { - /// "defaultName": "None", - /// "variants": [ - /// "None", - /// "Particle_Smoke", - /// "Particle_NetherPortal", - /// "Particle_EnderPortal", - /// "Particle_Ender", - /// "Particle_DragonBreathMin", - /// "Particle_DragonBreathMax" - /// ] - /// } - /// }, - /// { - /// "internalName": "generic_1", - /// "displayName": "Generic (Stage 2)", - /// [rest of string was truncated]";. - /// - public static string particleData { - get { - return ResourceManager.GetString("particleData", resourceCulture); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - public static System.Drawing.Bitmap particles_atlas { - get { - object obj = ResourceManager.GetObject("particles_atlas", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -969,6 +643,50 @@ namespace PckStudio.Properties { } } + /// + /// Looks up a localized string similar to #version 330 core + /// + ///layout(location = 0) out vec4 FragColor; + /// + ///uniform vec4 BlendColor; + ///uniform float Intensity; + /// + ///in vec4 color; + /// + ///void main() + ///{ + /// FragColor = vec4((color * BlendColor).rgb, Intensity); + ///}. + /// + public static string plainColorFragmentShader { + get { + return ResourceManager.GetString("plainColorFragmentShader", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to #version 330 core + /// + ///layout(location = 0) in vec4 a_Pos; + ///layout(location = 1) in vec4 a_Color; + /// + ///uniform mat4 ViewProjection; + ///uniform mat4 Transform; + /// + ///out vec4 color; + /// + ///void main() + ///{ + /// color = a_Color; + /// gl_Position = ViewProjection * Transform * vec4(a_Pos.xyz, 1.0); + ///};. + /// + public static string plainColorVertexShader { + get { + return ResourceManager.GetString("plainColorVertexShader", resourceCulture); + } + } + /// /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). /// @@ -1009,6 +727,16 @@ namespace PckStudio.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap Save { + get { + object obj = ResourceManager.GetObject("Save", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -1030,21 +758,54 @@ namespace PckStudio.Properties { } /// - /// Looks up a localized resource of type System.Drawing.Bitmap. + /// Looks up a localized string similar to #version 330 core + /// + ///layout(location = 0) out vec4 color; + /// + ///uniform samplerCube skybox; + ///uniform float brightness; + /// + ///in vec3 texCoords; + /// + ///void main() + ///{ + /// color = vec4(texture(skybox, texCoords).rgb * clamp(brightness, 0.0, 1.0), 1.0); + ///}. /// - public static System.Drawing.Bitmap slim_template { + public static string skyboxFragmentShader { get { - object obj = ResourceManager.GetObject("slim_template", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); + return ResourceManager.GetString("skyboxFragmentShader", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to #version 330 core + /// + ///layout(location = 0) in vec4 a_Pos; + /// + ///uniform mat4 ViewProjection; + /// + ///out vec3 texCoords; + /// + ///void main() + ///{ + /// vec4 pos = ViewProjection * a_Pos; + /// gl_Position = vec4(pos.x, pos.y, pos.ww); + /// texCoords = vec3(a_Pos.xy, -a_Pos.z); + ///};. + /// + public static string skyboxVertexShader { + get { + return ResourceManager.GetString("skyboxVertexShader", resourceCulture); } } /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - public static System.Drawing.Bitmap terrain_atlas { + public static System.Drawing.Bitmap slim_template { get { - object obj = ResourceManager.GetObject("terrain_atlas", resourceCulture); + object obj = ResourceManager.GetObject("slim_template", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } @@ -1060,12 +821,87 @@ namespace PckStudio.Properties { } /// - /// Looks up a localized resource of type System.Drawing.Bitmap. + /// Looks up a localized string similar to #version 330 core + /// + ///layout(location = 0) out vec4 color; + /// + ///uniform sampler2D Texture; + /// + ///in vec2 o_TillingFactor; + ///in vec2 o_TexCoord; + /// + ///void main() + ///{ + /// vec4 result = texture(Texture, o_TexCoord * o_TillingFactor); + /// if (result.a <= 0.0) + /// discard; + /// color = result; + ///};. /// - public static System.Drawing.Bitmap TexturePackIcon { + public static string texturedCubeFragmentShader { get { - object obj = ResourceManager.GetObject("TexturePackIcon", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); + return ResourceManager.GetString("texturedCubeFragmentShader", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to #version 330 core + /// + ///layout (triangles) in; + ///layout (triangle_strip, max_vertices=3) out; + /// + ///uniform vec2 TexSize; + /// + ///out vec2 o_TexCoord; + ///out vec2 o_TillingFactor; + /// + ///in geometryData + ///{ + /// vec2 TexCoord; + ///} dataIn[]; + /// + ///void FixUV() + ///{ + /// bool isXBad = + /// dataIn[0].TexCoord.x >= TexSize.x && + /// dataIn[1].TexCoord.x >= TexSize.x && + /// dataIn[2].TexCoord.x >= TexSize.x; + /// + /// gl_Position = gl_in[0].gl_Position; + /// o_TexCoord = dataIn[0].TexCoord; + /// if (isXBad) + /// o_TexCoord.x = mod(o_TexCoord.x, TexSize.x); + /// Em [rest of string was truncated]";. + /// + public static string texturedCubeGeometryShader { + get { + return ResourceManager.GetString("texturedCubeGeometryShader", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to #version 330 core + /// + ///layout(location = 0) in vec3 vertexPosition; + ///layout(location = 1) in vec2 texCoord; + /// + ///uniform mat4 ViewProjection; + ///uniform mat4 Transform; + /// + ///out geometryData + ///{ + /// vec2 TexCoord; + ///} dataOut; + /// + ///void main() + ///{ + /// dataOut.TexCoord = texCoord; + /// gl_Position = ViewProjection * Transform * vec4(vertexPosition, 1.0); + ///};. + /// + public static string texturedCubeVertexShader { + get { + return ResourceManager.GetString("texturedCubeVertexShader", resourceCulture); } } diff --git a/PCK-Studio/Properties/Resources.resx b/PCK-Studio/Properties/Resources.resx index bc72525c..0028ccd6 100644 --- a/PCK-Studio/Properties/Resources.resx +++ b/PCK-Studio/Properties/Resources.resx @@ -130,6 +130,12 @@ ..\Resources\NoImageFound.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\shader\skyboxVertexShader.glsl;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\..\ProjectLogo.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\HamburgerMenuIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -139,12 +145,6 @@ ..\Resources\fileTemplates\tu51colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\Resources\atlases\banners.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\icons\file_copy.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Resources\iconImageList\ZZFolder.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -154,11 +154,8 @@ ..\Resources\iconImageList\TEXTURE ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\fileTemplates\tu32colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ..\Resources\atlases\moonPhaseData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + ..\Resources\icons\file_copy.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\iconImageList\PCK ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -166,8 +163,11 @@ ..\Resources\changeTile.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\fileTemplates\tu46colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\shader\framebufferVertexShader.glsl;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\fileTemplates\tu32colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ..\Resources\iconImageList\BEHAVIOURS ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -178,9 +178,6 @@ ..\Resources\iconImageList\ARROW.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\atlases\items.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Resources\fileTemplates\tu31colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -190,33 +187,33 @@ ..\Resources\external\Discord.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\atlases\moon_phases.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Resources\fileTemplates\tu13colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\Resources\icons\file_paste.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\atlases\mapIconData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 - - - ..\Resources\atlases\blockData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 - - - ..\Resources\fileTemplates\tu19colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\iconImageList\SKIN ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\pckClosed.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\shader\texturedCubeVertexShader.glsl;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + ..\Resources\icons\file_export.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\fileTemplates\tu53colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\shader\skyboxFragmentShader.glsl;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\shader\plainColorVertexShader.glsl;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\anim_editor\slim_template.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\iconImageList\COL ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -235,42 +232,30 @@ ..\Resources\icons\file_import.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\atlases\paintingData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + ..\Resources\iconImageList\ENTITY MATERIALS ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\atlases\entityMaterialsData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + ..\Resources\icons\Replace.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\iconImageList\IMAGE ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\atlases\map_icons.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Resources\iconImageList\BINKA ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\shader\plainColorFragmentShader.glsl;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + ..\Resources\external\trello.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\atlases\terrain.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\atlases\bannerData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 - ..\Resources\iconImageList\LOC ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\iconImageList\GRF ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\atlases\experience_orbs.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\atlases\entityBehavioursData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 - ..\Resources\binka\mss32.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -280,29 +265,20 @@ ..\Resources\icons\ranch.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\atlases\explosion.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Resources\external\WiiU.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\iconImageList\ENTITY MATERIALS ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Resources\iconImageList\CAPE ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\external\PS3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\atlases\experienceOrbData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 - ..\Resources\icons\file_empty.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\pckOpen.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\fileTemplates\tu19colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ..\Resources\fileTemplates\1.91_colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -313,17 +289,14 @@ ..\Resources\iconImageList\INFO ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\atlases\explosionData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + ..\Resources\icons\file_paste.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\atlases\particleData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + ..\Resources\armor.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\atlases\particles.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\binka\binkawin.asi;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\shader\texturedCubeGeometryShader.glsl;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 ..\Resources\icons\file_delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -331,14 +304,11 @@ ..\Resources\icons\clock.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\atlases\additional_mapicons.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\shader\texturedCubeFragmentShader.glsl;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 - - ..\Resources\TexturePackIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\..\ProjectLogo.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\binka\binkawin.asi;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ..\Resources\pack.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -346,14 +316,11 @@ ..\Resources\fileTemplates\tu43colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\Resources\atlases\paintings.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\..\CHANGELOG.md;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - ..\Resources\iconImageList\SKIN ICON.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\fileTemplates\tu46colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ..\Resources\binka\binka_encode.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -361,31 +328,37 @@ ..\Resources\fileTemplates\tu12colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\Resources\atlases\itemData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 - ..\Resources\fileTemplates\tu14colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\Resources\atlases\entityModelsData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 - ..\Resources\fileTemplates\tu69colours.col;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ..\Resources\external\Youtube.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\icons\Replace.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\anim_editor\slim_template.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\Comparison.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Resources\icons\file_restore.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\skybox_texture.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\shader\framebufferFragmentShader.glsl;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\pckOpen.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\icons\Save.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\entityBehavioursData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\entityMaterialsData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\entityModelsData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + \ No newline at end of file diff --git a/PCK-Studio/Properties/Settings.Designer.cs b/PCK-Studio/Properties/Settings.Designer.cs index 0f286e3c..4d098b08 100644 --- a/PCK-Studio/Properties/Settings.Designer.cs +++ b/PCK-Studio/Properties/Settings.Designer.cs @@ -114,5 +114,17 @@ namespace PckStudio.Properties { this["RecentFiles"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool ValidateImageDimension { + get { + return ((bool)(this["ValidateImageDimension"])); + } + set { + this["ValidateImageDimension"] = value; + } + } } } diff --git a/PCK-Studio/Properties/Settings.settings b/PCK-Studio/Properties/Settings.settings index a32cf0c7..3753a5f9 100644 --- a/PCK-Studio/Properties/Settings.settings +++ b/PCK-Studio/Properties/Settings.settings @@ -26,5 +26,8 @@ + + True + \ No newline at end of file diff --git a/PCK-Studio/Rendering/ModelRenderer.Designer.cs b/PCK-Studio/Rendering/ModelRenderer.Designer.cs new file mode 100644 index 00000000..0e2be60d --- /dev/null +++ b/PCK-Studio/Rendering/ModelRenderer.Designer.cs @@ -0,0 +1,42 @@ +using System.Diagnostics; + +namespace PckStudio.Rendering +{ + internal partial class ModelRenderer + { + [DebuggerNonUserCode()] + protected override void Dispose(bool disposing) + { + try + { + if (disposing && components is not null) + { + components.Dispose(); + } + } + finally + { + base.Dispose(disposing); + } + } + + // Required by the Windows Form Designer + private System.ComponentModel.IContainer components; + + // NOTE: The following procedure is required by the Windows Form Designer + // It can be modified using the Windows Form Designer. + // Do not modify it using the code editor. + [DebuggerStepThrough()] + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + // + // ModelRenderer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.Name = "ModelRenderer"; + this.ResumeLayout(false); + this.PerformLayout(); + } + } +} diff --git a/PCK-Studio/Rendering/ModelRenderer.cs b/PCK-Studio/Rendering/ModelRenderer.cs new file mode 100644 index 00000000..8bfdc817 --- /dev/null +++ b/PCK-Studio/Rendering/ModelRenderer.cs @@ -0,0 +1,334 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using OMI.Formats.Material; +using OMI.Formats.Model; +using OpenTK; +using OpenTK.Graphics.OpenGL; +using PckStudio.Core.Extensions; +using PckStudio.Interfaces; +using PckStudio.Core.Json; +using PckStudio.Properties; +using PckStudio.Rendering.Shader; +using PckStudio.Rendering.Texture; +using PckStudio.Core; +using PckStudio.ModelSupport; + +namespace PckStudio.Rendering +{ + internal partial class ModelRenderer : SceneViewport + { + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Image Texture + { + get => _modelTexture; + set + { + var args = new TextureChangingEventArgs(value); + Events[nameof(ModelTextureChanging)]?.DynamicInvoke(this, args); + OnModelTextureChanging(this, args); + if (!args.Cancel) + { + _modelTexture = value; + } + } + } + + [Description("Event that gets fired when the skin texture is changing")] + [Category("Property Chnaged")] + [Browsable(true)] + public event EventHandler ModelTextureChanging + { + add => Events.AddHandler(nameof(ModelTextureChanging), value); + remove => Events.RemoveHandler(nameof(ModelTextureChanging), value); + } + + public bool RenderModelBounds { get; set; } + public string CurrentModelName => _currentModelName; + + private BoundingBox _maxBounds; + private string _currentModelName; + private Image _modelTexture; + private Texture2D _modelRenderTexture; + private List> _rootCollection; + private struct HighlightInfo + { + public static readonly HighlightInfo Empty = new HighlightInfo(Vector3.Zero, Vector3.Zero, BoundingBox.Empty); + public bool IsEmpty => BoundingBox.Volume.LengthSquared <= 0f; + public BoundingBox BoundingBox { get; } + public Vector3 Translation { get; } + public Vector3 Rotation { get; } + + public HighlightInfo(System.Numerics.Vector3 translation, System.Numerics.Vector3 rotation, BoundingBox boundingBox) + : this(translation.ToOpenTKVector(), rotation.ToOpenTKVector(), boundingBox) + { + } + + public HighlightInfo(Vector3 translation, Vector3 rotation, BoundingBox boundingBox) + { + Translation = translation; + Rotation = rotation; + BoundingBox = boundingBox; + } + } + private HighlightInfo _highlightingInfo; + + private readonly Vector3 modelOffset = Vector3.UnitY * 24f; + + public ModelRenderer() : base(fov: 60f) + { + InitializeComponent(); + _rootCollection = new List>(5); + if (!DesignMode) + { + InitializeShaders(); + } + } + + private void InitializeShaders() + { + Debug.Assert(Context.IsCurrent); + + // render texture + { + _modelRenderTexture = new Texture2D(); + _modelRenderTexture.PixelFormat = PixelFormat.Bgra; + _modelRenderTexture.InternalPixelFormat = PixelInternalFormat.Rgba8; + _modelRenderTexture.MinFilter = TextureMinFilter.Nearest; + _modelRenderTexture.MagFilter = TextureMagFilter.Nearest; + _modelRenderTexture.WrapS = TextureWrapMode.Repeat; + _modelRenderTexture.WrapT = TextureWrapMode.Repeat; + } + + // cubeShader + { + var cubeShader = ShaderProgram.Create( + new ShaderSource(ShaderType.VertexShader, Resources.texturedCubeVertexShader), + new ShaderSource(ShaderType.FragmentShader, Resources.texturedCubeFragmentShader), + new ShaderSource(ShaderType.GeometryShader, Resources.texturedCubeGeometryShader) + ); + cubeShader.Bind(); + cubeShader.SetUniform1("Texture", 0); + cubeShader.Validate(); + AddShader("CubeShader", cubeShader); + } + } + + public void LoadModel(Model model) + { + ResetHighlight(); + _rootCollection?.Clear(); + + _maxBounds = model.GetParts() + .SelectMany(p => p.GetBoxes().Select(b => new BoundingBox(b.Position + p.Translation, b.Position + p.Translation + b.Size))) + .GetEnclosingBoundingBox(); + + if (!TryGetModelMetaData(model, out JsonModelMetaData modelMetaData)) + { + Trace.TraceError($"[{nameof(ModelRenderer)}@{nameof(LoadModel)}] Failed to get meta data for model: '{model.Name}'"); + return; + } + + for (int i = -1; i < modelMetaData.UvOffsets.Length; i++) + { + bool tryGetPart(string name, out ModelPart modelPart) + { + if (!model.TryGetPart(name, out ModelPart originalModelPart)) + { + modelPart = default; + return false; + } + if (i == -1 || !modelMetaData.UvOffsets.IndexInRange(i)) + { + modelPart = originalModelPart; + return true; + } + System.Numerics.Vector2 uvoffset = modelMetaData.UvOffsets[i]; + modelPart = new ModelPart(originalModelPart.Name, originalModelPart.ParentName, originalModelPart.Translation, originalModelPart.Rotation, originalModelPart.AdditionalRotation); + modelPart.AddBoxes(originalModelPart.GetBoxes().Select(box => new ModelBox(box.Position, box.Size, box.Uv + uvoffset, box.Inflate, box.Mirror))); + return true; + } + _rootCollection.AddRange(BuildModelMesh(modelMetaData.RootParts, + Vector3.Zero, Vector3.Zero, Vector3.Zero, + TryGet.FromDelegate(tryGetPart))); + } + + + if (Context.IsCurrent) + { + ShaderProgram shader = GetShader("CubeShader"); + shader.Bind(); + shader.SetUniform2("TexSize", model.TextureSize); + + // Reset "Material" + GL.Disable(EnableCap.AlphaTest); + GL.Disable(EnableCap.Blend); + GL.BlendFunc(BlendingFactor.One, BlendingFactor.Zero); + } + _currentModelName = model.Name; + } + + private bool TryGetModelMetaData(Model model, out JsonModelMetaData modelMetaData) + { + if (!GameModelImporter.ModelMetaData.TryGetValue(model.Name, out modelMetaData)) + { + Trace.TraceError($"[{nameof(ModelRenderer)}@{nameof(TryGetModelMetaData)}] Couldn't get meta data for model: '{model.Name}'"); + return false; + } + + if (modelMetaData.RootParts.Length == 0) + { + modelMetaData.RootParts = model.GetParts().Select(p => new ModelMetaDataPart(p.Name)).ToArray(); + } + return true; + } + + public override void ResetCamera(Vector3 offset) + { + Vector3 center = (_maxBounds.Start + _maxBounds.End) / 2f; + Camera.FocalPoint = Vector3.TransformPosition(center - modelOffset + offset, Matrix4.CreateScale(-1f, 1f, 1f)); + Camera.Distance = _maxBounds.Volume.Length; + Camera.Yaw = 45f; + Camera.Pitch = 25f; + } + + private List> BuildModelMesh(ModelMetaDataPart[] metaDataParts, Vector3 parentTranslation, Vector3 parentRotation, Vector3 parentPivot, ITryGet model) + { + List> meshes = new List>(); + foreach (ModelMetaDataPart metaDataPart in metaDataParts) + { + if (!model.TryGet(metaDataPart.Name, out ModelPart modelPart)) + { + Trace.TraceError($"[{nameof(ModelRenderer)}@{nameof(BuildModelMesh)}] : Failed to find part: '{metaDataPart.Name}'"); + continue; + } + Vector3 translation = modelPart.Translation.ToOpenTKVector(); + Vector3 pivot = translation * -1; + Vector3 rotation = (modelPart.Rotation.ToOpenTKVector() + modelPart.AdditionalRotation.ToOpenTKVector()); + CubeMeshCollection cubeCollection = new CubeMeshCollection(modelPart.Name, translation - parentTranslation, pivot - parentPivot, rotation - parentRotation); + cubeCollection.FlipZMapping = true; + foreach (ModelBox boxes in modelPart.GetBoxes()) + { + cubeCollection.AddNamed(modelPart.Name, boxes.Position.ToOpenTKVector(), boxes.Size.ToOpenTKVector(), boxes.Uv.ToOpenTKVector(), boxes.Inflate, boxes.Mirror); + } + meshes.Add(cubeCollection); + BuildModelMesh(metaDataPart.Children, translation, rotation, pivot, model).ForEach(cubeCollection.Add); + } + return meshes; + } + + protected virtual void OnModelTextureChanging(object sender, TextureChangingEventArgs e) + { + if (e.NewTexture is null) + e.Cancel = true; + + if (e.Cancel) + return; + + if (Context.IsCurrent) + { + _modelRenderTexture.SetTexture(e.NewTexture); + GLErrorCheck(); + } + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + if (DesignMode) + return; + if (!Context.IsCurrent) + return; + + GL.Enable(EnableCap.Texture2D); // Enable textures + + GL.DepthFunc(DepthFunction.Lequal); + + ShaderProgram shader = GetShader("CubeShader"); + + _modelRenderTexture.Bind(slot: 0); + + Vector3 scaleVector = new Vector3(1f, -1f, -1f); + Matrix4 renderTransform = Matrix4.CreateScale(scaleVector) * Matrix4.CreateTranslation(modelOffset); + + foreach (GenericMesh item in _rootCollection) + { + DrawMesh(item, shader, item.GetTransform() * renderTransform); + } + _modelRenderTexture.Unbind(); + + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + + if (!_highlightingInfo.IsEmpty) + { + Matrix4 highlightMatrix = Matrix4.Identity; + highlightMatrix *= Matrix4.CreateRotationX(MathHelper.DegreesToRadians(_highlightingInfo.Rotation.X)); + highlightMatrix *= Matrix4.CreateRotationY(MathHelper.DegreesToRadians(_highlightingInfo.Rotation.Y)); + highlightMatrix *= Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(_highlightingInfo.Rotation.Z)); + highlightMatrix = Matrix4.CreateTranslation(_highlightingInfo.Translation) * highlightMatrix.Pivoted(_highlightingInfo.Translation * -1); + + highlightMatrix *= renderTransform; + DrawBoundingBox(highlightMatrix, _highlightingInfo.BoundingBox, Color.HotPink); + } + + if (RenderModelBounds) + { + DrawBoundingBox(renderTransform, _maxBounds, Color.Red); + } + } + + internal void Highlight(ModelPart part) + { + BoundingBox bb = part.GetBoxes().Select(b => b.GetBoundingBox()).GetEnclosingBoundingBox(); + _highlightingInfo = new HighlightInfo(part.Translation, part.Rotation + part.AdditionalRotation, bb); + } + + internal void Highlight(ModelBox box, ModelPart parent) + { + BoundingBox bb = box.GetBoundingBox(); + _highlightingInfo = new HighlightInfo(parent.Translation, parent.Rotation + parent.AdditionalRotation, bb); + } + + internal void ResetHighlight() + { + _highlightingInfo = HighlightInfo.Empty; + } + + internal void SetModelMaterial(MaterialContainer.Material entityMaterial) + { + _ = entityMaterial ?? throw new ArgumentNullException(nameof(entityMaterial)); + switch (entityMaterial.Type) + { + // todo + //case "entity": + // break; + //case "entity_change_color": + // break; + case "entity_alphatest": + GL.Enable(EnableCap.AlphaTest); + break; + case "entity_alphatest_change_color": + GL.Enable(EnableCap.AlphaTest); + goto default; + case "entity_emissive_alpha": + GL.Enable(EnableCap.Blend); + GL.BlendFunc(BlendingFactor.One, BlendingFactor.Zero); + break; + case "entity_emissive_alpha_only": + GL.Enable(EnableCap.Blend); + GL.BlendFuncSeparate(BlendingFactorSrc.One, BlendingFactorDest.One, BlendingFactorSrc.One, BlendingFactorDest.Zero); + break; + default: + Debug.WriteLine($"[{nameof(ModelRenderer)}@{nameof(SetModelMaterial)}]: Unhandled entity material(type: {entityMaterial.Type})"); + break; + } + } + } +} diff --git a/PCK-Studio/Rendering/ModelRenderer.resx b/PCK-Studio/Rendering/ModelRenderer.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/PCK-Studio/Rendering/ModelRenderer.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/PCK-Studio/Rendering/SceneViewport.cs b/PCK-Studio/Rendering/SceneViewport.cs new file mode 100644 index 00000000..195866f3 --- /dev/null +++ b/PCK-Studio/Rendering/SceneViewport.cs @@ -0,0 +1,640 @@ +/* + * + *The MIT License (MIT) + +Copyright (c) 2016 Kareem Morsy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +https://github.com/KareemMAX/Minecraft-Skiner +https://github.com/KareemMAX/Minecraft-Skiner/blob/master/src/Minecraft%20skiner/UserControls/Renderer3D.vb + */ +//#define USE_FRAMEBUFFER +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using OpenTK; +using OpenTK.Graphics; +using OpenTK.Graphics.OpenGL; +using PckStudio.Core.Extensions; +using PckStudio.Properties; +using PckStudio.Rendering; +using PckStudio.Rendering.Camera; +using PckStudio.Rendering.Shader; + +namespace PckStudio.Rendering +{ + internal class SceneViewport : GLControl + { + /// + /// Refresh rate at which the frame is updated. Default is 60(Hz) + /// + public int RefreshRate + { + get => _refreshRate; + set + { + _refreshRate = Math.Max(value, 1); + _timer.Interval = TimeSpan.FromSeconds(1d / _refreshRate).Milliseconds; + } + } + + public new Color BackColor + { + get => base.BackColor; + set + { + base.BackColor = value; + if (!DesignMode) + { + Renderer.SetClearColor(value); + } + } + } + + protected new bool DesignMode => base.DesignMode || LicenseManager.UsageMode == LicenseUsageMode.Designtime; + + protected PerspectiveCamera Camera { get; } + + protected virtual void OnUpdate(object sender, TimeSpan timestep) { } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool LockMousePosition { get; set; } = false; + + public float MouseSensetivity { get; set; } = 0.01f; + private Point PreviousMouseLocation; + private Point CurrentMouseLocation; + + private int _refreshRate = 60; + private Timer _timer; + private bool _initialized; + private ShaderLibrary _shaderLibrary; + + private DrawContext _boundingBoxDrawContext; + + private long _lastTick = 0L; + + private IndexBuffer _meshIndexBuffer; + private Dictionary _meshTypeVertexArray; + + private bool IsMouseHidden + { + get => !Cursor.IsVisible(); + set + { + if (value) + { + Cursor.Hide(); + return; + } + Cursor.Show(); + } + } + +#if USE_FRAMEBUFFER + private FrameBuffer _framebuffer; + private Texture2D _framebufferTexture; + private VertexArray _framebufferVAO; + private int _framebufferRenderBuffer; + private bool _framebufferStarted = false; + + private static Vector4[] _rectVertices = new Vector4[] + { + new Vector4( 1.0f, -1.0f, 1.0f, 0.0f), + new Vector4(-1.0f, -1.0f, 0.0f, 0.0f), + new Vector4(-1.0f, 1.0f, 0.0f, 1.0f), + new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), + new Vector4( 1.0f, -1.0f, 1.0f, 0.0f), + new Vector4(-1.0f, 1.0f, 0.0f, 1.0f), + }; +#endif + + private SceneViewport() + { + + } + + public SceneViewport(float fov, Vector3 camareaPosition = default) +#if DEBUG + : base(GraphicsMode.Default, 4, 6, GraphicsContextFlags.Debug) +#else + : base() +#endif + { + VSync = true; + _timer = new Timer(); + _timer.Tick += TimerTick; + + RefreshRate = _refreshRate; + Camera = new PerspectiveCamera(fov, camareaPosition); + _shaderLibrary = new ShaderLibrary(); + + if (!DesignMode) + { + _timer.Start(); + InitializeInternal(); + } + _initialized = false; + } + + private void InitializeInternal() + { + if (_initialized) + { + Debug.Fail("Already Initialized."); + return; + } + MakeCurrent(); + Trace.TraceInformation(GL.GetString(StringName.Version)); + GL.DebugMessageCallback(DebugProc, this.Handle); + AddShader("Internal_colorShader", Resources.plainColorVertexShader, Resources.plainColorFragmentShader); + var vao = new VertexArray(); + VertexBufferLayout layout = new VertexBufferLayout(); + layout.Add(ShaderDataType.Float3); + layout.Add(ShaderDataType.Float4); + int id = vao.AddNewBuffer(layout); + vao.GetBuffer(id).SetData(Addon.BoundingBox.GetVertices()); + var ibo = IndexBuffer.Create(Addon.BoundingBox.GetIndecies()); + _boundingBoxDrawContext = new DrawContext(vao, ibo, PrimitiveType.Lines); + + _meshTypeVertexArray = new Dictionary(); + _meshIndexBuffer = new IndexBuffer(); + +#if USE_FRAMEBUFFER + InitializeFramebuffer(); + // Framebuffer shader + { + var framebufferShader = ShaderProgram.Create(Resources.framebufferVertexShader, Resources.framebufferFragmentShader); + framebufferShader.Bind(); + framebufferShader.SetUniform1("screenTexture", 0); + framebufferShader.Validate(); + AddShader("Internal_framebufferShader", framebufferShader); + + GLErrorCheck(); + } +#endif + InitializeDebugComponents(); + InitializeDebugShaders(); + _initialized = true; + } + + public void ResetCamera() => ResetCamera(Vector3.Zero); + public virtual void ResetCamera(Vector3 defaultPosition) + { + Camera.FocalPoint = defaultPosition; + Camera.Yaw = 0f; + Camera.Pitch = 0f; + } + + protected override bool ProcessDialogKey(Keys keyData) + { + switch (keyData) + { +#if DEBUG + case Keys.Escape: + ReleaseMouse(); + debugContextMenuStrip1.Show(this, Point.Empty); + return true; +#endif + } + return base.ProcessDialogKey(keyData); + } + + protected override void Dispose(bool disposing) + { + if (DesignMode) + return; + if (disposing) + { + _timer.Stop(); + _timer.Dispose(); + foreach (VertexArray va in _meshTypeVertexArray.Values) + { + va.Dispose(); + } + _meshIndexBuffer.Dispose(); + _boundingBoxDrawContext.IndexBuffer.Dispose(); + _boundingBoxDrawContext.VertexArray.Dispose(); + _shaderLibrary.Dispose(); + } + _initialized = false; + base.Dispose(disposing); + } + + protected void AddShader(string shaderName, ShaderProgram shader) => _shaderLibrary.AddShader(shaderName, shader); + + protected void AddShader(string shaderName, string vertexSource, string fragmentSource) => AddShader(shaderName, ShaderProgram.Create(vertexSource, fragmentSource)); + + protected ShaderProgram GetShader(string shaderName) => _shaderLibrary.GetShader(shaderName); + + protected void DrawMesh(GenericMesh mesh, ShaderProgram shader, Matrix4 transform) where T : struct + { + Matrix4 viewProjection = Camera.GetViewProjection(); + shader.Bind(); + shader.SetUniformMat4("ViewProjection", ref viewProjection); + shader.SetUniformMat4("Transform", ref transform); + if (!_meshTypeVertexArray.ContainsKey(typeof(T))) + { + VertexArray vertexArray = new VertexArray(); + vertexArray.AddNewBuffer(mesh.VertexLayout); + _meshTypeVertexArray.Add(typeof(T), vertexArray); + } + T[] vertices = mesh.GetVertices().ToArray(); + _meshTypeVertexArray[typeof(T)].GetBuffer(0).SetData(vertices); + int[] indices = mesh.GetIndices().ToArray(); + _meshIndexBuffer.SetIndicies(indices); + var drawContext = new DrawContext(_meshTypeVertexArray[typeof(T)], _meshIndexBuffer, mesh.DrawType); + Renderer.Draw(shader, drawContext); + } + + protected void DrawBoundingBox(Matrix4 transform, Core.BoundingBox boundingBox, Color color) + { + ShaderProgram colorShader = _shaderLibrary.GetShader("Internal_colorShader"); + colorShader.Bind(); + Matrix4 viewProjection = Camera.GetViewProjection(); + colorShader.SetUniformMat4("ViewProjection", ref viewProjection); + transform = boundingBox.GetTransform() * transform; + colorShader.SetUniformMat4("Transform", ref transform); + colorShader.SetUniform4("BlendColor", color); + colorShader.SetUniform1("Intensity", 0.6f); + + GL.Enable(EnableCap.LineSmooth); + + GL.DepthFunc(DepthFunction.Always); + + Renderer.SetLineWidth(2f); + Renderer.Draw(colorShader, _boundingBoxDrawContext); + + GL.DepthFunc(DepthFunction.Less); + Renderer.SetLineWidth(1f); + } + + static void DebugProc(DebugSource source, DebugType type, int id, DebugSeverity severity, int length, IntPtr message, IntPtr instanceHandle) + { + string dbgMessage = Marshal.PtrToStringAnsi(message, length); + Debug.WriteLine($"{source}:{id} {type} {severity}: {dbgMessage}"); + } + + [Conditional("DEBUG")] + protected void GLErrorCheck() + { + ErrorCode error = GL.GetError(); + Debug.Assert(error == ErrorCode.NoError, error.ToString()); + } + + [Conditional("USE_FRAMEBUFFER")] + private void InitializeFramebuffer() + { +#if USE_FRAMEBUFFER + _framebuffer = new FrameBuffer(); + _framebuffer.Bind(); + _framebufferTexture = new Texture2D(); + _framebufferTexture.PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Rgb; + _framebufferTexture.InternalPixelFormat = PixelInternalFormat.Rgb; + _framebufferTexture.SetSize(Size); + _framebufferTexture.WrapS = TextureWrapMode.ClampToEdge; + _framebufferTexture.WrapT = TextureWrapMode.ClampToEdge; + _framebufferTexture.MinFilter = TextureMinFilter.Nearest; + _framebufferTexture.MagFilter = TextureMagFilter.Nearest; + + _framebufferTexture.AttachToFramebuffer(_framebuffer, FramebufferAttachment.ColorAttachment0); + + _framebufferRenderBuffer = GL.GenRenderbuffer(); + GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, _framebufferRenderBuffer); + GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Depth24Stencil8, Size.Width, Size.Height); + GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment, RenderbufferTarget.Renderbuffer, _framebufferRenderBuffer); + + _framebufferVAO = new VertexArray(); + VertexBuffer vertexBuffer = new VertexBuffer(); + vertexBuffer.SetData(_rectVertices); + VertexBufferLayout layout = new VertexBufferLayout(); + layout.Add(ShaderDataType.Float4); + _framebufferVAO.AddBuffer(vertexBuffer, layout); + _framebuffer.CheckStatus(); + + if (_framebuffer.Status != FramebufferErrorCode.FramebufferComplete) + { + Debug.Fail($"Framebuffer status: '{_framebuffer.Status}'"); + } + + _framebuffer.Unbind(); +#endif + } + + [Conditional("USE_FRAMEBUFFER")] + protected void FramebufferBegin() + { +#if USE_FRAMEBUFFER + if (_framebufferStarted) + Debug.Fail("FramebufferBegin: already begun."); + _framebufferStarted = true; + _framebuffer.Bind(); +#endif + } + + [Conditional("USE_FRAMEBUFFER")] + protected void FramebufferEnd() + { +#if USE_FRAMEBUFFER + if (!_framebufferStarted) + Debug.Fail("FramebufferEnd: framebuffer didn't start yet."); + _framebuffer.Unbind(); + GL.Disable(EnableCap.DepthTest); + ShaderProgram framebufferShader = GetShader("Internal_framebufferShader"); + framebufferShader.Bind(); + _framebufferVAO.Bind(); + _framebufferTexture.Bind(slot: 0); + + GL.DrawArrays(PrimitiveType.Triangles, 0, 6); + + _framebufferTexture.Unbind(); + _framebufferStarted = false; +#endif + } + +#if USE_FRAMEBUFFER + [Conditional("USE_FRAMEBUFFER")] + private void SetFramebufferSize(Size size) + { + if (_framebuffer is not null) + { + _framebuffer.Bind(); + + _framebufferTexture.Bind(); + _framebufferTexture.SetSize(size); + + GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, _framebufferRenderBuffer); + GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Depth24Stencil8, size.Width, size.Height); + GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment, RenderbufferTarget.Renderbuffer, _framebufferRenderBuffer); + + FramebufferErrorCode status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer); + if (status != FramebufferErrorCode.FramebufferComplete) + { + Debug.Fail($"Framebuffer status: '{_framebuffer.Status}'"); + } + _framebuffer.Unbind(); + } + } + + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + if (!IsHandleCreated || DesignMode) + return; + SetFramebufferSize(Size); + } +#endif + + private void TimerTick(object sender, EventArgs e) + { + long tick = DateTime.UtcNow.Ticks - _lastTick; + _lastTick = DateTime.UtcNow.Ticks; + OnUpdate(sender, TimeSpan.FromTicks(tick)); + Refresh(); + RenderDebug(); + if (IsHandleCreated && !IsDisposed) + SwapBuffers(); + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + if (DesignMode) + return; + GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + GL.Enable(EnableCap.DepthTest); // Enable correct Z Drawings + } + + protected override void OnSizeChanged(EventArgs e) + { + base.OnSizeChanged(e); + if (DesignMode) + return; + if (Camera is not null) + { + Camera.ViewportSize = ClientSize; + } + Renderer.SetViewportSize(Camera.ViewportSize); + } + + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + float mouseSensetivity = LockMousePosition ? MouseSensetivity : 64f * 3 * (1f / 56f) * MouseSensetivity; + + float deltaX = (Cursor.Position.X - CurrentMouseLocation.X) * mouseSensetivity; + float deltaY = (Cursor.Position.Y - CurrentMouseLocation.Y) * mouseSensetivity; + + switch (e.Button) + { + case MouseButtons.None: + case MouseButtons.Middle: + case MouseButtons.XButton1: + case MouseButtons.XButton2: + break; + case MouseButtons.Left: + Camera.Rotate(deltaX, deltaY); + goto default; + case MouseButtons.Right: + Camera.Pan(deltaX, deltaY); + goto default; + default: + if (LockMousePosition) + Cursor.Position = PointToScreen(new Point((int)Math.Round(Bounds.Width / 2d), (int)Math.Round(Bounds.Height / 2d))); + CurrentMouseLocation = Cursor.Position; + break; + } + } + + protected override void OnMouseWheel(MouseEventArgs e) + { + Camera.Distance -= e.Delta / System.Windows.Input.Mouse.MouseWheelDeltaForOneLine; + } + + protected override void OnMouseUp(MouseEventArgs e) + { + base.OnMouseUp(e); + ReleaseMouse(); + } + + protected void ReleaseMouse() + { + if (LockMousePosition) + { + Cursor.Position = PreviousMouseLocation; + if (IsMouseHidden) + IsMouseHidden = false; + } + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + if (e.Button == MouseButtons.Right || e.Button == MouseButtons.Left) + { + CurrentMouseLocation = PreviousMouseLocation = Cursor.Position; + IsMouseHidden = LockMousePosition; + } + } + + [Conditional("DEBUG")] + private void InitializeDebugShaders() + { +#if DEBUG + var plainColorVertexBufferLayout = new VertexBufferLayout(); + plainColorVertexBufferLayout.Add(ShaderDataType.Float3); + plainColorVertexBufferLayout.Add(ShaderDataType.Float4); + // Debug point render + { + ColorVertex[] vertices = [ + new ColorVertex(Vector3.Zero, Color.White), + ]; + VertexArray vao = new VertexArray(); + var debugVBO = new VertexBuffer(); + debugVBO.SetData(vertices); + vao.AddBuffer(debugVBO, plainColorVertexBufferLayout); + d_debugPointDrawContext = new DrawContext(vao, debugVBO.GenIndexBuffer(), PrimitiveType.Points); + } + // Debug line render + { + ColorVertex[] vertices = [ + new ColorVertex(Vector3.Zero, Color.Red) , new ColorVertex(Vector3.UnitX, Color.Red), + new ColorVertex(Vector3.Zero, Color.Green), new ColorVertex(Vector3.UnitY, Color.Green), + new ColorVertex(Vector3.Zero, Color.Blue) , new ColorVertex(Vector3.UnitZ, Color.Blue), + ]; + VertexArray vao = new VertexArray(); + var debugVBO = new VertexBuffer(); + debugVBO.SetData(vertices); + vao.AddBuffer(debugVBO, plainColorVertexBufferLayout); + d_debugLineDrawContext = new DrawContext(vao, debugVBO.GenIndexBuffer(), PrimitiveType.Lines); + } +#endif + } + + [Conditional("DEBUG")] + private void RenderDebug() + { +#if DEBUG + d_debugLabel.Text = Camera.ToString(); + GL.Disable(EnableCap.Blend); + GL.DepthMask(false); + GL.DepthFunc(DepthFunction.Always); + GL.Enable(EnableCap.PointSmooth); + GL.Enable(EnableCap.LineSmooth); + ShaderProgram colorShader = GetShader("Internal_colorShader"); + colorShader.Bind(); + Matrix4 viewProjection = Camera.GetViewProjection(); + colorShader.SetUniformMat4("ViewProjection", ref viewProjection); + if (d_showFocalPoint) + { + Matrix4 transform = Matrix4.CreateTranslation(Camera.FocalPoint).Inverted(); + colorShader.SetUniformMat4("Transform", ref transform); + colorShader.SetUniform1("Intensity", 0.75f); + colorShader.SetUniform4("BlendColor", Color.DeepPink); + GL.PointSize(5f); + Renderer.Draw(colorShader, d_debugPointDrawContext); + GL.PointSize(1f); + } + if (d_showDirectionArrows) + { + Matrix4 transform = Matrix4.CreateScale(1, -1, -1); + transform *= Matrix4.CreateTranslation(Vector3.Zero); + transform *= Matrix4.CreateScale(Camera.Distance / 4f).Inverted(); + transform.Invert(); + colorShader.SetUniformMat4("Transform", ref transform); + colorShader.SetUniform1("Intensity", 0.75f); + colorShader.SetUniform4("BlendColor", Color.White); + + Renderer.SetLineWidth(2f); + + Renderer.Draw(colorShader, d_debugLineDrawContext); + + Renderer.SetLineWidth(1f); + + } + GL.DepthMask(true); + GL.DepthFunc(DepthFunction.Less); + GL.Enable(EnableCap.Blend); +#endif + } + + [Conditional("DEBUG")] + private void InitializeDebugComponents() + { +#if DEBUG + debugContextMenuStrip1 = new ContextMenuStrip(); + debugContextMenuStrip1.SuspendLayout(); + SuspendLayout(); + // + // contextMenuStrip1 + // + debugContextMenuStrip1.Items.AddRange(new ToolStripItem[] {}); + debugContextMenuStrip1.Name = "contextMenuStrip1"; + debugContextMenuStrip1.Size = new Size(159, 48); + // + // debugLabel + // + d_debugLabel = new Label(); + d_debugLabel.AutoSize = true; + d_debugLabel.Visible = false; + d_debugLabel.BackColor = Color.Transparent; + d_debugLabel.ForeColor = SystemColors.ControlLight; + d_debugLabel.Location = new Point(3, 4); + d_debugLabel.Name = "debugLabel"; + d_debugLabel.Size = new Size(37, 13); + d_debugLabel.TabIndex = 2; + d_debugLabel.Text = "debug"; + var debugCameraToolStripMenuItem = new ToolStripMenuItem("Show Camera debug information"); + debugCameraToolStripMenuItem.CheckOnClick = true; + debugCameraToolStripMenuItem.Click += (s, e) => d_debugLabel.Visible = debugCameraToolStripMenuItem.Checked; + debugContextMenuStrip1.Items.Add(debugCameraToolStripMenuItem); + + var debugShowFocalPointToolStripMenuItem = new ToolStripMenuItem("Show Camera Focal point"); + debugShowFocalPointToolStripMenuItem.CheckOnClick = true; + debugShowFocalPointToolStripMenuItem.Click += (s, e) => d_showFocalPoint = debugShowFocalPointToolStripMenuItem.Checked; + debugContextMenuStrip1.Items.Add(debugShowFocalPointToolStripMenuItem); + + var debugShowDirectionArrows = new ToolStripMenuItem("Show Direction Arrows"); + debugShowDirectionArrows.CheckOnClick = true; + debugShowDirectionArrows.Click += (s, e) => d_showDirectionArrows = debugShowDirectionArrows.Checked; + debugContextMenuStrip1.Items.Add(debugShowDirectionArrows); + + Controls.Add(d_debugLabel); + + this.debugContextMenuStrip1.ResumeLayout(false); +#endif + } + +#if DEBUG + private bool d_showFocalPoint; + private bool d_showDirectionArrows; + private DrawContext d_debugPointDrawContext; + private DrawContext d_debugLineDrawContext; + private Label d_debugLabel; + private ContextMenuStrip debugContextMenuStrip1; +#endif + + } +} diff --git a/PCK-Studio/Rendering/SkinRenderer.Designer.cs b/PCK-Studio/Rendering/SkinRenderer.Designer.cs new file mode 100644 index 00000000..3403024a --- /dev/null +++ b/PCK-Studio/Rendering/SkinRenderer.Designer.cs @@ -0,0 +1,42 @@ +using System.Diagnostics; + +namespace PckStudio.Rendering +{ + internal partial class SkinRenderer + { + [DebuggerNonUserCode()] + protected override void Dispose(bool disposing) + { + try + { + if (disposing && components is not null) + { + components.Dispose(); + } + } + finally + { + base.Dispose(disposing); + } + } + + // Required by the Windows Form Designer + private System.ComponentModel.IContainer components; + + // NOTE: The following procedure is required by the Windows Form Designer + // It can be modified using the Windows Form Designer. + // Do not modify it using the code editor. + [DebuggerStepThrough()] + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + // + // SkinRenderer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.Name = "SkinRenderer"; + this.ResumeLayout(false); + this.PerformLayout(); + } + } +} diff --git a/PCK-Studio/Rendering/SkinRenderer.cs b/PCK-Studio/Rendering/SkinRenderer.cs new file mode 100644 index 00000000..390ed0b6 --- /dev/null +++ b/PCK-Studio/Rendering/SkinRenderer.cs @@ -0,0 +1,1109 @@ +/* Copyright (c) 2024-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 OpenTK; +using PckStudio.Internal; +using PckStudio.Core.Extensions; +using OpenTK.Graphics.OpenGL; +using System.Windows.Forms; +using System.ComponentModel; +using System.Drawing; +using PckStudio.Properties; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Drawing.Imaging; +using System.IO; +using PckStudio.Rendering.Extension; +using PckStudio.Rendering.Texture; +using PckStudio.Rendering.Shader; +using System.Linq; +using PckStudio.Core.Skin; +using PckStudio.Core; + +namespace PckStudio.Rendering +{ + internal partial class SkinRenderer : SceneViewport + { + /// + /// The visible Texture on the renderer + /// + /// The visible Texture + [Description("The current skin texture")] + [Category("Appearance")] + public Image Texture + { + get => _skinImage; + set + { + var args = new TextureChangingEventArgs(value); + Events[nameof(TextureChanging)]?.DynamicInvoke(this, args); + OnTextureChanging(this, args); + if (!args.Cancel) + { + _skinImage = value; + } + } + } + + [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 GuideLineColor { get; set; } + + [Description("The Color used for highlighting selected cube")] + [Category("Appearance")] + public Color HighlightlingColor { get; set; } = Color.Aqua; + + public int SelectedIndex + { + get => selectedIndices.Length > 0 ? selectedIndices[0] : -1; + set + { + if (selectedIndices.Length <= 0) + selectedIndices = new int[1]; + selectedIndices[0] = value; + if (CenterOnSelect) + CenterSelectedObject(); + } + } + + public int[] SelectedIndices + { + get => selectedIndices; + set + { + selectedIndices = value; + if (CenterOnSelect) + CenterSelectedObject(); + } + } + + public bool CenterOnSelect { get; set; } = false; + public bool ShowBoundingBox { get; set; } + public bool ShowArmor { get; set; } = false; + public bool Animate { get; set; } = true; + public bool ShowGuideLines + { + get => guidelineMode != GuidelineMode.None; + set + { + if (value) + { + guidelineMode = GuidelineMode.Cubical; + return; + } + guidelineMode = GuidelineMode.None; + } + } + + [Description("Event that gets fired when the skin texture is changing")] + [Category("Property Chnaged")] + [Browsable(true)] + public event EventHandler TextureChanging + { + add => Events.AddHandler(nameof(TextureChanging), value); + remove => Events.RemoveHandler(nameof(TextureChanging), value); + } + + [Description("Event that gets fired when the cape 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 + { + get => _anim; + set + { + _anim = value; + OnANIMUpdate(); + } + } + + public ObservableCollection ModelData { get; } + + /// + /// Captures the currently displayed frame + /// + /// Image of the cameras current view + // TODO: add thumbnail size argument + public Image GetThumbnail() + { + Bitmap bmp = new Bitmap(Width, Height); + BitmapData data = bmp.LockBits(ClientRectangle, ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + + GL.Finish(); + GL.ReadPixels(0, 0, Width, Height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0); + bmp.UnlockBits(data); + bmp.RotateFlip(RotateFlipType.RotateNoneFlipY); + return bmp; + } + + private enum GuidelineMode + { + None = -1, + Cubical, + Skeleton + }; + + private GuidelineMode guidelineMode { get; set; } = GuidelineMode.None; + private int[] selectedIndices = Array.Empty(); + private BoundingBox _skinBounds; + + public Size TextureSize { get; private set; } = new Size(64, 64); + public Vector2 TillingFactor => new Vector2(1f / TextureSize.Width, 1f / TextureSize.Height); + private const float OverlayScale = 0.25f; + + private VertexBufferLayout plainColorVertexBufferLayout; + + private SkinANIM _anim; + private Image _skinImage; + private Image _capeImage; + private Texture2D skinTexture; + private Texture2D capeTexture; + private Texture2D armorTexture; + + private DrawContext _cubicalDrawContext; + private DrawContext _skeletonDrawContext; + private DrawContext _groundDrawContext; + + private DrawContext _skyboxRenderBuffer; + private CubeTexture _skyboxTexture; + + private Dictionary meshStorage; + private Dictionary offsetSpecificMeshStorage; + + private CubeMesh cape; + + private CubeMeshCollection head; + private CubeMeshCollection body; + private CubeMeshCollection rightArm; + private CubeMeshCollection leftArm; + private CubeMeshCollection rightLeg; + private CubeMeshCollection leftLeg; + + private float animationCurrentRotationAngle; + private float animationRotationSpeed = 16f; + private float animationMaxAngleInDegrees = 5f; + + private bool showWireFrame = false; + private bool autoInflateOverlayParts; + + private const float defaultArmRotation = 5f; + + private Matrix4 RightArmMatrix => Matrix4.CreateFromAxisAngle(Vector3.UnitZ, MathHelper.DegreesToRadians(defaultArmRotation)); + private Matrix4 LeftArmMatrix => Matrix4.CreateFromAxisAngle(Vector3.UnitZ, MathHelper.DegreesToRadians(-defaultArmRotation)); + + private static Vector3[] cubeVertices = new Vector3[] + { + // front + new Vector3(-1.0f, -1.0f, 1.0f), + new Vector3( 1.0f, -1.0f, 1.0f), + new Vector3( 1.0f, 1.0f, 1.0f), + new Vector3(-1.0f, 1.0f, 1.0f), + // back + new Vector3(-1.0f, -1.0f, -1.0f), + new Vector3( 1.0f, -1.0f, -1.0f), + new Vector3( 1.0f, 1.0f, -1.0f), + new Vector3(-1.0f, 1.0f, -1.0f) + }; + + private bool initialized = false; + + public SkinRenderer() : base(fov: 60f) + { + InitializeSkinData(); + InitializeCapeData(); + meshStorage = new Dictionary() + { + { "HEAD", head }, + { "BODY", body }, + { "ARM0", rightArm }, + { "ARM1", leftArm }, + { "LEG0", rightLeg }, + { "LEG1", leftLeg }, + + { "HEADWEAR", head }, + { "JACKET" , body }, + { "SLEEVE0" , rightArm }, + { "SLEEVE1" , leftArm }, + { "PANTS0" , rightLeg }, + { "PANTS1" , leftLeg }, + }; + CalculateSkinBounds(); + InitializeArmorData(); + InitializeCamera(); + InitializeComponent(); + + ANIM ??= new SkinANIM(SkinAnimMask.RESOLUTION_64x64); + ModelData = new ObservableCollection(); + ModelData.CollectionChanged += ModelData_CollectionChanged; + } + + public void Initialize(bool inflateOverlayParts) + { + if (initialized) + Debug.Fail("Already Initialized!"); + autoInflateOverlayParts = inflateOverlayParts; + InitializeShaders(); + Renderer.SetClearColor(BackColor); + GLErrorCheck(); + initialized = true; + } + + private const float DefaultCameraDistance = 64f; + private void InitializeCamera() + { + Camera.Distance = DefaultCameraDistance; + Camera.FocalPoint = head.GetCenter(0); + } + + private void InitializeSkinData() + { + head ??= new CubeMeshCollection("Head", GameConstants.SkinHeadTranslation.ToOpenTKVector(), GameConstants.SkinHeadPivot.ToOpenTKVector()) + { + FlipZMapping = true + }; + head.AddNamed("DefaultHead", new(-4, -8, -4), new(8, 8, 8), new(0, 0)); + head.AddNamed("DefaultHeadOverlay", new(-4, -8, -4), new(8, 8, 8), new(32, 0), OverlayScale * 2); + + body ??= new CubeMeshCollection("Body", GameConstants.SkinBodyTranslation.ToOpenTKVector(), GameConstants.SkinBodyPivot.ToOpenTKVector()); + body.AddNamed("DefaultBody",new(-4, 0, -2), new(8, 12, 4), new(16, 16)); + body.AddNamed("DefaultBodyOverlay", new(-4, 0, -2), new(8, 12, 4), new(16, 32), OverlayScale); + + rightArm ??= new CubeMeshCollection("Right Arm", GameConstants.SkinRightArmTranslation.ToOpenTKVector(), GameConstants.SkinRightArmPivot.ToOpenTKVector()); + rightArm.AddNamed("DefaultRightArm",new(-3, -2, -2), new(4, 12, 4), new(40, 16)); + rightArm.AddNamed("DefaultRightArmOverlay", new(-3, -2, -2), new(4, 12, 4), new(40, 32), OverlayScale); + + leftArm ??= new CubeMeshCollection("Left Arm", GameConstants.SkinLeftArmTranslation.ToOpenTKVector(), GameConstants.SkinLeftArmPivot.ToOpenTKVector()); + leftArm.AddNamed("DefaultLeftArm",new(-1, -2, -2), new(4, 12, 4), new(32, 48)); + leftArm.AddNamed("DefaultLeftArmOverlay", new(-1, -2, -2), new(4, 12, 4), new(48, 48), inflate: OverlayScale); + + rightLeg ??= new CubeMeshCollection("Right Leg", GameConstants.SkinRightLegTranslation.ToOpenTKVector(), GameConstants.SkinRightLegPivot.ToOpenTKVector()); + rightLeg.AddNamed("DefaultRightLeg",new(-2, 0, -2), new(4, 12, 4), new(0, 16)); + rightLeg.AddNamed("DefaultRightLegOverlay", new(-2, 0, -2), new(4, 12, 4), new(0, 32), OverlayScale); + + leftLeg ??= new CubeMeshCollection("Left Leg", GameConstants.SkinLeftLegTranslation.ToOpenTKVector(), GameConstants.SkinLeftLegPivot.ToOpenTKVector()); + leftLeg.AddNamed("DefaultLeftLeg",new(-2, 0, -2), new(4, 12, 4), new(16, 48)); + leftLeg.AddNamed("DefaultLeftLegOverlay", new(-2, 0, -2), new(4, 12, 4), new(0, 48), OverlayScale); + } + + private void InitializeCapeData() + { + cape ??= new CubeMesh(new Cube(new(-5, 0, -3), new(10, 16, 1), new(0, 0), 0f, false, false)); + } + + private void InitializeArmorData() + { + const float armorInflation = 0.75f; + + var helmet = new CubeMeshCollection("HELMET"); + helmet.Add(new(-4, -8, -4), new(8, 8, 8), new(0, 0), inflate: armorInflation); + + var chest = new CubeMeshCollection("CHEST"); + chest.Add(new(-4, 0, -2), new(8, 12, 4), new(16, 16), inflate: armorInflation + 0.01f); + + var shoulder0 = new CubeMeshCollection("SHOULDER0", rightArm.Translation, rightArm.Pivot); + shoulder0.Add(new(-3, -2, -2), new(4, 12, 4), new(40, 16), inflate: armorInflation); + + var shoulder1 = new CubeMeshCollection("SHOULDER1", leftArm.Translation, leftArm.Pivot); + shoulder1.Add(new(-1, -2, -2), new(4, 12, 4), new(40, 16), inflate: armorInflation, mirrorTexture: true); + + var waist = new CubeMeshCollection("WAIST"); + waist.Add(new(-4, 0, -2), new(8, 12, 4), new(16, 48), inflate: armorInflation); + + var pants0 = new CubeMeshCollection("PANTS0", rightLeg.Translation, rightLeg.Pivot); + pants0.Add(new(-2, 0, -2), new(4, 12, 4), new(0, 48), inflate: armorInflation); + + var pants1 = new CubeMeshCollection("PANTS1", leftLeg.Translation, leftLeg.Pivot); + pants1.Add(new(-2, 0, -2), new(4, 12, 4), new(0, 48), inflate: armorInflation, mirrorTexture: true); + + var boot0 = new CubeMeshCollection("BOOT0", rightLeg.Translation, rightLeg.Pivot); + boot0.Add(new(-2, 0, -2), new(4, 12, 4), new(0, 16), inflate: armorInflation + 0.25f); + + var boot1 = new CubeMeshCollection("BOOT1", leftLeg.Translation, leftLeg.Pivot); + boot1.Add(new(-2, 0, -2), new(4, 12, 4), new(0, 16), inflate: armorInflation + 0.25f, mirrorTexture: true); + + offsetSpecificMeshStorage = new Dictionary + { + { helmet.Name, helmet }, + { chest.Name, chest }, + { shoulder0.Name, shoulder0 }, + { shoulder1.Name, shoulder1 }, + { waist.Name, waist }, + { pants0.Name, pants0 }, + { pants1.Name, pants1 }, + { boot0.Name, boot0 }, + { boot1.Name, boot1 } + }; + + //// TODO + //{ "TOOL0" , new CubeGroupMesh("TOOL0") }, + //{ "TOOL1" , new CubeGroupMesh("TOOL1") }, + } + + private void InitializeShaders() + { + plainColorVertexBufferLayout = new VertexBufferLayout(); + plainColorVertexBufferLayout.Add(ShaderDataType.Float3); + plainColorVertexBufferLayout.Add(ShaderDataType.Float4); + + // Skin shader + { + var cubeShader = ShaderProgram.Create( + new ShaderSource(ShaderType.VertexShader, Resources.texturedCubeVertexShader), + new ShaderSource(ShaderType.FragmentShader, Resources.texturedCubeFragmentShader), + new ShaderSource(ShaderType.GeometryShader, Resources.texturedCubeGeometryShader) + ); + cubeShader.Bind(); + cubeShader.SetUniform1("Texture", 0); + cubeShader.Validate(); + AddShader("CubeShader", cubeShader); + GLErrorCheck(); + + armorTexture = new Texture2D(); + armorTexture.PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Bgra; + armorTexture.InternalPixelFormat = PixelInternalFormat.Rgba8; + armorTexture.MinFilter = TextureMinFilter.Nearest; + armorTexture.MagFilter = TextureMagFilter.Nearest; + armorTexture.WrapS = TextureWrapMode.Repeat; + armorTexture.WrapT = TextureWrapMode.Repeat; + armorTexture.SetTexture(Resources.armor); + GLErrorCheck(); + + capeTexture = new Texture2D(); + 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(); + skinTexture.PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Bgra; + skinTexture.InternalPixelFormat = PixelInternalFormat.Rgba8; + skinTexture.MinFilter = TextureMinFilter.Nearest; + skinTexture.MagFilter = TextureMagFilter.Nearest; + skinTexture.WrapS = TextureWrapMode.Repeat; + skinTexture.WrapT = TextureWrapMode.Repeat; + + GLErrorCheck(); + } + + // Skybox shader + { + var skyboxVAO = new VertexArray(); + var skyboxVBO = new VertexBuffer(); + skyboxVBO.SetData(cubeVertices); + var vboLayout = new VertexBufferLayout(); + vboLayout.Add(ShaderDataType.Float3); + skyboxVAO.AddBuffer(skyboxVBO, vboLayout); + var skybocIBO = IndexBuffer.Create( + // front + 0, 1, 2, + 2, 3, 0, + // right + 1, 5, 6, + 6, 2, 1, + // back + 7, 6, 5, + 5, 4, 7, + // left + 4, 0, 3, + 3, 7, 4, + // bottom + 4, 5, 1, + 1, 0, 4, + // top + 3, 2, 6, + 6, 7, 3); + + _skyboxRenderBuffer = new DrawContext(skyboxVAO, skybocIBO, PrimitiveType.Triangles); + + var skyboxShader = ShaderProgram.Create(Resources.skyboxVertexShader, Resources.skyboxFragmentShader); + skyboxShader.Bind(); + skyboxShader.SetUniform1("skybox", 0); + skyboxShader.SetUniform1("brightness", 0.8f); + skyboxShader.Validate(); + AddShader("SkyboxShader", skyboxShader); + + _skyboxTexture = new CubeTexture(); + _skyboxTexture.InternalPixelFormat = PixelInternalFormat.Rgb8; + _skyboxTexture.PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Bgra; + _skyboxTexture.MinFilter = TextureMinFilter.Linear; + _skyboxTexture.MagFilter = TextureMagFilter.Linear; + + _skyboxTexture.WrapS = TextureWrapMode.ClampToEdge; + _skyboxTexture.WrapT = TextureWrapMode.ClampToEdge; + _skyboxTexture.WrapR = TextureWrapMode.ClampToEdge; + + string customSkyboxFilepath = Path.Combine(Program.AppData, "skybox.png"); + using Image skyboxImage = File.Exists(customSkyboxFilepath) + ? Image.FromFile(customSkyboxFilepath) + : Resources.DefaultSkyTexture; + _skyboxTexture.SetTexture(skyboxImage); + GLErrorCheck(); + } + + // Plain color shader + { + var lineShader = ShaderProgram.Create(Resources.plainColorVertexShader, Resources.plainColorFragmentShader); + lineShader.Bind(); + lineShader.SetUniform4("BlendColor", Color.WhiteSmoke); + lineShader.SetUniform1("Intensity", 0.5f); + lineShader.Validate(); + AddShader("PlainColorShader", lineShader); + + // Cubical draw context + { + VertexArray lineVAO = new VertexArray(); + + void AddOutline(BoundingBox boundingBox, ref List vertices, ref List indices) + { + int offset = vertices.Count; + vertices.AddRange(Addon.BoundingBox.GetVertices().Select(vert => new ColorVertex(Vector3.TransformPosition(vert.Position, boundingBox.GetTransform()), vert.Color))); + indices.AddRange(Addon.BoundingBox.GetIndecies().Select(i => i + offset)); + } + + List vertices = new List(8 * 6); + List indices = new List(24 * 6); + AddOutline(head.GetCubeBoundingBox(0), ref vertices, ref indices); + AddOutline(body.GetCubeBoundingBox(0), ref vertices, ref indices); + AddOutline(rightArm.GetCubeBoundingBox(0), ref vertices, ref indices); + AddOutline(leftArm.GetCubeBoundingBox(0), ref vertices, ref indices); + AddOutline(rightLeg.GetCubeBoundingBox(0), ref vertices, ref indices); + AddOutline(leftLeg.GetCubeBoundingBox(0), ref vertices, ref indices); + VertexBuffer buffer = new VertexBuffer(); + buffer.SetData(vertices.ToArray()); + lineVAO.AddBuffer(buffer, plainColorVertexBufferLayout); + lineVAO.Bind(); + + _cubicalDrawContext = new DrawContext(lineVAO, IndexBuffer.Create(indices.ToArray()), PrimitiveType.Lines); + } + + GLErrorCheck(); + + // Skeleton draw context + { + VertexArray lineVAO = new VertexArray(); + Vector3 bodyCenterTop = body.GetFaceCenter(0, Cube.Face.Top); + Vector3 bodyCenterBottom = body.GetFaceCenter(0, Cube.Face.Bottom); + ColorVertex[] data = [ + new ColorVertex(head.GetFaceCenter(0, Cube.Face.Top)), + new ColorVertex(bodyCenterBottom), + + new ColorVertex(rightArm.GetFaceCenter(0, Cube.Face.Bottom)), + new ColorVertex(rightArm.GetFaceCenter(0, Cube.Face.Top)), + new ColorVertex(rightArm.GetFaceCenter(0, Cube.Face.Top)), + new ColorVertex(leftArm.GetFaceCenter(0, Cube.Face.Top)), + + new ColorVertex(leftArm.GetFaceCenter(0, Cube.Face.Bottom)), + new ColorVertex(leftArm.GetFaceCenter(0, Cube.Face.Top)), + + new ColorVertex(rightLeg.GetFaceCenter(0, Cube.Face.Bottom)), + new ColorVertex(rightLeg.GetFaceCenter(0, Cube.Face.Top)), + new ColorVertex(rightLeg.GetFaceCenter(0, Cube.Face.Top)), + new ColorVertex(leftLeg.GetFaceCenter(0, Cube.Face.Top)), + + new ColorVertex(leftLeg.GetFaceCenter(0, Cube.Face.Bottom)), + new ColorVertex(leftLeg.GetFaceCenter(0, Cube.Face.Top)), + ]; + VertexBuffer buffer = new VertexBuffer(); + buffer.SetData(data); + lineVAO.AddBuffer(buffer, plainColorVertexBufferLayout); + lineVAO.Bind(); + + _skeletonDrawContext = new DrawContext(lineVAO, buffer.GenIndexBuffer(), PrimitiveType.Lines); + } + + // Ground plane draw context + { + Vector3 center = Vector3.Zero; + Color planeColor = Color.CadetBlue; + + ColorVertex[] vertices = [ + new ColorVertex(new Vector3(center.X + 1f, 0f, center.Z + 1f), planeColor), + new ColorVertex(new Vector3(center.X - 1f, 0f, center.Z + 1f), planeColor), + new ColorVertex(new Vector3(center.X - 1f, 0f, center.Z - 1f), planeColor), + new ColorVertex(new Vector3(center.X + 1f, 0f, center.Z - 1f), planeColor), + ]; + var planeVAO = new VertexArray(); + VertexBuffer buffer = new VertexBuffer(); + buffer.SetData(vertices); + planeVAO.AddBuffer(buffer, plainColorVertexBufferLayout); + + _groundDrawContext = new DrawContext(planeVAO, buffer.GenIndexBuffer(), PrimitiveType.Quads); + } + + GLErrorCheck(); + } + } + + private DrawContext GetGuidelineDrawContext() + { + return guidelineMode == GuidelineMode.Skeleton ? _skeletonDrawContext : _cubicalDrawContext; + } + + protected virtual void OnTextureChanging(object sender, TextureChangingEventArgs e) + { + if (e.NewTexture is null) + e.Cancel = true; + + if (e.Cancel) + return; + skinTexture.SetTexture(e.NewTexture); + 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(); + } + + public void SetPartOffset(SkinPartOffset offset) + { + SetPartOffset(offset.Type, offset.Value); + } + + public void SetPartOffset(string name, float value) + { + if (!SkinPartOffset.ValidModelOffsetTypes.Contains(name)) + { + Trace.TraceWarning($"{name} is not a valid offset."); + return; + } + bool offsetSpecific = offsetSpecificMeshStorage.ContainsKey(name); + if (!meshStorage.ContainsKey(name) && !offsetSpecific) + { + Trace.TraceError($"[{nameof(SetPartOffset)}]: '{name}' is not inside {nameof(meshStorage)} or {nameof(offsetSpecificMeshStorage)}"); + return; + } + if (offsetSpecific) + { + offsetSpecificMeshStorage[name].Offset = Vector3.UnitY * value; + return; + } + meshStorage[name].Offset = Vector3.UnitY * value; + CalculateSkinBounds(); + } + + internal void ResetOffsets() + { + foreach (var key in meshStorage.Keys.ToArray()) + { + meshStorage[key].Offset = Vector3.Zero; + } + foreach (var key in offsetSpecificMeshStorage.Keys.ToArray()) + { + offsetSpecificMeshStorage[key].Offset = Vector3.Zero; + } + CalculateSkinBounds(); + } + + internal IEnumerable GetOffsets() + { + foreach (KeyValuePair mesh in meshStorage) + { + if (SkinPartOffset.ValidModelOffsetTypes.Contains(mesh.Key) && mesh.Value.Offset.Y != 0f) + yield return new SkinPartOffset(mesh.Key, mesh.Value.Offset.Y); + } + foreach (KeyValuePair offsetmesh in offsetSpecificMeshStorage) + { + if (offsetmesh.Value.Offset.Y != 0f) + yield return new SkinPartOffset(offsetmesh.Key, offsetmesh.Value.Offset.Y); + } + yield break; + } + + private void ModelData_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + // TODO: dont re-initialize everytime.. + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + if (e.NewItems[0] is SkinBOX addedBox) + { + AddCustomModelPart(addedBox); + } + break; + case NotifyCollectionChangedAction.Reset: + case NotifyCollectionChangedAction.Remove: + case NotifyCollectionChangedAction.Replace: + ReInitialzeSkinData(); + goto default; + case NotifyCollectionChangedAction.Move: + break; + default: + break; + } + CalculateSkinBounds(); + } + + private void CalculateSkinBounds() + { + _skinBounds = meshStorage.Values.Select(item => item.GetBounds(Matrix4.Identity)).GetEnclosingBoundingBox(); + } + + private void AddCustomModelPart(SkinBOX skinBox) + { + if (!meshStorage.ContainsKey(skinBox.Type)) + { + Trace.TraceWarning("[{0}@{1}] Invalid BOX Type: '{2}'", nameof(SkinRenderer), nameof(AddCustomModelPart), skinBox.Type); + return; + } + + CubeMeshCollection cubeMesh = meshStorage[skinBox.Type]; + cubeMesh.AddSkinBox(skinBox, autoInflateOverlayParts && skinBox.IsOverlayPart() ? skinBox.Type == "HEADWEAR" ? OverlayScale * 2 : OverlayScale : 0f); + } + + private void OnANIMUpdate() + { + head.SetVisible(0, !ANIM.GetFlag(SkinAnimFlag.HEAD_DISABLED)); + head.SetVisible(1, !ANIM.GetFlag(SkinAnimFlag.HEAD_OVERLAY_DISABLED)); + + body.SetVisible(0, !ANIM.GetFlag(SkinAnimFlag.BODY_DISABLED)); + rightArm.SetVisible(0, !ANIM.GetFlag(SkinAnimFlag.RIGHT_ARM_DISABLED)); + leftArm.SetVisible(0, !ANIM.GetFlag(SkinAnimFlag.LEFT_ARM_DISABLED)); + rightLeg.SetVisible(0, !ANIM.GetFlag(SkinAnimFlag.RIGHT_LEG_DISABLED)); + leftLeg.SetVisible(0, !ANIM.GetFlag(SkinAnimFlag.LEFT_LEG_DISABLED)); + + bool slim = ANIM.GetFlag(SkinAnimFlag.SLIM_MODEL); + + head.FlipZMapping = true; + if (slim || ANIM.GetFlag(SkinAnimFlag.RESOLUTION_64x64)) + { + TextureSize = new Size(64, 64); + body.SetVisible(1, !ANIM.GetFlag(SkinAnimFlag.BODY_OVERLAY_DISABLED)); + rightArm.SetVisible(1, !ANIM.GetFlag(SkinAnimFlag.RIGHT_ARM_OVERLAY_DISABLED)); + leftArm.SetVisible(1, !ANIM.GetFlag(SkinAnimFlag.LEFT_ARM_OVERLAY_DISABLED)); + rightLeg.SetVisible(1, !ANIM.GetFlag(SkinAnimFlag.RIGHT_LEG_OVERLAY_DISABLED)); + leftLeg.SetVisible(1, !ANIM.GetFlag(SkinAnimFlag.LEFT_LEG_OVERLAY_DISABLED)); + + int slimValue = slim ? 3 : 4; + rightArm.ReplaceCube(0, new(slim ? -2 : -3, -2, -2), new(slimValue, 12, 4), new(40, 16)); + rightArm.ReplaceCube(1, new(slim ? -2 : -3, -2, -2), new(slimValue, 12, 4), new(40, 32), inflate: OverlayScale); + + leftArm.ReplaceCube(0, new(-1, -2, -2), new(slimValue, 12, 4), new(32, 48)); + leftArm.ReplaceCube(1, new(-1, -2, -2), new(slimValue, 12, 4), new(48, 48), inflate: OverlayScale); + + rightLeg.ReplaceCube(0, new(-2, 0, -2), new(4, 12, 4), new(0, 16)); + leftLeg.ReplaceCube(0, new(-2, 0, -2), new(4, 12, 4), new(16, 48)); + return; + } + + TextureSize = new Size(64, 32); + + body.SetVisible(1, false); + head.FlipZMapping = false; + + rightArm.ReplaceCube(0, new(-3, -2, -2), new(4, 12, 4), new(40, 16)); + rightArm.SetVisible(1, false); + + leftArm.ReplaceCube(0, new(-1, -2, -2), new(4, 12, 4), new(40, 16), mirrorTexture: true); + leftArm.SetVisible(1, false); + + rightLeg.ReplaceCube(0, new(-2, 0, -2), new(4, 12, 4), new(0, 16)); + rightLeg.SetVisible(1, false); + leftLeg.ReplaceCube (0, new(-2, 0, -2), new(4, 12, 4), new(0, 16), mirrorTexture: true); + leftLeg.SetVisible(1, false); + } + + protected override bool ProcessDialogKey(Keys keyData) + { + switch (keyData) + { + case Keys.F3: + showWireFrame = !showWireFrame; + return true; + case Keys.R: + ResetCamera(head.GetCenter(0)); + return true; + case Keys.C: + CenterSelectedObject(); + break; + } + return base.ProcessDialogKey(keyData); + } + + public override void ResetCamera(Vector3 defaultPosition) + { + base.ResetCamera(defaultPosition); + Camera.Distance = DefaultCameraDistance; + } + + internal void CenterSelectedObject() + { + if (ModelData.IndexInRange(SelectedIndex)) + { + SkinBOX skinBox = ModelData[SelectedIndex]; + if (!meshStorage.ContainsKey(skinBox.Type)) + { + Trace.TraceWarning("[{0}@{1}] Invalid BOX Type: '{2}'", nameof(SkinRenderer), nameof(CenterSelectedObject), skinBox.Type); + return; + } + + CubeMeshCollection cubeMesh = meshStorage[skinBox.Type]; + Vector3 center = skinBox.ToCube().Center; + Matrix4 camMat = (Matrix4.CreateTranslation(cubeMesh.Translation) * Matrix4.CreateTranslation(center + cubeMesh.Offset) * Matrix4.CreateScale(-1, 1, 1)); + Vector3 camPos = camMat.ExtractTranslation(); + Camera.FocalPoint = camPos; + Camera.Distance = skinBox.Size.Length() * 2; + } + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + if (DesignMode) + { + return; + } + + FramebufferBegin(); + + GL.Enable(EnableCap.LineSmooth); + Matrix4 viewProjection = Camera.GetViewProjection(); + + // Render Skybox + { + GL.DepthFunc(DepthFunction.Lequal); + GL.DepthMask(false); + ShaderProgram skyboxShader = GetShader("SkyboxShader"); + skyboxShader.Bind(); + _skyboxTexture.Bind(); + + Matrix4 view = new Matrix4(new Matrix3(Matrix4.LookAt(Camera.WorldPosition, Camera.WorldPosition + Camera.Orientation, Camera.Up))) + * Matrix4.CreateRotationY(MathHelper.DegreesToRadians(Camera.Yaw)) + * Matrix4.CreateRotationX(MathHelper.DegreesToRadians(Camera.Pitch)); + Matrix4 viewproj = view * Camera.GetProjection(); + skyboxShader.SetUniformMat4("ViewProjection", ref viewproj); + Renderer.Draw(skyboxShader, _skyboxRenderBuffer); + GL.DepthMask(true); + GL.DepthFunc(DepthFunction.Less); + } + + ShaderProgram lineShader = GetShader("PlainColorShader"); + + // Render (custom) skin + { + GL.Enable(EnableCap.Texture2D); // Enable textures + + GL.Enable(EnableCap.Blend); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + + GL.Enable(EnableCap.AlphaTest); // Enable transparent + GL.AlphaFunc(AlphaFunction.Greater, 0.0f); + GL.DepthFunc(DepthFunction.Lequal); + + if (showWireFrame) + GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); + + Matrix4 renderTransform = Matrix4.CreateScale(1f, -1f, -1f); + + ShaderProgram cubeShader = GetShader("CubeShader"); + cubeShader.Bind(); + cubeShader.SetUniformMat4("ViewProjection", ref viewProjection); + cubeShader.SetUniform2("TexSize", TextureSize); + + skinTexture.Bind(); + + Matrix4 legRightMatrix = Matrix4.Identity; + Matrix4 legLeftMatrix = Matrix4.Identity; + Matrix4 armRightMatrix = Matrix4.Identity; + Matrix4 armLeftMatrix = Matrix4.Identity; + if (Animate) + { + if (ANIM.GetFlag(SkinAnimFlag.DINNERBONE)) + { + renderTransform *= Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(-180f)); + renderTransform = Matrix4.CreateTranslation(head.GetFaceCenter(0, Cube.Face.Top)) * renderTransform.Pivoted(Vector3.UnitY * 12f); + } + + if (!ANIM.GetFlag(SkinAnimFlag.STATIC_ARMS)) + { + armRightMatrix = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(animationCurrentRotationAngle)); + armLeftMatrix = Matrix4.CreateRotationX(MathHelper.DegreesToRadians((ANIM.GetFlag(SkinAnimFlag.SYNCED_ARMS) ? 1f : -1f) * animationCurrentRotationAngle)); + if (ANIM.GetFlag(SkinAnimFlag.STATUE_OF_LIBERTY)) + { + armRightMatrix = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(-180f)); + armLeftMatrix = Matrix4.CreateRotationX(0f); + } + if (ANIM.GetFlag(SkinAnimFlag.ZOMBIE_ARMS)) + { + var rotation = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(-90f)); + armRightMatrix = rotation; + armLeftMatrix = rotation; + } + } + + if (!ANIM.GetFlag(SkinAnimFlag.STATIC_LEGS)) + { + legRightMatrix = Matrix4.CreateRotationX(MathHelper.DegreesToRadians((ANIM.GetFlag(SkinAnimFlag.SYNCED_LEGS) ? 1f : -1f) * animationCurrentRotationAngle)); + legLeftMatrix = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(animationCurrentRotationAngle)); + } + armRightMatrix = RightArmMatrix * armRightMatrix; + armLeftMatrix = LeftArmMatrix * armLeftMatrix; + } + + RenderBodyPart(cubeShader, Matrix4.Identity, renderTransform, "HEAD", "HEADWEAR", "BODY", "JACKET"); + RenderBodyPart(cubeShader, armRightMatrix, renderTransform, "ARM0", "SLEEVE0"); + RenderBodyPart(cubeShader, armLeftMatrix, renderTransform, "ARM1", "SLEEVE1"); + RenderBodyPart(cubeShader, legRightMatrix, renderTransform, "LEG0", "PANTS0"); + RenderBodyPart(cubeShader, legLeftMatrix, renderTransform, "LEG1", "PANTS1"); + + if (_capeImage is not null) + { + cubeShader.SetUniform2("TexSize", new Vector2(64, 32)); + capeTexture.Bind(); + // Defines minimum Angle(in Degrees) of the cape + float capeMinimumRotationAngle = 7.5f; + // Controls how much of an angle is applied + float capeRotationFactor = 0.4f; + // Low value = slow movement + float capeRotationSpeed = 0.02f; + float capeRotation = ((float)MathHelper.RadiansToDegrees(Math.Sin(Math.Abs(animationCurrentRotationAngle) * capeRotationSpeed) * capeRotationFactor)) + capeMinimumRotationAngle; + Matrix4 partMatrix = + Matrix4.CreateRotationY(MathHelper.DegreesToRadians(180f)) * + Matrix4.CreateRotationX(MathHelper.DegreesToRadians(capeRotation)); + RenderPart(cubeShader, cape, partMatrix, renderTransform); + } + + // Armor rendering + if (ShowArmor && !ANIM.GetFlag(SkinAnimFlag.ALL_ARMOR_DISABLED)) + { + armorTexture.Bind(); + cubeShader.SetUniform2("TexSize", new Vector2(64, 64)); + if (!ANIM.GetFlag(SkinAnimFlag.HEAD_DISABLED) || ANIM.GetFlag(SkinAnimFlag.FORCE_HEAD_ARMOR)) + RenderPart(cubeShader, offsetSpecificMeshStorage["HELMET"], Matrix4.Identity, renderTransform); + + if (!ANIM.GetFlag(SkinAnimFlag.BODY_DISABLED) || ANIM.GetFlag(SkinAnimFlag.FORCE_BODY_ARMOR)) + RenderPart(cubeShader, offsetSpecificMeshStorage["CHEST"], Matrix4.Identity, renderTransform); + + if (!ANIM.GetFlag(SkinAnimFlag.RIGHT_ARM_DISABLED) || ANIM.GetFlag(SkinAnimFlag.FORCE_RIGHT_ARM_ARMOR)) + RenderPart(cubeShader, offsetSpecificMeshStorage["SHOULDER0"], armRightMatrix, renderTransform); + + if (!ANIM.GetFlag(SkinAnimFlag.LEFT_ARM_DISABLED) || ANIM.GetFlag(SkinAnimFlag.FORCE_LEFT_ARM_ARMOR)) + RenderPart(cubeShader, offsetSpecificMeshStorage["SHOULDER1"], armLeftMatrix, renderTransform); + + bool showRightLegArmor = !ANIM.GetFlag(SkinAnimFlag.RIGHT_LEG_DISABLED) || ANIM.GetFlag(SkinAnimFlag.FORCE_RIGHT_LEG_ARMOR); + if (showRightLegArmor) + { + RenderPart(cubeShader, offsetSpecificMeshStorage["PANTS0"], legRightMatrix, renderTransform); + RenderPart(cubeShader, offsetSpecificMeshStorage["BOOT0"], legRightMatrix, renderTransform); + } + + bool showLeftLegArmor = !ANIM.GetFlag(SkinAnimFlag.LEFT_LEG_DISABLED) || ANIM.GetFlag(SkinAnimFlag.FORCE_LEFT_LEG_ARMOR); + if (showLeftLegArmor) + { + RenderPart(cubeShader, offsetSpecificMeshStorage["PANTS1"], legLeftMatrix, renderTransform); + RenderPart(cubeShader, offsetSpecificMeshStorage["BOOT1"], legLeftMatrix, renderTransform); + } + + if (showRightLegArmor && showLeftLegArmor) + RenderPart(cubeShader, offsetSpecificMeshStorage["WAIST"], Matrix4.Identity, renderTransform); + } + + if (showWireFrame) + GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); + + if (ShowGuideLines) + { + GL.DepthFunc(DepthFunction.Always); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + lineShader.Bind(); + lineShader.SetUniformMat4("ViewProjection", ref viewProjection); + lineShader.SetUniformMat4("Transform", ref renderTransform); + lineShader.SetUniform1("Intensity", 1f); + lineShader.SetUniform4("BlendColor", GuideLineColor); + Renderer.SetLineWidth(2.5f); + Renderer.Draw(lineShader, GetGuidelineDrawContext()); + Renderer.SetLineWidth(1f); + GL.DepthFunc(DepthFunction.Less); + } + + BoundingBox boundingBox = GetSelectedBoundingArea(); + + Matrix4 boundingBoxRenderTransform = renderTransform; + + if (SelectedIndices.Length == 1 && ModelData.IndexInRange(SelectedIndices[0])) + { + SkinBOX box = ModelData[SelectedIndices[0]]; + + if (meshStorage.ContainsKey(box.Type)) + { + CubeMeshCollection cubeMesh = meshStorage[box.Type]; + + Matrix4 GetGroupTransform(string type) + { + switch (type) + { + case "ARM0": + case "SLEEVE0": + return armRightMatrix; + case "ARM1": + case "SLEEVE1": + return armLeftMatrix; + case "LEG0": + case "PANTS0": + return legRightMatrix; + case "LEG1": + case "PANTS1": + return legLeftMatrix; + default: + return Matrix4.Identity; + } + } + boundingBoxRenderTransform = GetGroupTransform(box.Type) * renderTransform; + } + } + + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.SrcColor); + DrawBoundingBox(boundingBoxRenderTransform, boundingBox, HighlightlingColor); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + + // Show skin bounds + if (ShowBoundingBox) + { + GL.BlendFunc(BlendingFactor.SrcColor, BlendingFactor.SrcAlpha); + DrawBoundingBox(renderTransform, _skinBounds, Color.BurlyWood); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + } + } + + // Ground plane + { + GL.Enable(EnableCap.DepthTest); + GL.Enable(EnableCap.AlphaTest); // Enable transparent + GL.AlphaFunc(AlphaFunction.Always, 0.0f); + GL.BlendFunc(BlendingFactor.DstAlpha, BlendingFactor.OneMinusSrcAlpha); + lineShader.Bind(); + lineShader.SetUniformMat4("ViewProjection", ref viewProjection); + lineShader.SetUniform1("Intensity", 0.5f); + lineShader.SetUniform4("BlendColor", Color.AntiqueWhite); + Matrix4 transform = Matrix4.CreateScale(25f) * Matrix4.CreateTranslation(new Vector3(0f, -24.1f, 0f)); + lineShader.SetUniformMat4("Transform", ref transform); + Renderer.Draw(lineShader, _groundDrawContext); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + } + + FramebufferEnd(); + } + + private BoundingBox GetSelectedBoundingArea() + { + IEnumerable GetBoundingBoxesFromSelectedIndices(IEnumerable selectedIndices) + { + foreach (var selectedIndex in selectedIndices) + { + if (!ModelData.IndexInRange(selectedIndex)) + continue; + + SkinBOX box = ModelData[selectedIndex]; + + if (!meshStorage.ContainsKey(box.Type)) + continue; + + float inflate = autoInflateOverlayParts && box.IsOverlayPart() ? box.Type == "HEADWEAR" ? OverlayScale * 2 : OverlayScale : 0f; + Cube cube = box.ToCube(inflate); + CubeMeshCollection cubeMesh = meshStorage[box.Type]; + yield return cube.GetBoundingBox(cubeMesh.GetTransform()); + } + yield break; + } + return GetBoundingBoxesFromSelectedIndices(SelectedIndices).GetEnclosingBoundingBox(); + } + + private void RenderBodyPart(ShaderProgram shader, Matrix4 partsMatrix, Matrix4 globalMatrix, params string[] partNames) + { + foreach (var partName in partNames) + { + RenderPart(shader, meshStorage[partName], partsMatrix, globalMatrix); + } + } + + private void RenderPart(ShaderProgram shader, GenericMesh mesh, Matrix4 partMatrix, Matrix4 globalMatrix) where T : struct + { + Matrix4 transform = partMatrix * mesh.GetTransform() * globalMatrix; + DrawMesh(mesh, shader, transform); + } + + protected override void OnUpdate(object sender, TimeSpan timestep) + { + base.OnUpdate(sender, timestep); + double delta = timestep.TotalSeconds; + if (!Animate) + return; + + animationCurrentRotationAngle += (float)delta * animationRotationSpeed; + animationCurrentRotationAngle = MathHelper.Clamp(animationCurrentRotationAngle, -animationMaxAngleInDegrees, animationMaxAngleInDegrees); + if (animationCurrentRotationAngle >= animationMaxAngleInDegrees || animationCurrentRotationAngle <= -animationMaxAngleInDegrees) + animationRotationSpeed = -animationRotationSpeed; + } + + private void ReInitialzeSkinData() + { + foreach (CubeMeshCollection mesh in meshStorage.Values) + { + mesh.Clear(); + } + + InitializeSkinData(); + UpdateModelData(); + OnANIMUpdate(); + } + + private void UpdateModelData() + { + foreach (SkinBOX item in ModelData) + { + AddCustomModelPart(item); + } + } + } +} \ No newline at end of file diff --git a/PCK-Studio/Rendering/SkinRenderer.resx b/PCK-Studio/Rendering/SkinRenderer.resx new file mode 100644 index 00000000..b6091f39 --- /dev/null +++ b/PCK-Studio/Rendering/SkinRenderer.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 16, 20 + + \ No newline at end of file diff --git a/PCK-Studio/Resources/armor.png b/PCK-Studio/Resources/armor.png new file mode 100644 index 00000000..f6b1cfdb Binary files /dev/null and b/PCK-Studio/Resources/armor.png differ diff --git a/PCK-Studio/Resources/entityBehavioursData.json b/PCK-Studio/Resources/entityBehavioursData.json new file mode 100644 index 00000000..921fe41f --- /dev/null +++ b/PCK-Studio/Resources/entityBehavioursData.json @@ -0,0 +1,489 @@ +{ + "COMMENT": "Entity data research by NessieHax (Miku-666) and MattNL", + "entries": [ + { + "internalName": "area_effect_cloud", + "displayName": "Area Effect Cloud / Particle" + }, + { + "internalName": "armor_stand", + "displayName": "Armor Stand" + }, + { + "internalName": "arrow", + "displayName": "Arrow" + }, + { + "internalName": "bat", + "displayName": "Bat" + }, + { + "internalName": "blaze", + "displayName": "Blaze" + }, + { + "internalName": "boat", + "displayName": "Boat" + }, + { + "internalName": "cat", + "displayName": "Cat [PS4 EXCLUSIVE]" + }, + { + "internalName": "cave_spider", + "displayName": "Cave Spider" + }, + { + "internalName": "chest_minecart", + "displayName": "Chest Minecart" + }, + { + "internalName": "chicken", + "displayName": "Chicken" + }, + { + "internalName": "cod", + "displayName": "Cod" + }, + { + "internalName": "commandblock_minecart", + "displayName": "Command Block Minecart" + }, + { + "internalName": "cow", + "displayName": "Cow" + }, + { + "internalName": "creeper", + "displayName": "Creeper" + }, + { + "internalName": "dolphin", + "displayName": "Dolphin" + }, + { + "internalName": "donkey", + "displayName": "Donkey" + }, + { + "internalName": "dragon_fireball", + "displayName": "Dragon Fireball" + }, + { + "internalName": "drowned", + "displayName": "Drowned" + }, + { + "internalName": "egg", + "displayName": "Thrown Egg" + }, + { + "internalName": "elder_guardian", + "displayName": "Elder Guardian" + }, + { + "internalName": "ender_crystal", + "displayName": "End Crystal" + }, + { + "internalName": "ender_dragon", + "displayName": "Ender Dragon" + }, + { + "internalName": "ender_pearl", + "displayName": "Thrown Ender Pearl" + }, + { + "internalName": "enderman", + "displayName": "Enderman" + }, + { + "internalName": "endermite", + "displayName": "Endermite" + }, + { + "internalName": "evocation_illager", + "displayName": "Evoker" + }, + { + "internalName": "evocation_fangs", + "displayName": "Evoker Fangs" + }, + { + "internalName": "xp_bottle", + "displayName": "Thrown Bottle O' Enchanting" + }, + { + "internalName": "xp_orb", + "displayName": "Experience Orb" + }, + { + "internalName": "eye_of_ender_signal", + "displayName": "Thrown Eye of Ender" + }, + { + "internalName": "falling_block", + "displayName": "Falling Block" + }, + { + "internalName": "fireball", + "displayName": "Fireball" + }, + { + "internalName": "fireworks_rocket", + "displayName": "Firework Rocket" + }, + { + "internalName": "furnace_minecart", + "displayName": "Furnace Minecart" + }, + { + "internalName": "ghast", + "displayName": "Ghast" + }, + { + "internalName": "giant", + "displayName": "Giant" + }, + { + "internalName": "guardian", + "displayName": "Guardian" + }, + { + "internalName": "hopper_minecart", + "displayName": "Hopper Minecart" + }, + { + "internalName": "horse", + "displayName": "Horse" + }, + { + "internalName": "husk", + "displayName": "Husk" + }, + { + "internalName": "villager_golem", + "displayName": "Iron Golem" + }, + { + "internalName": "item", + "displayName": "Dropped Item" + }, + { + "internalName": "item_frame", + "displayName": "Item Frame" + }, + { + "internalName": "leash_knot", + "displayName": "Lead Knot" + }, + { + "internalName": "llama", + "displayName": "Llama" + }, + { + "internalName": "llama_spit", + "displayName": "Llama Spit" + }, + { + "internalName": "magma_cube", + "displayName": "Magma Cube" + }, + { + "internalName": "minecart", + "displayName": "Minecart" + }, + { + "internalName": "mooshroom", + "displayName": "Mooshroom" + }, + { + "internalName": "mule", + "displayName": "Mule" + }, + { + "internalName": "ocelot", + "displayName": "Ocelot" + }, + { + "internalName": "painting", + "displayName": "Painting" + }, + { + "internalName": "panda", + "displayName": "Panda [PS4 EXCLUSIVE]" + }, + { + "internalName": "parrot", + "displayName": "Parrot" + }, + { + "internalName": "phantom", + "displayName": "Phantom" + }, + { + "internalName": "pig", + "displayName": "Pig" + }, + { + "internalName": "pillager", + "displayName": "Pillager [PS4 EXCLUSIVE]" + }, + { + "internalName": "polar_bear", + "displayName": "Polar Bear" + }, + { + "internalName": "potion", + "displayName": "Thrown Potion" + }, + { + "internalName": "pufferfish", + "displayName": "Pufferfish" + }, + { + "internalName": "rabbit", + "displayName": "Rabbit" + }, + { + "internalName": "ravager", + "displayName": "Ravager [PS4 EXCLUSIVE]" + }, + { + "internalName": "salmon", + "displayName": "Salmon" + }, + { + "internalName": "sheep", + "displayName": "Sheep" + }, + { + "internalName": "shulker", + "displayName": "Shulker" + }, + { + "internalName": "shulker_bullet", + "displayName": "Shulker Bullet" + }, + { + "internalName": "silverfish", + "displayName": "Silverfish" + }, + { + "internalName": "skeleton", + "displayName": "Skeleton" + }, + { + "internalName": "skeleton_horse", + "displayName": "Skeleton Horse" + }, + { + "internalName": "slime", + "displayName": "Slime" + }, + { + "internalName": "small_fireball", + "displayName": "Small Fireball" + }, + { + "internalName": "snowman", + "displayName": "Snow Golem" + }, + { + "internalName": "snowball", + "displayName": "Thrown Snowball" + }, + { + "internalName": "spawner_minecart", + "displayName": "Spawner Minecart" + }, + { + "internalName": "spectral_arrow", + "displayName": "Spectral Arrow" + }, + { + "internalName": "spider", + "displayName": "Spider" + }, + { + "internalName": "squid", + "displayName": "Squid" + }, + { + "internalName": "stray", + "displayName": "Stray" + }, + { + "internalName": "tnt", + "displayName": "Primed TNT" + }, + { + "internalName": "tnt_minecart", + "displayName": "TNT Minecart" + }, + { + "internalName": "trident", + "displayName": "Thrown Trident" + }, + { + "internalName": "tropical_fish", + "displayName": "Tropical Fish" + }, + { + "internalName": "turtle", + "displayName": "Turtle" + }, + { + "internalName": "vex", + "displayName": "Vex" + }, + { + "internalName": "villager", + "displayName": "Villager" + }, + { + "internalName": "vindication_illager", + "displayName": "Vindicator" + }, + { + "internalName": "wandering_trader", + "displayName": "Wandering Trader [PS4 EXCLUSIVE]" + }, + { + "internalName": "witch", + "displayName": "Witch" + }, + { + "internalName": "wither", + "displayName": "Wither" + }, + { + "internalName": "wither_skeleton", + "displayName": "Wither Skeleton" + }, + { + "internalName": "wither_skull", + "displayName": "Wither Skull" + }, + { + "internalName": "wolf", + "displayName": "Wolf" + }, + { + "internalName": "zombie", + "displayName": "Zombie" + }, + { + "internalName": "zombie_horse", + "displayName": "Zombie Horse" + }, + { + "internalName": "zombie_pigman", + "displayName": "Zombie Pigman" + }, + { + "internalName": "zombie_villager", + "displayName": "Zombie Villager" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "illusion_illager", + "displayName": "Illusioner" + } + ] +} diff --git a/PCK-Studio/Resources/entityMaterialsData.json b/PCK-Studio/Resources/entityMaterialsData.json new file mode 100644 index 00000000..259a077b --- /dev/null +++ b/PCK-Studio/Resources/entityMaterialsData.json @@ -0,0 +1,485 @@ +{ + "COMMENT": "Entity data research by NessieHax (Miku-666) and MattNL", + "entries": [ + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "bat", + "displayName": "Bat" + }, + { + "internalName": "blaze_head", + "displayName": "Blaze" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "cat", + "displayName": "Cat [PS4 EXCLUSIVE]" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "drowned", + "displayName": "Drowned" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "ender_dragon", + "displayName": "Ender Dragon" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "enderman", + "displayName": "Enderman" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "ghast", + "displayName": "Ghast" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "guardian", + "displayName": "Guardian" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "iron_golem", + "displayName": "Iron Golem" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "magma_cube", + "displayName": "Magma Cube" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "phantom", + "displayName": "Phantom" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "sheep", + "displayName": "Sheep" + }, + { + "internalName": "shulker", + "displayName": "Shulker" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "skeleton", + "displayName": "Skeleton" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "stray", + "displayName": "Stray" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "wither_boss", + "displayName": "Wither" + }, + { + "internalName": "wither_skeleton", + "displayName": "Wither Skeleton" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "wolf", + "displayName": "Wolf" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "zombie_pigman", + "displayName": "Zombie Pigman" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "villager", + "displayName": "Villager [PS4 EXCLUSIVE]" + }, + { + "internalName": "zombie_villager", + "displayName": "Zombie Villager [PS4 EXCLUSIVE]" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "phantom_invisible", + "displayName": "Phantom (Overlay)" + }, + { + "internalName": "enderman_invisible", + "displayName": "Enderman (Overlay)" + }, + { + "internalName": "spider_invisible", + "displayName": "Spiders (Overlay)" + }, + { + "internalName": "spider", + "displayName": "Spiders" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + } + ] +} diff --git a/PCK-Studio/Resources/entityModelsData.json b/PCK-Studio/Resources/entityModelsData.json new file mode 100644 index 00000000..647be99b --- /dev/null +++ b/PCK-Studio/Resources/entityModelsData.json @@ -0,0 +1,485 @@ +{ + "COMMENT": "Entity data research by NessieHax (Miku-666) and MattNL", + "entries": [ + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "bat", + "displayName": "Bat" + }, + { + "internalName": "blaze", + "displayName": "Blaze" + }, + { + "internalName": "boat", + "displayName": "Boat" + }, + { + "internalName": "cat", + "displayName": "Cat [PS4 EXCLUSIVE]" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "chicken", + "displayName": "Chicken" + }, + { + "internalName": "cod", + "displayName": "Cod" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "cow", + "displayName": "Cow" + }, + { + "internalName": "creeper", + "displayName": "Creeper" + }, + { + "internalName": "dolphin", + "displayName": "Dolphin" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "zombie.drowned", + "displayName": "Drowned" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "dragon", + "displayName": "Ender Dragon" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "enderman", + "displayName": "Enderman" + }, + { + "internalName": "endermite", + "displayName": "Endermite" + }, + { + "internalName": "evoker", + "displayName": "Evoker" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "ghast", + "displayName": "Ghast" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "zombie.husk", + "displayName": "Husk" + }, + { + "internalName": "irongolem", + "displayName": "Iron Golem" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "llama", + "displayName": "Llama" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "lavaslime", + "displayName": "Magma Cube" + }, + { + "internalName": "minecart", + "displayName": "Minecart" + }, + { + "internalName": "mooshroom", + "displayName": "Mooshroom" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "ocelot", + "displayName": "Ocelot" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "panda", + "displayName": "Panda [PS4 EXCLUSIVE]" + }, + { + "internalName": "parrot", + "displayName": "Parrot" + }, + { + "internalName": "phantom", + "displayName": "Phantom" + }, + { + "internalName": "pig", + "displayName": "Pig" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "polarbear", + "displayName": "Polar Bear" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "pufferfish.large", + "displayName": "Pufferfish (Large)" + }, + { + "internalName": "rabbit", + "displayName": "Rabbit" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "salmon", + "displayName": "Salmon" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "shulker", + "displayName": "Shulker" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "silverfish", + "displayName": "Silverfish" + }, + { + "internalName": "skeleton", + "displayName": "Skeleton" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "snowgolem", + "displayName": "Snow Golem" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "squid", + "displayName": "Squid" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "trident", + "displayName": "Thrown Trident" + }, + { + "internalName": "tropicalfish_a", + "displayName": "Tropical Fish (Small)" + }, + { + "internalName": "turtle", + "displayName": "Turtle" + }, + { + "internalName": "vex", + "displayName": "Vex" + }, + { + "internalName": "villager", + "displayName": "Villager" + }, + { + "internalName": "vindicator", + "displayName": "Vindicator/Illusioner" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "witch", + "displayName": "Witch" + }, + { + "internalName": "witherboss", + "displayName": "Wither" + }, + { + "internalName": "skeleton.wither", + "displayName": "Wither Skeleton" + }, + { + "internalName": "witherboss.armor", + "displayName": "Wither (Armor)" + }, + { + "internalName": "wolf", + "displayName": "Wolf" + }, + { + "internalName": "zombie", + "displayName": "Zombie" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "pigzombie", + "displayName": "Zombie Pigman" + }, + { + "internalName": "zombie.villager", + "displayName": "Zombie Villager" + }, + { + "internalName": "skeleton_head", + "displayName": "Skeleton Skull" + }, + { + "internalName": "skeleton_wither_head", + "displayName": "Wither Skeleton Skull" + }, + { + "internalName": "zombie_head", + "displayName": "Zombie Head" + }, + { + "internalName": "creeper_head", + "displayName": "Creeper Head" + }, + { + "internalName": "dragon_head", + "displayName": "Ender Dragon Head" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "spider", + "displayName": "Spider" + }, + { + "internalName": "bed", + "displayName": "Bed" + }, + { + "internalName": "guardian", + "displayName": "Guardian" + }, + { + "internalName": "horse.v2", + "displayName": "Horse/Donkey/Mule" + }, + { + "internalName": "pufferfish.small", + "displayName": "Pufferfish (Small)" + }, + { + "internalName": "pufferfish.mid", + "displayName": "Pufferfish (Medium)" + }, + { + "internalName": "sheep.sheared", + "displayName": "Sheep (Without Fur)" + }, + { + "internalName": "sheep", + "displayName": "Sheep (Fur Only)" + }, + { + "internalName": "slime", + "displayName": "Slime (Inner)" + }, + { + "internalName": "slime.armor", + "displayName": "Slime (Outer)" + }, + { + "internalName": "skeleton.stray", + "displayName": "Stray" + }, + { + "internalName": "stray.armor", + "displayName": "Stray (Overlay)" + }, + { + "internalName": "tropicalfish_b", + "displayName": "Tropical Fish (Large)" + } + ] +} diff --git a/PCK-Studio/Resources/shader/framebufferFragmentShader.glsl b/PCK-Studio/Resources/shader/framebufferFragmentShader.glsl new file mode 100644 index 00000000..b4d3a552 --- /dev/null +++ b/PCK-Studio/Resources/shader/framebufferFragmentShader.glsl @@ -0,0 +1,13 @@ +#version 330 core + +layout(location = 0) out vec4 color; + +uniform sampler2D screenTexture; + +in vec2 texCoords; + +void main() +{ + vec3 texColor = texture(screenTexture, texCoords).rgb; + color = vec4(texColor, 1.0); +} \ No newline at end of file diff --git a/PCK-Studio/Resources/shader/framebufferVertexShader.glsl b/PCK-Studio/Resources/shader/framebufferVertexShader.glsl new file mode 100644 index 00000000..33a9e748 --- /dev/null +++ b/PCK-Studio/Resources/shader/framebufferVertexShader.glsl @@ -0,0 +1,12 @@ +#version 330 core + +layout(location = 0) in vec4 a_PosAndTexCoord; + +out vec2 texCoords; + +void main() +{ + vec2 pos = a_PosAndTexCoord.xy; + texCoords = a_PosAndTexCoord.zw; + gl_Position = vec4(pos, 0.0, 1.0); +}; \ No newline at end of file diff --git a/PCK-Studio/Resources/shader/plainColorFragmentShader.glsl b/PCK-Studio/Resources/shader/plainColorFragmentShader.glsl new file mode 100644 index 00000000..31725db1 --- /dev/null +++ b/PCK-Studio/Resources/shader/plainColorFragmentShader.glsl @@ -0,0 +1,13 @@ +#version 330 core + +layout(location = 0) out vec4 FragColor; + +uniform vec4 BlendColor; +uniform float Intensity; + +in vec4 color; + +void main() +{ + FragColor = vec4((color * BlendColor).rgb, Intensity); +} \ No newline at end of file diff --git a/PCK-Studio/Resources/shader/plainColorVertexShader.glsl b/PCK-Studio/Resources/shader/plainColorVertexShader.glsl new file mode 100644 index 00000000..c7d0b886 --- /dev/null +++ b/PCK-Studio/Resources/shader/plainColorVertexShader.glsl @@ -0,0 +1,15 @@ +#version 330 core + +layout(location = 0) in vec4 a_Pos; +layout(location = 1) in vec4 a_Color; + +uniform mat4 ViewProjection; +uniform mat4 Transform; + +out vec4 color; + +void main() +{ + color = a_Color; + gl_Position = ViewProjection * Transform * vec4(a_Pos.xyz, 1.0); +}; \ No newline at end of file diff --git a/PCK-Studio/Resources/shader/skyboxFragmentShader.glsl b/PCK-Studio/Resources/shader/skyboxFragmentShader.glsl new file mode 100644 index 00000000..5fd1a921 --- /dev/null +++ b/PCK-Studio/Resources/shader/skyboxFragmentShader.glsl @@ -0,0 +1,13 @@ +#version 330 core + +layout(location = 0) out vec4 color; + +uniform samplerCube skybox; +uniform float brightness; + +in vec3 texCoords; + +void main() +{ + color = vec4(texture(skybox, texCoords).rgb * clamp(brightness, 0.0, 1.0), 1.0); +} \ No newline at end of file diff --git a/PCK-Studio/Resources/shader/skyboxVertexShader.glsl b/PCK-Studio/Resources/shader/skyboxVertexShader.glsl new file mode 100644 index 00000000..729f6678 --- /dev/null +++ b/PCK-Studio/Resources/shader/skyboxVertexShader.glsl @@ -0,0 +1,14 @@ +#version 330 core + +layout(location = 0) in vec4 a_Pos; + +uniform mat4 ViewProjection; + +out vec3 texCoords; + +void main() +{ + vec4 pos = ViewProjection * a_Pos; + gl_Position = vec4(pos.x, pos.y, pos.ww); + texCoords = vec3(a_Pos.xy, -a_Pos.z); +}; \ No newline at end of file diff --git a/PCK-Studio/Resources/shader/texturedCubeFragmentShader.glsl b/PCK-Studio/Resources/shader/texturedCubeFragmentShader.glsl new file mode 100644 index 00000000..0bbfdba9 --- /dev/null +++ b/PCK-Studio/Resources/shader/texturedCubeFragmentShader.glsl @@ -0,0 +1,16 @@ +#version 330 core + +layout(location = 0) out vec4 color; + +uniform sampler2D Texture; + +in vec2 o_TillingFactor; +in vec2 o_TexCoord; + +void main() +{ + vec4 result = texture(Texture, o_TexCoord * o_TillingFactor); + if (result.a <= 0.0) + discard; + color = result; +}; \ No newline at end of file diff --git a/PCK-Studio/Resources/shader/texturedCubeGeometryShader.glsl b/PCK-Studio/Resources/shader/texturedCubeGeometryShader.glsl new file mode 100644 index 00000000..a84094f9 --- /dev/null +++ b/PCK-Studio/Resources/shader/texturedCubeGeometryShader.glsl @@ -0,0 +1,47 @@ +#version 330 core + +layout (triangles) in; +layout (triangle_strip, max_vertices=3) out; + +uniform vec2 TexSize; + +out vec2 o_TexCoord; +out vec2 o_TillingFactor; + +in geometryData +{ + vec2 TexCoord; +} dataIn[]; + +void FixUV() +{ + bool isXBad = + dataIn[0].TexCoord.x >= TexSize.x && + dataIn[1].TexCoord.x >= TexSize.x && + dataIn[2].TexCoord.x >= TexSize.x; + + gl_Position = gl_in[0].gl_Position; + o_TexCoord = dataIn[0].TexCoord; + if (isXBad) + o_TexCoord.x = mod(o_TexCoord.x, TexSize.x); + EmitVertex(); + + gl_Position = gl_in[1].gl_Position; + o_TexCoord = dataIn[1].TexCoord; + if (isXBad) + o_TexCoord.x = mod(o_TexCoord.x, TexSize.x); + EmitVertex(); + + gl_Position = gl_in[2].gl_Position; + o_TexCoord = dataIn[2].TexCoord; + if (isXBad) + o_TexCoord.x = mod(o_TexCoord.x, TexSize.x); + EmitVertex(); +} + +void main() +{ + o_TillingFactor = 1.0 / TexSize; + FixUV(); + EndPrimitive(); +}; \ No newline at end of file diff --git a/PCK-Studio/Resources/shader/texturedCubeVertexShader.glsl b/PCK-Studio/Resources/shader/texturedCubeVertexShader.glsl new file mode 100644 index 00000000..1e8c9114 --- /dev/null +++ b/PCK-Studio/Resources/shader/texturedCubeVertexShader.glsl @@ -0,0 +1,18 @@ +#version 330 core + +layout(location = 0) in vec3 vertexPosition; +layout(location = 1) in vec2 texCoord; + +uniform mat4 ViewProjection; +uniform mat4 Transform; + +out geometryData +{ + vec2 TexCoord; +} dataOut; + +void main() +{ + dataOut.TexCoord = texCoord; + gl_Position = ViewProjection * Transform * vec4(vertexPosition, 1.0); +}; \ No newline at end of file diff --git a/PCK-Studio/Resources/skybox_texture.png b/PCK-Studio/Resources/skybox_texture.png new file mode 100644 index 00000000..6a285591 Binary files /dev/null and b/PCK-Studio/Resources/skybox_texture.png differ diff --git a/PCK-Studio/ToolboxItems/AnimationPictureBox.cs b/PCK-Studio/ToolboxItems/AnimationPictureBox.cs index 196b19e1..ae02686a 100644 --- a/PCK-Studio/ToolboxItems/AnimationPictureBox.cs +++ b/PCK-Studio/ToolboxItems/AnimationPictureBox.cs @@ -16,14 +16,10 @@ * 3. This notice may not be removed or altered from any source distribution. **/ using System; -using System.Diagnostics; using System.Windows.Forms; -using System.Runtime.CompilerServices; -using PckStudio.Extensions; -using PckStudio.Internal; +using PckStudio.Core.Extensions; using System.Drawing; -using AnimatedGif; using System.Drawing.Imaging; namespace PckStudio.ToolboxItems @@ -39,10 +35,10 @@ namespace PckStudio.ToolboxItems get => base.Image; set { - base.Image = value; - this.Animate(false); if (value is null) return; + this.Animate(false); + base.Image = value; value.SelectActiveFrame(new FrameDimension(value.FrameDimensionsList[0]), 0); } } diff --git a/PCK-Studio/ToolboxItems/BlendPictureBox.cs b/PCK-Studio/ToolboxItems/BlendPictureBox.cs index cd0307d6..585c9684 100644 --- a/PCK-Studio/ToolboxItems/BlendPictureBox.cs +++ b/PCK-Studio/ToolboxItems/BlendPictureBox.cs @@ -1,11 +1,7 @@ using System; -using System.Collections.Generic; using System.ComponentModel; using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using PckStudio.Extensions; +using PckStudio.Core.Extensions; namespace PckStudio.ToolboxItems { @@ -24,8 +20,13 @@ namespace PckStudio.ToolboxItems public Color BlendColor { get => _blendColor; - set => _blendColor = value; + set + { + _blendColor = value; + Image = _image; + } } + [DefaultValue(typeof(BlendMode), "BlendMode.Add")] [Category("Blending")] @@ -37,6 +38,7 @@ namespace PckStudio.ToolboxItems private bool _useBlendColor = false; private Color _blendColor = Color.White; + private Image _image; private BlendMode _blendMode = BlendMode.Add; public new Image Image @@ -45,7 +47,9 @@ namespace PckStudio.ToolboxItems set { if (value is null) return; - base.Image = UseBlendColor && BlendColor != Color.White ? value.Blend(BlendColor, BlendMode) : value; + _image = value; + base.Image = UseBlendColor && BlendColor != Color.White ? _image.Blend(BlendColor, BlendMode) : _image; + Invalidate(); } } } diff --git a/PCK-Studio/ToolboxItems/InterpolationPictureBox.cs b/PCK-Studio/ToolboxItems/InterpolationPictureBox.cs index 3da28235..ad80b8d3 100644 --- a/PCK-Studio/ToolboxItems/InterpolationPictureBox.cs +++ b/PCK-Studio/ToolboxItems/InterpolationPictureBox.cs @@ -9,6 +9,15 @@ namespace PckStudio.ToolboxItems public class InterpolationPictureBox : PictureBox { public InterpolationMode InterpolationMode { get; set; } + + public InterpolationMode BackgroundInterpolationMode { get; set; } + + protected override void OnPaintBackground(PaintEventArgs paintEventArgs) + { + paintEventArgs.Graphics.InterpolationMode = BackgroundInterpolationMode; + paintEventArgs.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + base.OnPaintBackground(paintEventArgs); + } protected override void OnPaint(PaintEventArgs paintEventArgs) { diff --git a/PCK_Studio.sln b/PCK_Studio.sln index 8062268c..79c1d8d3 100644 --- a/PCK_Studio.sln +++ b/PCK_Studio.sln @@ -11,6 +11,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OMI Filetype Library", "Ven EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpMss32", "Vendor\SharpMss32\SharpMss32\SharpMss32.csproj", "{E8D0B671-3AB1-48B6-A767-58DF67BD5D11}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PckStudio.Rendering", "PckStudio.Rendering\PckStudio.Rendering.csproj", "{B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PckStudio.Core", "PckStudio.Core\PckStudio.Core.csproj", "{345EABED-F0D1-4D04-B409-BABDEF747352}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PckStuido.ModelSupport", "PckStuido.ModelSupport\PckStuido.ModelSupport.csproj", "{43BCACD7-5405-4499-9B45-E1435AC03C26}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Beta|Any CPU = Beta|Any CPU @@ -78,6 +84,60 @@ Global {E8D0B671-3AB1-48B6-A767-58DF67BD5D11}.Release|x64.Build.0 = Release|Any CPU {E8D0B671-3AB1-48B6-A767-58DF67BD5D11}.Release|x86.ActiveCfg = Release|Any CPU {E8D0B671-3AB1-48B6-A767-58DF67BD5D11}.Release|x86.Build.0 = Release|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Beta|Any CPU.ActiveCfg = Debug|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Beta|Any CPU.Build.0 = Debug|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Beta|x64.ActiveCfg = Debug|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Beta|x64.Build.0 = Debug|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Beta|x86.ActiveCfg = Debug|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Beta|x86.Build.0 = Debug|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Debug|x64.ActiveCfg = Debug|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Debug|x64.Build.0 = Debug|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Debug|x86.ActiveCfg = Debug|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Debug|x86.Build.0 = Debug|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Release|Any CPU.Build.0 = Release|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Release|x64.ActiveCfg = Release|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Release|x64.Build.0 = Release|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Release|x86.ActiveCfg = Release|Any CPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF}.Release|x86.Build.0 = Release|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Beta|Any CPU.ActiveCfg = Debug|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Beta|Any CPU.Build.0 = Debug|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Beta|x64.ActiveCfg = Debug|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Beta|x64.Build.0 = Debug|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Beta|x86.ActiveCfg = Debug|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Beta|x86.Build.0 = Debug|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Debug|Any CPU.Build.0 = Debug|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Debug|x64.ActiveCfg = Debug|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Debug|x64.Build.0 = Debug|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Debug|x86.ActiveCfg = Debug|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Debug|x86.Build.0 = Debug|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Release|Any CPU.ActiveCfg = Release|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Release|Any CPU.Build.0 = Release|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Release|x64.ActiveCfg = Release|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Release|x64.Build.0 = Release|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Release|x86.ActiveCfg = Release|Any CPU + {345EABED-F0D1-4D04-B409-BABDEF747352}.Release|x86.Build.0 = Release|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Beta|Any CPU.ActiveCfg = Debug|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Beta|Any CPU.Build.0 = Debug|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Beta|x64.ActiveCfg = Debug|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Beta|x64.Build.0 = Debug|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Beta|x86.ActiveCfg = Debug|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Beta|x86.Build.0 = Debug|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Debug|x64.ActiveCfg = Debug|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Debug|x64.Build.0 = Debug|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Debug|x86.ActiveCfg = Debug|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Debug|x86.Build.0 = Debug|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Release|Any CPU.ActiveCfg = Release|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Release|Any CPU.Build.0 = Release|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Release|x64.ActiveCfg = Release|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Release|x64.Build.0 = Release|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Release|x86.ActiveCfg = Release|Any CPU + {43BCACD7-5405-4499-9B45-E1435AC03C26}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PCK-Studio/Internal/Animation.cs b/PckStudio.Core/Animation.cs similarity index 93% rename from PCK-Studio/Internal/Animation.cs rename to PckStudio.Core/Animation.cs index 8b1c9966..f5917486 100644 --- a/PCK-Studio/Internal/Animation.cs +++ b/PckStudio.Core/Animation.cs @@ -18,13 +18,12 @@ using System; using System.Collections.Generic; using System.Drawing; -using PckStudio.Extensions; +using PckStudio.Core.Extensions; using System.Text; using System.Collections.ObjectModel; using System.Linq; -using System.Diagnostics; -namespace PckStudio.Internal +namespace PckStudio.Core { public sealed class Animation { @@ -42,11 +41,11 @@ namespace PckStudio.Internal private object _syncLock = new object(); - public Animation(IEnumerable textures, bool initFramesFromTextures = false) + public Animation(IEnumerable textures, bool initFramesFromTextures = false, int frameTime = MinimumFrameTime) { _textures = new List(textures); if (initFramesFromTextures) - AddTexturesAsFrames(MinimumFrameTime); + AddTexturesAsFrames(frameTime); } public class Frame @@ -167,7 +166,7 @@ namespace PckStudio.Internal SetFrame(frameIndex, new Frame(_textures[textureIndex], frameTime)); } - internal void SetFrameTicks(int ticks) + public void SetFrameTicks(int ticks) { lock(_syncLock) { @@ -178,7 +177,7 @@ namespace PckStudio.Internal } } - internal void SwapFrames(int sourceIndex, int destinationIndex) + public void SwapFrames(int sourceIndex, int destinationIndex) { lock(_syncLock) { @@ -186,7 +185,7 @@ namespace PckStudio.Internal } } - internal static Animation CreateEmpty() + public static Animation CreateEmpty() { return new Animation(Array.Empty()); } diff --git a/PCK-Studio/Internal/App/SettingsManager.cs b/PckStudio.Core/App/SettingsManager.cs similarity index 57% rename from PCK-Studio/Internal/App/SettingsManager.cs rename to PckStudio.Core/App/SettingsManager.cs index 9cc7e1b2..3559138d 100644 --- a/PCK-Studio/Internal/App/SettingsManager.cs +++ b/PckStudio.Core/App/SettingsManager.cs @@ -19,27 +19,40 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.Configuration; -using PckStudio.Properties; -namespace PckStudio.Internal.App +namespace PckStudio.Core.App { - internal sealed class SettingsManager + public sealed class SettingsManager { - public static SettingsManager Default { get; } = new SettingsManager(Settings.Default); + public bool IsReadOnly => _isReadOnly; + + public const string KeyToStringContextKeyConst = "keyToString"; private Dictionary> _registery = new Dictionary>(); private object _newValue = null; - private SettingsBase _settings = null; + private ApplicationSettingsBase _settings = null; + private bool _isReadOnly; - internal SettingsManager(ApplicationSettingsBase settings) + private class InternalSettings : ApplicationSettingsBase + { } + + public SettingsManager(ApplicationSettingsBase settings, bool isReadOnly = false) { _settings = settings; + _isReadOnly = isReadOnly; settings.PropertyChanged += PropertyChangedHandler; settings.SettingChanging += SettingChangingHandler; } - internal bool RegisterPropertyChangedCallback(string propertyName, Action callback) + public ApplicationSettingsBase GetSettings() => _settings; + + public static SettingsManager CreateSettings() + { + return new SettingsManager(new InternalSettings()); + } + + public bool RegisterPropertyChangedCallback(string propertyName, Action callback) { Type propertyType = _settings[propertyName].GetType(); if (!propertyType.Equals(typeof(TSettingsType))) @@ -49,7 +62,7 @@ namespace PckStudio.Internal.App return RegisterPropertyChangedCallback(propertyName, delegate (object obj) { callback((TSettingsType)obj); }); } - internal bool RegisterPropertyChangedCallback(string propertyName, Action callback) + public bool RegisterPropertyChangedCallback(string propertyName, Action callback) { return RegisterPropertyChangedCallback(propertyName, delegate (object _) { callback(); }); } @@ -78,5 +91,23 @@ namespace PckStudio.Internal.App _newValue = e.NewValue; } } + + public bool AddSetting(string name, T initialValue, string description, Action callback) + { + if (_isReadOnly) + throw new SettingsPropertyIsReadOnlyException("Can't add setting. Underlying SettingsBase is readonly."); + + if (!_settings.Context.ContainsKey(KeyToStringContextKeyConst)) + _settings.Context.Add(KeyToStringContextKeyConst, new Dictionary()); + + var settingsProperty = new SettingsProperty( + name, typeof(T), null, false, default(T), SettingsSerializeAs.String, null, false, false); + _settings.Properties.Add(settingsProperty); + _settings.PropertyValues.Add(new SettingsPropertyValue(settingsProperty) { PropertyValue = initialValue }); + if (_settings.Context[KeyToStringContextKeyConst] is Dictionary dict) + dict.Add(name, description); + callback(initialValue); + return RegisterPropertyChangedCallback(name, callback); + } } } diff --git a/PCK-Studio/Internal/App/Updater.cs b/PckStudio.Core/App/Updater.cs similarity index 76% rename from PCK-Studio/Internal/App/Updater.cs rename to PckStudio.Core/App/Updater.cs index 13ab8a6b..c3fb3a9b 100644 --- a/PCK-Studio/Internal/App/Updater.cs +++ b/PckStudio.Core/App/Updater.cs @@ -3,18 +3,19 @@ using System.IO; using System.Windows.Forms; using AutoUpdaterDotNET; using Newtonsoft.Json; -using PckStudio.Internal.Json; -using PckStudio.Properties; +using PckStudio.Core.Json; -namespace PckStudio.Internal.App +namespace PckStudio.Core.App { - internal static class Updater + public static class Updater { private static Uri _appCast; + private static bool _autoUpdate; - internal static void Initialize(Uri appCast) + public static void Initialize(Uri appCast, bool autoUpdate = false) { _appCast = appCast; + _autoUpdate = autoUpdate; //AutoUpdater.ClearAppDirectory = true; #if DEBUG AutoUpdater.ReportErrors = true; @@ -26,17 +27,17 @@ namespace PckStudio.Internal.App string jsonPath = Path.Combine(Environment.CurrentDirectory, "updates.json"); AutoUpdater.PersistenceProvider = new JsonFilePersistenceProvider(jsonPath); AutoUpdater.ParseUpdateInfoEvent += AutoUpdaterOnParseUpdateInfoEvent; - AutoUpdater.Icon = Resources.ProjectLogo.ToBitmap(); + //AutoUpdater.Icon = Resources.ProjectLogo.ToBitmap(); - if (Settings.Default.AutoUpdate) + if (_autoUpdate) { UpdateToLatest(); } } - internal static void SetOwner(Form owner) => AutoUpdater.SetOwner(owner); + public static void SetOwner(Form owner) => AutoUpdater.SetOwner(owner); - internal static void UpdateToLatest() + public static void UpdateToLatest() { #if NDEBUG string url = $"{_appCast}/main/Version.json"; diff --git a/PckStudio.Core/Atlas.cs b/PckStudio.Core/Atlas.cs new file mode 100644 index 00000000..d30f19b0 --- /dev/null +++ b/PckStudio.Core/Atlas.cs @@ -0,0 +1,231 @@ +/* Copyright (c) 2025-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.Drawing; +using System.Linq; +using PckStudio.Core.Extensions; + +namespace PckStudio.Core +{ + public sealed class Atlas + { + public string Name { get; set; } + public int Rows { get; } + public int Columns { get; } + + public Size TileSize { get; } + public int TileCount => _tiles.Length; + + private readonly AtlasTile[] _tiles; + private readonly ImageLayoutDirection _layoutDirection; + private readonly List _groups; + + public static implicit operator Image(Atlas atlas) => atlas.BuildFinalImage(); + + private Atlas(string name, int rows, int columns) + { + Name = name; + Rows = rows; + Columns = columns; + _tiles = new AtlasTile[rows * columns]; + _groups = new List(); + } + + private Atlas(string name, int rows, int columns, IEnumerable tiles, Size tileSize, ImageLayoutDirection layoutDirection) + : this(name, rows, columns) + { + _tiles = tiles.Take(rows * columns).ToArray(); + TileSize = tileSize; + _layoutDirection = layoutDirection; + } + + public static Atlas FromResourceLocation(Image source, ResourceLocation resourceLocation, ImageLayoutDirection imageLayout = default) + { + Json.JsonTileInfo[] tilesInfo = resourceLocation.TilesInfo.ToArray(); + Size tileArea = resourceLocation.GetTileArea(source.Size); + int rows = source.Width / tileArea.Width; + int columns = source.Height / tileArea.Height; + IEnumerable tiles = source.Split(tileArea, imageLayout).enumerate().Select(((int index, Image img) data) => new AtlasTile(data.img, GetSelectedPoint(data.index, out int col, rows, columns, imageLayout), col, index: data.index, userData: tilesInfo.IndexInRange(data.index) ? tilesInfo[data.index] : default)); + var atlas = new Atlas(resourceLocation.Path, rows, columns, tiles, tileArea, imageLayout); + atlas.AddGroups(resourceLocation.AtlasGroups); + return atlas; + } + + private static int GetSelectedPoint(int index, out int col, int rows, int columns, ImageLayoutDirection layoutDirection) + { + int y = Math.DivRem(index, rows, out int x); + if (layoutDirection == ImageLayoutDirection.Vertical) + x = Math.DivRem(index, columns, out y); + col = y; + return x; + } + + public void AddGroups(IEnumerable groups) + { + foreach (AtlasGroup group in groups) + { + AddGroup(group); + } + } + + public AtlasTile this[int row, int col] + { + get => this[(col * Rows) + row]; + set => this[(col * Rows) + row] = value; + } + + public AtlasTile this[int index] + { + get => _tiles.IndexInRange(index) ? _tiles[index] : throw new IndexOutOfRangeException(index.ToString()); + set + { + if (_tiles.IndexInRange(index)) + _tiles[index] = value; + } + } + + public IEnumerable GetRange(int row, int col, int count, ImageLayoutDirection direction) + { + return GetRange(row, col, direction == ImageLayoutDirection.Horizontal ? count : 1, direction == ImageLayoutDirection.Vertical ? count : 1); + } + + public IEnumerable GetRange(int row, int col, int rowCount, int columnCount) + { + for (int j = 0; j < columnCount; j++) + { + for (int i = 0; i < rowCount; i++) + { + if ((row + i) < Rows && (col + j) < Columns) + { + yield return this[row + i, col + j]; + } + } + } + yield break; + } + + private void SetRange(int row, int col, int count, ImageLayoutDirection direction, IEnumerable tiles) + => SetRange(row, col, direction == ImageLayoutDirection.Horizontal ? count : 1, direction == ImageLayoutDirection.Vertical ? count : 1, tiles); + private void SetRange(int row, int col, int rowCount, int columnCount, IEnumerable tiles) + { + Image[] atlasTiles = tiles.ToArray(); + for (int j = 0; j < columnCount; j++) + { + for (int i = 0; i < rowCount; i++) + { + if ((row + i) < Rows && (col + j) < Columns) + { + this[row + i, col + j].Texture = atlasTiles[(j * rowCount) + i]; + } + } + } + } + + private int AddGroup(AtlasGroup group) + { + IEnumerable tiles = InternalGetTilesFromGroup(group, out int _, out _); + foreach (AtlasTile tile in tiles) + { + tile.SetGroup(group); + } + int groupId = _groups.Count; + _groups.Add(group); + return groupId; + } + + + public Animation GetAnimationFromGroup(AtlasGroup group) + { + if (!group.IsAnimation()) + return Animation.CreateEmpty(); + if (group is AtlasGroupLargeTileAnimation largeTileAnimation) + return GetLargeAnimation(largeTileAnimation); + return GetAnimation(group as AtlasGroupAnimation); + } + + private Animation GetLargeAnimation(AtlasGroupLargeTileAnimation group) + { + return new Animation(GetLargeAnimationTiles(group).Select(largeTileParts => largeTileParts.Select(t => t.Texture).Combine(group.RowSpan, group.ColumnSpan, _layoutDirection)), true, group.FrameTime); + } + + private IEnumerable> GetLargeAnimationTiles(AtlasGroupLargeTileAnimation group) => group.GetLargeTiles().Select(GetLargeTile); + + private Animation GetAnimation(AtlasGroupAnimation groupAnimation) => new Animation(GetRange(groupAnimation.Row, groupAnimation.Column, groupAnimation.Direction == ImageLayoutDirection.Horizontal ? groupAnimation.Count : 1, groupAnimation.Direction == ImageLayoutDirection.Vertical ? groupAnimation.Count : 1).Select(t => t.Texture), true, groupAnimation.FrameTime); + + private Image BuildFinalImage() => _tiles.Select(t => t.Texture).Combine(Rows, Columns, _layoutDirection); + + public IReadOnlyCollection GetTiles() => _tiles; + + public void SetGroupTilesFromAnimation(AtlasGroup group, Animation animation) + { + SetRange(group.Row, group.Column, group.Count, group.Direction, animation.GetFrames().Select(f => f.Texture)); + } + + private IEnumerable GetLargeTile(AtlasGroupLargeTile group) => GetRange(group.Row, group.Column, group.RowSpan, group.ColumnSpan); + + public Image GetTileTexture(AtlasTile tile) + { + if (!tile.IsPartOfGroup) + return tile; + AtlasGroup atlasGroup = tile.GetGroup(); + + if (!atlasGroup.IsLargeTile()) + return tile; + + AtlasGroupLargeTile largeTile = atlasGroup is AtlasGroupLargeTileAnimation largeTileAnimation ? largeTileAnimation.GetTile(tile.Row, tile.Column) : atlasGroup as AtlasGroupLargeTile; + return GetLargeTile(largeTile).Select(t => t.Texture).Combine(largeTile.RowSpan, largeTile.ColumnSpan, _layoutDirection); + } + + private IEnumerable InternalGetTilesFromGroup(AtlasGroup atlasGroup, out int rowSpan, out int columnSpan) + { + if (atlasGroup is AtlasGroupLargeTileAnimation largeTileAnimation) + { + rowSpan = largeTileAnimation.RowSpan; + columnSpan = largeTileAnimation.ColumnSpan; + return largeTileAnimation.GetLargeTiles().SelectMany(GetLargeTile); + } + if (atlasGroup is AtlasGroupLargeTile largeTile) + { + rowSpan = largeTile.RowSpan; + columnSpan = largeTile.ColumnSpan; + return GetLargeTile(largeTile); + } + rowSpan = 1; + columnSpan = 1; + return GetRange(atlasGroup.Row, atlasGroup.Column, atlasGroup.Count, atlasGroup.Direction); + } + + public Rectangle GetTileArea(AtlasTile tile) + { + if (!tile.IsPartOfGroup) + return tile.GetArea(TileSize); + AtlasGroup group = tile.GetGroup(); + return new Rectangle(new Point(group.Row * TileSize.Width, group.Column * TileSize.Height), group.GetSize(TileSize)); + } + + public void SetGroup(AtlasGroup group, Image texture) + { + IEnumerable images = texture.Split(TileSize, group.Direction); + if (!images.All(img => img.Size == TileSize)) + return; + Size s = group.GetSize(new Size(1, 1)); + SetRange(group.Row, group.Column, s.Width, s.Height, images); + } + } +} \ No newline at end of file diff --git a/PckStudio.Core/AtlasGroup.cs b/PckStudio.Core/AtlasGroup.cs new file mode 100644 index 00000000..3b2a53f0 --- /dev/null +++ b/PckStudio.Core/AtlasGroup.cs @@ -0,0 +1,48 @@ +/* Copyright (c) 2025-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.Drawing; + +namespace PckStudio.Core +{ + public abstract class AtlasGroup + { + public string Name { get; set; } + public int Row { get; } + public int Column { get; } + + public virtual int Count => 1; + + protected abstract bool isAnimation { get; } + protected abstract bool isLargeTile { get; } + public virtual ImageLayoutDirection Direction => Column > Row ? ImageLayoutDirection.Vertical : ImageLayoutDirection.Horizontal; + + public AtlasGroup(string name, int row, int column) + { + Name = name; + Row = Math.Max(0, row); + Column = Math.Max(0, column); + } + + public bool IsAnimation() => isAnimation; + public bool IsLargeTile() => isLargeTile; + + public abstract Size GetSize(Size tileSize); + + } +} \ No newline at end of file diff --git a/PckStudio.Core/AtlasGroupAnimation.cs b/PckStudio.Core/AtlasGroupAnimation.cs new file mode 100644 index 00000000..aa3e6883 --- /dev/null +++ b/PckStudio.Core/AtlasGroupAnimation.cs @@ -0,0 +1,42 @@ +/* Copyright (c) 2025-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.Drawing; + +namespace PckStudio.Core +{ + internal sealed class AtlasGroupAnimation : AtlasGroup + { + public int FrameTime { get; } + public override int Count { get; } + public override ImageLayoutDirection Direction { get; } + + protected override bool isAnimation => true; + + protected override bool isLargeTile => false; + + public override Size GetSize(Size tileSize) => new Size(tileSize.Width * (Direction == ImageLayoutDirection.Horizontal ? Count : 1), tileSize.Height * (Direction == ImageLayoutDirection.Vertical ? Count : 1)); + + public AtlasGroupAnimation(string name, int row, int column, int frameCount, ImageLayoutDirection direction, int frameTime = Animation.MinimumFrameTime) + : base(name, row, column) + { + Count = frameCount; + Direction = direction; + FrameTime = frameTime; + } + } +} \ No newline at end of file diff --git a/PckStudio.Core/AtlasGroupLargeTile.cs b/PckStudio.Core/AtlasGroupLargeTile.cs new file mode 100644 index 00000000..7475cf4f --- /dev/null +++ b/PckStudio.Core/AtlasGroupLargeTile.cs @@ -0,0 +1,43 @@ +/* Copyright (c) 2025-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.Drawing; + +namespace PckStudio.Core +{ + internal sealed class AtlasGroupLargeTile : AtlasGroup + { + public int RowSpan { get; } + public int ColumnSpan { get; } + + public override int Count => RowSpan * ColumnSpan; + + protected override bool isAnimation => false; + + protected override bool isLargeTile => true; + + public override Size GetSize(Size tileSize) => new Size(RowSpan * tileSize.Width, ColumnSpan * tileSize.Height); + + public AtlasGroupLargeTile(string name, int row, int column, int rowSpan, int columnSpan) + : base(name, row, column) + { + RowSpan = Math.Max(1, rowSpan); + ColumnSpan = Math.Max(1, columnSpan); + } + } +} \ No newline at end of file diff --git a/PckStudio.Core/AtlasGroupLargeTileAnimation.cs b/PckStudio.Core/AtlasGroupLargeTileAnimation.cs new file mode 100644 index 00000000..4efdb43e --- /dev/null +++ b/PckStudio.Core/AtlasGroupLargeTileAnimation.cs @@ -0,0 +1,79 @@ +/* Copyright (c) 2025-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.Drawing; +using System.Linq; + +namespace PckStudio.Core +{ + internal sealed class AtlasGroupLargeTileAnimation : AtlasGroup + { + private AtlasGroupLargeTile[] _largeTiles; + private int _frameCount; + + public int RowSpan { get; } + public int ColumnSpan { get; } + public int FrameTime { get; } + + public override int Count => RowSpan * ColumnSpan * _frameCount; + + public override ImageLayoutDirection Direction { get; } + + protected override bool isAnimation => true; + + protected override bool isLargeTile => true; + + public override Size GetSize(Size tileSize) => new Size(RowSpan * tileSize.Width * (Direction == ImageLayoutDirection.Horizontal ? _frameCount : 1), ColumnSpan * tileSize.Height * (Direction == ImageLayoutDirection.Vertical ? _frameCount : 1)); + + public AtlasGroupLargeTileAnimation(string name, int row, int column, int rowSpan, int columnSpan, int frameCount, ImageLayoutDirection direction, int frameTime = Animation.MinimumFrameTime) + : base(name, row, column) + { + _frameCount = Math.Abs(frameCount); + RowSpan = Math.Max(1, rowSpan); + ColumnSpan = Math.Max(1, columnSpan); + Direction = direction; + FrameTime = frameTime; + _largeTiles = InternalGetLargeTiles().ToArray(); + } + + private IEnumerable InternalGetLargeTiles() + { + for (int i = 0; i < _frameCount; i++) + { + yield return new AtlasGroupLargeTile($"{Name}_{i}", Row + (Direction == ImageLayoutDirection.Horizontal ? i * RowSpan : 0), Column + (Direction == ImageLayoutDirection.Vertical ? i * ColumnSpan : 0), RowSpan, ColumnSpan); + } + yield break; + } + + internal AtlasGroupLargeTile GetTile(int row, int col) + { + if (!IsInRange(row, col)) + return default; + int i = (Direction == ImageLayoutDirection.Horizontal) ? Math.DivRem((row - Row), RowSpan, out _) : Math.DivRem((col - Column), ColumnSpan, out _); + return (i >= 0 && i < _frameCount) ? _largeTiles[i] : _largeTiles[0]; + } + + private bool IsInRange(int row, int col) + { + return Row <= row && row < (Row + (RowSpan * (Direction == ImageLayoutDirection.Horizontal ? _frameCount : 1))) && Column <= col && col < (Column + (ColumnSpan * (Direction == ImageLayoutDirection.Horizontal ? _frameCount : 1))); + } + + internal IEnumerable GetLargeTiles() => _largeTiles; + } +} \ No newline at end of file diff --git a/PckStudio.Core/AtlasTile.cs b/PckStudio.Core/AtlasTile.cs new file mode 100644 index 00000000..093978c8 --- /dev/null +++ b/PckStudio.Core/AtlasTile.cs @@ -0,0 +1,71 @@ +/* Copyright (c) 2025-present miku-666, MattNL + * 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.Drawing; + +namespace PckStudio.Core +{ + public sealed class AtlasTile + { + public int Index { get; } + public int Row { get; } + public int Column { get; } + public object UserData; + private Image texture; + public bool IsPartOfGroup => _group != null; + + public Image Texture { get => texture; set => texture = value; } + + private AtlasGroup _group; + + public AtlasTile(Image texture, int row, int column, int index, object userData) + { + Texture = texture; + Row = row; + Column = column; + Index = index; + UserData = userData; + } + + internal void SetGroup(AtlasGroup group) + { + _group = group; + } + + public AtlasGroup GetGroup() => _group; + + public Rectangle GetArea(Size tileSize) => new Rectangle(new Point(Row * tileSize.Width, Column * tileSize.Height), tileSize); + + public static implicit operator Image(AtlasTile tile) => tile.Texture; + + public bool IsUserDataOfType() where T : class => UserData is T _; + + public T GetUserDataOfType() where T : class => UserData as T; + + public bool TryGetUserDataOfType(out T value) where T : class + { + if (UserData is T val) + { + value = val; + return true; + } + value = default; + return false; + } + } +} \ No newline at end of file diff --git a/PckStudio.Core/BoundingBox.cs b/PckStudio.Core/BoundingBox.cs new file mode 100644 index 00000000..26fc1658 --- /dev/null +++ b/PckStudio.Core/BoundingBox.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using PckStudio.Core.Extensions; + +namespace PckStudio.Core +{ + public struct BoundingBox + { + public static BoundingBox Empty = new BoundingBox(OpenTK.Vector3.Zero, OpenTK.Vector3.Zero); + + public readonly OpenTK.Vector3 Start; + public readonly OpenTK.Vector3 End; + public readonly OpenTK.Vector3 Center; + public readonly OpenTK.Vector3 Volume; + + public BoundingBox(OpenTK.Vector3 start, OpenTK.Vector3 end) + { + Start = start; + End = end; + OpenTK.Vector3 size = End - Start; + Volume = OpenTKExtensions.Abs(size); + Center = start + Volume / 2; + } + + public BoundingBox(System.Numerics.Vector3 start, System.Numerics.Vector3 end) + : this(start.ToOpenTKVector(), end.ToOpenTKVector()) + { + } + + public OpenTK.Matrix4 GetTransform() + { + return OpenTK.Matrix4.CreateScale(Volume) * OpenTK.Matrix4.CreateTranslation(Start); + } + } +} diff --git a/PckStudio.Core/DelegatedFileSaveContext.cs b/PckStudio.Core/DelegatedFileSaveContext.cs new file mode 100644 index 00000000..98f78cd6 --- /dev/null +++ b/PckStudio.Core/DelegatedFileSaveContext.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Newtonsoft.Json.Linq; +using PckStudio.Interfaces; +using PckStudio.Core; + +namespace PckStudio.Core +{ + public sealed class DelegatedFileSaveContext : ISaveContext + { + public delegate void SerializeDataToStreamDelegate(T value, Stream stream); + + public bool AutoSave { get; } + public string Filepath { get; private set; } + private SerializeDataToStreamDelegate _serializeDataDelegate; + private FileDialogFilter _dialogFilter; + + public DelegatedFileSaveContext(string filepath, bool autoSave, FileDialogFilter dialogFilter, SerializeDataToStreamDelegate serializeDataDelegate) + { + AutoSave = autoSave; + Filepath = filepath; + _serializeDataDelegate = serializeDataDelegate; + _dialogFilter = dialogFilter; + } + + public void Save(T value) + { + if (!File.Exists(Filepath)) + { + SaveFileDialog saveFileDialog = new SaveFileDialog(); + saveFileDialog.Filter = _dialogFilter.ToString(); + if (saveFileDialog.ShowDialog() != DialogResult.OK) + return; + Filepath = saveFileDialog.FileName; + } + using (Stream stream = File.OpenWrite(Filepath)) + { + _serializeDataDelegate(value, stream); + } + } + } +} diff --git a/PckStudio.Core/DelegatedSaveContext.cs b/PckStudio.Core/DelegatedSaveContext.cs new file mode 100644 index 00000000..ee49b877 --- /dev/null +++ b/PckStudio.Core/DelegatedSaveContext.cs @@ -0,0 +1,19 @@ +using System; +using PckStudio.Interfaces; + +namespace PckStudio.Core +{ + public class DelegatedSaveContext : ISaveContext + { + private readonly Action _saveAction; + public bool AutoSave { get; } + + public void Save(T value) => _saveAction(value); + + public DelegatedSaveContext(bool autoSave, Action saveAction) + { + AutoSave = autoSave; + _saveAction = saveAction; + } + } +} \ No newline at end of file diff --git a/PCK-Studio/Internal/Deserializer/AnimationDeserializer.cs b/PckStudio.Core/Deserializer/AnimationDeserializer.cs similarity index 96% rename from PCK-Studio/Internal/Deserializer/AnimationDeserializer.cs rename to PckStudio.Core/Deserializer/AnimationDeserializer.cs index 9a0bc124..3d112032 100644 --- a/PCK-Studio/Internal/Deserializer/AnimationDeserializer.cs +++ b/PckStudio.Core/Deserializer/AnimationDeserializer.cs @@ -7,12 +7,13 @@ using System.Text; using System.Threading.Tasks; using Newtonsoft.Json.Linq; using OMI.Formats.Pck; -using PckStudio.Extensions; +using PckStudio.Core; +using PckStudio.Core.Extensions; using PckStudio.Interfaces; -namespace PckStudio.Internal.Deserializer +namespace PckStudio.Core.Deserializer { - internal sealed class AnimationDeserializer : IPckAssetDeserializer + public sealed class AnimationDeserializer : IPckAssetDeserializer { public static readonly AnimationDeserializer DefaultDeserializer = new AnimationDeserializer(); diff --git a/PckStudio.Core/Deserializer/AtlasDeserializer.cs b/PckStudio.Core/Deserializer/AtlasDeserializer.cs new file mode 100644 index 00000000..52394d69 --- /dev/null +++ b/PckStudio.Core/Deserializer/AtlasDeserializer.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OMI.Formats.Pck; +using PckStudio.Core.Extensions; +using PckStudio.Interfaces; + +namespace PckStudio.Core.Deserializer +{ + public sealed class AtlasDeserializer : IPckAssetDeserializer + { + private readonly ResourceLocation _resourceLocation; + + public AtlasDeserializer(ResourceLocation resourceLocation) + { + _resourceLocation = resourceLocation; + } + + public Atlas Deserialize(PckAsset asset) => Atlas.FromResourceLocation(asset.GetTexture(), _resourceLocation); + } +} diff --git a/PCK-Studio/Internal/Deserializer/ImageDeserializer.cs b/PckStudio.Core/Deserializer/ImageDeserializer.cs similarity index 52% rename from PCK-Studio/Internal/Deserializer/ImageDeserializer.cs rename to PckStudio.Core/Deserializer/ImageDeserializer.cs index 09d27721..bc365d7c 100644 --- a/PCK-Studio/Internal/Deserializer/ImageDeserializer.cs +++ b/PckStudio.Core/Deserializer/ImageDeserializer.cs @@ -1,17 +1,12 @@ using System; -using System.Collections.Generic; -using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using OMI.Formats.Pck; using PckStudio.Interfaces; -using PckStudio.Internal.IO.TGA; +using PckStudio.Core.IO.TGA; -namespace PckStudio.Internal.Deserializer +namespace PckStudio.Core.Deserializer { internal sealed class ImageDeserializer : IPckAssetDeserializer { @@ -26,19 +21,11 @@ namespace PckStudio.Internal.Deserializer return EmptyImage; using var stream = new MemoryStream(asset.Data); - try - { - if (Path.GetExtension(asset.Filename) == ".tga") - return TGADeserializer.DeserializeFromStream(stream); - else - return Image.FromStream(stream); - } - catch (Exception ex) - { - Trace.TraceError($"Failed to read image from pck file data({asset.Filename})."); - Debug.WriteLine(ex.Message); - return EmptyImage; - } + + Image img = Path.GetExtension(asset.Filename) == ".tga" + ? TGADeserializer.DeserializeFromStream(stream) + : Image.FromStream(stream); + return img.RawFormat != ImageFormat.Jpeg || img.RawFormat != ImageFormat.Png ? new Bitmap(img) : img; } } } diff --git a/PckStudio.Core/Extensions/AnimationExtensions.cs b/PckStudio.Core/Extensions/AnimationExtensions.cs new file mode 100644 index 00000000..fc80a08c --- /dev/null +++ b/PckStudio.Core/Extensions/AnimationExtensions.cs @@ -0,0 +1,27 @@ +using System.Drawing; +using AnimatedGif; + +namespace PckStudio.Core.Extensions +{ + public static class AnimationExtensions + { + public static Image CreateAnimationImage(this Animation animation) => animation.CreateAnimationImage(Color.Black); + + public static Image CreateAnimationImage(this Animation animation, Color blendColor) + { + if (animation.FrameCount == 0) + { + return null; + } + var ms = new System.IO.MemoryStream(); + var generateor = new AnimatedGifCreator(ms, GameConstants.GameTickInMilliseconds, 0); + foreach (Animation.Frame frame in animation.GetInterpolatedFrames()) + { + Image texture = (blendColor == Color.Black || blendColor == Color.White) ? frame.Texture : frame.Texture.Blend(blendColor, BlendMode.Multiply); + generateor.AddFrame(texture, frame.Ticks * GameConstants.GameTickInMilliseconds, GifQuality.Bit8); + } + ms.Position = 0; + return Image.FromStream(ms); + } + } +} diff --git a/PCK-Studio/Extensions/BlendMode.cs b/PckStudio.Core/Extensions/BlendMode.cs similarity index 70% rename from PCK-Studio/Extensions/BlendMode.cs rename to PckStudio.Core/Extensions/BlendMode.cs index 76709d50..05f77f27 100644 --- a/PCK-Studio/Extensions/BlendMode.cs +++ b/PckStudio.Core/Extensions/BlendMode.cs @@ -1,6 +1,6 @@ -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { - internal enum BlendMode + public enum BlendMode { Add, Subtract, diff --git a/PckStudio.Core/Extensions/BoundingBoxExtensions.cs b/PckStudio.Core/Extensions/BoundingBoxExtensions.cs new file mode 100644 index 00000000..ccb873d3 --- /dev/null +++ b/PckStudio.Core/Extensions/BoundingBoxExtensions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PckStudio.Core.Extensions +{ + public static class BoundingBoxExtensions + { + public static BoundingBox GetEnclosingBoundingBox(this IEnumerable boundingBoxes) + { + return boundingBoxes.DefaultIfEmpty().Aggregate((a, b) => new BoundingBox(OpenTK.Vector3.ComponentMin(a.Start, b.Start), OpenTK.Vector3.ComponentMax(a.End, b.End))); + } + } +} diff --git a/PCK-Studio/Extensions/ColorExtensions.cs b/PckStudio.Core/Extensions/ColorExtensions.cs similarity index 66% rename from PCK-Studio/Extensions/ColorExtensions.cs rename to PckStudio.Core/Extensions/ColorExtensions.cs index b11c0d5e..4a64fa9e 100644 --- a/PCK-Studio/Extensions/ColorExtensions.cs +++ b/PckStudio.Core/Extensions/ColorExtensions.cs @@ -1,30 +1,41 @@ using System.Drawing; using System.Numerics; -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { - internal static class ColorExtensions + public static class ColorExtensions { /// /// Normalizes the Color between 0.0 - 1.0 /// /// - internal static Vector4 Normalize(this Color color) + public static Vector4 Normalize(this Color color) { return new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f); } - internal static int ToBGR(this Color color) + public static Color Inversed(this Color color) + { + return Color.FromArgb(color.A, 255 - color.R, 255 - color.G, 255 - color.B); + } + + public static Color GreyScaled(this Color color) + { + int greyScaleValue = (color.R + color.G + color.B) / 3; + return Color.FromArgb(color.A, greyScaleValue, greyScaleValue, greyScaleValue); + } + + public static int ToBGR(this Color color) { return color.B << 16 | color.G << 8 | color.R; } - internal static byte BlendValues(byte source, byte overlay, BlendMode blendType) + public static byte BlendValues(byte source, byte overlay, BlendMode blendType) { return (byte)MathExtensions.Clamp(BlendValues(source / 255f, overlay / 255f, blendType) * 255, 0, 255); } - internal static float BlendValues(float source, float overlay, BlendMode blendType) + public static float BlendValues(float source, float overlay, BlendMode blendType) { source = MathExtensions.Clamp(source, 0.0f, 1.0f); overlay = MathExtensions.Clamp(overlay, 0.0f, 1.0f); @@ -43,13 +54,13 @@ namespace PckStudio.Extensions return MathExtensions.Clamp(resultValue, 0.0f, 1.0f); } - internal static byte Mix(double ratio, byte val1, byte val2) + public static byte Mix(double ratio, byte val1, byte val2) { ratio = MathExtensions.Clamp(ratio, 0.0, 1.0); return (byte)(ratio * val1 + (1.0 - ratio) * val2); } - internal static Color Mix(this Color c1, Color c2, double ratio) + public static Color Mix(this Color c1, Color c2, double ratio) { ratio = MathExtensions.Clamp(ratio, 0.0, 1.0); return Color.FromArgb(c1.A, diff --git a/PckStudio.Core/Extensions/CursorExtensions.cs b/PckStudio.Core/Extensions/CursorExtensions.cs new file mode 100644 index 00000000..dc897ac2 --- /dev/null +++ b/PckStudio.Core/Extensions/CursorExtensions.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace PckStudio.Core.Extensions +{ + public static class CursorExtensions + { + + [StructLayout(LayoutKind.Sequential)] + struct PointStruct + { + public Int32 x; + public Int32 y; + } + + [StructLayout(LayoutKind.Sequential)] + struct CursorInfoStruct + { + /// The structure size in bytes that must be set via calling Marshal.SizeOf(typeof(CursorInfoStruct)). + public Int32 cbSize; + /// The cursor state: 0 == hidden, 1 == showing, 2 == suppressed (is supposed to be when finger touch is used, but in practice finger touch results in 0, not 2) + public Int32 flags; + /// A handle to the cursor. + public IntPtr hCursor; + /// The cursor screen coordinates. + public PointStruct pt; + } + + /// Must initialize cbSize + [DllImport("user32.dll")] + static extern bool GetCursorInfo(ref CursorInfoStruct pci); + + public static bool IsVisible(this Cursor _) + { + CursorInfoStruct pci = new CursorInfoStruct(); + pci.cbSize = Marshal.SizeOf(typeof(CursorInfoStruct)); + GetCursorInfo(ref pci); + // const Int32 hidden = 0x00; + const Int32 showing = 0x01; + // const Int32 suppressed = 0x02; + bool isVisible = ((pci.flags & showing) != 0); + return isVisible; + } + + } +} diff --git a/PCK-Studio/Extensions/EnumerableExtensions.cs b/PckStudio.Core/Extensions/EnumerableExtensions.cs similarity index 91% rename from PCK-Studio/Extensions/EnumerableExtensions.cs rename to PckStudio.Core/Extensions/EnumerableExtensions.cs index 9ad08c8f..266c5317 100644 --- a/PCK-Studio/Extensions/EnumerableExtensions.cs +++ b/PckStudio.Core/Extensions/EnumerableExtensions.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Linq; -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { - internal static class EnumerableExtensions + public static class EnumerableExtensions { public static IEnumerable<(int index, T value)>enumerate(this IEnumerable array) { diff --git a/PCK-Studio/Extensions/GraphicsExtensions.cs b/PckStudio.Core/Extensions/GraphicsExtensions.cs similarity index 86% rename from PCK-Studio/Extensions/GraphicsExtensions.cs rename to PckStudio.Core/Extensions/GraphicsExtensions.cs index 2cc33088..48dd3fea 100644 --- a/PCK-Studio/Extensions/GraphicsExtensions.cs +++ b/PckStudio.Core/Extensions/GraphicsExtensions.cs @@ -1,9 +1,9 @@ using System.Drawing; using System.Drawing.Drawing2D; -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { - internal struct GraphicsConfig + public struct GraphicsConfig { public GraphicsConfig() { @@ -21,7 +21,7 @@ namespace PckStudio.Extensions public PixelOffsetMode PixelOffsetMode { get; set; } } - internal static class GraphicsExtensions + public static class GraphicsExtensions { public static void ApplyConfig(this Graphics graphics, GraphicsConfig config) { @@ -32,7 +32,7 @@ namespace PckStudio.Extensions graphics.PixelOffsetMode = config.PixelOffsetMode; } - internal static Graphics Fill(this Graphics graphics, Rectangle area, Color color) + public static Graphics Fill(this Graphics graphics, Rectangle area, Color color) { Region clip = graphics.Clip; graphics.SetClip(area, CombineMode.Replace); diff --git a/PCK-Studio/Extensions/ImageExtensions.cs b/PckStudio.Core/Extensions/ImageExtensions.cs similarity index 77% rename from PCK-Studio/Extensions/ImageExtensions.cs rename to PckStudio.Core/Extensions/ImageExtensions.cs index dd9ca899..a958c1e0 100644 --- a/PCK-Studio/Extensions/ImageExtensions.cs +++ b/PckStudio.Core/Extensions/ImageExtensions.cs @@ -16,22 +16,29 @@ * 3. This notice may not be removed or altered from any source distribution. **/ using System; -using System.Drawing; -using System.Diagnostics; -using System.Drawing.Imaging; -using System.Drawing.Drawing2D; using System.Collections.Generic; -using System.Runtime.InteropServices; +using System.Data.Common; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; using System.Linq; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Threading.Tasks; -using PckStudio.Internal.App; -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { - internal static class ImageExtensions + public static class ImageExtensions { - internal static Image GetArea(this Image source, Rectangle area) + public static Image ReleaseFromFile(this Image image) + { + Image img = new Bitmap(image); + image.Dispose(); + return img; + } + + public static Image GetArea(this Image source, Rectangle area) { Image tileImage = new Bitmap(area.Width, area.Height); using (Graphics gfx = Graphics.FromImage(tileImage)) @@ -50,33 +57,34 @@ namespace PckStudio.Extensions /// this image /// Indecates width and height of image sub section /// of type - internal static IEnumerable SplitHorizontal(this Image source, int scalar) + public static IEnumerable SplitHorizontal(this Image source, int scalar) { return source.Split(scalar, ImageLayoutDirection.Horizontal); } - internal static IEnumerable Split(this Image source, int scalar, ImageLayoutDirection layoutDirection) + public static IEnumerable Split(this Image source, int scalar, ImageLayoutDirection layoutDirection) { return Split(source, new Size(scalar, scalar), layoutDirection); } - internal static IEnumerable Split(this Image source, Size size, ImageLayoutDirection imageLayout) + public static IEnumerable Split(this Image source, Size size, ImageLayoutDirection imageLayout) { int rowCount = source.Width / size.Width; int columnCount = source.Height / size.Height; Debug.WriteLine($"Image size: {source.Size}, Area size: {size}, col num: {columnCount}, row num: {rowCount}"); + bool vertical = imageLayout == ImageLayoutDirection.Vertical; for (int i = 0; i < columnCount * rowCount; i++) { - int row = Math.DivRem(i, rowCount, out int column); - if (imageLayout == ImageLayoutDirection.Vertical) - column = Math.DivRem(i, columnCount, out row); - Rectangle tileArea = new Rectangle(new Point(column * size.Width, row * size.Height), size); + int column = Math.DivRem(i, rowCount, out int row); + if (vertical) + row = Math.DivRem(i, columnCount, out column); + Rectangle tileArea = new Rectangle(new Point(row * size.Width, column * size.Height), size); yield return source.GetArea(tileArea); } yield break; } - internal static IEnumerable Split(this Image source, ImageLayoutDirection layoutDirection) + public static IEnumerable Split(this Image source, ImageLayoutDirection layoutDirection) { for (int i = 0; i < source.Height / source.Width; i++) { @@ -86,49 +94,59 @@ namespace PckStudio.Extensions yield break; } - internal static Image Combine(this IEnumerable sources, ImageLayoutDirection layoutDirection) + public static Image Combine(this IEnumerable sources, ImageLayoutDirection layoutDirection) { - Size imageSize = CalculateImageSize(sources, layoutDirection); + bool horizontal = layoutDirection == ImageLayoutDirection.Horizontal; + int imgCount = sources.Count(); + int rows = horizontal ? imgCount : 1; + int columns = horizontal ? 1 : imgCount; + return sources.Combine(rows, columns, layoutDirection); + } + + public static Image Combine(this IEnumerable sources, int rows, int columns, ImageLayoutDirection layoutDirection) + { + Size imageSize = CalculateImageSize(sources, rows, columns); var image = new Bitmap(imageSize.Width, imageSize.Height); + bool horizontal = layoutDirection == ImageLayoutDirection.Horizontal; using (var graphic = Graphics.FromImage(image)) { foreach ((int i, Image texture) in sources.enumerate()) { - var info = new ImageSection(texture.Size, i, layoutDirection); - graphic.DrawImage(texture, info.Point); + int x = Math.DivRem(i, columns, out int y); + if (horizontal) + y = Math.DivRem(i, rows, out x); + graphic.DrawImage(texture, new Point(x * texture.Width, y * texture.Height)); } } return image; } - private static Size CalculateImageSize(IEnumerable sources, ImageLayoutDirection layoutDirection) + private static Size CalculateImageSize(IEnumerable sources, int rows, int columns) { - Size size = sources.First().Size; - int count = sources.Count(); + if (sources == null) + return Size.Empty; + Image[] imgs = sources.ToArray(); - if (count < 2) - return count < 1 ? Size.Empty : size; + if (imgs.Length < rows * columns) + throw new ArgumentOutOfRangeException("Insufficent soure images provided."); - var horizontal = layoutDirection == ImageLayoutDirection.Horizontal; + Size size = imgs[0].Size; - if (!sources.All(img => img.Size == size)) + if (!imgs.All(img => img.Size == size)) throw new InvalidOperationException("Images must have the same width and height."); - if (horizontal) - size.Width *= count; - else - size.Height *= count; - + size.Width *= rows; + size.Height *= columns; return size; } - internal static Image Resize(this Image image, Size size, GraphicsConfig graphicsConfig) + public static Image Resize(this Image image, Size size, GraphicsConfig graphicsConfig) { return image.Resize(size.Width, size.Height, graphicsConfig); } - internal static Image Resize(this Image image, int width, int height, GraphicsConfig graphicsConfig) + public static Image Resize(this Image image, int width, int height, GraphicsConfig graphicsConfig) { var destRect = new Rectangle(0, 0, width, height); var destImage = new Bitmap(width, height); @@ -147,7 +165,7 @@ namespace PckStudio.Extensions return destImage; } - internal static Image Blend(this Image image, Color overlayColor, BlendMode mode) + public static Image Blend(this Image image, Color overlayColor, BlendMode mode) { if (image is not Bitmap baseImage) return image; @@ -159,7 +177,6 @@ namespace PckStudio.Extensions BitmapData resultImageData = bitmapResult.LockBits(new Rectangle(Point.Empty, bitmapResult.Size), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); - Profiler.Start(); Parallel.For(0, baseImageData.Stride * baseImageData.Height / 4, (i) => { int k = i * 4; @@ -179,14 +196,13 @@ namespace PckStudio.Extensions Unsafe.Write((resultImageData.Scan0 + k).ToPointer(), blendedValue); } }); - Profiler.Stop(); bitmapResult.UnlockBits(resultImageData); baseImage.UnlockBits(baseImageData); return bitmapResult; } - internal static Image Blend(this Image image, Image overlay, BlendMode mode) + public static Image Blend(this Image image, Image overlay, BlendMode mode) { if (image is not Bitmap baseImage || overlay is not Bitmap overlayImage || image.Width != overlay.Width || image.Height != overlay.Height) @@ -223,7 +239,7 @@ namespace PckStudio.Extensions return bitmapResult; } - internal static Image Interpolate(this Image image1, Image image2, double delta) + public static Image Interpolate(this Image image1, Image image2, double delta) { delta = MathExtensions.Clamp(delta, 0.0, 1.0); if (image1 is not Bitmap baseImage || image2 is not Bitmap overlayImage || diff --git a/PckStudio.Core/Extensions/ImageLayoutDirection.cs b/PckStudio.Core/Extensions/ImageLayoutDirection.cs new file mode 100644 index 00000000..92ccdc8b --- /dev/null +++ b/PckStudio.Core/Extensions/ImageLayoutDirection.cs @@ -0,0 +1,8 @@ +namespace PckStudio.Core +{ + public enum ImageLayoutDirection + { + Horizontal, + Vertical + } +} diff --git a/PCK-Studio/Extensions/ImageSection.cs b/PckStudio.Core/Extensions/ImageSection.cs similarity index 96% rename from PCK-Studio/Extensions/ImageSection.cs rename to PckStudio.Core/Extensions/ImageSection.cs index 8e7b36ec..588e9417 100644 --- a/PCK-Studio/Extensions/ImageSection.cs +++ b/PckStudio.Core/Extensions/ImageSection.cs @@ -1,6 +1,6 @@ using System.Drawing; -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { internal struct ImageSection { diff --git a/PCK-Studio/Extensions/ListExtensions.cs b/PckStudio.Core/Extensions/ListExtensions.cs similarity index 85% rename from PCK-Studio/Extensions/ListExtensions.cs rename to PckStudio.Core/Extensions/ListExtensions.cs index 182239fa..6c4481b7 100644 --- a/PCK-Studio/Extensions/ListExtensions.cs +++ b/PckStudio.Core/Extensions/ListExtensions.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { - internal static class ListExtensions + public static class ListExtensions { public static IList Swap(this IList list, int index1, int index2) { diff --git a/PCK-Studio/Extensions/LocFileExtensions.cs b/PckStudio.Core/Extensions/LocFileExtensions.cs similarity index 87% rename from PCK-Studio/Extensions/LocFileExtensions.cs rename to PckStudio.Core/Extensions/LocFileExtensions.cs index 7ce2ecde..709a827c 100644 --- a/PCK-Studio/Extensions/LocFileExtensions.cs +++ b/PckStudio.Core/Extensions/LocFileExtensions.cs @@ -1,8 +1,8 @@ using OMI.Formats.Languages; -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { - internal static class LocFileExtensions + public static class LocFileExtensions { public static void InitializeDefault(this LOCFile locFile, string packName) => locFile.Initialize("en-EN", ("IDS_DISPLAY_NAME", packName)); diff --git a/PCK-Studio/Extensions/MaterialContainerExtensions.cs b/PckStudio.Core/Extensions/MaterialContainerExtensions.cs similarity index 96% rename from PCK-Studio/Extensions/MaterialContainerExtensions.cs rename to PckStudio.Core/Extensions/MaterialContainerExtensions.cs index a4a83581..32df0727 100644 --- a/PCK-Studio/Extensions/MaterialContainerExtensions.cs +++ b/PckStudio.Core/Extensions/MaterialContainerExtensions.cs @@ -1,8 +1,8 @@ using OMI.Formats.Material; -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { - internal static class MaterialContainerExtensions + public static class MaterialContainerExtensions { private static readonly MaterialContainer.Material[] defaultMaterials = [ new MaterialContainer.Material("bat", "entity_alphatest"), diff --git a/PCK-Studio/Extensions/MaterialExtensions.cs b/PckStudio.Core/Extensions/MaterialExtensions.cs similarity index 83% rename from PCK-Studio/Extensions/MaterialExtensions.cs rename to PckStudio.Core/Extensions/MaterialExtensions.cs index 38d2a45d..fe82480d 100644 --- a/PCK-Studio/Extensions/MaterialExtensions.cs +++ b/PckStudio.Core/Extensions/MaterialExtensions.cs @@ -5,9 +5,9 @@ using System.Text; using System.Threading.Tasks; using OMI.Formats.Material; -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { - internal static class MaterialExtensions + public static class MaterialExtensions { public static bool HasInvalidEntries(this MaterialContainer materials) { diff --git a/PCK-Studio/Extensions/MathExtensions.cs b/PckStudio.Core/Extensions/MathExtensions.cs similarity index 59% rename from PCK-Studio/Extensions/MathExtensions.cs rename to PckStudio.Core/Extensions/MathExtensions.cs index 5a162631..38fb5b2b 100644 --- a/PCK-Studio/Extensions/MathExtensions.cs +++ b/PckStudio.Core/Extensions/MathExtensions.cs @@ -1,10 +1,10 @@ using System; -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { - internal class MathExtensions + public class MathExtensions { - internal static T Clamp(T value, T min, T max) where T : IComparable + public static T Clamp(T value, T min, T max) where T : IComparable { if (value.CompareTo(min) < 0) return min; diff --git a/PckStudio.Core/Extensions/ModelBoxExtension.cs b/PckStudio.Core/Extensions/ModelBoxExtension.cs new file mode 100644 index 00000000..a380879e --- /dev/null +++ b/PckStudio.Core/Extensions/ModelBoxExtension.cs @@ -0,0 +1,20 @@ +using System; +using OMI.Formats.Model; +using System.Numerics; + +namespace PckStudio.Core.Extensions +{ + public static class ModelBoxExtension + { + public static BoundingBox GetBoundingBox(this ModelBox modelBox) + { + Vector3 halfSize = modelBox.Size / 2f; + Vector3 halfSizeInflated = new Vector3(modelBox.Inflate) + halfSize; + Vector3 transformedCenter = modelBox.Position + halfSize; + Vector3 start = transformedCenter - halfSizeInflated; + Vector3 end = transformedCenter + halfSizeInflated; + return new BoundingBox(start, end); + } + + } +} diff --git a/PckStudio.Core/Extensions/OpenTKExtensions.cs b/PckStudio.Core/Extensions/OpenTKExtensions.cs new file mode 100644 index 00000000..69fb7243 --- /dev/null +++ b/PckStudio.Core/Extensions/OpenTKExtensions.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK; + +namespace PckStudio.Core.Extensions +{ + public static class OpenTKExtensions + { + public static Matrix4 Pivoted(this Matrix4 rotation, Vector3 pivot) + { + var model = Matrix4.CreateTranslation(pivot); + model *= rotation; + model *= Matrix4.CreateTranslation(pivot).Inverted(); + return model; + } + + public static Vector3 Abs(Vector3 value) + { + return new Vector3(Math.Abs(value.X), Math.Abs(value.Y), Math.Abs(value.Z)); + } + } +} diff --git a/PckStudio.Core/Extensions/PckAssetExtensions.cs b/PckStudio.Core/Extensions/PckAssetExtensions.cs new file mode 100644 index 00000000..bbf72698 --- /dev/null +++ b/PckStudio.Core/Extensions/PckAssetExtensions.cs @@ -0,0 +1,226 @@ +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Drawing; +using System.Diagnostics; +using System.Collections.Generic; + +using OMI.Formats.Languages; +using OMI.Formats.Pck; +using OMI.Workers; + +using PckStudio.Interfaces; +using PckStudio.Core.Deserializer; +using PckStudio.Core.Serializer; +using PckStudio.Core.Skin; + +namespace PckStudio.Core.Extensions +{ + public static class PckAssetExtensions + { + private const string MipMap = "MipMapLevel"; + + public static PckAsset CreateNewAssetIf(this PckFile pck, bool condition, string filename, PckAssetType filetype, IDataFormatWriter writer) + { + if (condition) + { + return pck.CreateNewAsset(filename, filetype, writer); + } + return default; + } + + public static PckAsset CreateNewAsset(this PckFile pck, string filename, PckAssetType filetype, IDataFormatWriter writer) + { + PckAsset asset = pck.CreateNewAsset(filename, filetype); + asset.SetData(writer); + return asset; + } + + public static Image GetTexture(this PckAsset asset) + { + if (asset.Type != PckAssetType.SkinFile && + asset.Type != PckAssetType.CapeFile && + asset.Type != PckAssetType.TextureFile) + { + throw new Exception("Asset is not suitable to contain image data."); + } + return asset.GetDeserializedData(ImageDeserializer.DefaultDeserializer); + } + + /// + /// Tries to get the skin id of the skin + /// + /// + /// Non-zero base number on success, otherwise 0 + /// + public static int GetSkinId(this PckAsset asset) + { + if (asset.Type != PckAssetType.SkinFile) + throw new InvalidOperationException("Asset is not a skin."); + + const string skinAssetnamePrefix = "dlcskin"; + + string assetPath = Path.GetFileNameWithoutExtension(asset.Filename); + if (!assetPath.StartsWith(skinAssetnamePrefix)) + { + Trace.TraceWarning($"[{nameof(GetSkinId)}] Asset name does not start with '{skinAssetnamePrefix}'"); + return 0; + } + + int skinId = 0; + if (!int.TryParse(assetPath.Substring(skinAssetnamePrefix.Length), out skinId)) + { + Trace.TraceWarning($"[{nameof(GetSkinId)}] Failed to parse Skin Id"); + } + return skinId; + } + + public static Skin.Skin GetSkin(this PckAsset asset) + { + if (asset.Type != PckAssetType.SkinFile) + throw new InvalidOperationException("Asset is not a skin."); + + int skinId = asset.GetSkinId(); + + string name = asset.GetProperty("DISPLAYNAME"); + Image texture = asset.GetTexture(); + SkinANIM anim = asset.GetProperty("ANIM", SkinANIM.FromString); + IEnumerable boxes = asset.GetMultipleProperties("BOX").Select(kv => SkinBOX.FromString(kv.Value)); + IEnumerable offsets = asset.GetMultipleProperties("OFFSET").Select(kv => SkinPartOffset.FromString(kv.Value)); + return new Skin.Skin(name, skinId, texture, anim, boxes, offsets); + } + + public static void SetSkin(this PckAsset asset, Skin.Skin skin, LOCFile localizationFile) + { + if (asset.Type != PckAssetType.SkinFile) + throw new InvalidOperationException("Asset is not a skin file"); + + asset.SetTexture(skin.Texture); + + string skinId = skin.Identifier.ToString("d08"); + + // TODO: keep filepath + asset.Filename = $"dlcskin{skinId}.png"; + + asset.SetProperty("DISPLAYNAME", skin.MetaData.Name); + + if (localizationFile is not null) + { + string skinLocKey = $"IDS_dlcskin{skinId}_DISPLAYNAME"; + asset.SetProperty("DISPLAYNAMEID", skinLocKey); + localizationFile.SetLocEntry(skinLocKey, skin.MetaData.Name); + } + + if (!string.IsNullOrEmpty(skin.MetaData.Theme)) + { + asset.SetProperty("THEMENAME", skin.MetaData.Theme); + + if (localizationFile is not null) + { + string skinThemeLocKey = $"IDS_dlcskin{skinId}_THEMENAME"; + asset.SetProperty("THEMENAMEID", skinThemeLocKey); + localizationFile.SetLocEntry(skinThemeLocKey, skin.MetaData.Theme); + } + } + + if (skin.HasCape) + { + asset.SetProperty("CAPEPATH", $"dlccape{skinId}.png"); + } + + asset.SetProperty("ANIM", skin.Anim.ToString()); + asset.SetProperty("GAME_FLAGS", "0x18"); + asset.SetProperty("FREE", "1"); + + asset.RemoveProperties("BOX"); + asset.RemoveProperties("OFFSET"); + + foreach (SkinBOX box in skin.Model.AdditionalBoxes) + { + asset.AddProperty(box.ToProperty()); + } + foreach (SkinPartOffset offset in skin.Model.PartOffsets) + { + asset.AddProperty(offset.ToProperty()); + } + } + + public static T GetDeserializedData(this PckAsset asset, IPckAssetDeserializer deserializer) + { + return deserializer.Deserialize(asset); + } + + public static T GetData(this PckAsset asset, IDataFormatReader formatReader) where T : class + { + using var ms = new MemoryStream(asset.Data); + return formatReader.FromStream(ms); + } + + public static void SetSerializedData(this PckAsset asset, T obj, IPckAssetSerializer serializer) + { + serializer.Serialize(obj, ref asset); + } + + public static void SetData(this PckAsset asset, IDataFormatWriter formatWriter) + { + using (var stream = new MemoryStream()) + { + formatWriter.WriteToStream(stream); + asset.SetData(stream.ToArray()); + } + } + + public static void SetTexture(this PckAsset asset, Image image) + { + if (asset.Type != PckAssetType.SkinFile && + asset.Type != PckAssetType.CapeFile && + asset.Type != PckAssetType.TextureFile) + { + throw new Exception("Asset is not suitable to contain image data."); + } + asset.SetSerializedData(image, ImageSerializer.DefaultSerializer); + } + + public static bool IsMipmappedFile(this PckAsset asset) + { + // We only want to test the file name itself. ex: "terrainMipMapLevel2" + string name = Path.GetFileNameWithoutExtension(asset.Filename); + + // check if last character is a digit (0-9). If not return false + if (!char.IsDigit(name[name.Length - 1])) + return false; + + // If string does not end with MipMapLevel, then it's not MipMapped + if (!name.Remove(name.Length - 1, 1).EndsWith(MipMap)) + return false; + return true; + } + + public static string GetNormalPath(this PckAsset asset) + { + if (!asset.IsMipmappedFile()) + return asset.Filename; + string ext = Path.GetExtension(asset.Filename); + return asset.Filename.Remove(asset.Filename.Length - (MipMap.Length + 1) - ext.Length) + ext; + } + + public static void DeserializeProperties(this PckAsset asset, IEnumerable serializedData) + { + IEnumerable> lines = serializedData + .Select(line => line.Split([' '], 2)) + .Where (keyValue => keyValue.Length == 2) + .Select(keyValue => new KeyValuePair(keyValue[0].Replace(":", ""), keyValue[1])); + foreach (KeyValuePair kv in lines) + { + asset.AddProperty(kv); + } + } + + public static IEnumerable SerializeProperties(this PckAsset asset, string seperater = ":") + { + IReadOnlyList> properties = asset.GetProperties(); + return properties.Select(property => property.Key + seperater + property.Value); + } + } +} diff --git a/PCK-Studio/Extensions/PictureBoxExtensions.cs b/PckStudio.Core/Extensions/PictureBoxExtensions.cs similarity index 89% rename from PCK-Studio/Extensions/PictureBoxExtensions.cs rename to PckStudio.Core/Extensions/PictureBoxExtensions.cs index 75ee7c6c..b3a51d46 100644 --- a/PCK-Studio/Extensions/PictureBoxExtensions.cs +++ b/PckStudio.Core/Extensions/PictureBoxExtensions.cs @@ -2,9 +2,9 @@ using System.Reflection; using System.Windows.Forms; -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { - internal static class PictureBoxExtensions + public static class PictureBoxExtensions { public static bool IsAnimating(this PictureBox pictureBox) { diff --git a/PckStudio.Core/Extensions/SkinBOXExtensions.cs b/PckStudio.Core/Extensions/SkinBOXExtensions.cs new file mode 100644 index 00000000..2c95b2ba --- /dev/null +++ b/PckStudio.Core/Extensions/SkinBOXExtensions.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using PckStudio.Core.Skin; + +namespace PckStudio.Core.Extensions +{ + public static class SkinBOXExtensions + { + public static GraphicsPath GetUVGraphicsPath(this SkinBOX skinBOX, Vector2 tillingFactor) + { + var types = new byte[9]; + var points = new PointF[9]; + + var path = new GraphicsPath(FillMode.Winding); + + Vector2 uv = skinBOX.UV; + Vector3 size = skinBOX.Size; + + path.AddRectangle(new RectangleF(new PointF((uv.X ) * tillingFactor.X, (uv.Y + size.Z) * tillingFactor.Y), new SizeF(size.Z * tillingFactor.X, size.Y * tillingFactor.Y))); + path.AddRectangle(new RectangleF(new PointF((uv.X + size.Z ) * tillingFactor.X, (uv.Y + size.Z) * tillingFactor.Y), new SizeF(size.X * tillingFactor.X, size.Y * tillingFactor.Y))); + path.AddRectangle(new RectangleF(new PointF((uv.X + size.Z + size.X ) * tillingFactor.X, (uv.Y + size.Z) * tillingFactor.Y), new SizeF(size.Z * tillingFactor.X, size.Y * tillingFactor.Y))); + path.AddRectangle(new RectangleF(new PointF((uv.X + size.Z * 2 + size.X) * tillingFactor.X, (uv.Y + size.Z) * tillingFactor.Y), new SizeF(size.X * tillingFactor.X, size.Y * tillingFactor.Y))); + + path.AddRectangle(new RectangleF(new PointF((uv.X + size.Z ) * tillingFactor.X, (uv.Y ) * tillingFactor.Y), new SizeF(size.X * tillingFactor.X, size.Z * tillingFactor.Y))); + path.AddRectangle(new RectangleF(new PointF((uv.X + size.Z + size.X ) * tillingFactor.X, (uv.Y ) * tillingFactor.Y), new SizeF(size.X * tillingFactor.X, size.Z * tillingFactor.Y))); + + return path; + } + + public static GraphicsPath GetUVGraphicsPath(this SkinBOX skinBox) + { + return skinBox.GetUVGraphicsPath(Vector2.One); + } + + public static string GetOverlayType(this SkinBOX skinBox) + { + if (!skinBox.IsValidType()) + return ""; + if (skinBox.IsOverlayPart()) + return skinBox.Type; + int index = Array.IndexOf(SkinBOX.BaseTypes, skinBox.Type); + return SkinBOX.OverlayTypes.IndexInRange(index) ? SkinBOX.OverlayTypes[index] : ""; + } + + public static string GetOverlayType(string type) + { + if (!SkinBOX.IsValidType(type)) + return ""; + if (SkinBOX.IsOverlayPart(type)) + return type; + int index = Array.IndexOf(SkinBOX.BaseTypes, type); + return SkinBOX.OverlayTypes.IndexInRange(index) ? SkinBOX.OverlayTypes[index] : ""; + } + + public static string GetBaseType(this SkinBOX skinBox) + { + if (!skinBox.IsValidType()) + return ""; + if (skinBox.IsBasePart()) + return skinBox.Type; + int index = Array.IndexOf(SkinBOX.OverlayTypes, skinBox.Type); + return SkinBOX.BaseTypes.IndexInRange(index) ? SkinBOX.BaseTypes[index] : ""; + } + + public static string GetBaseType(string type) + { + if (!SkinBOX.IsValidType(type)) + return ""; + if (SkinBOX.IsBasePart(type)) + return type; + int index = Array.IndexOf(SkinBOX.OverlayTypes, type); + return SkinBOX.BaseTypes.IndexInRange(index) ? SkinBOX.BaseTypes[index] : ""; + } + } +} diff --git a/PckStudio.Core/Extensions/SkinExtensions.cs b/PckStudio.Core/Extensions/SkinExtensions.cs new file mode 100644 index 00000000..d1518fd4 --- /dev/null +++ b/PckStudio.Core/Extensions/SkinExtensions.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Drawing.Imaging; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OMI.Formats.Languages; +using OMI.Formats.Pck; +using PckStudio.Core.Skin; + +namespace PckStudio.Core.Extensions +{ + public static class SkinExtensions + { + public static PckAsset CreateFile(this Skin.Skin skin, LOCFile localizationFile) + { + string skinId = skin.Identifier.ToString("d08"); + PckAsset skinFile = new PckAsset($"dlcskin{skinId}.png", PckAssetType.SkinFile); + + skinFile.AddProperty("DISPLAYNAME", skin.MetaData.Name); + if (localizationFile is not null) + { + string skinLocKey = $"IDS_dlcskin{skinId}_DISPLAYNAME"; + skinFile.AddProperty("DISPLAYNAMEID", skinLocKey); + localizationFile.AddLocKey(skinLocKey, skin.MetaData.Name); + } + + if (!string.IsNullOrEmpty(skin.MetaData.Theme)) + { + skinFile.AddProperty("THEMENAME", skin.MetaData.Theme); + if (localizationFile is not null) + { + skinFile.AddProperty("THEMENAMEID", $"IDS_dlcskin{skinId}_THEMENAME"); + localizationFile.AddLocKey($"IDS_dlcskin{skinId}_THEMENAME", skin.MetaData.Theme); + } + } + + if (skin.HasCape) + { + skinFile.AddProperty("CAPEPATH", $"dlccape{skinId}.png"); + } + + skinFile.AddProperty("ANIM", skin.Anim); + skinFile.AddProperty("GAME_FLAGS", "0x18"); + skinFile.AddProperty("FREE", "1"); + + foreach (SkinBOX box in skin.Model.AdditionalBoxes) + { + skinFile.AddProperty(box.ToProperty()); + } + foreach (SkinPartOffset offset in skin.Model.PartOffsets) + { + skinFile.AddProperty(offset.ToProperty()); + } + + skinFile.SetTexture(skin.Texture); + + return skinFile; + } + + public static PckAsset CreateCapeFile(this Skin.Skin skin) + { + if (!skin.HasCape) + throw new InvalidOperationException("Skin does not contain a cape."); + string skinId = skin.Identifier.ToString("d08"); + PckAsset capeFile = new PckAsset($"dlccape{skinId}.png", PckAssetType.CapeFile); + capeFile.SetTexture(skin.CapeTexture); + return capeFile; + } + } +} diff --git a/PckStudio.Core/Extensions/System.Numerics.cs b/PckStudio.Core/Extensions/System.Numerics.cs new file mode 100644 index 00000000..52ecb717 --- /dev/null +++ b/PckStudio.Core/Extensions/System.Numerics.cs @@ -0,0 +1,29 @@ +namespace PckStudio.Core.Extensions +{ + public static class NumericsExtensions + { + //internal static Cube ToCube(this SkinBOX skinBOX) => skinBOX.ToCube(0f); + + //internal static Cube ToCube(this SkinBOX skinBOX, float inflate, bool flipZMapping = false) + // => new Cube(skinBOX.Pos.ToOpenTKVector(), skinBOX.Size.ToOpenTKVector(), skinBOX.UV.ToOpenTKVector(), skinBOX.Scale + inflate, skinBOX.Mirror, flipZMapping); + public static OpenTK.Vector3 ToOpenTKVector(this System.Numerics.Vector3 vector3) + { + return new OpenTK.Vector3(vector3.X, vector3.Y, vector3.Z); + } + + public static OpenTK.Vector2 ToOpenTKVector(this System.Numerics.Vector2 vector2) + { + return new OpenTK.Vector2(vector2.X, vector2.Y); + } + + public static System.Numerics.Vector3 ToNumericsVector(this OpenTK.Vector3 vector3) + { + return new System.Numerics.Vector3(vector3.X, vector3.Y, vector3.Z); + } + + public static System.Numerics.Vector2 ToNumericsVector(this OpenTK.Vector2 vector2) + { + return new System.Numerics.Vector2(vector2.X, vector2.Y); + } + } +} diff --git a/PCK-Studio/Extensions/TreeNodeExtensions.cs b/PckStudio.Core/Extensions/TreeNodeExtensions.cs similarity index 70% rename from PCK-Studio/Extensions/TreeNodeExtensions.cs rename to PckStudio.Core/Extensions/TreeNodeExtensions.cs index 90cad0be..b29ee031 100644 --- a/PCK-Studio/Extensions/TreeNodeExtensions.cs +++ b/PckStudio.Core/Extensions/TreeNodeExtensions.cs @@ -1,16 +1,16 @@ using System.Collections.Generic; using System.Windows.Forms; -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { - internal static class TreeNodeExtensions + public static class TreeNodeExtensions { - internal static bool IsTagOfType(this TreeNode node) where T : class + public static bool IsTagOfType(this TreeNode node) where T : class { return node?.Tag is T; } - internal static bool TryGetTagData(this TreeNode node, out TOut tagData) where TOut : class + public static bool TryGetTagData(this TreeNode node, out TOut tagData) where TOut : class { if (node?.Tag is TOut data) { @@ -21,7 +21,7 @@ namespace PckStudio.Extensions return false; } - internal static bool Contains(this TreeNode thisNode, TreeNode childNode) + public static bool Contains(this TreeNode thisNode, TreeNode childNode) { if (childNode.Parent == null) return false; @@ -32,7 +32,7 @@ namespace PckStudio.Extensions return thisNode.Contains(childNode.Parent); } - internal static List GetChildNodes(this TreeNode thisNode) + public static List GetChildNodes(this TreeNode thisNode) { List nodes = new List(thisNode.Nodes.Count); foreach (TreeNode node in thisNode.Nodes) diff --git a/PCK-Studio/Extensions/TreeViewExtensions.cs b/PckStudio.Core/Extensions/TreeViewExtensions.cs similarity index 90% rename from PCK-Studio/Extensions/TreeViewExtensions.cs rename to PckStudio.Core/Extensions/TreeViewExtensions.cs index 79f36ddb..ec17789e 100644 --- a/PCK-Studio/Extensions/TreeViewExtensions.cs +++ b/PckStudio.Core/Extensions/TreeViewExtensions.cs @@ -2,9 +2,9 @@ using System.Linq; using System.Windows.Forms; -namespace PckStudio.Extensions +namespace PckStudio.Core.Extensions { - internal static class TreeViewExtensions + public static class TreeViewExtensions { public static TreeNode[] FindPath(this TreeView treeView, string path) { diff --git a/PckStudio.Core/FileDialogFilter.cs b/PckStudio.Core/FileDialogFilter.cs new file mode 100644 index 00000000..e35c00df --- /dev/null +++ b/PckStudio.Core/FileDialogFilter.cs @@ -0,0 +1,23 @@ +using System.IO; + +namespace PckStudio.Core +{ + public readonly struct FileDialogFilter + { + public readonly string Description; + public readonly string Pattern; + + public string Extension => Path.GetExtension(Pattern); + + public FileDialogFilter(string description, string pattern) + { + Description = description; + Pattern = pattern; + } + + public override string ToString() + { + return $"{Description}|{Pattern}"; + } + } +} \ No newline at end of file diff --git a/PCK-Studio/FileFormats/PckAudioFile.cs b/PckStudio.Core/FileFormats/PckAudioFile.cs similarity index 98% rename from PCK-Studio/FileFormats/PckAudioFile.cs rename to PckStudio.Core/FileFormats/PckAudioFile.cs index 40e77bfd..848d69b6 100644 --- a/PCK-Studio/FileFormats/PckAudioFile.cs +++ b/PckStudio.Core/FileFormats/PckAudioFile.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using OMI.Formats.Languages; -namespace PckStudio.FileFormats +namespace PckStudio.Core.FileFormats { public class PckAudioFile { diff --git a/PckStudio.Core/GameConstants.cs b/PckStudio.Core/GameConstants.cs new file mode 100644 index 00000000..a8b4b05e --- /dev/null +++ b/PckStudio.Core/GameConstants.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using PckStudio.Core.Extensions; +using PckStudio.Core.Skin; + +namespace PckStudio.Core +{ + public static class GameConstants + { + // 16777215 being the uint24 max value + public const int MAX_PACK_ID = 0xffffff; + + public static readonly Vector3 SkinHeadTranslation = Vector3.Zero; + public static readonly Vector3 SkinHeadPivot = Vector3.Zero; + + public static readonly Vector3 SkinBodyTranslation = Vector3.Zero; + public static readonly Vector3 SkinBodyPivot = Vector3.Zero; + + public static readonly Vector3 SkinRightArmTranslation = new(-5f, 2f, 0f); + public static readonly Vector3 SkinRightArmPivot = new(-6f, 2f, 0f); + + public static readonly Vector3 SkinLeftArmTranslation = new(5f, 2f, 0f); + public static readonly Vector3 SkinLeftArmPivot = new(6f, 2f, 0f); + + public static readonly Vector3 SkinRightLegTranslation = new(-2f, 12f, 0f); + public static readonly Vector3 SkinRightLegPivot = new(-2f, 12f, 0f); + + public static readonly Vector3 SkinLeftLegTranslation = new(2f, 12f, 0f); + public static readonly Vector3 SkinLeftLegPivot = new(2f, 12f, 0f); + + private static Dictionary _posisioningInfos = new Dictionary() + { + ["HEAD"] = new PositioningInfo(SkinHeadTranslation, SkinHeadPivot), + ["BODY"] = new PositioningInfo(SkinBodyTranslation, SkinBodyPivot), + ["ARM0"] = new PositioningInfo(SkinRightArmTranslation, SkinRightArmPivot), + ["ARM1"] = new PositioningInfo(SkinLeftArmTranslation, SkinLeftArmPivot), + ["LEG0"] = new PositioningInfo(SkinRightLegTranslation, SkinRightLegPivot), + ["LEG1"] = new PositioningInfo(SkinLeftLegTranslation, SkinLeftLegPivot), + }; + public record struct PositioningInfo(Vector3 Translation, Vector3 Pivot); + + public static PositioningInfo GetPositioningInfo(string partName) + { + if (SkinBOX.IsOverlayPart(partName)) + partName = SkinBOXExtensions.GetBaseType(partName); + return _posisioningInfos.ContainsKey(partName) ? _posisioningInfos[partName] : default; + } + + public static Vector3 GetSkinPartPivot(string partName) => GetPositioningInfo(partName).Pivot; + + public static Vector3 GetSkinPartTranslation(string partName) => GetPositioningInfo(partName).Translation; + + public const int GameTickInMilliseconds = 50; + + // See: https://minecraft.fandom.com/wiki/Dye#Color_values for more information. + public static readonly Color[] DyeColors = [ + Color.FromArgb(0xf9fffe), // White + Color.FromArgb(0xf9801d), // Orange + Color.FromArgb(0xc74ebd), // Magenta + Color.FromArgb(0x3ab3da), // Light Blue + Color.FromArgb(0xfed83d), // Yellow + Color.FromArgb(0x80c71f), // Lime + Color.FromArgb(0xf38baa), // Pink + Color.FromArgb(0x474f52), // Gray + Color.FromArgb(0x9d9d97), // Light Gray + Color.FromArgb(0x169c9c), // Cyan + Color.FromArgb(0x8932b8), // Purple + Color.FromArgb(0x3c44aa), // Blue + Color.FromArgb(0x835432), // Brown + Color.FromArgb(0x5e7c16), // Green + Color.FromArgb(0xb02e26), // Red + Color.FromArgb(0x1d1d21), // Black + ]; + } +} diff --git a/PCK-Studio/Internal/IO/3DST/3DSTextureReader.cs b/PckStudio.Core/IO/3DST/3DSTextureReader.cs similarity index 94% rename from PCK-Studio/Internal/IO/3DST/3DSTextureReader.cs rename to PckStudio.Core/IO/3DST/3DSTextureReader.cs index 0def6f89..cc6930b0 100644 --- a/PCK-Studio/Internal/IO/3DST/3DSTextureReader.cs +++ b/PckStudio.Core/IO/3DST/3DSTextureReader.cs @@ -8,9 +8,9 @@ using System.Threading.Tasks; using OMI.Workers; using OMI; -namespace PckStudio.Internal.IO._3DST +namespace PckStudio.Core.IO._3DST { - internal class _3DSTextureReader : IDataFormatReader, IDataFormatReader + public class _3DSTextureReader : IDataFormatReader, IDataFormatReader { public Image FromFile(string filename) { @@ -29,7 +29,7 @@ namespace PckStudio.Internal.IO._3DST public Image FromStream(Stream stream) { Image img = null; - using (var reader = new EndiannessAwareBinaryReader(stream, Encoding.ASCII, leaveOpen: true, Endianness.LittleEndian)) + using (var reader = new EndiannessAwareBinaryReader(stream, Encoding.ASCII, leaveOpen: true, ByteOrder.LittleEndian)) { if (reader.ReadString(4) == "3DST") { diff --git a/PCK-Studio/Internal/IO/3DST/3DSTextureWriter.cs b/PckStudio.Core/IO/3DST/3DSTextureWriter.cs similarity index 88% rename from PCK-Studio/Internal/IO/3DST/3DSTextureWriter.cs rename to PckStudio.Core/IO/3DST/3DSTextureWriter.cs index 6ffbb76d..9a5ec6dc 100644 --- a/PCK-Studio/Internal/IO/3DST/3DSTextureWriter.cs +++ b/PckStudio.Core/IO/3DST/3DSTextureWriter.cs @@ -5,9 +5,9 @@ using System.Text; using OMI; using OMI.Workers; -namespace PckStudio.Internal.IO._3DST +namespace PckStudio.Core.IO._3DST { - internal class _3DSTextureWriter : IDataFormatWriter + public class _3DSTextureWriter : IDataFormatWriter { private Image _image; private _3DSTextureFormat _format; @@ -27,7 +27,7 @@ namespace PckStudio.Internal.IO._3DST public void WriteToStream(Stream stream) { - using (var writer = new EndiannessAwareBinaryWriter(stream, Encoding.ASCII, leaveOpen: true, Endianness.LittleEndian)) + using (var writer = new EndiannessAwareBinaryWriter(stream, Encoding.ASCII, leaveOpen: true, ByteOrder.LittleEndian)) { writer.WriteString("3DST"); // 0 writer.Write(2); // 4 unknown diff --git a/PCK-Studio/Internal/IO/3DST/TextureCodec.cs b/PckStudio.Core/IO/3DST/TextureCodec.cs similarity index 99% rename from PCK-Studio/Internal/IO/3DST/TextureCodec.cs rename to PckStudio.Core/IO/3DST/TextureCodec.cs index e2aaead1..6e53b373 100644 --- a/PCK-Studio/Internal/IO/3DST/TextureCodec.cs +++ b/PckStudio.Core/IO/3DST/TextureCodec.cs @@ -3,7 +3,7 @@ using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; -namespace PckStudio.Internal.IO._3DST +namespace PckStudio.Core.IO._3DST { /// /// Format of the texture used on the PICA200. diff --git a/PCK-Studio/Internal/IO/PckAudio/PckAudioFileReader.cs b/PckStudio.Core/IO/PckAudio/PckAudioFileReader.cs similarity index 93% rename from PCK-Studio/Internal/IO/PckAudio/PckAudioFileReader.cs rename to PckStudio.Core/IO/PckAudio/PckAudioFileReader.cs index e0c641f5..d1b8165a 100644 --- a/PCK-Studio/Internal/IO/PckAudio/PckAudioFileReader.cs +++ b/PckStudio.Core/IO/PckAudio/PckAudioFileReader.cs @@ -1,13 +1,13 @@ using OMI; using OMI.Workers; -using PckStudio.FileFormats; +using PckStudio.Core.FileFormats; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; -namespace PckStudio.Internal.IO.PckAudio +namespace PckStudio.Core.IO.PckAudio { public class InvalidAudioPckException : Exception @@ -16,14 +16,14 @@ namespace PckStudio.Internal.IO.PckAudio { } } - internal class PckAudioFileReader : IDataFormatReader, IDataFormatReader + public class PckAudioFileReader : IDataFormatReader, IDataFormatReader { private PckAudioFile _file; - private Endianness _endianness; + private ByteOrder _endianness; private List LUT = new List(); private List _OriginalAudioTypeOrder = new List(); - public PckAudioFileReader(Endianness endianness) + public PckAudioFileReader(ByteOrder endianness) { _endianness = endianness; } @@ -45,7 +45,7 @@ namespace PckStudio.Internal.IO.PckAudio public PckAudioFile FromStream(Stream stream) { using (var reader = new EndiannessAwareBinaryReader(stream, - _endianness == Endianness.BigEndian + _endianness == ByteOrder.BigEndian ? Encoding.BigEndianUnicode : Encoding.Unicode, leaveOpen: true, _endianness)) diff --git a/PCK-Studio/Internal/IO/PckAudio/PckAudioFileWriter.cs b/PckStudio.Core/IO/PckAudio/PckAudioFileWriter.cs similarity index 90% rename from PCK-Studio/Internal/IO/PckAudio/PckAudioFileWriter.cs rename to PckStudio.Core/IO/PckAudio/PckAudioFileWriter.cs index 2538e885..73c343bb 100644 --- a/PCK-Studio/Internal/IO/PckAudio/PckAudioFileWriter.cs +++ b/PckStudio.Core/IO/PckAudio/PckAudioFileWriter.cs @@ -1,17 +1,17 @@ using OMI; using OMI.Workers; -using PckStudio.FileFormats; +using PckStudio.Core.FileFormats; using System.Collections.Generic; using System.IO; using System.Text; -namespace PckStudio.Internal.IO.PckAudio +namespace PckStudio.Core.IO.PckAudio { - internal class PckAudioFileWriter : IDataFormatWriter + public class PckAudioFileWriter : IDataFormatWriter { private PckAudioFile _file; - private Endianness _endianness; + private ByteOrder _endianness; private static readonly List LUT = new List { "CUENAME", @@ -19,7 +19,7 @@ namespace PckStudio.Internal.IO.PckAudio "CREDITID" }; - public PckAudioFileWriter(PckAudioFile file, Endianness endianness) + public PckAudioFileWriter(PckAudioFile file, ByteOrder endianness) { _file = file; _endianness = endianness; @@ -36,7 +36,7 @@ namespace PckStudio.Internal.IO.PckAudio public void WriteToStream(Stream stream) { using (var writer = new EndiannessAwareBinaryWriter(stream, - _endianness == Endianness.BigEndian + _endianness == ByteOrder.BigEndian ? Encoding.BigEndianUnicode : Encoding.Unicode, leaveOpen: true, _endianness)) diff --git a/PCK-Studio/Internal/IO/TGA/TGADataTypeCode.cs b/PckStudio.Core/IO/TGA/TGADataTypeCode.cs similarity index 98% rename from PCK-Studio/Internal/IO/TGA/TGADataTypeCode.cs rename to PckStudio.Core/IO/TGA/TGADataTypeCode.cs index aa092c3a..75d10fdf 100644 --- a/PCK-Studio/Internal/IO/TGA/TGADataTypeCode.cs +++ b/PckStudio.Core/IO/TGA/TGADataTypeCode.cs @@ -16,7 +16,7 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -namespace PckStudio.Internal.IO.TGA +namespace PckStudio.Core.IO.TGA { internal enum TGADataTypeCode : byte { diff --git a/PCK-Studio/Internal/IO/TGA/TGADeserializer.cs b/PckStudio.Core/IO/TGA/TGADeserializer.cs similarity index 97% rename from PCK-Studio/Internal/IO/TGA/TGADeserializer.cs rename to PckStudio.Core/IO/TGA/TGADeserializer.cs index 23e43625..b95bbc1c 100644 --- a/PCK-Studio/Internal/IO/TGA/TGADeserializer.cs +++ b/PckStudio.Core/IO/TGA/TGADeserializer.cs @@ -18,7 +18,7 @@ using System.IO; using System.Drawing; -namespace PckStudio.Internal.IO.TGA +namespace PckStudio.Core.IO.TGA { internal static class TGADeserializer { diff --git a/PCK-Studio/Internal/IO/TGA/TGAException.cs b/PckStudio.Core/IO/TGA/TGAException.cs similarity index 93% rename from PCK-Studio/Internal/IO/TGA/TGAException.cs rename to PckStudio.Core/IO/TGA/TGAException.cs index 7e6461c1..3af64252 100644 --- a/PCK-Studio/Internal/IO/TGA/TGAException.cs +++ b/PckStudio.Core/IO/TGA/TGAException.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.Serialization; -namespace PckStudio.Internal.IO.TGA +namespace PckStudio.Core.IO.TGA { [Serializable] internal class TGAException : Exception diff --git a/PCK-Studio/Internal/IO/TGA/TGAExtentionData.cs b/PckStudio.Core/IO/TGA/TGAExtentionData.cs similarity index 98% rename from PCK-Studio/Internal/IO/TGA/TGAExtentionData.cs rename to PckStudio.Core/IO/TGA/TGAExtentionData.cs index c22aec78..169979ab 100644 --- a/PCK-Studio/Internal/IO/TGA/TGAExtentionData.cs +++ b/PckStudio.Core/IO/TGA/TGAExtentionData.cs @@ -18,7 +18,7 @@ using System; using System.Windows.Forms; -namespace PckStudio.Internal.IO.TGA +namespace PckStudio.Core.IO.TGA { internal struct TGAExtentionData { diff --git a/PCK-Studio/Internal/IO/TGA/TGAFileData.cs b/PckStudio.Core/IO/TGA/TGAFileData.cs similarity index 97% rename from PCK-Studio/Internal/IO/TGA/TGAFileData.cs rename to PckStudio.Core/IO/TGA/TGAFileData.cs index 92936e17..317ddc42 100644 --- a/PCK-Studio/Internal/IO/TGA/TGAFileData.cs +++ b/PckStudio.Core/IO/TGA/TGAFileData.cs @@ -18,7 +18,7 @@ using System.IO; using System.Drawing; -namespace PckStudio.Internal.IO.TGA +namespace PckStudio.Core.IO.TGA { internal class TGAFileData { diff --git a/PCK-Studio/Internal/IO/TGA/TGAFooter.cs b/PckStudio.Core/IO/TGA/TGAFooter.cs similarity index 96% rename from PCK-Studio/Internal/IO/TGA/TGAFooter.cs rename to PckStudio.Core/IO/TGA/TGAFooter.cs index 6859de2f..06b8d47b 100644 --- a/PCK-Studio/Internal/IO/TGA/TGAFooter.cs +++ b/PckStudio.Core/IO/TGA/TGAFooter.cs @@ -16,7 +16,7 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -namespace PckStudio.Internal.IO.TGA +namespace PckStudio.Core.IO.TGA { internal struct TGAFooter { diff --git a/PCK-Studio/Internal/IO/TGA/TGAHeader.cs b/PckStudio.Core/IO/TGA/TGAHeader.cs similarity index 97% rename from PCK-Studio/Internal/IO/TGA/TGAHeader.cs rename to PckStudio.Core/IO/TGA/TGAHeader.cs index a1bed5f1..4e40358d 100644 --- a/PCK-Studio/Internal/IO/TGA/TGAHeader.cs +++ b/PckStudio.Core/IO/TGA/TGAHeader.cs @@ -16,7 +16,7 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -namespace PckStudio.Internal.IO.TGA +namespace PckStudio.Core.IO.TGA { /// /// Resources: diff --git a/PCK-Studio/Internal/IO/TGA/TGAReader.cs b/PckStudio.Core/IO/TGA/TGAReader.cs similarity index 98% rename from PCK-Studio/Internal/IO/TGA/TGAReader.cs rename to PckStudio.Core/IO/TGA/TGAReader.cs index fae9d530..ac4489fe 100644 --- a/PCK-Studio/Internal/IO/TGA/TGAReader.cs +++ b/PckStudio.Core/IO/TGA/TGAReader.cs @@ -22,11 +22,10 @@ using System.Drawing; using System.Diagnostics; using System.Drawing.Imaging; using System.Runtime.InteropServices; -using System.Collections.Generic; using OMI.Workers; using OMI; -namespace PckStudio.Internal.IO.TGA +namespace PckStudio.Core.IO.TGA { internal class TGAReader : IDataFormatReader, IDataFormatReader { @@ -48,7 +47,7 @@ namespace PckStudio.Internal.IO.TGA public TGAFileData FromStream(Stream stream) { - using var reader = new EndiannessAwareBinaryReader(stream, Encoding.ASCII, leaveOpen: true, Endianness.LittleEndian); + using var reader = new EndiannessAwareBinaryReader(stream, Encoding.ASCII, leaveOpen: true, ByteOrder.LittleEndian); TGAHeader header = LoadHeader(reader); Image image = LoadImage(reader, header); TGAFooter footer = LoadFooter(reader); diff --git a/PCK-Studio/Internal/IO/TGA/TGASerializer.cs b/PckStudio.Core/IO/TGA/TGASerializer.cs similarity index 97% rename from PCK-Studio/Internal/IO/TGA/TGASerializer.cs rename to PckStudio.Core/IO/TGA/TGASerializer.cs index a467174a..14d3e491 100644 --- a/PCK-Studio/Internal/IO/TGA/TGASerializer.cs +++ b/PckStudio.Core/IO/TGA/TGASerializer.cs @@ -18,7 +18,7 @@ using System.IO; using System.Drawing; -namespace PckStudio.Internal.IO.TGA +namespace PckStudio.Core.IO.TGA { internal static class TGASerializer { diff --git a/PCK-Studio/Internal/IO/TGA/TGAWriter.cs b/PckStudio.Core/IO/TGA/TGAWriter.cs similarity index 96% rename from PCK-Studio/Internal/IO/TGA/TGAWriter.cs rename to PckStudio.Core/IO/TGA/TGAWriter.cs index ad749d00..fbce4d85 100644 --- a/PCK-Studio/Internal/IO/TGA/TGAWriter.cs +++ b/PckStudio.Core/IO/TGA/TGAWriter.cs @@ -18,15 +18,12 @@ using System; using System.IO; using System.Drawing; -using System.Diagnostics; using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.Text; using OMI; -using System.Windows.Forms; -using DiscordRPC; -namespace PckStudio.Internal.IO.TGA +namespace PckStudio.Core.IO.TGA { internal class TGAWriter { @@ -123,7 +120,7 @@ namespace PckStudio.Internal.IO.TGA public void WriteToStream(Stream stream, Image image) { _bitmap = new Bitmap(image); - using (var writer = new EndiannessAwareBinaryWriter(stream, Encoding.ASCII, leaveOpen: true, Endianness.LittleEndian)) + using (var writer = new EndiannessAwareBinaryWriter(stream, Encoding.ASCII, leaveOpen: true, ByteOrder.LittleEndian)) { WriteHeader(writer); WriteImage(writer); diff --git a/PckStudio.Core/Interfaces/IEditor.cs b/PckStudio.Core/Interfaces/IEditor.cs new file mode 100644 index 00000000..dd19944d --- /dev/null +++ b/PckStudio.Core/Interfaces/IEditor.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OMI.Formats.Pck; + +namespace PckStudio.Interfaces +{ + public interface IEditor where T : class + { + T EditorValue { get; } + + ISaveContext SaveContext { get; } + + void Save(); + + void SaveAs(); + + void Close(); + + void UpdateView(); + } +} \ No newline at end of file diff --git a/PckStudio.Core/Interfaces/IModelImportProvider.cs b/PckStudio.Core/Interfaces/IModelImportProvider.cs new file mode 100644 index 00000000..a7303926 --- /dev/null +++ b/PckStudio.Core/Interfaces/IModelImportProvider.cs @@ -0,0 +1,22 @@ +using System; +using System.IO; +using PckStudio.Core; + +namespace PckStudio.Interfaces +{ + public interface IModelImportProvider where T : class + { + public string Name { get; } + + public FileDialogFilter DialogFilter { get; } + + public bool SupportImport { get; } + public bool SupportExport { get; } + + public T Import(string filename); + public T Import(Stream stream); + + public void Export(string filename, T model); + public void Export(ref Stream stream, T model); + } +} diff --git a/PCK-Studio/Interfaces/IPckAssetDeserializer.cs b/PckStudio.Core/Interfaces/IPckAssetDeserializer.cs similarity index 70% rename from PCK-Studio/Interfaces/IPckAssetDeserializer.cs rename to PckStudio.Core/Interfaces/IPckAssetDeserializer.cs index 3416c6d5..fbb55d1e 100644 --- a/PCK-Studio/Interfaces/IPckAssetDeserializer.cs +++ b/PckStudio.Core/Interfaces/IPckAssetDeserializer.cs @@ -2,7 +2,7 @@ namespace PckStudio.Interfaces { - internal interface IPckAssetDeserializer + public interface IPckAssetDeserializer { public T Deserialize(PckAsset asset); } diff --git a/PCK-Studio/Interfaces/IPckAssetSerializer.cs b/PckStudio.Core/Interfaces/IPckAssetSerializer.cs similarity index 74% rename from PCK-Studio/Interfaces/IPckAssetSerializer.cs rename to PckStudio.Core/Interfaces/IPckAssetSerializer.cs index dbaa903b..17f46a91 100644 --- a/PCK-Studio/Interfaces/IPckAssetSerializer.cs +++ b/PckStudio.Core/Interfaces/IPckAssetSerializer.cs @@ -2,7 +2,7 @@ namespace PckStudio.Interfaces { - internal interface IPckAssetSerializer + public interface IPckAssetSerializer { public void Serialize(T obj, ref PckAsset asset); } diff --git a/PckStudio.Core/Interfaces/ISaveContext.cs b/PckStudio.Core/Interfaces/ISaveContext.cs new file mode 100644 index 00000000..1b11d4f4 --- /dev/null +++ b/PckStudio.Core/Interfaces/ISaveContext.cs @@ -0,0 +1,9 @@ +namespace PckStudio.Interfaces +{ + public interface ISaveContext + { + public bool AutoSave { get; } + + public void Save(T value); + } +} \ No newline at end of file diff --git a/PckStudio.Core/Interfaces/ITryGetSet.cs b/PckStudio.Core/Interfaces/ITryGetSet.cs new file mode 100644 index 00000000..058a672c --- /dev/null +++ b/PckStudio.Core/Interfaces/ITryGetSet.cs @@ -0,0 +1,65 @@ +namespace PckStudio.Interfaces +{ + public delegate bool TryGetDelegate(TKey key, out TValue value); + public delegate bool TrySetDelegate(TKey key, TValue value); + + public sealed class TryGet : ITryGet + { + private TryGetDelegate _tryGetDelegate; + + public static ITryGet FromDelegate(TryGetDelegate tryGetDelegate) => new TryGet(tryGetDelegate); + + bool ITryGet.TryGet(TKey key, out TValue value) => _tryGetDelegate(key, out value); + + private TryGet(TryGetDelegate tryGetDelegate) + { + _tryGetDelegate = tryGetDelegate; + } + } + + public sealed class TrySet : ITrySet + { + private TrySetDelegate _trySetDelegate; + + public static ITrySet FromDelegate(TrySetDelegate trySetDelegate) => new TrySet(trySetDelegate); + + bool ITrySet.TrySet(TKey key, TValue value) => _trySetDelegate(key, value); + + private TrySet(TrySetDelegate trySetDelegate) + { + _trySetDelegate = trySetDelegate; + } + } + + public sealed class TryGetSet : ITryGetSet + { + public static ITryGetSet FromDelegates(TryGetDelegate tryGetDelegate, TrySetDelegate trySetDelegate) => new TryGetSet(tryGetDelegate, trySetDelegate); + + public bool TryGet(TKey key, out TValue value) => _tryGetDelegate(key, out value); + + public bool TrySet(TKey key, TValue value) => _trySetDelegate(key, value); + + private TryGetDelegate _tryGetDelegate; + private TrySetDelegate _trySetDelegate; + + private TryGetSet(TryGetDelegate tryGetDelegate, TrySetDelegate trySetDelegate) + { + _tryGetDelegate = tryGetDelegate; + _trySetDelegate = trySetDelegate; + } + } + + public interface ITryGet + { + bool TryGet(TKey key, out TValue value); + } + + public interface ITrySet + { + bool TrySet(TKey key, TValue value); + } + + public interface ITryGetSet : ITryGet, ITrySet + { + } +} diff --git a/PckStudio.Core/ItemSelectionPopUp.Designer.cs b/PckStudio.Core/ItemSelectionPopUp.Designer.cs new file mode 100644 index 00000000..42d80301 --- /dev/null +++ b/PckStudio.Core/ItemSelectionPopUp.Designer.cs @@ -0,0 +1,90 @@ +namespace PckStudio.Core.Additional_Popups +{ + partial class ItemSelectionPopUp + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ItemSelectionPopUp)); + this.label2 = new System.Windows.Forms.Label(); + this.okBtn = new System.Windows.Forms.Button(); + this.cancelButton = new System.Windows.Forms.Button(); + this.ComboBox = new System.Windows.Forms.ComboBox(); + this.SuspendLayout(); + // + // label2 + // + resources.ApplyResources(this.label2, "label2"); + this.label2.ForeColor = System.Drawing.Color.White; + this.label2.Name = "label2"; + // + // okBtn + // + resources.ApplyResources(this.okBtn, "okBtn"); + this.okBtn.ForeColor = System.Drawing.Color.White; + this.okBtn.Name = "okBtn"; + this.okBtn.UseVisualStyleBackColor = true; + this.okBtn.Click += new System.EventHandler(this.okBtn_Click); + // + // cancelButton + // + resources.ApplyResources(this.cancelButton, "cancelButton"); + this.cancelButton.ForeColor = System.Drawing.Color.White; + this.cancelButton.Name = "cancelButton"; + this.cancelButton.UseVisualStyleBackColor = true; + this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click); + // + // ComboBox + // + this.ComboBox.FormattingEnabled = true; + resources.ApplyResources(this.ComboBox, "ComboBox"); + this.ComboBox.Name = "ComboBox"; + // + // ItemSelectionPopUp + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ControlBox = false; + this.Controls.Add(this.ComboBox); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.okBtn); + this.Controls.Add(this.label2); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ItemSelectionPopUp"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.ComboBox ComboBox; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Button okBtn; + } +} \ No newline at end of file diff --git a/PckStudio.Core/ItemSelectionPopUp.cs b/PckStudio.Core/ItemSelectionPopUp.cs new file mode 100644 index 00000000..b753810c --- /dev/null +++ b/PckStudio.Core/ItemSelectionPopUp.cs @@ -0,0 +1,44 @@ +using System; +using System.Windows.Forms; + +namespace PckStudio.Core.Additional_Popups +{ + public partial class ItemSelectionPopUp : Form + { + public string SelectedItem => DialogResult == DialogResult.OK ? ComboBox.Text : string.Empty; + public int SelectedIndex => DialogResult == DialogResult.OK ? ComboBox.SelectedIndex : -1; + + public string LabelText + { + get => label2.Text; + set => label2.Text = value; + } + public string ButtonText + { + get => okBtn.Text; + set => okBtn.Text = value; + } + + public ItemSelectionPopUp(params string[] items) + { + InitializeComponent(); + ComboBox.Items.AddRange(items); + } + + private void okBtn_Click(object sender, EventArgs e) + { + if(ComboBox.SelectedIndex <= -1) + { + cancelButton_Click(sender, e); + return; + } + DialogResult = DialogResult.OK; + } + + private void cancelButton_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + Close(); + } + } +} diff --git a/PCK-Studio/Forms/Skins-And-Textures/SkinPreview.resx b/PckStudio.Core/ItemSelectionPopUp.resx similarity index 97% rename from PCK-Studio/Forms/Skins-And-Textures/SkinPreview.resx rename to PckStudio.Core/ItemSelectionPopUp.resx index 72d29f17..c818e94a 100644 --- a/PCK-Studio/Forms/Skins-And-Textures/SkinPreview.resx +++ b/PckStudio.Core/ItemSelectionPopUp.resx @@ -117,7 +117,126 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + 15, 41 + + + 35, 13 + + + 3 + + + Items: + + + label2 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + + Flat + + + 54, 76 + + + 75, 23 + + + 4 + + + Add + + + okBtn + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Flat + + + NoControl + + + 135, 76 + + + 75, 23 + + + 6 + + + Cancel + + + cancelButton + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + 23 + + + 60, 34 + + + 192, 29 + + + 7 + + + ComboBox + + + MetroFramework.Controls.MetroComboBox, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + + + $this + + + 0 + + + True + + + 6, 13 + + + 264, 105 + AAABAA0AAAAAAAEAIAD7NAAA1gAAAICAAAABACAAKAgBANE1AACAgAAAAQAIAChMAAD5PQEAQEAAAAEA @@ -2624,4 +2743,13 @@ AP//AAA= + + CenterParent + + + ItemSelectionPopUp + + + MetroFramework.Forms.MetroForm, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a + \ No newline at end of file diff --git a/PCK-Studio/Internal/Json/ColorEntry.cs b/PckStudio.Core/Json/ColorEntry.cs similarity index 89% rename from PCK-Studio/Internal/Json/ColorEntry.cs rename to PckStudio.Core/Json/ColorEntry.cs index 8523a311..283c3761 100644 --- a/PCK-Studio/Internal/Json/ColorEntry.cs +++ b/PckStudio.Core/Json/ColorEntry.cs @@ -5,9 +5,9 @@ using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; -namespace PckStudio.Internal.Json +namespace PckStudio.Core.Json { - internal class JsonColorEntry + public class JsonColorEntry { [JsonProperty("defaultName", Required = Required.Always)] public string DefaultName { get; set; } diff --git a/PCK-Studio/Internal/Json/EntityInfo.cs b/PckStudio.Core/Json/EntityInfo.cs similarity index 70% rename from PCK-Studio/Internal/Json/EntityInfo.cs rename to PckStudio.Core/Json/EntityInfo.cs index 9c72c388..ddbd0d7b 100644 --- a/PCK-Studio/Internal/Json/EntityInfo.cs +++ b/PckStudio.Core/Json/EntityInfo.cs @@ -1,13 +1,9 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json; -namespace PckStudio.Internal.Json +namespace PckStudio.Core.Json { - internal class EntityInfo + public class EntityInfo { [JsonProperty("displayName")] public string DisplayName { get; set; } diff --git a/PCK-Studio/Internal/Json/TileInfo.cs b/PckStudio.Core/Json/TileInfo.cs similarity index 79% rename from PCK-Studio/Internal/Json/TileInfo.cs rename to PckStudio.Core/Json/TileInfo.cs index b5fb0510..db8628a5 100644 --- a/PCK-Studio/Internal/Json/TileInfo.cs +++ b/PckStudio.Core/Json/TileInfo.cs @@ -5,9 +5,9 @@ using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; -namespace PckStudio.Internal.Json +namespace PckStudio.Core.Json { - internal class JsonTileInfo + public sealed class JsonTileInfo { [JsonProperty("displayName")] public string DisplayName { get; set; } @@ -21,10 +21,10 @@ namespace PckStudio.Internal.Json [JsonProperty("height")] public int TileHeight { get; set; } = 1; - [JsonProperty("hasColourEntry", DefaultValueHandling = DefaultValueHandling.Populate)] - public bool HasColourEntry { get; set; } + [JsonIgnore] + public bool HasColourEntry => ColourEntry != null; - [JsonProperty("colourEntry", DefaultValueHandling = DefaultValueHandling.Populate)] + [JsonProperty("colourEntry", DefaultValueHandling = DefaultValueHandling.Ignore)] public JsonColorEntry ColourEntry { get; set; } [JsonProperty("allowCustomColour", DefaultValueHandling = DefaultValueHandling.Populate)] diff --git a/PCK-Studio/Internal/Json/UpdateInformation.cs b/PckStudio.Core/Json/UpdateInformation.cs similarity index 93% rename from PCK-Studio/Internal/Json/UpdateInformation.cs rename to PckStudio.Core/Json/UpdateInformation.cs index c6d1fd30..ef4836bf 100644 --- a/PCK-Studio/Internal/Json/UpdateInformation.cs +++ b/PckStudio.Core/Json/UpdateInformation.cs @@ -5,7 +5,7 @@ using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; -namespace PckStudio.Internal.Json +namespace PckStudio.Core.Json { internal class UpdateInformation { diff --git a/PCK-Studio/Internal/Misc/FileCacher.cs b/PckStudio.Core/Misc/FileCacher.cs similarity index 97% rename from PCK-Studio/Internal/Misc/FileCacher.cs rename to PckStudio.Core/Misc/FileCacher.cs index 3a810d10..c91fa8ad 100644 --- a/PCK-Studio/Internal/Misc/FileCacher.cs +++ b/PckStudio.Core/Misc/FileCacher.cs @@ -18,9 +18,9 @@ using System; using System.IO; -namespace PckStudio.Internal.Misc +namespace PckStudio.Core.Misc { - internal class FileCacher + public class FileCacher { private string _cacheDirectory; diff --git a/PCK-Studio/Internal/Misc/OpenFolderDialog.cs b/PckStudio.Core/Misc/OpenFolderDialog.cs similarity index 95% rename from PCK-Studio/Internal/Misc/OpenFolderDialog.cs rename to PckStudio.Core/Misc/OpenFolderDialog.cs index 02ac4eca..90a18310 100644 --- a/PCK-Studio/Internal/Misc/OpenFolderDialog.cs +++ b/PckStudio.Core/Misc/OpenFolderDialog.cs @@ -6,10 +6,8 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; -using System.Windows; // for WPF support -using System.Windows.Interop; // for WPF support -namespace PckStudio.Internal.Misc +namespace PckStudio.Core.Misc { public class OpenFolderDialog { @@ -30,13 +28,6 @@ namespace PckStudio.Internal.Misc return options; } - // for WPF support - public bool? ShowDialog(Window owner = null, bool throwOnError = false) - { - owner ??= Application.Current.MainWindow; - return ShowDialog(owner != null ? new WindowInteropHelper(owner).Handle : IntPtr.Zero, throwOnError); - } - // for all .NET public virtual bool? ShowDialog(IntPtr owner, bool throwOnError = false) { diff --git a/PckStudio.Core/NamedData.cs b/PckStudio.Core/NamedData.cs new file mode 100644 index 00000000..717db6f6 --- /dev/null +++ b/PckStudio.Core/NamedData.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PckStudio.Core +{ + public readonly struct NamedData(string name, T value) + { + public readonly string Name = name; + public readonly T Value = value; + } +} diff --git a/PckStudio.Core/PackInfo.cs b/PckStudio.Core/PackInfo.cs new file mode 100644 index 00000000..df451b8c --- /dev/null +++ b/PckStudio.Core/PackInfo.cs @@ -0,0 +1,45 @@ +using System; +using OMI.Formats.Pck; + +namespace PckStudio.Core +{ + public sealed class PackInfo + { + public static readonly PackInfo Empty = new PackInfo(default, default, default); + public bool IsValid { get; } + public PckFile File { get; } + public OMI.ByteOrder Endianness { get; } + + + //public enum PackType + //{ + // Unknown = -1, + // SkinPack, + // TexturePack, + // MashUpPack + //} + + //public PackType Type { get; } + + public bool AllowEndianSwap { get; } + + public static PackInfo Create(PckFile file, OMI.ByteOrder endianness, bool allowEndianSwap) + { + return new PackInfo(file, endianness, allowEndianSwap); + } + + private PackInfo(PckFile file, OMI.ByteOrder endianness, bool allowEndianSwap) + { + File = file; + Endianness = endianness; + AllowEndianSwap = allowEndianSwap; + //Type = GetPackType(); + IsValid = file is not null && Enum.IsDefined(typeof(OMI.ByteOrder), endianness); // && Type != PackType.Unknown; + } + + //private PackType GetPackType() + //{ + // return PackType.SkinPack; + //} + } +} \ No newline at end of file diff --git a/PckStudio.Core/PckStudio.Core.csproj b/PckStudio.Core/PckStudio.Core.csproj new file mode 100644 index 00000000..19f40da6 --- /dev/null +++ b/PckStudio.Core/PckStudio.Core.csproj @@ -0,0 +1,220 @@ + + + + + Debug + AnyCPU + {345EABED-F0D1-4D04-B409-BABDEF747352} + Library + NDEBUG + Properties + PckStudio.Core + PckStudio.Core + true + v4.8 + 12 + 512 + true + true + True + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Form + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + + + 13.0.3 + + + 1.9.2 + + + + + + {693aebc1-293d-4df0-bcae-26a1099fe7bb} + OMI Filetype Library + + + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PckStudio.Core/Properties/Resources.Designer.cs b/PckStudio.Core/Properties/Resources.Designer.cs new file mode 100644 index 00000000..af12b5e9 --- /dev/null +++ b/PckStudio.Core/Properties/Resources.Designer.cs @@ -0,0 +1,470 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PckStudio.Core.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PckStudio.Core.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap additional_map_icons_atlas { + get { + object obj = ResourceManager.GetObject("additional_map_icons_atlas", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to { + /// "COMMENT_1": "JSON by MattNL", + /// "entries": [ + /// { + /// "internalName": "base", + /// "displayName": "Base", + /// "hasColourEntry": true, + /// "colourEntry": { + /// "defaultName": "Banner_White", + /// "variants": [ + /// "Banner_Black", + /// "Banner_Blue", + /// "Banner_Brown", + /// "Banner_Cyan", + /// "Banner_Gray", + /// "Banner_Green", + /// "Banner_Light_Blue", + /// "Banner_Lime", + /// "Banner_Magenta", + /// "Banner_Orange", + /// "Banner_Pink", + /// "Banner_Purple", + /// "Banner_Red", + /// "Ban [rest of string was truncated]";. + /// + public static string bannerData { + get { + return ResourceManager.GetString("bannerData", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap banners_atlas { + get { + object obj = ResourceManager.GetObject("banners_atlas", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to { + /// "COMMENT_1": "Tile data research by MattNL", + /// "COMMENT_2": "JSON by PhoenixARC, MattNL, and NessieHax (Miku-666)", + /// "entries": [ + /// { + /// "internalName": "grass_top", + /// "displayName": "Grass Block (Top)", + /// "hasColourEntry": true, + /// "colourEntry": { + /// "defaultName": "Grass_Common", + /// "variants": [ + /// "Grass_Common", + /// "Grass_Mesa", + /// "Grass_Swamp1", + /// "Grass_Swamp2" + /// ] + /// } + /// }, + /// { + /// "internalName": "stone", + /// "displayName": "Stone" + /// }, + /// { + /// "internalName": [rest of string was truncated]";. + /// + public static string blockData { + get { + return ResourceManager.GetString("blockData", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap Comparison { + get { + object obj = ResourceManager.GetObject("Comparison", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap experience_orbs_atlas { + get { + object obj = ResourceManager.GetObject("experience_orbs_atlas", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to { + /// "COMMENT_1": "JSON by MattNL", + /// "entries": [ + /// { + /// "internalName": "experience_orb_0", + /// "displayName": "Experience Orb (Size 1)", + /// "hasColourEntry": true, + /// "colourEntry": { + /// "defaultName": "experience_orb", + /// "variants": ["experience_orb"] + /// } + /// }, + /// { + /// "internalName": "experience_orb_1", + /// "displayName": "Experience Orb (Size 2)", + /// "hasColourEntry": true, + /// "colourEntry": { + /// "defaultName": "experience_orb", + /// "variants": ["experience_orb"] + /// } + /// }, + /// { + /// " [rest of string was truncated]";. + /// + public static string experienceOrbData { + get { + return ResourceManager.GetString("experienceOrbData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "COMMENT_1": "JSON by MattNL", + /// "entries": [ + /// { + /// "internalName": "explosion_0", + /// "displayName": "Explosion (Stage 1)", + /// "hasColourEntry": true, + /// "colourEntry": { + /// "defaultName": "Particle_Explode", + /// "variants": [ + /// "Particle_Explode", + /// "Particle_HugeExplosion" + /// ] + /// } + /// }, + /// { + /// "internalName": "explosion_1", + /// "displayName": "Explosion (Stage 2)", + /// "hasColourEntry": true, + /// "colourEntry": { + /// "defaultName": "Particle_Explode", + /// "variants": [ + /// [rest of string was truncated]";. + /// + public static string explosionData { + get { + return ResourceManager.GetString("explosionData", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap explosions_atlas { + get { + object obj = ResourceManager.GetObject("explosions_atlas", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to { + /// "COMMENT_1": "Tile data research by MattNL", + /// "COMMENT_2": "JSON by PhoenixARC, MattNL, and NessieHax (Miku-666)", + /// "entries": [ + /// { + /// "internalName": "helmetCloth", + /// "displayName": "Leather Cap", + /// "allowCustomColour": true, + /// "hasColourEntry": true, + /// "colourEntry": { + /// "defaultName": "Armour_Default_Leather_Colour", + /// "variants": [ "Armour_Default_Leather_Colour" ] + /// } + /// }, + /// { + /// "internalName": "helmetChain", + /// "displayName": "Chain Helmet" + /// }, + /// { + /// "internalName": [rest of string was truncated]";. + /// + public static string itemData { + get { + return ResourceManager.GetString("itemData", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap items_atlas { + get { + object obj = ResourceManager.GetObject("items_atlas", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap map_icons_atlas { + get { + object obj = ResourceManager.GetObject("map_icons_atlas", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to { + /// "COMMENT_1": "JSON by MattNL", + /// "entries": [ + /// { + /// "internalName": "player_1", + /// "displayName": "Player 1" + /// }, + /// { + /// "internalName": "player_2", + /// "displayName": "Player 2" + /// }, + /// { + /// "internalName": "player_3", + /// "displayName": "Player 3" + /// }, + /// { + /// "internalName": "player_4", + /// "displayName": "Player 4" + /// }, + /// { + /// "internalName": "target_x", + /// "displayName": "Unused" + /// }, + /// { + /// "internalName": "target_point", + /// "displayName": "Target Point (Unused)" + /// }, + /// { + /// [rest of string was truncated]";. + /// + public static string mapIconData { + get { + return ResourceManager.GetString("mapIconData", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap moon_phases_atlas { + get { + object obj = ResourceManager.GetObject("moon_phases_atlas", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to { + /// "COMMENT_1": "JSON by MattNL", + /// "entries": [ + /// { + /// "internalName": "moon_phase_0", + /// "displayName": "Full Moon" + /// }, + /// { + /// "internalName": "moon_phase_1", + /// "displayName": "Waning Gibbous" + /// }, + /// { + /// "internalName": "moon_phase_2", + /// "displayName": "Last Quarter" + /// }, + /// { + /// "internalName": "moon_phase_3", + /// "displayName": "Waning Crescent" + /// }, + /// { + /// "internalName": "moon_phase_4", + /// "displayName": "New Moon" + /// }, + /// { + /// "internalName": "moon_phase_5", + /// "displayName": [rest of string was truncated]";. + /// + public static string moonPhaseData { + get { + return ResourceManager.GetString("moonPhaseData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "COMMENT_1": "JSON by MattNL", + /// "entries": [ + /// { + /// "internalName": "Kebab", + /// "displayName": "\"Kebab med tre pepperoni\" by Kristoffer Zetterstrand" + /// }, + /// { + /// "internalName": "Aztec", + /// "displayName": "\"de_aztec\" by Kristoffer Zetterstrand" + /// }, + /// { + /// "internalName": "Alban", + /// "displayName": "\"Albanian\" by Kristoffer Zetterstrand" + /// }, + /// { + /// "internalName": "Aztec2", + /// "displayName": "\"de_aztec\" by Kristoffer Zetterstrand" + /// }, + /// { + /// "internalName": "Bomb", + /// "disp [rest of string was truncated]";. + /// + public static string paintingData { + get { + return ResourceManager.GetString("paintingData", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap paintings_atlas { + get { + object obj = ResourceManager.GetObject("paintings_atlas", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to { + /// "COMMENT_1": "JSON by MattNL", + /// "entries": [ + /// { + /// "internalName": "generic_0", + /// "displayName": "Generic (Stage 1)", + /// "hasColourEntry": true, + /// "colourEntry": { + /// "defaultName": "None", + /// "variants": [ + /// "None", + /// "Particle_Smoke", + /// "Particle_NetherPortal", + /// "Particle_EnderPortal", + /// "Particle_Ender", + /// "Particle_DragonBreathMin", + /// "Particle_DragonBreathMax" + /// ] + /// } + /// }, + /// { + /// "internalName": "generic_1", + /// "displayName": "Generic (Stage 2)", + /// [rest of string was truncated]";. + /// + public static string particleData { + get { + return ResourceManager.GetString("particleData", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap particles_atlas { + get { + object obj = ResourceManager.GetObject("particles_atlas", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap terrain_atlas { + get { + object obj = ResourceManager.GetObject("terrain_atlas", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap TexturePackIcon { + get { + object obj = ResourceManager.GetObject("TexturePackIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/PckStudio.Core/Properties/Resources.resx b/PckStudio.Core/Properties/Resources.resx new file mode 100644 index 00000000..b1f785a9 --- /dev/null +++ b/PckStudio.Core/Properties/Resources.resx @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\additional_mapicons.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\bannerData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\banners.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\blockData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\Comparison.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\experienceOrbData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\experience_orbs.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\explosionData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\explosion.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\itemData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\items.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\mapIconData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\map_icons.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\moonPhaseData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\moon_phases.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\paintingData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\paintings.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\particleData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + + ..\Resources\particles.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\terrain.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\TexturePackIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/PCK-Studio/Internal/ResourceCategory.cs b/PckStudio.Core/ResourceCategory.cs similarity index 91% rename from PCK-Studio/Internal/ResourceCategory.cs rename to PckStudio.Core/ResourceCategory.cs index 8b8c1243..1512c8b7 100644 --- a/PCK-Studio/Internal/ResourceCategory.cs +++ b/PckStudio.Core/ResourceCategory.cs @@ -16,13 +16,15 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -namespace PckStudio.Internal +namespace PckStudio.Core { - internal enum ResourceCategory + public enum ResourceCategory { Unknown = -1, ItemAnimation, BlockAnimation, + MobEntityTextures, + ItemEntityTextures, ItemAtlas, BlockAtlas, ParticleAtlas, diff --git a/PckStudio.Core/ResourceLocation.cs b/PckStudio.Core/ResourceLocation.cs new file mode 100644 index 00000000..d633b8a6 --- /dev/null +++ b/PckStudio.Core/ResourceLocation.cs @@ -0,0 +1,208 @@ +/* Copyright (c) 2024-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.Drawing; +using System.Linq; +using PckStudio.Core.Json; +using PckStudio.Json; + +namespace PckStudio.Core +{ + public sealed class ResourceLocation + { + private static List ResourceGroups = new List(); + private static readonly ResourceLocation Unknown = new ResourceLocation(string.Empty, ResourceCategory.Unknown, -1); + + private static AtlasGroup[] _particaleAtlasGroups = + { + new AtlasGroupAnimation("generic" , row: 0, column: 0, frameCount: 8, ImageLayoutDirection.Horizontal, 2), + new AtlasGroupAnimation("splash" , row: 3, column: 1, frameCount: 4, ImageLayoutDirection.Horizontal, 2), + new AtlasGroupAnimation("drip" , row: 0, column: 7, frameCount: 3, ImageLayoutDirection.Horizontal, 4), + new AtlasGroupAnimation("effect" , row: 0, column: 8, frameCount: 8, ImageLayoutDirection.Horizontal, 2), + new AtlasGroupAnimation("splash_effect" , row: 0, column: 9, frameCount: 8, ImageLayoutDirection.Horizontal, 2), + new AtlasGroupAnimation("firework_spark" , row: 0, column: 10, frameCount: 8, ImageLayoutDirection.Horizontal, 2), + new AtlasGroupAnimation("glitter" , row: 0, column: 11, frameCount: 8, ImageLayoutDirection.Horizontal, 2), + new AtlasGroupAnimation("BE_explosion" , row: 0, column: 12, frameCount: 16, ImageLayoutDirection.Horizontal), + new AtlasGroupLargeTile("flash" , row: 4, column: 2, rowSpan: 4, columnSpan: 4), + new AtlasGroupLargeTileAnimation("bubble_pop", row: 6, column: 6, rowSpan: 2, columnSpan: 2, frameCount: 5, ImageLayoutDirection.Horizontal, 2), + }; + + private static AtlasGroup[] _terrainAtlasGroups = + { + new AtlasGroupLargeTile("Oak Door" , row: 1, column: 5, rowSpan: 1, columnSpan: 2), + new AtlasGroupLargeTile("Iron Door" , row: 2, column: 5, rowSpan: 1, columnSpan: 2), + new AtlasGroupLargeTile("Acacia Door" , row: 0, column: 23, rowSpan: 1, columnSpan: 2), + new AtlasGroupLargeTile("Birch Door" , row: 1, column: 23, rowSpan: 1, columnSpan: 2), + new AtlasGroupLargeTile("Dark Oak Door", row: 2, column: 23, rowSpan: 1, columnSpan: 2), + new AtlasGroupLargeTile("Jungle Door" , row: 3, column: 23, rowSpan: 1, columnSpan: 2), + new AtlasGroupLargeTile("Spruce Door" , row: 4, column: 23, rowSpan: 1, columnSpan: 2), + + new AtlasGroupLargeTile("Large Fern" , row: 0, column: 20, rowSpan: 1, columnSpan: 2), + new AtlasGroupLargeTile("Double Tall Grass", row: 1, column: 20, rowSpan: 1, columnSpan: 2), + new AtlasGroupLargeTile("Poeny" , row: 2, column: 20, rowSpan: 1, columnSpan: 2), + new AtlasGroupLargeTile("Rose Bush" , row: 3, column: 20, rowSpan: 1, columnSpan: 2), + new AtlasGroupLargeTile("Lilac" , row: 4, column: 20, rowSpan: 1, columnSpan: 2), + + new AtlasGroupAnimation("Wheat" , row: 8, column: 5, frameCount: 8, ImageLayoutDirection.Horizontal, 5), + new AtlasGroupAnimation("Potatoes" , row: 9, column: 16, frameCount: 4, ImageLayoutDirection.Horizontal, 5), + new AtlasGroupAnimation("Carrots" , row: 8, column: 12, frameCount: 4, ImageLayoutDirection.Horizontal, 5), + new AtlasGroupAnimation("Beetroots" , row: 0, column: 25, frameCount: 4, ImageLayoutDirection.Horizontal, 5), + new AtlasGroupAnimation("Nether Wart", row: 2, column: 14, frameCount: 3, ImageLayoutDirection.Horizontal, 5), + new AtlasGroupAnimation("Destroy" , row: 0, column: 15, frameCount: 10, ImageLayoutDirection.Horizontal, 3), + }; + + private static AtlasGroup[] _itemsAtlasGroups = + { + new AtlasGroupAnimation("Bow Pulling", row: 5, column: 6, frameCount: 3, ImageLayoutDirection.Vertical, 6), + }; + + private static AtlasGroup[] _paintingAtlasGroups = + { + new AtlasGroupLargeTile("The Pool" , row: 0, column: 2, rowSpan: 2, columnSpan: 1), + new AtlasGroupLargeTile("Bonjour Monsiuer Courbet", row: 2, column: 2, rowSpan: 2, columnSpan: 1), + new AtlasGroupLargeTile("Seaside" , row: 4, column: 2, rowSpan: 2, columnSpan: 1), + new AtlasGroupLargeTile("sunset_dense" , row: 6, column: 2, rowSpan: 2, columnSpan: 1), + new AtlasGroupLargeTile("Creebet" , row: 8, column: 2, rowSpan: 2, columnSpan: 1), + + new AtlasGroupLargeTile("Wanderer" , row: 0, column: 4, rowSpan: 1, columnSpan: 2), + new AtlasGroupLargeTile("Graham" , row: 1, column: 4, rowSpan: 1, columnSpan: 2), + + new AtlasGroupLargeTile("Fighters" , row: 0, column: 6, rowSpan: 4, columnSpan: 2), + + new AtlasGroupLargeTile("Match" , row: 0, column: 8, rowSpan: 2, columnSpan: 2), + new AtlasGroupLargeTile("Bust" , row: 2, column: 8, rowSpan: 2, columnSpan: 2), + new AtlasGroupLargeTile("The stage is set" , row: 4, column: 8, rowSpan: 2, columnSpan: 2), + new AtlasGroupLargeTile("The Void" , row: 6, column: 8, rowSpan: 2, columnSpan: 2), + new AtlasGroupLargeTile("Skull and Roses" , row: 8, column: 8, rowSpan: 2, columnSpan: 2), + new AtlasGroupLargeTile("Wither" , row: 10, column: 8, rowSpan: 2, columnSpan: 2), + + new AtlasGroupLargeTile("Mortal Coil" , row: 12, column: 4, rowSpan: 4, columnSpan: 3), + new AtlasGroupLargeTile("Kong" , row: 12, column: 7, rowSpan: 4, columnSpan: 3), + + new AtlasGroupLargeTile("Back Texture" , row: 12, column: 0, rowSpan: 4, columnSpan: 4), + new AtlasGroupLargeTile("Pointer" , row: 0, column: 12, rowSpan: 4, columnSpan: 4), + new AtlasGroupLargeTile("Pigscene" , row: 4, column: 12, rowSpan: 4, columnSpan: 4), + new AtlasGroupLargeTile("Skull On Fire" , row: 8, column: 12, rowSpan: 4, columnSpan: 4), + }; + + private static readonly Dictionary _categoryLookUp = new Dictionary() + { + ["textures/items"] = new ResourceLocation("textures/items", ResourceCategory.ItemAnimation, 16, isGroup: true), + ["textures/blocks"] = new ResourceLocation("textures/blocks", ResourceCategory.BlockAnimation, 16, isGroup: true), + ["mob"] = new ResourceLocation("mob", ResourceCategory.MobEntityTextures, 1, isGroup: true), + ["item"] = new ResourceLocation("item", ResourceCategory.ItemEntityTextures, 1, isGroup: true), + ["terrain.png"] = new ResourceLocation("terrain.png", ResourceCategory.BlockAtlas, 16, tilesInfo: Tiles.BlockTileInfos, atlasGroups: _terrainAtlasGroups), + ["items.png"] = new ResourceLocation("items.png", ResourceCategory.ItemAtlas, 16, tilesInfo: Tiles.ItemTileInfos, atlasGroups: _itemsAtlasGroups), + ["particles.png"] = new ResourceLocation("particles.png", ResourceCategory.ParticleAtlas, 16, tilesInfo: Tiles.ParticleTileInfos, atlasGroups: _particaleAtlasGroups), + //============ TODO ============// + ["item/banner/Banner_Atlas.png"] = new ResourceLocation("item/banner/Banner_Atlas.png", ResourceCategory.BannerAtlas, new Size(6, 7), TillingMode.WidthAndHeight, tilesInfo: Tiles.BannerTileInfos), + //==============================// + ["art/kz.png"] = new ResourceLocation("art/kz.png", ResourceCategory.PaintingAtlas, 16, tilesInfo: Tiles.PaintingTileInfos, atlasGroups: _paintingAtlasGroups), + ["misc/explosion.png"] = new ResourceLocation("misc/explosion.png", ResourceCategory.ExplosionAtlas, 16, tilesInfo: Tiles.ExplosionTileInfos), + ["item/xporb.png"] = new ResourceLocation("item/xporb.png", ResourceCategory.ExperienceOrbAtlas, 4, tilesInfo: Tiles.ExperienceOrbTileInfos), + ["terrain/moon_phases.png"] = new ResourceLocation("terrain/moon_phases.png", ResourceCategory.MoonPhaseAtlas, 4, tilesInfo: Tiles.MoonPhaseTileInfos), + ["misc/mapicons.png"] = new ResourceLocation("misc/mapicons.png", ResourceCategory.MapIconAtlas, 4, tilesInfo: Tiles.MapIconTileInfos), + ["misc/additionalmapicons.png"] = new ResourceLocation("misc/additionalmapicons.png", ResourceCategory.AdditionalMapIconsAtlas, 4, tilesInfo: Tiles.AdditionalMapIconTileInfos), + }; + + public static string GetPathFromCategory(ResourceCategory category) + { + return category switch + { + ResourceCategory.ItemAnimation => _categoryLookUp["textures/items"].ToString(), + ResourceCategory.BlockAnimation => _categoryLookUp["textures/blocks"].ToString(), + ResourceCategory.MobEntityTextures => _categoryLookUp["mob"].ToString(), + ResourceCategory.ItemEntityTextures => _categoryLookUp["item"].ToString(), + ResourceCategory.BlockAtlas => _categoryLookUp["terrain.png"].ToString(), + ResourceCategory.ItemAtlas => _categoryLookUp["items.png"].ToString(), + ResourceCategory.ParticleAtlas => _categoryLookUp["particles.png"].ToString(), + ResourceCategory.BannerAtlas => _categoryLookUp["item/banner/Banner_Atlas.png"].ToString(), + ResourceCategory.PaintingAtlas => _categoryLookUp["art/kz.png"].ToString(), + ResourceCategory.ExplosionAtlas => _categoryLookUp["misc/explosion.png"].ToString(), + ResourceCategory.ExperienceOrbAtlas => _categoryLookUp["item/xporb.png"].ToString(), + ResourceCategory.MoonPhaseAtlas => _categoryLookUp["terrain/moon_phases.png"].ToString(), + ResourceCategory.MapIconAtlas => _categoryLookUp["misc/mapicons.png"].ToString(), + ResourceCategory.AdditionalMapIconsAtlas => _categoryLookUp["misc/additionalmapicons.png"].ToString(), + _ => string.Empty + }; + } + + public static ResourceCategory GetCategoryFromPath(string path) => GetFromPath(path).Category; + + public static ResourceLocation GetFromPath(string path) + { + if (string.IsNullOrWhiteSpace(path) || !path.StartsWith("res/")) + return Unknown; + string categoryPath = path.Substring("res/".Length); + if (_categoryLookUp.ContainsKey(categoryPath)) + return _categoryLookUp[categoryPath]; + return ResourceGroups.Where(group => categoryPath.StartsWith(group.Path)).FirstOrDefault() ?? Unknown; + } + + public enum TillingMode + { + Width, + Height, + WidthAndHeight + } + + public string Path { get; } + public ResourceCategory Category { get; } + public Size TillingFactor { get; } + public TillingMode Tilling { get; } + public bool IsGroup { get; } + public IEnumerable TilesInfo { get; } + public IEnumerable AtlasGroups { get; } + + public Size GetTileArea(Size imgSize) + { + return Tilling switch + { + TillingMode.Width => new Size(imgSize.Width / TillingFactor.Width, imgSize.Width / TillingFactor.Height), + TillingMode.Height => new Size(imgSize.Height / TillingFactor.Width, imgSize.Height / TillingFactor.Height), + TillingMode.WidthAndHeight => new Size(imgSize.Width / TillingFactor.Width, imgSize.Height / TillingFactor.Height), + _ => Size.Empty, + }; + } + + private ResourceLocation(string path, ResourceCategory category, int tillingFactor, TillingMode tilling = TillingMode.Width, bool isGroup = false, IEnumerable tilesInfo = default, IEnumerable atlasGroups = default) + : this(path, category, new Size(tillingFactor, tillingFactor), tilling, isGroup, tilesInfo, atlasGroups) + { + } + + + private ResourceLocation(string path, ResourceCategory category, Size tillingFactor, TillingMode tilling = TillingMode.Width, bool isGroup = false, IEnumerable tilesInfo = default, IEnumerable atlasGroups = default) + { + Path = path; + Category = category; + TillingFactor = new Size(Math.Max(1, tillingFactor.Width), Math.Max(1, tillingFactor.Height)); + Tilling = tilling; + IsGroup = isGroup; + TilesInfo = tilesInfo ?? Enumerable.Empty(); + AtlasGroups = atlasGroups ?? Enumerable.Empty(); + if (isGroup) + ResourceGroups.Add(this); + } + + public override string ToString() + { + return "res/" + Path; + } + } +} diff --git a/PckStudio.Core/Resources/Comparison.png b/PckStudio.Core/Resources/Comparison.png new file mode 100644 index 00000000..144a16a3 Binary files /dev/null and b/PckStudio.Core/Resources/Comparison.png differ diff --git a/PckStudio.Core/Resources/TexturePackIcon.png b/PckStudio.Core/Resources/TexturePackIcon.png new file mode 100644 index 00000000..5ee74794 Binary files /dev/null and b/PckStudio.Core/Resources/TexturePackIcon.png differ diff --git a/PckStudio.Core/Resources/additional_mapicons.png b/PckStudio.Core/Resources/additional_mapicons.png new file mode 100644 index 00000000..11b7256a Binary files /dev/null and b/PckStudio.Core/Resources/additional_mapicons.png differ diff --git a/PckStudio.Core/Resources/bannerData.json b/PckStudio.Core/Resources/bannerData.json new file mode 100644 index 00000000..f1de015f --- /dev/null +++ b/PckStudio.Core/Resources/bannerData.json @@ -0,0 +1,1053 @@ +{ + "COMMENT_1": "JSON by MattNL", + "entries": [ + { + "internalName": "base", + "displayName": "Base", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "border", + "displayName": "Bordure", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "bricks", + "displayName": "Field Masoned", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "circle", + "displayName": "Roundel", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "creeper", + "displayName": "Creeper Charge", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "cross", + "displayName": "Saltire", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "curly_border", + "displayName": "Bordure Indented", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "diagonal_left", + "displayName": "Per Bend Sinister", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "diagonal_right", + "displayName": "Per Bend", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "diagonal_up_left", + "displayName": "Per Bend Inverted", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "diagonal_up_right", + "displayName": "Per Bend Sinister Inverted", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "flower", + "displayName": "Flower Charge", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "gradient", + "displayName": "Gradient", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "gradient_up", + "displayName": "Base Gradient", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "half_horizontal", + "displayName": "Per Fess", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "half_horizontal_bottom", + "displayName": "Per Fess Inverted", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "half_vertical", + "displayName": "Per Pale", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "half_vertical_right", + "displayName": "Per Pale Inverted", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "mojang", + "displayName": "Thing", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "rhombus", + "displayName": "Lozenge", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "skull", + "displayName": "Skull Charge", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "small_stripes", + "displayName": "Paly", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "square_bottom_left", + "displayName": "Base Dexter Canton", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "square_bottom_right", + "displayName": "Base Sinister Canton", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "square_top_left", + "displayName": "Chief Dexter Canton", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "square_top_right", + "displayName": "Chief Sinister Canton", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "straight_cross", + "displayName": "Cross", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "stripe_bottom", + "displayName": "Base Fess", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "stripe_center", + "displayName": "Pale", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "strip_downleft", + "displayName": "Bend Sinister", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "stripe_downright", + "displayName": "Bend", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "stripe_left", + "displayName": "Pale Dexter", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "stripe_middle", + "displayName": "Fess", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "stripe_right", + "displayName": "Pale Sinister", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "stripe_top", + "displayName": "Chief Fess", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "triangle_bottom", + "displayName": "Chevron", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "triangle_top", + "displayName": "Inverted Chevron", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "triangles_bottom", + "displayName": "Base Indented", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "triangles_top", + "displayName": "Chief Indented", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + }, + { + "internalName": "mask", + "displayName": "Mask" + }, + { + "internalName": "illager", + "displayName": "Ominous Banner [PS4 ONLY]" + }, + { + "internalName": "globe", + "displayName": "Globe [PS4 ONLY]", + + "colourEntry": { + "defaultName": "Banner_White", + "variants": [ + "Banner_Black", + "Banner_Blue", + "Banner_Brown", + "Banner_Cyan", + "Banner_Gray", + "Banner_Green", + "Banner_Light_Blue", + "Banner_Lime", + "Banner_Magenta", + "Banner_Orange", + "Banner_Pink", + "Banner_Purple", + "Banner_Red", + "Banner_Silver", + "Banner_White", + "Banner_Yellow" + ] + } + } + ] +} diff --git a/PckStudio.Core/Resources/banners.png b/PckStudio.Core/Resources/banners.png new file mode 100644 index 00000000..952a0eff Binary files /dev/null and b/PckStudio.Core/Resources/banners.png differ diff --git a/PckStudio.Core/Resources/blockData.json b/PckStudio.Core/Resources/blockData.json new file mode 100644 index 00000000..d4622c10 --- /dev/null +++ b/PckStudio.Core/Resources/blockData.json @@ -0,0 +1,2922 @@ +{ + "COMMENT_1": "Tile data research by MattNL", + "COMMENT_2": "JSON by PhoenixARC, MattNL, and NessieHax (Miku-666)", + "entries": [ + { + "internalName": "grass_top", + "displayName": "Grass Block (Top)", + + "colourEntry": { + "defaultName": "Grass_Common", + "variants": [ + "Grass_Common", + "Grass_Mesa", + "Grass_Swamp1", + "Grass_Swamp2" + ] + } + }, + { + "internalName": "stone", + "displayName": "Stone" + }, + { + "internalName": "dirt", + "displayName": "Dirt" + }, + { + "internalName": "grass_side", + "displayName": "Grass Block (Side)" + }, + { + "internalName": "planks_oak", + "displayName": "Oak Planks" + }, + { + "internalName": "stoneslab_side", + "displayName": "Stone Slab (Side)" + }, + { + "internalName": "stoneslab_top", + "displayName": "Stone Slab (Top)" + }, + { + "internalName": "brick", + "displayName": "Bricks" + }, + { + "internalName": "tnt_side", + "displayName": "TNT (Side)" + }, + { + "internalName": "tnt_top", + "displayName": "TNT (Top)" + }, + { + "internalName": "tnt_bottom", + "displayName": "TNT (Bottom)" + }, + { + "internalName": "web", + "displayName": "Cobweb" + }, + { + "internalName": "flower_rose", + "displayName": "Poppy" + }, + { + "internalName": "flower_dandelion", + "displayName": "Dandelion" + }, + { + "internalName": "portal", + "displayName": "Nether Portal" + }, + { + "internalName": "sapling", + "displayName": "Oak Sapling" + }, + { + "internalName": "cobblestone", + "displayName": "Cobblestone" + }, + { + "internalName": "bedrock", + "displayName": "Bedrock" + }, + { + "internalName": "sand", + "displayName": "Sand" + }, + { + "internalName": "gravel", + "displayName": "Gravel" + }, + { + "internalName": "log_oak", + "displayName": "Oak Wood (Side)" + }, + { + "internalName": "log_oak_top", + "displayName": "Oak Wood (Top)" + }, + { + "internalName": "iron_block", + "displayName": "Block of Iron" + }, + { + "internalName": "gold_block", + "displayName": "Block of Gold" + }, + { + "internalName": "diamond_block", + "displayName": "Block of Diamond" + }, + { + "internalName": "emerald_block", + "displayName": "Block of Emerald" + }, + { + "internalName": "redstone_block", + "displayName": "Block of Redstone" + }, + { + "internalName": "dropper_front_horizontal", + "displayName": "Dropper (Front)" + }, + { + "internalName": "mushroom_red", + "displayName": "Mushroom (Red)" + }, + { + "internalName": "mushroom_brown", + "displayName": "Mushroom (Brown)" + }, + { + "internalName": "sapling_jungle", + "displayName": "Jungle Tree Sapling" + }, + { + "internalName": "fire_0", + "displayName": "Fire (Layer 1)" + }, + { + "internalName": "gold_ore", + "displayName": "Gold Ore" + }, + { + "internalName": "iron_ore", + "displayName": "Iron Ore" + }, + { + "internalName": "coal_ore", + "displayName": "Coal Ore" + }, + { + "internalName": "bookshelf", + "displayName": "Bookshelf" + }, + { + "internalName": "cobblestone_mossy", + "displayName": "Moss Stone" + }, + { + "internalName": "obsidian", + "displayName": "Obsidian" + }, + { + "internalName": "grass_side_overlay", + "displayName": "Grass Side (Overlay)", + + "colourEntry": { + "defaultName": "Grass_Common", + "variants": [ + "Grass_Common", + "Grass_Mesa", + "Grass_Swamp1", + "Grass_Swamp2" + ] + } + }, + { + "internalName": "tallgrass", + "displayName": "Tall Grass", + + "colourEntry": { + "defaultName": "Grass_Common", + "variants": [ + "Grass_Common", + "Grass_Mesa", + "Grass_Swamp1", + "Grass_Swamp2" + ] + } + }, + { + "internalName": "dispenser_front_vertical", + "displayName": "Dispenser (Vertical) (Front)" + }, + { + "internalName": "beacon", + "displayName": "Beacon" + }, + { + "internalName": "dropper_front_vertical", + "displayName": "Dropper (Vertical) (Front)" + }, + { + "internalName": "workbench_top", + "displayName": "Crafting Table (Top)" + }, + { + "internalName": "furnace_front", + "displayName": "Furnace (Front)" + }, + { + "internalName": "furnace_side", + "displayName": "Furnace/Dispenser/Dropper (Side)" + }, + { + "internalName": "dispenser_front", + "displayName": "Dispenser (Front)" + }, + { + "internalName": "fire_1", + "displayName": "Fire (Layer 2)" + }, + { + "internalName": "sponge", + "displayName": "Sponge" + }, + { + "internalName": "glass", + "displayName": "Glass" + }, + { + "internalName": "diamond_ore", + "displayName": "Diamond Ore" + }, + { + "internalName": "redstone_ore", + "displayName": "Redstone Ore" + }, + { + "internalName": "leaves", + "displayName": "Oak Leaves", + + "colourEntry": { + "defaultName": "Foliage_Default", + "variants": [ + "Foliage_Default", + "Foliage_Evergreen", + "Foliage_Birch", + "Foliage_Mesa", + "Foliage_Swampland" + ] + } + }, + { + "internalName": "leaves_opaque", + "displayName": "Oak Leaves (Opaque)", + + "colourEntry": { + "defaultName": "Foliage_Default", + "variants": [ + "Foliage_Default", + "Foliage_Evergreen", + "Foliage_Birch", + "Foliage_Mesa", + "Foliage_Swampland" + ] + } + }, + { + "internalName": "stonebrick", + "displayName": "Stone Bricks" + }, + { + "internalName": "deadbush", + "displayName": "Dead Bush/Shrub" + }, + { + "internalName": "fern", + "displayName": "Fern", + + "colourEntry": { + "defaultName": "Grass_Common", + "variants": [ + "Grass_Common", + "Grass_Mesa", + "Grass_Swamp1", + "Grass_Swamp2" + ] + } + }, + { + "internalName": "daylight_detector_top", + "displayName": "Daylight Sensor (Top)" + }, + { + "internalName": "daylight_detector_side", + "displayName": "Daylight Sensor (Side)" + }, + { + "internalName": "workbench_side", + "displayName": "Crafting Table (Side)" + }, + { + "internalName": "workbench_front", + "displayName": "Crafting Table (Front)" + }, + { + "internalName": "furnace_front_lit", + "displayName": "Furnace (Lit) (Front)" + }, + { + "internalName": "furnace_top", + "displayName": "Furnace/Dispenser/Dropper (Top)" + }, + { + "internalName": "sapling_spruce", + "displayName": "Spruce Sapling" + }, + { + "internalName": "wool_colored_white", + "displayName": "White Wool" + }, + { + "internalName": "mob_spawner", + "displayName": "Monster Spawner" + }, + { + "internalName": "snow", + "displayName": "Snow" + }, + { + "internalName": "ice", + "displayName": "Ice" + }, + { + "internalName": "snow_side", + "displayName": "Grass Block (Snowy) (Side)" + }, + { + "internalName": "cactus_top", + "displayName": "Cactus (Top)" + }, + { + "internalName": "cactus_side", + "displayName": "Cactus (Side)" + }, + { + "internalName": "cactus_bottom", + "displayName": "Cactus (Bottom)" + }, + { + "internalName": "clay", + "displayName": "Clay" + }, + { + "internalName": "reeds", + "displayName": "Sugar Canes" + }, + { + "internalName": "jukebox_side", + "displayName": "Jukebox (Side)" + }, + { + "internalName": "jukebox_top", + "displayName": "Jukebox (Top)" + }, + { + "internalName": "waterlily", + "displayName": "Lily Pad", + + "colourEntry": { + "defaultName": "Tile_WaterLily", + "variants": [ "Tile_WaterLily" ] + } + }, + { + "internalName": "mycel_side", + "displayName": "Mycelium (Side)" + }, + { + "internalName": "mycel_top", + "displayName": "Mycelium (Top)" + }, + { + "internalName": "sapling_birch", + "displayName": "Birch Sapling" + }, + { + "internalName": "torch_on", + "displayName": "Torch" + }, + { + "internalName": "door_wood_upper", + "displayName": "Oak Door (Top)" + }, + { + "internalName": "door_iron_upper", + "displayName": "Iron Door (Top)" + }, + { + "internalName": "ladder", + "displayName": "Ladder" + }, + { + "internalName": "trapdoor", + "displayName": "Oak Trapdoor" + }, + { + "internalName": "iron_bars", + "displayName": "Iron Bars" + }, + { + "internalName": "farmland_wet", + "displayName": "Farmland (Wet)" + }, + { + "internalName": "farmland_dry", + "displayName": "Farmland" + }, + { + "internalName": "crops_0", + "displayName": "Wheat (Stage 1)" + }, + { + "internalName": "crops_1", + "displayName": "Wheat (Stage 2)" + }, + { + "internalName": "crops_2", + "displayName": "Wheat (Stage 3)" + }, + { + "internalName": "crops_3", + "displayName": "Wheat (Stage 4)" + }, + { + "internalName": "crops_4", + "displayName": "Wheat (Stage 5)" + }, + { + "internalName": "crops_5", + "displayName": "Wheat (Stage 6)" + }, + { + "internalName": "crops_6", + "displayName": "Wheat (Stage 7)" + }, + { + "internalName": "crops_7", + "displayName": "Wheat (Stage 8)" + }, + { + "internalName": "lever", + "displayName": "Lever" + }, + { + "internalName": "door_wood_lower", + "displayName": "Oak Door (Bottom)" + }, + { + "internalName": "door_iron_lower", + "displayName": "Iron Door (Bottom)" + }, + { + "internalName": "redstone_torch_on", + "displayName": "Redstone Torch" + }, + { + "internalName": "stonebrick_mossy", + "displayName": "Mossy Stone Bricks" + }, + { + "internalName": "stonebrick_cracked", + "displayName": "Cracked Stone Bricks" + }, + { + "internalName": "pumpkin_top", + "displayName": "Pumpkin (Top)" + }, + { + "internalName": "netherrack", + "displayName": "Netherrack" + }, + { + "internalName": "soul_sand", + "displayName": "Soul Sand" + }, + { + "internalName": "glowstone", + "displayName": "Glowstone" + }, + { + "internalName": "piston_top_sticky", + "displayName": "Sticky Piston (Top)" + }, + { + "internalName": "piston_top", + "displayName": "Piston (Top)" + }, + { + "internalName": "piston_side", + "displayName": "Piston (Side)" + }, + { + "internalName": "piston_bottom", + "displayName": "Piston (Bottom)" + }, + { + "internalName": "piston_inner_top", + "displayName": "Piston (Inside)" + }, + { + "internalName": "stem_straight", + "displayName": "Stem", + + "colourEntry": { + "defaultName": "Tile_StemMin", + "variants": [ + "Tile_StemMin", + "Tile_StemMax" + ] + } + }, + { + "internalName": "rail_normal_turned", + "displayName": "Rail (Turned)" + }, + { + "internalName": "wool_colored_black", + "displayName": "Black Wool" + }, + { + "internalName": "wool_colored_gray", + "displayName": "Gray Wool" + }, + { + "internalName": "redstone_torch_off", + "displayName": "Redstone Torch (Off)" + }, + { + "internalName": "log_spruce", + "displayName": "Spruce Wood (Side)" + }, + { + "internalName": "log_birch", + "displayName": "Birch Wood (Side)" + }, + { + "internalName": "pumpkin_side", + "displayName": "Pumpkin (Side)" + }, + { + "internalName": "pumpkin_face_off", + "displayName": "Carved Pumpkin" + }, + { + "internalName": "pumpkin_face_on", + "displayName": "Jack-O-Lantern" + }, + { + "internalName": "cake_top", + "displayName": "Cake (Top)" + }, + { + "internalName": "cake_side", + "displayName": "Cake (Side)" + }, + { + "internalName": "cake_inner", + "displayName": "Cake (Inside)" + }, + { + "internalName": "cake_bottom", + "displayName": "Cake (Bottom)" + }, + { + "internalName": "mushroom_block_skin_red", + "displayName": "Mushroom (Red Block)" + }, + { + "internalName": "mushroom_block_skin_brown", + "displayName": "Mushroom (Brown Block)" + }, + { + "internalName": "stem_bent", + "displayName": "Stem (Attached)", + + "colourEntry": { + "defaultName": "Tile_StemMin", + "variants": [ + "Tile_StemMin", + "Tile_StemMax" + ] + } + }, + { + "internalName": "rail_normal", + "displayName": "Rail" + }, + { + "internalName": "wool_colored_red", + "displayName": "Red Wool" + }, + { + "internalName": "wool_colored_pink", + "displayName": "Pink Wool" + }, + { + "internalName": "repeater_off", + "displayName": "Repeater" + }, + { + "internalName": "leaves_spruce", + "displayName": "Spruce Leaves", + + "colourEntry": { + "defaultName": "Foliage_Evergreen", + "variants": [ + "Foliage_Default", + "Foliage_Evergreen", + "Foliage_Birch", + "Foliage_Mesa", + "Foliage_Swampland" + ] + } + }, + { + "internalName": "leaves_spruce_opaque", + "displayName": "Spruce Leaves (Opaque)", + + "colourEntry": { + "defaultName": "Foliage_Evergreen", + "variants": [ + "Foliage_Default", + "Foliage_Evergreen", + "Foliage_Birch", + "Foliage_Mesa", + "Foliage_Swampland" + ] + } + }, + { + "internalName": "conduit_top", + "displayName": "Conduit (Break Particles)" + }, + { + "internalName": "turtle_egg_hatch_0", + "displayName": "Sea Turtle Egg (Stage 1)" + }, + { + "internalName": "melon_side", + "displayName": "Melon (Side)" + }, + { + "internalName": "melon_top", + "displayName": "Melon (Top)" + }, + { + "internalName": "cauldron_top", + "displayName": "Cauldron (Top)" + }, + { + "internalName": "cauldron_inner", + "displayName": "Cauldron (Inside)" + }, + { + "internalName": "sponge_wet", + "displayName": "Wet Sponge" + }, + { + "internalName": "mushroom_block_skin_stem", + "displayName": "Mushroom (Stem Block)" + }, + { + "internalName": "mushroom_block_inside", + "displayName": "Mushroom (Inside Block)" + }, + { + "internalName": "vine", + "displayName": "Vines", + + "colourEntry": { + "defaultName": "Foliage_Default", + "variants": [ + "Foliage_Default", + "Foliage_Evergreen", + "Foliage_Birch", + "Foliage_Mesa", + "Foliage_Swampland" + ] + } + }, + { + "internalName": "lapis_block", + "displayName": "Lapis Lazuli Block" + }, + { + "internalName": "wool_colored_green", + "displayName": "Green Wool" + }, + { + "internalName": "wool_colored_lime", + "displayName": "Lime Wool" + }, + { + "internalName": "repeater_on", + "displayName": "Redstone Repeater (On)" + }, + { + "internalName": "glass_pane_top", + "displayName": "Glass Pane (Top)" + }, + { + "internalName": "chest_top", + "displayName": "Chest (Break Particles)" + }, + { + "internalName": "ender_chest_top", + "displayName": "Ender Chest (Break Particles)" + }, + { + "internalName": "turtle_egg_hatch_1", + "displayName": "Sea Turtle Egg (Stage 2)" + }, + { + "internalName": "turtle_egg_hatch_2", + "displayName": "Sea Turtle Egg (Stage 3)" + }, + { + "internalName": "log_jungle", + "displayName": "Jungle Wood (Side)" + }, + { + "internalName": "cauldron_side", + "displayName": "Cauldron (Side)" + }, + { + "internalName": "cauldron_bottom", + "displayName": "Cauldron (Bottom)" + }, + { + "internalName": "brewing_stand_base", + "displayName": "Brewing Stand (Base)" + }, + { + "internalName": "brewing_stand", + "displayName": "Brewing Stand" + }, + { + "internalName": "endframe_top", + "displayName": "End Portal Frame (Top)" + }, + { + "internalName": "endframe_side", + "displayName": "End Portal Frame (Side)" + }, + { + "internalName": "lapis_ore", + "displayName": "Lapis Lazuli Ore" + }, + { + "internalName": "wool_colored_brown", + "displayName": "Brown Wool" + }, + { + "internalName": "wool_colored_yellow", + "displayName": "Yellow Wool" + }, + { + "internalName": "rail_golden", + "displayName": "Powered Rail" + }, + { + "internalName": "redstone_dust_cross", + "displayName": "Redstone Dust (Cross)", + + "colourEntry": { + "defaultName": "Tile_RedstoneDust", + "variants": [ + "Tile_RedstoneDust", + "Tile_RedstoneDustUnlit", + "Tile_RedstoneDustLitMin", + "Tile_RedstoneDustLitMax" + ] + } + }, + { + "internalName": "redstone_dust_line", + "displayName": "Redstone Dust (Line)", + + "colourEntry": { + "defaultName": "Tile_RedstoneDust", + "variants": [ + "Tile_RedstoneDust", + "Tile_RedstoneDustUnlit", + "Tile_RedstoneDustLitMin", + "Tile_RedstoneDustLitMax" + ] + } + }, + { + "internalName": "enchantment_top", + "displayName": "Enchantment Table (Top)" + }, + { + "internalName": "dragon_egg", + "displayName": "Dragon Egg" + }, + { + "internalName": "cocoa_2", + "displayName": "Cocoa (Stage 3)" + }, + { + "internalName": "cocoa_1", + "displayName": "Cocoa (Stage 2)" + }, + { + "internalName": "cocoa_0", + "displayName": "Cocoa (Stage 1)" + }, + { + "internalName": "emerald_ore", + "displayName": "Emerald Ore" + }, + { + "internalName": "trip_wire_source", + "displayName": "Tripwire Hook" + }, + { + "internalName": "trip_wire", + "displayName": "Tripwire" + }, + { + "internalName": "endframe_eye", + "displayName": "End Portal Frame (Eye)" + }, + { + "internalName": "end_stone", + "displayName": "End Stone" + }, + { + "internalName": "sandstone_top", + "displayName": "Sandstone (Top)" + }, + { + "internalName": "wool_colored_blue", + "displayName": "Blue Wool" + }, + { + "internalName": "wool_colored_light_blue", + "displayName": "Light Blue Wool" + }, + { + "internalName": "rail_golden_powered", + "displayName": "Powered Rail (On)" + }, + { + "internalName": "redstone_dust_cross_overlay", + "displayName": "Redstone Dust (Cross) (Overlay)" + }, + { + "internalName": "redstone_dust_line_overlay", + "displayName": "Redstone Dust (Line) (Overlay)" + }, + { + "internalName": "enchantment_side", + "displayName": "Enchantment Table (Side)" + }, + { + "internalName": "enchantment_bottom", + "displayName": "Enchantment Table (Bottom)" + }, + { + "internalName": "diamondRing", + "displayName": "Diamond Score Ring" + }, + { + "internalName": "itemframe_back", + "displayName": "Item Frame" + }, + { + "internalName": "flower_pot", + "displayName": "Flower Pot" + }, + { + "internalName": "comparator_off", + "displayName": "Redstone Comparator" + }, + { + "internalName": "comparator_on", + "displayName": "Redstone Comparator (On)" + }, + { + "internalName": "rail_activator", + "displayName": "Activator Rail" + }, + { + "internalName": "rail_activator_powered", + "displayName": "Activator Rail (On)" + }, + { + "internalName": "quartz_ore", + "displayName": "Nether Quartz Ore" + }, + { + "internalName": "sandstone_side", + "displayName": "Sandstone (Side)" + }, + { + "internalName": "wool_colored_purple", + "displayName": "Purple Wool" + }, + { + "internalName": "wool_colored_magenta", + "displayName": "Magenta Wool" + }, + { + "internalName": "detectorRail", + "displayName": "Detector Rail" + }, + { + "internalName": "leaves_jungle", + "displayName": "Jungle Leaves", + + "colourEntry": { + "defaultName": "Foliage_Default", + "variants": [ + "Foliage_Default", + "Foliage_Evergreen", + "Foliage_Birch", + "Foliage_Mesa", + "Foliage_Swampland" + ] + } + }, + { + "internalName": "leaves_jungle_opaque", + "displayName": "Jungle Leaves (Opaque)", + + "colourEntry": { + "defaultName": "Foliage_Default", + "variants": [ + "Foliage_Default", + "Foliage_Evergreen", + "Foliage_Birch", + "Foliage_Mesa", + "Foliage_Swampland" + ] + } + }, + { + "internalName": "planks_spruce", + "displayName": "Spruce Planks" + }, + { + "internalName": "planks_jungle", + "displayName": "Jungle Planks" + }, + { + "internalName": "carrots_stage_0", + "displayName": "Carrots (Stage 1)" + }, + { + "internalName": "carrots_stage_1", + "displayName": "Carrots (Stage 2)" + }, + { + "internalName": "carrots_stage_2", + "displayName": "Carrots (Stage 3)" + }, + { + "internalName": "carrots_stage_3", + "displayName": "Carrots (Stage 4)" + }, + { + "internalName": "slime", + "displayName": "Slime Block" + }, + { + "internalName": "water", + "displayName": "Water", + + "colourEntry": { + "isWaterColour": true, + "defaultName": "Water_Plains", + "variants": [ + "Water_Ocean", + "Water_Plains", + "Water_Desert", + "Water_ExtremeHills", + "Water_Forest", + "Water_Taiga", + "Water_Swampland", + "Water_River", + "Water_Hell", + "Water_Sky", + "Water_FrozenOcean", + "Water_FrozenRiver", + "Water_IcePlains", + "Water_IceMountains", + "Water_MushroomIsland", + "Water_MushroomIslandShore", + "Water_Beach", + "Water_DesertHills", + "Water_ForestHills", + "Water_TaigaHills", + "Water_ExtremeHillsEdge", + "Water_Jungle", + "Water_JungleHills", + "Water_JungleEdge", + "Water_DeepOcean", + "Water_StoneBeach", + "Water_ColdBeach", + "Water_BirchForest", + "Water_BirchForestHills", + "Water_RoofedForest", + "Water_ColdTaiga", + "Water_ColdTaigaHills", + "Water_MegaTaiga", + "Water_MegaTaigaHills", + "Water_ExtremeHillsPlus", + "Water_Savanna", + "Water_SavannaPlateau", + "Water_Mesa", + "Water_MesaPlateauF", + "Water_MesaPlateau" + ] + } + }, + { + "internalName": "water_flow", + "displayName": "Flowing Water", + + "width": 2, + "height": 2, + "colourEntry": { + "isWaterColour": true, + "defaultName": "Water_Plains", + "variants": [ + "Water_Ocean", + "Water_Plains", + "Water_Desert", + "Water_ExtremeHills", + "Water_Forest", + "Water_Taiga", + "Water_Swampland", + "Water_River", + "Water_Hell", + "Water_Sky", + "Water_FrozenOcean", + "Water_FrozenRiver", + "Water_IcePlains", + "Water_IceMountains", + "Water_MushroomIsland", + "Water_MushroomIslandShore", + "Water_Beach", + "Water_DesertHills", + "Water_ForestHills", + "Water_TaigaHills", + "Water_ExtremeHillsEdge", + "Water_Jungle", + "Water_JungleHills", + "Water_JungleEdge", + "Water_DeepOcean", + "Water_StoneBeach", + "Water_ColdBeach", + "Water_BirchForest", + "Water_BirchForestHills", + "Water_RoofedForest", + "Water_ColdTaiga", + "Water_ColdTaigaHills", + "Water_MegaTaiga", + "Water_MegaTaigaHills", + "Water_ExtremeHillsPlus", + "Water_Savanna", + "Water_SavannaPlateau", + "Water_Mesa", + "Water_MesaPlateauF", + "Water_MesaPlateau" + ] + } + }, + { + "internalName": "water_flow", + "displayName": "" + }, + { + "internalName": "sandstone_bottom", + "displayName": "Sandstone (Bottom)" + }, + { + "internalName": "wool_colored_cyan", + "displayName": "Cyan Wool" + }, + { + "internalName": "wool_colored_orange", + "displayName": "Orange Wool" + }, + { + "internalName": "redstoneLight", + "displayName": "Redstone Lamp" + }, + { + "internalName": "redstoneLight_lit", + "displayName": "Redstone Lamp (On)" + }, + { + "internalName": "stonebrick_carved", + "displayName": "Chiseled Stone Bricks" + }, + { + "internalName": "planks_birch", + "displayName": "Birch Planks" + }, + { + "internalName": "anvil_base", + "displayName": "Anvil (Base)" + }, + { + "internalName": "anvil_top_damaged_1", + "displayName": "Anvil (Slightly Damaged) (Top)" + }, + { + "internalName": "quartz_block_chiseled_top", + "displayName": "Chiseled Quartz Block (Top)" + }, + { + "internalName": "quartz_block_lines_top", + "displayName": "Pillar Quartz Block (Top)" + }, + { + "internalName": "quartz_block_top", + "displayName": "Block of Quartz (Top)" + }, + { + "internalName": "hopper_outside", + "displayName": "Hopper (Side)" + }, + { + "internalName": "detectorRail_on", + "displayName": "Detector Rail (On)" + }, + { + "internalName": "water_flow", + "displayName": "" + }, + { + "internalName": "water_flow", + "displayName": "" + }, + { + "internalName": "nether_brick", + "displayName": "Nether Brick" + }, + { + "internalName": "wool_colored_silver", + "displayName": "Light Gray Wool" + }, + { + "internalName": "nether_wart_stage_0", + "displayName": "Nether Wart (Stage 1)" + }, + { + "internalName": "nether_wart_stage_1", + "displayName": "Nether Wart (Stage 2)" + }, + { + "internalName": "nether_wart_stage_2", + "displayName": "Nether Wart (Stage 3)" + }, + { + "internalName": "sandstone_carved", + "displayName": "Chiseled Sandstone" + }, + { + "internalName": "sandstone_smooth", + "displayName": "Smooth Sandstone" + }, + { + "internalName": "anvil_top", + "displayName": "Anvil (Top)" + }, + { + "internalName": "anvil_top_damaged_2", + "displayName": "Anvil (Very Damaged) (Top)" + }, + { + "internalName": "quartz_block_chiseled", + "displayName": "Chiseled Quartz Block (Side)" + }, + { + "internalName": "quartz_block_lines", + "displayName": "Pillar Quartz Block (Side)" + }, + { + "internalName": "quartz_block_side", + "displayName": "Block of Quartz (Side)" + }, + { + "internalName": "hopper_inside", + "displayName": "Hopper (Inside)" + }, + { + "internalName": "lava", + "displayName": "Lava" + }, + { + "internalName": "lava_flow", + "displayName": "Flowing Lava", + "width": 2, + "height": 2 + }, + { + "internalName": "lava_flow", + "displayName": "", + }, + { + "internalName": "destroy_0", + "displayName": "Destroy (Stage 1)" + }, + { + "internalName": "destroy_1", + "displayName": "Destroy (Stage 2)" + }, + { + "internalName": "destroy_2", + "displayName": "Destroy (Stage 3)" + }, + { + "internalName": "destroy_3", + "displayName": "Destroy (Stage 4)" + }, + { + "internalName": "destroy_4", + "displayName": "Destroy (Stage 5)" + }, + { + "internalName": "destroy_5", + "displayName": "Destroy (Stage 6)" + }, + { + "internalName": "destroy_6", + "displayName": "Destroy (Stage 7)" + }, + { + "internalName": "destroy_7", + "displayName": "Destroy (Stage 8)" + }, + { + "internalName": "destroy_8", + "displayName": "Destroy (Stage 9)" + }, + { + "internalName": "destroy_9", + "displayName": "Destroy (Stage 10)" + }, + { + "internalName": "hay_block_side", + "displayName": "Hay Bale (Side)" + }, + { + "internalName": "quartz_block_bottom", + "displayName": "Quartz Block (Bottom)" + }, + { + "internalName": "hopper_top", + "displayName": "Hopper (Top)" + }, + { + "internalName": "hay_block_top", + "displayName": "Hay Bale (Top)" + }, + { + "internalName": "lava_flow", + "displayName": "", + }, + { + "internalName": "lava_flow", + "displayName": "", + }, + { + "internalName": "coal_block", + "displayName": "Block of Coal" + }, + { + "internalName": "hardened_clay", + "displayName": "Terracotta" + }, + { + "internalName": "noteblock", + "displayName": "Note Block" + }, + { + "internalName": "stone_andesite", + "displayName": "Andesite" + }, + { + "internalName": "stone_andesite_smooth", + "displayName": "Polished Andesite" + }, + { + "internalName": "stone_diorite", + "displayName": "Diorite" + }, + { + "internalName": "stone_diorite_smooth", + "displayName": "Polished Diorite" + }, + { + "internalName": "stone_granite", + "displayName": "Granite" + }, + { + "internalName": "stone_granite_smooth", + "displayName": "Polished Granite" + }, + { + "internalName": "potatoes_stage_0", + "displayName": "Potatoes (Stage 1)" + }, + { + "internalName": "potatoes_stage_1", + "displayName": "Potatoes (Stage 2)" + }, + { + "internalName": "potatoes_stage_2", + "displayName": "Potatoes (Stage 3)" + }, + { + "internalName": "potatoes_stage_3", + "displayName": "Potatoes (Stage 4)" + }, + { + "internalName": "log_spruce_top", + "displayName": "Spruce Wood (Top)" + }, + { + "internalName": "log_jungle_top", + "displayName": "Jungle Wood (Top)" + }, + { + "internalName": "log_birch_top", + "displayName": "Birch Wood (Top)" + }, + { + "internalName": "hardened_clay_stained_black", + "displayName": "Black Terracotta" + }, + { + "internalName": "hardened_clay_stained_blue", + "displayName": "Blue Terracotta" + }, + { + "internalName": "hardened_clay_stained_brown", + "displayName": "Brown Terracotta" + }, + { + "internalName": "hardened_clay_stained_cyan", + "displayName": "Cyan Terracotta" + }, + { + "internalName": "hardened_clay_stained_gray", + "displayName": "Gray Terracotta" + }, + { + "internalName": "hardened_clay_stained_green", + "displayName": "Green Terracotta" + }, + { + "internalName": "hardened_clay_stained_light_blue", + "displayName": "Light Blue Terracotta" + }, + { + "internalName": "hardened_clay_stained_lime", + "displayName": "Lime Terracotta" + }, + { + "internalName": "hardened_clay_stained_magenta", + "displayName": "Magenta Terracotta" + }, + { + "internalName": "hardened_clay_stained_orange", + "displayName": "Orange Terracotta" + }, + { + "internalName": "hardened_clay_stained_pink", + "displayName": "Pink Terracotta" + }, + { + "internalName": "hardened_clay_stained_purple", + "displayName": "Purple Terracotta" + }, + { + "internalName": "hardened_clay_stained_red", + "displayName": "Red Terracotta" + }, + { + "internalName": "hardened_clay_stained_silver", + "displayName": "Light Gray Terracotta" + }, + { + "internalName": "hardened_clay_stained_white", + "displayName": "White Terracotta" + }, + { + "internalName": "hardened_clay_stained_yellow", + "displayName": "Yellow Terracotta" + }, + { + "internalName": "glass_black", + "displayName": "Black Stained Glass" + }, + { + "internalName": "glass_blue", + "displayName": "Blue Stained Glass" + }, + { + "internalName": "glass_brown", + "displayName": "Brown Stained Glass" + }, + { + "internalName": "glass_cyan", + "displayName": "Cyan Stained Glass" + }, + { + "internalName": "glass_gray", + "displayName": "Gray Stained Glass" + }, + { + "internalName": "glass_green", + "displayName": "Green Stained Glass" + }, + { + "internalName": "glass_light_blue", + "displayName": "Light Blue Stained Glass" + }, + { + "internalName": "glass_lime", + "displayName": "Lime Stained Glass" + }, + { + "internalName": "glass_magenta", + "displayName": "Magenta Stained Glass" + }, + { + "internalName": "glass_orange", + "displayName": "Orange Stained Glass" + }, + { + "internalName": "glass_pink", + "displayName": "Pink Stained Glass" + }, + { + "internalName": "glass_purple", + "displayName": "Purple Stained Glass" + }, + { + "internalName": "glass_red", + "displayName": "Red Stained Glass" + }, + { + "internalName": "glass_silver", + "displayName": "Light Gray Stained Glass" + }, + { + "internalName": "glass_white", + "displayName": "White Stained Glass" + }, + { + "internalName": "glass_yellow", + "displayName": "Yellow Stained Glass" + }, + { + "internalName": "glass_pane_top_black", + "displayName": "Black Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_blue", + "displayName": "Blue Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_brown", + "displayName": "Brown Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_cyan", + "displayName": "Cyan Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_gray", + "displayName": "Gray Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_green", + "displayName": "Green Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_light_blue", + "displayName": "Light Blue Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_lime", + "displayName": "Lime Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_magenta", + "displayName": "Magenta Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_orange", + "displayName": "Orange Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_pink", + "displayName": "Pink Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_purple", + "displayName": "Purple Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_red", + "displayName": "Red Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_silver", + "displayName": "Light Gray Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_white", + "displayName": "White Stained Glass Pane (Top)" + }, + { + "internalName": "glass_pane_top_yellow", + "displayName": "Yellow Stained Glass Pane (Top)" + }, + { + "internalName": "double_plant_fern_top", + "displayName": "Large Fern (Top)", + + "colourEntry": { + "defaultName": "Grass_Common", + "variants": [ + "Grass_Common", + "Grass_Mesa", + "Grass_Swamp1", + "Grass_Swamp2" + ] + } + }, + { + "internalName": "double_plant_grass_top", + "displayName": "Double Tall Grass (Top)", + + "colourEntry": { + "defaultName": "Grass_Common", + "variants": [ + "Grass_Common", + "Grass_Mesa", + "Grass_Swamp1", + "Grass_Swamp2" + ] + } + }, + { + "internalName": "double_plant_paeonia_top", + "displayName": "Peony (Top)" + }, + { + "internalName": "double_plant_rose_top", + "displayName": "Rose Bush (Top)" + }, + { + "internalName": "double_plant_syringa_top", + "displayName": "Lilac (Top)" + }, + { + "internalName": "flower_tulip_orange", + "displayName": "Orange Tulip" + }, + { + "internalName": "double_plant_sunflower_top", + "displayName": "Sunflower (Top)" + }, + { + "internalName": "double_plant_sunflower_front", + "displayName": "Sunflower (Front)" + }, + { + "internalName": "log_acacia", + "displayName": "Acacia Wood (Side)" + }, + { + "internalName": "log_acacia_top", + "displayName": "Acacia Wood (Top)" + }, + { + "internalName": "planks_acacia", + "displayName": "Acacia Planks" + }, + { + "internalName": "leaves_acacia", + "displayName": "Acacia Leaves", + + "colourEntry": { + "defaultName": "Foliage_Default", + "variants": [ + "Foliage_Default", + "Foliage_Evergreen", + "Foliage_Birch", + "Foliage_Mesa", + "Foliage_Swampland" + ] + } + }, + { + "internalName": "leaves_acacia_fast", + "displayName": "Acacia Leaves (Opaque)", + + "colourEntry": { + "defaultName": "Foliage_Default", + "variants": [ + "Foliage_Default", + "Foliage_Evergreen", + "Foliage_Birch", + "Foliage_Mesa", + "Foliage_Swampland" + ] + } + }, + { + "internalName": "prismarine_bricks", + "displayName": "Prismarine Bricks" + }, + { + "internalName": "red_sand", + "displayName": "Red Sand" + }, + { + "internalName": "red_sandstone_top", + "displayName": "Red Sandstone (Top)" + }, + { + "internalName": "double_plant_fern_bottom", + "displayName": "Large Fern (Bottom)", + + "colourEntry": { + "defaultName": "Grass_Common", + "variants": [ + "Grass_Common", + "Grass_Mesa", + "Grass_Swamp1", + "Grass_Swamp2" + ] + } + }, + { + "internalName": "double_plant_grass_bottom", + "displayName": "Double Tall Grass (Bottom)", + + "colourEntry": { + "defaultName": "Grass_Common", + "variants": [ + "Grass_Common", + "Grass_Mesa", + "Grass_Swamp1", + "Grass_Swamp2" + ] + } + }, + { + "internalName": "double_plant_paeonia_bottom", + "displayName": "Peony (Bottom)" + }, + { + "internalName": "double_plant_rose_bottom", + "displayName": "Rose Bush (Bottom)" + }, + { + "internalName": "double_plant_syringa_bottom", + "displayName": "Lilac (Bottom)" + }, + { + "internalName": "flower_tulip_pink", + "displayName": "Pink Tulip" + }, + { + "internalName": "double_plant_sunflower_bottom", + "displayName": "Sunflower (Bottom)" + }, + { + "internalName": "double_plant_sunflower_back", + "displayName": "Sunflower (Back)" + }, + { + "internalName": "log_big_oak", + "displayName": "Dark Oak Wood (Side)" + }, + { + "internalName": "log_big_oak_top", + "displayName": "Dark Oak Wood (Top)" + }, + { + "internalName": "planks_big_oak", + "displayName": "Dark Oak Planks" + }, + { + "internalName": "leaves_big_oak", + "displayName": "Dark Oak Leaves", + + "colourEntry": { + "defaultName": "Foliage_Default", + "variants": [ + "Foliage_Default", + "Foliage_Evergreen", + "Foliage_Birch", + "Foliage_Mesa", + "Foliage_Swampland" + ] + } + }, + { + "internalName": "leaves_big_oak_fast", + "displayName": "Dark Oak Leaves (Opaque)", + + "colourEntry": { + "defaultName": "Foliage_Default", + "variants": [ + "Foliage_Default", + "Foliage_Evergreen", + "Foliage_Birch", + "Foliage_Mesa", + "Foliage_Swampland" + ] + } + }, + { + "internalName": "prismarine_dark", + "displayName": "Dark Prismarine" + }, + { + "internalName": "red_sandstone_bottom", + "displayName": "Red Sandstone (Bottom)" + }, + { + "internalName": "red_sandstone_normal", + "displayName": "Red Sandstone (Side)" + }, + { + "internalName": "flower_alium", + "displayName": "Allium" + }, + { + "internalName": "flower_blue_orchid", + "displayName": "Blue Orchid" + }, + { + "internalName": "flower_houstonia", + "displayName": "Azure Bluet" + }, + { + "internalName": "flower_oxeye_daisy", + "displayName": "Oxeye Daisy" + }, + { + "internalName": "flower_tulip_red", + "displayName": "Red Tulip" + }, + { + "internalName": "flower_tulip_white", + "displayName": "White Tulip" + }, + { + "internalName": "sapling_acacia", + "displayName": "Acacia Sapling" + }, + { + "internalName": "sapling_roofed_oak", + "displayName": "Dark Oak Sapling" + }, + { + "internalName": "coarse_dirt", + "displayName": "Coarse Dirt" + }, + { + "internalName": "dirt_podzol_side", + "displayName": "Podzol (Side)" + }, + { + "internalName": "dirt_podzol_top", + "displayName": "Podzol (Top)" + }, + { + "internalName": "leaves_birch", + "displayName": "Birch Leaves", + + "colourEntry": { + "defaultName": "Foliage_Birch", + "variants": [ + "Foliage_Default", + "Foliage_Evergreen", + "Foliage_Birch", + "Foliage_Mesa", + "Foliage_Swampland" + ] + } + }, + { + "internalName": "leaves_birch_fast", + "displayName": "Birch Leaves (Opaque)", + + "colourEntry": { + "defaultName": "Foliage_Birch", + "variants": [ + "Foliage_Default", + "Foliage_Evergreen", + "Foliage_Birch", + "Foliage_Mesa", + "Foliage_Swampland" + ] + } + }, + { + "internalName": "prismarine_rough", + "displayName": "Prismarine" + }, + { + "internalName": "red_sandstone_carved", + "displayName": "Chiseled Red Sandstone" + }, + { + "internalName": "red_sandstone_smooth", + "displayName": "Smooth Red Standstone" + }, + { + "internalName": "door_acacia_upper", + "displayName": "Acacia Door (Top)" + }, + { + "internalName": "door_birch_upper", + "displayName": "Birch Door (Top)" + }, + { + "internalName": "door_dark_oak_upper", + "displayName": "Dark Oak Door (Top)" + }, + { + "internalName": "door_jungle_upper", + "displayName": "Jungle Door (Top)" + }, + { + "internalName": "door_spruce_upper", + "displayName": "Spruce Door (Top)" + }, + { + "internalName": "chorus_flower", + "displayName": "Chorus Flower" + }, + { + "internalName": "chorus_flower_dead", + "displayName": "Chorus Flower (Dead)" + }, + { + "internalName": "chorus_flower_plant", + "displayName": "Chorus Plant" + }, + { + "internalName": "end_bricks", + "displayName": "End Stone Bricks" + }, + { + "internalName": "grass_path_side", + "displayName": "Grass Path (Side)" + }, + { + "internalName": "grass_path_top", + "displayName": "Grass Path (Top)" + }, + { + "internalName": "barrier", + "displayName": "Barrier" + }, + { + "internalName": "ice_packed", + "displayName": "Packed Ice" + }, + { + "internalName": "sea_lantern", + "displayName": "Sea Lantern" + }, + { + "internalName": "daylight_detector_inverted_top", + "displayName": "Daylight Sensor (Inverted) (Top)" + }, + { + "internalName": "iron_trapdoor", + "displayName": "Iron Trapdoor" + }, + { + "internalName": "door_acacia_lower", + "displayName": "Acacia Door (Bottom)" + }, + { + "internalName": "door_birch_lower", + "displayName": "Birch Door (Bottom)" + }, + { + "internalName": "door_dark_oak_lower", + "displayName": "Dark Oak Door (Bottom)" + }, + { + "internalName": "door_jungle_lower", + "displayName": "Jungle Door (Bottom)" + }, + { + "internalName": "door_spruce_lower", + "displayName": "Spruce Door (Bottom)" + }, + { + "internalName": "purpur_block", + "displayName": "Purpur Block" + }, + { + "internalName": "purpur_pillar", + "displayName": "Purpur Pillar (Side)" + }, + { + "internalName": "purpur_pillar_top", + "displayName": "Purpur Pillar (Top)" + }, + { + "internalName": "end_rod", + "displayName": "End Rod" + }, + { + "internalName": "magma", + "displayName": "Magma Block" + }, + { + "internalName": "nether_wart_block", + "displayName": "Nether Wart Block" + }, + { + "internalName": "red_nether_brick", + "displayName": "Red Nether Brick" + }, + { + "internalName": "frosted_ice_0", + "displayName": "Frosted Ice (Stage 1)" + }, + { + "internalName": "frosted_ice_1", + "displayName": "Frosted Ice (Stage 2)" + }, + { + "internalName": "frosted_ice_2", + "displayName": "Frosted Ice (Stage 3)" + }, + { + "internalName": "frosted_ice_3", + "displayName": "Frosted Ice (Stage 4)" + }, + { + "internalName": "beetroots_stage_0", + "displayName": "Beetroots (Stage 1)" + }, + { + "internalName": "beetroots_stage_1", + "displayName": "Beetroots (Stage 2)" + }, + { + "internalName": "beetroots_stage_2", + "displayName": "Beetroots (Stage 3)" + }, + { + "internalName": "beetroots_stage_3", + "displayName": "Beetroots (Stage 4)" + }, + { + "internalName": "chain_command_block_back", + "displayName": "Chain Command Block (Back)" + }, + { + "internalName": "chain_command_block_conditional", + "displayName": "Chain Command Block (Conditional) (Side)" + }, + { + "internalName": "chain_command_block_front", + "displayName": "Chain Command Block (Front)" + }, + { + "internalName": "chain_command_block_side", + "displayName": "Chain Command Block (Side)" + }, + { + "internalName": "command_block_back", + "displayName": "Command Block (Back)" + }, + { + "internalName": "command_block_conditional", + "displayName": "Command Block (Conditional) (Side)" + }, + { + "internalName": "command_block_front", + "displayName": "Command Block (Front)" + }, + { + "internalName": "command_block_side", + "displayName": "Command Block (Side)" + }, + { + "internalName": "repeating_command_block_back", + "displayName": "Repeating Command Block (Back)" + }, + { + "internalName": "repeating_command_block_conditional", + "displayName": "Repeating Command Block (Conditional) (Side)" + }, + { + "internalName": "repeating_command_block_front", + "displayName": "Repeating Command Block (Front)" + }, + { + "internalName": "repeating_command_block_side", + "displayName": "Repeating Command Block (Side)" + }, + { + "internalName": "bone_block_side", + "displayName": "Bone Block (Side)" + }, + { + "internalName": "bone_block_top", + "displayName": "Bone Block (Top)" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "observer_front", + "displayName": "Observer (Front)" + }, + { + "internalName": "observer_side", + "displayName": "Observer (Side)" + }, + { + "internalName": "observer_back", + "displayName": "Observer (Back)" + }, + { + "internalName": "observer_back_lit", + "displayName": "Observer (On) (Back)" + }, + { + "internalName": "observer_top", + "displayName": "Observer (Top and Bottom)" + }, + { + "internalName": "goldRing", + "displayName": "Gold Score Ring" + }, + { + "internalName": "emeraldRing", + "displayName": "Emerald Score Ring" + }, + { + "internalName": "structure_block", + "displayName": "Structure Block" + }, + { + "internalName": "structure_block_corner", + "displayName": "Structure Block (Corner)" + }, + { + "internalName": "structure_block_data", + "displayName": "Structure Block (Data)" + }, + { + "internalName": "structure_block_load", + "displayName": "Structure Block (Load)" + }, + { + "internalName": "structure_block_save", + "displayName": "Structure Block (Save)" + }, + { + "internalName": "concrete_black", + "displayName": "Black Concrete" + }, + { + "internalName": "concrete_blue", + "displayName": "Blue Concrete" + }, + { + "internalName": "concrete_brown", + "displayName": "Brown Concrete" + }, + { + "internalName": "concrete_cyan", + "displayName": "Cyan Concrete" + }, + { + "internalName": "concrete_gray", + "displayName": "Gray Concrete" + }, + { + "internalName": "concrete_green", + "displayName": "Green Concrete" + }, + { + "internalName": "concrete_light_blue", + "displayName": "Light Blue Concrete" + }, + { + "internalName": "concrete_lime", + "displayName": "Lime Concrete" + }, + { + "internalName": "concrete_magenta", + "displayName": "Magenta Concrete" + }, + { + "internalName": "concrete_orange", + "displayName": "Orange Concrete" + }, + { + "internalName": "concrete_pink", + "displayName": "Pink Concrete" + }, + { + "internalName": "concrete_purple", + "displayName": "Purple Concrete" + }, + { + "internalName": "concrete_red", + "displayName": "Red Concrete" + }, + { + "internalName": "concrete_silver", + "displayName": "Light Gray Concrete" + }, + { + "internalName": "concrete_white", + "displayName": "White Concrete" + }, + { + "internalName": "concrete_yellow", + "displayName": "Yellow Concrete" + }, + { + "internalName": "concrete_powder_black", + "displayName": "Black Concrete Powder" + }, + { + "internalName": "concrete_powder_blue", + "displayName": "Blue Concrete Powder" + }, + { + "internalName": "concrete_powder_brown", + "displayName": "Brown Concrete Powder" + }, + { + "internalName": "concrete_powder_cyan", + "displayName": "Cyan Concrete Powder" + }, + { + "internalName": "concrete_powder_gray", + "displayName": "Gray Concrete Powder" + }, + { + "internalName": "concrete_powder_green", + "displayName": "Green Concrete Powder" + }, + { + "internalName": "concrete_powder_light_blue", + "displayName": "Light Blue Concrete Powder" + }, + { + "internalName": "concrete_powder_lime", + "displayName": "Lime Concrete Powder" + }, + { + "internalName": "concrete_powder_magenta", + "displayName": "Magenta Concrete Powder" + }, + { + "internalName": "concrete_powder_orange", + "displayName": "Orange Concrete Powder" + }, + { + "internalName": "concrete_powder_pink", + "displayName": "Pink Concrete Powder" + }, + { + "internalName": "concrete_powder_purple", + "displayName": "Purple Concrete Powder" + }, + { + "internalName": "concrete_powder_red", + "displayName": "Red Concrete Powder" + }, + { + "internalName": "concrete_powder_silver", + "displayName": "Light Gray Concrete Powder" + }, + { + "internalName": "concrete_powder_white", + "displayName": "White Concrete Powder" + }, + { + "internalName": "concrete_powder_yellow", + "displayName": "Yellow Concrete Powder" + }, + { + "internalName": "glazed_terracotta_black", + "displayName": "Black Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_blue", + "displayName": "Blue Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_brown", + "displayName": "Brown Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_cyan", + "displayName": "Cyan Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_gray", + "displayName": "Gray Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_green", + "displayName": "Green Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_light_blue", + "displayName": "Light Blue Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_lime", + "displayName": "Lime Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_magenta", + "displayName": "Magenta Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_orange", + "displayName": "Orange Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_pink", + "displayName": "Pink Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_purple", + "displayName": "Purple Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_red", + "displayName": "Red Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_silver", + "displayName": "Light Gray Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_white", + "displayName": "White Glazed Terracotta" + }, + { + "internalName": "glazed_terracotta_yellow", + "displayName": "Yellow Glazed Terracotta" + }, + { + "internalName": "shulker_top", + "displayName": "Shulker Box (Break Particles)", + + "colourEntry": { + "defaultName": "Shulker_Box_Purple", + "variants": [ + "Shulker_Box_Black", + "Shulker_Box_Blue", + "Shulker_Box_Brown", + "Shulker_Box_Cyan", + "Shulker_Box_Grey", + "Shulker_Box_Green", + "Shulker_Box_Light_Blue", + "Shulker_Box_Light_Green", + "Shulker_Box_Magenta", + "Shulker_Box_Orange", + "Shulker_Box_Pink", + "Shulker_Box_Purple", + "Shulker_Box_Red", + "Shulker_Box_Silver", + "Shulker_Box_White", + "Shulker_Box_Yellow" + ] + } + }, + { + "internalName": "shulker_top_overlay", + "displayName": "Shulker Box (Break Particles) (Overlay) (Unused)" + }, + { + "internalName": "cauldron_water", + "displayName": "Cauldron Water", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Cauldron_Water", + "variants": [ + "Cauldron_Water", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "seagrass_doubletall_top", + "displayName": "Double Tall Seagrass (Top)" + }, + { + "internalName": "coral_blue", + "displayName": "Tube Coral Block" + }, + { + "internalName": "coral_purple", + "displayName": "Bubble Coral Block" + }, + { + "internalName": "coral_pink", + "displayName": "Brain Coral Block" + }, + { + "internalName": "coral_red", + "displayName": "Fire Coral Block" + }, + { + "internalName": "coral_yellow", + "displayName": "Horn Coral Block" + }, + { + "internalName": "coral_plant_blue", + "displayName": "Tube Coral" + }, + { + "internalName": "coral_plant_purple", + "displayName": "Bubble Coral" + }, + { + "internalName": "coral_plant_pink", + "displayName": "Brain Coral" + }, + { + "internalName": "coral_plant_red", + "displayName": "Fire Coral" + }, + { + "internalName": "coral_plant_yellow", + "displayName": "Horn Coral" + }, + { + "internalName": "sea_pickle", + "displayName": "Sea Pickle" + }, + { + "internalName": "blue_ice", + "displayName": "Blue Ice" + }, + { + "internalName": "dried_kelp_top", + "displayName": "Dried Kelp Block (Top)" + }, + { + "internalName": "dried_kelp_side", + "displayName": "Dried Kelp Block (Side)" + }, + { + "internalName": "seagrass_carried", + "displayName": "Seagrass (Item)" + }, + { + "internalName": "seagrass_doubletall_bottom", + "displayName": "Double Tall Seagrass (Bottom)" + }, + { + "internalName": "coral_blue_dead", + "displayName": "Dead Tube Coral Block" + }, + { + "internalName": "coral_purple_dead", + "displayName": "Dead Bubble Coral Block" + }, + { + "internalName": "coral_pink_dead", + "displayName": "Dead Brain Coral Block" + }, + { + "internalName": "coral_red_dead", + "displayName": "Dead Fire Coral Block" + }, + { + "internalName": "coral_yellow_dead", + "displayName": "Dead Horn Coral Block" + }, + { + "internalName": "coral_fan_blue", + "displayName": "Tube Coral Fan" + }, + { + "internalName": "coral_fan_purple", + "displayName": "Bubble Coral Fan" + }, + { + "internalName": "coral_fan_pink", + "displayName": "Brain Coral Fan" + }, + { + "internalName": "coral_fan_red", + "displayName": "Fire Coral Fan" + }, + { + "internalName": "coral_fan_yellow", + "displayName": "Horn Coral Fan" + }, + { + "internalName": "bamboo_stem", + "displayName": "Bamboo (Stem) [PS4 ONLY]" + }, + { + "internalName": "bamboo_leaf_small", + "displayName": "Bamboo (Small Leaves) [PS4 ONLY]" + }, + { + "internalName": "kelp_a", + "displayName": "Kelp (Bottom)" + }, + { + "internalName": "kelp_a", + "displayName": "" + }, + { + "internalName": "kelp_a", + "displayName": "" + }, + { + "internalName": "kelp_a", + "displayName": "" + }, + { + "internalName": "kelp_top_a", + "displayName": "Kelp (Top)" + }, + { + "internalName": "kelp_top_a", + "displayName": "" + }, + { + "internalName": "kelp_top_a", + "displayName": "" + }, + { + "internalName": "kelp_top_a", + "displayName": "" + }, + { + "internalName": "seagrass", + "displayName": "Seagrass" + }, + { + "internalName": "coral_fan_blue_dead", + "displayName": "Dead Tube Coral Fan" + }, + { + "internalName": "coral_fan_purple_dead", + "displayName": "Dead Bubble Coral Fan" + }, + { + "internalName": "coral_fan_pink_dead", + "displayName": "Dead Brain Coral Fan" + }, + { + "internalName": "coral_fan_red_dead", + "displayName": "Dead Fire Coral Fan" + }, + { + "internalName": "coral_fan_yellow_dead", + "displayName": "Dead Horn Coral Fan" + }, + { + "internalName": "bamboo_leaf", + "displayName": "Bamboo (Leaves) [PS4 ONLY]" + }, + { + "internalName": "spruce_trapdoor", + "displayName": "Spruce Trapdoor" + }, + { + "internalName": "stripped_log_oak", + "displayName": "Stripped Oak Log (Side)" + }, + { + "internalName": "stripped_log_oak_top", + "displayName": "Stripped Oak Log (Top)" + }, + { + "internalName": "stripped_log_acacia", + "displayName": "Stripped Acacia Log (Side)" + }, + { + "internalName": "stripped_log_acacia_top", + "displayName": "Stripped Acacia Log (Top)" + }, + { + "internalName": "stripped_log_birch", + "displayName": "Stripped Birch Log (Side)" + }, + { + "internalName": "stripped_log_birch_top", + "displayName": "Stripped Birch Log (Top)" + }, + { + "internalName": "stripped_log_dark_oak", + "displayName": "Stripped Dark Oak Log (Side)" + }, + { + "internalName": "stripped_log_dark_oak_top", + "displayName": "Stripped Dark Oak Log (Top)" + }, + { + "internalName": "stripped_log_jungle", + "displayName": "Stripped Jungle Log (Side)" + }, + { + "internalName": "stripped_log_jungle_top", + "displayName": "Stripped Birch Log (Top)" + }, + { + "internalName": "stripped_log_spruce", + "displayName": "Stripped Spruce Log (Side)" + }, + { + "internalName": "stripped_log_spruce_top", + "displayName": "Stripped Spruce Log (Top)" + }, + { + "internalName": "acacia_trapdoor", + "displayName": "Acacia Trapdoor" + }, + { + "internalName": "birch_trapdoor", + "displayName": "Birch Trapdoor" + }, + { + "internalName": "dark_oak_trapdoor", + "displayName": "Dark Oak Trapdoor" + }, + { + "internalName": "jungle_trapdoor", + "displayName": "Jungle Trapdoor" + }, + { + "internalName": "bamboo_sapling", + "displayName": "Bamboo Sapling [PS4 ONLY]" + }, + { + "internalName": "bamboo_singleleaf", + "displayName": "Bamboo (Single Leaf) [PS4 ONLY]" + }, + { + "internalName": "flower_lily_of_the_valley", + "displayName": "Lily of the Valley [PS4 ONLY]" + }, + { + "internalName": "flower_cornflower", + "displayName": "Cornflower [PS4 ONLY]" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "berry_bush_sapling", + "displayName": "Sweet Berry Bush (Stage 1) [PS4 ONLY]" + }, + { + "internalName": "berry_bush_no_berries", + "displayName": "Sweet Berry Bush (Stage 2) [PS4 ONLY]" + }, + { + "internalName": "berry_bush_some_berries", + "displayName": "Sweet Berry Bush (Stage 3) [PS4 ONLY]" + }, + { + "internalName": "berry_bush_full_berries", + "displayName": "Sweet Berry Bush (Stage 4) [PS4 ONLY]" + }, + { + "internalName": "campfire_log", + "displayName": "Campfire (Log) [PS4 ONLY]" + }, + { + "internalName": "campfire_log_lit", + "displayName": "Campfire (Log) (Lit) [PS4 ONLY]" + }, + { + "internalName": "campfire_smoke", + "displayName": "Campfire (Smoke) [PS4 ONLY]" + }, + { + "internalName": "campfire", + "displayName": "Campfire (Flame) [PS4 ONLY]" + }, + { + "internalName": "scaffolding_side", + "displayName": "Scaffolding (Side) [PS4 ONLY]" + }, + { + "internalName": "scaffolding_bottom", + "displayName": "Scaffolding (Bottom) [PS4 ONLY]" + }, + { + "internalName": "scaffolding_top", + "displayName": "Scaffolding (Top) [PS4 ONLY]" + }, + { + "internalName": "barrel_side", + "displayName": "Barrel (Side) [PS4 ONLY]" + }, + { + "internalName": "barrel_top", + "displayName": "Barrel (Top) [PS4 ONLY]" + }, + { + "internalName": "barrel_bottom", + "displayName": "Barrel (Bottom) [PS4 ONLY]" + }, + { + "internalName": "bell_side", + "displayName": "Bell (Side) [PS4 ONLY]" + }, + { + "internalName": "bell_top", + "displayName": "Bell (Top) [PS4 ONLY]" + }, + { + "internalName": "bell_bottom", + "displayName": "Bell (Bottom) [PS4 ONLY]" + }, + { + "internalName": "lantern", + "displayName": "Lantern [PS4 ONLY]" + }, + { + "internalName": "jigsaw_side", + "displayName": "Jigsaw (Side) [PS4 ONLY]" + }, + { + "internalName": "jigsaw_top", + "displayName": "Jigsaw (Top) [PS4 ONLY]" + }, + { + "internalName": "blast_furnace_front", + "displayName": "Blast Furnace (Front) [PS4 ONLY]" + }, + { + "internalName": "blast_furnace_front_on", + "displayName": "Blast Furnace (Front) (Lit) [PS4 ONLY]" + }, + { + "internalName": "blast_furnace_side", + "displayName": "Blast Furnace (Side) [PS4 ONLY]" + }, + { + "internalName": "blast_furnace_top", + "displayName": "Blast Furnace (Top) [PS4 ONLY]" + }, + { + "internalName": "grindstone_side", + "displayName": "Grindstone (Side) [PS4 ONLY]" + }, + { + "internalName": "grindstone_round", + "displayName": "Grindstone (Round) [PS4 ONLY]" + }, + { + "internalName": "grindstone_pivot", + "displayName": "Grindstone (Pivot) [PS4 ONLY]" + }, + { + "internalName": "cartography_table_side1", + "displayName": "Cartography Table (Back) [PS4 ONLY]" + }, + { + "internalName": "cartography_table_side2", + "displayName": "Cartography Table (Right Side) [PS4 ONLY]" + }, + { + "internalName": "cartography_table_side3", + "displayName": "Cartography Table (Front and Left Side) [PS4 ONLY]" + }, + { + "internalName": "cartography_table_top", + "displayName": "Cartography Table (Top) [PS4 ONLY]" + }, + { + "internalName": "lectern_sides", + "displayName": "Lectern (Side) [PS4 ONLY]" + }, + { + "internalName": "lectern_front", + "displayName": "Lectern (Front) [PS4 ONLY]" + }, + { + "internalName": "lectern_base", + "displayName": "Lectern (Base) [PS4 ONLY]" + }, + { + "internalName": "lectern_top", + "displayName": "Lectern (Top) [PS4 ONLY]" + }, + { + "internalName": "loom_side", + "displayName": "Loom (Side) [PS4 ONLY]" + }, + { + "internalName": "loom_front", + "displayName": "Loom (Front) [PS4 ONLY]" + }, + { + "internalName": "loom_top", + "displayName": "Loom (Top) [PS4 ONLY]" + }, + { + "internalName": "loom_bottom", + "displayName": "Loom (Bottom) [PS4 ONLY]" + }, + { + "internalName": "smithing_table_side", + "displayName": "Smithing Table (Side) [PS4 ONLY]" + }, + { + "internalName": "smithing_table_front", + "displayName": "Smithing Table (Front) [PS4 ONLY]" + }, + { + "internalName": "smithing_table_top", + "displayName": "Smithing Table (Top) [PS4 ONLY]" + }, + { + "internalName": "composter_top", + "displayName": "Composter (Top) [PS4 ONLY]" + }, + { + "internalName": "fletcher_table_side2", + "displayName": "Fletching Table (Front and Back) [PS4 ONLY]" + }, + { + "internalName": "fletcher_table_side1", + "displayName": "Fletching Table (Side) [PS4 ONLY]" + }, + { + "internalName": "fletcher_table_top", + "displayName": "Fletching Table (Top) [PS4 ONLY]" + }, + { + "internalName": "stonecutter2_saw", + "displayName": "Stonecutter (Saw) [PS4 ONLY]" + }, + { + "internalName": "stonecutter2_side", + "displayName": "Stonecutter (Side) [PS4 ONLY]" + }, + { + "internalName": "stonecutter2_top", + "displayName": "Stonecutter (Top) [PS4 ONLY]" + }, + { + "internalName": "stonecutter2_bottom", + "displayName": "Stonecutter (Bottom) [PS4 ONLY]" + }, + { + "internalName": "smoker_side", + "displayName": "Smoker (Side) [PS4 ONLY]" + }, + { + "internalName": "smoker_front", + "displayName": "Smoker (Front) [PS4 ONLY]" + }, + { + "internalName": "smoker_front_on", + "displayName": "Smoker (Front) (Lit) [PS4 ONLY]" + }, + { + "internalName": "smoker_top", + "displayName": "Smoker (Top) [PS4 ONLY]" + }, + { + "internalName": "smoker_bottom", + "displayName": "Smoker (Bottom) [PS4 ONLY]" + }, + { + "internalName": "compost", + "displayName": "Compost [PS4 ONLY]" + }, + { + "internalName": "compost_ready", + "displayName": "Compost (Ready) [PS4 ONLY]" + }, + { + "internalName": "composter_bottom", + "displayName": "Composter (Bottom) [PS4 ONLY]" + }, + { + "internalName": "composter_side", + "displayName": "Composter (Side) [PS4 ONLY]" + }, + { + "internalName": "barrel_top_open", + "displayName": "Barrel (Top) (Open) [PS4 ONLY]" + }, + { + "internalName": "smithing_table_bottom", + "displayName": "Smithing Table (Bottom) [PS4 ONLY]" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + } + ] +} diff --git a/PckStudio.Core/Resources/entityBehavioursData.json b/PckStudio.Core/Resources/entityBehavioursData.json new file mode 100644 index 00000000..921fe41f --- /dev/null +++ b/PckStudio.Core/Resources/entityBehavioursData.json @@ -0,0 +1,489 @@ +{ + "COMMENT": "Entity data research by NessieHax (Miku-666) and MattNL", + "entries": [ + { + "internalName": "area_effect_cloud", + "displayName": "Area Effect Cloud / Particle" + }, + { + "internalName": "armor_stand", + "displayName": "Armor Stand" + }, + { + "internalName": "arrow", + "displayName": "Arrow" + }, + { + "internalName": "bat", + "displayName": "Bat" + }, + { + "internalName": "blaze", + "displayName": "Blaze" + }, + { + "internalName": "boat", + "displayName": "Boat" + }, + { + "internalName": "cat", + "displayName": "Cat [PS4 EXCLUSIVE]" + }, + { + "internalName": "cave_spider", + "displayName": "Cave Spider" + }, + { + "internalName": "chest_minecart", + "displayName": "Chest Minecart" + }, + { + "internalName": "chicken", + "displayName": "Chicken" + }, + { + "internalName": "cod", + "displayName": "Cod" + }, + { + "internalName": "commandblock_minecart", + "displayName": "Command Block Minecart" + }, + { + "internalName": "cow", + "displayName": "Cow" + }, + { + "internalName": "creeper", + "displayName": "Creeper" + }, + { + "internalName": "dolphin", + "displayName": "Dolphin" + }, + { + "internalName": "donkey", + "displayName": "Donkey" + }, + { + "internalName": "dragon_fireball", + "displayName": "Dragon Fireball" + }, + { + "internalName": "drowned", + "displayName": "Drowned" + }, + { + "internalName": "egg", + "displayName": "Thrown Egg" + }, + { + "internalName": "elder_guardian", + "displayName": "Elder Guardian" + }, + { + "internalName": "ender_crystal", + "displayName": "End Crystal" + }, + { + "internalName": "ender_dragon", + "displayName": "Ender Dragon" + }, + { + "internalName": "ender_pearl", + "displayName": "Thrown Ender Pearl" + }, + { + "internalName": "enderman", + "displayName": "Enderman" + }, + { + "internalName": "endermite", + "displayName": "Endermite" + }, + { + "internalName": "evocation_illager", + "displayName": "Evoker" + }, + { + "internalName": "evocation_fangs", + "displayName": "Evoker Fangs" + }, + { + "internalName": "xp_bottle", + "displayName": "Thrown Bottle O' Enchanting" + }, + { + "internalName": "xp_orb", + "displayName": "Experience Orb" + }, + { + "internalName": "eye_of_ender_signal", + "displayName": "Thrown Eye of Ender" + }, + { + "internalName": "falling_block", + "displayName": "Falling Block" + }, + { + "internalName": "fireball", + "displayName": "Fireball" + }, + { + "internalName": "fireworks_rocket", + "displayName": "Firework Rocket" + }, + { + "internalName": "furnace_minecart", + "displayName": "Furnace Minecart" + }, + { + "internalName": "ghast", + "displayName": "Ghast" + }, + { + "internalName": "giant", + "displayName": "Giant" + }, + { + "internalName": "guardian", + "displayName": "Guardian" + }, + { + "internalName": "hopper_minecart", + "displayName": "Hopper Minecart" + }, + { + "internalName": "horse", + "displayName": "Horse" + }, + { + "internalName": "husk", + "displayName": "Husk" + }, + { + "internalName": "villager_golem", + "displayName": "Iron Golem" + }, + { + "internalName": "item", + "displayName": "Dropped Item" + }, + { + "internalName": "item_frame", + "displayName": "Item Frame" + }, + { + "internalName": "leash_knot", + "displayName": "Lead Knot" + }, + { + "internalName": "llama", + "displayName": "Llama" + }, + { + "internalName": "llama_spit", + "displayName": "Llama Spit" + }, + { + "internalName": "magma_cube", + "displayName": "Magma Cube" + }, + { + "internalName": "minecart", + "displayName": "Minecart" + }, + { + "internalName": "mooshroom", + "displayName": "Mooshroom" + }, + { + "internalName": "mule", + "displayName": "Mule" + }, + { + "internalName": "ocelot", + "displayName": "Ocelot" + }, + { + "internalName": "painting", + "displayName": "Painting" + }, + { + "internalName": "panda", + "displayName": "Panda [PS4 EXCLUSIVE]" + }, + { + "internalName": "parrot", + "displayName": "Parrot" + }, + { + "internalName": "phantom", + "displayName": "Phantom" + }, + { + "internalName": "pig", + "displayName": "Pig" + }, + { + "internalName": "pillager", + "displayName": "Pillager [PS4 EXCLUSIVE]" + }, + { + "internalName": "polar_bear", + "displayName": "Polar Bear" + }, + { + "internalName": "potion", + "displayName": "Thrown Potion" + }, + { + "internalName": "pufferfish", + "displayName": "Pufferfish" + }, + { + "internalName": "rabbit", + "displayName": "Rabbit" + }, + { + "internalName": "ravager", + "displayName": "Ravager [PS4 EXCLUSIVE]" + }, + { + "internalName": "salmon", + "displayName": "Salmon" + }, + { + "internalName": "sheep", + "displayName": "Sheep" + }, + { + "internalName": "shulker", + "displayName": "Shulker" + }, + { + "internalName": "shulker_bullet", + "displayName": "Shulker Bullet" + }, + { + "internalName": "silverfish", + "displayName": "Silverfish" + }, + { + "internalName": "skeleton", + "displayName": "Skeleton" + }, + { + "internalName": "skeleton_horse", + "displayName": "Skeleton Horse" + }, + { + "internalName": "slime", + "displayName": "Slime" + }, + { + "internalName": "small_fireball", + "displayName": "Small Fireball" + }, + { + "internalName": "snowman", + "displayName": "Snow Golem" + }, + { + "internalName": "snowball", + "displayName": "Thrown Snowball" + }, + { + "internalName": "spawner_minecart", + "displayName": "Spawner Minecart" + }, + { + "internalName": "spectral_arrow", + "displayName": "Spectral Arrow" + }, + { + "internalName": "spider", + "displayName": "Spider" + }, + { + "internalName": "squid", + "displayName": "Squid" + }, + { + "internalName": "stray", + "displayName": "Stray" + }, + { + "internalName": "tnt", + "displayName": "Primed TNT" + }, + { + "internalName": "tnt_minecart", + "displayName": "TNT Minecart" + }, + { + "internalName": "trident", + "displayName": "Thrown Trident" + }, + { + "internalName": "tropical_fish", + "displayName": "Tropical Fish" + }, + { + "internalName": "turtle", + "displayName": "Turtle" + }, + { + "internalName": "vex", + "displayName": "Vex" + }, + { + "internalName": "villager", + "displayName": "Villager" + }, + { + "internalName": "vindication_illager", + "displayName": "Vindicator" + }, + { + "internalName": "wandering_trader", + "displayName": "Wandering Trader [PS4 EXCLUSIVE]" + }, + { + "internalName": "witch", + "displayName": "Witch" + }, + { + "internalName": "wither", + "displayName": "Wither" + }, + { + "internalName": "wither_skeleton", + "displayName": "Wither Skeleton" + }, + { + "internalName": "wither_skull", + "displayName": "Wither Skull" + }, + { + "internalName": "wolf", + "displayName": "Wolf" + }, + { + "internalName": "zombie", + "displayName": "Zombie" + }, + { + "internalName": "zombie_horse", + "displayName": "Zombie Horse" + }, + { + "internalName": "zombie_pigman", + "displayName": "Zombie Pigman" + }, + { + "internalName": "zombie_villager", + "displayName": "Zombie Villager" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "illusion_illager", + "displayName": "Illusioner" + } + ] +} diff --git a/PckStudio.Core/Resources/entityMaterialsData.json b/PckStudio.Core/Resources/entityMaterialsData.json new file mode 100644 index 00000000..259a077b --- /dev/null +++ b/PckStudio.Core/Resources/entityMaterialsData.json @@ -0,0 +1,485 @@ +{ + "COMMENT": "Entity data research by NessieHax (Miku-666) and MattNL", + "entries": [ + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "bat", + "displayName": "Bat" + }, + { + "internalName": "blaze_head", + "displayName": "Blaze" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "cat", + "displayName": "Cat [PS4 EXCLUSIVE]" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "drowned", + "displayName": "Drowned" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "ender_dragon", + "displayName": "Ender Dragon" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "enderman", + "displayName": "Enderman" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "ghast", + "displayName": "Ghast" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "guardian", + "displayName": "Guardian" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "iron_golem", + "displayName": "Iron Golem" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "magma_cube", + "displayName": "Magma Cube" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "phantom", + "displayName": "Phantom" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "sheep", + "displayName": "Sheep" + }, + { + "internalName": "shulker", + "displayName": "Shulker" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "skeleton", + "displayName": "Skeleton" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "stray", + "displayName": "Stray" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "wither_boss", + "displayName": "Wither" + }, + { + "internalName": "wither_skeleton", + "displayName": "Wither Skeleton" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "wolf", + "displayName": "Wolf" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "zombie_pigman", + "displayName": "Zombie Pigman" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "villager", + "displayName": "Villager [PS4 EXCLUSIVE]" + }, + { + "internalName": "zombie_villager", + "displayName": "Zombie Villager [PS4 EXCLUSIVE]" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "phantom_invisible", + "displayName": "Phantom (Overlay)" + }, + { + "internalName": "enderman_invisible", + "displayName": "Enderman (Overlay)" + }, + { + "internalName": "spider_invisible", + "displayName": "Spiders (Overlay)" + }, + { + "internalName": "spider", + "displayName": "Spiders" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + } + ] +} diff --git a/PckStudio.Core/Resources/entityModelsData.json b/PckStudio.Core/Resources/entityModelsData.json new file mode 100644 index 00000000..647be99b --- /dev/null +++ b/PckStudio.Core/Resources/entityModelsData.json @@ -0,0 +1,485 @@ +{ + "COMMENT": "Entity data research by NessieHax (Miku-666) and MattNL", + "entries": [ + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "bat", + "displayName": "Bat" + }, + { + "internalName": "blaze", + "displayName": "Blaze" + }, + { + "internalName": "boat", + "displayName": "Boat" + }, + { + "internalName": "cat", + "displayName": "Cat [PS4 EXCLUSIVE]" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "chicken", + "displayName": "Chicken" + }, + { + "internalName": "cod", + "displayName": "Cod" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "cow", + "displayName": "Cow" + }, + { + "internalName": "creeper", + "displayName": "Creeper" + }, + { + "internalName": "dolphin", + "displayName": "Dolphin" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "zombie.drowned", + "displayName": "Drowned" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "dragon", + "displayName": "Ender Dragon" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "enderman", + "displayName": "Enderman" + }, + { + "internalName": "endermite", + "displayName": "Endermite" + }, + { + "internalName": "evoker", + "displayName": "Evoker" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "ghast", + "displayName": "Ghast" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "zombie.husk", + "displayName": "Husk" + }, + { + "internalName": "irongolem", + "displayName": "Iron Golem" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "llama", + "displayName": "Llama" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "lavaslime", + "displayName": "Magma Cube" + }, + { + "internalName": "minecart", + "displayName": "Minecart" + }, + { + "internalName": "mooshroom", + "displayName": "Mooshroom" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "ocelot", + "displayName": "Ocelot" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "panda", + "displayName": "Panda [PS4 EXCLUSIVE]" + }, + { + "internalName": "parrot", + "displayName": "Parrot" + }, + { + "internalName": "phantom", + "displayName": "Phantom" + }, + { + "internalName": "pig", + "displayName": "Pig" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "polarbear", + "displayName": "Polar Bear" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "pufferfish.large", + "displayName": "Pufferfish (Large)" + }, + { + "internalName": "rabbit", + "displayName": "Rabbit" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "salmon", + "displayName": "Salmon" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "shulker", + "displayName": "Shulker" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "silverfish", + "displayName": "Silverfish" + }, + { + "internalName": "skeleton", + "displayName": "Skeleton" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "snowgolem", + "displayName": "Snow Golem" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "squid", + "displayName": "Squid" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "trident", + "displayName": "Thrown Trident" + }, + { + "internalName": "tropicalfish_a", + "displayName": "Tropical Fish (Small)" + }, + { + "internalName": "turtle", + "displayName": "Turtle" + }, + { + "internalName": "vex", + "displayName": "Vex" + }, + { + "internalName": "villager", + "displayName": "Villager" + }, + { + "internalName": "vindicator", + "displayName": "Vindicator/Illusioner" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "witch", + "displayName": "Witch" + }, + { + "internalName": "witherboss", + "displayName": "Wither" + }, + { + "internalName": "skeleton.wither", + "displayName": "Wither Skeleton" + }, + { + "internalName": "witherboss.armor", + "displayName": "Wither (Armor)" + }, + { + "internalName": "wolf", + "displayName": "Wolf" + }, + { + "internalName": "zombie", + "displayName": "Zombie" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "pigzombie", + "displayName": "Zombie Pigman" + }, + { + "internalName": "zombie.villager", + "displayName": "Zombie Villager" + }, + { + "internalName": "skeleton_head", + "displayName": "Skeleton Skull" + }, + { + "internalName": "skeleton_wither_head", + "displayName": "Wither Skeleton Skull" + }, + { + "internalName": "zombie_head", + "displayName": "Zombie Head" + }, + { + "internalName": "creeper_head", + "displayName": "Creeper Head" + }, + { + "internalName": "dragon_head", + "displayName": "Ender Dragon Head" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "spider", + "displayName": "Spider" + }, + { + "internalName": "bed", + "displayName": "Bed" + }, + { + "internalName": "guardian", + "displayName": "Guardian" + }, + { + "internalName": "horse.v2", + "displayName": "Horse/Donkey/Mule" + }, + { + "internalName": "pufferfish.small", + "displayName": "Pufferfish (Small)" + }, + { + "internalName": "pufferfish.mid", + "displayName": "Pufferfish (Medium)" + }, + { + "internalName": "sheep.sheared", + "displayName": "Sheep (Without Fur)" + }, + { + "internalName": "sheep", + "displayName": "Sheep (Fur Only)" + }, + { + "internalName": "slime", + "displayName": "Slime (Inner)" + }, + { + "internalName": "slime.armor", + "displayName": "Slime (Outer)" + }, + { + "internalName": "skeleton.stray", + "displayName": "Stray" + }, + { + "internalName": "stray.armor", + "displayName": "Stray (Overlay)" + }, + { + "internalName": "tropicalfish_b", + "displayName": "Tropical Fish (Large)" + } + ] +} diff --git a/PckStudio.Core/Resources/experienceOrbData.json b/PckStudio.Core/Resources/experienceOrbData.json new file mode 100644 index 00000000..f83a7ab3 --- /dev/null +++ b/PckStudio.Core/Resources/experienceOrbData.json @@ -0,0 +1,124 @@ +{ + "COMMENT_1": "JSON by MattNL", + "entries": [ + { + "internalName": "experience_orb_0", + "displayName": "Experience Orb (Size 1)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "experience_orb", + "variants": ["experience_orb"] + } + }, + { + "internalName": "experience_orb_1", + "displayName": "Experience Orb (Size 2)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "experience_orb", + "variants": ["experience_orb"] + } + }, + { + "internalName": "experience_orb_2", + "displayName": "Experience Orb (Size 3)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "experience_orb", + "variants": ["experience_orb"] + } + }, + { + "internalName": "experience_orb_3", + "displayName": "Experience Orb (Size 4)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "experience_orb", + "variants": ["experience_orb"] + } + }, + { + "internalName": "experience_orb_4", + "displayName": "Experience Orb (Size 5)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "experience_orb", + "variants": ["experience_orb"] + } + }, + { + "internalName": "experience_orb_5", + "displayName": "Experience Orb (Size 6)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "experience_orb", + "variants": ["experience_orb"] + } + }, + { + "internalName": "experience_orb_6", + "displayName": "Experience Orb (Size 7)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "experience_orb", + "variants": ["experience_orb"] + } + }, + { + "internalName": "experience_orb_7", + "displayName": "Experience Orb (Size 8)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "experience_orb", + "variants": ["experience_orb"] + } + }, + { + "internalName": "experience_orb_8", + "displayName": "Experience Orb (Size 9)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "experience_orb", + "variants": ["experience_orb"] + } + }, + { + "internalName": "experience_orb_9", + "displayName": "Experience Orb (Size 10)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "experience_orb", + "variants": ["experience_orb"] + } + }, + { + "internalName": "experience_orb_10", + "displayName": "Experience Orb (Size 11)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "experience_orb", + "variants": ["experience_orb"] + } + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + } + ] +} \ No newline at end of file diff --git a/PckStudio.Core/Resources/experience_orbs.png b/PckStudio.Core/Resources/experience_orbs.png new file mode 100644 index 00000000..1a2d58a3 Binary files /dev/null and b/PckStudio.Core/Resources/experience_orbs.png differ diff --git a/PckStudio.Core/Resources/explosion.png b/PckStudio.Core/Resources/explosion.png new file mode 100644 index 00000000..242d9115 Binary files /dev/null and b/PckStudio.Core/Resources/explosion.png differ diff --git a/PckStudio.Core/Resources/explosionData.json b/PckStudio.Core/Resources/explosionData.json new file mode 100644 index 00000000..f9845f7e --- /dev/null +++ b/PckStudio.Core/Resources/explosionData.json @@ -0,0 +1,197 @@ +{ + "COMMENT_1": "JSON by MattNL", + "entries": [ + { + "internalName": "explosion_0", + "displayName": "Explosion (Stage 1)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_1", + "displayName": "Explosion (Stage 2)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_2", + "displayName": "Explosion (Stage 3)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_3", + "displayName": "Explosion (Stage 4)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_4", + "displayName": "Explosion (Stage 5)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_5", + "displayName": "Explosion (Stage 6)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_6", + "displayName": "Explosion (Stage 7)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_7", + "displayName": "Explosion (Stage 8)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_8", + "displayName": "Explosion (Stage 9)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_9", + "displayName": "Explosion (Stage 10)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_10", + "displayName": "Explosion (Stage 11)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_11", + "displayName": "Explosion (Stage 12)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_12", + "displayName": "Explosion (Stage 13)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_13", + "displayName": "Explosion (Stage 14)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_14", + "displayName": "Explosion (Stage 15)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + }, + { + "internalName": "explosion_15", + "displayName": "Explosion (Stage 16)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Particle_Explode", + "variants": [ + "Particle_Explode", + "Particle_HugeExplosion" + ] + } + } + ] +} \ No newline at end of file diff --git a/PckStudio.Core/Resources/itemData.json b/PckStudio.Core/Resources/itemData.json new file mode 100644 index 00000000..51c380b7 --- /dev/null +++ b/PckStudio.Core/Resources/itemData.json @@ -0,0 +1,1361 @@ +{ + "COMMENT_1": "Tile data research by MattNL", + "COMMENT_2": "JSON by PhoenixARC, MattNL, and NessieHax (Miku-666)", + "entries": [ + { + "internalName": "helmetCloth", + "displayName": "Leather Cap", + "allowCustomColour": true, + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Armour_Default_Leather_Colour", + "variants": [ "Armour_Default_Leather_Colour" ] + } + }, + { + "internalName": "helmetChain", + "displayName": "Chain Helmet" + }, + { + "internalName": "helmetIron", + "displayName": "Iron Helmet" + }, + { + "internalName": "helmetDiamond", + "displayName": "Diamond Helmet" + }, + { + "internalName": "helmetGold", + "displayName": "Golden Helmet" + }, + { + "internalName": "flintAndSteel", + "displayName": "Flint and Steel" + }, + { + "internalName": "flint", + "displayName": "Flint" + }, + { + "internalName": "coal", + "displayName": "Coal" + }, + { + "internalName": "string", + "displayName": "String" + }, + { + "internalName": "seeds", + "displayName": "Seeds" + }, + { + "internalName": "apple", + "displayName": "Apple" + }, + { + "internalName": "appleGold", + "displayName": "Golden Apple" + }, + { + "internalName": "egg", + "displayName": "Egg" + }, + { + "internalName": "sugar", + "displayName": "Sugar" + }, + { + "internalName": "snowball", + "displayName": "Snowball" + }, + { + "internalName": "elytra", + "displayName": "Elytra" + }, + { + "internalName": "chestplateCloth", + "displayName": "Leather Tunic", + "allowCustomColour": true, + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Armour_Default_Leather_Colour", + "variants": [ "Armour_Default_Leather_Colour" ] + } + }, + { + "internalName": "chestplateChain", + "displayName": "Chain Chestplate" + }, + { + "internalName": "chestplateIron", + "displayName": "Iron Chestplate" + }, + { + "internalName": "chestplateDiamond", + "displayName": "Diamond Chestplate" + }, + { + "internalName": "chestplateGold", + "displayName": "Golden Chestplate" + }, + { + "internalName": "bow", + "displayName": "Bow" + }, + { + "internalName": "brick", + "displayName": "Brick" + }, + { + "internalName": "ingotIron", + "displayName": "Iron Ingot" + }, + { + "internalName": "feather", + "displayName": "Feather" + }, + { + "internalName": "wheat", + "displayName": "Wheat" + }, + { + "internalName": "painting", + "displayName": "Painting" + }, + { + "internalName": "reeds", + "displayName": "Sugar Canes" + }, + { + "internalName": "bone", + "displayName": "Bone" + }, + { + "internalName": "cake", + "displayName": "Cake" + }, + { + "internalName": "slimeball", + "displayName": "Slimeball" + }, + { + "internalName": "broken_elytra", + "displayName": "Elytra (Broken)" + }, + { + "internalName": "leggingsCloth", + "displayName": "Leather Pants", + "allowCustomColour": true, + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Armour_Default_Leather_Colour", + "variants": [ "Armour_Default_Leather_Colour" ] + } + }, + { + "internalName": "leggingsChain", + "displayName": "Chain Leggings" + }, + { + "internalName": "leggingsIron", + "displayName": "Iron Leggings" + }, + { + "internalName": "leggingsDiamond", + "displayName": "Diamond Leggings" + }, + { + "internalName": "leggingsGold", + "displayName": "Golden Leggings" + }, + { + "internalName": "arrow", + "displayName": "Arrow" + }, + { + "internalName": "end_crystal", + "displayName": "End Crystal" + }, + { + "internalName": "ingotGold", + "displayName": "Gold Ingot" + }, + { + "internalName": "sulphur", + "displayName": "Gunpowder" + }, + { + "internalName": "bread", + "displayName": "Bread" + }, + { + "internalName": "sign", + "displayName": "Oak Sign" + }, + { + "internalName": "doorWood", + "displayName": "Oak Door" + }, + { + "internalName": "doorIron", + "displayName": "Iron Door" + }, + { + "internalName": "bed", + "displayName": "Bed" + }, + { + "internalName": "fireball", + "displayName": "Fire Charge" + }, + { + "internalName": "chorus_fruit", + "displayName": "Chorus Fruit" + }, + { + "internalName": "bootsCloth", + "displayName": "Leather Boots", + "allowCustomColour": true, + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Armour_Default_Leather_Colour", + "variants": [ "Armour_Default_Leather_Colour" ] + } + }, + { + "internalName": "bootsChain", + "displayName": "Chain Boots" + }, + { + "internalName": "bootsIron", + "displayName": "Iron Boots" + }, + { + "internalName": "bootsDiamond", + "displayName": "Diamond Boots" + }, + { + "internalName": "bootsGold", + "displayName": "Golden Boots" + }, + { + "internalName": "stick", + "displayName": "Stick" + }, + { + "internalName": "compass", + "displayName": "Compass" + }, + { + "internalName": "diamond", + "displayName": "Diamond" + }, + { + "internalName": "redstone", + "displayName": "Redstone" + }, + { + "internalName": "clay", + "displayName": "Clay" + }, + { + "internalName": "paper", + "displayName": "Paper" + }, + { + "internalName": "book", + "displayName": "Book" + }, + { + "internalName": "map", + "displayName": "Map" + }, + { + "internalName": "seeds_pumpkin", + "displayName": "Pumpkin Seeds" + }, + { + "internalName": "seeds_melon", + "displayName": "Melon Seeds" + }, + { + "internalName": "chorus_fruit_popped", + "displayName": "Popped Chorus Fruit" + }, + { + "internalName": "swordWood", + "displayName": "Wooden Sword" + }, + { + "internalName": "swordStone", + "displayName": "Stone Sword" + }, + { + "internalName": "swordIron", + "displayName": "Iron Sword" + }, + { + "internalName": "swordDiamond", + "displayName": "Diamond Sword" + }, + { + "internalName": "swordGold", + "displayName": "Golden Sword" + }, + { + "internalName": "fishingRod_uncast", + "displayName": "Fishing Rod" + }, + { + "internalName": "clock", + "displayName": "Clock" + }, + { + "internalName": "bowl", + "displayName": "Bowl" + }, + { + "internalName": "mushroomStew", + "displayName": "Mushroom Stew" + }, + { + "internalName": "yellowDust", + "displayName": "Glowstone Dust" + }, + { + "internalName": "bucket", + "displayName": "Bucket" + }, + { + "internalName": "bucketWater", + "displayName": "Water Bucket" + }, + { + "internalName": "bucketLava", + "displayName": "Lava Bucket" + }, + { + "internalName": "milk", + "displayName": "Milk Bucket" + }, + { + "internalName": "dyePowder_black", + "displayName": "Ink Sac" + }, + { + "internalName": "dyePowder_gray", + "displayName": "Gray Dye" + }, + { + "internalName": "shovelWood", + "displayName": "Wooden Shovel" + }, + { + "internalName": "shovelStone", + "displayName": "Stone Shovel" + }, + { + "internalName": "shovelIron", + "displayName": "Iron Shovel" + }, + { + "internalName": "shovelDiamond", + "displayName": "Diamond Shovel" + }, + { + "internalName": "shovelGold", + "displayName": "Golden Shovel" + }, + { + "internalName": "fishingRod_cast", + "displayName": "Fishing Rod (Cast)" + }, + { + "internalName": "diode", + "displayName": "Redstone Repeater" + }, + { + "internalName": "porkchopRaw", + "displayName": "Raw Porkchop" + }, + { + "internalName": "porkchopCooked", + "displayName": "Cooked Porkchop" + }, + { + "internalName": "fishRaw", + "displayName": "Raw Cod" + }, + { + "internalName": "fishCooked", + "displayName": "Cooked Cod" + }, + { + "internalName": "rottenFlesh", + "displayName": "Rotten Flesh" + }, + { + "internalName": "cookie", + "displayName": "Cookie" + }, + { + "internalName": "shears", + "displayName": "Shears" + }, + { + "internalName": "dyePowder_red", + "displayName": "Rose Red" + }, + { + "internalName": "dyePowder_pink", + "displayName": "Pink Dye" + }, + { + "internalName": "pickaxeWood", + "displayName": "Wooden Pickaxe" + }, + { + "internalName": "pickaxeStone", + "displayName": "Stone Pickaxe" + }, + { + "internalName": "pickaxeIron", + "displayName": "Iron Pickaxe" + }, + { + "internalName": "pickaxeDiamond", + "displayName": "Diamond Pickaxe" + }, + { + "internalName": "pickaxeGold", + "displayName": "Golden Pickaxe" + }, + { + "internalName": "bow_pull_0", + "displayName": "Bow (Pulling Stage 1)" + }, + { + "internalName": "carrotOnAStick", + "displayName": "Carrot on a Stick" + }, + { + "internalName": "leather", + "displayName": "Leather" + }, + { + "internalName": "saddle", + "displayName": "Saddle" + }, + { + "internalName": "beefRaw", + "displayName": "Raw Beef" + }, + { + "internalName": "beefCooked", + "displayName": "Steak" + }, + { + "internalName": "enderPearl", + "displayName": "Ender Pearl" + }, + { + "internalName": "blazeRod", + "displayName": "Blaze Rod" + }, + { + "internalName": "melon", + "displayName": "Melon Slice" + }, + { + "internalName": "dyePowder_green", + "displayName": "Cactus Green" + }, + { + "internalName": "dyePowder_lime", + "displayName": "Lime Dye" + }, + { + "internalName": "hatchetWood", + "displayName": "Wooden Axe" + }, + { + "internalName": "hatchetStone", + "displayName": "Stone Axe" + }, + { + "internalName": "hatchetIron", + "displayName": "Iron Axe" + }, + { + "internalName": "hatchetDiamond", + "displayName": "Diamond Axe" + }, + { + "internalName": "hatchetGold", + "displayName": "Golden Axe" + }, + { + "internalName": "bow_pull_1", + "displayName": "Bow (Pulling Stage 2)" + }, + { + "internalName": "potatoBaked", + "displayName": "Baked Potato" + }, + { + "internalName": "potato", + "displayName": "Potato" + }, + { + "internalName": "carrots", + "displayName": "Carrot" + }, + { + "internalName": "chickenRaw", + "displayName": "Raw Chicken" + }, + { + "internalName": "chickenCooked", + "displayName": "Cooked Chicken" + }, + { + "internalName": "ghastTear", + "displayName": "Ghast Tear" + }, + { + "internalName": "goldNugget", + "displayName": "Gold Nugget" + }, + { + "internalName": "netherStalkSeeds", + "displayName": "Nether Wart" + }, + { + "internalName": "dyePowder_brown", + "displayName": "Cocoa Beans" + }, + { + "internalName": "dyePowder_yellow", + "displayName": "Dandelion Yellow" + }, + { + "internalName": "hoeWood", + "displayName": "Wooden Hoe" + }, + { + "internalName": "hoeStone", + "displayName": "Stone Hoe" + }, + { + "internalName": "hoeIron", + "displayName": "Iron Hoe" + }, + { + "internalName": "hoeDiamond", + "displayName": "Diamond Hoe" + }, + { + "internalName": "hoeGold", + "displayName": "Golden Hoe" + }, + { + "internalName": "bow_pull_2", + "displayName": "Bow (Pulling Stage 3)" + }, + { + "internalName": "potatoPoisonous", + "displayName": "Poisonous Potato" + }, + { + "internalName": "minecart", + "displayName": "Minecart" + }, + { + "internalName": "boat", + "displayName": "Oak Boat" + }, + { + "internalName": "speckledMelon", + "displayName": "Glistering Melon" + }, + { + "internalName": "fermentedSpiderEye", + "displayName": "Fermented Spider Eye" + }, + { + "internalName": "spiderEye", + "displayName": "Spider Eye" + }, + { + "internalName": "glassBottle", + "displayName": "Glass Bottle" + }, + { + "internalName": "potion_contents", + "displayName": "Potion (Overlay)", + "allowCustomColour": true, + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "dyePowder_blue", + "displayName": "Lapis Lazuli" + }, + { + "internalName": "dyePowder_light_blue", + "displayName": "Light Blue Dye" + }, + { + "internalName": "helmetCloth_overlay", + "displayName": "Leather Cap (Overlay)" + }, + { + "internalName": "spectral_arrow", + "displayName": "Spectral Arrow" + }, + { + "internalName": "iron_horse_armor", + "displayName": "Iron Horse Armor" + }, + { + "internalName": "diamond_horse_armor", + "displayName": "Diamond Horse Armor" + }, + { + "internalName": "gold_horse_armor", + "displayName": "Gold Horse Armor" + }, + { + "internalName": "comparator", + "displayName": "Redstone Comparator" + }, + { + "internalName": "carrotGolden", + "displayName": "Golden Carrot" + }, + { + "internalName": "minecart_chest", + "displayName": "Minecart with Chest" + }, + { + "internalName": "pumpkinPie", + "displayName": "Pumpkin Pie" + }, + { + "internalName": "monsterPlacer", + "displayName": "Spawn Egg", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Mob_Creeper_Colour1", + "variants": [ + "Mob_Creeper_Colour1", + "Mob_Skeleton_Colour1", + "Mob_Spider_Colour1", + "Mob_Zombie_Colour1", + "Mob_Slime_Colour1", + "Mob_Ghast_Colour1", + "Mob_PigZombie_Colour1", + "Mob_Enderman_Colour1", + "Mob_CaveSpider_Colour1", + "Mob_Silverfish_Colour1", + "Mob_Blaze_Colour1", + "Mob_LavaSlime_Colour1", + "Mob_Pig_Colour1", + "Mob_Sheep_Colour1", + "Mob_Cow_Colour1", + "Mob_Chicken_Colour1", + "Mob_Squid_Colour1", + "Mob_Wolf_Colour1", + "Mob_MushroomCow_Colour1", + "Mob_Ocelot_Colour1", + "Mob_Villager_Colour1", + "Mob_Bat_Colour1", + "Mob_Witch_Colour1", + "Mob_Horse_Colour1", + "Mob_Endermite_Color1", + "Mob_Guardian_Color1", + "Mob_Rabbit_Colour1", + "Mob_PolarBear_Colour1", + "Mob_Shulker_Colour1", + "Mob_Elder_Guardian_Colour1", + "Mob_Evocation_Illager_Colour1", + "Mob_Llama_Colour1", + "Mob_Donkey_Colour1", + "Mob_Skeleton_Horse_Colour1", + "Mob_Zombie_Horse_Colour1", + "Mob_Mule_Colour1", + "Mob_Stray_Colour1", + "Mob_Husk_Colour1", + "Mob_Vex_Colour1", + "Mob_Vindication_Illager_Colour1", + "Mob_Zombie_Villager_Colour1", + "Mob_Parrot_Colour1", + "Mob_Wither_Skeleton_Colour1", + "Mob_Turtle_Colour1", + "Mob_Tropical_Colour1", + "Mob_Cod_Colour1", + "Mob_Pufferfish_Colour1", + "Mob_Salmon_Colour1", + "Mob_Drowned_Colour1", + "Mob_Dolphin_Colour1", + "Mob_Phantom_Colour1" + ] + } + }, + { + "internalName": "potion_splash", + "displayName": "Splash Potion" + }, + { + "internalName": "eyeOfEnder", + "displayName": "Eye of Ender" + }, + { + "internalName": "cauldron", + "displayName": "Cauldron" + }, + { + "internalName": "blazePowder", + "displayName": "Blaze Powder" + }, + { + "internalName": "dyePowder_purple", + "displayName": "Purple Dye" + }, + { + "internalName": "dyePowder_magenta", + "displayName": "Magenta Dye" + }, + { + "internalName": "chestplateCloth_overlay", + "displayName": "Leather Tunic (Overlay)" + }, + { + "internalName": "tipped_arrow_base", + "displayName": "Tipped Arrow" + }, + { + "internalName": "dragon_breath", + "displayName": "Dragon's Breath" + }, + { + "internalName": "name_tag", + "displayName": "Name Tag" + }, + { + "internalName": "lead", + "displayName": "Lead" + }, + { + "internalName": "netherbrick", + "displayName": "Nether Brick" + }, + { + "internalName": "fish_clownfish_raw", + "displayName": "Tropical Fish" + }, + { + "internalName": "minecart_furnace", + "displayName": "Minecart with Furnace" + }, + { + "internalName": "charcoal", + "displayName": "Charcoal" + }, + { + "internalName": "monsterPlacer_overlay", + "displayName": "Spawn Egg (Overlay)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Mob_Creeper_Colour2", + "variants": [ + "Mob_Creeper_Colour2", + "Mob_Skeleton_Colour2", + "Mob_Spider_Colour2", + "Mob_Zombie_Colour2", + "Mob_Slime_Colour2", + "Mob_Ghast_Colour2", + "Mob_PigZombie_Colour2", + "Mob_Enderman_Colour2", + "Mob_CaveSpider_Colour2", + "Mob_Silverfish_Colour2", + "Mob_Blaze_Colour2", + "Mob_LavaSlime_Colour2", + "Mob_Pig_Colour2", + "Mob_Sheep_Colour2", + "Mob_Cow_Colour2", + "Mob_Chicken_Colour2", + "Mob_Squid_Colour2", + "Mob_Wolf_Colour2", + "Mob_MushroomCow_Colour2", + "Mob_Ocelot_Colour2", + "Mob_Villager_Colour2", + "Mob_Bat_Colour2", + "Mob_Witch_Colour2", + "Mob_Horse_Colour2", + "Mob_Endermite_Color2", + "Mob_Guardian_Color2", + "Mob_Rabbit_Colour2", + "Mob_PolarBear_Colour2", + "Mob_Shulker_Colour2", + "Mob_Elder_Guardian_Colour2", + "Mob_Evocation_Illager_Colour2", + "Mob_Llama_Colour2", + "Mob_Donkey_Colour2", + "Mob_Skeleton_Horse_Colour2", + "Mob_Zombie_Horse_Colour2", + "Mob_Mule_Colour2", + "Mob_Stray_Colour2", + "Mob_Husk_Colour2", + "Mob_Vex_Colour2", + "Mob_Vindication_Illager_Colour2", + "Mob_Zombie_Villager_Colour2", + "Mob_Parrot_Colour2", + "Mob_Wither_Skeleton_Colour2", + "Mob_Turtle_Colour2", + "Mob_Tropical_Colour2", + "Mob_Cod_Colour2", + "Mob_Pufferfish_Colour2", + "Mob_Salmon_Colour2", + "Mob_Drowned_Colour2", + "Mob_Dolphin_Colour2", + "Mob_Phantom_Colour2" + ] + } + }, + { + "internalName": "bed_overlay", + "displayName": "Bed (Overlay)", + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Bed_White", + "variants": [ + "Bed_Black", + "Bed_Blue", + "Bed_Brown", + "Bed_Cyan", + "Bed_Grey", + "Bed_Green", + "Bed_Light_Blue", + "Bed_Lime", + "Bed_Magenta", + "Bed_Orange", + "Bed_Pink", + "Bed_Purple", + "Bed_Red", + "Bed_Silver", + "Bed_White", + "Bed_Yellow" + ] + } + }, + { + "internalName": "expBottle", + "displayName": "Bottle o'Enchanting" + }, + { + "internalName": "brewingStand", + "displayName": "Brewing Stand" + }, + { + "internalName": "magmaCream", + "displayName": "Magma Cream" + }, + { + "internalName": "dyePowder_cyan", + "displayName": "Cyan Dye" + }, + { + "internalName": "dyePowder_orange", + "displayName": "Orange Dye" + }, + { + "internalName": "leggingsCloth_overlay", + "displayName": "Leather Pants (Overlay)" + }, + { + "internalName": "tipped_arrow_head", + "displayName": "Tipped Arrow (Overlay)" + }, + { + "internalName": "potion_bottle_lingering", + "displayName": "Lingering Potion" + }, + { + "internalName": "barrier", + "displayName": "debug_fourj_item" + }, + { + "internalName": "mutton_raw", + "displayName": "Raw Mutton" + }, + { + "internalName": "rabbit_raw", + "displayName": "Raw Rabbit" + }, + { + "internalName": "fish_pufferfish_raw", + "displayName": "Pufferfish" + }, + { + "internalName": "minecart_hopper", + "displayName": "Minecart with Hopper" + }, + { + "internalName": "hopper", + "displayName": "Hopper" + }, + { + "internalName": "nether_star", + "displayName": "Nether Star" + }, + { + "internalName": "emerald", + "displayName": "Emerald" + }, + { + "internalName": "writingBook", + "displayName": "Book and Quill" + }, + { + "internalName": "writtenBook", + "displayName": "Written Book" + }, + { + "internalName": "flowerPot", + "displayName": "Flower Pot" + }, + { + "internalName": "dyePowder_silver", + "displayName": "Light Gray Dye" + }, + { + "internalName": "dyePowder_white", + "displayName": "Bone Meal" + }, + { + "internalName": "bootsCloth_overlay", + "displayName": "Leather Boots (Overlay)" + }, + { + "internalName": "beetroot", + "displayName": "Beetroot" + }, + { + "internalName": "beetroot_seeds", + "displayName": "Beetroot Seeds" + }, + { + "internalName": "beetroot_soup", + "displayName": "Beetroot Soup" + }, + { + "internalName": "mutton_cooked", + "displayName": "Cooked Mutton" + }, + { + "internalName": "rabbit_cooked", + "displayName": "Cooked Rabbit" + }, + { + "internalName": "fish_salmon_raw", + "displayName": "Raw Salmon" + }, + { + "internalName": "minecart_tnt", + "displayName": "Minecart with TNT" + }, + { + "internalName": "wooden_armorstand", + "displayName": "Armor Stand" + }, + { + "internalName": "fireworks", + "displayName": "Firework Rocket" + }, + { + "internalName": "fireworks_charge", + "displayName": "Firework Star" + }, + { + "internalName": "fireworks_charge_overlay", + "displayName": "Firework Star (Overlay)", + "allowCustomColour": true + }, + { + "internalName": "netherquartz", + "displayName": "Nether Quartz" + }, + { + "internalName": "map_empty", + "displayName": "Empty Map" + }, + { + "internalName": "frame", + "displayName": "Item Frame" + }, + { + "internalName": "enchantedBook", + "displayName": "Enchanted Book" + }, + { + "internalName": "door_acacia", + "displayName": "Acacia Door" + }, + { + "internalName": "door_birch", + "displayName": "Birch Door" + }, + { + "internalName": "door_dark_oak", + "displayName": "Dark Oak Door" + }, + { + "internalName": "door_jungle", + "displayName": "Jungle Door" + }, + { + "internalName": "door_spruce", + "displayName": "Spruce Door" + }, + { + "internalName": "rabbit_stew", + "displayName": "Rabbit Stew" + }, + { + "internalName": "fish_salmon_cooked", + "displayName": "Cooked Salmon" + }, + { + "internalName": "minecart_command_block", + "displayName": "Minecart with Command Block" + }, + { + "internalName": "acacia_boat", + "displayName": "Acacia Boat" + }, + { + "internalName": "birch_boat", + "displayName": "Birch Boat" + }, + { + "internalName": "dark_oak_boat", + "displayName": "Dark Oak Boat" + }, + { + "internalName": "jungle_boat", + "displayName": "Jungle Boat" + }, + { + "internalName": "spruce_boat", + "displayName": "Spruce Boat" + }, + { + "internalName": "prismarine_shard", + "displayName": "Prismarine Shard" + }, + { + "internalName": "prismarine_crystals", + "displayName": "Prismarine Crystals" + }, + { + "internalName": "leather_horse_armor_base", + "displayName": "Leather Horse Armor", + "allowCustomColour": true, + "hasColourEntry": true, + "colourEntry": { + "defaultName": "Armour_Default_Leather_Colour", + "variants": [ "Armour_Default_Leather_Colour" ] + } + }, + { + "internalName": "structure_void", + "displayName": "Structure Void" + }, + { + "internalName": "map_filled_markings", + "displayName": "Filled Map (Overlay)" + }, + { + "internalName": "totem", + "displayName": "Totem of Undying" + }, + { + "internalName": "shulker_shell", + "displayName": "Shulker Shell" + }, + { + "internalName": "iron_nugget", + "displayName": "Iron Nugget" + }, + { + "internalName": "rabbit_foot", + "displayName": "Rabbit's Foot" + }, + { + "internalName": "rabbit_hide", + "displayName": "Rabbit Hide" + }, + { + "internalName": "compass", + "displayName": "" + }, + { + "internalName": "compass", + "displayName": "" + }, + { + "internalName": "compass", + "displayName": "" + }, + { + "internalName": "compass", + "displayName": "" + }, + { + "internalName": "clock", + "displayName": "" + }, + { + "internalName": "clock", + "displayName": "" + }, + { + "internalName": "clock", + "displayName": "" + }, + { + "internalName": "clock", + "displayName": "" + }, + { + "internalName": "dragonFireball", + "displayName": "Dragon Fireball" + }, + { + "internalName": "record_13", + "displayName": "Music Disc (C418 - 13)" + }, + { + "internalName": "record_cat", + "displayName": "Music Disc (C418 - cat)" + }, + { + "internalName": "record_blocks", + "displayName": "Music Disc (C418 - blocks)" + }, + { + "internalName": "record_chirp", + "displayName": "Music Disc (C418 - chirp)" + }, + { + "internalName": "record_far", + "displayName": "Music Disc (C418 - far)" + }, + { + "internalName": "record_mall", + "displayName": "Music Disc (C418 - mall)" + }, + { + "internalName": "record_mellohi", + "displayName": "Music Disc (C418 - mellohi)" + }, + { + "internalName": "record_stal", + "displayName": "Music Disc (C418 - stal)" + }, + { + "internalName": "record_strad", + "displayName": "Music Disc (C418 - strad)" + }, + { + "internalName": "record_ward", + "displayName": "Music Disc (C418 - ward)" + }, + { + "internalName": "record_11", + "displayName": "Music Disc (C418 - 11)" + }, + { + "internalName": "record_where are we now", + "displayName": "Music Disc (C418 - wait)" + }, + { + "internalName": "bucketFish", + "displayName": "Bucket of Cod" + }, + { + "internalName": "bucketSalmon", + "displayName": "Bucket of Salmon" + }, + { + "internalName": "bucketPuffer", + "displayName": "Bucket of Pufferfish" + }, + { + "internalName": "bucketTropical", + "displayName": "Bucket of Tropical Fish" + }, + { + "internalName": "leather_horse_armor_detail", + "displayName": "Leather Horse Armor (Overlay)" + }, + { + "internalName": "dyePowder_black1", + "displayName": "Black Dye [PS4 ONLY]" + }, + { + "internalName": "dyePowder_blue1", + "displayName": "Blue Dye [PS4 ONLY]" + }, + { + "internalName": "dyePowder_brown1", + "displayName": "Brown Dye [PS4 ONLY]" + }, + { + "internalName": "dyePowder_white1", + "displayName": "White Dye [PS4 ONLY]" + }, + { + "internalName": "bamboo", + "displayName": "Bamboo [PS4 ONLY]" + }, + { + "internalName": "lantern_carried", + "displayName": "Lantern [PS4 ONLY]" + }, + { + "internalName": "kelp", + "displayName": "Kelp" + }, + { + "internalName": "dried_kelp", + "displayName": "Dried Kelp" + }, + { + "internalName": "sea_pickle", + "displayName": "Sea Pickle" + }, + { + "internalName": "nautilus", + "displayName": "Nautilus Shell" + }, + { + "internalName": "nautilus_core", + "displayName": "Heart of the Sea" + }, + { + "internalName": "turtle_helmet", + "displayName": "Turtle Shell" + }, + { + "internalName": "turtle_shell_piece", + "displayName": "Scute" + }, + { + "internalName": "trident", + "displayName": "Trident" + }, + { + "internalName": "phantom_membrane", + "displayName": "Phantom Membrane" + }, + { + "internalName": "acacia_sign", + "displayName": "Acacia Sign [PS4 ONLY]" + }, + { + "internalName": "birch_sign", + "displayName": "Birch Sign [PS4 ONLY]" + }, + { + "internalName": "dark_oak_sign", + "displayName": "Dark Oak Sign [PS4 ONLY]" + }, + { + "internalName": "jungle_sign", + "displayName": "Jungle Sign [PS4 ONLY]" + }, + { + "internalName": "spruce_sign", + "displayName": "Spruce Sign [PS4 ONLY]" + }, + { + "internalName": "crossbow", + "displayName": "Crossbow [PS4 ONLY]" + }, + { + "internalName": "crossbow_pull_0", + "displayName": "Crossbow (Pulling Stage 1) [PS4 ONLY]" + }, + { + "internalName": "crossbow_pull_1", + "displayName": "Crossbow (Pulling Stage 2) [PS4 ONLY]" + }, + { + "internalName": "crossbow_pull_2", + "displayName": "Crossbow (Pulling Stage 3) [PS4 ONLY]" + }, + { + "internalName": "crossbow_arrow", + "displayName": "Crossbow (Loaded) [PS4 ONLY]" + }, + { + "internalName": "crossbow_firework", + "displayName": "Crossbow (Loaded) (Firework) [PS4 ONLY]" + }, + { + "internalName": "sweet_berries", + "displayName": "Sweet Berries [PS4 ONLY]" + }, + { + "internalName": "banner_pattern", + "displayName": "Banner Pattern [PS4 ONLY]" + }, + { + "internalName": "bell", + "displayName": "Bell [PS4 ONLY]" + }, + { + "internalName": "campfire_carried", + "displayName": "Campfire [PS4 ONLY]" + }, + { + "internalName": "", + "displayName": "" + } + ] +} diff --git a/PckStudio.Core/Resources/items.png b/PckStudio.Core/Resources/items.png new file mode 100644 index 00000000..6d316ad9 Binary files /dev/null and b/PckStudio.Core/Resources/items.png differ diff --git a/PckStudio.Core/Resources/mapIconData.json b/PckStudio.Core/Resources/mapIconData.json new file mode 100644 index 00000000..8e1273f2 --- /dev/null +++ b/PckStudio.Core/Resources/mapIconData.json @@ -0,0 +1,135 @@ +{ + "COMMENT_1": "JSON by MattNL", + "entries": [ + { + "internalName": "player_1", + "displayName": "Player 1" + }, + { + "internalName": "player_2", + "displayName": "Player 2" + }, + { + "internalName": "player_3", + "displayName": "Player 3" + }, + { + "internalName": "player_4", + "displayName": "Player 4" + }, + { + "internalName": "target_x", + "displayName": "Unused" + }, + { + "internalName": "target_point", + "displayName": "Target Point (Unused)" + }, + { + "internalName": "player_off_map", + "displayName": "Player (Off Map) (Unused)" + }, + { + "internalName": "frame", + "displayName": "Item Frame" + }, + { + "internalName": "player_5", + "displayName": "Player 5" + }, + { + "internalName": "player_6", + "displayName": "Player 6" + }, + { + "internalName": "player_7", + "displayName": "Player 7" + }, + { + "internalName": "player_8", + "displayName": "Player 8" + }, + { + "internalName": "structure", + "displayName": "Structure (Explorer Map)" + }, + { + "internalName": "player_off_limits", + "displayName": "Player (Off Limits) (Unused)" + }, + { + "internalName": "mansion", + "displayName": "Woodland Mansion (Explorer Map)" + }, + { + "internalName": "monument", + "displayName": "Ocean Monument (Explorer Map)" + } + ], + "additional_entries": [ + { + "internalName": "player_1_off_map", + "displayName": "Player 1 (Off Map)" + }, + { + "internalName": "player_2_off_map", + "displayName": "Player 2 (Off Map)" + }, + { + "internalName": "player_3_off_map", + "displayName": "Player 3 (Off Map)" + }, + { + "internalName": "player_4_off_map", + "displayName": "Player 4 (Off Map)" + }, + { + "internalName": "treasure", + "displayName": "Buried Treasure" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "player_5_off_map", + "displayName": "Player 5 (Off Map)" + }, + { + "internalName": "player_6_off_map", + "displayName": "Player 6 (Off Map)" + }, + { + "internalName": "player_7_off_map", + "displayName": "Player 7 (Off Map)" + }, + { + "internalName": "player_8_off_map", + "displayName": "Player 8 (Off Map)" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + } + ] +} diff --git a/PckStudio.Core/Resources/map_icons.png b/PckStudio.Core/Resources/map_icons.png new file mode 100644 index 00000000..7b6ecd13 Binary files /dev/null and b/PckStudio.Core/Resources/map_icons.png differ diff --git a/PckStudio.Core/Resources/moonPhaseData.json b/PckStudio.Core/Resources/moonPhaseData.json new file mode 100644 index 00000000..506e7f6f --- /dev/null +++ b/PckStudio.Core/Resources/moonPhaseData.json @@ -0,0 +1,37 @@ +{ + "COMMENT_1": "JSON by MattNL", + "entries": [ + { + "internalName": "moon_phase_0", + "displayName": "Full Moon" + }, + { + "internalName": "moon_phase_1", + "displayName": "Waning Gibbous" + }, + { + "internalName": "moon_phase_2", + "displayName": "Last Quarter" + }, + { + "internalName": "moon_phase_3", + "displayName": "Waning Crescent" + }, + { + "internalName": "moon_phase_4", + "displayName": "New Moon" + }, + { + "internalName": "moon_phase_5", + "displayName": "Waxing Crescent" + }, + { + "internalName": "moon_phase_6", + "displayName": "First Quarter" + }, + { + "internalName": "moon_phase_7", + "displayName": "Waxing Gibbous" + } + ] +} diff --git a/PckStudio.Core/Resources/moon_phases.png b/PckStudio.Core/Resources/moon_phases.png new file mode 100644 index 00000000..ce239ea7 Binary files /dev/null and b/PckStudio.Core/Resources/moon_phases.png differ diff --git a/PckStudio.Core/Resources/paintingData.json b/PckStudio.Core/Resources/paintingData.json new file mode 100644 index 00000000..5b5b0ef9 --- /dev/null +++ b/PckStudio.Core/Resources/paintingData.json @@ -0,0 +1,1062 @@ +{ + "COMMENT_1": "JSON by MattNL", + "entries": [ + { + "internalName": "Kebab", + "displayName": "\"Kebab med tre pepperoni\" by Kristoffer Zetterstrand" + }, + { + "internalName": "Aztec", + "displayName": "\"de_aztec\" by Kristoffer Zetterstrand" + }, + { + "internalName": "Alban", + "displayName": "\"Albanian\" by Kristoffer Zetterstrand" + }, + { + "internalName": "Aztec2", + "displayName": "\"de_aztec\" by Kristoffer Zetterstrand" + }, + { + "internalName": "Bomb", + "displayName": "\"Target Successfully Bombed\" by Kristoffer Zetterstrand" + }, + { + "internalName": "Plant", + "displayName": "\"Paradisträd\" by Kristoffer Zetterstrand" + }, + { + "internalName": "Wasteland", + "displayName": "\"Wasteland\" by Kristoffer Zetterstrand" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "Back", + "displayName": "Back Texture", + "width": 4, + "height": 4 + }, + { + "internalName": "Back", + "displayName": "", + }, + { + "internalName": "Back", + "displayName": "", + }, + { + "internalName": "Back", + "displayName": "", + }, + { + "internalName": "1x1E1", + "displayName": "Extra Painting 1" + }, + { + "internalName": "1x1E2", + "displayName": "Extra Painting 2" + }, + { + "internalName": "1x1E3", + "displayName": "Extra Painting 3" + }, + { + "internalName": "1x1E4", + "displayName": "Extra Painting 4" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "Back", + "displayName": "" + }, + { + "internalName": "Back", + "displayName": "", + }, + { + "internalName": "Back", + "displayName": "", + }, + { + "internalName": "Back", + "displayName": "", + }, + { + "internalName": "Pool", + "displayName": "\"The Pool\" by Kristoffer Zetterstrand", + "width": 2 + }, + { + "internalName": "Pool", + "displayName": "" + }, + { + "internalName": "Courbet", + "displayName": "\"Bonjour Monsieur Courbet\" by Kristoffer Zetterstrand", + "width": 2 + }, + { + "internalName": "Courbet", + "displayName": "" + }, + { + "internalName": "Sea", + "displayName": "\"Seaside\" by Kristoffer Zetterstrand", + "width": 2 + }, + { + "internalName": "Sea", + "displayName": "" + }, + { + "internalName": "Sunset", + "displayName": "\"sunset_dense\" by Kristoffer Zetterstrand", + "width": 2 + }, + { + "internalName": "Sunset", + "displayName": "" + }, + { + "internalName": "Creebet", + "displayName": "\"Creebet\" by Kristoffer Zetterstrand", + "width": 2 + }, + { + "internalName": "Creebet", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "Back", + "displayName": "" + }, + { + "internalName": "Back", + "displayName": "", + }, + { + "internalName": "Back", + "displayName": "", + }, + { + "internalName": "Back", + "displayName": "", + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "Back", + "displayName": "" + }, + { + "internalName": "Back", + "displayName": "", + }, + { + "internalName": "Back", + "displayName": "", + }, + { + "internalName": "Back", + "displayName": "", + }, + { + "internalName": "Wanderer", + "displayName": "\"Wanderer\" by Kristoffer Zetterstrand", + "height": 2 + }, + { + "internalName": "Graham", + "displayName": "\"Graham\" by Kristoffer Zetterstrand", + "height": 2 + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "Skeleton", + "displayName": "\"Mortal Coil\" by Kristoffer Zetterstrand", + "width": 4, + "height": 3 + }, + { + "internalName": "Skeleton", + "displayName": "", + }, + { + "internalName": "Skeleton", + "displayName": "", + }, + { + "internalName": "Skeleton", + "displayName": "", + }, + { + "internalName": "Wanderer", + "displayName": "" + }, + { + "internalName": "Graham", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "Skeleton", + "displayName": "", + }, + { + "internalName": "Skeleton", + "displayName": "", + }, + { + "internalName": "Skeleton", + "displayName": "", + }, + { + "internalName": "Skeleton", + "displayName": "", + }, + { + "internalName": "Fighters", + "displayName": "\"Fighters\" by Kristoffer Zetterstrand", + "width": 4, + "height": 2 + }, + { + "internalName": "Fighters", + "displayName": "" + }, + { + "internalName": "Fighters", + "displayName": "" + }, + { + "internalName": "Fighters", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "Skeleton", + "displayName": "" + }, + { + "internalName": "Skeleton", + "displayName": "" + }, + { + "internalName": "Skeleton", + "displayName": "" + }, + { + "internalName": "Skeleton", + "displayName": "" + }, + { + "internalName": "Fighters", + "displayName": "" + }, + { + "internalName": "Fighters", + "displayName": "" + }, + { + "internalName": "Fighters", + "displayName": "" + }, + { + "internalName": "Fighters", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "DonkeyKong", + "displayName": "\"Kong\" by Kristoffer Zetterstrand", + "width": 4, + "height": 3 + }, + { + "internalName": "DonkeyKong", + "displayName": "" + }, + { + "internalName": "DonkeyKong", + "displayName": "" + }, + { + "internalName": "DonkeyKong", + "displayName": "" + }, + { + "internalName": "Match", + "displayName": "\"Match\" by Kristoffer Zetterstrand", + "width": 2, + "height": 2 + }, + { + "internalName": "Match", + "displayName": "" + }, + { + "internalName": "Bust", + "displayName": "\"Bust\" by Kristoffer Zetterstrand", + "width": 2, + "height": 2 + }, + { + "internalName": "Bust", + "displayName": "" + }, + { + "internalName": "Stage", + "displayName": "\"The stage is set\" by Kristoffer Zetterstrand", + "width": 2, + "height": 2 + }, + { + "internalName": "Stage", + "displayName": "" + }, + { + "internalName": "Void", + "displayName": "\"The Void\" by Kristoffer Zetterstrand", + "width": 2, + "height": 2 + }, + { + "internalName": "Void", + "displayName": "" + }, + { + "internalName": "SkullAndRoses", + "displayName": "\"Skull and Roses\" by Kristoffer Zetterstrand", + "width": 2, + "height": 2 + }, + { + "internalName": "SkullAndRoses", + "displayName": "" + }, + { + "internalName": "Wither", + "displayName": "\"Wither\" by Jens Bergensten", + "width": 2, + "height": 2 + }, + { + "internalName": "Wither", + "displayName": "" + }, + { + "internalName": "DonkeyKong", + "displayName": "" + }, + { + "internalName": "DonkeyKong", + "displayName": "" + }, + { + "internalName": "DonkeyKong", + "displayName": "" + }, + { + "internalName": "DonkeyKong", + "displayName": "" + }, + { + "internalName": "Match", + "displayName": "" + }, + { + "internalName": "Match", + "displayName": "" + }, + { + "internalName": "Bust", + "displayName": "" + }, + { + "internalName": "Bust", + "displayName": "" + }, + { + "internalName": "Stage", + "displayName": "" + }, + { + "internalName": "Stage", + "displayName": "" + }, + { + "internalName": "Void", + "displayName": "" + }, + { + "internalName": "Void", + "displayName": "" + }, + { + "internalName": "SkullAndRoses", + "displayName": "" + }, + { + "internalName": "SkullAndRoses", + "displayName": "" + }, + { + "internalName": "Wither", + "displayName": "" + }, + { + "internalName": "Wither", + "displayName": "" + }, + { + "internalName": "DonkeyKong", + "displayName": "", + }, + { + "internalName": "DonkeyKong", + "displayName": "", + }, + { + "internalName": "DonkeyKong", + "displayName": "", + }, + { + "internalName": "DonkeyKong", + "displayName": "", + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "Pointer", + "displayName": "\"Pointer\" by Kristoffer Zetterstrand", + "width": 4, + "height": 4 + }, + { + "internalName": "Pointer", + "displayName": "" + }, + { + "internalName": "Pointer", + "displayName": "" + }, + { + "internalName": "Pointer", + "displayName": "" + }, + { + "internalName": "Pigscene", + "displayName": "\"Pigscene\" by Kristoffer Zetterstrand", + "width": 4, + "height": 4 + }, + { + "internalName": "Pigscene", + "displayName": "" + }, + { + "internalName": "Pigscene", + "displayName": "" + }, + { + "internalName": "Pigscene", + "displayName": "" + }, + { + "internalName": "BurningSkull", + "displayName": "\"Skull On Fire\" by Kristoffer Zetterstrand", + "width": 4, + "height": 4 + }, + { + "internalName": "BurningSkull", + "displayName": "" + }, + { + "internalName": "BurningSkull", + "displayName": "" + }, + { + "internalName": "BurningSkull", + "displayName": "" + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "Pointer", + "displayName": "", + }, + { + "internalName": "Pointer", + "displayName": "" + }, + { + "internalName": "Pointer", + "displayName": "" + }, + { + "internalName": "Pointer", + "displayName": "" + }, + { + "internalName": "Pigscene", + "displayName": "" + }, + { + "internalName": "Pigscene", + "displayName": "" + }, + { + "internalName": "Pigscene", + "displayName": "" + }, + { + "internalName": "Pigscene", + "displayName": "" + }, + { + "internalName": "BurningSkull", + "displayName": "" + }, + { + "internalName": "BurningSkull", + "displayName": "" + }, + { + "internalName": "BurningSkull", + "displayName": "" + }, + { + "internalName": "BurningSkull", + "displayName": "" + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "Pointer", + "displayName": "" + }, + { + "internalName": "Pointer", + "displayName": "" + }, + { + "internalName": "Pointer", + "displayName": "" + }, + { + "internalName": "Pointer", + "displayName": "" + }, + { + "internalName": "Pigscene", + "displayName": "", + }, + { + "internalName": "Pigscene", + "displayName": "" + }, + { + "internalName": "Pigscene", + "displayName": "" + }, + { + "internalName": "Pigscene", + "displayName": "" + }, + { + "internalName": "BurningSkull", + "displayName": "", + }, + { + "internalName": "BurningSkull", + "displayName": "" + }, + { + "internalName": "BurningSkull", + "displayName": "" + }, + { + "internalName": "BurningSkull", + "displayName": "" + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "Pointer", + "displayName": "", + }, + { + "internalName": "Pointer", + "displayName": "" + }, + { + "internalName": "Pointer", + "displayName": "" + }, + { + "internalName": "Pointer", + "displayName": "" + }, + { + "internalName": "Pigscene", + "displayName": "", + }, + { + "internalName": "Pigscene", + "displayName": "" + }, + { + "internalName": "Pigscene", + "displayName": "" + }, + { + "internalName": "Pigscene", + "displayName": "" + }, + { + "internalName": "BurningSkull", + "displayName": "", + }, + { + "internalName": "BurningSkull", + "displayName": "" + }, + { + "internalName": "BurningSkull", + "displayName": "" + }, + { + "internalName": "BurningSkull", + "displayName": "" + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "", + "displayName": "", + }, + { + "internalName": "", + "displayName": "", + } + ] +} diff --git a/PckStudio.Core/Resources/paintings.png b/PckStudio.Core/Resources/paintings.png new file mode 100644 index 00000000..b8bc84fe Binary files /dev/null and b/PckStudio.Core/Resources/paintings.png differ diff --git a/PckStudio.Core/Resources/particleData.json b/PckStudio.Core/Resources/particleData.json new file mode 100644 index 00000000..924ab98a --- /dev/null +++ b/PckStudio.Core/Resources/particleData.json @@ -0,0 +1,2097 @@ +{ + "COMMENT_1": "JSON by MattNL", + "entries": [ + { + "internalName": "generic_0", + "displayName": "Generic (Stage 1)", + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_Smoke", + "Particle_NetherPortal", + "Particle_EnderPortal", + "Particle_Ender", + "Particle_DragonBreathMin", + "Particle_DragonBreathMax" + ] + } + }, + { + "internalName": "generic_1", + "displayName": "Generic (Stage 2)", + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_Smoke", + "Particle_NetherPortal", + "Particle_EnderPortal", + "Particle_Ender", + "Particle_DragonBreathMin", + "Particle_DragonBreathMax" + ] + } + }, + { + "internalName": "generic_2", + "displayName": "Generic (Stage 3)", + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_Smoke", + "Particle_NetherPortal", + "Particle_EnderPortal", + "Particle_Ender", + "Particle_DragonBreathMin", + "Particle_DragonBreathMax" + ] + } + }, + { + "internalName": "generic_3", + "displayName": "Generic (Stage 4)", + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_Smoke", + "Particle_NetherPortal", + "Particle_EnderPortal", + "Particle_Ender", + "Particle_DragonBreathMin", + "Particle_DragonBreathMax" + ] + } + }, + { + "internalName": "generic_4", + "displayName": "Generic (Stage 5)", + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_Smoke", + "Particle_NetherPortal", + "Particle_EnderPortal", + "Particle_Ender", + "Particle_DragonBreathMin", + "Particle_DragonBreathMax" + ] + } + }, + { + "internalName": "generic_5", + "displayName": "Generic (Stage 6)", + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_Smoke", + "Particle_NetherPortal", + "Particle_EnderPortal", + "Particle_Ender", + "Particle_DragonBreathMin", + "Particle_DragonBreathMax" + ] + } + }, + { + "internalName": "generic_6", + "displayName": "Generic (Stage 7)", + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_Smoke", + "Particle_NetherPortal", + "Particle_EnderPortal", + "Particle_Ender", + "Particle_DragonBreathMin", + "Particle_DragonBreathMax" + ] + } + }, + { + "internalName": "generic_7", + "displayName": "Generic (Stage 8)", + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_Smoke", + "Particle_NetherPortal", + "Particle_EnderPortal", + "Particle_Ender", + "Particle_DragonBreathMin", + "Particle_DragonBreathMax" + ] + } + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "unused_splash_0", + "displayName": "Splash (Stage 1) (Unused)" + }, + { + "internalName": "unused_splash_1", + "displayName": "Splash (Stage 2) (Unused)" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "splash_0", + "displayName": "Splash (Stage 1)" + }, + { + "internalName": "splash_1", + "displayName": "Splash (Stage 2)" + }, + { + "internalName": "splash_2", + "displayName": "Splash (Stage 3)" + }, + { + "internalName": "splash_3", + "displayName": "Splash (Stage 4)" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "classic_bubble", + "displayName": "Bubble (Unused)" + }, + { + "internalName": "bobber", + "displayName": "Fishing Bobber" + }, + { + "internalName": "bubble", + "displayName": "Bubble", + "colourEntry": { + "isWaterColour": true, + "defaultName": "Water_Plains", + "variants": [ + "Water_Ocean", + "Water_Plains", + "Water_Desert", + "Water_ExtremeHills", + "Water_Forest", + "Water_Taiga", + "Water_Swampland", + "Water_River", + "Water_Hell", + "Water_Sky", + "Water_FrozenOcean", + "Water_FrozenRiver", + "Water_IcePlains", + "Water_IceMountains", + "Water_MushroomIsland", + "Water_MushroomIslandShore", + "Water_Beach", + "Water_DesertHills", + "Water_ForestHills", + "Water_TaigaHills", + "Water_ExtremeHillsEdge", + "Water_Jungle", + "Water_JungleHills", + "Water_JungleEdge", + "Water_DeepOcean", + "Water_StoneBeach", + "Water_ColdBeach", + "Water_BirchForest", + "Water_BirchForestHills", + "Water_RoofedForest", + "Water_ColdTaiga", + "Water_ColdTaigaHills", + "Water_MegaTaiga", + "Water_MegaTaigaHills", + "Water_ExtremeHillsPlus", + "Water_Savanna", + "Water_SavannaPlateau", + "Water_Mesa", + "Water_MesaPlateauF", + "Water_MesaPlateau" + ] + } + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "flash", + "displayName": "Firework Flash", + "width": 4, + "height": 4, + "allowCustomColour": true + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "flame", + "displayName": "Flame" + }, + { + "internalName": "lava", + "displayName": "Lava" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "note", + "displayName": "Noteblock Note", + "colourEntry": { + "defaultName": "Particle_Note_00", + "variants": [ + "Particle_Note_00", + "Particle_Note_01", + "Particle_Note_02", + "Particle_Note_03", + "Particle_Note_04", + "Particle_Note_05", + "Particle_Note_06", + "Particle_Note_07", + "Particle_Note_08", + "Particle_Note_09", + "Particle_Note_10", + "Particle_Note_11", + "Particle_Note_12", + "Particle_Note_13", + "Particle_Note_14", + "Particle_Note_15", + "Particle_Note_16", + "Particle_Note_17", + "Particle_Note_18", + "Particle_Note_19", + "Particle_Note_20", + "Particle_Note_21", + "Particle_Note_22", + "Particle_Note_23", + "Particle_Note_24", + ] + } + }, + { + "internalName": "critical_hit", + "displayName": "Critical Hit", + "colourEntry": { + "defaultName": "critical_hit", + "variants": [ + "critical_hit" + ] + } + }, + { + "internalName": "enchanted_hit", + "displayName": "Enchanted Hit", + "colourEntry": { + "defaultName": "critical_hit", + "variants": [ + "critical_hit" + ] + } + }, + { + "internalName": "damage", + "displayName": "Damage Indicator" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "heart", + "displayName": "Heart" + }, + { + "internalName": "angry", + "displayName": "Angry" + }, + { + "internalName": "glint", + "displayName": "Glint" + }, + { + "internalName": "angry_villager", + "displayName": "Angry Villager (Unused)" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "flash", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "water_0", + "displayName": "Water (Stage 1) (Unused)" + }, + { + "internalName": "water_1", + "displayName": "Water (Stage 2) (Unused)" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "bubble_pop_0", + "displayName": "Bubble Pop (Stage 1) (Unused)", + "width": 2, + "height": 2 + }, + { + "internalName": "bubble_pop_0", + "displayName": "" + }, + { + "internalName": "bubble_pop_1", + "displayName": "Bubble Pop (Stage 2) (Unused)", + "width": 2, + "height": 2 + }, + { + "internalName": "bubble_pop_1", + "displayName": "" + }, + { + "internalName": "bubble_pop_2", + "displayName": "Bubble Pop (Stage 3) (Unused)", + "width": 2, + "height": 2 + }, + { + "internalName": "bubble_pop_2", + "displayName": "" + }, + { + "internalName": "bubble_pop_3", + "displayName": "Bubble Pop (Stage 4) (Unused)", + "width": 2, + "height": 2 + }, + { + "internalName": "bubble_pop_3", + "displayName": "" + }, + { + "internalName": "bubble_pop_4", + "displayName": "Bubble Pop (Stage 5) (Unused)", + "width": 2, + "height": 2 + }, + { + "internalName": "bubble_pop_4", + "displayName": "" + }, + { + "internalName": "drip_hang", + "displayName": "Drip (Hang)", + + "colourEntry": { + "defaultName": "Particle_DripWater", + "variants": [ + "Particle_DripWater", + "Particle_DripLavaStart", + "Particle_DripLavaEnd" + ] + } + }, + { + "internalName": "drip_fall", + "displayName": "Drip (Fall)", + "colourEntry": { + "defaultName": "Particle_DripWater", + "variants": [ + "Particle_DripWater", + "Particle_DripLavaStart", + "Particle_DripLavaEnd" + ] + } + }, + { + "internalName": "drip_land", + "displayName": "Drip (Land)", + "colourEntry": { + "defaultName": "Particle_DripWater", + "variants": [ + "Particle_DripWater", + "Particle_DripLavaStart", + "Particle_DripLavaEnd" + ] + } + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "bubble_pop_0", + "displayName": "" + }, + { + "internalName": "bubble_pop_0", + "displayName": "" + }, + { + "internalName": "bubble_pop_1", + "displayName": "" + }, + { + "internalName": "bubble_pop_1", + "displayName": "" + }, + { + "internalName": "bubble_pop_2", + "displayName": "" + }, + { + "internalName": "bubble_pop_2", + "displayName": "" + }, + { + "internalName": "bubble_pop_3", + "displayName": "" + }, + { + "internalName": "bubble_pop_3", + "displayName": "" + }, + { + "internalName": "bubble_pop_4", + "displayName": "" + }, + { + "internalName": "bubble_pop_4", + "displayName": "" + }, + { + "internalName": "effect_0", + "displayName": "Effect (Stage 1)", + + "allowCustomColour": true, + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "effect_1", + "displayName": "Effect (Stage 2)", + + "allowCustomColour": true, + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "effect_2", + "displayName": "Effect (Stage 3)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "effect_3", + "displayName": "Effect (Stage 4)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "effect_4", + "displayName": "Effect (Stage 5)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "effect_5", + "displayName": "Effect (Stage 6)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "effect_6", + "displayName": "Effect (Stage 7)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "effect_7", + "displayName": "Effect (Stage 8)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "spell_0", + "displayName": "Splash Effect (Stage 1)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "spell_1", + "displayName": "Splash Effect (Stage 2)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "spell_2", + "displayName": "Splash Effect (Stage 3)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "spell_3", + "displayName": "Splash Effect (Stage 4)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "spell_4", + "displayName": "Splash Effect (Stage 5)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "spell_5", + "displayName": "Splash Effect (Stage 6)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "spell_6", + "displayName": "Splash Effect (Stage 7)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "spell_7", + "displayName": "Splash Effect (Stage 8)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "Potion_BaseColour", + "variants": [ + "Potion_BaseColour", + "Effect_MovementSpeed", + "Effect_MovementSlowDown", + "Effect_DigSpeed", + "Effect_DigSlowdown", + "Effect_DamageBoost", + "Effect_Heal", + "Effect_Harm", + "Effect_Jump", + "Effect_Confusion", + "Effect_Regeneration", + "Effect_DamageResistance", + "Effect_FireResistance", + "Effect_WaterBreathing", + "Effect_Invisibility", + "Effect_Blindness", + "Effect_NightVision", + "Effect_Hunger", + "Effect_Weakness", + "Effect_Poison", + "Effect_Wither", + "Effect_HealthBoost", + "Effect_Absorption", + "Effect_Saturation", + "Effect_Levitation", + "Effect_Luck", + "Effect_BadLuck", + "Effect_TurtleMaster", + "Effect_SlowFall" + ] + } + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "spark_0", + "displayName": "Firework Spark (Stage 1)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_ScoreRing_Small", + "Particle_ScoreRing_Medium", + "Particle_ScoreRing_Large" + ] + } + }, + { + "internalName": "spark_1", + "displayName": "Firework Spark (Stage 2)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_ScoreRing_Small", + "Particle_ScoreRing_Medium", + "Particle_ScoreRing_Large" + ] + } + }, + { + "internalName": "spark_2", + "displayName": "Firework Spark (Stage 3)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_ScoreRing_Small", + "Particle_ScoreRing_Medium", + "Particle_ScoreRing_Large" + ] + } + }, + { + "internalName": "spark_3", + "displayName": "Firework Spark (Stage 4)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_ScoreRing_Small", + "Particle_ScoreRing_Medium", + "Particle_ScoreRing_Large" + ] + } + }, + { + "internalName": "spark_4", + "displayName": "Firework Spark (Stage 5)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_ScoreRing_Small", + "Particle_ScoreRing_Medium", + "Particle_ScoreRing_Large" + ] + } + }, + { + "internalName": "spark_5", + "displayName": "Firework Spark (Stage 6)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_ScoreRing_Small", + "Particle_ScoreRing_Medium", + "Particle_ScoreRing_Large" + ] + } + }, + { + "internalName": "spark_6", + "displayName": "Firework Spark (Stage 7)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_ScoreRing_Small", + "Particle_ScoreRing_Medium", + "Particle_ScoreRing_Large" + ] + } + }, + { + "internalName": "spark_7", + "displayName": "Firework Spark (Stage 8)", + "allowCustomColour": true, + + "colourEntry": { + "defaultName": "None", + "variants": [ + "None", + "Particle_ScoreRing_Small", + "Particle_ScoreRing_Medium", + "Particle_ScoreRing_Large" + ] + } + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "glitter_0", + "displayName": "Shulker/End Rod Glitter (Stage 1)" + }, + { + "internalName": "glitter_1", + "displayName": "Shulker/End Rod Glitter (Stage 2)" + }, + { + "internalName": "glitter_2", + "displayName": "Shulker/End Rod Glitter (Stage 3)" + }, + { + "internalName": "glitter_3", + "displayName": "Shulker/End Rod Glitter (Stage 4)" + }, + { + "internalName": "glitter_4", + "displayName": "Shulker/End Rod Glitter (Stage 5)" + }, + { + "internalName": "glitter_5", + "displayName": "Shulker/End Rod Glitter (Stage 6)" + }, + { + "internalName": "glitter_6", + "displayName": "Shulker/End Rod Glitter (Stage 7)" + }, + { + "internalName": "glitter_7", + "displayName": "Shulker/End Rod Glitter (Stage 8)" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "camera_shoot_explosion_0", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 1)" + }, + { + "internalName": "camera_shoot_explosion_1", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 2)" + }, + { + "internalName": "camera_shoot_explosion_2", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 3)" + }, + { + "internalName": "camera_shoot_explosion_3", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 4)" + }, + { + "internalName": "camera_shoot_explosion_4", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 5)" + }, + { + "internalName": "camera_shoot_explosion_5", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 6)" + }, + { + "internalName": "camera_shoot_explosion_6", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 7)" + }, + { + "internalName": "camera_shoot_explosion_7", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 8)" + }, + { + "internalName": "camera_shoot_explosion_8", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 9)" + }, + { + "internalName": "camera_shoot_explosion_9", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 10)" + }, + { + "internalName": "camera_shoot_explosion_10", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 11)" + }, + { + "internalName": "camera_shoot_explosion_11", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 12)" + }, + { + "internalName": "camera_shoot_explosion_12", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 13)" + }, + { + "internalName": "camera_shoot_explosion_13", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 14)" + }, + { + "internalName": "camera_shoot_explosion_14", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 15)" + }, + { + "internalName": "camera_shoot_explosion_15", + "displayName": "Bedrock Edition Explosion (Unused) (Stage 16)" + }, + { + "internalName": "conduit_0", + "displayName": "Conduit (Stage 1)" + }, + { + "internalName": "conduit_1", + "displayName": "Conduit (Stage 2)" + }, + { + "internalName": "conduit_2", + "displayName": "Conduit (Stage 3)" + }, + { + "internalName": "conduit_3", + "displayName": "Conduit (Stage 4)" + }, + { + "internalName": "conduit_4", + "displayName": "Conduit (Stage 5)" + }, + { + "internalName": "conduit_5", + "displayName": "Conduit (Stage 6)" + }, + { + "internalName": "conduit_6", + "displayName": "Conduit (Stage 7)" + }, + { + "internalName": "conduit_7", + "displayName": "Conduit (Stage 8)" + }, + { + "internalName": "conduit_8", + "displayName": "Conduit (Stage 9)" + }, + { + "internalName": "conduit_9", + "displayName": "Conduit (Stage 10)" + }, + { + "internalName": "conduit_10", + "displayName": "Conduit (Stage 11)" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "sga_a", + "displayName": "Standard Galactic Language (A)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_b", + "displayName": "Standard Galactic Language (B)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_c", + "displayName": "Standard Galactic Language (C)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_d", + "displayName": "Standard Galactic Language (D)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_e", + "displayName": "Standard Galactic Language (E)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_f", + "displayName": "Standard Galactic Language (F)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_g", + "displayName": "Standard Galactic Language (G)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_h", + "displayName": "Standard Galactic Language (H)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_i", + "displayName": "Standard Galactic Language (I)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_j", + "displayName": "Standard Galactic Language (J)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_k", + "displayName": "Standard Galactic Language (K)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_l", + "displayName": "Standard Galactic Language (L)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_m", + "displayName": "Standard Galactic Language (M)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_n", + "displayName": "Standard Galactic Language (N)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_o", + "displayName": "Standard Galactic Language (O)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_p", + "displayName": "Standard Galactic Language (P)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_q", + "displayName": "Standard Galactic Language (Q)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_r", + "displayName": "Standard Galactic Language (R)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_s", + "displayName": "Standard Galactic Language (S)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_t", + "displayName": "Standard Galactic Language (T)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_u", + "displayName": "Standard Galactic Language (U)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_v", + "displayName": "Standard Galactic Language (V)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_w", + "displayName": "Standard Galactic Language (W)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_x", + "displayName": "Standard Galactic Language (X)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_y", + "displayName": "Standard Galactic Language (Y)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "sga_z", + "displayName": "Standard Galactic Language (Z)", + + "colourEntry": { + "defaultName": "Particle_EnchantmentTable", + "variants": [ + "Particle_EnchantmentTable" + ] + } + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + { + "internalName": "", + "displayName": "" + }, + ] +} \ No newline at end of file diff --git a/PckStudio.Core/Resources/particles.png b/PckStudio.Core/Resources/particles.png new file mode 100644 index 00000000..b4f1e1f6 Binary files /dev/null and b/PckStudio.Core/Resources/particles.png differ diff --git a/PckStudio.Core/Resources/terrain.png b/PckStudio.Core/Resources/terrain.png new file mode 100644 index 00000000..9b6d1791 Binary files /dev/null and b/PckStudio.Core/Resources/terrain.png differ diff --git a/PCK-Studio/Internal/Serializer/AnimationSerializer.cs b/PckStudio.Core/Serializer/AnimationSerializer.cs similarity index 90% rename from PCK-Studio/Internal/Serializer/AnimationSerializer.cs rename to PckStudio.Core/Serializer/AnimationSerializer.cs index 08e08272..a3e78b68 100644 --- a/PCK-Studio/Internal/Serializer/AnimationSerializer.cs +++ b/PckStudio.Core/Serializer/AnimationSerializer.cs @@ -20,15 +20,16 @@ using System; using System.Drawing; using System.Text; using OMI.Formats.Pck; -using PckStudio.Extensions; +using PckStudio.Core.Extensions; using PckStudio.Interfaces; +using PckStudio.Core; using System.Linq; using Newtonsoft.Json.Linq; using System.Windows.Forms; -namespace PckStudio.Internal.Serializer +namespace PckStudio.Core.Serializer { - internal sealed class AnimationSerializer : IPckAssetSerializer + public sealed class AnimationSerializer : IPckAssetSerializer { public static readonly AnimationSerializer DefaultSerializer = new AnimationSerializer(); @@ -48,7 +49,7 @@ namespace PckStudio.Internal.Serializer return stringBuilder.ToString(0, stringBuilder.Length - 1); } - internal static Image SerializeTexture(Animation animation) + public static Image SerializeTexture(Animation animation) { IReadOnlyCollection textures = animation.GetTextures(); Size size = textures.First().Size; @@ -58,7 +59,7 @@ namespace PckStudio.Internal.Serializer return textures.Combine(ImageLayoutDirection.Vertical); } - internal static JObject SerializeJavaAnimation(Animation animation) + public static JObject SerializeJavaAnimation(Animation animation) { JObject janimation = new JObject(); JObject mcmeta = new JObject(); diff --git a/PckStudio.Core/Serializer/AtlasSerializer.cs b/PckStudio.Core/Serializer/AtlasSerializer.cs new file mode 100644 index 00000000..9eaa4b6c --- /dev/null +++ b/PckStudio.Core/Serializer/AtlasSerializer.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OMI.Formats.Pck; +using PckStudio.Core.Extensions; +using PckStudio.Interfaces; + +namespace PckStudio.Core.Serializer +{ + internal sealed class AtlasSerializer : IPckAssetSerializer + { + public void Serialize(Atlas atlas, ref PckAsset asset) + { + asset.SetTexture(atlas); + } + } +} diff --git a/PCK-Studio/Internal/Serializer/ImageSerializer.cs b/PckStudio.Core/Serializer/ImageSerializer.cs similarity index 96% rename from PCK-Studio/Internal/Serializer/ImageSerializer.cs rename to PckStudio.Core/Serializer/ImageSerializer.cs index dfd4c3f1..07f86568 100644 --- a/PCK-Studio/Internal/Serializer/ImageSerializer.cs +++ b/PckStudio.Core/Serializer/ImageSerializer.cs @@ -21,10 +21,10 @@ using System.Drawing; using System.Drawing.Imaging; using System.IO; using OMI.Formats.Pck; +using PckStudio.Core.IO.TGA; using PckStudio.Interfaces; -using PckStudio.Internal.IO.TGA; -namespace PckStudio.Internal.Serializer +namespace PckStudio.Core.Serializer { internal sealed class ImageSerializer : IPckAssetSerializer { diff --git a/PckStudio.Core/Skin/Skin.cs b/PckStudio.Core/Skin/Skin.cs new file mode 100644 index 00000000..95c14b7b --- /dev/null +++ b/PckStudio.Core/Skin/Skin.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PckStudio.Core.Skin +{ + public sealed class Skin + { + public SkinMetaData MetaData { get; set; } + + public SkinIdentifier Identifier { get; set; } + + public SkinANIM Anim { get; set; } + + public SkinModel Model { get; set; } + + public Image Texture { get; set; } + + public Image CapeTexture { get; set; } + + public bool HasCape => CapeTexture is not null; + + public Skin(string name, Image texture) + { + MetaData = new SkinMetaData(name, string.Empty); + Texture = texture; + Model = new SkinModel(); + } + + public Skin(string name, Image texture, Image capeTexture) + : this(name, texture) + { + CapeTexture = capeTexture; + } + + public Skin(string name, SkinANIM anim, Image texture, IEnumerable additionalBoxes, IEnumerable partOffsets) + : this(name, texture) + { + Model.AdditionalBoxes.AddRange(additionalBoxes); + Model.PartOffsets.AddRange(partOffsets); + Anim = anim; + } + + public Skin(string name, int id, Image texture, SkinANIM anim, IEnumerable additionalBoxes, IEnumerable partOffsets) + : this(name, anim, texture, additionalBoxes, partOffsets) + { + Identifier = new(id); + } + } +} diff --git a/PCK-Studio/Internal/SkinANIM.cs b/PckStudio.Core/Skin/SkinANIM.cs similarity index 93% rename from PCK-Studio/Internal/SkinANIM.cs rename to PckStudio.Core/Skin/SkinANIM.cs index ef3136cd..16468bd8 100644 --- a/PCK-Studio/Internal/SkinANIM.cs +++ b/PckStudio.Core/Skin/SkinANIM.cs @@ -19,7 +19,7 @@ using System; using System.Collections.Specialized; using System.Text.RegularExpressions; -namespace PckStudio.Internal +namespace PckStudio.Core.Skin { /// /// Represents a Skin Anim value where flags can be set @@ -56,6 +56,11 @@ namespace PckStudio.Internal public static SkinANIM operator |(SkinANIM @this, SkinANIM other) => new SkinANIM(@this._flags.Data | other._flags.Data); public static SkinANIM operator |(SkinANIM @this, SkinAnimMask mask) => new SkinANIM(@this._flags.Data | (int)mask); + public static SkinANIM operator &(SkinANIM @this, SkinAnimMask mask) => new SkinANIM(@this._flags.Data & (int)mask); + + public static SkinANIM FromValue(int value) => new SkinANIM(value); + + public int ToValue() => _flags.Data; public static implicit operator SkinANIM(SkinAnimMask mask) => new SkinANIM(mask); diff --git a/PCK-Studio/Internal/SkinAnimFlag.cs b/PckStudio.Core/Skin/SkinAnimFlag.cs similarity index 98% rename from PCK-Studio/Internal/SkinAnimFlag.cs rename to PckStudio.Core/Skin/SkinAnimFlag.cs index f4f8af0e..a0475ab0 100644 --- a/PCK-Studio/Internal/SkinAnimFlag.cs +++ b/PckStudio.Core/Skin/SkinAnimFlag.cs @@ -16,7 +16,7 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -namespace PckStudio.Internal +namespace PckStudio.Core.Skin { /// /// For usage see diff --git a/PCK-Studio/Internal/SkinAnimMask.cs b/PckStudio.Core/Skin/SkinAnimMask.cs similarity index 95% rename from PCK-Studio/Internal/SkinAnimMask.cs rename to PckStudio.Core/Skin/SkinAnimMask.cs index fc7e7b47..5daffe91 100644 --- a/PCK-Studio/Internal/SkinAnimMask.cs +++ b/PckStudio.Core/Skin/SkinAnimMask.cs @@ -1,6 +1,10 @@ using System; using System.Collections.Generic; -namespace PckStudio.Internal +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PckStudio.Core.Skin { [Flags] public enum SkinAnimMask : int diff --git a/PckStudio.Core/Skin/SkinBOX.cs b/PckStudio.Core/Skin/SkinBOX.cs new file mode 100644 index 00000000..aa0efab8 --- /dev/null +++ b/PckStudio.Core/Skin/SkinBOX.cs @@ -0,0 +1,180 @@ +/* Copyright (c) 2023-present miku-666, MattNL + * 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.Linq; +using System.Numerics; +using PckStudio.Core.Extensions; + +namespace PckStudio.Core.Skin +{ + public record SkinBOX : IEquatable + { + public static readonly SkinBOX DefaultHead = new SkinBOX("HEAD", new Vector3(-4, -8, -4), new Vector3(8), Vector2.Zero); + + public static readonly string[] BaseTypes = new string[] + { + "HEAD", + "BODY", + "ARM0", + "ARM1", + "LEG0", + "LEG1", + }; + + public static readonly string[] OverlayTypes = new string[] + { + "HEADWEAR", + "JACKET", + "SLEEVE0", + "SLEEVE1", + "PANTS0", + "PANTS1", + }; + + public static Dictionary KnownHashes = new Dictionary() + { + [unchecked((int)0x9560320c)] = SkinAnimFlag.HEAD_DISABLED, // HEAD -4 -8 -4 8 8 8 0 0 0 0 0 + + [unchecked((int)0x1f13e4a3)] = SkinAnimFlag.BODY_DISABLED, // BODY -4 0 -2 8 12 4 16 16 0 0 0 + + [unchecked((int)0x407c9b27)] = SkinAnimFlag.RIGHT_ARM_DISABLED, // ARM0 -3 -2 -2 4 12 4 40 16 0 0 0 // standard (64x64) + [unchecked((int)0x867c9b27)] = SkinAnimFlag.RIGHT_ARM_DISABLED, // ARM0 -2 -2 -2 3 12 4 40 16 0 0 0 // slim + + [unchecked((int)0xca3cf050)] = SkinAnimFlag.LEFT_ARM_DISABLED, // ARM1 -1 -2 -2 4 12 4 40 16 0 1 0 // classic (64x32) + [unchecked((int)0x879b27)] = SkinAnimFlag.LEFT_ARM_DISABLED, // ARM1 -1 -2 -2 4 12 4 32 48 0 0 0 // standard (64x64) + [unchecked((int)0xe8c79b27)] = SkinAnimFlag.LEFT_ARM_DISABLED, // ARM1 -1 -2 -2 3 12 4 32 48 0 0 0 // slim + + [unchecked((int)0x1910e24a)] = SkinAnimFlag.LEFT_LEG_DISABLED, // LEG1 -2 0 -2 4 12 4 16 48 0 0 0 // 64x64 + [unchecked((int)0xce263773)] = SkinAnimFlag.LEFT_LEG_DISABLED, // LEG1 -2 0 -2 4 12 4 0 16 0 1 0 // 64x32 + + [unchecked((int)0x5da5e24a)] = SkinAnimFlag.RIGHT_LEG_DISABLED, // LEG0 -2 0 -2 4 12 4 0 16 0 0 0 + + [unchecked((int)0x4bfe0142)] = SkinAnimFlag.HEAD_OVERLAY_DISABLED, // HEADWEAR -4 -8 -4 8 8 8 32 0 0 0 0 + + // ------------------------------------------------------------------------------------------------------------------------------------ + + [unchecked((int)0xe693e4a3)] = SkinAnimFlag.BODY_OVERLAY_DISABLED, // BODY -4 0 -2 8 12 4 16 32 0 0 0 + [unchecked((int)0x8e322609)] = SkinAnimFlag.BODY_OVERLAY_DISABLED, // JACKET -4 0 -2 8 12 4 16 32 0 0 0 + + [unchecked((int)0x860c4433)] = SkinAnimFlag.RIGHT_ARM_OVERLAY_DISABLED, // SLEEVE0 -3 -2 -2 4 12 4 40 32 0 0 0 // classic + [unchecked((int)0xcc0c4433)] = SkinAnimFlag.RIGHT_ARM_OVERLAY_DISABLED, // SLEEVE0 -2 -2 -2 3 12 4 40 32 0 0 0 // slim + + [unchecked((int)0x91407908)] = SkinAnimFlag.LEFT_ARM_OVERLAY_DISABLED, // SLEEVE1 -1 -2 -2 4 12 4 48 48 0 0 0 // classic + [unchecked((int)0x79807908)] = SkinAnimFlag.LEFT_ARM_OVERLAY_DISABLED, // SLEEVE1 -1 -2 -2 3 12 4 48 48 0 0 0 // slim + + [unchecked((int)0x4de0238a)] = SkinAnimFlag.RIGHT_LEG_OVERLAY_DISABLED, // PANTS0 -2 0 -2 4 12 4 0 32 0 0 0 + + [unchecked((int)0x176f238a)] = SkinAnimFlag.LEFT_LEG_OVERLAY_DISABLED, // PANTS1 -2 0 -2 4 12 4 0 48 0 0 0 + }; + + public static readonly string[] ValidBoxTypes = BaseTypes.Concat(OverlayTypes).ToArray(); + + public string Type { get; } + public Vector3 Pos { get; } + public Vector3 Size { get; } + public Vector2 UV { get; } + public bool HideWithArmor { get; } + public bool Mirror { get; } + public float Scale { get; } + + public SkinBOX(string type, Vector3 pos, Vector3 size, Vector2 uv, + bool hideWithArmor = false, bool mirror = false, float scale = 0.0f) + { + Type = type; + Pos = pos; + Size = size; + UV = uv; + HideWithArmor = hideWithArmor; + Mirror = mirror; + Scale = scale; + } + + public static SkinBOX FromString(string value) + { + var arguments = value.TrimEnd('\n', '\r', ' ').Split(' '); + if (arguments.Length < 9) + { + throw new ArgumentException("Arguments must have at least a length of 9"); + } + var type = arguments[0]; + Vector3 pos = TryGetVector3(arguments, 1); + Vector3 size = TryGetVector3(arguments, 4); + Vector2 uv = TryGetVector2(arguments, 7); + + bool hideWithArmor = arguments.IndexInRange(9) && arguments[9] == "1"; + bool mirror = arguments.IndexInRange(10) && arguments[10] == "1"; + float scale = default; + if (arguments.IndexInRange(11)) + float.TryParse(arguments[11], out scale); + return new SkinBOX(type, pos, size, uv, hideWithArmor, mirror, scale); + } + + public bool IsValidType() => IsValidType(Type); + + public static bool IsValidType(string type) => ValidBoxTypes.Contains(type); + + public bool IsBasePart() => IsBasePart(Type); + + public static bool IsBasePart(string type) => BaseTypes.Contains(type); + + public bool IsOverlayPart() => IsOverlayPart(Type); + + public static bool IsOverlayPart(string type) => OverlayTypes.Contains(type); + + public KeyValuePair ToProperty() + { + return new KeyValuePair("BOX", ToString()); + } + + public override string ToString() + { + return + $"{Type} {Pos.X} {Pos.Y} {Pos.Z} {Size.X} {Size.Y} {Size.Z} {UV.X} {UV.Y} {Convert.ToInt32(HideWithArmor)} {Convert.ToInt32(Mirror)} {Scale}" + .Replace(',', '.'); + } + + private static Vector2 TryGetVector2(string[] arguments, int startIndex) + { + float.TryParse(arguments[startIndex], out float x); + float.TryParse(arguments[startIndex + 1], out float y); + return new Vector2(x, y); + } + + private static Vector3 TryGetVector3(string[] arguments, int startIndex) + { + Vector2 xy = TryGetVector2(arguments, startIndex); + float.TryParse(arguments[startIndex + 2], out float z); + return new Vector3(xy, z); + } + + public override int GetHashCode() + { + int hashCode = -1311939065; + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Type); + hashCode = hashCode * -1521134295 + Pos.GetHashCode(); + hashCode = hashCode * -1521134295 + Size.GetHashCode(); + hashCode = hashCode * -1521134295 + UV.GetHashCode(); + hashCode = hashCode * -1521134295 + HideWithArmor.GetHashCode(); + hashCode = hashCode * -1521134295 + Mirror.GetHashCode(); + hashCode = hashCode * -1521134295 + Scale.GetHashCode(); + return hashCode; + } + } +} diff --git a/PckStudio.Core/Skin/SkinIdentifier.cs b/PckStudio.Core/Skin/SkinIdentifier.cs new file mode 100644 index 00000000..cec8e9aa --- /dev/null +++ b/PckStudio.Core/Skin/SkinIdentifier.cs @@ -0,0 +1,23 @@ +using System; +using System.Globalization; + +namespace PckStudio.Core.Skin +{ + public sealed class SkinIdentifier : IFormattable + { + public int Id { get; } + + public SkinIdentifier(int id) + { + Id = id; + } + + public static implicit operator int(SkinIdentifier _this) => _this.Id; + + public string ToString(string format, IFormatProvider formatProvider) => Id.ToString(format, formatProvider); + + public string ToString(string format) => Id.ToString(format, NumberFormatInfo.CurrentInfo); + + public override string ToString() => Id.ToString(NumberFormatInfo.CurrentInfo); + } +} diff --git a/PckStudio.Core/Skin/SkinMetaData.cs b/PckStudio.Core/Skin/SkinMetaData.cs new file mode 100644 index 00000000..0077bdc5 --- /dev/null +++ b/PckStudio.Core/Skin/SkinMetaData.cs @@ -0,0 +1,14 @@ +namespace PckStudio.Core.Skin +{ + public sealed class SkinMetaData + { + public string Name { get; } + public string Theme { get; } + + public SkinMetaData(string name, string theme) + { + Name = name; + Theme = theme; + } + } +} diff --git a/PckStudio.Core/Skin/SkinModel.cs b/PckStudio.Core/Skin/SkinModel.cs new file mode 100644 index 00000000..63f5b519 --- /dev/null +++ b/PckStudio.Core/Skin/SkinModel.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using OMI.Formats.Pck; + +namespace PckStudio.Core.Skin +{ + public sealed class SkinModel + { + public readonly List AdditionalBoxes; + public readonly List PartOffsets; + + public SkinModel() + { + AdditionalBoxes = new List(); + PartOffsets = new List(5); + } + + public SkinModel(IEnumerable additionalBoxes, IEnumerable partOffsets) + { + AdditionalBoxes = new List(additionalBoxes); + PartOffsets = new List(partOffsets); + } + } +} diff --git a/PckStudio.Core/Skin/SkinPartOffset.cs b/PckStudio.Core/Skin/SkinPartOffset.cs new file mode 100644 index 00000000..ccdc3eab --- /dev/null +++ b/PckStudio.Core/Skin/SkinPartOffset.cs @@ -0,0 +1,81 @@ +using System; +using System.Linq; +using System.IO; +using PckStudio.Core.Extensions; +using System.Diagnostics; +using System.Text.RegularExpressions; +using System.Collections.Generic; + +namespace PckStudio.Core.Skin +{ + public readonly struct SkinPartOffset + { + private static readonly Regex sWhitespace = new Regex(@"\s+"); + public static string ReplaceWhitespace(string input, string replacement) + { + return sWhitespace.Replace(input, replacement); + } + + public static readonly string[] ValidModelOffsetTypes = new string[] + { + //! See: 0x02af8a20 - 0x02af8ed8 (Wii U Editon) + "HEAD", + "BODY", + "ARM0", + "ARM1", + "LEG0", + "LEG1", + + "TOOL0", + "TOOL1", + + "HELMET", + "SHOULDER0", + "SHOULDER1", + "CHEST", + "WAIST", + "PANTS0", + "PANTS1", + "BOOT0", + "BOOT1", + }; + + public string Type { get; } + public float Value { get; } + + public SkinPartOffset(string type, float value) + { + Type = type; + Value = value; + } + + public static SkinPartOffset FromString(string offsetFormatString) + { + string[] offset = ReplaceWhitespace(offsetFormatString.TrimEnd('\n', '\r', ' '), ",").Split(','); + if (offset.Length < 3) + throw new InvalidDataException("Format string does not contain enough data."); + + string type = offset[0]; + + if (!ValidModelOffsetTypes.Contains(type)) + { + Debug.WriteLine($"'{type}' is an invalid offset type.", category: nameof(SkinPartOffset)); + } + + // Ignore => Y assumed + //if (offset[1] != "Y") + + if (!float.TryParse(offset[2], out float value)) + { + Debug.WriteLine($"Failed to parse y offset for: '{type}'", category: nameof(SkinPartOffset)); + } + return new SkinPartOffset(type, value); + } + + public KeyValuePair ToProperty() + { + string value = $"{Type} Y {Value}"; + return new KeyValuePair("OFFSET", value.Replace(',', '.')); + } + } +} \ No newline at end of file diff --git a/PCK-Studio/Internal/Json/Tiles.cs b/PckStudio.Core/Tiles.cs similarity index 60% rename from PCK-Studio/Internal/Json/Tiles.cs rename to PckStudio.Core/Tiles.cs index 921407a2..223fe78d 100644 --- a/PCK-Studio/Internal/Json/Tiles.cs +++ b/PckStudio.Core/Tiles.cs @@ -2,16 +2,15 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; using Newtonsoft.Json; -using PckStudio.Extensions; -using PckStudio.Properties; +using PckStudio.Core.Extensions; +using PckStudio.Core.Json; +using PckStudio.Core.Properties; -namespace PckStudio.Internal.Json +namespace PckStudio.Json { - internal class JsonTiles + public class JsonTiles { [JsonProperty("entries")] public List Entries { get; set; } @@ -20,33 +19,33 @@ namespace PckStudio.Internal.Json public List AdditionalEntries { get; set; } } - internal static class Tiles + public static class Tiles { - private static JsonTiles - _jsonBlockData, _jsonItemData, + private static JsonTiles + _jsonBlockData, _jsonItemData, _jsonParticleData, _jsonMoonPhaseData, - _jsonMapIconData, _jsonExplosionData, + _jsonMapIconData, _jsonExplosionData, _jsonExperienceOrbData, _jsonPaintingData, _jsonBannerData; - internal static JsonTiles JsonBlockData => _jsonBlockData ??= JsonConvert.DeserializeObject(Resources.blockData); - internal static JsonTiles JsonItemData => _jsonItemData ??= JsonConvert.DeserializeObject(Resources.itemData); - internal static JsonTiles JsonParticleData => _jsonParticleData ??= JsonConvert.DeserializeObject(Resources.particleData); - internal static JsonTiles JsonMoonPhaseData => _jsonMoonPhaseData ??= JsonConvert.DeserializeObject(Resources.moonPhaseData); - internal static JsonTiles JsonMapIconData => _jsonMapIconData ??= JsonConvert.DeserializeObject(Resources.mapIconData); - internal static JsonTiles JsonExplosionData => _jsonExplosionData ??= JsonConvert.DeserializeObject(Resources.explosionData); - internal static JsonTiles JsonExperienceOrbData => _jsonExperienceOrbData ??= JsonConvert.DeserializeObject(Resources.experienceOrbData); - internal static JsonTiles JsonPaintingData => _jsonPaintingData ??= JsonConvert.DeserializeObject(Resources.paintingData); - internal static JsonTiles JsonBannerData => _jsonBannerData ??= JsonConvert.DeserializeObject(Resources.bannerData); + public static JsonTiles JsonBlockData => _jsonBlockData ??= JsonConvert.DeserializeObject(Resources.blockData); + public static JsonTiles JsonItemData => _jsonItemData ??= JsonConvert.DeserializeObject(Resources.itemData); + public static JsonTiles JsonParticleData => _jsonParticleData ??= JsonConvert.DeserializeObject(Resources.particleData); + public static JsonTiles JsonMoonPhaseData => _jsonMoonPhaseData ??= JsonConvert.DeserializeObject(Resources.moonPhaseData); + public static JsonTiles JsonMapIconData => _jsonMapIconData ??= JsonConvert.DeserializeObject(Resources.mapIconData); + public static JsonTiles JsonExplosionData => _jsonExplosionData ??= JsonConvert.DeserializeObject(Resources.explosionData); + public static JsonTiles JsonExperienceOrbData => _jsonExperienceOrbData ??= JsonConvert.DeserializeObject(Resources.experienceOrbData); + public static JsonTiles JsonPaintingData => _jsonPaintingData ??= JsonConvert.DeserializeObject(Resources.paintingData); + public static JsonTiles JsonBannerData => _jsonBannerData ??= JsonConvert.DeserializeObject(Resources.bannerData); - internal static List ItemTileInfos => JsonItemData.Entries; - internal static List BlockTileInfos => JsonBlockData.Entries; - internal static List ParticleTileInfos => JsonParticleData.Entries; - internal static List MoonPhaseTileInfos => JsonMoonPhaseData.Entries; - internal static List MapIconTileInfos => JsonMapIconData.Entries; - internal static List AdditionalMapIconTileInfos => JsonMapIconData.AdditionalEntries; - internal static List ExperienceOrbTileInfos => JsonExperienceOrbData.Entries; - internal static List ExplosionTileInfos => JsonExplosionData.Entries; - internal static List PaintingTileInfos => JsonPaintingData.Entries; - internal static List BannerTileInfos => JsonBannerData.Entries; + public static List ItemTileInfos => JsonItemData.Entries; + public static List BlockTileInfos => JsonBlockData.Entries; + public static List ParticleTileInfos => JsonParticleData.Entries; + public static List MoonPhaseTileInfos => JsonMoonPhaseData.Entries; + public static List MapIconTileInfos => JsonMapIconData.Entries; + public static List AdditionalMapIconTileInfos => JsonMapIconData.AdditionalEntries; + public static List ExperienceOrbTileInfos => JsonExperienceOrbData.Entries; + public static List ExplosionTileInfos => JsonExplosionData.Entries; + public static List PaintingTileInfos => JsonPaintingData.Entries; + public static List BannerTileInfos => JsonBannerData.Entries; private static Image[] _itemImages; public static Image[] ItemImages => _itemImages ??= Resources.items_atlas.SplitHorizontal(16).ToArray(); @@ -80,11 +79,11 @@ namespace PckStudio.Internal.Json private static ImageList GetImageList(Image[] images) { - ImageList _imageList = new ImageList(); - _imageList.ColorDepth = ColorDepth.Depth32Bit; - _imageList.Images.AddRange(images); + ImageList imageList = new ImageList(); + imageList.ColorDepth = ColorDepth.Depth32Bit; + imageList.Images.AddRange(images); - return _imageList; + return imageList; } private static ImageList _blockImageList = GetImageList(BlockImages); diff --git a/PckStudio.Rendering/BoundingBox.cs b/PckStudio.Rendering/BoundingBox.cs new file mode 100644 index 00000000..ac692c8a --- /dev/null +++ b/PckStudio.Rendering/BoundingBox.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PckStudio.Rendering.Addon +{ + public struct BoundingBox + { + private static readonly ColorVertex[] _vertices = [ + new ColorVertex(new OpenTK.Vector3(0f, 1f, 1f)), + new ColorVertex(new OpenTK.Vector3(1f, 1f, 1f)), + new ColorVertex(new OpenTK.Vector3(1f, 0f, 1f)), + new ColorVertex(new OpenTK.Vector3(0f, 0f, 1f)), + new ColorVertex(new OpenTK.Vector3(0f, 1f, 0f)), + new ColorVertex(new OpenTK.Vector3(1f, 1f, 0f)), + new ColorVertex(new OpenTK.Vector3(1f, 0f, 0f)), + new ColorVertex(new OpenTK.Vector3(0f, 0f, 0f)), + ]; + + private static readonly int[] _indecies = [ + 0, 1, + 1, 2, + 2, 3, + 3, 0, + + 4, 5, + 5, 6, + 6, 7, + 7, 4, + + 0, 4, + 1, 5, + 2, 6, + 3, 7 + ]; + + public static ColorVertex[] GetVertices() + { + return _vertices; + } + + public static int[] GetIndecies() => _indecies; + } +} diff --git a/PckStudio.Rendering/Camera/Camera.cs b/PckStudio.Rendering/Camera/Camera.cs new file mode 100644 index 00000000..7ff811a2 --- /dev/null +++ b/PckStudio.Rendering/Camera/Camera.cs @@ -0,0 +1,12 @@ +using System; +using OpenTK; + +namespace PckStudio.Rendering.Camera +{ + public abstract class Camera + { + protected Matrix4 projectionMatrix; + + public abstract Matrix4 GetViewProjection(); + } +} diff --git a/PckStudio.Rendering/Camera/PerspectiveCamera.cs b/PckStudio.Rendering/Camera/PerspectiveCamera.cs new file mode 100644 index 00000000..31e21120 --- /dev/null +++ b/PckStudio.Rendering/Camera/PerspectiveCamera.cs @@ -0,0 +1,208 @@ +/* Copyright (c) 2024-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. +**/ +// movement code taken from: +// https://github.com/TheCherno/Hazel/blob/master/Hazel/src/Hazel/Renderer/EditorCamera.cpp +using System; +using System.Drawing; +using OpenTK; + +namespace PckStudio.Rendering.Camera +{ + public class PerspectiveCamera : Camera + { + public float NearClip + { + get => _nearClip; + set + { + _nearClip = value; + UpdateProjection(); + } + } + + public float FarClip + { + get => _farClip; + set + { + _farClip = value; + UpdateProjection(); + } + } + + public float Distance + { + get => _spherical.Radius; + set + { + _spherical.Radius = Math.Max(value, 2f); + UpdateViewMatrix(); + } + } + + public float RotationSpeed { get; set; } = 5f; + + public Size ViewportSize + { + get => _viewportSize; + set + { + _viewportSize = value; + UpdateProjection(); + } + } + + public Vector3 WorldPosition => _position; + + public Vector3 FocalPoint + { + get => _focalPoint; + set + { + _focalPoint = value; + UpdateViewMatrix(); + } + } + + public float Pitch + { + get => _spherical.Theta; + set + { + _spherical.Theta = MathHelper.Clamp(value, -90f, 90f); + UpdateViewMatrix(); + } + } + + public float Yaw + { + get => _spherical.Phi; + set + { + _spherical.Phi = value % 360f; + UpdateViewMatrix(); + } + } + + public Vector3 Orientation => -Vector3.UnitZ; + + public Vector3 Up => Vector3.UnitY; + + public float MinimumFov { get; } = 30f; + public float MaximumFov { get; } = 180f; + + public float Fov + { + get => _fov; + set + { + _fov = MathHelper.Clamp(value, MinimumFov, MaximumFov); + UpdateProjection(); + } + } + + public PerspectiveCamera(float fov, Vector3 target) + { + _fov = fov; + _focalPoint = target; + _nearClip = 1f; + _farClip = 1000f; + UpdateProjection(); + } + + private Matrix4 viewMatrix; + private float _fov; + + private float _nearClip; + private float _farClip; + private Spherical _spherical; + private Size _viewportSize; + private Vector3 _position; + private Vector3 _focalPoint; + + public override Matrix4 GetViewProjection() + { + return viewMatrix * projectionMatrix; + } + + public Matrix4 GetProjection() + { + return projectionMatrix; + } + + private void UpdateViewMatrix() + { + Matrix4 rotation = Matrix4.CreateRotationY(MathHelper.DegreesToRadians(Yaw)) * Matrix4.CreateRotationX(MathHelper.DegreesToRadians(Pitch)); + + viewMatrix = Matrix4.CreateTranslation(FocalPoint) * rotation * Matrix4.CreateTranslation(0, 0, -Distance); + // Position in Right-handed coordinates + _position = viewMatrix.Inverted().ExtractTranslation(); + } + + private void UpdateProjection() + { + float aspect = (float)ViewportSize.Width / (float)ViewportSize.Height; + projectionMatrix = Matrix4.CreatePerspectiveFieldOfView((float)MathHelper.DegreesToRadians(Fov), aspect, NearClip, FarClip); + } + + private Vector2 GetPanSpeed() + { + float x = Math.Min(ViewportSize.Width / 100.0f, 1.4f); // max = 2.4f + float xFactor = 0.0366f * (x * x) - 0.1778f * x + 0.3021f; + + float y = Math.Min(ViewportSize.Height / 100.0f, 1.4f); // max = 2.4f + float yFactor = 0.0366f * (y * y) - 0.1778f * y + 0.3021f; + + return new Vector2(xFactor, yFactor); + } + + public void Pan(Vector2 delta) + { + Pan(delta.X, delta.Y); + } + + public void Pan(float deltaX, float deltaY) + { + Vector2 panSpeed = GetPanSpeed(); + + // Taken from: blockbench + // https://github.com/JannisX11/blockbench/blob/a56fe01a517ace8d013f67bbd3d02442c44d3141/js/preview/OrbitControls.js#L271-L322 + Vector3 left = viewMatrix.Column0.Xyz * -Distance; + Vector3 up = viewMatrix.Column1.Xyz * Distance; + _focalPoint -= left * deltaX * panSpeed.X; + _focalPoint -= up * deltaY * panSpeed.Y; + UpdateViewMatrix(); + } + + public void Rotate(Vector2 delta) + { + Rotate(delta.X, delta.Y); + } + + public void Rotate(float deltaX,float deltaY) + { + Yaw += deltaX * RotationSpeed; + Pitch += deltaY * RotationSpeed; + } + + public override string ToString() + { + return $"FOV: {Fov}\nPosition: {WorldPosition}\nRotation: {_spherical}"; + } + } +} diff --git a/PckStudio.Rendering/ColorVertex.cs b/PckStudio.Rendering/ColorVertex.cs new file mode 100644 index 00000000..54634b4c --- /dev/null +++ b/PckStudio.Rendering/ColorVertex.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using OpenTK; +using OpenTK.Graphics; + +namespace PckStudio.Rendering +{ + [StructLayout(LayoutKind.Sequential, Size = 28)] + public struct ColorVertex + { + public ColorVertex(Vector3 position, Color4 color) + { + Position = position; + Color = color; + } + + public ColorVertex(Vector3 position) + : this(position, System.Drawing.Color.White) + { + } + + public static implicit operator ColorVertex(Vector3 vector3) => new ColorVertex(vector3); + + public Vector3 Position { get; set; } + public Color4 Color { get; set; } + } +} diff --git a/PckStudio.Rendering/Cube.cs b/PckStudio.Rendering/Cube.cs new file mode 100644 index 00000000..de675454 --- /dev/null +++ b/PckStudio.Rendering/Cube.cs @@ -0,0 +1,102 @@ +/* Copyright (c) 2024-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 OpenTK; +using PckStudio.Core; + +namespace PckStudio.Rendering +{ + public sealed class Cube + { + public Vector3 Position { get; } + + public Vector3 Size { get; } + + public Vector3 Rotation { get; } + + public Vector2 Uv { get; } + + public float Inflate { get; } + + public bool MirrorTexture { get; } + + public bool FlipZMapping { get; } + + public Vector3 Center => Position + Size / 2f; + + public enum Face + { + Back, + Front, + Top, + Bottom, + Left, + Right + } + + public Cube(Vector3 position, Vector3 size, Vector2 uv, float inflate, bool mirrorTexture, bool flipZMapping) + { + Position = position; + Size = size; + Uv = uv; + Inflate = inflate; + MirrorTexture = mirrorTexture; + FlipZMapping = flipZMapping; + } + + public Vector3 GetFaceCenter(Face face) + { + Vector3 result = Center; + switch (face) + { + case Face.Top: + result.Y -= Size.Y / 2f; + return result; + case Face.Bottom: + result.Y += Size.Y / 2f; + return result; + case Face.Back: + result.Z -= Size.Z / 2f; + return result; + case Face.Front: + result.Z += Size.Z / 2f; + return result; + case Face.Left: + result.X -= Size.X / 2f; + return result; + case Face.Right: + result.X += Size.X / 2f; + return result; + default: + return result; + } + } + + public BoundingBox GetBoundingBox() => GetBoundingBox(Matrix4.Identity); + + public BoundingBox GetBoundingBox(Matrix4 transform) + { + Vector3 halfSize = Size / 2f; + Vector3 halfSizeInflated = halfSize + new Vector3(Inflate); + Vector3 transformedCenter = Vector3.TransformPosition(Center, transform); + Vector3 start = transformedCenter - halfSizeInflated; + Vector3 end = transformedCenter + halfSizeInflated; + return new BoundingBox(start, end); + } + } +} diff --git a/PckStudio.Rendering/CubeMesh.cs b/PckStudio.Rendering/CubeMesh.cs new file mode 100644 index 00000000..f3812440 --- /dev/null +++ b/PckStudio.Rendering/CubeMesh.cs @@ -0,0 +1,137 @@ +/* Copyright (c) 2024-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; +using PckStudio.Core; +using PckStudio.Core.Extensions; + +namespace PckStudio.Rendering +{ + public class CubeMesh : GenericMesh + { + private Cube _cube; + + public Vector3 Center => _cube.Center; + + internal static int[] IndicesData { get; } = [ + // Face 1 (Back) + 0, 1, 2, + 2, 3, 0, + // Face 2 (Front) + 4, 5, 6, + 6, 7, 4, + // Face 3 (Top) + 8, 9, 10, + 10, 11, 8, + // Face 4 (Bottom) + 12, 13, 14, + 14, 15, 12, + // Face 5 (Left) + 16, 17, 18, + 18, 19, 16, + // Face 6 (Right) + 20, 21, 22, + 22, 23, 20 + ]; + + internal static VertexBufferLayout VertexBufferLayout { get; } = new VertexBufferLayout().Add(ShaderDataType.Float3).Add(ShaderDataType.Float2); + + public CubeMesh(Cube cube) : this(nameof(CubeMesh), cube) + { + } + + public CubeMesh(string name, Cube cube) : this(name, cube, true) + { + } + + private CubeMesh(string name, Cube cube, bool visible) + : base(name, visible, OpenTK.Graphics.OpenGL.PrimitiveType.Triangles, VertexBufferLayout) + { + _cube = cube; + } + + public CubeMesh SetCube(Cube cube) + { + _ = cube ?? throw new ArgumentNullException(nameof(cube)); + return new CubeMesh(Name, cube, Visible); + } + + public override GenericMesh SetVisible(bool visible) => new CubeMesh(Name, _cube, visible); + + public Cube GetCube() => _cube; + + public override Matrix4 GetTransform() => _cube.GetBoundingBox().GetTransform(); + + public override BoundingBox GetBounds(Matrix4 transform) + { + return _cube.GetBoundingBox(transform); + } + + public override IEnumerable GetVertices() + { + int mirror = Convert.ToInt32(_cube.MirrorTexture); + + Vector2 uv = _cube.Uv; + + Vector3 size = _cube.Size; + + // Back + yield return new TextureVertex(new Vector3(0f, 1f, 1f), new Vector2(uv.X + size.Z * 2 + size.X + size.X * (1 - mirror), uv.Y + size.Z + size.Y)); + yield return new TextureVertex(new Vector3(1f, 1f, 1f), new Vector2(uv.X + size.Z * 2 + size.X + size.X * mirror, uv.Y + size.Z + size.Y)); + yield return new TextureVertex(new Vector3(1f, 0f, 1f), new Vector2(uv.X + size.Z * 2 + size.X + size.X * mirror, uv.Y + size.Z)); + yield return new TextureVertex(new Vector3(0f, 0f, 1f), new Vector2(uv.X + size.Z * 2 + size.X + size.X * (1 - mirror), uv.Y + size.Z)); + + // Front + yield return new TextureVertex(new Vector3(0f, 1f, 0f), new Vector2(uv.X + size.Z + size.X * mirror, uv.Y + size.Z + size.Y)); + yield return new TextureVertex(new Vector3(1f, 1f, 0f), new Vector2(uv.X + size.Z + size.X * (1 - mirror), uv.Y + size.Z + size.Y)); + yield return new TextureVertex(new Vector3(1f, 0f, 0f), new Vector2(uv.X + size.Z + size.X * (1 - mirror), uv.Y + size.Z)); + yield return new TextureVertex(new Vector3(0f, 0f, 0f), new Vector2(uv.X + size.Z + size.X * mirror, uv.Y + size.Z)); + + // Top + yield return new TextureVertex(new Vector3(0f, 0f, 0f), new Vector2(uv.X + size.Z + size.X * mirror, uv.Y + size.Z)); + yield return new TextureVertex(new Vector3(0f, 0f, 1f), new Vector2(uv.X + size.Z + size.X * mirror, uv.Y)); + yield return new TextureVertex(new Vector3(1f, 0f, 1f), new Vector2(uv.X + size.Z + size.X * (1 - mirror), uv.Y)); + yield return new TextureVertex(new Vector3(1f, 0f, 0f), new Vector2(uv.X + size.Z + size.X * (1 - mirror), uv.Y + size.Z)); + + // Bottom + yield return new TextureVertex(new Vector3(1f, 1f, 0f), new Vector2(uv.X + size.Z + size.X + size.X * (1 - mirror), uv.Y + (_cube.FlipZMapping ? size.Z : 0))); + yield return new TextureVertex(new Vector3(1f, 1f, 1f), new Vector2(uv.X + size.Z + size.X + size.X * (1 - mirror), uv.Y + (!_cube.FlipZMapping ? size.Z : 0))); + yield return new TextureVertex(new Vector3(0f, 1f, 1f), new Vector2(uv.X + size.Z + size.X + size.X * mirror, uv.Y + (!_cube.FlipZMapping ? size.Z : 0))); + yield return new TextureVertex(new Vector3(0f, 1f, 0f), new Vector2(uv.X + size.Z + size.X + size.X * mirror, uv.Y + (_cube.FlipZMapping ? size.Z : 0))); + + // Left + yield return new TextureVertex(new Vector3(_cube.MirrorTexture ? 0f : 1f, 0f, 0f), new Vector2(uv.X + size.X + size.Z, uv.Y + size.Z)); + yield return new TextureVertex(new Vector3(_cube.MirrorTexture ? 0f : 1f, 1f, 0f), new Vector2(uv.X + size.X + size.Z, uv.Y + size.Z + size.Y)); + yield return new TextureVertex(new Vector3(_cube.MirrorTexture ? 0f : 1f, 1f, 1f), new Vector2(uv.X + size.X + size.Z * 2, uv.Y + size.Z + size.Y)); + yield return new TextureVertex(new Vector3(_cube.MirrorTexture ? 0f : 1f, 0f, 1f), new Vector2(uv.X + size.X + size.Z * 2, uv.Y + size.Z)); + + // Right + yield return new TextureVertex(new Vector3(_cube.MirrorTexture ? 1f : 0f, 0f, 0f), new Vector2(uv.X + size.Z, uv.Y + size.Z)); + yield return new TextureVertex(new Vector3(_cube.MirrorTexture ? 1f : 0f, 1f, 0f), new Vector2(uv.X + size.Z, uv.Y + size.Z + size.Y)); + yield return new TextureVertex(new Vector3(_cube.MirrorTexture ? 1f : 0f, 1f, 1f), new Vector2(uv.X, uv.Y + size.Z + size.Y)); + yield return new TextureVertex(new Vector3(_cube.MirrorTexture ? 1f : 0f, 0f, 1f), new Vector2(uv.X, uv.Y + size.Z)); + yield break; + } + + public override IEnumerable GetIndices() => IndicesData; + } +} \ No newline at end of file diff --git a/PckStudio.Rendering/CubeMeshCollection.cs b/PckStudio.Rendering/CubeMeshCollection.cs new file mode 100644 index 00000000..9114acc4 --- /dev/null +++ b/PckStudio.Rendering/CubeMeshCollection.cs @@ -0,0 +1,236 @@ +/* Copyright (c) 2024-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; +using System.Collections.Generic; +using System.Linq; +using OpenTK; +using OpenTK.Graphics.OpenGL; +using PckStudio.Core.Extensions; +using PckStudio.Core; +using PckStudio.Core.Skin; +using PckStudio.Rendering.Extension; + +namespace PckStudio.Rendering +{ + public static class CubeMeshCollectionExtensions + { + public static void AddSkinBox(this CubeMeshCollection cubeMeshes, SkinBOX skinBox, float inflate = 0f) + { + var cube = skinBox.ToCube(inflate, cubeMeshes.FlipZMapping); + cubeMeshes.Add(new CubeMesh(skinBox.Type, cube)); + } + } + + public class CubeMeshCollection : GenericMesh, ICollection> + { + private List> cubes; + private Dictionary subCollection; + + public bool FlipZMapping + { + get => _flipZMapping; + set => _flipZMapping = value; + } + + public Vector3 Translation { get; set; } + public Vector3 Rotation { get; } + public Vector3 Pivot { get; } + private Vector3 _offset { get; set; } = Vector3.Zero; + public Vector3 Offset + { + get => _offset; + set => _offset = value; + } + + public override Matrix4 GetTransform() + { + Matrix4 rotations = ( + Matrix4.CreateRotationX(MathHelper.DegreesToRadians(Rotation.X)) * + Matrix4.CreateRotationY(MathHelper.DegreesToRadians(Rotation.Y)) * + Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(Rotation.Z)) + ); + Matrix4 translation = Matrix4.CreateTranslation(Translation + Offset); + return translation * rotations.Pivoted(Pivot - Offset); + } + + public int Count => cubes.Count; + + public bool IsReadOnly => false; + + private bool _flipZMapping = false; + + public CubeMeshCollection(string name, bool visible = true) : base(name, visible, PrimitiveType.Triangles, CubeMesh.VertexBufferLayout) + { + cubes = new List>(5); + subCollection = new Dictionary(); + } + + public CubeMeshCollection(string name, Vector3 translation, Vector3 pivot, Vector3 rotation = default) + : this(name) + { + Translation = translation; + Pivot = pivot; + Rotation = rotation; + } + + public override GenericMesh SetVisible(bool visible) + { + if (Visible == visible) + return this; + + var mesh = new CubeMeshCollection(Name, visible); + mesh.cubes = this.cubes; + return mesh; + } + + public override IEnumerable GetVertices() + => cubes.Where(c => c.Visible).SelectMany(c => + c.GetVertices().Select(vertex => new TextureVertex(Vector3.TransformPosition(vertex.Position, c.GetTransform()), vertex.TexPosition)) + ); + + public override IEnumerable GetIndices() + { + int offset = 0; + IEnumerable selector(GenericMesh c) + { + IEnumerable result = c.GetIndices().Select(i => i + offset).ToArray(); + int vertexCount = c.GetVertices().Count(); + offset += vertexCount; + return result; + } + return cubes.Where(c => c.Visible).SelectMany(selector); + } + + public void Add(Vector3 position, Vector3 size, Vector2 uv, float inflate = 0f, bool mirrorTexture = false) + { + var cube = new Cube(position, size, uv, inflate, mirrorTexture, FlipZMapping); + Add(new CubeMesh(cube)); + } + + public void AddNamed(string name, Vector3 position, Vector3 size, Vector2 uv, float inflate = 0f, bool mirrorTexture = false) + { + var cube = new Cube(position, size, uv, inflate, mirrorTexture, FlipZMapping); + Add(new CubeMesh(name, cube)); + } + + internal void AddSubCollection(string name, Vector3 translation, Vector3 pivot, Vector3 rotation = default) + { + var item = new CubeMeshCollection(name, translation, pivot, rotation); + Add(item); + subCollection.Add(name, item); + } + + public CubeMeshCollection GetCollection(string collectionName) + { + _ = collectionName ?? throw new ArgumentNullException(nameof(collectionName)); + return ContainsCollection(collectionName) ? subCollection[collectionName] : null; + } + + public void Remove(int index) + { + if (!cubes.IndexInRange(index)) + throw new IndexOutOfRangeException(); + + cubes.RemoveAt(index); + } + + public void ReplaceCube(int index, Vector3 position, Vector3 size, Vector2 uv, float inflate = 0f, bool mirrorTexture = false) + { + if (!cubes.IndexInRange(index)) + throw new IndexOutOfRangeException(); + + + if (cubes[index] is CubeMesh cubeMesh) + cubes[index] = cubeMesh.SetCube(new Cube(position, size, uv, inflate, mirrorTexture, FlipZMapping)); + } + + public Vector3 GetCenter(int index) + { + if (!cubes.IndexInRange(index)) + throw new IndexOutOfRangeException(); + + return cubes[index].GetBounds(GetTransform()).Center; + } + + public BoundingBox GetCubeBoundingBox(int index) + { + if (!cubes.IndexInRange(index)) + throw new IndexOutOfRangeException(); + + return cubes[index].GetBounds(GetTransform()); + } + + public override BoundingBox GetBounds(Matrix4 transform) + { + return cubes + .Where(c => c.Visible) + .Select(c => c.GetBounds(GetTransform() * transform)) + .GetEnclosingBoundingBox(); + } + + public Vector3 GetFaceCenter(int index, Cube.Face face) + { + if (!cubes.IndexInRange(index)) + throw new IndexOutOfRangeException(); + + Vector3 faceCenter = cubes[index] is CubeMesh c ? c.GetCube().GetFaceCenter(face) : Vector3.Zero; + return Vector3.TransformPosition(faceCenter, GetTransform()); + } + + public void SetVisible(int index, bool visible) + { + if (!cubes.IndexInRange(index)) + throw new IndexOutOfRangeException(); + if (cubes[index].Visible == visible) + return; + cubes[index] = cubes[index].SetVisible(visible); + } + + public void Add(GenericMesh item) => cubes.Add(item); + + public void Clear() + { + subCollection.Clear(); + cubes.Clear(); + } + + public bool Contains(GenericMesh item) + { + return cubes.Any(c => c.Name == item.Name); + } + + public bool ContainsCollection(string collectionName) => subCollection.ContainsKey(key: collectionName); + + public bool Contains(GenericMesh item, bool searchSubCollections) + { + return Contains(item) || (searchSubCollections && subCollection.Values.Any(collection => collection.Contains(item, searchSubCollections))); + } + + public void CopyTo(GenericMesh[] array, int arrayIndex) + { + throw new NotImplementedException(); + } + + public bool Remove(GenericMesh item) => cubes.Remove(item); + + public IEnumerator> GetEnumerator() => cubes.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } +} diff --git a/PckStudio.Rendering/DrawContext.cs b/PckStudio.Rendering/DrawContext.cs new file mode 100644 index 00000000..5795e8e0 --- /dev/null +++ b/PckStudio.Rendering/DrawContext.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK.Graphics.OpenGL; + +namespace PckStudio.Rendering +{ + public sealed class DrawContext + { + public readonly VertexArray VertexArray; + public readonly IndexBuffer IndexBuffer; + public readonly PrimitiveType PrimitiveType; + + public DrawContext(VertexArray vertexArray, IndexBuffer indexBuffer, PrimitiveType primitiveType) + { + VertexArray = vertexArray; + IndexBuffer = indexBuffer; + PrimitiveType = primitiveType; + } + } +} diff --git a/PckStudio.Rendering/Extension/SkinBoxExtension.cs b/PckStudio.Rendering/Extension/SkinBoxExtension.cs new file mode 100644 index 00000000..6a8675bf --- /dev/null +++ b/PckStudio.Rendering/Extension/SkinBoxExtension.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PckStudio.Core.Extensions; +using PckStudio.Core.Skin; + +namespace PckStudio.Rendering.Extension +{ + public static class SkinBoxExtension + { + public static Cube ToCube(this SkinBOX skinBOX) => skinBOX.ToCube(0f); + + public static Cube ToCube(this SkinBOX skinBOX, float inflate, bool flipZMapping = false) + => new Cube(skinBOX.Pos.ToOpenTKVector(), skinBOX.Size.ToOpenTKVector(), skinBOX.UV.ToOpenTKVector(), skinBOX.Scale + inflate, skinBOX.Mirror, flipZMapping); + } +} diff --git a/PckStudio.Rendering/FrameBuffer.cs b/PckStudio.Rendering/FrameBuffer.cs new file mode 100644 index 00000000..bae0343f --- /dev/null +++ b/PckStudio.Rendering/FrameBuffer.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK.Graphics.OpenGL; + +namespace PckStudio.Rendering +{ + public class FrameBuffer + { + private int _id; + private FramebufferErrorCode status; + + public FramebufferErrorCode Status => status; + public FrameBuffer() + { + _id = GL.GenFramebuffer(); + } + + public void Bind() + { + GL.BindFramebuffer(FramebufferTarget.Framebuffer, _id); + } + + public void Unbind() + { + GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); + } + + internal void CheckStatus() + { + status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer); + } + } +} diff --git a/PckStudio.Rendering/GenericMesh.cs b/PckStudio.Rendering/GenericMesh.cs new file mode 100644 index 00000000..d9df190d --- /dev/null +++ b/PckStudio.Rendering/GenericMesh.cs @@ -0,0 +1,54 @@ +/* Copyright (c) 2024-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 OpenTK; +using OpenTK.Graphics.OpenGL; +using PckStudio.Core; + +namespace PckStudio.Rendering +{ + public abstract class GenericMesh where T : struct + { + public string Name { get; } + public PrimitiveType DrawType { get; } + public VertexBufferLayout VertexLayout { get; } + public bool Visible { get; } + + + protected GenericMesh(string name, bool visible, PrimitiveType type, VertexBufferLayout vertexLayout) + { + Name = name; + DrawType = type; + Visible = visible; + VertexLayout = vertexLayout; + } + + public abstract GenericMesh SetVisible(bool visible); + public abstract BoundingBox GetBounds(Matrix4 transform); + public abstract Matrix4 GetTransform(); + + public abstract IEnumerable GetVertices(); + public abstract IEnumerable GetIndices(); + + public override string ToString() + { + return $"Name: {Name} T={typeof(T)} Visible={Visible}"; + } + } +} \ No newline at end of file diff --git a/PckStudio.Rendering/IndexBuffer.cs b/PckStudio.Rendering/IndexBuffer.cs new file mode 100644 index 00000000..9d8fcb9e --- /dev/null +++ b/PckStudio.Rendering/IndexBuffer.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK.Graphics.OpenGL; + +namespace PckStudio.Rendering +{ + public class IndexBuffer : IDisposable + { + private int _id; + private int _size; + private int[] _indicies; + + public IndexBuffer() + { + _id = GL.GenBuffer(); + _size = 0; + } + + /// + /// Creates and attaches created index buffer + /// + /// + /// + public static IndexBuffer Create(params int[] indicies) + { + var ib = new IndexBuffer(); + ib.SetIndicies(indicies); + return ib; + } + + public void SetIndicies(int[] indicies) + { + Bind(); + int size = indicies.Length * sizeof(int); + _indicies = indicies; + if (_size < size) + { + GL.BufferData(BufferTarget.ElementArrayBuffer, size, indicies, BufferUsageHint.StaticDraw); + _size = size; + return; + } + GL.BufferSubData(BufferTarget.ElementArrayBuffer, IntPtr.Zero, size, indicies); + } + + public int GetCount() => _indicies.Length; + + public void Bind() + { + GL.BindBuffer(BufferTarget.ElementArrayBuffer, _id); + } + + [Conditional("DEBUG")] + public void Unbind() + { + GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); + } + + public void Dispose() + { + Unbind(); + GL.DeleteBuffer(_id); + } + } +} diff --git a/PckStudio.Rendering/PckStudio.Rendering.csproj b/PckStudio.Rendering/PckStudio.Rendering.csproj new file mode 100644 index 00000000..3e83c5d7 --- /dev/null +++ b/PckStudio.Rendering/PckStudio.Rendering.csproj @@ -0,0 +1,90 @@ + + + + + Debug + AnyCPU + {B1E19D0F-6DD5-4D91-9B45-9818759CA8EF} + Library + NDEBUG + Properties + PckStudio.Rendering + PckStudio.Rendering + v4.8 + 12 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3.3.3 + + + 3.3.3 + + + + + {345eabed-f0d1-4d04-b409-babdef747352} + PckStudio.Core + + + + \ No newline at end of file diff --git a/PckStudio.Rendering/Properties/AssemblyInfo.cs b/PckStudio.Rendering/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..88352485 --- /dev/null +++ b/PckStudio.Rendering/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PckStudio.Rendering")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PckStudio.Rendering")] +[assembly: AssemblyCopyright("Copyright © 2025")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b1e19d0f-6dd5-4d91-9b45-9818759ca8ef")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PckStudio.Rendering/Renderer.cs b/PckStudio.Rendering/Renderer.cs new file mode 100644 index 00000000..8ba22c2a --- /dev/null +++ b/PckStudio.Rendering/Renderer.cs @@ -0,0 +1,50 @@ +/* Copyright (c) 2024-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.Drawing; +using OpenTK.Graphics.OpenGL; +using PckStudio.Rendering.Shader; + +namespace PckStudio.Rendering +{ + public static class Renderer + { + public static void Draw(ShaderProgram shader, DrawContext context) + { + shader.Bind(); + context.VertexArray.Bind(); + context.IndexBuffer.Bind(); + GL.DrawElements(context.PrimitiveType, context.IndexBuffer.GetCount(), DrawElementsType.UnsignedInt, 0); + } + + public static void SetViewportSize(Size size) + { + GL.Viewport(size); + } + + public static void SetClearColor(Color color) + { + GL.ClearColor(color); + } + + public static void SetLineWidth(float width) + { + GL.LineWidth(width); + } + } +} diff --git a/PckStudio.Rendering/Shader/ShaderLibrary.cs b/PckStudio.Rendering/Shader/ShaderLibrary.cs new file mode 100644 index 00000000..3917f7a8 --- /dev/null +++ b/PckStudio.Rendering/Shader/ShaderLibrary.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PckStudio.Rendering.Shader +{ + public sealed class ShaderLibrary : IDisposable + { + private readonly Dictionary _shaderStorage = new Dictionary(); + + public void AddShader(string name, ShaderProgram shader) => _shaderStorage.Add(name, shader); + + public bool HasShader(string name) => _shaderStorage.TryGetValue(name, out _); + + public bool HasShader(string name, out ShaderProgram shader) => _shaderStorage.TryGetValue(name, out shader); + + public ShaderProgram GetShader(string name) => _shaderStorage[name]; + + public void RemoveShader(string name) => _shaderStorage.Remove(name); + + public void Dispose() + { + foreach (ShaderProgram shader in _shaderStorage.Values) + { + shader.Dispose(); + } + } + } +} diff --git a/PckStudio.Rendering/Shader/ShaderObject.cs b/PckStudio.Rendering/Shader/ShaderObject.cs new file mode 100644 index 00000000..3b0d54ed --- /dev/null +++ b/PckStudio.Rendering/Shader/ShaderObject.cs @@ -0,0 +1,81 @@ +/* Copyright (c) 2024-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.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK.Graphics.OpenGL; + +namespace PckStudio.Rendering.Shader +{ + internal class ShaderObject + { + private int _shaderId; + private ShaderSource _source; + private int _compileStatus; + + internal bool CompileStatusOK => _compileStatus != 0; + + private ShaderObject(ShaderSource source) + { + _shaderId = GL.CreateShader(source.Type); + _source = source; + _compileStatus = 0; + } + + internal static ShaderObject Create(ShaderSource shaderSource) + { + var shaderObject = new ShaderObject(shaderSource); + if (!shaderObject.Compile()) + { + string infoLog = shaderObject.GetShaderInfoLog(); + Debug.Fail(infoLog); + shaderObject.Delete(); + return null; + } + return shaderObject; + } + + private string GetShaderInfoLog() + { + return GL.GetShaderInfoLog(_shaderId); + } + + internal void Delete() + { + GL.DeleteShader(_shaderId); + } + + private bool Compile() + { + GL.ShaderSource(_shaderId, _source.Source); + GL.CompileShader(_shaderId); + + GL.GetShader(_shaderId, ShaderParameter.CompileStatus, out _compileStatus); + + return CompileStatusOK; + } + + internal void AttachToProgram(int programId) + { + GL.AttachShader(programId, _shaderId); + } + } +} diff --git a/PckStudio.Rendering/Shader/ShaderProgram.cs b/PckStudio.Rendering/Shader/ShaderProgram.cs new file mode 100644 index 00000000..97b69ee3 --- /dev/null +++ b/PckStudio.Rendering/Shader/ShaderProgram.cs @@ -0,0 +1,176 @@ +/* Copyright (c) 2024-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 System.Text; +using System.Threading.Tasks; +using OpenTK; +using OpenTK.Graphics.OpenGL; + +namespace PckStudio.Rendering.Shader +{ + public sealed class ShaderProgram : IDisposable + { + private int _programId; + private Dictionary locationCache = new Dictionary(); + + private ShaderProgram(int programId) + { + _programId = programId; + } + + public void Bind() + { + GL.UseProgram(_programId); + } + + public void Unbind() + { + GL.UseProgram(0); + } + + public void Dispose() + { + Unbind(); + GL.DeleteProgram(_programId); + } + + public void SetUniform1(string name, int value) + { + int location = GetUniformLocation(name); + GL.Uniform1(location, value); + } + + public void SetUniform1(string name, float value) + { + int location = GetUniformLocation(name); + GL.Uniform1(location, value); + } + + public void SetUniform2(string name, Size value) => SetUniform2(name, new Vector2(value.Width, value.Height)); + + public void SetUniform2(string name, Vector2 value) + { + int location = GetUniformLocation(name); + GL.Uniform2(location, value); + } + + public void SetUniform4(string name, Vector4 value) + { + int location = GetUniformLocation(name); + GL.Uniform4(location, value); + } + + public void SetUniform4(string name, Color color) + { + int location = GetUniformLocation(name); + GL.Uniform4(location, color); + } + + public void SetUniformMat4(string name, ref Matrix4 matrix) + { + int location = GetUniformLocation(name); + GL.UniformMatrix4(location, false, ref matrix); + } + + private int GetUniformLocation(string name) + { + if (locationCache.ContainsKey(name)) + return locationCache[name]; + Debug.Assert(false, $"Uniform location '{name}' not found"); + return -1; + } + + private bool Link() + { + GL.LinkProgram(_programId); + GL.GetProgram(_programId, GetProgramParameterName.LinkStatus, out int status); + bool success = status != 0; + if (!success) + Debug.WriteLine(GL.GetProgramInfoLog(_programId), category: nameof(ShaderProgram)); + GetActiveUniformLocations(); + return success; + } + + private void GetActiveUniformLocations() + { + GL.GetProgram(_programId, GetProgramParameterName.ActiveUniforms, out int count); + Debug.WriteLine("Active Uniforms: {0}", count); + for (int i = 0; i < count; i++) + { + GL.GetActiveUniform(_programId, i, 256, out int length, out int size, out ActiveUniformType type, out string name); + int id = GL.GetUniformLocation(_programId, name); + Debug.Assert(id != -1); + RegisterUniform(name, id, type); + Debug.WriteLine("Uniform {0}(id:{1}) Type: {2} Name: {3}", i, id, type, name); + } + } + + private void RegisterUniform(string name, int id, ActiveUniformType type) => locationCache.Add(name, id); + + public bool Validate() + { +#if DEBUG + GL.ValidateProgram(_programId); + GL.GetProgram(_programId, GetProgramParameterName.ValidateStatus, out int status); + bool success = status != 0; + if (!success) + Debug.WriteLine(GL.GetProgramInfoLog(_programId), category: nameof(ShaderProgram)); + return success; +#else + return true; +#endif + } + + public static ShaderProgram Create(string vertexSource, string fragmentSource) + { + return Create( + new ShaderSource(ShaderType.VertexShader, vertexSource), + new ShaderSource(ShaderType.FragmentShader, fragmentSource) + ); + } + + public static ShaderProgram Create(params ShaderSource[] shaderSources) + { + int programId = GL.CreateProgram(); + + var shaderObjects = new List(shaderSources.Length); + + foreach (ShaderSource shaderSource in shaderSources) + { + ShaderObject shaderObject = ShaderObject.Create(shaderSource); + shaderObject.AttachToProgram(programId); + shaderObjects.Add(shaderObject); + } + + var shader = new ShaderProgram(programId); + bool success = shader.Link(); + Debug.Assert(success, "Shader Program linking failed."); + + foreach (ShaderObject shaderObject in shaderObjects) + { + shaderObject.Delete(); + } + return shader; + } + + } +} diff --git a/PckStudio.Rendering/Shader/ShaderSource.cs b/PckStudio.Rendering/Shader/ShaderSource.cs new file mode 100644 index 00000000..eb4df595 --- /dev/null +++ b/PckStudio.Rendering/Shader/ShaderSource.cs @@ -0,0 +1,38 @@ +/* Copyright (c) 2024-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.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK.Graphics.OpenGL; + +namespace PckStudio.Rendering.Shader +{ + public readonly struct ShaderSource + { + public readonly ShaderType Type; + public readonly string Source; + + public ShaderSource(ShaderType type, string source) + { + Type = type; + Source = source; + } + } +} diff --git a/PckStudio.Rendering/Spherical.cs b/PckStudio.Rendering/Spherical.cs new file mode 100644 index 00000000..5e1498cd --- /dev/null +++ b/PckStudio.Rendering/Spherical.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK; + +namespace PckStudio.Rendering +{ + internal struct Spherical + { + private Vector3 vector; + + public Spherical() + { + vector = new Vector3(); + } + + /// + /// Radial distance + /// + public float Radius + { + get => vector.X; + set => vector.X = value; + } + + /// + /// Polar angle + /// + public float Theta + { + get => vector.Y; + set => vector.Y = value; + } + + /// + /// Azimuthal angle + /// + public float Phi + { + get => vector.Z; + set => vector.Z = value; + } + + public override string ToString() + { + return $"Radius: {Radius}; Theta: {Theta}; Phi: {Phi};"; + } + } +} diff --git a/PckStudio.Rendering/Texture/CubeTexture.cs b/PckStudio.Rendering/Texture/CubeTexture.cs new file mode 100644 index 00000000..970d1a60 --- /dev/null +++ b/PckStudio.Rendering/Texture/CubeTexture.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK.Graphics.OpenGL; +using PckStudio.Core.Extensions; + +namespace PckStudio.Rendering.Texture +{ + public class CubeTexture : Texture + { + public CubeTexture() : base(TextureTarget.TextureCubeMap) + { + } + + public override void SetTexture(Image image) + { + Bind(); + + int heightPerFace = image.Height / 3; + int widthPerFace = image.Width / 4; + + Size faceSize = new Size(widthPerFace, heightPerFace); + + Image[] faces = new Image[6]; + + Point rightFace = new Point(widthPerFace * 2, heightPerFace * 1); + faces[0] = image.GetArea(new Rectangle(rightFace, faceSize)); + + Point lefttFace = new Point(widthPerFace * 0, heightPerFace * 1); + faces[1] = image.GetArea(new Rectangle(lefttFace, faceSize)); + + Point topFace = new Point(widthPerFace * 1, heightPerFace * 0); + faces[2] = image.GetArea(new Rectangle(topFace, faceSize)); + + Point bottomFace = new Point(widthPerFace * 1, heightPerFace * 2); + faces[3] = image.GetArea(new Rectangle(bottomFace, faceSize)); + + Point frontFace = new Point(widthPerFace * 1, heightPerFace * 1); + faces[4] = image.GetArea(new Rectangle(frontFace, faceSize)); + + Point backFace = new Point(widthPerFace * 3, heightPerFace * 1); + faces[5] = image.GetArea(new Rectangle(backFace, faceSize)); + + for (int i = 0; i < 6; i++) + { + var texture = new Bitmap(faces[i]); + BitmapData data = texture.LockBits(new Rectangle(Point.Empty, texture.Size), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + GL.TexImage2D(TextureTarget.TextureCubeMapPositiveX + i, 0, InternalPixelFormat, widthPerFace, heightPerFace, 0, PixelFormat, PixelType.UnsignedByte, data.Scan0); + } + Unbind(); + } + + } +} diff --git a/PckStudio.Rendering/Texture/Texture.cs b/PckStudio.Rendering/Texture/Texture.cs new file mode 100644 index 00000000..ac80c258 --- /dev/null +++ b/PckStudio.Rendering/Texture/Texture.cs @@ -0,0 +1,109 @@ +using System; +using System.Diagnostics; +using System.Drawing; +using OpenTK; +using OpenTK.Graphics.OpenGL; + +namespace PckStudio.Rendering.Texture +{ + public abstract class Texture : IDisposable + { + protected readonly int _GL_Id; + + protected readonly TextureTarget Target; + + public PixelFormat PixelFormat { get; set; } + public PixelInternalFormat InternalPixelFormat { get; set; } + + public TextureMinFilter MinFilter + { + get => minFilter; + set + { + minFilter = value; + SetTexParameter(TextureParameterName.TextureMinFilter, (int)value); + } + } + + public TextureMagFilter MagFilter + { + get => magFilter; + set + { + magFilter = value; + SetTexParameter(TextureParameterName.TextureMagFilter, (int)value); + } + } + + public TextureWrapMode WrapS + { + get => wrapS; + set + { + wrapS = value; + SetTexParameter(TextureParameterName.TextureWrapS, (int)value); + } + } + + public TextureWrapMode WrapT + { + get => wrapT; + set + { + wrapT = value; + SetTexParameter(TextureParameterName.TextureWrapT, (int)value); + } + } + + public TextureWrapMode WrapR + { + get => wrapR; + set + { + wrapR = value; + SetTexParameter(TextureParameterName.TextureWrapR, (int)value); + } + } + + private TextureMinFilter minFilter; + private TextureMagFilter magFilter; + private TextureWrapMode wrapS; + private TextureWrapMode wrapT; + private TextureWrapMode wrapR; + + protected Texture(TextureTarget target) + { + _GL_Id = GL.GenTexture(); + Target = target; + } + + public virtual void SetTexture(Image image) + { + throw new NotImplementedException(); + } + + public void Bind(int slot = 0) + { + GL.ActiveTexture(TextureUnit.Texture0 + slot); + GL.BindTexture(Target, _GL_Id); + } + + public void Unbind() + { + GL.BindTexture(Target, 0); + } + + private void SetTexParameter(TextureParameterName parameterName, int value) + { + Bind(); + GL.TexParameter(Target, parameterName, value); + Debug.WriteLineIf(GL.GetError() != ErrorCode.NoError, $"{Target}: {parameterName} = {value}"); + } + + public void Dispose() + { + Unbind(); + GL.DeleteTexture(_GL_Id); + } + } +} diff --git a/PckStudio.Rendering/Texture/Texture2D.cs b/PckStudio.Rendering/Texture/Texture2D.cs new file mode 100644 index 00000000..eda7b47f --- /dev/null +++ b/PckStudio.Rendering/Texture/Texture2D.cs @@ -0,0 +1,39 @@ +using System; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using OpenTK; +using OpenTK.Graphics.OpenGL; + +namespace PckStudio.Rendering.Texture +{ + public class Texture2D : Texture + { + public Texture2D() : base(TextureTarget.Texture2D) + { + } + + public void SetSize(Size size) + { + Bind(); + GL.TexImage2D(TextureTarget.Texture2D, 0, InternalPixelFormat, size.Width, size.Height, 0, PixelFormat, PixelType.UnsignedByte, IntPtr.Zero); + Unbind(); + } + + public override void SetTexture(Image image) + { + Bind(); + var bitmap = new Bitmap(image); + BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + GL.TexImage2D(TextureTarget.Texture2D, 0, InternalPixelFormat, bitmap.Width, bitmap.Height, 0, PixelFormat, PixelType.UnsignedByte, data.Scan0); + bitmap.UnlockBits(data); + Unbind(); + } + + public void AttachToFramebuffer(FrameBuffer frameBuffer, FramebufferAttachment attachment) + { + frameBuffer.Bind(); + GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, attachment, Target, _GL_Id, 0); + } + } +} diff --git a/PckStudio.Rendering/TextureChangingEventArgs.cs b/PckStudio.Rendering/TextureChangingEventArgs.cs new file mode 100644 index 00000000..6174e509 --- /dev/null +++ b/PckStudio.Rendering/TextureChangingEventArgs.cs @@ -0,0 +1,32 @@ +/* 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.ComponentModel; +using System.Drawing; + +namespace PckStudio.Rendering +{ + public class TextureChangingEventArgs : CancelEventArgs + { + public Image NewTexture { get; } + + public TextureChangingEventArgs(Image newTexture) : base() + { + NewTexture = newTexture; + } + } +} \ No newline at end of file diff --git a/PckStudio.Rendering/TextureVertex.cs b/PckStudio.Rendering/TextureVertex.cs new file mode 100644 index 00000000..70dfd602 --- /dev/null +++ b/PckStudio.Rendering/TextureVertex.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Runtime.InteropServices; +using OpenTK; + +namespace PckStudio.Rendering +{ + [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 20)] + public struct TextureVertex + { + public Vector3 Position { get; set; } + public Vector2 TexPosition { get; set; } + + public TextureVertex(Vector3 position, Vector2 texPosition) + { + Position = position; + TexPosition = texPosition; + } + } +} diff --git a/PckStudio.Rendering/VertexArray.cs b/PckStudio.Rendering/VertexArray.cs new file mode 100644 index 00000000..a160df17 --- /dev/null +++ b/PckStudio.Rendering/VertexArray.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK.Graphics.OpenGL; +using PckStudio.Core.Extensions; + +namespace PckStudio.Rendering +{ + public class VertexArray : IDisposable + { + private int _id; + private List _vertexBuffers; + + public VertexArray() + { + _id = GL.GenVertexArray(); + _vertexBuffers = new List(); + } + + public int AddNewBuffer(VertexBufferLayout layout) => AddBuffer(new VertexBuffer(), layout); + + public int AddBuffer(VertexBuffer buffer, VertexBufferLayout layout) + { + Bind(); + buffer.Bind(); + System.Collections.ObjectModel.ReadOnlyCollection elements = layout.GetElements(); + int offset = 0; + int vertexBufferIndex = 0; + foreach (LayoutElement element in elements) + { + Debug.Assert(element.Size > 0); + switch (element.Type) + { + case ShaderDataType.Float: + case ShaderDataType.Float2: + case ShaderDataType.Float3: + case ShaderDataType.Float4: + GL.EnableVertexAttribArray(vertexBufferIndex); + GL.VertexAttribPointer(vertexBufferIndex, element.ComponentCount, VertexAttribPointerType.Float, element.Normalize, layout.GetStride(), offset); + vertexBufferIndex += 1; + break; + case ShaderDataType.Int: + case ShaderDataType.Int2: + case ShaderDataType.Int3: + case ShaderDataType.Int4: + GL.EnableVertexAttribArray(vertexBufferIndex); + GL.VertexAttribIPointer(vertexBufferIndex, element.ComponentCount, VertexAttribIntegerType.Int, layout.GetStride(), new IntPtr(offset)); + vertexBufferIndex += 1; + break; + case ShaderDataType.Mat2: + case ShaderDataType.Mat3: + case ShaderDataType.Mat4: + { + int count = element.ComponentCount; + for (int i = 0; i < count; i++) + { + GL.EnableVertexAttribArray(vertexBufferIndex); + + GL.VertexAttribPointer(vertexBufferIndex, count, VertexAttribPointerType.Float, element.Normalize, layout.GetStride(), offset + count * i); + + GL.VertexAttribDivisor(vertexBufferIndex, 1); + vertexBufferIndex += 1; + } + } + break; + default: + break; + } + offset += element.Size; + } + int index = _vertexBuffers.Count; + _vertexBuffers.Add(buffer); + return index; + } + + public void Bind() + { + GL.BindVertexArray(_id); + } + + public void Unbind() + { + GL.BindVertexArray(0); + } + + public void Dispose() + { + Unbind(); + Clear(); + GL.DeleteVertexArray(_id); + } + + public void Clear() + { + foreach (VertexBuffer vao in _vertexBuffers) + { + vao.Dispose(); + } + _vertexBuffers.Clear(); + } + + public void SelectBuffer(int index) + { + if (!_vertexBuffers.IndexInRange(index)) + throw new IndexOutOfRangeException(index.ToString()); + Bind(); + GetBuffer(index).Bind(); + } + + public VertexBuffer GetBuffer(int index) + { + if (_vertexBuffers.IndexInRange(index)) + return _vertexBuffers[index]; + throw new IndexOutOfRangeException(index.ToString()); + } + } +} diff --git a/PckStudio.Rendering/VertexBuffer.cs b/PckStudio.Rendering/VertexBuffer.cs new file mode 100644 index 00000000..5870cc05 --- /dev/null +++ b/PckStudio.Rendering/VertexBuffer.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Markup; +using OpenTK; +using OpenTK.Graphics.OpenGL; + +namespace PckStudio.Rendering +{ + public struct VertexBuffer : IDisposable + { + private int _id; + private int _count; + private int _size; + + public VertexBuffer() + { + _id = GL.GenBuffer(); + _size = 0; + } + + public VertexBuffer(int size) : this() + { + _size = size; + Bind(); + GL.BufferData(BufferTarget.ArrayBuffer, size, IntPtr.Zero, BufferUsageHint.StaticDraw); + Unbind(); + } + + public void SetData(T[] data) where T : struct + { + int sizeofT = Marshal.SizeOf(); + _count = data.Length; + Bind(); + int size = sizeofT * _count; + if (_size < size) + { + GL.BufferData(BufferTarget.ArrayBuffer, size, data, BufferUsageHint.StaticDraw); + _size = size; + return; + } + GL.BufferSubData(BufferTarget.ArrayBuffer, IntPtr.Zero, size, data); + } + + public void Bind() + { + GL.BindBuffer(BufferTarget.ArrayBuffer, _id); + } + + public void Unbind() + { + GL.BindBuffer(BufferTarget.ArrayBuffer, 0); + } + + public void Dispose() + { + Unbind(); + GL.DeleteBuffer(_id); + } + + public IndexBuffer GenIndexBuffer() + { + return IndexBuffer.Create(Enumerable.Range(0, _count).ToArray()); + } + } +} diff --git a/PckStudio.Rendering/VertexBufferLayout.cs b/PckStudio.Rendering/VertexBufferLayout.cs new file mode 100644 index 00000000..fb2bfec0 --- /dev/null +++ b/PckStudio.Rendering/VertexBufferLayout.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace PckStudio.Rendering +{ + public enum ShaderDataType + { + Float, + Float2, + Float3, + Float4, + + Int, + Int2, + Int3, + Int4, + + Mat2, + Mat3, + Mat4, + } + + public struct LayoutElement + { + public readonly ShaderDataType Type; + public readonly bool Normalize; + + public int Size => GetSize(Type); + + public int ComponentCount => GetComponentCount(Type); + + private static int GetSize(ShaderDataType type) + { + return type switch + { + ShaderDataType.Int => 1 * 4, + ShaderDataType.Int2 => 2 * 4, + ShaderDataType.Int3 => 3 * 4, + ShaderDataType.Int4 => 4 * 4, + + ShaderDataType.Float => 1 * 4, + ShaderDataType.Float2 => 2 * 4, + ShaderDataType.Float3 => 3 * 4, + ShaderDataType.Float4 => 4 * 4, + + ShaderDataType.Mat2 => 2 * 2 * 4, + ShaderDataType.Mat3 => 3 * 3 * 4, + ShaderDataType.Mat4 => 4 * 4 * 4, + _ => 0 + }; + } + + private static int GetComponentSize(ShaderDataType type) + { + return type switch + { + ShaderDataType.Int => 4, + ShaderDataType.Int2 => 4, + ShaderDataType.Int3 => 4, + ShaderDataType.Int4 => 4, + + ShaderDataType.Float => 4, + ShaderDataType.Float2 => 4, + ShaderDataType.Float3 => 4, + ShaderDataType.Float4 => 4, + + ShaderDataType.Mat2 => 2 * 4, + ShaderDataType.Mat3 => 3 * 4, + ShaderDataType.Mat4 => 4 * 4, + _ => 0 + }; + } + + private static int GetComponentCount(ShaderDataType type) + { + return type switch + { + ShaderDataType.Int => 1, + ShaderDataType.Int2 => 2, + ShaderDataType.Int3 => 3, + ShaderDataType.Int4 => 4, + + ShaderDataType.Float => 1, + ShaderDataType.Float2 => 2, + ShaderDataType.Float3 => 3, + ShaderDataType.Float4 => 4, + + ShaderDataType.Mat2 => 2 * 2, + ShaderDataType.Mat3 => 3 * 3, + ShaderDataType.Mat4 => 4 * 4, + _ => 0 + }; + } + + public LayoutElement(ShaderDataType type) : this(type, false) { } + + public LayoutElement(ShaderDataType type, bool normalize) + { + Type = type; + Normalize = normalize; + } + + public static implicit operator LayoutElement(ShaderDataType type) => new LayoutElement(type); + } + + public struct VertexBufferLayout + { + private List elements; + private int stride; + + public VertexBufferLayout() + { + elements = new List(); + stride = 0; + } + + public readonly ReadOnlyCollection GetElements() + { + return elements.AsReadOnly(); + } + + public VertexBufferLayout Add(ShaderDataType type) + { + var element = new LayoutElement(type); + elements.Add(element); + stride += element.Size; + return this; + } + + internal readonly int GetStride() + { + return stride; + } + } +} diff --git a/PckStuido.ModelSupport/Extension/SkinExtension.cs b/PckStuido.ModelSupport/Extension/SkinExtension.cs new file mode 100644 index 00000000..3dcf6492 --- /dev/null +++ b/PckStuido.ModelSupport/Extension/SkinExtension.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OMI.Formats.Model; +using PckStudio.Core.Skin; +using PckStudio.ModelSupport; + +namespace PckStuido.ModelSupport.Extension +{ + public static class SkinExtension + { + public static SkinModelInfo GetModelInfo(this Skin skin) => new SkinModelInfo(skin.Texture, skin.Anim, skin.Model); + + public static void SetModelInfo(this Skin skin, SkinModelInfo modelInfo) + { + skin.Texture = modelInfo.Texture; + skin.Anim = modelInfo.Anim; + skin.Model = modelInfo.Model; + } + } +} diff --git a/PckStuido.ModelSupport/Format/External/BedrockLegacyModel.cs b/PckStuido.ModelSupport/Format/External/BedrockLegacyModel.cs new file mode 100644 index 00000000..1f96f7d4 --- /dev/null +++ b/PckStuido.ModelSupport/Format/External/BedrockLegacyModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace PckStudio.ModelSupport.Format.External +{ + internal class BedrockLegacyModel : Dictionary + { + } +} diff --git a/PckStuido.ModelSupport/Format/External/BedrockModel.cs b/PckStuido.ModelSupport/Format/External/BedrockModel.cs new file mode 100644 index 00000000..7f8f4766 --- /dev/null +++ b/PckStuido.ModelSupport/Format/External/BedrockModel.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace PckStudio.ModelSupport.Format.External +{ + internal class BedrockModel + { + [JsonProperty("format_version")] + public string FormatVersion { get; set; } + + [JsonProperty("minecraft:geometry")] + public List Models { get; } = new List(); + } + + internal class Geometry + { + [JsonProperty("description", NullValueHandling = NullValueHandling.Ignore)] + public GeometryDescription Description { get; set; } + + [JsonProperty("bones")] + public List Bones { get; } = new List(); + } + + internal class GeometryDescription + { + [JsonProperty("identifier")] + public string Identifier { get; set; } + + [JsonProperty("texture_width")] + private int TextureWidth; + + [JsonProperty("texture_height")] + private int TextureHeight; + + [JsonIgnore] + public Size TextureSize + { + get => new Size(TextureWidth, TextureHeight); + set + { + TextureWidth = value.Width; + TextureHeight = value.Height; + } + } + } + + internal class Bone + { + [JsonProperty("name")] + public string Name { get; set; } + + public Bone(string name) + { + Name = name; + Cubes = new List(); + } + + + [JsonProperty("parent", NullValueHandling = NullValueHandling.Ignore)] + public string Parent { get; set; } = ""; + + [JsonIgnore] + public Vector3 Pivot + { + get => pivot.Length < 3 ? Vector3.Zero : new Vector3(pivot[0], pivot[1], pivot[2]); + set + { + if (pivot.Length < 3) + pivot = new float[3]; + pivot[0] = value.X; + pivot[1] = value.Y; + pivot[2] = value.Z; + } + } + + [JsonProperty("cubes")] + public List Cubes; + + [JsonProperty("pivot")] + private float[] pivot { get; set; } = new float[3]; + } + + internal class Cube + { + [JsonProperty("origin")] + private float[] origin { get; set; } = new float[3]; + [JsonIgnore] + public Vector3 Origin + { + get => origin.Length < 3 ? Vector3.Zero : new Vector3(origin[0], origin[1], origin[2]); + set + { + if (origin.Length < 3) + origin = new float[3]; + origin[0] = value.X; + origin[1] = value.Y; + origin[2] = value.Z; + } + } + + [JsonProperty("rotation")] + private float[] rotation { get; set; } = new float[3]; + [JsonIgnore] + public Vector3 Rotation + { + get => rotation.Length < 3 ? Vector3.Zero : new Vector3(rotation[0], rotation[1], rotation[2]); + set + { + rotation[0] = value.X; + rotation[1] = value.Y; + rotation[2] = value.Z; + } + } + + [JsonProperty("size")] + private float[] size { get; set; } = new float[3]; + [JsonIgnore] + public Vector3 Size + { + get => size.Length < 3 ? Vector3.Zero : new Vector3(size[0], size[1], size[2]); + set + { + if (size.Length < 3) + size = new float[3]; + size[0] = value.X; + size[1] = value.Y; + size[2] = value.Z; + } + } + + [JsonProperty("uv")] + private float[] uv { get; set; } = new float[2]; + [JsonIgnore] + public Vector2 Uv + { + get => uv.Length < 2 ? Vector2.Zero : new Vector2(uv[0], uv[1]); + set + { + if (uv.Length < 2) + uv = new float[2]; + uv[0] = value.X; + uv[1] = value.Y; + } + } + + [JsonProperty("inflate")] + public float Inflate { get; set; } = 0f; + + [JsonProperty("mirror", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool Mirror { get; set; } = false; + } +} diff --git a/PckStuido.ModelSupport/Format/External/BlockBenchModel.cs b/PckStuido.ModelSupport/Format/External/BlockBenchModel.cs new file mode 100644 index 00000000..1c3f5e3e --- /dev/null +++ b/PckStuido.ModelSupport/Format/External/BlockBenchModel.cs @@ -0,0 +1,362 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NamedTexture = PckStudio.Core.NamedData; + +namespace PckStudio.ModelSupport.Format.External +{ + internal static class BlockBenchFormatInfos + { + internal static readonly string FormatVersion = "4.5"; + + internal static BlockBenchFormatInfo Free { get; } = new BlockBenchFormatInfo(FormatVersion, "free", true); + internal static BlockBenchFormatInfo BedrockEntity { get; } = new BlockBenchFormatInfo(FormatVersion, "bedrock", true); + } + + internal sealed class BlockBenchFormatInfo + { + [JsonProperty("format_version")] + internal string FormatVersion { get; } + + [JsonProperty("model_format")] + internal string ModelFormat { get; } + + [JsonProperty("box_uv")] + internal bool UseBoxUv { get; set; } + + [JsonConstructor] + private BlockBenchFormatInfo() { } + + internal BlockBenchFormatInfo(string formatVersion, string modelFormat, bool useBoxUv) + { + FormatVersion = formatVersion; + ModelFormat = modelFormat; + UseBoxUv = useBoxUv; + } + } + + internal class Element + { + [JsonProperty("name")] + internal string Name; + + [JsonProperty("box_uv")] + internal bool UseBoxUv; + + [JsonProperty("visibility", DefaultValueHandling = DefaultValueHandling.Ignore)] + internal bool IsVisibile { get; set; } = true; + + [JsonProperty("rescale")] + internal bool Rescale; + + [JsonProperty("mirror_uv")] + internal bool MirrorUv; + + [JsonProperty("locked")] + internal bool Locked; + + [DefaultValue(true)] + [JsonProperty("export", DefaultValueHandling = DefaultValueHandling.Ignore)] + internal bool Export { get; } = true; + + [JsonProperty("inflate")] + internal float Inflate; + + [JsonProperty("origin", NullValueHandling = NullValueHandling.Ignore)] + private float[] origin; + + [JsonProperty("from")] + private float[] from; + + [JsonProperty("to")] + private float[] to; + + [JsonProperty("uv_offset")] + private int[] uv_offset; + + [JsonProperty("rotation", NullValueHandling = NullValueHandling.Ignore)] + private float[] rotation; + + [JsonIgnore()] + internal Vector3 Origin + { + get + { + return new Vector3(origin?[0] ?? 0, origin?[1] ?? 0, origin?[2] ?? 0); + } + set + { + if (origin is null || origin.Length < 3) + origin = new float[3]; + origin[0] = value.X; + origin[1] = value.Y; + origin[2] = value.Z; + } + } + + [JsonIgnore()] + internal Vector3 From + { + get + { + return new Vector3(from?[0] ?? 0, from?[1] ?? 0, from?[2] ?? 0); + } + set + { + if (from is null || from.Length < 3) + from = new float[3]; + from[0] = value.X; + from[1] = value.Y; + from[2] = value.Z; + } + } + + [JsonIgnore()] + internal Vector3 To + { + get + { + return new Vector3(to?[0] ?? 0, to?[1] ?? 0, to?[2] ?? 0); + } + set + { + if (to is null || to.Length < 3) + to = new float[3]; + to[0] = value.X; + to[1] = value.Y; + to[2] = value.Z; + } + } + + [JsonIgnore()] + internal Vector2 UvOffset + { + get + { + return new Vector2(uv_offset?[0] ?? 0, uv_offset?[1] ?? 0); + } + set + { + if (uv_offset is null || uv_offset.Length < 2) + uv_offset = new int[2]; + uv_offset[0] = (int)value.X; + uv_offset[1] = (int)value.Y; + } + } + + [JsonIgnore()] + internal Vector3 Rotation + { + get + { + return new Vector3(rotation?[0] ?? 0, rotation?[1] ?? 0, rotation?[2] ?? 0); + } + set + { + if (rotation is null || rotation.Length < 3) + rotation = new float[3]; + rotation[0] = value.X; + rotation[1] = value.Y; + rotation[2] = value.Z; + } + } + + [JsonProperty("type")] + internal string Type; + + [JsonProperty("uuid")] + internal Guid Uuid; + + internal static Element CreateCube(string name, Vector2 uvOffset, Vector3 pos, Vector3 size, float inflate, bool mirror) + { + return new Element + { + Name = name, + UseBoxUv = true, + Locked = false, + Rescale = false, + Type = "cube", + Uuid = Guid.NewGuid(), + UvOffset = uvOffset, + MirrorUv = mirror, + Inflate = inflate, + From = pos, + To = pos + size + }; + } + + } + + internal class Texture + { + public static implicit operator Image(Texture texture) => texture.GetImage(); + public static implicit operator Texture(Image image) => new Texture(image); + public static implicit operator Texture(NamedTexture namedTexture) => new Texture(namedTexture.Name, namedTexture.Value); + + private const string _TEXTUREDATAHEAD = "data:image/png;base64,"; + + [JsonConstructor] + private Texture() + { + } + + internal Texture(string name, Image image) + : this(image) + { + Name = name; + } + + internal Texture(Image image) + { + if (image is not null) + { + SetImage(image); + return; + } + Debug.WriteLine($"param: {nameof(image)} is null"); + } + + [JsonProperty("name")] + internal string Name { get; set; } + + [JsonProperty("source")] + internal string TextureSource { get; private set; } + + private Image GetImage() + { + string data = TextureSource; + if (data.StartsWith(_TEXTUREDATAHEAD)) + { + byte[] encodedData = Convert.FromBase64String(data.Substring(_TEXTUREDATAHEAD.Length)); + using var ms = new MemoryStream(encodedData); + return Image.FromStream(ms); + } + return null; + } + + private void SetImage(Image image) + { + var ms = new MemoryStream(); + image.Save(ms, ImageFormat.Png); + TextureSource = _TEXTUREDATAHEAD + Convert.ToBase64String(ms.ToArray()); + } + } + + internal class Outline + { + [JsonProperty("name")] + internal string Name; + + [JsonProperty("origin")] + private float[] origin; + + [JsonIgnore] + public Vector3 Origin + { + get => new Vector3(origin?[0] ?? 0, origin?[1] ?? 0, origin?[2] ?? 0); + set + { + if (origin is null || origin.Length < 3) + origin = new float[3]; + origin[0] = value.X; + origin[1] = value.Y; + origin[2] = value.Z; + } + } + + [JsonProperty("rotation")] + private float[] rotation; + + [JsonIgnore] + public Vector3 Rotation + { + get => new Vector3(rotation?[0] ?? 0, rotation?[1] ?? 0, rotation?[2] ?? 0); + set + { + if (rotation is null || rotation.Length < 3) + rotation = new float[3]; + rotation[0] = value.X; + rotation[1] = value.Y; + rotation[2] = value.Z; + } + } + + [JsonProperty("uuid")] + internal Guid Uuid; + + [JsonProperty("children")] + internal JArray Children; + + public Outline(string name) + { + Name = name; + origin = new float[3]; + Uuid = Guid.NewGuid(); + Children = new JArray(); + } + } + + internal class TextureRes + { + [JsonProperty("width")] + internal int Width { get; set; } + + [JsonProperty("height")] + internal int Height { get; set; } + + public TextureRes(int width, int height) + { + Width = width; + Height = height; + } + + public static implicit operator Size(TextureRes res) => new Size(res.Width, res.Height); + public static implicit operator TextureRes(Size size) => new TextureRes(size.Width, size.Height); + } + + internal class BlockBenchModel + { + [JsonProperty("name")] + internal string Name; + + [JsonProperty("meta")] + internal BlockBenchFormatInfo Format; + + [JsonProperty("model_identifier")] + internal string ModelIdentifier { get; set; } = ""; + + [JsonProperty("resolution")] + internal TextureRes TextureResolution; + + [JsonProperty("elements")] + internal Element[] Elements; + + [JsonProperty("outliner")] + internal JArray Outliner; + + [JsonProperty("textures")] + internal Texture[] Textures; + + internal static BlockBenchModel Create(BlockBenchFormatInfo formatInfo, string name, Size textureResolution, IEnumerable textures) + { + return new BlockBenchModel() + { + Name = name, + Textures = textures.ToArray(), + TextureResolution = textureResolution, + ModelIdentifier = "", + Format = formatInfo, + }; + } + } +} diff --git a/PckStuido.ModelSupport/Format/Internal/PSM/PSMFile.cs b/PckStuido.ModelSupport/Format/Internal/PSM/PSMFile.cs new file mode 100644 index 00000000..1aebcecc --- /dev/null +++ b/PckStuido.ModelSupport/Format/Internal/PSM/PSMFile.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using PckStudio.Core.Skin; + +namespace PckStudio.ModelSupport.Internal.Format +{ +/* + Magic - 3 bytes("psm") + Version - 1 byte [u8] + Anim - 4 bytes[int32] + NumberOfParts - 4 bytes[int32] + { + part parent - 1 byte (HEAD=0, BODY=1, LEG0=2, LEG1=3, ARM0=4, ARM1=5) + Position-X - 4 bytes (float32) + Position-Y - 4 bytes (float32) + Position-Z - 4 bytes (float32) + Size-X - 4 bytes (float32) + Size-Y - 4 bytes (float32) + Size-Z - 4 bytes (float32) + MirrorAndUvX - 1 bit flag 7 bits uv.x value(0-64) (s8) + HideWithArmorAndUvY - 1 bit flag 7 bits uv.y value(0-64) (s8) + inflation/scale value - 4 bytes (float32) + } + NumberOfOffsets - 4 bytes[int32] + { + offset part - 1 byte + vertical offset - 4 bytes[float] + } +*/ + public sealed class PSMFile + { + internal static readonly string HEADER_MAGIC = "psm"; + internal const byte CurrentVersion = 1; + + public readonly byte Version; + + internal PSMFile(byte version) + { + Version = version; + } + + internal PSMFile(byte version, SkinANIM skinANIM) + : this(version) + { + SkinANIM = skinANIM; + } + + public SkinANIM SkinANIM { get; private set; } + + public readonly List Parts = new List(); + public readonly List Offsets = new List(); + } + + public enum PSMOffsetType : byte + { + HEAD = 0, + BODY = 1, + ARM0 = 2, + ARM1 = 3, + LEG0 = 4, + LEG1 = 5, + + TOOL0 = 6, + TOOL1 = 7, + + HELMET = 8, + SHOULDER0 = 9, + SHOULDER1 = 10, + CHEST = 11, + WAIST = 12, + PANTS0 = 13, + PANTS1 = 14, + BOOT0 = 15, + BOOT1 = 16, + } + + public enum PSMParentType : byte + { + HEAD = 0, + BODY = 1, + ARM0 = 2, + ARM1 = 3, + LEG0 = 4, + LEG1 = 5, + } +} diff --git a/PckStuido.ModelSupport/Format/Internal/PSM/PSMFileReader.cs b/PckStuido.ModelSupport/Format/Internal/PSM/PSMFileReader.cs new file mode 100644 index 00000000..40579ea3 --- /dev/null +++ b/PckStuido.ModelSupport/Format/Internal/PSM/PSMFileReader.cs @@ -0,0 +1,156 @@ +using System.Diagnostics; +using System.IO; +using System.Text; +using OMI; +using OMI.Workers; +using PckStudio.Core.FileFormats; +using PckStudio.Core; +using PckStudio.Core.Skin; + +namespace PckStudio.ModelSupport.Internal.Format +{ + internal class PSMFileReader : IDataFormatReader, IDataFormatReader + { + public PSMFile FromFile(string filename) + { + if (File.Exists(filename)) + { + using (var fs = File.OpenRead(filename)) + { + return FromStream(fs); + } + } + throw new FileNotFoundException(filename); + } + + public PSMFile FromStream(Stream stream) + { + using var reader = new EndiannessAwareBinaryReader(stream, Encoding.ASCII, leaveOpen: true, ByteOrder.LittleEndian); + + var magic = reader.ReadString(3); + if (magic != PSMFile.HEADER_MAGIC) + { + Trace.TraceError("PSMFileReader.FromStream - Failed to load csmb.\n\tReason: Header magic mismatch."); + return new PSMFile(byte.MaxValue); + } + + byte version = reader.ReadByte(); + if (version < 1 || version > 1) + { + Trace.TraceError("PSMFileReader.FromStream - Failed to load csmb.\n\tReason: Unsupported version."); + return new PSMFile(byte.MaxValue); + } + + var skinANIM = SkinANIM.FromValue(reader.ReadInt32()); + PSMFile csmbFile = new PSMFile(version, skinANIM); + int numOfParts = reader.ReadInt32(); + for (int i = 0; i < numOfParts; i++) + { + SkinBOX part = ReadPart(reader); + csmbFile.Parts.Add(part); + } + int numOfOffsets = reader.ReadInt32(); + for (int i = 0; i < numOfOffsets; i++) + { + SkinPartOffset offset = ReadOffset(reader); + csmbFile.Offsets.Add(offset); + } + + return csmbFile; + } + + private SkinBOX ReadPart(EndiannessAwareBinaryReader reader) + { + string type = GetParentType((PSMParentType)reader.ReadByte()); + float posX = reader.ReadSingle(); + float posY = reader.ReadSingle(); + float posZ = reader.ReadSingle(); + float sizeX = reader.ReadSingle(); + float sizeY = reader.ReadSingle(); + float sizeZ = reader.ReadSingle(); + byte mirrorAndUvX = reader.ReadByte(); + byte hideWithArmorAndUvY = reader.ReadByte(); + int uvX = mirrorAndUvX & 0x7f; + int uvY = hideWithArmorAndUvY & 0x7f; + bool mirror = (mirrorAndUvX & 0x80) != 0; + bool hideWithArmor = (hideWithArmorAndUvY & 0x80) != 0; + float scale = reader.ReadSingle(); + return new SkinBOX(type, new System.Numerics.Vector3(posX, posY, posZ), new System.Numerics.Vector3(sizeX, sizeY, sizeZ), new System.Numerics.Vector2(uvX, uvY), hideWithArmor, mirror, scale); + } + + private SkinPartOffset ReadOffset(EndiannessAwareBinaryReader reader) + { + PSMOffsetType type = (PSMOffsetType)reader.ReadByte(); + float value = reader.ReadSingle(); + return new SkinPartOffset(GetOffsetType(type), value); + } + + private static string GetParentType(PSMParentType type) + { + switch (type) + { + case PSMParentType.HEAD: + return "HEAD"; + case PSMParentType.BODY: + return "BODY"; + case PSMParentType.ARM0: + return "ARM0"; + case PSMParentType.ARM1: + return "ARM1"; + case PSMParentType.LEG0: + return "LEG0"; + case PSMParentType.LEG1: + return "LEG1"; + default: + throw new InvalidDataException(type.ToString()); + } + } + + private static string GetOffsetType(PSMOffsetType type) + { + switch (type) + { + case PSMOffsetType.HEAD: + return "HEAD"; + case PSMOffsetType.BODY: + return "BODY"; + case PSMOffsetType.ARM0: + return "ARM0"; + case PSMOffsetType.ARM1: + return "ARM1"; + case PSMOffsetType.LEG0: + return "LEG0"; + case PSMOffsetType.LEG1: + return "LEG1"; + case PSMOffsetType.TOOL0: + return "TOOL0"; + case PSMOffsetType.TOOL1: + return "TOOL1"; + case PSMOffsetType.HELMET: + return "HELMET"; + case PSMOffsetType.SHOULDER0: + return "SHOULDER0"; + case PSMOffsetType.SHOULDER1: + return "SHOULDER1"; + case PSMOffsetType.CHEST: + return "CHEST"; + case PSMOffsetType.WAIST: + return "WAIST"; + case PSMOffsetType.PANTS0: + return "PANTS0"; + case PSMOffsetType.PANTS1: + return "PANTS1"; + case PSMOffsetType.BOOT0: + return "BOOT0"; + case PSMOffsetType.BOOT1: + return "BOOT1"; + default: + throw new InvalidDataException(type.ToString()); + } + } + + object IDataFormatReader.FromStream(Stream stream) => FromStream(stream); + + object IDataFormatReader.FromFile(string filename) => FromFile(filename); + } +} diff --git a/PckStuido.ModelSupport/Format/Internal/PSM/PSMFileWriter.cs b/PckStuido.ModelSupport/Format/Internal/PSM/PSMFileWriter.cs new file mode 100644 index 00000000..aebb3144 --- /dev/null +++ b/PckStuido.ModelSupport/Format/Internal/PSM/PSMFileWriter.cs @@ -0,0 +1,134 @@ +using System.IO; +using System.Text; +using PckStudio.Core.FileFormats; +using OMI.Workers; +using OMI; +using System; +using OpenTK; +using PckStudio.Core.Skin; + +namespace PckStudio.ModelSupport.Internal.Format +{ + internal class PSMFileWriter : IDataFormatWriter + { + PSMFile _PSM; + + public PSMFileWriter(PSMFile csmb) + { + _PSM = csmb; + } + + public void WriteToFile(string filename) + { + using(var fs = File.OpenWrite(filename)) + { + WriteToStream(fs); + } + } + + public void WriteToStream(Stream stream) + { + using (var writer = new EndiannessAwareBinaryWriter(stream, Encoding.ASCII, leaveOpen: true, ByteOrder.LittleEndian)) + { + writer.WriteString(PSMFile.HEADER_MAGIC); + writer.Write(_PSM.Version); + writer.Write(_PSM.SkinANIM.ToValue()); + writer.Write(_PSM.Parts.Count); + foreach (SkinBOX part in _PSM.Parts) + { + WritePart(writer, part); + } + writer.Write(_PSM.Offsets.Count); + foreach (SkinPartOffset offset in _PSM.Offsets) + { + writer.Write((byte)GetOffsetPart(offset.Type)); + writer.Write(offset.Value); + } + } + } + + private void WritePart(EndiannessAwareBinaryWriter writer, SkinBOX part) + { + writer.Write((byte)GetParentPart(part.Type)); + writer.Write(part.Pos.X); + writer.Write(part.Pos.Y); + writer.Write(part.Pos.Z); + writer.Write(part.Size.X); + writer.Write(part.Size.Y); + writer.Write(part.Size.Z); + + byte uvX = (byte)MathHelper.Clamp((int)part.UV.X, 0, 64); + byte uvY = (byte)MathHelper.Clamp((int)part.UV.Y, 0, 64); + byte mirrorAndUvX = (byte)(Convert.ToByte(part.Mirror) << 7 | uvX); + byte hideWithArmorAndUvY = (byte)(Convert.ToByte(part.HideWithArmor) << 7 | uvY); + + writer.Write(mirrorAndUvX); + writer.Write(hideWithArmorAndUvY); + writer.Write(part.Scale); + } + + private static PSMParentType GetParentPart(string type) + { + switch (type) + { + case "HEAD": + return PSMParentType.HEAD; + case "BODY": + return PSMParentType.BODY; + case "ARM0": + return PSMParentType.ARM0; + case "ARM1": + return PSMParentType.ARM1; + case "LEG0": + return PSMParentType.LEG0; + case "LEG1": + return PSMParentType.LEG1; + default: + throw new InvalidDataException(type); + } + } + + private static PSMOffsetType GetOffsetPart(string type) + { + switch (type) + { + case "HEAD": + return PSMOffsetType.HEAD; + case "BODY": + return PSMOffsetType.BODY; + case "ARM0": + return PSMOffsetType.ARM0; + case "ARM1": + return PSMOffsetType.ARM1; + case "LEG0": + return PSMOffsetType.LEG0; + case "LEG1": + return PSMOffsetType.LEG1; + case "TOOL0": + return PSMOffsetType.TOOL0; + case "TOOL1": + return PSMOffsetType.TOOL1; + case "HELMET": + return PSMOffsetType.HELMET; + case "SHOULDER0": + return PSMOffsetType.SHOULDER0; + case "SHOULDER1": + return PSMOffsetType.SHOULDER1; + case "CHEST": + return PSMOffsetType.CHEST; + case "WAIST": + return PSMOffsetType.WAIST; + case "PANTS0": + return PSMOffsetType.PANTS0; + case "PANTS1": + return PSMOffsetType.PANTS1; + case "BOOT0": + return PSMOffsetType.BOOT0; + case "BOOT1": + return PSMOffsetType.BOOT1; + default: + throw new InvalidDataException(type); + } + } + } +} diff --git a/PckStuido.ModelSupport/GameModelImporter.cs b/PckStuido.ModelSupport/GameModelImporter.cs new file mode 100644 index 00000000..5730d551 --- /dev/null +++ b/PckStuido.ModelSupport/GameModelImporter.cs @@ -0,0 +1,239 @@ +/* Copyright (c) 2024-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.IO; +using System.Linq; +using System.Drawing; +using System.Numerics; +using System.Diagnostics; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using OMI.Formats.Model; + +using PckStudio.Core.Json; +using PckStudio.Core.Extensions; +using PckStudio.Core; +using PckStudio.ModelSupport.Format.External; +using PckStuido.ModelSupport.Properties; +using NamedTexture = PckStudio.Core.NamedData; + +namespace PckStudio.ModelSupport +{ + public sealed class GameModelImporter : ModelImporter + { + public static GameModelImporter Default { get; } = new GameModelImporter(); + + public sealed class ModelExportSettings + { + public bool CreateModelOutline { get; set; } = true; + } + + public ModelExportSettings ExportSettings { get; } = new ModelExportSettings(); + + public sealed class ModelImportSettings + { + public int ModelVersion { get; set; } = 1; + } + + public ModelImportSettings ImportSettings { get; } = new ModelImportSettings(); + + public static ReadOnlyDictionary ModelMetaData { get; } = JsonConvert.DeserializeObject>(Resources.modelMetaData); + public static ReadOnlyDictionary DefaultModels { get; } = JsonConvert.DeserializeObject>(Resources.defaultModels); + + private GameModelImporter() + { + // TODO: add import functionality -miku + InternalAddProvider(new FileDialogFilter("Block bench model(*.bbmodel)", "*.bbmodel"), ImportBlockBenchModel, ExportBlockBenchModel); + } + + private readonly Vector3 bbModelTransformAxis = new Vector3(1, 1, 0); + // maybe get this value from the json. -miku + private readonly Vector3 _heightOffset = Vector3.UnitY * 24f; + + private void ExportBlockBenchModel(string filepath, GameModelInfo modelInfo) + { + BlockBenchModel blockBenchModel = BlockBenchModel.Create(BlockBenchFormatInfos.BedrockEntity, modelInfo.Model.Name, modelInfo.Model.TextureSize, modelInfo.Textures.Select(nt => (Texture)nt)); + blockBenchModel.ModelIdentifier = modelInfo.Model.Name; + + List elements = new List(modelInfo.Model.PartCount); + + if (!ModelMetaData.TryGetValue(modelInfo.Model.Name, out JsonModelMetaData modelMetaData)) + { + Trace.TraceError($"[{nameof(GameModelImporter)}:{nameof(ExportBlockBenchModel)}] Failed to get model meta data for '{modelInfo.Model.Name}'."); + return; + } + + IEnumerable outlines = ConvertToOutlines(modelInfo.Model, Vector3.Zero, modelMetaData.RootParts, elements.AddRange); + + blockBenchModel.Elements = elements.ToArray(); + if (ExportSettings.CreateModelOutline) + outlines = new Outline[1] + { + new Outline(modelInfo.Model.Name) { Children = JArray.FromObject(outlines) } + }; + + blockBenchModel.Outliner = JArray.FromObject(outlines); + + string content = JsonConvert.SerializeObject(blockBenchModel, Formatting.Indented); + File.WriteAllText(filepath, content); + } + + private Element ToElement(string partName, ModelBox modelBox, Vector3 partTranslation) + { + Element element = CreateElement(partName, modelBox, partTranslation, bbModelTransformAxis, _heightOffset); + //element.Rotation = rotation * TransformSpace(Vector3.One, Vector3.Zero, bbModelTransformAxis); + //element.Origin = outline.Origin; + return element; + } + + private Outline[] ConvertToOutlines(Model model, Vector3 parentRotation, IReadOnlyCollection keyValues, Action addElements, int depth = 0) + { + Outline CreateOutline(ModelPart modelPart) + { + Outline outline = new Outline(modelPart.Name); + + Vector3 partTranslation = modelPart.Translation; + outline.Origin = TransformSpace(partTranslation, Vector3.Zero, bbModelTransformAxis); + outline.Origin += _heightOffset; + + Vector3 rotation = modelPart.Rotation; + outline.Rotation = rotation * TransformSpace(Vector3.One, Vector3.Zero, bbModelTransformAxis); + outline.Rotation += parentRotation; + + Element[] elements1 = modelPart.GetBoxes().Select(box => ToElement(modelPart.Name, box, partTranslation)).ToArray(); + addElements(elements1); + + outline.Children.Add(elements1.Select(element => element.Uuid).ToArray()); + return outline; + } + + if (depth == 0 && keyValues.Count == 0) + { + return model.GetParts().Select(CreateOutline).ToArray(); + } + + List outlines = new List(); + foreach (ModelMetaDataPart item in keyValues) + { + if (!model.TryGetPart(item.Name, out ModelPart modelPart)) + { + Debug.WriteLine($"{nameof(item.Name)}: '{item.Name}' not in {nameof(model)}."); + continue; + } + Outline partentOutline = CreateOutline(modelPart); + JToken[] s = ConvertToOutlines(model, modelPart.Rotation, item.Children, addElements, depth + 1).Select(JToken.FromObject).ToArray(); + partentOutline.Children.Add(s); + outlines.Add(partentOutline); + } + return outlines.ToArray(); + } + + + private static Element CreateElement(string name, ModelBox box, Vector3 origin, Vector3 translationUnit, Vector3 offset) + { + Vector3 pos = box.Position; + Vector3 size = box.Size; + Vector3 transformPos = TransformSpace(pos + origin, size, translationUnit) + offset; + return Element.CreateCube(name, box.Uv, transformPos, size, box.Inflate, box.Mirror); + } + + private GameModelInfo ImportBlockBenchModel(string filepath) + { + BlockBenchModel blockBenchModel = JsonConvert.DeserializeObject(File.ReadAllText(filepath)); + if (!blockBenchModel.Format.UseBoxUv) + { + Trace.TraceError($"[{nameof(GameModelImporter)}:{nameof(ImportBlockBenchModel)}] Failed to import model '{blockBenchModel.ModelIdentifier}': Model does not use box uv."); + return null; + } + + if (!ModelMetaData.TryGetValue(blockBenchModel.ModelIdentifier, out JsonModelMetaData modelMetaData)) + { + Trace.TraceError($"[{nameof(GameModelImporter)}:{nameof(ImportBlockBenchModel)}] Failed to import model '{blockBenchModel.ModelIdentifier}': No model meta data found."); + return null; + } + + IEnumerable textures = blockBenchModel.Textures + .Where(t => modelMetaData.TextureLocations.Any(texName => !string.IsNullOrEmpty(t.Name) && texName.EndsWith(Path.GetFileNameWithoutExtension(t.Name)))) + .Select(t => new NamedTexture(modelMetaData.TextureLocations.First(texName => texName.EndsWith(Path.GetFileNameWithoutExtension(t.Name))), (Image)t)); + + Model model = new Model(blockBenchModel.ModelIdentifier, blockBenchModel.TextureResolution); + + JArray rootOutline = blockBenchModel.Outliner + .FirstOrDefault(token => token.Type == JTokenType.Object && token.ToObject().Name == blockBenchModel.ModelIdentifier) + ?.ToObject().Children ?? blockBenchModel.Outliner; + + foreach (Outline outline in rootOutline.Where(token => token.Type == JTokenType.Object).Select(token => token.ToObject())) + { + foreach (ModelPart part in ConvertOutlineToModelPart(outline, blockBenchModel.Elements)) + { + model.AddPart(part); + } + } + + return new GameModelInfo(model, textures); + } + + private IEnumerable ConvertOutlineToModelPart(Outline root, IReadOnlyCollection elements) + { + List parts = new List( + root.Children + .Where(token => token.Type == JTokenType.Object) + .SelectMany(token => ConvertOutlineToModelPart(token.ToObject(), elements)) + ); + + IEnumerable modelBoxElements = root.Children + .Where(token => token.Type == JTokenType.String && Guid.TryParse(token.ToString(), out Guid _)) + .Select(token => elements.First(e => e.Uuid == Guid.Parse(token.ToString()))) + .Where(element => element.Type == "cube" && element.UseBoxUv && element.Export); + + Vector3 additionalRotation = new Vector3(); + Element first = modelBoxElements.FirstOrDefault() ?? new Element() { Rotation = Vector3.Zero }; + if (first.Rotation != Vector3.Zero) + { + if (!modelBoxElements.All(e => e.Rotation == first.Rotation)) + { + Trace.TraceError($"[{nameof(GameModelImporter)}:{nameof(ImportBlockBenchModel)}] Rotation can't be applied for single elements."); + return Enumerable.Empty(); + } + additionalRotation = first.Rotation; + } + Vector3 translation = TransformSpace(root.Origin - _heightOffset, Vector3.Zero, bbModelTransformAxis); + Vector3 rotation = TransformSpace(root.Rotation, Vector3.Zero, bbModelTransformAxis); + ModelPart part = new ModelPart(root.Name, string.Empty, translation, rotation, additionalRotation); + part.AddBoxes(modelBoxElements.Select(box => ConvertElementToModelBox(box, part.Translation))); + parts.Add(part); + return parts; + } + + private ModelBox ConvertElementToModelBox(Element element, Vector3 translation) + { + BoundingBox boundingBox = new BoundingBox(element.From, element.To); + + Vector3 pos = boundingBox.Start.ToNumericsVector(); + Vector3 size = boundingBox.Volume.ToNumericsVector(); + + Vector3 transformedPos = TransformSpace(pos, size, bbModelTransformAxis) - translation + _heightOffset; + + return new ModelBox(transformedPos, size, element.UvOffset, element.Inflate, element.MirrorUv); + } + } +} diff --git a/PckStuido.ModelSupport/GameModelInfo.cs b/PckStuido.ModelSupport/GameModelInfo.cs new file mode 100644 index 00000000..dd53eb5a --- /dev/null +++ b/PckStuido.ModelSupport/GameModelInfo.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using OMI.Formats.Model; +using NamedTexture = PckStudio.Core.NamedData; + +namespace PckStudio.ModelSupport +{ + public sealed class GameModelInfo + { + public Model Model { get; } + + public IEnumerable Textures { get; } + + public GameModelInfo(Model model, IEnumerable textures) + { + Model = model; + Textures = textures; + } + + } +} diff --git a/PckStuido.ModelSupport/Json/JsonDefaultModel.cs b/PckStuido.ModelSupport/Json/JsonDefaultModel.cs new file mode 100644 index 00000000..2fb3aadc --- /dev/null +++ b/PckStuido.ModelSupport/Json/JsonDefaultModel.cs @@ -0,0 +1,48 @@ +using System; +using System.Numerics; +using Newtonsoft.Json; + +namespace PckStudio.Core.Json +{ + public class DefaultModel + { + [JsonProperty("textureSize", Required = Required.Always)] + public Vector2 TextureSize { get; set; } + + [JsonProperty("parts", Required = Required.Always)] + public DefaultPart[] Parts { get; set; } = Array.Empty(); + } + + public class DefaultPart + { + [JsonProperty("name", Required = Required.Always)] + public string Name { get; set; } + + [JsonProperty("translation")] + public Vector3 Translation { get; set; } = Vector3.Zero; + + [JsonProperty("rotation")] + public Vector3 Rotation { get; set; } = Vector3.Zero; + + [JsonProperty("boxes")] + public ModelDefaultBox[] Boxes { get; set; } + } + + public class ModelDefaultBox + { + [JsonProperty("pos")] + public Vector3 Position { get; set; } + + [JsonProperty("size")] + public Vector3 Size { get; set; } + + [JsonProperty("uv")] + public Vector2 Uv { get; set; } + + [JsonProperty("mirror")] + public bool Mirror { get; set; } = false; + + [JsonProperty("inflate")] + public float Inflate { get; set; } = 0f; + } +} diff --git a/PckStuido.ModelSupport/Json/JsonModelMetaData.cs b/PckStuido.ModelSupport/Json/JsonModelMetaData.cs new file mode 100644 index 00000000..d274cfb3 --- /dev/null +++ b/PckStuido.ModelSupport/Json/JsonModelMetaData.cs @@ -0,0 +1,46 @@ +using System; +using System.Numerics; +using Newtonsoft.Json; + +namespace PckStudio.Core.Json +{ + public class ModelMetaDataPart + { + [JsonProperty("name", Required = Required.Always)] + public string Name { get; set; } + + [JsonProperty("children", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)] + public ModelMetaDataPart[] Children { get; set; } = Array.Empty(); + + [JsonConstructor] + public ModelMetaDataPart() + { + } + + public ModelMetaDataPart(string name) + : this(name, Array.Empty()) + { + } + + public ModelMetaDataPart(string name, params ModelMetaDataPart[] children) + { + Name = name; + Children = children; + } + } + + public class JsonModelMetaData + { + [JsonProperty("textureLocations", Required = Required.Always)] + public string[] TextureLocations { get; set; } + + [JsonProperty("materialName", NullValueHandling = NullValueHandling.Ignore)] + public string MaterialName { get; set; } = string.Empty; + + [JsonProperty("uv_offsets", NullValueHandling = NullValueHandling.Ignore)] + public Vector2[] UvOffsets { get; set; } = Array.Empty(); + + [JsonProperty("parts", NullValueHandling = NullValueHandling.Ignore)] + public ModelMetaDataPart[] RootParts { get; set; } = Array.Empty(); + } +} diff --git a/PckStuido.ModelSupport/ModelImporter.cs b/PckStuido.ModelSupport/ModelImporter.cs new file mode 100644 index 00000000..ee32a94a --- /dev/null +++ b/PckStuido.ModelSupport/ModelImporter.cs @@ -0,0 +1,178 @@ +/* Copyright (c) 2024-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.IO; +using System.Linq; +using System.Numerics; +using PckStudio.Core; +using PckStudio.Interfaces; + +namespace PckStudio.ModelSupport +{ + public abstract class ModelImporter where T : class + { + private Dictionary> _importProviders = new Dictionary>(); + + private sealed class InternalImportProvider : IModelImportProvider + { + public string Name => nameof(InternalImportProvider); + + public FileDialogFilter DialogFilter => _dialogFilter; + + public bool SupportImport => _import != null; + + public bool SupportExport => _export != null; + + private FileDialogFilter _dialogFilter; + private Func _import; + private Action _export; + + public InternalImportProvider(FileDialogFilter dialogFilter, Func import, Action export) + { + _dialogFilter = dialogFilter; + _import = import; + _export = export; + } + + public void Export(string filename, T model) + { + _ = _export ?? throw new NotImplementedException(); + _export(filename, model); + } + + public T Import(string filename) + { + _ = _import ?? throw new NotImplementedException(); + return _import(filename); + } + + public void Export(ref Stream stream, T model) + { + throw new NotImplementedException(); + } + + public T Import(Stream stream) + { + throw new NotImplementedException(); + } + } + + /// + /// Filter that can be used for or + /// + public string SupportedModelFileFormatsFilter => string.Join("|", _importProviders.Values.Select(p => p.DialogFilter)); + + public T Import(string filename) + { + if (!File.Exists(filename)) + { + Trace.TraceWarning($"[{nameof(ModelImporter)}:Import] Failed to import '{filename}'. File does not exist."); + return default; + } + + if (!HasProvider(filename)) + { + Trace.TraceWarning($"[{nameof(ModelImporter)}:Import] No provider found for '{Path.GetExtension(filename)}'."); + return default; + } + + IModelImportProvider provider = GetProvider(filename); + if (!provider.SupportImport) + { + throw new NotSupportedException($"Provider '{provider.Name}' does not support importing."); + } + + return provider.Import(filename); + } + + public void Export(string filename, T model) + { + if (model is null) + { + Trace.TraceError($"[{nameof(ModelImporter)}:Export] Model is null."); + return; + } + + if (!HasProvider(filename)) + { + Trace.TraceWarning($"[{nameof(ModelImporter)}:Export] No provider found for '{Path.GetExtension(filename)}'."); + return; + } + + IModelImportProvider provider = GetProvider(filename); + if (!provider.SupportExport) + { + throw new NotSupportedException($"Provider '{provider.Name}' does not support exporting."); + } + provider.Export(filename, model); + } + + internal bool AddProvider(IModelImportProvider provider) + { + if (_importProviders.ContainsKey(provider.DialogFilter.Extension)) + return false; + + _importProviders.Add(provider.DialogFilter.Extension, provider); + return true; + } + + protected bool InternalAddProvider(FileDialogFilter dialogFilter, Func import, Action export) + { + return AddProvider(new InternalImportProvider(dialogFilter, import, export)); + } + + /// + /// Translates coordinate unit system into our coordinate system + /// + /// Position/Origin of the Object(Cube). + /// The Size of the Object(Cube). + /// Describes what axises need translation. + /// The translated position + protected static Vector3 TransformSpace(Vector3 origin, Vector3 size, Vector3 translationUnit) + { + // The translation unit describes what axises need to be swapped + // Example: + // translation unit = (1, 0, 0) => This translation unit will ONLY swap the X axis + translationUnit = Vector3.Clamp(translationUnit, Vector3.Zero, Vector3.One); + // To better understand see: + // https://sharplab.io/#v2:C4LgTgrgdgNAJiA1AHwAICYCMBYAUKgBgAJVMA6AOQgFsBTMASwGMBnAbj1QGYT0iBhIgG88RMb3SjxI3OLlEAbgEMwRBlAAOEYEQC8RKLQDuRAGq0mwAPZguACkwwijogQCUHWfLHLVtAB4aFsC0cHoGxmbBNvYAtC7xTpgeUt6+RGC0LOEAKmBKUCwAYjbU/FY2cOpKISx26lrAKV7epACcdpkszd5i7Z1ZevoBQZahPeIAvqlEM9wkmABsUZYxRHkFxaXlldW1duartmqa2m4zMr2KKhmD+ofWtmT8ADZK1Br1p8BODzFkAC16FZftEngB5QwTbxdIgAKn06E8V1hsXuYK4ZEhtGRvVQAHYiLEurixNNcJMgA + Vector3 transformUnit = -((translationUnit * 2) - Vector3.One); + + Vector3 pos = origin; + // The next line essentialy does uses the fomular below just on all axis. + // x = -(pos.x + size.x) + pos *= transformUnit; + pos -= size * translationUnit; + return pos; + } + + private bool HasProvider(string filename) + { + string fileExtension = Path.GetExtension(filename); + return _importProviders.ContainsKey(fileExtension) && _importProviders[fileExtension] is not null; + } + + private IModelImportProvider GetProvider(string filename) + { + string fileExtension = Path.GetExtension(filename); + return _importProviders.ContainsKey(fileExtension) ? _importProviders[fileExtension] : null; + } + } +} diff --git a/PckStuido.ModelSupport/PckStuido.ModelSupport.csproj b/PckStuido.ModelSupport/PckStuido.ModelSupport.csproj new file mode 100644 index 00000000..d7697c87 --- /dev/null +++ b/PckStuido.ModelSupport/PckStuido.ModelSupport.csproj @@ -0,0 +1,96 @@ + + + + + Debug + AnyCPU + {43BCACD7-5405-4499-9B45-E1435AC03C26} + Library + NDEBUG + Properties + PckStuido.ModelSupport + PckStuido.ModelSupport + v4.8 + 12 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + + 13.0.3 + + + + + {345eabed-f0d1-4d04-b409-babdef747352} + PckStudio.Core + + + {693aebc1-293d-4df0-bcae-26a1099fe7bb} + OMI Filetype Library + + + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + + + + + + \ No newline at end of file diff --git a/PckStuido.ModelSupport/Properties/AssemblyInfo.cs b/PckStuido.ModelSupport/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..4e98a15b --- /dev/null +++ b/PckStuido.ModelSupport/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PckStuido.ModelSupport")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PckStuido.ModelSupport")] +[assembly: AssemblyCopyright("Copyright © 2025")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("43bcacd7-5405-4499-9b45-e1435ac03c26")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PckStuido.ModelSupport/Properties/Resources.Designer.cs b/PckStuido.ModelSupport/Properties/Resources.Designer.cs new file mode 100644 index 00000000..b98cf665 --- /dev/null +++ b/PckStuido.ModelSupport/Properties/Resources.Designer.cs @@ -0,0 +1,120 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PckStuido.ModelSupport.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PckStuido.ModelSupport.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to { + /// "bat": { + /// "textureSize": { "X": 64, "Y": 64 }, + /// "parts": [ + /// { + /// "name": "head", + /// "boxes": [ + /// { "pos": { "X": -3, "Y": -3, "Z": -3 }, "size": { "X": 6, "Y": 6, "Z": 6 }, "uv": { "X": 0, "Y": 0 } } + /// ] + /// }, + /// { + /// "name": "body", + /// "boxes": [ + /// { "pos": { "X": -3, "Y": 4, "Z": -3 }, "size": { "X": 6, "Y": 12, "Z": 6 }, "uv": { "X": 0, "Y": 16 } }, + /// { "pos": { "X": -5, "Y": 16, "Z": 0 }, "size": { "X": 10, "Y": 6, "Z": [rest of string was truncated]";. + /// + internal static string defaultModels { + get { + return ResourceManager.GetString("defaultModels", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "bat": { + /// "textureLocations": [ + /// "res/mob/bat" + /// ], + /// "materialName": "bat", + /// "parts": [ + /// { + /// "name": "head", + /// "children": [ + /// { "name": "rightEar" }, + /// { "name": "leftEar" } + /// ] + /// }, + /// { + /// "name": "body", + /// "children": [ + /// { + /// "name": "rightWing", + /// "children": [ + /// { "name": "rightWingTip" } + /// ] + /// }, + /// { + /// "name": "leftWing", + /// [rest of string was truncated]";. + /// + internal static string modelMetaData { + get { + return ResourceManager.GetString("modelMetaData", resourceCulture); + } + } + } +} diff --git a/PckStuido.ModelSupport/Properties/Resources.resx b/PckStuido.ModelSupport/Properties/Resources.resx new file mode 100644 index 00000000..b1909c61 --- /dev/null +++ b/PckStuido.ModelSupport/Properties/Resources.resx @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\defaultModels.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + + ..\Resources\modelMetaData.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1 + + \ No newline at end of file diff --git a/PckStuido.ModelSupport/Resources/defaultModels.json b/PckStuido.ModelSupport/Resources/defaultModels.json new file mode 100644 index 00000000..c77963e9 --- /dev/null +++ b/PckStuido.ModelSupport/Resources/defaultModels.json @@ -0,0 +1,619 @@ +{ + "bat": { + "textureSize": { "X": 64, "Y": 64 }, + "parts": [ + { + "name": "head", + "boxes": [ + { "pos": { "X": -3, "Y": -3, "Z": -3 }, "size": { "X": 6, "Y": 6, "Z": 6 }, "uv": { "X": 0, "Y": 0 } } + ] + }, + { + "name": "body", + "boxes": [ + { "pos": { "X": -3, "Y": 4, "Z": -3 }, "size": { "X": 6, "Y": 12, "Z": 6 }, "uv": { "X": 0, "Y": 16 } }, + { "pos": { "X": -5, "Y": 16, "Z": 0 }, "size": { "X": 10, "Y": 6, "Z": 1 }, "uv": { "X": 0, "Y": 34 } } + ] + }, + { + "name": "rightEar", + "boxes": [ + { "pos": { "X": -4, "Y": -6, "Z": -2 }, "size": { "X": 3, "Y": 4, "Z": 1 }, "uv": { "X": 24, "Y": 0 } } + ] + }, + { + "name": "leftEar", + "boxes": [ + { "pos": { "X": 1, "Y": -6, "Z": -2 }, "size": { "X": 3, "Y": 4, "Z": 1 }, "uv": { "X": 24, "Y": 0 }, "mirror": true } + ] + }, + { + "name": "rightWing", + "boxes": [ + { "pos": { "X": -12, "Y": 1, "Z": 1.5 }, "size": { "X": 10, "Y": 16, "Z": 1 }, "uv": { "X": 42, "Y": 0 } } + ] + }, + { + "name": "rightWingTip", + "translation": { "X": -12, "Y": 1, "Z": 1.5 }, + "boxes": [ + { "pos": { "X": -8, "Y": 1, "Z": 0 }, "size": { "X": 8, "Y": 12, "Z": 1 }, "uv": { "X": 24, "Y": 16 } } + ] + }, + { + "name": "leftWing", + "boxes": [ + { "pos": { "X": 2, "Y": 1, "Z": 1.5 }, "size": { "X": 10, "Y": 16, "Z": 1 }, "uv": { "X": 42, "Y": 0 }, "mirror": true } + ] + }, + { + "name": "leftWingTip", + "translation": { "X": 12, "Y": 1, "Z": 1.5 }, + "boxes": [ + { "pos": { "X": 0, "Y": 1, "Z": 0 }, "size": { "X": 8, "Y": 12, "Z": 1 }, "uv": { "X": 24, "Y": 16 }, "mirror": true } + ] + } + ] + }, + "trident": { + "textureSize": { "X": 32, "Y": 32 }, + "parts": [ + { + "name": "pole", + "boxes": [ + { "pos": { "X": -0.5, "Y": -4, "Z": -0.5 }, "size": { "X": 1, "Y": 31, "Z": 1 }, "uv": { "X": 0, "Y": 0 } }, + { "pos": { "X": -1.5, "Y": 0, "Z": -0.5 }, "size": { "X": 3, "Y": 2, "Z": 1 }, "uv": { "X": 4, "Y": 0 } }, + { "pos": { "X": -2.5, "Y": -3, "Z": -0.5 }, "size": { "X": 1, "Y": 4, "Z": 1 }, "uv": { "X": 4, "Y": 3 } }, + { "pos": { "X": 1.5, "Y": -3, "Z": -0.5 }, "size": { "X": 1, "Y": 4, "Z": 1 }, "uv": { "X": 4, "Y": 3 }, "mirror": true } + ] + } + ] + }, + "irongolem": { + "textureSize": { "X": 128, "Y": 128 }, + "parts": [ + { + "name": "head", + "translation": { "X": 0, "Y": 0, "Z": -2 }, + "boxes": [ + { "pos": { "X": -4, "Y": -12, "Z": -5.5 }, "size": { "X": 8, "Y": 10, "Z": 8 }, "uv": { "X": 0, "Y": 0 } }, + { "pos": { "X": -1, "Y": -5, "Z": -7.5 }, "size": { "X": 2, "Y": 4, "Z": 2 }, "uv": { "X": 24, "Y": 0 } } + ] + }, + { + "name": "body", + "boxes": [ + { "pos": { "X": -9, "Y": -2, "Z": -6 }, "size": { "X": 18, "Y": 12, "Z": 11 }, "uv": { "X": 0, "Y": 40 } }, + { "pos": { "X": -4.5, "Y": 10, "Z": -3 }, "size": { "X": 9, "Y": 5, "Z": 6 }, "uv": { "X": 0, "Y": 70 }, "inflate": 0.5 } + ] + }, + { + "name": "arm0", + "translation": { "X": 0, "Y": 0, "Z": 0 }, + "boxes": [ + { "pos": { "X": -13, "Y": -2.5, "Z": -3 }, "size": { "X": 4, "Y": 30, "Z": 6 }, "uv": { "X": 60, "Y": 58 } } + ] + }, + { + "name": "arm1", + "translation": { "X": 0, "Y": 0, "Z": 0 }, + "boxes": [ + { "pos": { "X": 9, "Y": -2.5, "Z": -3 }, "size": { "X": 4, "Y": 30, "Z": 6 }, "uv": { "X": 60, "Y": 21 } } + ] + }, + { + "name": "leg0", + "translation": { "X": -4, "Y": 18, "Z": 0 }, + "boxes": [ + { "pos": { "X": -3.5, "Y": -3, "Z": -3 }, "size": { "X": 6, "Y": 16, "Z": 5 }, "uv": { "X": 37, "Y": 0 } } + ] + }, + { + "name": "leg1", + "translation": { "X": 5, "Y": 18, "Z": 0 }, + "boxes": [ + { "pos": { "X": -3.5, "Y": -3, "Z": -3 }, "size": { "X": 6, "Y": 16, "Z": 5 }, "uv": { "X": 60, "Y": 0 }, "mirror": true } + ] + } + ] + }, + "dolphin": { + "textureSize": { "X": 64, "Y": 64 }, + "parts": [ + { + "name": "head", + "boxes": [ + { "pos": { "X": -4, "Y": -7, "Z": -6 }, "size": { "X": 8, "Y": 7, "Z": 6 }, "uv": { "X": 0, "Y": 0 } } + ] + }, + { + "name": "nose", + "translation": { "X": 0, "Y": 0, "Z": -10 }, + "boxes": [ + { "pos": { "X": -1, "Y": -2, "Z": 0 }, "size": { "X": 2, "Y": 2, "Z": 4 }, "uv": { "X": 0, "Y": 13 } } + ] + }, + { + "name": "body", + "translation": { "X": 0, "Y": 0, "Z": 0 }, + "rotation": { "X": 0, "Y": 0, "Z": 0 }, + "boxes": [ + { "pos": { "X": -4, "Y": -7, "Z": 0 }, "size": { "X": 8, "Y": 7, "Z": 13 }, "uv": { "X": 0, "Y": 13 } } + ] + }, + { + "name": "back_fin", + "translation": { "X": 0, "Y": -7, "Z": 7 }, + "boxes": [ + { "pos": { "X": -0.5, "Y": -5, "Z": -1 }, "size": { "X": 1, "Y": 5, "Z": 4 }, "uv": { "X": 29, "Y": 0 } } + ] + }, + { + "name": "left_fin", + "translation": { "X": 3, "Y": -1, "Z": 2 }, + "boxes": [ + { "pos": { "X": 0, "Y": -1, "Z": -1 }, "size": { "X": 8, "Y": 1, "Z": 4 }, "uv": { "X": 40, "Y": 0 } } + ] + }, + { + "name": "right_fin", + "translation": { "X": -3, "Y": -1, "Z": 2 }, + "boxes": [ + { "pos": { "X": -8, "Y": -1, "Z": -1 }, "size": { "X": 8, "Y": 1, "Z": 4 }, "uv": { "X": 40, "Y": 6 } } + ] + }, + { + "name": "tail", + "translation": { "X": 0, "Y": -2.5, "Z": 14 }, + "boxes": [ + { "pos": { "X": -2, "Y": -2.5, "Z": -1 }, "size": { "X": 4, "Y": 5, "Z": 11 }, "uv": { "X": 0, "Y": 33 } } + ] + }, + { + "name": "tail_fin", + "translation": { "X": 0, "Y": 0, "Z": 24 }, + "boxes": [ + { "pos": { "X": -5, "Y": -2.5, "Z": -1 }, "size": { "X": 10, "Y": 1, "Z": 6 }, "uv": { "X": 0, "Y": 49 } } + ] + } + ] + }, + "creeper_head": { + "textureSize": { "X": 64, "Y": 32 }, + "parts": [ + { + "name": "head", + "boxes": [ + { "pos": { "X": -4, "Y": -8, "Z": -4 }, "size": { "X": 8, "Y": 8, "Z": 8 }, "uv": { "X": 0, "Y": 0 } } + ] + } + ] + }, + "creeper": { + "textureSize": { "X": 64, "Y": 32 }, + "parts": [ + { + "name": "head", + "translation": { "X": 0, "Y": 6, "Z": 0 }, + "boxes": [ + { "pos": { "X": -4, "Y": -8, "Z": -4 }, "size": { "X": 8, "Y": 8, "Z": 8 }, "uv": { "X": 0, "Y": 0 } } + ] + }, + { + "name": "body", + "translation": { "X": 0, "Y": 6, "Z": 0 }, + "boxes": [ + { "pos": { "X": -4, "Y": 0, "Z": -2 }, "size": { "X": 8, "Y": 12, "Z": 4 }, "uv": { "X": 16, "Y": 16 } } + ] + }, + { + "name": "leg0", + "translation": { "X": -2, "Y": 18, "Z": 4 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 6, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + }, + { + "name": "leg1", + "translation": { "X": 2, "Y": 18, "Z": 4 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 6, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + }, + { + "name": "leg2", + "translation": { "X": -2, "Y": 18, "Z": -4 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 6, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + }, + { + "name": "leg3", + "translation": { "X": 2, "Y": 18, "Z": -4 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 6, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + } + ] + }, + "boat": { + "textureSize": { "X": 128, "Y": 64 }, + "parts": [ + { + "name": "bottom", + "translation": { "X": 0, "Y": 3, "Z": 1 }, + "rotation": { "X": 90, "Y": 0, "Z": 0 }, + "boxes": [ + { "pos": { "X": -14, "Y": -9, "Z": -3 }, "size": { "X": 28, "Y": 16, "Z": 3 }, "uv": { "X": 0, "Y": 0 } } + ] + }, + { + "name": "front", + "translation": { "X": 15, "Y": 4, "Z": 0 }, + "rotation": { "X": 0, "Y": 90, "Z": 0 }, + "boxes": [ + { "pos": { "X": -8, "Y": -7, "Z": -1 }, "size": { "X": 16, "Y": 6, "Z": 2 }, "uv": { "X": 0, "Y": 27 } } + ] + }, + { + "name": "back", + "translation": { "X": -15, "Y": 4, "Z": 4 }, + "rotation": { "X": 0, "Y": 270, "Z": 0 }, + "boxes": [ + { "pos": { "X": -13, "Y": -7, "Z": -1 }, "size": { "X": 18, "Y": 6, "Z": 2 }, "uv": { "X": 0, "Y": 19 } } + ] + }, + { + "name": "left", + "translation": { "X": 0, "Y": 4, "Z": 9 }, + "boxes": [ + { "pos": { "X": -14, "Y": -7, "Z": -1 }, "size": { "X": 28, "Y": 6, "Z": 2 }, "uv": { "X": 0, "Y": 43 } } + ] + }, + { + "name": "right", + "translation": { "X": 0, "Y": 4, "Z": -9 }, + "rotation": { "X": 0, "Y": 180, "Z": 0 }, + "boxes": [ + { "pos": { "X": -14, "Y": -7, "Z": -1 }, "size": { "X": 28, "Y": 6, "Z": 2 }, "uv": { "X": 0, "Y": 35 } } + ] + }, + { + "name": "paddle_left", + "translation": { "X": 3, "Y": -5, "Z": 9 }, + "rotation": { "X": 0, "Y": 0, "Z": 11.25 }, + "boxes": [ + { "pos": { "X": -1, "Y": 0, "Z": -5 }, "size": { "X": 2, "Y": 2, "Z": 18 }, "uv": { "X": 62, "Y": 0 } }, + { "pos": { "X": -1.001, "Y": -3, "Z": 8 }, "size": { "X": 1, "Y": 6, "Z": 7 }, "uv": { "X": 62, "Y": 0 } } + ] + }, + { + "name": "paddle_right", + "translation": { "X": 3, "Y": -5, "Z": -9 }, + "rotation": { "X": 0, "Y": 180, "Z": 11.25 }, + "boxes": [ + { "pos": { "X": -1, "Y": 0, "Z": -5 }, "size": { "X": 2, "Y": 2, "Z": 18 }, "uv": { "X": 62, "Y": 20 } }, + { "pos": { "X": 0.001, "Y": -3, "Z": 8 }, "size": { "X": 1, "Y": 6, "Z": 7 }, "uv": { "X": 62, "Y": 20 } } + ] + } + ] + }, + "bed":{ + "textureSize": { "X": 64, "Y": 128 }, + "parts": [ + { + "name": "bed", + "boxes": [ + { "pos": { "X": 0, "Y": 0, "Z": 0 }, "size": { "X": 16, "Y": 32, "Z": 6 }, "uv": { "X": 0, "Y": 0 } }, + { "pos": { "X": 3, "Y": 31, "Z": 6 }, "size": { "X": 10, "Y": 1, "Z": 3 }, "uv": { "X": 38, "Y": 2 } }, + { "pos": { "X": 3, "Y": 0, "Z": 6 }, "size": { "X": 10, "Y": 1, "Z": 3 }, "uv": { "X": 38, "Y": 38 } }, + { "pos": { "X": 15, "Y": 3, "Z": 6 }, "size": { "X": 1, "Y": 26, "Z": 3 }, "uv": { "X": 52, "Y": 6 } }, + { "pos": { "X": 0, "Y": 3, "Z": 6 }, "size": { "X": 1, "Y": 26, "Z": 3 }, "uv": { "X": 44, "Y": 6 } } + ] + }, + { + "name": "leg0", + "boxes": [ + { "pos": { "X": 0, "Y": 29, "Z": 6 }, "size": { "X": 3, "Y": 3, "Z": 3 }, "uv": { "X": 0, "Y": 44 } } + ] + }, + { + "name": "leg1", + "boxes": [ + { "pos": { "X": 13, "Y": 29, "Z": 6 }, "size": { "X": 3, "Y": 3, "Z": 3 }, "uv": { "X": 12, "Y": 44 } } + ] + }, + { + "name": "leg2", + "boxes": [ + { "pos": { "X": 0, "Y": 0, "Z": 6 }, "size": { "X": 3, "Y": 3, "Z": 3 }, "uv": { "X": 0, "Y": 38 } } + ] + }, + { + "name": "leg3", + "boxes": [ + { "pos": { "X": 13, "Y": 0, "Z": 6 }, "size": { "X": 3, "Y": 3, "Z": 3 }, "uv": { "X": 12, "Y": 38 } } + ] + } + ] + }, + "chicken": { + "textureSize": { "X": 64, "Y": 32 }, + "parts": [ + { + "name": "head", + "translation": { "X": 0, "Y": 15, "Z": -4 }, + "boxes": [ + { "pos": { "X": -2, "Y": -6, "Z": -2 }, "size": { "X": 4, "Y": 6, "Z": 3 }, "uv": { "X": 0, "Y": 0 } } + ] + }, + { + "name": "beak", + "translation": { "X": 0, "Y": 15, "Z": -4 }, + "boxes": [ + { "pos": { "X": -2, "Y": -4, "Z": -4 }, "size": { "X": 4, "Y": 2, "Z": 2 }, "uv": { "X": 14, "Y": 0 } } + ] + }, + { + "name": "comb", + "translation": { "X": 0, "Y": 15, "Z": -4 }, + "boxes": [ + { "pos": { "X": -1, "Y": -2, "Z": -3 }, "size": { "X": 2, "Y": 2, "Z": 2 }, "uv": { "X": 14, "Y": 4 } } + ] + }, + { + "name": "body", + "translation": { "X": 0, "Y": 16, "Z": 0 }, + "boxes": [ + { "pos": { "X": -3, "Y": -4, "Z": -3 }, "size": { "X": 6, "Y": 8, "Z": 6 }, "uv": { "X": 0, "Y": 9 } } + ] + }, + { + "name": "leg0", + "translation": { "X": -2, "Y": 19, "Z": 1 }, + "boxes": [ + { "pos": { "X": -1, "Y": 0, "Z": -3 }, "size": { "X": 3, "Y": 5, "Z": 3 }, "uv": { "X": 26, "Y": 0 } } + ] + }, + { + "name": "leg1", + "translation": { "X": 1, "Y": 19, "Z": 1 }, + "boxes": [ + { "pos": { "X": -1, "Y": 0, "Z": -3 }, "size": { "X": 3, "Y": 5, "Z": 3 }, "uv": { "X": 26, "Y": 0 } } + ] + }, + { + "name": "wing0", + "translation": { "X": -4, "Y": 13, "Z": 0 }, + "boxes": [ + { "pos": { "X": 0, "Y": 0, "Z": -3 }, "size": { "X": 1, "Y": 4, "Z": 6 }, "uv": { "X": 24, "Y": 13 } } + ] + }, + { + "name": "wing1", + "translation": { "X": 4, "Y": 13, "Z": 0 }, + "boxes": [ + { "pos": { "X": -1, "Y": 0, "Z": -3 }, "size": { "X": 1, "Y": 4, "Z": 6 }, "uv": { "X": 24, "Y": 13 } } + ] + } + ] + }, + "cow": { + "textureSize": { "X": 64, "Y": 32 }, + "parts": [ + { + "name": "head", + "translation": { "X": 0, "Y": 4, "Z": -8 }, + "boxes": [ + { "pos": { "X": -4, "Y": -4, "Z": -6 }, "size": { "X": 8, "Y": 8, "Z": 6 }, "uv": { "X": 0, "Y": 0 } }, + { "pos": { "X": -5, "Y": -5, "Z": -4 }, "size": { "X": 1, "Y": 3, "Z": 1 }, "uv": { "X": 22, "Y": 0 } }, + { "pos": { "X": 4, "Y": -5, "Z": -4 }, "size": { "X": 1, "Y": 3, "Z": 1 }, "uv": { "X": 22, "Y": 0 } } + ] + }, + { + "name": "body", + "translation": { "X": 0, "Y": 5, "Z": 2 }, + "rotation": { "X": 90, "Y": 0, "Z": 0 }, + "boxes": [ + { "pos": { "X": -6, "Y": -10, "Z": -7 }, "size": { "X": 12, "Y": 18, "Z": 10 }, "uv": { "X": 18, "Y": 4 } }, + { "pos": { "X": -2, "Y": 2, "Z": -8 }, "size": { "X": 4, "Y": 6, "Z": 1 }, "uv": { "X": 52, "Y": 0 } } + ] + }, + { + "name": "leg0", + "translation": { "X": -4, "Y": 12, "Z": 7 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 12, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + }, + { + "name": "leg1", + "translation": { "X": 4, "Y": 12, "Z": 7 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 12, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + }, + { + "name": "leg2", + "translation": { "X": -4, "Y": 12, "Z": -6 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 12, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + }, + { + "name": "leg3", + "translation": { "X": 4, "Y": 12, "Z": -6 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 12, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + } + ] + }, + "mooshroom": { + "textureSize": { "X": 64, "Y": 32 }, + "parts": [ + { + "name": "head", + "translation": { "X": 0, "Y": 4, "Z": -8 }, + "boxes": [ + { "pos": { "X": -4, "Y": -4, "Z": -6 }, "size": { "X": 8, "Y": 8, "Z": 6 }, "uv": { "X": 0, "Y": 0 } }, + { "pos": { "X": -5, "Y": -5, "Z": -4 }, "size": { "X": 1, "Y": 3, "Z": 1 }, "uv": { "X": 22, "Y": 0 } }, + { "pos": { "X": 4, "Y": -5, "Z": -4 }, "size": { "X": 1, "Y": 3, "Z": 1 }, "uv": { "X": 22, "Y": 0 } } + ] + }, + { + "name": "body", + "translation": { "X": 0, "Y": 5, "Z": 2 }, + "rotation": { "X": 90, "Y": 0, "Z": 0 }, + "boxes": [ + { "pos": { "X": -6, "Y": -10, "Z": -7 }, "size": { "X": 12, "Y": 18, "Z": 10 }, "uv": { "X": 18, "Y": 4 } }, + { "pos": { "X": -2, "Y": 2, "Z": -8 }, "size": { "X": 4, "Y": 6, "Z": 1 }, "uv": { "X": 52, "Y": 0 } } + ] + }, + { + "name": "leg0", + "translation": { "X": -4, "Y": 12, "Z": 7 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 12, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + }, + { + "name": "leg1", + "translation": { "X": 4, "Y": 12, "Z": 7 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 12, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + }, + { + "name": "leg2", + "translation": { "X": -4, "Y": 12, "Z": -6 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 12, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + }, + { + "name": "leg3", + "translation": { "X": 4, "Y": 12, "Z": -6 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 12, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + } + ] + }, + "dragon_head": { + "textureSize": { "X": 256, "Y": 256 }, + "parts": [ + { + "name": "head", + "boxes": [ + // upperlip + { "pos": { "X": -6, "Y": -1, "Z": -24 }, "size": { "X": 12, "Y": 5, "Z": 16 }, "uv": { "X": 176, "Y": 44 } }, + // upperhead + { "pos": { "X": -8, "Y": -8, "Z": -10 }, "size": { "X": 16, "Y": 16, "Z": 16 }, "uv": { "X": 112, "Y": 30 } }, + // scale + { "pos": { "X": 3, "Y": -12, "Z": -4 }, "size": { "X": 2, "Y": 4, "Z": 6 }, "uv": { "X": 0, "Y": 0 } }, + { "pos": { "X": -5, "Y": -12, "Z": -4 }, "size": { "X": 2, "Y": 4, "Z": 6 }, "uv": { "X": 0, "Y": 0 }, "mirror": true }, + // nostril + { "pos": { "X": 3, "Y": -3, "Z": -22 }, "size": { "X": 2, "Y": 2, "Z": 4 }, "uv": { "X": 112, "Y": 0 } }, + { "pos": { "X": -5, "Y": -3, "Z": -22 }, "size": { "X": 2, "Y": 2, "Z": 4 }, "uv": { "X": 112, "Y": 0 }, "mirror": true }, + ] + }, + { + "name": "jaw", + "translation": { "X": 0, "Y": 4, "Z": -8 }, + "boxes": [ + { "pos": { "X": -6, "Y": 0, "Z": -16 }, "size": { "X": 12, "Y": 4, "Z": 16 }, "uv": { "X": 176, "Y": 65 } } + ] + } + ] + }, + "pig": { + "textureSize": { "X": 64, "Y": 32 }, + "parts": [ + { + "name": "head", + "translation": { "X": 0, "Y": 12, "Z": -6 }, + "boxes": [ + { "pos": { "X": -4, "Y": -4, "Z": -8 }, "size": { "X": 8, "Y": 8, "Z": 8 }, "uv": { "X": 0, "Y": 0 } }, + { "pos": { "X": -2, "Y": 0, "Z": -9 }, "size": { "X": 4, "Y": 3, "Z": 1 }, "uv": { "X": 16, "Y": 16 } } + ] + }, + { + "name": "body", + "translation": { "X": 0, "Y": 11, "Z": 2 }, + "rotation": { "X": 90, "Y": 0, "Z": 0 }, + "boxes": [ + { "pos": { "X": -5, "Y": -10, "Z": -7 }, "size": { "X": 10, "Y": 16, "Z": 8 }, "uv": { "X": 28, "Y": 8 } } + ] + }, + { + "name": "leg0", + "translation": { "X": -3, "Y": 18, "Z": 7 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 6, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + }, + { + "name": "leg1", + "translation": { "X": 3, "Y": 18, "Z": 7 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 6, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + }, + { + "name": "leg2", + "translation": { "X": -3, "Y": 18, "Z": -5 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 6, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + }, + { + "name": "leg3", + "translation": { "X": 3, "Y": 18, "Z": -5 }, + "boxes": [ + { "pos": { "X": -2, "Y": 0, "Z": -2 }, "size": { "X": 4, "Y": 6, "Z": 4 }, "uv": { "X": 0, "Y": 16 } } + ] + } + ] + }, + "snowgolem": { + "textureSize": { "X": 64, "Y": 64 }, + "parts": [ + { + "name": "head", + "translation": { "X": 0, "Y": 4, "Z": 0 }, + "boxes": [ + { "pos": { "X": -4, "Y": -8, "Z": -4 }, "size": { "X": 8, "Y": 8, "Z": 8 }, "uv": { "X": 0, "Y": 0 }, "inflate": -0.5 } + ] + }, + { + "name": "arm1", + "translation": { "X": 0, "Y": 6, "Z": 0 }, + "boxes": [ + { "pos": { "X": -1, "Y": 0, "Z": -1 }, "size": { "X": 12, "Y": 2, "Z": 2 }, "uv": { "X": 32, "Y": 0 }, "inflate": -0.5 } + ] + }, + { + "name": "arm2", + "translation": { "X": 0, "Y": 6, "Z": 0 }, + "boxes": [ + { "pos": { "X": -1, "Y": 0, "Z": -1 }, "size": { "X": 12, "Y": 2, "Z": 2 }, "uv": { "X": 32, "Y": 0 }, "inflate": -0.5 } + ] + }, + { + "name": "piece1", + "translation": { "X": 0, "Y": 13, "Z": 0 }, + "boxes": [ + { "pos": { "X": -5, "Y": -10, "Z": -5 }, "size": { "X": 10, "Y": 10, "Z": 10 }, "uv": { "X": 0, "Y": 16 }, "inflate": -0.5 } + ] + }, + { + "name": "piece2", + "translation": { "X": 0, "Y": 24, "Z": 0 }, + "boxes": [ + { "pos": { "X": -6, "Y": -12, "Z": -6 }, "size": { "X": 12, "Y": 12, "Z": 12 }, "uv": { "X": 0, "Y": 36 }, "inflate": -0.5 } + ] + } + ] + } +} \ No newline at end of file diff --git a/PckStuido.ModelSupport/Resources/modelMetaData.json b/PckStuido.ModelSupport/Resources/modelMetaData.json new file mode 100644 index 00000000..9be05f36 --- /dev/null +++ b/PckStuido.ModelSupport/Resources/modelMetaData.json @@ -0,0 +1,739 @@ +{ + "bat": { + "textureLocations": [ + "res/mob/bat" + ], + "materialName": "bat", + "parts": [ + { + "name": "head", + "children": [ + { "name": "rightEar" }, + { "name": "leftEar" } + ] + }, + { + "name": "body", + "children": [ + { + "name": "rightWing", + "children": [ + { "name": "rightWingTip" } + ] + }, + { + "name": "leftWing", + "children": [ + { "name": "leftWingTip" } + ] + } + ] + } + ] + }, + "bed": { + "textureLocations": [ + "res/item/bed" + ], + "uv_offsets": [ {"X": 0, "Y": 64} ] + }, + "blaze": { + "textureLocations": [ + "res/mob/fire" + ], + "materialName": "blaze_head" + }, + "boat": { + "textureLocations": [ + "res/item/boat/boat_acacia", + "res/item/boat/boat_birch", + "res/item/boat/boat_darkoak", + "res/item/boat/boat_jungle", + "res/item/boat/boat_oak", + "res/item/boat/boat_spruce" + ] + }, + "chicken": { + "textureLocations": [ + "res/mob/chicken" + ] + }, + "cow": { + "textureLocations": [ + "res/mob/cow" + ] + }, + "creeper": { + "textureLocations": [ + "res/mob/creeper" + ] + }, + "creeper_head": { + "textureLocations": [ + "res/mob/creeper" + ] + }, + "dolphin": { + "textureLocations": [ + "res/mob/dolphin" + ], + "parts": [ + { + "name": "body", + "children": [ + { + "name": "head", + "children": [ { "name": "nose" } ] + }, + { + "name": "tail", + "children": [ { "name": "tail_fin" } ] + }, + { "name": "right_fin" }, + { "name": "left_fin" }, + { "name": "back_fin" } + ] + } + ] + }, + "dragon": { + "textureLocations": [ + "res/mob/enderdragon/ender" + ], + "materialName": "ender_dragon", + "parts": [ + { "name": "body" }, + // only needs to be inside when neck 1-5 aren't present + { "name": "neck" }, + + // neck 1-5 & tail 1-12 are not required to be inside the model + { "name": "neck1" }, + { "name": "neck2" }, + { "name": "neck3" }, + { "name": "neck4" }, + { "name": "neck5" }, + + { "name": "tail1" }, + { "name": "tail2" }, + { "name": "tail3" }, + { "name": "tail4" }, + { "name": "tail5" }, + { "name": "tail6" }, + { "name": "tail7" }, + { "name": "tail8" }, + { "name": "tail9" }, + { "name": "tail10" }, + { "name": "tail11" }, + { "name": "tail12" }, + + { + "name": "head", + "children": [ { "name": "jaw" } ] + }, + { + "name": "wing", + "children": [ { "name": "wingtip" } ] + }, + { + "name": "wing1", + "children": [ { "name": "wingtip1" } ] + }, + { + "name": "rearleg", + "children": [ + { + "name": "rearlegtip", + "children": [ { "name": "rearfoot" } ] + } + ] + }, + { + "name": "rearleg1", + "children": [ + { + "name": "rearlegtip1", + "children": [ { "name": "rearfoot1" } ] + } + ] + }, + { + "name": "frontleg", + "children": [ + { + "name": "frontlegtip", + "children": [ { "name": "frontfoot" } ] + } + ] + }, + { + "name": "frontleg1", + "children": [ + { + "name": "frontlegtip1", + "children": [ { "name": "frontfoot1" } ] + } + ] + } + ] + }, + "dragon_head": { + "textureLocations": [ + "res/mob/enderdragon/ender" + ], + "parts": [ + { + "name": "head", + "children": [ { "name": "jaw" } ] + } + ] + }, + "enderman": { + "textureLocations": [ + "res/mob/enderman" + ], + "materialName": "enderman" // "enderman_invisible" also valid + }, + "ghast": { + "textureLocations": [ + "res/mob/ghast", + "res/mob/ghast_fire" + ], + "materialName": "ghast" + }, + "guardian": { + "textureLocations": [ + "res/mob/guardian", + "res/mob/guardian_elder" + ], + "materialName": "guardian", + "parts": [ + { + "name": "head", + "children": [ + { "name": "eye" }, + { + "name": "tailpart0", + "children": [ + { + "name": "tailpart1", + "children": [ { "name": "tailpart2" } ] + } + ] + } + ] + } + ] + }, + "irongolem": { + "textureLocations": [ + "res/mob/villager_golem" + ], + "materialName": "iron_golem" + }, + "lavaslime": { + "textureLocations": [ + "res/mob/lava" + ], + "materialName": "magma_cube" + }, + "llama": { + "textureLocations": [ + "res/mob/llama/llama", + "res/mob/llama/llama_brown", + "res/mob/llama/llama_creamy", + "res/mob/llama/llama_gray", + "res/mob/llama/llama_white" + ] + }, + "llamaspit": { + "textureLocations": [ + "res/mob/llama/spit" + ] + }, + "minecart": { + "textureLocations": [ + "res/item/cart" + ] + }, + // the ocelot model is weird.. -miku + "ocelot": { + "textureLocations": [ + "res/mob/ozelot" + ] + }, + "parrot": { + "textureLocations": [ + "res/mob/parrot/parrot_blue", + "res/mob/parrot/parrot_green", + "res/mob/parrot/parrot_grey", + "res/mob/parrot/parrot_red_blue", + "res/mob/parrot/parrot_yellow_blue" + ], + "parts": [ + { + "name": "head", + "children": [ + { "name": "head2" }, + { "name": "beak1" }, + { "name": "beak2" }, + { "name": "feather" } + ] + }, + { "name": "body" }, + { "name": "tail" }, + { "name": "wing0" }, + { "name": "wing1" }, + { "name": "leg0" }, + { "name": "leg1" } + ] + }, + "phantom": { + "textureLocations": [ + "res/mob/phantom" + ], + "materialName": "phantom", // phantom_invisible is also valid + "parts": [ + { + "name": "body", + "children": [ + { "name": "head" }, + { + "name": "wing0", + "children": [ { "name": "wingtip0" } ] + }, + { + "name": "wing1", + "children": [ { "name": "wingtip1" } ] + }, + { + "name": "tail", + "children": [ { "name": "tailtip" } ] + } + ] + } + ] + }, + "pig": { + "textureLocations": [ + "res/mob/pig", + "res/mob/saddle" + ] + }, + "pigzombie": { + "textureLocations": [ + "res/mob/pigzombie" + ], + "materialName": "zombie_pigman" + }, + "polarbear": { + "textureLocations": [ + "res/mob/bear/polarbear" + ] + }, + "rabbit": { + "textureLocations": [ + "res/mob/rabbit/black", + "res/mob/rabbit/brown", + "res/mob/rabbit/caerbannog", + "res/mob/rabbit/gold", + "res/mob/rabbit/salt", + "res/mob/rabbit/toast", + "res/mob/rabbit/white", + "res/mob/rabbit/white_splotched" + ] + }, + "sheep": { + "textureLocations": [ + "res/mob/sheep", + "res/mob/sheep_fur" + ], + "materialName": "sheep" + }, + "sheep.sheared": { + "textureLocations": [ + "res/mob/sheep" + ], + "materialName": "sheep" + }, + "shulker": { + "textureLocations": [ + "res/mob/shulker/endergolem", + "res/mob/shulker/spark" + ], + "materialName": "shulker" + }, + "silverfish": { + "textureLocations": [ + "res/mob/silverfish" + ] + }, + "skeleton": { + "textureLocations": [ + "res/mob/skeleton" + ], + "materialName": "skeleton" + }, + "skeleton.stray": { + "textureLocations": [ + "res/mob/skeleton/stray" + ], + "materialName": "stray" + }, + "skeleton.wither": { + "textureLocations": [ + "res/mob/skeleton_wither" + ], + "materialName": "wither_skeleton" + }, + "slime": { + "textureLocations": [ + "res/mob/slime" + ] + }, + "slime.armor": { + "textureLocations": [ + "res/mob/slime" + ] + }, + "snowgolem": { + "textureLocations": [ + "res/mob/snowman" + ] + }, + "spider": { + "textureLocations": [ + "res/mob/spider", + "res/mob/cavespider" + ], + "materialName": "spider" // "spider_invisible" also valid + }, + "squid": { + "textureLocations": [ + "res/mob/squid" + ] + }, + "trident": { + "textureLocations": [ + "res/item/trident" + ] + }, + "turtle": { + "textureLocations": [ + "res/mob/sea_turtle" + ] + }, + "villager": { + "textureLocations": [ + "res/mob/villager/villager", + "res/mob/villager/butcher", + "res/mob/villager/farmer", + "res/mob/villager/librarian", + "res/mob/villager/priest", + "res/mob/villager/smith" + ] + }, + "villager.witch": { + "textureLocations": [ + "res/mob/witch" + ] + }, + "vex": { + "textureLocations": [ + "res/mob/illager/vex", + "res/mob/illager/vex_charging" + ] + }, + "evoker": { + "textureLocations": [ + "res/mob/illager/evoker" + ] + }, + "vindicator": { + "textureLocations": [ + "res/mob/illager/vindicator" + ] + }, + "witherBoss": { + "textureLocations": [ + "res/mob/wither/wither", + "res/mob/wither/wither_invulnerable" + ], + "materialName": "wither_boss" + }, + "wolf": { + "textureLocations": [ + "res/mob/wolf", + "res/mob/wolf_angry", + "res/mob/wolf_tame" + ], + "materialName": "wolf" + }, + "zombie": { + "textureLocations": [ + "res/mob/zombie" + ] + }, + "zombie.husk": { + "textureLocations": [ + "res/mob/zombie/husk" + ] + }, + "zombie.villager": { + "textureLocations": [ + "res/mob/zombie_villager/zombie_villager", + "res/mob/zombie_villager/zombie_butcher", + "res/mob/zombie_villager/zombie_farmer", + "res/mob/zombie_villager/zombie_librarian", + "res/mob/zombie_villager/zombie_priest", + "res/mob/zombie_villager/zombie_smith" + ] + }, + "horse.v2": { + // markings and armor not included + "textureLocations": [ + "res/mob/horse/donkey", + "res/mob/horse/horse_black", + "res/mob/horse/horse_brown", + "res/mob/horse/horse_chestnut", + "res/mob/horse/horse_creamy", + "res/mob/horse/horse_darkbrown", + "res/mob/horse/horse_gray", + "res/mob/horse/horse_skeleton", + "res/mob/horse/horse_white", + "res/mob/horse/horse_zombie", + "res/mob/horse/mule" + ], + "parts": [ + { + "name": "Neck", + "children": [ + { + "name": "Head", + "children": [ + { "name": "HeadSaddle" }, + { "name": "UMouth" }, + { "name": "Ear1" }, + { "name": "Ear2" }, + { "name": "MuleEarL" }, + { "name": "MuleEarR" }, + { "name": "SaddleMouthL" }, + { "name": "SaddleMouthR" } + ] + } + ] + }, + { + "name": "Body", + "children": [ + { "name": "TailA" }, + { "name": "Saddle" } + ] + }, + { "name": "Mane" }, + { "name": "Leg1A" }, + { "name": "Leg2A" }, + { "name": "Leg3A" }, + { "name": "Leg4A" }, + { "name": "Bag1" }, + { "name": "Bag2" }, + { "name": "SaddleMouthLine" }, + { "name": "SaddleMouthLineR" } + ] + }, + "cat": { + "textureLocations": [ + "res/mob/cat_black", + "res/mob/cat_red", + "res/mob/cat_siamese" + ] + }, + "zombie.drowned": { + "textureLocations": [ + "res/mob/zombie/drowned" + ], + "materialName": "drowned" + }, + "endermite": { + "textureLocations": [ + "res/mob/endermite" + ] + }, + "cod": { + "textureLocations": [ + "res/mob/fish/cod" + ] + }, + "pufferfish.small": { + "textureLocations": [ + "res/mob/fish/pufferfish" + ] + }, + "pufferfish.mid": { + "textureLocations": [ + "res/mob/fish/pufferfish" + ] + }, + "pufferfish.large": { + "textureLocations": [ + "res/mob/fish/pufferfish" + ] + }, + "salmon": { + "textureLocations": [ + "res/mob/fish/salmon" + ] + }, + "skeleton_head": { + "textureLocations": [ + "res/mob/skeleton" + ] + }, + "skeleton_wither_head": { + "textureLocations": [ + "res/mob/skeleton_wither" + ] + }, + "stray.armor": { + "textureLocations": [ + "res/mob/skeleton/stray_overlay" + ] + }, + "stray_armor": { + "textureLocations": [ + "res/mob/skeleton/stray_overlay" + ] + }, + "tropicalfish_a": { + "textureLocations": [ + "res/mob/fish/tropical_a", + "res/mob/fish/tropical_a_pattern_1", + "res/mob/fish/tropical_a_pattern_2", + "res/mob/fish/tropical_a_pattern_3", + "res/mob/fish/tropical_a_pattern_4", + "res/mob/fish/tropical_a_pattern_5", + "res/mob/fish/tropical_a_pattern_6" + ] + }, + "tropicalfish_b": { + "textureLocations": [ + "res/mob/fish/tropical_b", + "res/mob/fish/tropical_b_pattern_1", + "res/mob/fish/tropical_b_pattern_2", + "res/mob/fish/tropical_b_pattern_3", + "res/mob/fish/tropical_b_pattern_4", + "res/mob/fish/tropical_b_pattern_5", + "res/mob/fish/tropical_b_pattern_6" + ] + }, + "zombie_head": { + "textureLocations": [ + "res/mob/zombie" + ] + }, + "mooshroom": { + "textureLocations": [ + "res/mob/redcow" + ] + }, + "witherBoss.armor": { + "textureLocations": [ + "res/mob/wither/wither_armor" + ] + }, + + "villager_v2": { + "textureLocations": [ + "res/mob/villager/villagerBase1", + "res/mob/villager/villagerBase2", + "res/mob/villager/villagerBase3", + "res/mob/villager/villagerBase4", + "res/mob/villager/villagerBase5", + "res/mob/villager/villagerBase6", + + "res/mob/wandering_trader", + + "res/mob/villager/professions/armorer", + "res/mob/villager/professions/butcher", + "res/mob/villager/professions/cartographer", + "res/mob/villager/professions/cleric", + "res/mob/villager/professions/farmer", + "res/mob/villager/professions/fisherman", + "res/mob/villager/professions/fletcher", + "res/mob/villager/professions/leatherworker", + "res/mob/villager/professions/librarian", + "res/mob/villager/professions/nitwit", + "res/mob/villager/professions/shepherd", + "res/mob/villager/professions/stonemason", + "res/mob/villager/professions/toolsmith", + "res/mob/villager/professions/unskilled", + "res/mob/villager/professions/weaponsmith", + + "res/mob/villager/biomes/biome_desert", + "res/mob/villager/biomes/biome_jungle", + "res/mob/villager/biomes/biome_plains", + "res/mob/villager/biomes/biome_savanna", + "res/mob/villager/biomes/biome_snow", + "res/mob/villager/biomes/biome_swamp", + "res/mob/villager/biomes/biome_taiga", + + "res/mob/villager/levels/level_diamond", + "res/mob/villager/levels/level_gold", + "res/mob/villager/levels/level_iron" + ] + }, + "zombie.villager_v2": { + "textureLocations": [ + "res/mob/zombie_villager/zombie_villager", + "res/mob/zombie_villager/zombie_butcher", + "res/mob/zombie_villager/zombie_farmer", + "res/mob/zombie_villager/zombie_librarian", + "res/mob/zombie_villager/zombie_priest", + "res/mob/zombie_villager/zombie_smith", + + "res/mob/zombie_villager/biomes/biome-desert-zombie", + "res/mob/zombie_villager/biomes/biome-jungle-zombie", + "res/mob/zombie_villager/biomes/biome-plains-zombie", + "res/mob/zombie_villager/biomes/biome-savanna-zombie", + "res/mob/zombie_villager/biomes/biome-snow-zombie", + "res/mob/zombie_villager/biomes/biome-swamp-zombie", + "res/mob/zombie_villager/biomes/biome-taiga-zombie", + + "res/mob/zombie_villager/professions/armorer", + "res/mob/zombie_villager/professions/butcher", + "res/mob/zombie_villager/professions/cartographer", + "res/mob/zombie_villager/professions/cleric", + "res/mob/zombie_villager/professions/farmer", + "res/mob/zombie_villager/professions/fisherman", + "res/mob/zombie_villager/professions/fletcher", + "res/mob/zombie_villager/professions/leatherworker", + "res/mob/zombie_villager/professions/librarian", + "res/mob/zombie_villager/professions/nitwit", + "res/mob/zombie_villager/professions/shepherd", + "res/mob/zombie_villager/professions/stonemason", + "res/mob/zombie_villager/professions/toolsmith", + "res/mob/zombie_villager/professions/weaponsmith" + ] + }, + "pillager": { + "textureLocations": [ + "res/mob/pillager" + ] + }, + "ravager": { + "textureLocations": [ + "res/mob/illager/ravager" + ] + }, + + "panda": { + "textureLocations": [ + "res/mob/panda/panda", + "res/mob/panda/panda_aggressive", + "res/mob/panda/panda_brown", + "res/mob/panda/panda_lazy", + "res/mob/panda/panda_playful", + "res/mob/panda/panda_sneezy", + "res/mob/panda/panda_worried" + ] + } +} diff --git a/PckStuido.ModelSupport/SkinModelImporter.cs b/PckStuido.ModelSupport/SkinModelImporter.cs new file mode 100644 index 00000000..2cc7c2a8 --- /dev/null +++ b/PckStuido.ModelSupport/SkinModelImporter.cs @@ -0,0 +1,557 @@ +/* Copyright (c) 2024-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.IO; +using System.Linq; +using System.Drawing; +using System.Numerics; +using System.Diagnostics; +using System.Windows.Forms; +using System.Drawing.Imaging; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using PckStudio.Core; +using PckStudio.Core.Skin; +using PckStudio.Core.Extensions; +using PckStudio.Core.FileFormats; +using PckStudio.ModelSupport.Format.External; +using PckStudio.Core.Additional_Popups; +using PckStudio.ModelSupport.Internal.Format; + +namespace PckStudio.ModelSupport +{ + public sealed class SkinModelImporter : ModelImporter + { + public static SkinModelImporter Default { get; } = new SkinModelImporter(); + + private SkinModelImporter() + { + InternalAddProvider(new("Pck skin model(*.psm)", "*.psm"), ImportPsm, ExportPsm); + InternalAddProvider(new("Block bench model(*.bbmodel)", "*.bbmodel"), ImportBlockBenchModel, ExportBlockBenchModel); + InternalAddProvider(new("Bedrock (Legacy) Model(*.geo.json;*.json)", "*.geo.json;*.json"), ImportBedrockJson, ExportBedrockJson); + } + + internal static SkinModelInfo ImportPsm(string filepath) + { + var reader = new PSMFileReader(); + PSMFile csmbFile = reader.FromFile(filepath); + return new SkinModelInfo(null, csmbFile.SkinANIM, new(csmbFile.Parts, csmbFile.Offsets)); + } + + internal static void ExportPsm(string filepath, SkinModelInfo modelInfo) + { + PSMFile psmFile = new PSMFile(PSMFile.CurrentVersion, modelInfo.Anim); + psmFile.Parts.AddRange(modelInfo.Model.AdditionalBoxes); + psmFile.Offsets.AddRange(modelInfo.Model.PartOffsets); + var writer = new PSMFileWriter(psmFile); + writer.WriteToFile(filepath); + } + + internal static SkinModelInfo ImportBlockBenchModel(string filepath) + { + BlockBenchModel blockBenchModel = JsonConvert.DeserializeObject(File.ReadAllText(filepath)); + if (!blockBenchModel.Format.UseBoxUv) + { + Trace.TraceError($"[{nameof(SkinModelImporter)}:{nameof(ImportBlockBenchModel)}] Failed to import skin '{blockBenchModel.Name}': Skin does not use box uv."); + return null; + } + + IEnumerable partOffsets = blockBenchModel.Outliner + .Where(token => token.Type == JTokenType.Object && SkinBOX.IsValidType(TryConvertToSkinBoxType(token.ToObject().Name))) + .Select(token => token.ToObject()) + .Select(outline => new SkinPartOffset(TryConvertToSkinBoxType(outline.Name), -GetOffsetFromOrigin(TryConvertToSkinBoxType(outline.Name), outline.Origin).Y)) + .Where(offset => offset.Value != 0f); + + IEnumerable boxes = ReadOutliner(null, blockBenchModel.Outliner, blockBenchModel.Elements); + + Image texture = null; + if (blockBenchModel.Textures.IndexInRange(0)) + { + texture = blockBenchModel.Textures[0]; + texture = SwapBoxBottomTexture(texture, boxes); + } + + return CreateSkinModelInfo(texture, boxes, partOffsets); + } + + private static SkinModelInfo CreateSkinModelInfo(Image texture, IEnumerable boxes, IEnumerable partOffsets) + { + SkinANIM skinANIM = ( + SkinAnimMask.HEAD_DISABLED | + SkinAnimMask.HEAD_OVERLAY_DISABLED | + SkinAnimMask.BODY_DISABLED | + SkinAnimMask.BODY_OVERLAY_DISABLED | + SkinAnimMask.RIGHT_ARM_DISABLED | + SkinAnimMask.RIGHT_ARM_OVERLAY_DISABLED | + SkinAnimMask.LEFT_ARM_DISABLED | + SkinAnimMask.LEFT_ARM_OVERLAY_DISABLED | + SkinAnimMask.RIGHT_LEG_DISABLED | + SkinAnimMask.RIGHT_LEG_OVERLAY_DISABLED | + SkinAnimMask.LEFT_LEG_DISABLED | + SkinAnimMask.LEFT_LEG_OVERLAY_DISABLED); + + skinANIM = skinANIM.SetFlag(SkinAnimFlag.RESOLUTION_64x64, texture.Size.Width == texture.Size.Height); + + SkinModel skinModel = new SkinModel(); + + skinModel.PartOffsets.AddRange(partOffsets); + + SkinBOX ApplyOffset(SkinBOX box) + { + SkinPartOffset offset = skinModel.PartOffsets.FirstOrDefault(offset => offset.Type == (box.IsOverlayPart() ? box.GetBaseType() : box.Type)); + return string.IsNullOrEmpty(offset.Type) ? box : new SkinBOX(box.Type, box.Pos - (Vector3.UnitY * offset.Value), box.Size, box.UV, box.HideWithArmor, box.Mirror, box.Scale); + } + + IEnumerable convertedBoxes = boxes.Select(ApplyOffset); + + IEnumerable customBoxes = convertedBoxes.Where(box => !SkinBOX.KnownHashes.ContainsKey(box.GetHashCode())); + + skinModel.AdditionalBoxes.AddRange(customBoxes); + + // check for know boxes and filter them out + SkinAnimMask mask = (SkinAnimMask)convertedBoxes + .Where(box => SkinBOX.KnownHashes.ContainsKey(box.GetHashCode()) && Enum.IsDefined(typeof(SkinAnimMask), (1 >> (int)SkinBOX.KnownHashes[box.GetHashCode()]))) + .Select(box => SkinBOX.KnownHashes[box.GetHashCode()]) + .Select(i => 1 << (int)i) + .DefaultIfEmpty() + .Aggregate((a, b) => a | b); + + if (mask != SkinAnimMask.NONE) + skinANIM &= ~mask; + + return new SkinModelInfo(texture, skinANIM, skinModel); + } + + private static IEnumerable ReadOutliner(string parentName, JArray oulineChildren, IReadOnlyCollection elements) + { + IEnumerable boxes = oulineChildren + .Where(token => token.Type == JTokenType.String && Guid.TryParse(token.ToString(), out Guid elementUuid) && elements.Any(e => e.Uuid == elementUuid)) + .Select(token => elements.First(e => Guid.Parse(token.ToString()) == e.Uuid)) + .Where(element => element.Type == "cube" && element.UseBoxUv && element.Export && SkinBOX.IsValidType(TryConvertToSkinBoxType(parentName ?? element.Name))) + .Select(element => LoadElement(element, TryConvertToSkinBoxType(parentName ?? element.Name))); + + IEnumerable childOutlines = oulineChildren + .Where(token => token.Type == JTokenType.Object) + .Select(token => token.ToObject()); + + foreach (Outline childOutline in childOutlines) + { + boxes = boxes.Concat(ReadOutliner(parentName ?? childOutline.Name, childOutline.Children, elements)); + } + return boxes; + } + + private static SkinBOX LoadElement(Element element, string outlineName) + { + var boundingBox = new BoundingBox(element.From, element.To); + Vector3 pos = boundingBox.Start.ToNumericsVector(); + Vector3 size = boundingBox.Volume.ToNumericsVector(); + Vector2 uv = element.UvOffset; + + pos = TranslateToInternalPosition(outlineName, pos, size, new Vector3(1, 1, 0)); + + var box = new SkinBOX(outlineName, pos, size, uv, mirror: element.MirrorUv); + if (SkinBOX.IsBasePart(outlineName) && ((outlineName == "HEAD" && element.Inflate == 0.5f) || (element.Inflate >= 0.25f && element.Inflate <= 0.5f))) + box = new SkinBOX(SkinBOXExtensions.GetOverlayType(outlineName), pos, size, uv, mirror: element.MirrorUv); + return box; + } + + internal static void ExportBlockBenchModel(string filepath, SkinModelInfo modelInfo) + { + Image exportTexture = SwapBoxBottomTexture(modelInfo); + BlockBenchModel blockBenchModel = BlockBenchModel.Create(BlockBenchFormatInfos.BedrockEntity, Path.GetFileNameWithoutExtension(filepath), new Size(64, exportTexture.Width == exportTexture.Height ? 64 : 32), [exportTexture]); + + Dictionary outliners = new Dictionary(5); + List elements = new List(modelInfo.Model.AdditionalBoxes.Count); + + Dictionary offsetLookUp = new Dictionary(5); + + void AddElement(SkinBOX box) + { + string offsetType = box.IsOverlayPart() ? box.GetBaseType() : box.Type; + + Vector3 offset = GetOffsetForPart(offsetType, ref offsetLookUp, modelInfo.Model.PartOffsets); + if (!outliners.ContainsKey(offsetType)) + { + outliners.Add(offsetType, new Outline(offsetType) + { + Origin = GetSkinPartPivot(offsetType, new Vector3(1, 1, 0)) + offset + }); + } + + Element element = CreateElement(box); + + element.From += offset; + element.To += offset; + + elements.Add(element); + outliners[offsetType].Children.Add(element.Uuid); + } + + ANIM2BOX(modelInfo.Anim, AddElement); + + foreach (SkinBOX box in modelInfo.Model.AdditionalBoxes) + { + AddElement(box); + } + blockBenchModel.Elements = elements.ToArray(); + blockBenchModel.Outliner = JArray.FromObject(outliners.Values); + + string content = JsonConvert.SerializeObject(blockBenchModel); + File.WriteAllText(filepath, content); + } + + private static Element CreateElement(SkinBOX box) + { + Vector3 transformPos = TranslateFromInternalPosistion(box, new Vector3(1, 1, 0)); + Element element = CreateElement(box.UV, transformPos, box.Size, box.Scale, box.Mirror); + if (box.IsOverlayPart()) + element.Inflate = box.Type == "HEADWEAR" ? 0.5f : 0.25f; + return element; + } + + private static Element CreateElement(Vector2 uvOffset, Vector3 pos, Vector3 size, float inflate, bool mirror) + { + return Element.CreateCube("cube", uvOffset, pos, size, inflate, mirror); + } + + private static Geometry GetGeometry(string filepath) + { + // Bedrock Entity (Model) + if (filepath.EndsWith(".geo.json")) + { + BedrockModel bedrockModel = JsonConvert.DeserializeObject(File.ReadAllText(filepath)); + var availableModels = bedrockModel.Models.Select(m => m.Description.Identifier).ToArray(); + if (availableModels.Length < 2) + return availableModels.Length == 1 ? bedrockModel.Models[0] : null; + + using ItemSelectionPopUp itemSelectionPopUp = new ItemSelectionPopUp(availableModels); + if (itemSelectionPopUp.ShowDialog() == DialogResult.OK && bedrockModel.Models.IndexInRange(itemSelectionPopUp.SelectedIndex)) + { + return bedrockModel.Models[itemSelectionPopUp.SelectedIndex]; + } + } + + // Bedrock Legacy Model + else if (filepath.EndsWith(".json")) + { + BedrockLegacyModel bedrockModel = JsonConvert.DeserializeObject(File.ReadAllText(filepath)); + var availableModels = bedrockModel.Select(m => m.Key).ToArray(); + if (availableModels.Length < 2) + return availableModels.Length == 1 ? bedrockModel[availableModels[0]] : null; + using ItemSelectionPopUp itemSelectionPopUp = new ItemSelectionPopUp(availableModels); + if (itemSelectionPopUp.ShowDialog() == DialogResult.OK && bedrockModel.ContainsKey(itemSelectionPopUp.SelectedItem)) + { + return bedrockModel[itemSelectionPopUp.SelectedItem]; + } + } + + return null; + } + + private static SkinModelInfo ImportBedrockJson(string filepath) + { + Geometry geometry = GetGeometry(filepath); + if (geometry is null) + return null; + + (IEnumerable boxes, IEnumerable partOffsets) = LoadGeometry(geometry); + + Image texture = null; + string texturePath = Path.Combine(Path.GetDirectoryName(filepath), Path.GetFileNameWithoutExtension(filepath)) + ".png"; + if (File.Exists(texturePath)) + { + texture = Image.FromFile(texturePath).ReleaseFromFile(); + texture = SwapBoxBottomTexture(texture, boxes); + } + + return CreateSkinModelInfo(texture, boxes, partOffsets); + } + + private static (IEnumerable boxes, IEnumerable partOffsets) LoadGeometry(Geometry geometry) + { + List skinPartOffsets = new List(); + List boxes = new List(); + + foreach (Bone bone in geometry.Bones) + { + string boxType = TryConvertToSkinBoxType(bone.Name); + if (!SkinBOX.IsValidType(boxType)) + continue; + + string offsetType = SkinBOX.IsOverlayPart(boxType) ? SkinBOXExtensions.GetBaseType(boxType) : boxType; + Vector3 offset = GetOffsetFromOrigin(offsetType, bone.Pivot * new Vector3(-1, 1, 1)); + if (offset.Y != 0f) + skinPartOffsets.Add(new SkinPartOffset(offsetType, -offset.Y)); + + foreach (Cube cube in bone.Cubes) + { + Vector3 pos = TranslateToInternalPosition(boxType, cube.Origin, cube.Size, Vector3.UnitY); + var skinBox = new SkinBOX(boxType, pos, cube.Size, cube.Uv, hideWithArmor: bone.Name == "helmet", mirror: cube.Mirror); + if (SkinBOX.IsBasePart(boxType) && ((boxType == "HEAD" && cube.Inflate == 0.5f) || (cube.Inflate >= 0.25f && cube.Inflate <= 0.5f))) + skinBox = new SkinBOX(SkinBOXExtensions.GetOverlayType(boxType), pos, cube.Size, cube.Uv, hideWithArmor: bone.Name == "helmet", mirror: cube.Mirror); + boxes.Add(skinBox); + } + } + return (boxes, skinPartOffsets); + } + + internal static void ExportBedrockJson(string filepath, SkinModelInfo modelInfo) + { + if (string.IsNullOrEmpty(filepath) || !filepath.EndsWith(".json")) + return; + + Dictionary bones = new Dictionary(5); + Dictionary offsetLookUp = new Dictionary(5); + + void AddBone(SkinBOX box) + { + string offsetType = box.IsOverlayPart() ? box.GetBaseType() : box.Type; + + Vector3 offset = GetOffsetForPart(offsetType, ref offsetLookUp, modelInfo.Model.PartOffsets); + + if (!bones.ContainsKey(offsetType)) + { + Bone bone = new Bone(offsetType) + { + Pivot = GetSkinPartPivot(offsetType, new Vector3(0, 1, 0)) + offset + }; + bones.Add(offsetType, bone); + } + Vector3 pivot = bones.ContainsKey(offsetType) ? bones[offsetType].Pivot : Vector3.Zero; + Vector3 pos = TranslateFromInternalPosistion(box, new Vector3(1, 1, 0)); + pos = TransformSpace(pos, box.Size, new Vector3(1, 0, 0)); + + bones[offsetType].Cubes.Add(new Cube() + { + Origin = pos + offset, + Size = box.Size, + Uv = box.UV, + Inflate = box.Scale + (box.IsOverlayPart() ? box.Type == "HEAD" ? 0.5f : 0.25f : 0f), + Mirror = box.Mirror, + }); + } + + ANIM2BOX(modelInfo.Anim, AddBone); + + foreach (SkinBOX box in modelInfo.Model.AdditionalBoxes) + { + AddBone(box); + } + + Geometry selectedGeometry = new Geometry(); + selectedGeometry.Bones.AddRange(bones.Values); + object bedrockModel = null; + // Bedrock Entity (Model) + if (filepath.EndsWith(".geo.json")) + { + selectedGeometry.Description = new GeometryDescription() + { + Identifier = $"geometry.{Application.ProductName}.{Path.GetFileNameWithoutExtension(filepath)}", + TextureSize = modelInfo.Texture.Size, + }; + bedrockModel = new BedrockModel + { + FormatVersion = "1.12.0", + Models = { selectedGeometry } + }; + } + // Bedrock Legacy Model + else if (filepath.EndsWith(".json") && modelInfo.Texture.Height == modelInfo.Texture.Width) + { + bedrockModel = new BedrockLegacyModel + { + { $"geometry.{Application.ProductName}.{Path.GetFileNameWithoutExtension(filepath)}", selectedGeometry } + }; + } + else + { + MessageBox.Show("Can't export to Bedrock Legacy Model.", "Invalid Texture Dimensions", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + if (bedrockModel is not null) + { + string content = JsonConvert.SerializeObject(bedrockModel); + File.WriteAllText(filepath, content); + string texturePath = Path.Combine(Path.GetDirectoryName(filepath), Path.GetFileNameWithoutExtension(filepath)) + ".png"; + SwapBoxBottomTexture(modelInfo).Save(texturePath, ImageFormat.Png); + } + } + + private static void ANIM2BOX(SkinANIM anim, Action converter) + { + bool isSlim = anim.GetFlag(SkinAnimFlag.SLIM_MODEL); + bool is32x64 = !(anim.GetFlag(SkinAnimFlag.RESOLUTION_64x64) || isSlim); + if (!anim.GetFlag(SkinAnimFlag.HEAD_DISABLED)) + converter(new SkinBOX("HEAD", new Vector3(-4, -8, -4), new Vector3(8), Vector2.Zero)); + + if (!is32x64 && !anim.GetFlag(SkinAnimFlag.HEAD_OVERLAY_DISABLED)) + converter(new SkinBOX("HEADWEAR", new Vector3(-4, -8, -4), new Vector3(8), new Vector2(32, 0))); + + if (!anim.GetFlag(SkinAnimFlag.BODY_DISABLED)) + converter(new SkinBOX("BODY", new(-4, 0, -2), new(8, 12, 4), new(16, 16))); + + if (!is32x64 && !anim.GetFlag(SkinAnimFlag.BODY_OVERLAY_DISABLED)) + converter(new SkinBOX("JACKET", new(-4, 0, -2), new(8, 12, 4), new(16, 32))); + + if (!anim.GetFlag(SkinAnimFlag.RIGHT_ARM_DISABLED)) + converter(new SkinBOX("ARM0", new(isSlim ? -2 : - 3, -2, -2), new(isSlim ? 3 : 4, 12, 4), new(40, 16))); + + if (!is32x64 && !anim.GetFlag(SkinAnimFlag.RIGHT_ARM_OVERLAY_DISABLED)) + converter(new SkinBOX("SLEEVE0", new(isSlim ? -2 : - 3, -2, -2), new(isSlim ? 3 : 4, 12, 4), new(40, 32))); + + if (!anim.GetFlag(SkinAnimFlag.LEFT_ARM_DISABLED)) + converter(new SkinBOX("ARM1", new(-1, -2, -2), new(isSlim ? 3 : 4, 12, 4), is32x64 ? new(40, 16) : new(32, 48), mirror: is32x64)); + + if (!is32x64 && !anim.GetFlag(SkinAnimFlag.LEFT_ARM_OVERLAY_DISABLED)) + converter(new SkinBOX("SLEEVE1", new(-1, -2, -2), new(isSlim ? 3 : 4, 12, 4), new(48, 48))); + + if (!anim.GetFlag(SkinAnimFlag.RIGHT_LEG_DISABLED)) + converter(new SkinBOX("LEG0", new(-2, 0, -2), new(4, 12, 4), new(0, 16))); + + if (!is32x64 && !anim.GetFlag(SkinAnimFlag.RIGHT_LEG_OVERLAY_DISABLED)) + converter(new SkinBOX("PANTS0", new(-2, 0, -2), new(4, 12, 4), new(0, 32))); + + if (!anim.GetFlag(SkinAnimFlag.LEFT_LEG_DISABLED)) + { + converter(new SkinBOX("LEG1", new(-2, 0, -2), new(4, 12, 4), is32x64 ? new(0, 16) : new(16, 48), mirror: is32x64)); + } + + if (!is32x64 && !anim.GetFlag(SkinAnimFlag.LEFT_LEG_OVERLAY_DISABLED)) + { + converter(new SkinBOX("PANTS1", new(-2, 0, -2), new(4, 12, 4), new(0, 48))); + } + } + + private static string TryConvertToSkinBoxType(string name) + { + if (!SkinBOX.IsValidType(name) && SkinBOX.IsValidType(name.ToUpper())) + { + return name.ToUpper(); + } + return name.ToLower() switch + { + "helmet" => "HEAD", + "rightarm" => "ARM0", + "leftarm" => "ARM1", + "rightleg" => "LEG0", + "leftleg" => "LEG1", + "hat" => "HEADWEAR", + "bodyarmor" => "BODY", + "rightsleeve" => "SLEEVE0", + "leftsleeve" => "SLEEVE1", + "rightpants" => "PANTS0", + "leftpants" => "PANTS1", + _ => name, + }; + } + + private static Vector3 GetOffsetFromOrigin(string boxType, Vector3 origin) + { + Vector3 partTranslation = GameConstants.GetSkinPartPivot(boxType); + Vector3 offset = partTranslation - ((Vector3.UnitY * 24f) - origin); + if (offset.X != 0f || offset.Z != 0f) + Trace.TraceWarning($"[{nameof(SkinModelImporter)}:{nameof(GetOffsetFromOrigin)}] Warning: skin part({boxType}) offsets only support horizontal offsets."); + return offset * Vector3.UnitY; + } + + private static Vector3 GetSkinPartPivot(string partName, Vector3 translationUnit) + { + return TransformSpace(GameConstants.GetSkinPartPivot(partName), Vector3.Zero, translationUnit) + (24f * Vector3.UnitY); + } + + private static Vector3 GetOffsetForPart(string offsetType, ref Dictionary offsetLookUp, IEnumerable partOffsets) + { + if (offsetLookUp.ContainsKey(offsetType)) + { + return -offsetLookUp[offsetType].Value * Vector3.UnitY; + } + if (partOffsets.Any(o => o.Type == offsetType)) + { + SkinPartOffset partOffset = partOffsets.First(o => o.Type == offsetType); + offsetLookUp.Add(offsetType, partOffset); + return -partOffset.Value * Vector3.UnitY; + } + return Vector3.Zero; + } + + private static Image SwapBoxBottomTexture(SkinModelInfo modelInfo) + { + return SwapBoxBottomTexture(modelInfo.Texture, modelInfo.Model.AdditionalBoxes); + } + + private static Image SwapBoxBottomTexture(Image texture, IEnumerable boxes) + { + return SwapTextureAreas(texture, boxes.Where(box => !(box.Size == Vector3.One || box.Size == Vector3.Zero)).Select(box => + { + var imgPos = Point.Truncate(new PointF(box.UV.X + box.Size.X + box.Size.Z, box.UV.Y)); + var area = new RectangleF(imgPos, Size.Truncate(new SizeF(box.Size.X, box.Size.Z))); + return Rectangle.Truncate(area); + }), RotateFlipType.RotateNoneFlipY); + } + + private static Image SwapTextureAreas(Image texture, IEnumerable areasToFix, RotateFlipType type) + { + if (texture == null) + { + Trace.TraceError($"[{nameof(SkinModelImporter)}:{nameof(SwapBoxBottomTexture)}] Failed to fix texture: texture is null."); + return null; + } + areasToFix = areasToFix.Where(rect => rect.Size.Width > 0 && rect.Size.Height > 0); + Image result = new Bitmap(texture); + using var g = Graphics.FromImage(result); + g.ApplyConfig(new GraphicsConfig() + { + InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor, + PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality + }); + foreach (Rectangle area in areasToFix) + { + Image targetAreaImage = texture.GetArea(area); + targetAreaImage.RotateFlip(type); + Region clip = g.Clip; + g.SetClip(area); + g.Clear(Color.Transparent); + g.DrawImage(targetAreaImage, area.Location); + g.Clip = clip; + } + return result; + } + + private static Vector3 TranslateToInternalPosition(string boxType, Vector3 origin, Vector3 size, Vector3 translationUnit) + { + Vector3 pos = TransformSpace(origin, size, translationUnit); + // Skin Renderer (and Game) specific offset value. + pos.Y += 24f; + + // This will cancel out the part specific translation. + Vector3 translation = GameConstants.GetSkinPartTranslation(boxType); + pos -= translation; + + return pos; + } + + private static Vector3 TranslateFromInternalPosistion(SkinBOX skinBox, Vector3 translationUnit) + { + return TranslateToInternalPosition(skinBox.Type, skinBox.Pos, skinBox.Size, translationUnit); + } + } +} diff --git a/PckStuido.ModelSupport/SkinModelInfo.cs b/PckStuido.ModelSupport/SkinModelInfo.cs new file mode 100644 index 00000000..a7a1b2f9 --- /dev/null +++ b/PckStuido.ModelSupport/SkinModelInfo.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PckStudio.Core.Skin; + +namespace PckStudio.ModelSupport +{ + public sealed class SkinModelInfo + { + public SkinModel Model { get; } + public SkinANIM Anim { get; } + public Image Texture { get; } + + public SkinModelInfo(Image texture, SkinANIM anim, SkinModel model) + { + Texture = texture; + Anim = anim; + Model = model; + } + } +} diff --git a/Vendor/OMI-Lib b/Vendor/OMI-Lib index e90b0ed8..87fcc157 160000 --- a/Vendor/OMI-Lib +++ b/Vendor/OMI-Lib @@ -1 +1 @@ -Subproject commit e90b0ed8b50679456c82817e2682b0fdf0cceec9 +Subproject commit 87fcc15776c0829a06430f82eac9b343d7989b10 diff --git a/docs/PSM.md b/docs/PSM.md new file mode 100644 index 00000000..52ccdaf1 --- /dev/null +++ b/docs/PSM.md @@ -0,0 +1,32 @@ +# Pck Skin Model / PSM - v1 + +

A technical documentation about the custom format PCK-Studio uses to save custom skin data.

+ +| Name | Size
(in bytes) | Description | +|:-:|:-:|:-:| +| Version | 1 | Describes the version of the file format. | +| Anim | 4 | Animation flags for the custom skin. | +| Box Count | 4 | The amount of [box data](#box-data) that has to be read. | +| [Box Data](#box-data)[] | Box Count | | +| Offset Count | 4 | The amount of [offset data](#offset-data) that has to be read. | +| [Offset Data](#offset-data)[] | Offset Count | | + + +### Box data +| Name | Size
(in bytes) | Description | +|:-:|:--:|:-:| +| Type | 1 | Type of model part ([see PSMParentType](../PCK-Studio/Internal/FileFormats/PSMFile.cs#L83)). | +| Postion | 24 | Position in 3D space (3 Floats). | +| Size | 24 | Size in 3D space (3 Floats). | +| Mirror | 1 (bit) | Specifies if the texture should be mirrored. | +| U | 7 (bits) | U texture coordinate. | +| Hide with armor | 1 (bit) | Specifies if the box should hide when wearing armor. | +| V | 7 (bits) | V texture coordinate. | +| Inflate | 4 | Defines box scale without changing the UV. | + + +### Offset data +| Name | Size
(in bytes) | Description | +|:-:|:--:|:-:| +| Type | 1 | Type of offset ([see PSMOffsetType](../PCK-Studio/Internal/FileFormats/PSMFile.cs#L60)). | +| Value | 4 | The Vertical Offset. | \ No newline at end of file