From 3a4262ac15f14f621364059f1a9f419e292f8e63 Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Mon, 19 Feb 2024 18:58:14 +0100 Subject: [PATCH] Add Simple Guideline rendering --- .../Forms/Editor/CustomSkinEditor.Designer.cs | 1 + PCK-Studio/Forms/Editor/CustomSkinEditor.cs | 42 ++-- PCK-Studio/Forms/Editor/CustomSkinEditor.resx | 109 +++------ .../Forms/Skins-And-Textures/SkinPreview.cs | 14 +- PCK-Studio/PckStudio.csproj | 3 + PCK-Studio/Properties/Resources.Designer.cs | 60 ++++- PCK-Studio/Properties/Resources.resx | 6 + PCK-Studio/Rendering/CubeBatchMesh.cs | 41 +++- PCK-Studio/Rendering/CubeData.cs | 93 +++++++ PCK-Studio/Rendering/GenericMesh.cs | 5 +- PCK-Studio/Rendering/LineVertex.cs | 24 ++ PCK-Studio/Rendering/Renderer.cs | 5 + PCK-Studio/Rendering/SkinRenderer.Designer.cs | 14 +- PCK-Studio/Rendering/SkinRenderer.cs | 231 +++++++++++++++--- PCK-Studio/Rendering/VertexArray.cs | 2 +- PCK-Studio/Rendering/VertexBuffer.cs | 42 +++- .../Resources/shader/lineFragmentShader.glsl | 12 + .../Resources/shader/lineVertexShader.glsl | 15 ++ .../Resources/shader/skinVertexShader.glsl | 7 +- .../Resources/shader/skyboxVertexShader.glsl | 6 +- 20 files changed, 558 insertions(+), 174 deletions(-) create mode 100644 PCK-Studio/Rendering/LineVertex.cs create mode 100644 PCK-Studio/Resources/shader/lineFragmentShader.glsl create mode 100644 PCK-Studio/Resources/shader/lineVertexShader.glsl diff --git a/PCK-Studio/Forms/Editor/CustomSkinEditor.Designer.cs b/PCK-Studio/Forms/Editor/CustomSkinEditor.Designer.cs index b7074008..e443f079 100644 --- a/PCK-Studio/Forms/Editor/CustomSkinEditor.Designer.cs +++ b/PCK-Studio/Forms/Editor/CustomSkinEditor.Designer.cs @@ -386,6 +386,7 @@ this.renderer3D1.RefreshRate = 50; this.renderer3D1.Texture = null; this.renderer3D1.VSync = true; + this.renderer3D1.TextureChanging += new System.EventHandler(renderer3D1_TextureChanging); // // uvPictureBox // diff --git a/PCK-Studio/Forms/Editor/CustomSkinEditor.cs b/PCK-Studio/Forms/Editor/CustomSkinEditor.cs index 2d55577f..5d0b0b1c 100644 --- a/PCK-Studio/Forms/Editor/CustomSkinEditor.cs +++ b/PCK-Studio/Forms/Editor/CustomSkinEditor.cs @@ -36,30 +36,22 @@ namespace PckStudio.Forms.Editor PixelOffsetMode = PixelOffsetMode.HighQuality, }; - private CustomSkinEditor() + public CustomSkinEditor(PckFileData file) { InitializeComponent(); + _file = file; + rng = new Random(); } - public CustomSkinEditor(PckFileData file) : this() + protected override void OnLoad(EventArgs e) { - _file = file; - - if (DesignMode) - return; - renderer3D1.RefreshRate = 50; - renderer3D1.Texture = null; - renderer3D1.VSync = true; - renderer3D1.TextureChanging += new System.EventHandler(renderer3D1_TextureChanging); + base.OnLoad(e); renderer3D1.InitializeGL(); - - Controls.Add(renderer3D1); - rng = new Random(); if (_file.Size > 0) { renderer3D1.Texture = _file.GetTexture(); } - LoadModelData(file.Properties); + LoadModelData(_file.Properties); } private void LoadModelData(PckFileProperties properties) @@ -77,7 +69,7 @@ namespace PckStudio.Forms.Editor skinPartListBox.DataSource = skinPartListBindingSource; skinPartListBox.DisplayMember = "Type"; - skinOffsetListBindingSource = new BindingSource(renderer3D1.PartOffsets, null); + skinOffsetListBindingSource = new BindingSource(renderer3D1, null); offsetListBox.DataSource = skinOffsetListBindingSource; } @@ -186,17 +178,17 @@ namespace PckStudio.Forms.Editor private void LoadCsmb(CSMBFile csmbFile) { - renderer3D1.ModelData.Clear(); - foreach (var part in csmbFile.Parts) - { - renderer3D1.ModelData.Add(part); - } + //renderer3D1.ModelData.Clear(); + //foreach (var part in csmbFile.Parts) + //{ + // renderer3D1.ModelData.Add(part); + //} - renderer3D1.ResetOffsets(); - foreach (var offset in csmbFile.Offsets) - { - renderer3D1.SetPartOffset(offset); - } + //renderer3D1.ResetOffsets(); + //foreach (var offset in csmbFile.Offsets) + //{ + // renderer3D1.SetPartOffset(offset); + //} } private void cloneToolStripMenuItem_Click(object sender, EventArgs e) diff --git a/PCK-Studio/Forms/Editor/CustomSkinEditor.resx b/PCK-Studio/Forms/Editor/CustomSkinEditor.resx index cce6f060..dc425ff4 100644 --- a/PCK-Studio/Forms/Editor/CustomSkinEditor.resx +++ b/PCK-Studio/Forms/Editor/CustomSkinEditor.resx @@ -267,15 +267,6 @@ 17, 17 - - 152, 108 - - - contextMenuStrip1 - - - System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO @@ -348,6 +339,15 @@ Change Color + + 152, 108 + + + contextMenuStrip1 + + + System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + Bottom, Right @@ -963,51 +963,6 @@ Top, Bottom, Left - - skinPartsTabPage - - - System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - metroTabControl1 - - - 0 - - - skinOffsetsTabPage - - - System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - metroTabControl1 - - - 1 - - - 23, 59 - - - 165, 492 - - - 166 - - - metroTabControl1 - - - MetroFramework.Controls.MetroTabControl, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - - $this - - - 1 - Center @@ -1035,6 +990,18 @@ 0 + + Fill + + + 0, 0 + + + 157, 450 + + + 0 + offsetListBox @@ -1071,29 +1038,26 @@ 1 - - Fill + + 23, 59 - - 0, 0 + + 165, 492 - - 157, 450 + + 166 - - 0 + + metroTabControl1 - - offsetListBox + + MetroFramework.Controls.MetroTabControl, MetroFramework, Version=1.4.0.0, Culture=neutral, PublicKeyToken=5f91a84759bf584a - - System.Windows.Forms.ListBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + $this - - skinOffsetsTabPage - - - 0 + + 1 Top, Bottom, Left, Right @@ -3670,9 +3634,6 @@ AP//AAA= - - NoControl - 900, 600 diff --git a/PCK-Studio/Forms/Skins-And-Textures/SkinPreview.cs b/PCK-Studio/Forms/Skins-And-Textures/SkinPreview.cs index 6acb0ec0..c13fed89 100644 --- a/PCK-Studio/Forms/Skins-And-Textures/SkinPreview.cs +++ b/PCK-Studio/Forms/Skins-And-Textures/SkinPreview.cs @@ -15,11 +15,21 @@ namespace PckStudio.Forms set => ModelView.ANIM = value; } - public SkinPreview(Image texture, IEnumerable modelData) + private Image texture; + private IEnumerable data; + + public SkinPreview(Image image, IEnumerable modelData) { InitializeComponent(); + texture = image; + data = modelData; + } + + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); ModelView.InitializeGL(); - foreach (var item in modelData) + foreach (var item in data) { ModelView.ModelData.Add(item); } diff --git a/PCK-Studio/PckStudio.csproj b/PCK-Studio/PckStudio.csproj index 5de5c1fc..51942590 100644 --- a/PCK-Studio/PckStudio.csproj +++ b/PCK-Studio/PckStudio.csproj @@ -158,6 +158,7 @@ + @@ -646,6 +647,8 @@ + + diff --git a/PCK-Studio/Properties/Resources.Designer.cs b/PCK-Studio/Properties/Resources.Designer.cs index 8498a747..0a532903 100644 --- a/PCK-Studio/Properties/Resources.Designer.cs +++ b/PCK-Studio/Properties/Resources.Designer.cs @@ -355,7 +355,8 @@ namespace PckStudio.Properties { /// ///void main() ///{ - /// color = texture(screenTexture, texCoords); + /// vec3 texColor = texture(screenTexture, texCoords).rgb; + /// color = vec4(texColor, 1.0); ///}. /// public static string framebufferFragmentShader { @@ -444,6 +445,42 @@ namespace PckStudio.Properties { } } + /// + /// Looks up a localized string similar to #version 330 core + /// + ///layout(location = 0) in vec4 a_Pos; + /// + ///uniform mat4 ViewProjection; + /// + ///void main() + ///{ + /// gl_Position = ViewProjection * a_Pos; + ///};. + /// + public static string lineFragmentShader { + get { + return ResourceManager.GetString("lineFragmentShader", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to #version 330 core + /// + ///layout(location = 0) out vec4 FragColor; + /// + ///uniform vec4 color; + /// + ///void main() + ///{ + /// FragColor = color; + ///}. + /// + public static string lineVertexShader { + get { + return ResourceManager.GetString("lineVertexShader", resourceCulture); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -611,12 +648,12 @@ namespace PckStudio.Properties { /// ///uniform sampler2D u_Texture; /// - ///in vec2 o_TexScale; + ///in vec2 o_TillingFactor; ///in vec2 o_TexCoord; /// ///void main() ///{ - /// color = texture(u_Texture, o_TexCoord * o_TexScale); + /// color = texture(u_Texture, o_TexCoord * o_TillingFactor); ///};. /// public static string skinFragmentShader { @@ -634,7 +671,7 @@ namespace PckStudio.Properties { ///uniform vec2 u_TexSize; /// ///out vec2 o_TexCoord; - ///out vec2 o_TexScale; + ///out vec2 o_TillingFactor; /// ///in geometryData ///{ @@ -651,7 +688,7 @@ namespace PckStudio.Properties { /// gl_Position = gl_in[0].gl_Position; /// o_TexCoord = dataIn[0].TexCoord; /// if (isXBad) - /// o_TexCoord.x = mod(o_TexCoord.x, u_TexSize.x); [rest of string was truncated]";. + /// o_TexCoord.x = mod(o_TexCoord.x, u_TexSiz [rest of string was truncated]";. /// public static string skinGeometryShader { get { @@ -677,7 +714,7 @@ namespace PckStudio.Properties { ///layout(location = 2) in float scale; /// ///uniform mat4 u_ViewProjection; - ///uniform mat4 u_Model; + ///uniform mat4 u_Transform; /// ///out geometryData ///{ @@ -687,9 +724,8 @@ namespace PckStudio.Properties { ///void main() ///{ /// dataOut.TexCoord = texCoord; - /// vec4 scaledVertex = scale * vertexPosition; - /// vec4 invertedVertex = vec4(scaledVertex.x, scaledVertex.y * -1.0, scaledVertex.z * -1.0, 1.0); - /// gl_Position = u_ViewProjection * u_Model * invertedVertex; + /// vec4 invertedVertex = vec4(vertexPosition.x, vertexPosition.yz * -1.0, 1.0); + /// gl_Position = u_ViewProjection * u_Transform * invertedVertex * scale; ///};. /// public static string skinVertexShader { @@ -724,15 +760,15 @@ namespace PckStudio.Properties { /// ///layout(location = 0) in vec4 a_Pos; /// - ///uniform mat4 viewProjection; + ///uniform mat4 ViewProjection; /// ///out vec3 texCoords; /// ///void main() ///{ - /// vec4 pos = viewProjection * a_Pos; + /// vec4 pos = ViewProjection * a_Pos; /// gl_Position = vec4(pos.x, pos.y, pos.ww); - /// texCoords = vec3(a_Pos.x, a_Pos.y, -a_Pos.z); + /// texCoords = vec3(a_Pos.xy, -a_Pos.z); ///};. /// public static string skyboxVertexShader { diff --git a/PCK-Studio/Properties/Resources.resx b/PCK-Studio/Properties/Resources.resx index bb5d3b1c..39ecec81 100644 --- a/PCK-Studio/Properties/Resources.resx +++ b/PCK-Studio/Properties/Resources.resx @@ -352,4 +352,10 @@ ..\Resources\shader\framebufferVertexShader.glsl;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + ..\Resources\shader\lineFragmentShader.glsl;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + + ..\Resources\shader\lineVertexShader.glsl;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + \ No newline at end of file diff --git a/PCK-Studio/Rendering/CubeBatchMesh.cs b/PCK-Studio/Rendering/CubeBatchMesh.cs index a16b1d57..9c6c37ee 100644 --- a/PCK-Studio/Rendering/CubeBatchMesh.cs +++ b/PCK-Studio/Rendering/CubeBatchMesh.cs @@ -30,6 +30,8 @@ namespace PckStudio.Rendering private List cubes; internal float Scale { get; set; } = 1f; + public Vector3 Translation { get; set; } = Vector3.Zero; + public Vector3 Pivot { get; set; } = Vector3.Zero; internal CubeBatchMesh(string name) : base(name, PrimitiveType.Triangles) { @@ -44,7 +46,9 @@ namespace PckStudio.Rendering internal void AddSkinBox(SkinBOX skinBox) { - AddCube(skinBox.Pos.ToOpenTKVector(), skinBox.Size.ToOpenTKVector(), skinBox.UV.ToOpenTKVector(), skinBox.Scale + Scale, skinBox.Mirror, skinBox.Type == "HEAD"); + AddCube(skinBox.Pos.ToOpenTKVector(), skinBox.Size.ToOpenTKVector(), skinBox.UV.ToOpenTKVector(), skinBox.Scale + Scale, skinBox.Mirror, + skinBox.Type == "HEAD" || + skinBox.Type == "HEADWEAR"); } internal void ClearData() @@ -92,6 +96,41 @@ namespace PckStudio.Rendering cube.MirrorTexture = mirrorTexture; } + private Vector3 Transform + { + get + { + Vector3 offset = Translation; + offset.Xz -= Pivot.Xz / 2f; + return -offset; + } + } + + + internal Vector3 GetCenter(int index) + { + if (!cubes.IndexInRange(index)) + throw new IndexOutOfRangeException(); + + return cubes[index].Center + Transform; + } + + internal Vector3[] GetCubical(int index) + { + if (!cubes.IndexInRange(index)) + throw new IndexOutOfRangeException(); + + CubeData cube = cubes[index]; + return cube.GetOutline().Select(pos => pos + Transform).ToArray(); + } + + internal Vector3 GetFaceCenter(int index, CubeData.CubeFace face) + { + if (!cubes.IndexInRange(index)) + throw new IndexOutOfRangeException(); + return cubes[index].GetFaceCenter(face) + Transform; + } + internal void SetEnabled(int index, bool enable) { if (!cubes.IndexInRange(index)) diff --git a/PCK-Studio/Rendering/CubeData.cs b/PCK-Studio/Rendering/CubeData.cs index 7449dbfc..a3aa3b8a 100644 --- a/PCK-Studio/Rendering/CubeData.cs +++ b/PCK-Studio/Rendering/CubeData.cs @@ -106,6 +106,99 @@ namespace PckStudio.Rendering } } + internal Vector3 Center => Position + Size / 2f; + + internal enum CubeFace + { + Back, + Front, + Top, + Bottom, + Left, + Right + } + + internal Vector3 GetFaceCenter(CubeFace face) + { + var result = Center; + switch (face) + { + case CubeFace.Top: + result.Y -= Size.Y / 2f; + return result; + case CubeFace.Bottom: + result.Y += Size.Y / 2f; + return result; + case CubeFace.Back: + result.Z -= Size.Z / 2f; + return result; + case CubeFace.Front: + result.Z += Size.Z / 2f; + return result; + case CubeFace.Left: + result.X -= Size.X / 2f; + return result; + case CubeFace.Right: + result.X += Size.X / 2f; + return result; + default: + return result; + } + } + + internal Vector3[] GetOutline() + { + List verts = new List(); + + Vector3 bottomRightBack = vertices[0].Position; + Vector3 bottomLeftBack = vertices[1].Position; + Vector3 topLeftBack = vertices[2].Position; + Vector3 topRightBack = vertices[3].Position; + + Vector3 bottomRightFront = vertices[4].Position; + Vector3 bottomLeftFront = vertices[5].Position; + Vector3 topLeftFront = vertices[6].Position; + Vector3 topRightFront = vertices[7].Position; + + + return [ + topLeftBack, + topLeftFront, + + topLeftBack, + topRightBack, + + topRightBack, + topRightFront, + + topLeftFront, + topRightFront, + + bottomLeftBack, + bottomLeftFront, + + bottomLeftBack, + bottomRightBack, + + bottomRightBack, + bottomRightFront, + + bottomLeftFront, + bottomRightFront, + + topLeftFront, + bottomLeftFront, + + topRightFront, + bottomRightFront, + topLeftBack, + bottomLeftBack, + + topRightBack, + bottomRightBack, + ]; + } + private void UpdateVertices() { vertices = GetCubeVertexData(Position, Size, Uv, Scale, MirrorTexture, FlipZMapping); diff --git a/PCK-Studio/Rendering/GenericMesh.cs b/PCK-Studio/Rendering/GenericMesh.cs index 6cf2e360..dbc7e313 100644 --- a/PCK-Studio/Rendering/GenericMesh.cs +++ b/PCK-Studio/Rendering/GenericMesh.cs @@ -35,7 +35,7 @@ namespace PckStudio.Rendering protected int indicesOffset; private VertexArray vertexArray; - private VertexBuffer vertexBuffer; + private VertexBuffer vertexBuffer; private IndexBuffer indexBuffer; private readonly VertexBufferLayout _layout; private readonly PrimitiveType drawType; @@ -65,7 +65,8 @@ namespace PckStudio.Rendering vertexArray ??= new VertexArray(); var vertexData = vertices.ToArray(); - vertexBuffer = new VertexBuffer(vertexData, vertexData.Length * SizeInBytes); + vertexBuffer = new VertexBuffer(vertexData.Length * SizeInBytes); + vertexBuffer.SetData(vertexData); vertexArray.AddBuffer(vertexBuffer, _layout); diff --git a/PCK-Studio/Rendering/LineVertex.cs b/PCK-Studio/Rendering/LineVertex.cs new file mode 100644 index 00000000..3950cfa4 --- /dev/null +++ b/PCK-Studio/Rendering/LineVertex.cs @@ -0,0 +1,24 @@ +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)] + internal struct LineVertex + { + public LineVertex(Vector3 position, Color4 color) + { + Position = position; + Color = color; + } + + public Vector3 Position { get; set; } + public Color4 Color { get; set; } + } +} diff --git a/PCK-Studio/Rendering/Renderer.cs b/PCK-Studio/Rendering/Renderer.cs index 3cdea456..48d025d6 100644 --- a/PCK-Studio/Rendering/Renderer.cs +++ b/PCK-Studio/Rendering/Renderer.cs @@ -41,5 +41,10 @@ namespace PckStudio.Rendering { GL.ClearColor(color); } + + public static void SetLineWidth(float width) + { + GL.LineWidth(width); + } } } diff --git a/PCK-Studio/Rendering/SkinRenderer.Designer.cs b/PCK-Studio/Rendering/SkinRenderer.Designer.cs index 6828d002..ca88f97e 100644 --- a/PCK-Studio/Rendering/SkinRenderer.Designer.cs +++ b/PCK-Studio/Rendering/SkinRenderer.Designer.cs @@ -37,6 +37,7 @@ namespace PckStudio.Rendering this.components = new System.ComponentModel.Container(); this.reToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); + this.guidelineModeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.contextMenuStrip1.SuspendLayout(); this.SuspendLayout(); // @@ -50,9 +51,17 @@ namespace PckStudio.Rendering // contextMenuStrip1 // this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.reToolStripMenuItem}); + this.reToolStripMenuItem, + this.guidelineModeToolStripMenuItem}); this.contextMenuStrip1.Name = "contextMenuStrip1"; - this.contextMenuStrip1.Size = new System.Drawing.Size(181, 48); + this.contextMenuStrip1.Size = new System.Drawing.Size(181, 70); + // + // guidelineModeToolStripMenuItem + // + this.guidelineModeToolStripMenuItem.Name = "guidelineModeToolStripMenuItem"; + this.guidelineModeToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.guidelineModeToolStripMenuItem.Text = "Guideline Mode"; + this.guidelineModeToolStripMenuItem.Click += new System.EventHandler(this.guidelineModeToolStripMenuItem_Click); // // SkinRenderer // @@ -64,5 +73,6 @@ namespace PckStudio.Rendering } private System.Windows.Forms.ToolStripMenuItem reToolStripMenuItem; private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; + private System.Windows.Forms.ToolStripMenuItem guidelineModeToolStripMenuItem; } } diff --git a/PCK-Studio/Rendering/SkinRenderer.cs b/PCK-Studio/Rendering/SkinRenderer.cs index 2916d2e5..7a4f18dd 100644 --- a/PCK-Studio/Rendering/SkinRenderer.cs +++ b/PCK-Studio/Rendering/SkinRenderer.cs @@ -64,6 +64,19 @@ namespace PckStudio.Rendering } public bool ClampModel { get; set; } = false; + public bool ShowGuideLines + { + get => guidelineMode != GuidelineMode.None; + set + { + if (value) + { + guidelineMode = GuidelineMode.Cubical; + return; + } + guidelineMode = GuidelineMode.None; + } + } [Description("Event that gets fired when the Texture is changing")] [Category("Property Chnaged")] @@ -110,6 +123,16 @@ namespace PckStudio.Rendering return bmp; } + + private enum GuidelineMode + { + None = -1, + Cubical, + Skeleton + }; + + private GuidelineMode guidelineMode { get; set; } = GuidelineMode.None; + private Vector2 _globalModelRotation; private Vector2 GlobalModelRotation { @@ -151,6 +174,9 @@ namespace PckStudio.Rendering private ShaderProgram framebufferShader; private VertexArray framebufferVAO; #endif + private DrawContext _cubicalDrawContext; + private DrawContext _skeletonDrawContext; + private DrawContext _skyboxRenderBuffer; private CubeTexture _skyboxTexture; private float skyboxRotation = 0f; @@ -179,12 +205,8 @@ namespace PckStudio.Rendering private bool showWireFrame = false; - private Matrix4 HeadMatrix { get; set; } = Matrix4.Identity; - private Matrix4 BodyMatrix { get; set; } = Matrix4.Identity; private Matrix4 RightArmMatrix { get; set; } = Matrix4.CreateFromAxisAngle(Vector3.UnitZ, 25f); private Matrix4 LeftArmMatrix { get; set; } = Matrix4.CreateFromAxisAngle(Vector3.UnitZ, -25f); - private Matrix4 RightLegMatrix { get; set; } = Matrix4.Identity; - private Matrix4 LeftLegMatrix { get; set; } = Matrix4.Identity; private static Vector3[] cubeVertices = new Vector3[] { @@ -265,7 +287,7 @@ namespace PckStudio.Rendering InitializeCamera(); InitializeComponent(); - + _shaders = new ShaderLibrary(); ANIM ??= new SkinANIM(SkinAnimMask.RESOLUTION_64x64); OnTimerTick = AnimationTick; @@ -304,27 +326,43 @@ namespace PckStudio.Rendering bodyOverlay.AddCube(new(-4, 0, -2), new(8, 12, 4), new(16, 32), scale: OverlayScale); rightArm ??= new CubeBatchMesh("Right Arm"); + rightArm.Pivot = new Vector3(4f, 2f, 0f); + rightArm.Translation = new Vector3(-5f, -2f, 0f); rightArm.AddCube(new(-3, -2, -2), new(4, 12, 4), new(40, 16)); rightArmOverlay ??= new CubeBatchMesh("Right Arm Overlay", OverlayScale); + rightArmOverlay.Pivot = new Vector3(4f, 2f, 0f); + rightArmOverlay.Translation = new Vector3(-5f, -2f, 0f); rightArmOverlay.AddCube(new(-3, -2, -2), new(4, 12, 4), new(40, 32), scale: OverlayScale); leftArm ??= new CubeBatchMesh("Left Arm"); + leftArm.Pivot = new Vector3(-4f, 2f, 0f); + leftArm.Translation = new Vector3(5f, -2f, 0f); leftArm.AddCube(new(-1, -2, -2), new(4, 12, 4), new(32, 48)); leftArmOverlay ??= new CubeBatchMesh("Left Arm Overlay", OverlayScale); + leftArmOverlay.Pivot = new Vector3(-4f, 2f, 0f); + leftArmOverlay.Translation = new Vector3(5f, -2f, 0f); leftArmOverlay.AddCube(new(-1, -2, -2), new(4, 12, 4), new(48, 48), scale: OverlayScale); rightLeg ??= new CubeBatchMesh("Right Leg"); + rightLeg.Pivot = new Vector3(0f, 12f, 0f); + rightLeg.Translation = new Vector3(-2f, -12f, 0f); rightLeg.AddCube(new(-2, 0, -2), new(4, 12, 4), new(0, 16)); rightLegOverlay ??= new CubeBatchMesh("Right Leg Overlay", OverlayScale); + rightLegOverlay.Pivot = new Vector3(0f, 12f, 0f); + rightLegOverlay.Translation = new Vector3(-2f, -12f, 0f); rightLegOverlay.AddCube(new(-2, 0, -2), new(4, 12, 4), new(0, 32), scale: OverlayScale); leftLeg ??= new CubeBatchMesh("Left Leg"); + leftLeg.Pivot = new Vector3(0f, 12f, 0f); + leftLeg.Translation = new Vector3(2f, -12f, 0f); leftLeg.AddCube(new(-2, 0, -2), new(4, 12, 4), new(16, 48)); leftLegOverlay ??= new CubeBatchMesh("Left Leg Overlay", OverlayScale); + leftLegOverlay.Pivot = new Vector3(0f, 12f, 0f); + leftLegOverlay.Translation = new Vector3(2f, -12f, 0f); leftLegOverlay.AddCube(new(-2, 0, -2), new(4, 12, 4), new(0, 48), scale: OverlayScale); } @@ -362,9 +400,10 @@ namespace PckStudio.Rendering } // Skybox shader - { + { var skyboxVAO = new VertexArray(); - var skyboxVBO = new VertexBuffer(cubeVertices, cubeVertices.Length * Vector3.SizeInBytes); + var skyboxVBO = new VertexBuffer(); + skyboxVBO.SetData(cubeVertices); var vboLayout = new VertexBufferLayout(); vboLayout.Add(3); skyboxVAO.AddBuffer(skyboxVBO, vboLayout); @@ -428,6 +467,90 @@ namespace PckStudio.Rendering GLErrorCheck(); } #endif + // Line Shader + { + var lineShader = ShaderProgram.Create(Resources.lineVertexShader, Resources.lineFragmentShader); + lineShader.Bind(); + lineShader.SetUniform4("baseColor", Color.WhiteSmoke); + lineShader.Validate(); + _shaders.AddShader("LineShader", lineShader); + + Color lineColor = Color.Aquamarine; + + // Cubical draw context + { + VertexArray lineVAO = new VertexArray(); + List vertices = new List(24 * 6); + vertices.AddRange(head.GetCubical(0).Select(pos => new LineVertex(pos, lineColor))); + vertices.AddRange(body.GetCubical(0).Select(pos => new LineVertex(pos, lineColor))); + vertices.AddRange(rightArm.GetCubical(0).Select(pos => new LineVertex(pos, lineColor))); + vertices.AddRange(leftArm.GetCubical(0).Select(pos => new LineVertex(pos, lineColor))); + vertices.AddRange(rightLeg.GetCubical(0).Select(pos => new LineVertex(pos, lineColor))); + vertices.AddRange(leftLeg.GetCubical(0).Select(pos => new LineVertex(pos, lineColor))); + VertexBuffer buffer = new VertexBuffer(); + buffer.SetData(vertices.ToArray()); + VertexBufferLayout layout = new VertexBufferLayout(); + layout.Add(3); + layout.Add(4); + lineVAO.AddBuffer(buffer, layout); + lineVAO.Bind(); + + _cubicalDrawContext = new DrawContext(lineVAO, buffer.GenIndexBuffer(), PrimitiveType.Lines); + } + + GLErrorCheck(); + + // Skeleton draw context + { + VertexArray lineVAO = new VertexArray(); + Vector3 bodyCenterTop = body.GetFaceCenter(0, CubeData.CubeFace.Top); + Vector3 bodyCenterBottom = body.GetFaceCenter(0, CubeData.CubeFace.Bottom); + LineVertex[] data = [ + new LineVertex(head.GetFaceCenter(0, CubeData.CubeFace.Top), lineColor), + new LineVertex(bodyCenterTop, lineColor), + + new LineVertex(rightArm.GetFaceCenter(0, CubeData.CubeFace.Bottom), lineColor), + new LineVertex(rightArm.GetFaceCenter(0, CubeData.CubeFace.Top), lineColor), + new LineVertex(rightArm.GetFaceCenter(0, CubeData.CubeFace.Top), lineColor), + new LineVertex(bodyCenterTop, lineColor), + + new LineVertex(leftArm.GetFaceCenter(0, CubeData.CubeFace.Bottom), lineColor), + new LineVertex(leftArm.GetFaceCenter(0, CubeData.CubeFace.Top), lineColor), + new LineVertex(leftArm.GetFaceCenter(0, CubeData.CubeFace.Top), lineColor), + new LineVertex(bodyCenterTop, lineColor), + + new LineVertex(rightLeg.GetFaceCenter(0, CubeData.CubeFace.Bottom), lineColor), + new LineVertex(rightLeg.GetFaceCenter(0, CubeData.CubeFace.Top), lineColor), + new LineVertex(rightLeg.GetFaceCenter(0, CubeData.CubeFace.Top), lineColor), + new LineVertex(bodyCenterBottom, lineColor), + new LineVertex(bodyCenterBottom, lineColor), + new LineVertex(bodyCenterTop, lineColor), + + new LineVertex(leftLeg.GetFaceCenter(0, CubeData.CubeFace.Bottom), lineColor), + new LineVertex(leftLeg.GetFaceCenter(0, CubeData.CubeFace.Top), lineColor), + new LineVertex(leftLeg.GetFaceCenter(0, CubeData.CubeFace.Top), lineColor), + new LineVertex(bodyCenterBottom, lineColor), + new LineVertex(bodyCenterBottom, lineColor), + new LineVertex(bodyCenterTop, lineColor), + ]; + VertexBuffer buffer = new VertexBuffer(); + buffer.SetData(data); + VertexBufferLayout layout = new VertexBufferLayout(); + layout.Add(3); + layout.Add(4); + lineVAO.AddBuffer(buffer, layout); + lineVAO.Bind(); + + _skeletonDrawContext = new DrawContext(lineVAO, buffer.GenIndexBuffer(), PrimitiveType.Lines); + } + + GLErrorCheck(); + } + } + + private DrawContext GetGuidelineDrawContext() + { + return guidelineMode == GuidelineMode.Skeleton ? _skeletonDrawContext : _cubicalDrawContext; } protected virtual void OnTextureChanging(object sender, TextureChangingEventArgs e) @@ -462,7 +585,8 @@ namespace PckStudio.Rendering GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment, RenderbufferTarget.Renderbuffer, rbo); framebufferVAO = new VertexArray(); - VertexBuffer vertexBuffer = new VertexBuffer(rectVertices, rectVertices.Length * Vector4.SizeInBytes); + VertexBuffer vertexBuffer = new VertexBuffer(); + vertexBuffer.SetData(rectVertices); VertexBufferLayout layout = new VertexBufferLayout(); layout.Add(4); framebufferVAO.AddBuffer(vertexBuffer, layout); @@ -677,17 +801,36 @@ namespace PckStudio.Rendering return; } - MakeCurrent(); + MakeCurrent(); #if USE_FRAMEBUFFER framebuffer.Bind(); #endif GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + GL.Enable(EnableCap.DepthTest); // Enable correct Z Drawings + GL.Enable(EnableCap.LineSmooth); + Matrix4 viewProjection = Camera.GetViewProjection(); + + // Render Skybox + { + GL.DepthFunc(DepthFunction.Lequal); + GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); + var skyboxShader = _shaders.GetShader("SkyboxShader"); + skyboxShader.Bind(); + _skyboxTexture.Bind(); + + var view = new Matrix4(new Matrix3(Matrix4.LookAt(Camera.WorldPosition, Camera.WorldPosition + Camera.Orientation, Camera.Up))) + * Matrix4.CreateRotationY(MathHelper.DegreesToRadians(skyboxRotation)); + var proj = Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(Camera.Fov), AspectRatio, 1f, 1000f); + var viewproj = view * proj; + skyboxShader.SetUniformMat4("ViewProjection", ref viewproj); + Renderer.Draw(skyboxShader, _skyboxRenderBuffer); + GL.DepthFunc(DepthFunction.Less); + } // Render (custom) skin { - var viewProjection = Camera.GetViewProjection(); var skinShader = _shaders.GetShader("SkinShader"); skinShader.Bind(); skinShader.SetUniformMat4("u_ViewProjection", ref viewProjection); @@ -749,29 +892,29 @@ namespace PckStudio.Rendering } bool slimModel = ANIM.GetFlag(SkinAnimFlag.SLIM_MODEL); - RenderBodyPart(skinShader, new Vector3(0f, 0f, 0f), new Vector3(0f), HeadMatrix, modelMatrix, "HEAD", "HEADWEAR"); - RenderBodyPart(skinShader, new Vector3(0f, 0f, 0f), new Vector3(0f), BodyMatrix, modelMatrix, "BODY", "JACKET"); - RenderBodyPart(skinShader, new Vector3(4f, 2f, 0f), new Vector3(slimModel ? -4f : -5f, -2f, 0f), RightArmMatrix * armRightMatrix, modelMatrix, "ARM0", "SLEEVE0"); - RenderBodyPart(skinShader, new Vector3(-4f, 2f, 0f), new Vector3(5f, -2f, 0f), LeftArmMatrix * armLeftMatrix, modelMatrix, "ARM1", "SLEEVE1"); - RenderBodyPart(skinShader, new Vector3(0f, 12f, 0f), new Vector3(-2f, -12f, 0f), RightLegMatrix * legRightMatrix, modelMatrix, "LEG0", "PANTS0"); - RenderBodyPart(skinShader, new Vector3(0f, 12f, 0f), new Vector3(2f, -12f, 0f), LeftLegMatrix * legLeftMatrix, modelMatrix, "LEG1", "PANTS1"); - } - - // Render Skybox - { - GL.DepthFunc(DepthFunction.Lequal); - GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); - var skyboxShader = _shaders.GetShader("SkyboxShader"); - skyboxShader.Bind(); - _skyboxTexture.Bind(); + rightArm.Translation = rightArmOverlay.Translation = new Vector3(slimModel ? -4f : -5f, -2f, 0f); + - var view = new Matrix4(new Matrix3(Matrix4.LookAt(Camera.WorldPosition, Camera.WorldPosition + Camera.Orientation, Camera.Up))) - * Matrix4.CreateRotationY(MathHelper.DegreesToRadians(skyboxRotation)); - var proj = Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(Camera.Fov), AspectRatio, 1f, 1000f); - var viewproj = view * proj; - skyboxShader.SetUniformMat4("ViewProjection", ref viewproj); - Renderer.Draw(skyboxShader, _skyboxRenderBuffer); - GL.DepthFunc(DepthFunction.Less); + RenderBodyPart(skinShader, Matrix4.Identity, modelMatrix, "HEAD", "HEADWEAR"); + RenderBodyPart(skinShader, Matrix4.Identity, modelMatrix, "BODY", "JACKET"); + RenderBodyPart(skinShader, RightArmMatrix * armRightMatrix, modelMatrix, "ARM0", "SLEEVE0"); + RenderBodyPart(skinShader, LeftArmMatrix * armLeftMatrix, modelMatrix, "ARM1", "SLEEVE1"); + RenderBodyPart(skinShader, legRightMatrix, modelMatrix, "LEG0", "PANTS0"); + RenderBodyPart(skinShader, legLeftMatrix, modelMatrix, "LEG1", "PANTS1"); + + // render lines + if (ShowGuideLines) + { + GL.DepthFunc(DepthFunction.Always); + var shader = _shaders.GetShader("LineShader"); + shader.Bind(); + shader.SetUniformMat4("ViewProjection", ref viewProjection); + shader.SetUniformMat4("Transform", ref modelMatrix); + Renderer.SetLineWidth(2.5f); + Renderer.Draw(shader, GetGuidelineDrawContext()); + //GL.DepthFunc(DepthFunction.Less); + Renderer.SetLineWidth(1f); + } } #if USE_FRAMEBUFFER @@ -837,23 +980,26 @@ namespace PckStudio.Rendering base.OnMouseUp(e); } - private void RenderBodyPart(ShaderProgram shader, Vector3 pivot, Vector3 translation, Matrix4 partMatrix, Matrix4 globalMatrix, params string[] additionalData) + private void RenderBodyPart(ShaderProgram shader, Matrix4 partMatrix, Matrix4 globalMatrix, params string[] additionalData) { foreach (var data in additionalData) { - RenderPart(shader, data, pivot, translation, partMatrix, globalMatrix); + RenderPart(shader, data, partMatrix, globalMatrix); } } - private void RenderPart(ShaderProgram shader, string name, Vector3 pivot, Vector3 translation, Matrix4 partMatrix, Matrix4 globalMatrix) + private void RenderPart(ShaderProgram shader, string name, Matrix4 partMatrix, Matrix4 globalMatrix) { CubeBatchMesh cubeMesh = meshStorage[name]; + Vector3 translation = cubeMesh.Translation; + Vector3 pivot = cubeMesh.Pivot; float yOffset = GetOffset(name); translation.Y -= yOffset; pivot.Y += yOffset; - Matrix4 model = Pivot(translation, pivot, partMatrix); - model *= globalMatrix; - _skinShader.SetUniformMat4("u_Model", ref model); + Matrix4 transform = Matrix4.CreateScale(cubeMesh.Scale); + transform *= Pivot(translation, pivot, partMatrix); + transform *= globalMatrix; + shader.SetUniformMat4("u_Transform", ref transform); cubeMesh.Draw(shader); } @@ -901,5 +1047,14 @@ namespace PckStudio.Rendering MakeCurrent(); UploadMeshData(); } + + private void guidelineModeToolStripMenuItem_Click(object sender, EventArgs e) + { + if (!Enum.IsDefined(typeof(GuidelineMode), ++guidelineMode)) + { + guidelineMode = GuidelineMode.None; + } + guidelineModeToolStripMenuItem.Text = $"Guideline Mode: {guidelineMode}"; + } } } \ No newline at end of file diff --git a/PCK-Studio/Rendering/VertexArray.cs b/PCK-Studio/Rendering/VertexArray.cs index 6a40f389..dce617fd 100644 --- a/PCK-Studio/Rendering/VertexArray.cs +++ b/PCK-Studio/Rendering/VertexArray.cs @@ -17,7 +17,7 @@ namespace PckStudio.Rendering _id = GL.GenVertexArray(); } - public void AddBuffer(VertexBuffer buffer, VertexBufferLayout layout) where T : struct + public void AddBuffer(VertexBuffer buffer, VertexBufferLayout layout) { Bind(); buffer.Bind(); diff --git a/PCK-Studio/Rendering/VertexBuffer.cs b/PCK-Studio/Rendering/VertexBuffer.cs index fe974c5f..82a3b7e7 100644 --- a/PCK-Studio/Rendering/VertexBuffer.cs +++ b/PCK-Studio/Rendering/VertexBuffer.cs @@ -2,6 +2,7 @@ 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; @@ -10,25 +11,41 @@ using OpenTK.Graphics.OpenGL; namespace PckStudio.Rendering { - internal struct VertexBuffer : IDisposable where T : struct + internal struct VertexBuffer : IDisposable { private int _id; + private int _count; + private int _size; -#if DEBUG - private T[] __data; -#endif - - public VertexBuffer(T[] data, int size) + public VertexBuffer() { -#if DEBUG - __data = data; -#endif _id = GL.GenBuffer(); + _size = 0; + } + + public VertexBuffer(int size) : this() + { + _size = size; Bind(); - GL.BufferData(BufferTarget.ArrayBuffer, size, data, BufferUsageHint.StaticDraw); + 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 == 0) + { + 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); @@ -44,5 +61,10 @@ namespace PckStudio.Rendering Unbind(); GL.DeleteBuffer(_id); } + + internal IndexBuffer GenIndexBuffer() + { + return IndexBuffer.Create(Enumerable.Range(0, _count).ToArray()); + } } } diff --git a/PCK-Studio/Resources/shader/lineFragmentShader.glsl b/PCK-Studio/Resources/shader/lineFragmentShader.glsl new file mode 100644 index 00000000..5a86eaef --- /dev/null +++ b/PCK-Studio/Resources/shader/lineFragmentShader.glsl @@ -0,0 +1,12 @@ +#version 330 core + +layout(location = 0) out vec4 FragColor; + +uniform vec4 baseColor; + +in vec4 color; + +void main() +{ + FragColor = color * baseColor; +} \ No newline at end of file diff --git a/PCK-Studio/Resources/shader/lineVertexShader.glsl b/PCK-Studio/Resources/shader/lineVertexShader.glsl new file mode 100644 index 00000000..0f1a32b1 --- /dev/null +++ b/PCK-Studio/Resources/shader/lineVertexShader.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.x, a_Pos.yz * -1.0, 1.0); +}; \ No newline at end of file diff --git a/PCK-Studio/Resources/shader/skinVertexShader.glsl b/PCK-Studio/Resources/shader/skinVertexShader.glsl index b5a3cf3e..7d22fb22 100644 --- a/PCK-Studio/Resources/shader/skinVertexShader.glsl +++ b/PCK-Studio/Resources/shader/skinVertexShader.glsl @@ -5,7 +5,7 @@ layout(location = 1) in vec2 texCoord; layout(location = 2) in float scale; uniform mat4 u_ViewProjection; -uniform mat4 u_Model; +uniform mat4 u_Transform; out geometryData { @@ -15,7 +15,6 @@ out geometryData void main() { dataOut.TexCoord = texCoord; - vec4 scaledVertex = scale * vertexPosition; - vec4 invertedVertex = vec4(scaledVertex.x, scaledVertex.y * -1.0, scaledVertex.z * -1.0, 1.0); - gl_Position = u_ViewProjection * u_Model * invertedVertex; + vec4 invertedVertex = vec4(vertexPosition.x, vertexPosition.yz * -1.0, 1.0); + gl_Position = u_ViewProjection * u_Transform * invertedVertex * scale; }; \ No newline at end of file diff --git a/PCK-Studio/Resources/shader/skyboxVertexShader.glsl b/PCK-Studio/Resources/shader/skyboxVertexShader.glsl index 7a955686..729f6678 100644 --- a/PCK-Studio/Resources/shader/skyboxVertexShader.glsl +++ b/PCK-Studio/Resources/shader/skyboxVertexShader.glsl @@ -2,13 +2,13 @@ layout(location = 0) in vec4 a_Pos; -uniform mat4 viewProjection; +uniform mat4 ViewProjection; out vec3 texCoords; void main() { - vec4 pos = viewProjection * a_Pos; + vec4 pos = ViewProjection * a_Pos; gl_Position = vec4(pos.x, pos.y, pos.ww); - texCoords = vec3(a_Pos.x, a_Pos.y, -a_Pos.z); + texCoords = vec3(a_Pos.xy, -a_Pos.z); }; \ No newline at end of file