From dab56be662dfd1df7bd32698b977abeb6327d681 Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Sun, 6 Oct 2024 19:03:36 +0200 Subject: [PATCH] Move Debug & Camera control into SceneViewport --- PCK-Studio/Rendering/CubeMesh.cs | 20 +- PCK-Studio/Rendering/CubeMeshCollection.cs | 72 ++-- PCK-Studio/Rendering/SceneViewport.cs | 336 +++++++++++++++-- PCK-Studio/Rendering/SkinRenderer.Designer.cs | 7 +- PCK-Studio/Rendering/SkinRenderer.cs | 354 +++--------------- .../shader/texturedCubeFragmentShader.glsl | 4 +- .../shader/texturedCubeGeometryShader.glsl | 16 +- .../shader/texturedCubeVertexShader.glsl | 6 +- 8 files changed, 431 insertions(+), 384 deletions(-) diff --git a/PCK-Studio/Rendering/CubeMesh.cs b/PCK-Studio/Rendering/CubeMesh.cs index e63d3c51..94b2899f 100644 --- a/PCK-Studio/Rendering/CubeMesh.cs +++ b/PCK-Studio/Rendering/CubeMesh.cs @@ -26,8 +26,6 @@ namespace PckStudio.Rendering { internal class CubeMesh : GenericMesh { - internal bool ShouldRender { get; } = true; - private Cube _cube; public Vector3 Center => _cube.Center; @@ -53,7 +51,7 @@ namespace PckStudio.Rendering 22, 23, 20 ]; - public override Matrix4 Transform => Matrix4.CreateScale(1f, -1f, -1f); + public override Matrix4 Transform => Matrix4.Identity; internal static VertexBufferLayout VertexBufferLayout { get; } = new VertexBufferLayout().Add(ShaderDataType.Float3).Add(ShaderDataType.Float2); @@ -62,25 +60,24 @@ namespace PckStudio.Rendering } private CubeMesh(string name, Cube cube, bool visible) - : base(name, OpenTK.Graphics.OpenGL.PrimitiveType.Triangles, VertexBufferLayout) + : base(name, visible, OpenTK.Graphics.OpenGL.PrimitiveType.Triangles, VertexBufferLayout) { - ShouldRender = visible; _cube = cube; } public CubeMesh SetName(string name) { _ = name ?? throw new ArgumentNullException(nameof(name)); - return new CubeMesh(name, _cube, ShouldRender); + return new CubeMesh(name, _cube, Visible); } public CubeMesh SetCube(Cube cube) { _ = cube ?? throw new ArgumentNullException(nameof(cube)); - return new CubeMesh(Name, cube, ShouldRender); + return new CubeMesh(Name, cube, Visible); } - - public CubeMesh SetVisible(bool visible) => new CubeMesh(Name, _cube, visible); + + public override GenericMesh SetVisible(bool visible) => new CubeMesh(Name, _cube, visible); public Cube GetCube() => _cube; @@ -135,10 +132,5 @@ namespace PckStudio.Rendering } internal override IEnumerable GetIndices() => IndicesData; - - public override string ToString() - { - return base.ToString() + $" Render={ShouldRender}"; - } } } \ No newline at end of file diff --git a/PCK-Studio/Rendering/CubeMeshCollection.cs b/PCK-Studio/Rendering/CubeMeshCollection.cs index c946eee0..f0a8b551 100644 --- a/PCK-Studio/Rendering/CubeMeshCollection.cs +++ b/PCK-Studio/Rendering/CubeMeshCollection.cs @@ -37,39 +37,28 @@ namespace PckStudio.Rendering } } - internal class CubeMeshCollection : GenericMesh, ICollection + internal class CubeMeshCollection : GenericMesh, ICollection> { - private List cubes; + private List> cubes; + private Dictionary subCollection; public bool FlipZMapping { get => _flipZMapping; - set - { - _flipZMapping = value; - //foreach (Cube cube in cubes) - //{ - // cube.FlipZMapping = FlipZMapping; - //} + set => _flipZMapping = value; } - } - public Vector3 Translation { get; } + 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 - { - if (value != _offset) - { - _offset = value; + set => _offset = value; } - } - } - public override Matrix4 Transform => Matrix4.CreateTranslation(Translation + _offset) * Matrix4.CreateScale(1f, -1f, -1f); + public override Matrix4 Transform => (Matrix4.CreateRotationX(MathHelper.DegreesToRadians(Rotation.X)) * Matrix4.CreateRotationY(MathHelper.DegreesToRadians(Rotation.Y)) * Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(Rotation.Z))).Pivoted(Translation + _offset, Pivot); public int Count => cubes.Count; @@ -77,32 +66,46 @@ namespace PckStudio.Rendering private bool _flipZMapping = false; - internal CubeMeshCollection(string name) : base(name, PrimitiveType.Triangles, CubeMesh.VertexBufferLayout) + internal CubeMeshCollection(string name, bool visible = true) : base(name, visible, PrimitiveType.Triangles, CubeMesh.VertexBufferLayout) { - cubes = new List(5); + cubes = new List>(5); + subCollection = new Dictionary(); } - internal CubeMeshCollection(string name, Vector3 translation, Vector3 pivot) + internal 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; } internal override IEnumerable GetVertices() - => cubes.Where(c => c.ShouldRender).SelectMany(c => c.GetVertices()); + => cubes.Where(c => c.Visible).SelectMany(c => + c.GetVertices().Select(vertex => new TextureVertex(Vector3.TransformPosition(vertex.Position, c.Transform), vertex.TexPosition)) + ); internal override IEnumerable GetIndices() { int offset = 0; - IEnumerable selector(CubeMesh c) + 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.ShouldRender).SelectMany(selector); + return cubes.Where(c => c.Visible).SelectMany(selector); } internal void Add(Vector3 position, Vector3 size, Vector2 uv, float inflate = 0f, bool mirrorTexture = false) @@ -117,6 +120,19 @@ namespace PckStudio.Rendering Add(new CubeMesh(cube).SetName(name)); } + 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); + } + + internal CubeMeshCollection GetCollection(string collectionName) + { + _ = collectionName ?? throw new ArgumentNullException(nameof(collectionName)); + return ContainsCollection(collectionName) ? subCollection[collectionName] : null; + } + internal void Remove(int index) { if (!cubes.IndexInRange(index)) @@ -130,7 +146,9 @@ namespace PckStudio.Rendering if (!cubes.IndexInRange(index)) throw new IndexOutOfRangeException(); - cubes[index] = cubes[index].SetCube(new Cube(position, size, uv, inflate, mirrorTexture, FlipZMapping)); + + if (cubes[index] is CubeMesh cubeMesh) + cubes[index] = cubeMesh.SetCube(new Cube(position, size, uv, inflate, mirrorTexture, FlipZMapping)); } internal Vector3 GetCenter(int index) @@ -138,7 +156,7 @@ namespace PckStudio.Rendering if (!cubes.IndexInRange(index)) throw new IndexOutOfRangeException(); - return cubes[index].Center + Offset; + return cubes[index] is CubeMesh c ? c.Center + Offset : Vector3.Zero; } internal BoundingBox GetCubeBoundingBox(int index) diff --git a/PCK-Studio/Rendering/SceneViewport.cs b/PCK-Studio/Rendering/SceneViewport.cs index d855c86f..eecca02c 100644 --- a/PCK-Studio/Rendering/SceneViewport.cs +++ b/PCK-Studio/Rendering/SceneViewport.cs @@ -24,19 +24,22 @@ SOFTWARE. https://github.com/KareemMAX/Minecraft-Skiner https://github.com/KareemMAX/Minecraft-Skiner/blob/master/src/Minecraft%20skiner/UserControls/Renderer3D.vb */ -#define USE_FRAMEBUFFER +//#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.Extensions; using PckStudio.Properties; using PckStudio.Rendering.Camera; using PckStudio.Rendering.Shader; -using PckStudio.Rendering.Texture; namespace PckStudio.Rendering { @@ -55,16 +58,39 @@ namespace PckStudio.Rendering } } + 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) { - SwapBuffers(); + if (IsHandleCreated && !IsDisposed) + SwapBuffers(); } + [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 = 120; private Timer _timer; - private Stopwatch _stopwatch; private bool _initialized; private ShaderLibrary _shaderLibrary; @@ -75,6 +101,20 @@ namespace PckStudio.Rendering 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; @@ -93,25 +133,30 @@ namespace PckStudio.Rendering }; #endif - public SceneViewport() : base() + public SceneViewport(float fov, Vector3 camareaPosition = default) +#if DEBUG + : base(GraphicsMode.Default, 4, 6, GraphicsContextFlags.Debug) +#else + : base() +#endif { VSync = true; - _stopwatch = new Stopwatch(); _timer = new Timer(); _timer.Tick += TimerTick; + + RefreshRate = _refreshRate; + Camera = new PerspectiveCamera(fov, camareaPosition); + _shaderLibrary = new ShaderLibrary(); + if (!DesignMode) { _timer.Start(); - _stopwatch.Start(); + InitializeInternal(); } - - RefreshRate = _refreshRate; - Camera = new PerspectiveCamera(60f, new Vector3(0f, 0f, 0f)); - _shaderLibrary = new ShaderLibrary(); _initialized = false; } - protected void Initialize() + private void InitializeInternal() { if (_initialized) { @@ -119,6 +164,8 @@ namespace PckStudio.Rendering return; } MakeCurrent(); + Trace.TraceInformation(GL.GetString(StringName.Version)); + GL.DebugMessageCallback(DebugProc, IntPtr.Zero); AddShader("Internal_colorShader", ShaderProgram.Create(Resources.plainColorVertexShader, Resources.plainColorFragmentShader)); var vao = new VertexArray(); VertexBufferLayout layout = new VertexBufferLayout(); @@ -144,27 +191,43 @@ namespace PckStudio.Rendering GLErrorCheck(); } #endif - + InitializeDebugComponents(); + InitializeDebugShaders(); _initialized = true; } + 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(); - _stopwatch.Stop(); _timer.Dispose(); + MakeCurrent(); + foreach (VertexArray va in _meshTypeVertexArray.Values) + { + va.Dispose(); + } + _meshIndexBuffer.Dispose(); + _boundingBoxDrawContext.IndexBuffer.Dispose(); + _boundingBoxDrawContext.VertexArray.Dispose(); + _shaderLibrary.Dispose(); } - MakeCurrent(); - foreach (VertexArray va in _meshTypeVertexArray.Values) - { - va.Dispose(); - } - _meshIndexBuffer.Dispose(); - _boundingBoxDrawContext.IndexBuffer.Dispose(); - _boundingBoxDrawContext.VertexArray.Dispose(); - _shaderLibrary.Dispose(); _initialized = false; base.Dispose(disposing); } @@ -175,8 +238,12 @@ namespace PckStudio.Rendering protected ShaderProgram GetShader(string shaderName) => _shaderLibrary.GetShader(shaderName); - protected void DrawMesh(GenericMesh mesh, ShaderProgram shader) where T : struct + 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(); @@ -213,6 +280,17 @@ namespace PckStudio.Rendering Renderer.SetLineWidth(1f); } + protected BoundingBox GetBounds(IEnumerable boundingBoxes) + { + return boundingBoxes.Aggregate((a, b) => new BoundingBox(Vector3.ComponentMin(a.Start, b.Start), Vector3.ComponentMax(a.End, b.End))); + } + + void DebugProc(DebugSource source, DebugType type, int id, DebugSeverity severity, int length, IntPtr message, IntPtr userParam) + { + string dbgMessage = Marshal.PtrToStringAnsi(message, length); + + Debug.WriteLine($"{source} {type} {severity}: {dbgMessage}"); + } [Conditional("DEBUG")] protected void GLErrorCheck() @@ -330,6 +408,9 @@ namespace PckStudio.Rendering long tick = DateTime.UtcNow.Ticks - _lastTick; Refresh(); _lastTick = DateTime.UtcNow.Ticks; + if (!HasValidContext) + MakeCurrent(); + RenderDebug(); OnUpdate(sender, TimeSpan.FromTicks(tick)); } @@ -345,5 +426,212 @@ namespace PckStudio.Rendering } 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) + { + ReleaseMouse(); + base.OnMouseUp(e); + } + + 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 + ShaderProgram colorShader = GetShader("Internal_colorShader"); + Matrix4 viewProjection = Camera.GetViewProjection(); + colorShader.SetUniformMat4("ViewProjection", ref viewProjection); + if (d_showFocalPoint) + { + GL.BlendFunc(BlendingFactor.SrcColor, BlendingFactor.SrcColor); + GL.DepthFunc(DepthFunction.Always); + GL.DepthMask(false); + GL.Enable(EnableCap.PointSmooth); + colorShader.Bind(); + Matrix4 transform = Matrix4.CreateTranslation(Camera.FocalPoint).Inverted(); + colorShader.SetUniformMat4("Transform", ref transform); + colorShader.SetUniform1("intensity", 0.75f); + colorShader.SetUniform4("baseColor", Color.DeepPink); + GL.PointSize(5f); + Renderer.Draw(colorShader, d_debugPointDrawContext); + GL.PointSize(1f); + GL.DepthMask(true); + GL.DepthFunc(DepthFunction.Less); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + } + if (d_showDirectionArrows) + { + GL.BlendFunc(BlendingFactor.SrcColor, BlendingFactor.SrcColor); + GL.DepthFunc(DepthFunction.Always); + GL.DepthMask(false); + GL.Enable(EnableCap.LineSmooth); + colorShader.Bind(); + + 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("baseColor", Color.White); + + Renderer.SetLineWidth(2f); + + Renderer.Draw(colorShader, d_debugLineDrawContext); + + Renderer.SetLineWidth(1f); + + GL.DepthMask(true); + GL.DepthFunc(DepthFunction.Less); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + } + d_debugLabel.Text = Camera.ToString(); +#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 index c04b2e86..3403024a 100644 --- a/PCK-Studio/Rendering/SkinRenderer.Designer.cs +++ b/PCK-Studio/Rendering/SkinRenderer.Designer.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Diagnostics; namespace PckStudio.Rendering { diff --git a/PCK-Studio/Rendering/SkinRenderer.cs b/PCK-Studio/Rendering/SkinRenderer.cs index 7cf282c8..c33cc847 100644 --- a/PCK-Studio/Rendering/SkinRenderer.cs +++ b/PCK-Studio/Rendering/SkinRenderer.cs @@ -85,13 +85,25 @@ namespace PckStudio.Rendering [Category("Appearance")] public Color HighlightlingColor { get; set; } = Color.Aqua; - public float MouseSensetivity { get; set; } = 0.01f; public int SelectedIndex { - get => selectedIndex; + get => selectedIndices.Length > 0 ? selectedIndices[0] : -1; set { - selectedIndex = value; + 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(); } @@ -172,33 +184,12 @@ namespace PckStudio.Rendering }; private GuidelineMode guidelineMode { get; set; } = GuidelineMode.None; - private int selectedIndex = -1; + private int[] selectedIndices = Array.Empty(); 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 bool IsMouseHidden - { - get => !Cursor.IsVisible(); - set - { - if (value) - { - Cursor.Hide(); - return; - } - Cursor.Show(); - } - } - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public bool LockMousePosition { get; set; } = false; - - private Point PreviousMouseLocation; - private Point CurrentMouseLocation; - private VertexBufferLayout plainColorVertexBufferLayout; private SkinANIM _anim; @@ -255,7 +246,7 @@ namespace PckStudio.Rendering private bool initialized = false; - public SkinRenderer() : base() + public SkinRenderer() : base(fov: 60f) { InitializeSkinData(); InitializeCapeData(); @@ -278,7 +269,6 @@ namespace PckStudio.Rendering InitializeArmorData(); InitializeCamera(); InitializeComponent(); - InitializeDebug(); ANIM ??= new SkinANIM(SkinAnimMask.RESOLUTION_64x64); ModelData = new ObservableCollection(); @@ -294,8 +284,6 @@ namespace PckStudio.Rendering InitializeShaders(); Renderer.SetClearColor(BackColor); GLErrorCheck(); - base.Initialize(); - GLErrorCheck(); initialized = true; } @@ -399,10 +387,6 @@ namespace PckStudio.Rendering private void InitializeShaders() { MakeCurrent(); - - Trace.TraceInformation(GL.GetString(StringName.Version)); - - plainColorVertexBufferLayout = new VertexBufferLayout(); plainColorVertexBufferLayout.Add(ShaderDataType.Float3); plainColorVertexBufferLayout.Add(ShaderDataType.Float4); @@ -415,7 +399,7 @@ namespace PckStudio.Rendering new ShaderSource(ShaderType.GeometryShader, Resources.texturedCubeGeometryShader) ); cubeShader.Bind(); - cubeShader.SetUniform1("u_Texture", 0); + cubeShader.SetUniform1("Texture", 0); cubeShader.Validate(); AddShader("CubeShader", cubeShader); GLErrorCheck(); @@ -597,8 +581,6 @@ namespace PckStudio.Rendering GLErrorCheck(); } - - InitializeDebugShaders(); } private DrawContext GetGuidelineDrawContext() @@ -772,13 +754,6 @@ namespace PckStudio.Rendering { switch (keyData) { -#if DEBUG - case Keys.Escape: - ReleaseMouse(); - var point = new Point(Parent.Location.X + Location.X, Parent.Location.Y + Location.Y); - debugContextMenuStrip1.Show(point); - return true; -#endif case Keys.F3: showWireFrame = !showWireFrame; return true; @@ -867,12 +842,12 @@ namespace PckStudio.Rendering if (showWireFrame) GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); - Matrix4 transform = Matrix4.Identity; + Matrix4 transform = Matrix4.CreateScale(1f, -1f, -1f); ShaderProgram cubeShader = GetShader("CubeShader"); cubeShader.Bind(); - cubeShader.SetUniformMat4("u_ViewProjection", ref viewProjection); - cubeShader.SetUniform2("u_TexSize", TextureSize); + cubeShader.SetUniformMat4("ViewProjection", ref viewProjection); + cubeShader.SetUniform2("TexSize", TextureSize); skinTexture.Bind(); @@ -923,7 +898,7 @@ namespace PckStudio.Rendering if (_capeImage is not null) { - cubeShader.SetUniform2("u_TexSize", new Vector2(64, 32)); + cubeShader.SetUniform2("TexSize", new Vector2(64, 32)); capeTexture.Bind(); // Defines minimum Angle(in Degrees) of the cape float capeMinimumRotationAngle = 7.5f; @@ -942,7 +917,7 @@ namespace PckStudio.Rendering if (ShowArmor && !ANIM.GetFlag(SkinAnimFlag.ALL_ARMOR_DISABLED)) { armorTexture.Bind(); - cubeShader.SetUniform2("u_TexSize", new Vector2(64, 64)); + 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, transform); @@ -991,14 +966,13 @@ namespace PckStudio.Rendering GL.DepthFunc(DepthFunction.Less); } - if (ModelData.IndexInRange(SelectedIndex)) + BoundingBox boundingBox = GetSelectedBoundingArea(); + + Matrix4 boundingBoxTransform = transform; + + if (SelectedIndices.Length == 1 && ModelData.IndexInRange(SelectedIndices[0])) { - SkinBOX box = ModelData[SelectedIndex]; - - float inflate = autoInflateOverlayParts && box.IsOverlayPart() ? box.Type == "HEADWEAR" ? OverlayScale * 2 : OverlayScale : 0f; - Cube cube = box.ToCube(inflate); - - BoundingBox cubeBoundingBox = cube.GetBoundingBox(); + SkinBOX box = ModelData[SelectedIndices[0]]; if (meshStorage.ContainsKey(box.Type)) { @@ -1024,17 +998,14 @@ namespace PckStudio.Rendering return Matrix4.Identity; } } - - Matrix4 bbTransform = GetGroupTransform(box.Type); - bbTransform *= cubeMesh.Transform; - bbTransform *= transform; - GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.SrcColor); - DrawBoundingBox(bbTransform, cubeBoundingBox, HighlightlingColor); - GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + boundingBoxTransform = GetGroupTransform(box.Type) * boundingBoxTransform; } } - } + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.SrcColor); + DrawBoundingBox(boundingBoxTransform, boundingBox, HighlightlingColor); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + } // Ground plane { @@ -1052,70 +1023,31 @@ namespace PckStudio.Rendering GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); } - // Debug - RenderDebug(); FramebufferEnd(); } - protected override void OnMouseMove(MouseEventArgs e) + private BoundingBox GetSelectedBoundingArea() { - 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) + IEnumerable GetBoundingBoxesFromSelectedIndices(IEnumerable selectedIndices) { - 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) - { - ReleaseMouse(); - base.OnMouseUp(e); - } - - private 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; + 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.Transform); + } + yield break; } + return SelectedIndices.Length >= 1 ? GetBounds(GetBoundingBoxesFromSelectedIndices(SelectedIndices)) : BoundingBox.Empty; } private void RenderBodyPart(ShaderProgram shader, Matrix4 partsMatrix, Matrix4 globalMatrix, params string[] partNames) @@ -1129,8 +1061,7 @@ namespace PckStudio.Rendering private void RenderPart(ShaderProgram shader, GenericMesh mesh, Matrix4 partMatrix, Matrix4 globalMatrix) where T : struct { Matrix4 transform = partMatrix * mesh.Transform * globalMatrix; - shader.SetUniformMat4("u_Transform", ref transform); - DrawMesh(mesh, shader); + DrawMesh(mesh, shader, transform); } protected override void OnUpdate(object sender, TimeSpan timestep) @@ -1165,182 +1096,5 @@ namespace PckStudio.Rendering AddCustomModelPart(item); } } - - [Conditional("DEBUG")] - private void InitializeDebugShaders() - { -#if DEBUG - // 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 - ShaderProgram colorShader = GetShader("PlainColorShader"); - Matrix4 viewProjection = Camera.GetViewProjection(); - colorShader.SetUniformMat4("ViewProjection", ref viewProjection); - if (d_showFocalPoint) - { - GL.BlendFunc(BlendingFactor.DstAlpha, BlendingFactor.OneMinusSrcAlpha); - GL.DepthFunc(DepthFunction.Always); - GL.DepthMask(false); - GL.Enable(EnableCap.PointSmooth); - colorShader.Bind(); - Matrix4 transform = Matrix4.CreateTranslation(Camera.FocalPoint).Inverted(); - colorShader.SetUniformMat4("Transform", ref transform); - colorShader.SetUniform1("intensity", 0.75f); - colorShader.SetUniform4("baseColor", Color.DeepPink); - GL.PointSize(5f); - Renderer.Draw(colorShader, d_debugPointDrawContext); - GL.PointSize(1f); - GL.DepthMask(true); - GL.DepthFunc(DepthFunction.Less); - GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); - } - if (d_showDirectionArrows) - { - GL.BlendFunc(BlendingFactor.DstAlpha, BlendingFactor.OneMinusSrcAlpha); - GL.DepthFunc(DepthFunction.Always); - GL.DepthMask(false); - GL.Enable(EnableCap.LineSmooth); - colorShader.Bind(); - - 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("baseColor", Color.White); - - Renderer.SetLineWidth(2f); - - Renderer.Draw(colorShader, d_debugLineDrawContext); - - Renderer.SetLineWidth(1f); - - GL.DepthMask(true); - GL.DepthFunc(DepthFunction.Less); - GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); - } - d_debugLabel.Text = Camera.ToString(); -#endif - } - - [Conditional("DEBUG")] - private void InitializeDebug() - { -#if DEBUG - reToolStripMenuItem = new ToolStripMenuItem(); - debugContextMenuStrip1 = new ContextMenuStrip(this.components); - guidelineModeToolStripMenuItem = new ToolStripMenuItem(); - debugContextMenuStrip1.SuspendLayout(); - SuspendLayout(); - // - // contextMenuStrip1 - // - debugContextMenuStrip1.Items.AddRange(new ToolStripItem[] { - reToolStripMenuItem, - guidelineModeToolStripMenuItem}); - debugContextMenuStrip1.Name = "contextMenuStrip1"; - debugContextMenuStrip1.Size = new Size(159, 48); - // - // reToolStripMenuItem - // - reToolStripMenuItem.Name = "reToolStripMenuItem"; - reToolStripMenuItem.Size = new Size(158, 22); - reToolStripMenuItem.Text = "Re-Init"; - reToolStripMenuItem.Click += new EventHandler(this.reInitToolStripMenuItem_Click); - // - // guidelineModeToolStripMenuItem - // - guidelineModeToolStripMenuItem.Name = "guidelineModeToolStripMenuItem"; - guidelineModeToolStripMenuItem.Size = new Size(158, 22); - guidelineModeToolStripMenuItem.Text = "Guideline Mode"; - guidelineModeToolStripMenuItem.Click += new EventHandler(this.guidelineModeToolStripMenuItem_Click); - // - // 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 ToolStripMenuItem reToolStripMenuItem; - private ContextMenuStrip debugContextMenuStrip1; - private ToolStripMenuItem guidelineModeToolStripMenuItem; - - private void reInitToolStripMenuItem_Click(object sender, EventArgs e) - { - ReInitialzeSkinData(); - MakeCurrent(); - } - - private void guidelineModeToolStripMenuItem_Click(object sender, EventArgs e) - { - if (!Enum.IsDefined(typeof(GuidelineMode), ++guidelineMode)) - { - guidelineMode = GuidelineMode.None; - } - guidelineModeToolStripMenuItem.Text = $"Guideline Mode: {guidelineMode}"; - } -#endif } } \ No newline at end of file diff --git a/PCK-Studio/Resources/shader/texturedCubeFragmentShader.glsl b/PCK-Studio/Resources/shader/texturedCubeFragmentShader.glsl index 81c18ca5..66a1b9dc 100644 --- a/PCK-Studio/Resources/shader/texturedCubeFragmentShader.glsl +++ b/PCK-Studio/Resources/shader/texturedCubeFragmentShader.glsl @@ -2,12 +2,12 @@ layout(location = 0) out vec4 color; -uniform sampler2D u_Texture; +uniform sampler2D Texture; in vec2 o_TillingFactor; in vec2 o_TexCoord; void main() { - color = texture(u_Texture, o_TexCoord * o_TillingFactor); + color = texture(Texture, o_TexCoord * o_TillingFactor); }; \ No newline at end of file diff --git a/PCK-Studio/Resources/shader/texturedCubeGeometryShader.glsl b/PCK-Studio/Resources/shader/texturedCubeGeometryShader.glsl index 944aaee0..a84094f9 100644 --- a/PCK-Studio/Resources/shader/texturedCubeGeometryShader.glsl +++ b/PCK-Studio/Resources/shader/texturedCubeGeometryShader.glsl @@ -3,7 +3,7 @@ layout (triangles) in; layout (triangle_strip, max_vertices=3) out; -uniform vec2 u_TexSize; +uniform vec2 TexSize; out vec2 o_TexCoord; out vec2 o_TillingFactor; @@ -16,32 +16,32 @@ in geometryData void FixUV() { bool isXBad = - dataIn[0].TexCoord.x >= u_TexSize.x && - dataIn[1].TexCoord.x >= u_TexSize.x && - dataIn[2].TexCoord.x >= u_TexSize.x; + 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, u_TexSize.x); + 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, u_TexSize.x); + 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, u_TexSize.x); + o_TexCoord.x = mod(o_TexCoord.x, TexSize.x); EmitVertex(); } void main() { - o_TillingFactor = 1.0 / u_TexSize; + 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 index dafde5c4..1e8c9114 100644 --- a/PCK-Studio/Resources/shader/texturedCubeVertexShader.glsl +++ b/PCK-Studio/Resources/shader/texturedCubeVertexShader.glsl @@ -3,8 +3,8 @@ layout(location = 0) in vec3 vertexPosition; layout(location = 1) in vec2 texCoord; -uniform mat4 u_ViewProjection; -uniform mat4 u_Transform; +uniform mat4 ViewProjection; +uniform mat4 Transform; out geometryData { @@ -14,5 +14,5 @@ out geometryData void main() { dataOut.TexCoord = texCoord; - gl_Position = u_ViewProjection * u_Transform * vec4(vertexPosition, 1.0); + gl_Position = ViewProjection * Transform * vec4(vertexPosition, 1.0); }; \ No newline at end of file