From 5f7f9c3517fc29e7f6eab060c691f437cf7b71eb Mon Sep 17 00:00:00 2001 From: KillzXGaming Date: Tue, 15 Oct 2019 19:27:17 -0400 Subject: [PATCH] Add all the latest files --- .../FileFormats/Collision/KCL.cs | 6 +- .../FileFormats/Texture/BNTX.cs | 11 +- .../File_Format_Library.csproj | 12 +- .../File_Format_Library.csproj.user | 3 + .../GL/Custom2D/KCLRendering2D.cs | 23 ++ File_Format_Library/GL/KCL_Render.cs | 3 + .../MK8MapCameraEditor.Designer.cs | 64 ++++-- .../MK8TrackEditor/MK8MapCameraEditor.cs | 35 ++- .../MK8TrackEditor/MK8MapCameraEditor.resx | 3 + .../Editors/MK8TrackEditor/MapCameraViewer.cs | 55 +++++ File_Format_Library/Main.cs | 2 +- .../OpenGL/GLShaderGeneric.cs | 208 ++++++++++++++++++ Switch_Toolbox_Library/OpenGL/Render2D.cs | 115 ++++++++++ Switch_Toolbox_Library/OpenGL/Viewport2D.cs | 202 +++++++++++++++++ Switch_Toolbox_Library/Toolbox_Library.csproj | 6 + Toolbox/Lib/SARCExt.dll | Bin 228864 -> 228864 bytes Toolbox/Lib/SARCExt.pdb | Bin 65024 -> 65024 bytes Toolbox/Shader/Drawing2D/KCL.frag | 13 ++ Toolbox/Shader/Drawing2D/KCL.vert | 21 ++ Toolbox/Toolbox.csproj | 6 + UpgradeLog.htm | Bin 0 -> 29036 bytes 21 files changed, 756 insertions(+), 32 deletions(-) create mode 100644 File_Format_Library/GL/Custom2D/KCLRendering2D.cs create mode 100644 File_Format_Library/GUI/Editors/MK8TrackEditor/MapCameraViewer.cs create mode 100644 Switch_Toolbox_Library/OpenGL/GLShaderGeneric.cs create mode 100644 Switch_Toolbox_Library/OpenGL/Render2D.cs create mode 100644 Switch_Toolbox_Library/OpenGL/Viewport2D.cs create mode 100644 Toolbox/Shader/Drawing2D/KCL.frag create mode 100644 Toolbox/Shader/Drawing2D/KCL.vert create mode 100644 UpgradeLog.htm diff --git a/File_Format_Library/FileFormats/Collision/KCL.cs b/File_Format_Library/FileFormats/Collision/KCL.cs index 2024b7a0..1b365930 100644 --- a/File_Format_Library/FileFormats/Collision/KCL.cs +++ b/File_Format_Library/FileFormats/Collision/KCL.cs @@ -71,7 +71,7 @@ namespace FirstPlugin } } - private DrawableContainer DrawableContainer = new DrawableContainer(); + public DrawableContainer DrawableContainer = new DrawableContainer(); public void Load(System.IO.Stream stream) { @@ -463,6 +463,10 @@ namespace FirstPlugin } } + public List GetKclModels() + { + return Renderer.models; + } private void Read(MarioKart.MK7.KCL kcl) { diff --git a/File_Format_Library/FileFormats/Texture/BNTX.cs b/File_Format_Library/FileFormats/Texture/BNTX.cs index cedcdcb2..6c2737bb 100644 --- a/File_Format_Library/FileFormats/Texture/BNTX.cs +++ b/File_Format_Library/FileFormats/Texture/BNTX.cs @@ -382,14 +382,21 @@ namespace FirstPlugin { long StartPos = reader.Position; + Console.WriteLine("StartPos " + StartPos); + uint TotalSize = (uint)reader.BaseStream.Length; + Console.WriteLine("TotalSize " + TotalSize); + //Get file size in header reader.SeekBegin(StartPos + 28); uint FileSize = reader.ReadUInt32(); + Console.WriteLine("FileSize " + FileSize); + //Create bntx for array BNTX bntx = new BNTX(); + bntx.IFileInfo = new IFileInfo(); bntx.Text = "Sheet " + Containers.Count; @@ -399,6 +406,8 @@ namespace FirstPlugin bntx.Load(new MemoryStream(Data)); Containers.Add(bntx); + Console.WriteLine("File Container " + bntx.Text + " " + StartPos); + reader.SeekBegin(StartPos + FileSize); if (TotalSize > FileSize) { @@ -1616,7 +1625,7 @@ namespace FirstPlugin public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0) { int target = 1; - if (Parent != null && Parent is BNTX) + if (Parent != null && Parent is BNTX && ((BNTX)Parent).BinaryTexFile != null) { bool IsNX = ((BNTX)Parent).BinaryTexFile.PlatformTarget == "NX "; if (!IsNX) diff --git a/File_Format_Library/File_Format_Library.csproj b/File_Format_Library/File_Format_Library.csproj index e248dafd..919fadcf 100644 --- a/File_Format_Library/File_Format_Library.csproj +++ b/File_Format_Library/File_Format_Library.csproj @@ -1,4 +1,4 @@ - + @@ -113,7 +113,8 @@ False ..\Toolbox\Lib\OpenTK.dll - + + False ..\Toolbox\Lib\OpenTK.GLControl.dll @@ -352,6 +353,7 @@ + Form @@ -646,6 +648,9 @@ SmoothNormalsMultiMeshForm.cs + + UserControl + Component @@ -1818,5 +1823,4 @@ - - + \ No newline at end of file diff --git a/File_Format_Library/File_Format_Library.csproj.user b/File_Format_Library/File_Format_Library.csproj.user index 64a5aae8..dee06e3e 100644 --- a/File_Format_Library/File_Format_Library.csproj.user +++ b/File_Format_Library/File_Format_Library.csproj.user @@ -3,4 +3,7 @@ true + + ProjectFiles + \ No newline at end of file diff --git a/File_Format_Library/GL/Custom2D/KCLRendering2D.cs b/File_Format_Library/GL/Custom2D/KCLRendering2D.cs new file mode 100644 index 00000000..a13a704c --- /dev/null +++ b/File_Format_Library/GL/Custom2D/KCLRendering2D.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK; +using OpenTK.Graphics; + +namespace FirstPlugin +{ + public class KCLRendering2D + { + public KCLRendering2D(KCL kcl) + { + + } + + public void Draw(Matrix4 modelViewMatrix) + { + + } + } +} diff --git a/File_Format_Library/GL/KCL_Render.cs b/File_Format_Library/GL/KCL_Render.cs index a91cab25..70314195 100644 --- a/File_Format_Library/GL/KCL_Render.cs +++ b/File_Format_Library/GL/KCL_Render.cs @@ -281,12 +281,14 @@ namespace FirstPlugin GL.Enable(EnableCap.DepthTest); GL.Enable(EnableCap.CullFace); } + private void SetRenderSettings(ShaderProgram shader) { shader.SetBoolToInt("renderVertColor", Runtime.renderVertColor); GL.Uniform1(defaultShaderProgram["renderType"], (int)Runtime.viewportShading); } + private void DrawModel(KCL.KCLModel m, ShaderProgram shader, bool drawSelection = false) { if (m.faces.Count <= 3) @@ -314,6 +316,7 @@ namespace FirstPlugin } } } + private static void DrawModelSelection(KCL.KCLModel p, ShaderProgram shader) { //This part needs to be reworked for proper outline. Currently would make model disappear diff --git a/File_Format_Library/GUI/Editors/MK8TrackEditor/MK8MapCameraEditor.Designer.cs b/File_Format_Library/GUI/Editors/MK8TrackEditor/MK8MapCameraEditor.Designer.cs index f37183c0..63a244cc 100644 --- a/File_Format_Library/GUI/Editors/MK8TrackEditor/MK8MapCameraEditor.Designer.cs +++ b/File_Format_Library/GUI/Editors/MK8TrackEditor/MK8MapCameraEditor.Designer.cs @@ -28,30 +28,30 @@ /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.stPropertyGrid1 = new Toolbox.Library.Forms.STPropertyGrid(); this.leBtnRadio = new System.Windows.Forms.RadioButton(); this.beBtnRadio = new System.Windows.Forms.RadioButton(); - this.glControl2D1 = new Toolbox.Library.Forms.GLControl2D(); + this.mapCameraViewer1 = new MapCameraViewer(); + this.stContextMenuStrip1 = new Toolbox.Library.Forms.STContextMenuStrip(this.components); + this.loadKCLFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.stContextMenuStrip1.SuspendLayout(); this.SuspendLayout(); - this.Controls.Add(this.glControl2D1); - this.Controls.Add(this.beBtnRadio); - this.Controls.Add(this.leBtnRadio); - this.Controls.Add(this.stPropertyGrid1); // // stPropertyGrid1 // this.stPropertyGrid1.AutoScroll = true; - this.stPropertyGrid1.ShowHintDisplay = true; this.stPropertyGrid1.Dock = System.Windows.Forms.DockStyle.Right; - this.stPropertyGrid1.Location = new System.Drawing.Point(272, 25); + this.stPropertyGrid1.Location = new System.Drawing.Point(503, 0); this.stPropertyGrid1.Name = "stPropertyGrid1"; - this.stPropertyGrid1.Size = new System.Drawing.Size(298, 372); + this.stPropertyGrid1.ShowHintDisplay = true; + this.stPropertyGrid1.Size = new System.Drawing.Size(217, 437); this.stPropertyGrid1.TabIndex = 11; // // leBtnRadio // this.leBtnRadio.AutoSize = true; - this.leBtnRadio.Location = new System.Drawing.Point(154, 31); + this.leBtnRadio.Location = new System.Drawing.Point(85, 3); this.leBtnRadio.Name = "leBtnRadio"; this.leBtnRadio.Size = new System.Drawing.Size(83, 17); this.leBtnRadio.TabIndex = 13; @@ -62,7 +62,7 @@ // beBtnRadio // this.beBtnRadio.AutoSize = true; - this.beBtnRadio.Location = new System.Drawing.Point(72, 31); + this.beBtnRadio.Location = new System.Drawing.Point(3, 3); this.beBtnRadio.Name = "beBtnRadio"; this.beBtnRadio.Size = new System.Drawing.Size(76, 17); this.beBtnRadio.TabIndex = 14; @@ -71,25 +71,47 @@ this.beBtnRadio.UseVisualStyleBackColor = true; this.beBtnRadio.CheckedChanged += new System.EventHandler(this.beBtnRadio_CheckedChanged); // - // glControl2D1 + // mapCameraViewer1 // - this.glControl2D1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.mapCameraViewer1.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.glControl2D1.BackColor = System.Drawing.Color.Black; - this.glControl2D1.Location = new System.Drawing.Point(3, 54); - this.glControl2D1.Name = "glControl2D1"; - this.glControl2D1.Size = new System.Drawing.Size(263, 343); - this.glControl2D1.TabIndex = 15; - this.glControl2D1.VSync = false; + this.mapCameraViewer1.Location = new System.Drawing.Point(3, 26); + this.mapCameraViewer1.Name = "mapCameraViewer1"; + this.mapCameraViewer1.Size = new System.Drawing.Size(494, 408); + this.mapCameraViewer1.TabIndex = 15; + this.mapCameraViewer1.UseGrid = true; + this.mapCameraViewer1.UseOrtho = true; + this.mapCameraViewer1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.mapCameraViewer1_MouseDown); + // + // stContextMenuStrip1 + // + this.stContextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.loadKCLFileToolStripMenuItem}); + this.stContextMenuStrip1.Name = "stContextMenuStrip1"; + this.stContextMenuStrip1.Size = new System.Drawing.Size(145, 26); + // + // loadKCLFileToolStripMenuItem + // + this.loadKCLFileToolStripMenuItem.Name = "loadKCLFileToolStripMenuItem"; + this.loadKCLFileToolStripMenuItem.Size = new System.Drawing.Size(144, 22); + this.loadKCLFileToolStripMenuItem.Text = "Load KCL File"; + this.loadKCLFileToolStripMenuItem.Click += new System.EventHandler(this.loadKCLFileToolStripMenuItem_Click); // // MK8MapCameraEditor // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(576, 402); + this.Controls.Add(this.mapCameraViewer1); + this.Controls.Add(this.beBtnRadio); + this.Controls.Add(this.leBtnRadio); + this.Controls.Add(this.stPropertyGrid1); this.Name = "MK8MapCameraEditor"; + this.Size = new System.Drawing.Size(720, 437); + this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.MK8MapCameraEditor_MouseDown); + this.stContextMenuStrip1.ResumeLayout(false); this.ResumeLayout(false); + this.PerformLayout(); } @@ -98,6 +120,8 @@ private Toolbox.Library.Forms.STPropertyGrid stPropertyGrid1; private System.Windows.Forms.RadioButton beBtnRadio; private System.Windows.Forms.RadioButton leBtnRadio; - private Toolbox.Library.Forms.GLControl2D glControl2D1; + private MapCameraViewer mapCameraViewer1; + private Toolbox.Library.Forms.STContextMenuStrip stContextMenuStrip1; + private System.Windows.Forms.ToolStripMenuItem loadKCLFileToolStripMenuItem; } } diff --git a/File_Format_Library/GUI/Editors/MK8TrackEditor/MK8MapCameraEditor.cs b/File_Format_Library/GUI/Editors/MK8TrackEditor/MK8MapCameraEditor.cs index 6beb563c..b84431a6 100644 --- a/File_Format_Library/GUI/Editors/MK8TrackEditor/MK8MapCameraEditor.cs +++ b/File_Format_Library/GUI/Editors/MK8TrackEditor/MK8MapCameraEditor.cs @@ -26,7 +26,7 @@ namespace FirstPlugin.Turbo InitializeComponent(); } - Course_MapCamera_bin activeCameraFile; + private Course_MapCamera_bin activeCameraFile; public void LoadFile(Course_MapCamera_bin mapCamera) { activeCameraFile = mapCamera; @@ -40,10 +40,7 @@ namespace FirstPlugin.Turbo stPropertyGrid1.LoadProperty(activeCameraFile.cameraData, OnPropertyChanged); - glControl2D1.AddCircle(new OpenTK.Vector2(cam.PositionX, cam.PositionZ)); - glControl2D1.AddCircle(new OpenTK.Vector2(cam.TargetX, cam.TargetZ)); - - glControl2D1.AddRectangle(cam.BoundingWidth, cam.BoundingHeight, new OpenTK.Vector2(cam.PositionX, cam.PositionZ)); + mapCameraViewer1.LoadCameraFile(mapCamera); } public void OnPropertyChanged() { } @@ -57,5 +54,33 @@ namespace FirstPlugin.Turbo { activeCameraFile.BigEndian = beBtnRadio.Checked; } + + private void mapCameraViewer1_MouseDown(object sender, MouseEventArgs e) + { + + } + + private void loadKCLFileToolStripMenuItem_Click(object sender, EventArgs e) + { + OpenFileDialog ofd = new OpenFileDialog(); + ofd.Filter = Utils.GetAllFilters(typeof(KCL)); + if (ofd.ShowDialog() == DialogResult.OK) + { + var fileFormat = Toolbox.Library.IO.STFileLoader.OpenFileFormat(ofd.FileName); + if (fileFormat != null && fileFormat is KCL) + { + var kcl = fileFormat as KCL; + mapCameraViewer1.LoadCollision(kcl); + } + } + } + + private void MK8MapCameraEditor_MouseDown(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Right) + { + stContextMenuStrip1.Show(Cursor.Position); + } + } } } diff --git a/File_Format_Library/GUI/Editors/MK8TrackEditor/MK8MapCameraEditor.resx b/File_Format_Library/GUI/Editors/MK8TrackEditor/MK8MapCameraEditor.resx index 1af7de15..197ca22e 100644 --- a/File_Format_Library/GUI/Editors/MK8TrackEditor/MK8MapCameraEditor.resx +++ b/File_Format_Library/GUI/Editors/MK8TrackEditor/MK8MapCameraEditor.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + \ No newline at end of file diff --git a/File_Format_Library/GUI/Editors/MK8TrackEditor/MapCameraViewer.cs b/File_Format_Library/GUI/Editors/MK8TrackEditor/MapCameraViewer.cs new file mode 100644 index 00000000..f9adb072 --- /dev/null +++ b/File_Format_Library/GUI/Editors/MK8TrackEditor/MapCameraViewer.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.Forms; +using OpenTK.Graphics.OpenGL; +using Toolbox.Library; +using System.Drawing; +using FirstPlugin.Turbo; +using OpenTK; + +namespace FirstPlugin.Turbo +{ + public class MapCameraViewer : Viewport2D + { + private KCL CollisionFile; + private KCLRendering2D KCLRender; + private Course_MapCamera_bin MapCamera; + + public void LoadCollision(KCL kcl) { + CollisionFile = kcl; + KCLRender = new KCLRendering2D(kcl); + } + + public void LoadCameraFile(Course_MapCamera_bin camera) { + MapCamera = camera; + } + + public override void RenderSceme() + { + if (MapCamera == null) return; + + GL.PushMatrix(); + + GL.Scale(0.1f, 0.1f ,1.0f); + + var cam = MapCamera.cameraData; + + if (CollisionFile != null) + DrawCollision(CollisionFile); + + Render2D.DrawRectangle(cam.BoundingWidth, cam.BoundingHeight, Color.White, true); + + Render2D.DrawCircle(new Vector2(cam.PositionX, cam.PositionY), Color.Red); + Render2D.DrawCircle(new Vector2(cam.TargetX, cam.TargetY), Color.Green); + + GL.PopMatrix(); + } + + private void DrawCollision(KCL kcl) { + KCLRender.Draw(Camera.ModelViewMatrix); + } + } +} diff --git a/File_Format_Library/Main.cs b/File_Format_Library/Main.cs index de86ed9e..0402d5d1 100644 --- a/File_Format_Library/Main.cs +++ b/File_Format_Library/Main.cs @@ -396,7 +396,7 @@ namespace FirstPlugin //Unfinished wip formats not ready for use if (Runtime.DEVELOPER_DEBUG_MODE) { - Formats.Add(typeof(XLINK)); + Formats.Add(typeof(XLINK)); Formats.Add(typeof(BFSAR)); Formats.Add(typeof(GFA)); Formats.Add(typeof(HyruleWarriors.G1M.G1M)); diff --git a/Switch_Toolbox_Library/OpenGL/GLShaderGeneric.cs b/Switch_Toolbox_Library/OpenGL/GLShaderGeneric.cs new file mode 100644 index 00000000..28d3cf3d --- /dev/null +++ b/Switch_Toolbox_Library/OpenGL/GLShaderGeneric.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Text; +using System.Threading.Tasks; +using OpenTK.Graphics.OpenGL; +using OpenTK; + +namespace Toolbox.Library +{ + public class GLShaderGeneric : IDisposable + { + public bool Compiled = false; + + public int program; + private int vertexShaderID; + private int fragmentShaderID; + + private Dictionary attributes = new Dictionary(); + private Dictionary uniforms = new Dictionary(); + private int activeAttributeCount; + + public void LoadShaders() + { + program = CompileShaders(); + } + + public void Enable() + { + GL.UseProgram(program); + } + + public void Disable() + { + GL.UseProgram(0); + } + + public void Dispose() + { + GL.DeleteProgram(program); + } + + private string vertexShader; + private string fragShader; + private string geomShader; + + public virtual string VertexShader + { + get { return vertexShader; } + set { vertexShader = value; } + } + + public virtual string FragmentShader + { + get { return fragShader; } + set { fragShader = value; } + } + + public virtual string GeometryShader + { + get { return geomShader; } + set { geomShader = value; } + } + + public void SetVec4(string name, Vector4 value) + { + if (uniforms.ContainsKey(name)) + GL.Uniform4(uniforms[name], value); + } + + public void SetVec2(string name, Vector2 value) + { + if (uniforms.ContainsKey(name)) + GL.Uniform2(uniforms[name], value); + } + + public void SetFloat(string name, float value) + { + if (uniforms.ContainsKey(name)) + GL.Uniform1(uniforms[name], value); + } + + public void SetInt(string name, int value) + { + if (uniforms.ContainsKey(name)) + GL.Uniform1(uniforms[name], value); + } + + public void SetBool(string name, bool value) + { + int intValue = value == true ? 1 : 0; + + if (uniforms.ContainsKey(name)) + GL.Uniform1(uniforms[name], intValue); + } + + public void SetColor(string name, Color color) + { + if (uniforms.ContainsKey(name)) + GL.Uniform4(uniforms[name], color); + } + + public void SetMatrix(string name, ref Matrix4 value) + { + if (uniforms.ContainsKey(name)) + GL.UniformMatrix4(uniforms[name], false, ref value); + } + + public int this[string name] + { + get { return uniforms[name]; } + } + + private void LoadAttributes(int program) + { + attributes.Clear(); + + GL.GetProgram(program, GetProgramParameterName.ActiveAttributes, out activeAttributeCount); + for (int i = 0; i < activeAttributeCount; i++) + { + int size = 0; + ActiveAttribType type; + + string name = GL.GetActiveAttrib(program, i, out size, out type); + int location = GL.GetAttribLocation(program, name); + + // Overwrite existing vertex attributes. + attributes[name] = location; + } + } + + public void EnableVertexAttributes() + { + foreach (KeyValuePair attrib in attributes) + GL.EnableVertexAttribArray(attrib.Value); + } + + public void DisableVertexAttributes() + { + foreach (KeyValuePair attrib in attributes) + GL.DisableVertexAttribArray(attrib.Value); + } + + public int GetAttribute(string name) + { + if (string.IsNullOrEmpty(name) || !attributes.ContainsKey(name)) + return -1; + else + return attributes[name]; + } + + private void LoadUniorms(int program) + { + uniforms.Clear(); + + GL.GetProgram(program, GetProgramParameterName.ActiveUniforms, out activeAttributeCount); + for (int i = 0; i < activeAttributeCount; i++) + { + int size = 0; + ActiveUniformType type; + string name = GL.GetActiveUniform(program, i, out size, out type); + int location = GL.GetUniformLocation(program, name); + + // Overwrite existing vertex attributes. + uniforms[name] = location; + } + } + + public void Compile() + { + program = CompileShaders(); + + LoadAttributes(program); + LoadUniorms(program); + OnCompiled(); + + Compiled = true; + } + + public virtual void OnCompiled() { } + + private int CompileShaders() + { + vertexShaderID = GL.CreateShader(ShaderType.VertexShader); + GL.ShaderSource(vertexShaderID, VertexShader); + GL.CompileShader(vertexShaderID); + + fragmentShaderID = GL.CreateShader(ShaderType.FragmentShader); + GL.ShaderSource(fragmentShaderID, FragmentShader); + GL.CompileShader(fragmentShaderID); + + var program = GL.CreateProgram(); + GL.AttachShader(program, vertexShaderID); + GL.AttachShader(program, fragmentShaderID); + GL.LinkProgram(program); + + var info = GL.GetProgramInfoLog(program); + if (!string.IsNullOrWhiteSpace(info)) + Console.WriteLine($"GL.LinkProgram had info log: {info}"); + + GL.DetachShader(program, vertexShaderID); + GL.DetachShader(program, fragmentShaderID); + GL.DeleteShader(vertexShaderID); + GL.DeleteShader(fragmentShaderID); + return program; + } + } +} diff --git a/Switch_Toolbox_Library/OpenGL/Render2D.cs b/Switch_Toolbox_Library/OpenGL/Render2D.cs new file mode 100644 index 00000000..0a49a091 --- /dev/null +++ b/Switch_Toolbox_Library/OpenGL/Render2D.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK.Graphics.OpenGL; +using OpenTK; +using System.Drawing; +using Toolbox.Library.IO; + +namespace Toolbox.Library +{ + public class Render2D + { + public static void DrawRectangle(float width, float height, Vector3 translate, Vector3 rotate, Vector3 scale) + { + GL.PushMatrix(); + + GL.Scale(scale); + GL.Rotate(rotate.X, new Vector3(1, 0, 0)); + GL.Rotate(rotate.Y, new Vector3(0, 1, 0)); + GL.Rotate(rotate.Z, new Vector3(0, 0, 1)); + GL.Translate(translate); + + DrawRectangle(width, height, Color.White, false); + + GL.PopMatrix(); + } + + public static void DrawCircle(Vector2 Position, Color color) + { + GL.PushMatrix(); + GL.Translate(Position.X, Position.Y, 0); + GL.Scale(300,300,1); + + GL.Color4(color); + GL.Begin(PrimitiveType.LineLoop); + for (int i = 0; i <= 300; i++) + { + double angle = 2 * Math.PI * i / 300; + double x = Math.Cos(angle); + double y = Math.Sin(angle); + GL.Vertex2(x, y); + } + GL.End(); + + GL.PopMatrix(); + } + + public static void DrawRectangle(float width, float height, Color color, bool wireframe) + { + if (wireframe) + { + GL.Begin(PrimitiveType.LineLoop); + GL.LineWidth(1); + GL.Color4(color); + GL.Vertex2(-width, -height); + GL.Vertex2(width, -height); + GL.Vertex2(width, height); + GL.Vertex2(-width, height); + GL.End(); + + GL.PopAttrib(); + } + else + { + GL.Begin(PrimitiveType.Quads); + GL.Color4(color); + GL.TexCoord2(-1, -1); + GL.Vertex2(-width, -height); + GL.TexCoord2(0, -1); + GL.Vertex2(width, -height); + GL.TexCoord2(0, 0); + GL.Vertex2(width, height); + GL.TexCoord2(-1, 0); + GL.Vertex2(-width, height); + GL.End(); + } + } + + public static void DrawGrid(Color color) + { + var size = 40; + var amount = 300; + + GL.LineWidth(0.001f); + GL.Color3(color.Darken(20)); + GL.Begin(PrimitiveType.Lines); + + int squareGridCounter = 0; + for (var i = -amount; i <= amount; i++) + { + if (squareGridCounter > 5) + { + squareGridCounter = 0; + GL.LineWidth(33f); + } + else + { + GL.LineWidth(0.001f); + } + + GL.Vertex2(new Vector2(-amount * size, i * size)); + GL.Vertex2(new Vector2(amount * size, i * size)); + GL.Vertex2(new Vector2(i * size, -amount * size)); + GL.Vertex2(new Vector2(i * size, amount * size)); + + squareGridCounter++; + } + GL.End(); + GL.Color3(Color.Transparent); + GL.PopAttrib(); + } + } +} diff --git a/Switch_Toolbox_Library/OpenGL/Viewport2D.cs b/Switch_Toolbox_Library/OpenGL/Viewport2D.cs new file mode 100644 index 00000000..a9b7fa3c --- /dev/null +++ b/Switch_Toolbox_Library/OpenGL/Viewport2D.cs @@ -0,0 +1,202 @@ +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 OpenTK; +using OpenTK.Graphics.OpenGL; +using Toolbox.Library; + +namespace Toolbox.Library.Forms +{ + public class Viewport2D : UserControl + { + public virtual bool UseOrtho { get; set; } = false; + public virtual bool UseGrid { get; set; } = true; + + public Camera2D Camera = new Camera2D(); + + public class Camera2D + { + public Matrix4 ViewMatrix = Matrix4.Identity; + public Matrix4 ModelMatrix = Matrix4.Identity; + + public Matrix4 ModelViewMatrix + { + get + { + return ModelMatrix * ViewMatrix; + } + } + + public float Zoom = 1; + public Vector2 Position; + } + + private GLControl glControl1; + private Color BackgroundColor = Color.FromArgb(40, 40, 40); + + public Viewport2D() + { + glControl1 = new GLControl(); + glControl1.Dock = DockStyle.Fill; + glControl1.MouseDown += glControl1_MouseDown; + glControl1.MouseUp += glControl1_MouseUp; + glControl1.MouseMove += glControl1_MouseMove; + glControl1.Paint += glControl1_Paint; + glControl1.Resize += glControl1_Resize; + Controls.Add(glControl1); + } + + + public void UpdateViewport() { + glControl1.Invalidate(); + } + + private void glControl1_Paint(object sender, PaintEventArgs e) + { + if (!Runtime.OpenTKInitialized) + return; + + glControl1.Context.MakeCurrent(glControl1.WindowInfo); + + RenderEditor(); + SetupScene(); + } + + private void RenderEditor() + { + glControl1.MakeCurrent(); + + GL.Viewport(0, 0, glControl1.Width, glControl1.Height); + GL.MatrixMode(MatrixMode.Projection); + GL.LoadIdentity(); + if (UseOrtho) + { + float halfW = glControl1.Width / 2.0f, halfH = glControl1.Height / 2.0f; + var orthoMatrix = Matrix4.CreateOrthographic(halfW, halfH, -10000, 10000); + GL.LoadMatrix(ref orthoMatrix); + GL.MatrixMode(MatrixMode.Modelview); + Camera.ViewMatrix = orthoMatrix; + } + else + { + var cameraPosition = new Vector3(Camera.Position.X, Camera.Position.Y, -(Camera.Zoom * 500)); + + var perspectiveMatrix = Matrix4.CreateRotationY(90) * Matrix4.CreateTranslation(cameraPosition) * Matrix4.CreatePerspectiveFieldOfView(1.3f, glControl1.Width / glControl1.Height, 0.01f, 100000); + GL.LoadMatrix(ref perspectiveMatrix); + GL.MatrixMode(MatrixMode.Modelview); + Camera.ViewMatrix = perspectiveMatrix; + } + + GL.ClearColor(BackgroundColor); + GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + + if (UseOrtho) + { + GL.PushMatrix(); + GL.Scale(Camera.Zoom, Camera.Zoom, 1); + GL.Translate(Camera.Position.X, Camera.Position.Y, 0); + + Matrix4 scaleMat = Matrix4.CreateScale(Camera.Zoom, Camera.Zoom, 1); + Matrix4 transMat = Matrix4.CreateTranslation(Camera.Position.X, -Camera.Position.Y, 0); + + Camera.ModelMatrix = scaleMat * transMat; + } + } + + private void SetupScene() + { + GL.Enable(EnableCap.Blend); + GL.Enable(EnableCap.AlphaTest); + GL.AlphaFunc(AlphaFunction.Always, 0f); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + GL.Enable(EnableCap.ColorMaterial); + GL.Enable(EnableCap.Texture2D); + GL.BindTexture(TextureTarget.Texture2D, 0); + GL.BlendEquation(BlendEquationMode.FuncAdd); + + if (UseGrid) + Render2D.DrawGrid(BackgroundColor); + + RenderSceme(); + + if (UseOrtho) + GL.PopMatrix(); + + GL.UseProgram(0); + glControl1.SwapBuffers(); + } + + public virtual void RenderSceme() + { + + } + + private Point originMouse; + private bool mouseCameraDown; + + private void glControl1_MouseDown(object sender, MouseEventArgs e) + { + if (Control.ModifierKeys == Keys.Shift && e.Button == MouseButtons.Left || + e.Button == MouseButtons.Middle) + { + originMouse = e.Location; + mouseCameraDown = true; + glControl1.Invalidate(); + } + } + + private void glControl1_MouseUp(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Middle) + { + mouseCameraDown = false; + } + } + + private void glControl1_MouseMove(object sender, MouseEventArgs e) + { + if (mouseCameraDown) + { + var pos = new Vector2(e.Location.X - originMouse.X, e.Location.Y - originMouse.Y); + Camera.Position.X += pos.X; + Camera.Position.Y += pos.Y; + + originMouse = e.Location; + + glControl1.Invalidate(); + } + } + + private void glControl1_Resize(object sender, EventArgs e) + { + glControl1.Invalidate(); + } + + protected override void OnMouseWheel(MouseEventArgs e) + { + base.OnMouseWheel(e); + if (UseOrtho) + { + if (e.Delta > 0 && Camera.Zoom > 0) + Camera.Zoom += 0.1f; + if (e.Delta < 0 && Camera.Zoom < 100 && Camera.Zoom > 0.1) + Camera.Zoom -= 0.1f; + } + else + { + if (e.Delta > 0 && Camera.Zoom > 0.1) + Camera.Zoom -= 0.1f; + if (e.Delta < 0 && Camera.Zoom < 100 && Camera.Zoom > 0) + Camera.Zoom += 0.1f; + } + + glControl1.Invalidate(); + } + } +} diff --git a/Switch_Toolbox_Library/Toolbox_Library.csproj b/Switch_Toolbox_Library/Toolbox_Library.csproj index cf0f3dc9..bce4ef82 100644 --- a/Switch_Toolbox_Library/Toolbox_Library.csproj +++ b/Switch_Toolbox_Library/Toolbox_Library.csproj @@ -392,6 +392,12 @@ + + + + UserControl + + diff --git a/Toolbox/Lib/SARCExt.dll b/Toolbox/Lib/SARCExt.dll index 627c86cdbba15632e88aa12e593ee74045af0f8f..e998f86b5ad7f1e80f5ec2d4219c688b4e162bcb 100644 GIT binary patch delta 5833 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 CUtVhf delta 5841 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 V?$#Cy{}yO<_HO+#;S1Er{{sP`Wx)Ud diff --git a/Toolbox/Lib/SARCExt.pdb b/Toolbox/Lib/SARCExt.pdb index 822cc2c972febc520bb7e7f1ead243135147899b..c0175513ea73b9a1c89b7d42a223619b0136a426 100644 GIT binary patch delta 186 zcmZqp!`$$Pc>@cVgy8Ebv5X81442h4*3`uJIW3*6&35>S2+w92E*&9}MUVbEJ$DUu zS~a0Ip);f1Ks?#)!$!v?jGN>*1UQ6DHx&C-US*t|=wdM0LC=TfxkZ-b<_UTeGgw6! z&6spIt4(j@@cV#2oE~F^mih40&h0HkG{Oaqjh6vF*smhkl!7xO9X>UTV+sFPRls z{5PTd|HgCIG~Z9WYP8XD3F9U?4grpxSEg67zPQ3TInl*nvV)!v%SGS#FPkUmP0U~w zWi)5f+pIRdk(1L=jFG8fH&dhe<_!zJF)_+cUcPuequS>1C6oCX4K}~ttgOb#->1M3 Ul%dGLuvz@pTTwht`tXDo0P2xTf&c&j diff --git a/Toolbox/Shader/Drawing2D/KCL.frag b/Toolbox/Shader/Drawing2D/KCL.frag new file mode 100644 index 00000000..c593fbff --- /dev/null +++ b/Toolbox/Shader/Drawing2D/KCL.frag @@ -0,0 +1,13 @@ +#version 330 + +in vec3 normal; +in vec3 color; +in vec3 position; + +out vec4 FragColor; + +void main() +{ + vec3 displayNormal = (normal.xyz * 0.5) + 0.5; + FragColor = vec4(displayNormal.rgb,1); +} diff --git a/Toolbox/Shader/Drawing2D/KCL.vert b/Toolbox/Shader/Drawing2D/KCL.vert new file mode 100644 index 00000000..1f762afa --- /dev/null +++ b/Toolbox/Shader/Drawing2D/KCL.vert @@ -0,0 +1,21 @@ +#version 330 + +in vec3 vPosition; +in vec3 vNormal; +in vec3 vColor; + +out vec3 normal; +out vec3 color; +out vec3 position; + +uniform mat4 modelViewMatrix; +uniform mat4 modelMatrix; + +void main() +{ + normal = vNormal; + color = vColor; + position = vPosition; + + gl_Position = modelMatrix * modelViewMatrix * vec4(vPosition.xyz, 1.0); +} \ No newline at end of file diff --git a/Toolbox/Toolbox.csproj b/Toolbox/Toolbox.csproj index 773fdfde..81c360c6 100644 --- a/Toolbox/Toolbox.csproj +++ b/Toolbox/Toolbox.csproj @@ -227,6 +227,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/UpgradeLog.htm b/UpgradeLog.htm new file mode 100644 index 0000000000000000000000000000000000000000..a3ef1fbb736af340ec9b8ce44fcf7df8c3194873 GIT binary patch literal 29036 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 Z&f+6U&(tVN6JL|(@n|yqv)|k3{{Ty@6}$id literal 0 HcmV?d00001