Switch-Toolbox/Switch_Toolbox_Library/OpenGL/Viewport2D.cs
KillzXGaming 8939687f6a Update files.
Load vertex positions for layouts in rectangle class. This will be used for proper rotation adjusting.
Add latest muunt editor files.
Add somewhat functional mk8 camera bin editor. Points can be moved around. The map orientation determines the position of the icons to map over the model.
Fix window content UV map for layouts.
Add 2D KCL renderer for top down KCL preview for both muunt and camera editors.
2019-10-26 20:28:56 -04:00

400 lines
13 KiB
C#

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;
using Toolbox.Library.OpenGL2D;
namespace Toolbox.Library.Forms
{
public class Viewport2D : UserControl
{
public virtual float PreviewScale => 1f;
public virtual bool UseOrtho { get; set; } = true;
public virtual bool UseGrid { get; set; } = true;
public Camera2D Camera = new Camera2D();
public class Camera2D
{
public Matrix4 ViewMatrix = Matrix4.Identity;
public Matrix4 ProjectionMatrix = Matrix4.Identity;
public Matrix4 ModelViewMatrix
{
get
{
return ViewMatrix * ProjectionMatrix;
}
}
public float Zoom = 1;
public Vector2 Position;
}
private GLControl glControl1;
private Color BackgroundColor = Color.FromArgb(40, 40, 40);
private List<IPickable2DObject> SelectedObjects = new List<IPickable2DObject>();
private PickAction pickAction = PickAction.None;
private PickAxis pickAxis = PickAxis.All;
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.ProjectionMatrix = orthoMatrix;
Matrix4 scaleMat = Matrix4.CreateScale(Camera.Zoom * PreviewScale, Camera.Zoom * PreviewScale, 1);
Matrix4 transMat = Matrix4.CreateTranslation(Camera.Position.X, Camera.Position.Y, 0);
Camera.ViewMatrix = scaleMat * transMat;
}
else
{
var cameraPosition = new Vector3(Camera.Position.X, Camera.Position.Y, -(Camera.Zoom * 500));
var perspectiveMatrix = Matrix4.CreatePerspectiveFieldOfView(1.3f, glControl1.Width / glControl1.Height, 0.01f, 100000);
GL.LoadMatrix(ref perspectiveMatrix);
GL.MatrixMode(MatrixMode.Modelview);
Camera.ViewMatrix = Matrix4.CreateTranslation(cameraPosition);
Camera.ProjectionMatrix = perspectiveMatrix;
GL.LoadMatrix(ref Camera.ViewMatrix);
}
GL.ClearColor(BackgroundColor);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
if (UseOrtho)
{
GL.PushMatrix();
GL.Scale(Camera.Zoom * PreviewScale, Camera.Zoom * PreviewScale, 1);
GL.Translate(Camera.Position.X, Camera.Position.Y, 0);
}
}
public virtual List<IPickable2DObject> GetPickableObjects()
{
return new List<IPickable2DObject>();
}
private List<IPickable2DObject> SearchHit(float X, float Y)
{
List<IPickable2DObject> picks = new List<IPickable2DObject>();
foreach (var pickObj in GetPickableObjects())
{
if (pickObj.IsHit(X, Y))
picks.Add(pickObj);
}
return picks;
}
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 (showSelectionBox)
{
GL.Disable(EnableCap.DepthTest);
GL.Begin(PrimitiveType.LineLoop);
GL.Color4(Color.Red);
GL.Vertex2(SelectionBox.LeftPoint, SelectionBox.BottomPoint);
GL.Vertex2(SelectionBox.RightPoint, SelectionBox.BottomPoint);
GL.Vertex2(SelectionBox.RightPoint, SelectionBox.TopPoint);
GL.Vertex2(SelectionBox.LeftPoint, SelectionBox.TopPoint);
GL.End();
GL.Enable(EnableCap.DepthTest);
}
if (UseOrtho)
GL.PopMatrix();
GL.UseProgram(0);
glControl1.SwapBuffers();
}
private STRectangle SelectionBox;
private bool showSelectionBox = false;
private void DrawSelectionBox(Point point1, Point point2)
{
SelectedObjects.Clear();
int left = point1.X;
int right = point2.X;
int top = point1.Y;
int bottom = point2.Y;
//Determine each point direction to see what is left/right/top/bottom
if (bottom > top)
{
top = point2.Y;
bottom = point1.Y;
}
if (left > right)
{
right = point1.X;
left = point2.X;
}
showSelectionBox = true;
SelectionBox = new STRectangle(left, right, top, bottom);
SetupScene();
}
public virtual void RenderSceme()
{
}
private Point pickOriginMouse;
private Point originMouse;
private bool mouseCameraDown;
private bool isPicked;
private bool mouseDown = false;
private Vector2 GetMouseCoords(Point screenMouse)
{
RenderEditor();
var coords = OpenGLHelper.convertScreenToWorldCoords(screenMouse.X, screenMouse.Y);
GL.PopMatrix();
return new Vector2(coords.X, coords.Y);
}
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();
}
else if (e.Button == MouseButtons.Left)
{
mouseDown = true;
var mouseCoords = GetMouseCoords(e.Location);
var picks = SearchHit(mouseCoords.X, mouseCoords.Y);
if (picks.Count > 0)
{
if (!SelectedObjects.Contains(picks[0]))
{
if (Control.ModifierKeys != Keys.Control)
UnselectAll();
SelectedObjects.Add(picks[0]);
picks[0].IsSelected = true;
}
pickAction = PickAction.Translate;
isPicked = true;
}
else if (Control.ModifierKeys != Keys.Control)
UnselectAll();
pickOriginMouse = e.Location;
glControl1.Invalidate();
}
}
private void glControl1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Middle)
{
pickAction = PickAction.None;
mouseCameraDown = false;
mouseDown = false;
isPicked = false;
showSelectionBox = false;
glControl1.Invalidate();
}
}
private void UnselectAll()
{
foreach (var pick in SelectedObjects)
pick.IsSelected = false;
SelectedObjects.Clear();
}
private void glControl1_MouseMove(object sender, MouseEventArgs e)
{
var mouseCoords = GetMouseCoords(e.Location);
var picks = SearchHit(mouseCoords.X, mouseCoords.Y);
if (picks.Count > 0)
{
if (!picks[0].IsSelected)
{
picks[0].IsHovered = true;
glControl1.Invalidate();
}
}
else
{
foreach (var obj in GetPickableObjects())
obj.IsHovered = false;
glControl1.Invalidate();
}
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();
}
if (!showSelectionBox && isPicked)
{
Console.WriteLine(pickAction);
RenderEditor();
var temp = e.Location;
var curPos = OpenGLHelper.convertScreenToWorldCoords(temp.X, temp.Y);
var prevPos = OpenGLHelper.convertScreenToWorldCoords(pickOriginMouse.X, pickOriginMouse.Y);
var pickMouse = new Point((int)(prevPos.X - curPos.X), (int)(prevPos.Y - curPos.Y));
Console.WriteLine("curPos " + curPos);
Console.WriteLine("prevPos " + prevPos);
GL.PopMatrix();
if (pickAction == PickAction.Translate)
{
foreach (var pickObject in SelectedObjects)
{
if (pickOriginMouse != Point.Empty)
{
float posX = 0;
float posY = 0;
float posZ = 0;
if (pickAxis == PickAxis.X)
posX = pickMouse.X;
if (pickAxis == PickAxis.Y)
posY = pickMouse.Y;
if (pickAxis == PickAxis.All)
{
posX = pickMouse.X;
posY = pickMouse.Y;
}
pickObject.PickTranslate(posX, posY, posZ);
}
}
}
pickOriginMouse = temp;
glControl1.Invalidate();
}
if (mouseDown && !isPicked)
{
RenderEditor();
var temp = e.Location;
var curPos = OpenGLHelper.convertScreenToWorldCoords(temp.X, temp.Y);
var prevPos = OpenGLHelper.convertScreenToWorldCoords(pickOriginMouse.X, pickOriginMouse.Y);
DrawSelectionBox(prevPos, curPos);
}
}
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();
}
}
}