466 lines
16 KiB
C#
466 lines
16 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.IO;
|
|
using System.Threading.Tasks;
|
|
using GL_EditorFramework.GL_Core;
|
|
using GL_EditorFramework.Interfaces;
|
|
using OpenTK;
|
|
using OpenTK.Graphics.OpenGL;
|
|
using Toolbox.Library;
|
|
using Toolbox.Library.Rendering;
|
|
|
|
namespace FirstPlugin
|
|
{
|
|
public class KCLRendering : AbstractGlDrawable
|
|
{
|
|
public bool DrawGlobalOctrees = false;
|
|
|
|
public List<KCL.OctreeNode> OctreeNodes = new List<KCL.OctreeNode>();
|
|
|
|
public MarioKart.MK7.KCL KclFile;
|
|
public Vector3 Max = new Vector3(0);
|
|
public Vector3 Min = new Vector3(0);
|
|
|
|
public List<ushort> SelectedTypes = new List<ushort>();
|
|
|
|
public Vector3 position = new Vector3(0, 0, 0);
|
|
|
|
protected bool Selected = false;
|
|
protected bool Hovered = false;
|
|
|
|
// public override bool IsSelected() => Selected;
|
|
// public override bool IsSelected(int partIndex) => Selected;
|
|
|
|
public bool IsHovered() => Selected;
|
|
|
|
// gl buffer objects
|
|
int vbo_position;
|
|
int ibo_elements;
|
|
|
|
//Set the game's material list
|
|
public KCL.GameSet GameMaterialSet = KCL.GameSet.MarioKart8D;
|
|
public List<KCL.KCLModel> models = new List<KCL.KCLModel>();
|
|
|
|
private void GenerateBuffers()
|
|
{
|
|
GL.GenBuffers(1, out vbo_position);
|
|
GL.GenBuffers(1, out ibo_elements);
|
|
}
|
|
|
|
public void Destroy()
|
|
{
|
|
GL.DeleteBuffer(vbo_position);
|
|
GL.DeleteBuffer(ibo_elements);
|
|
}
|
|
|
|
public void UpdateVertexData()
|
|
{
|
|
if (!Runtime.OpenTKInitialized)
|
|
return;
|
|
|
|
KCL.DisplayVertex[] Vertices;
|
|
int[] Faces;
|
|
|
|
int poffset = 0;
|
|
int voffset = 0;
|
|
List<KCL.DisplayVertex> Vs = new List<KCL.DisplayVertex>();
|
|
List<int> Ds = new List<int>();
|
|
foreach (KCL.KCLModel m in models)
|
|
{
|
|
m.Offset = poffset * 4;
|
|
List<KCL.DisplayVertex> pv = m.CreateDisplayVertices();
|
|
Vs.AddRange(pv);
|
|
|
|
for (int i = 0; i < m.displayFaceSize; i++)
|
|
{
|
|
Ds.Add(m.display[i] + voffset);
|
|
}
|
|
poffset += m.displayFaceSize;
|
|
voffset += pv.Count;
|
|
}
|
|
|
|
// Binds
|
|
Vertices = Vs.ToArray();
|
|
Faces = Ds.ToArray();
|
|
|
|
// Bind only once!
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
|
|
GL.BufferData<KCL.DisplayVertex>(BufferTarget.ArrayBuffer, (IntPtr)(Vertices.Length * KCL.DisplayVertex.Size), Vertices, BufferUsageHint.StaticDraw);
|
|
|
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo_elements);
|
|
GL.BufferData<int>(BufferTarget.ElementArrayBuffer, (IntPtr)(Faces.Length * sizeof(int)), Faces, BufferUsageHint.StaticDraw);
|
|
|
|
LibraryGUI.UpdateViewport();
|
|
}
|
|
|
|
public void DrawGlobalOctree(ref Matrix4 mvp)
|
|
{
|
|
var octreeMax = KclFile.GlobalHeader.OctreeMax;
|
|
var octreeOrigin = KclFile.GlobalHeader.OctreeOrigin;
|
|
Vector3 max = new Vector3((float)octreeMax.X, (float)octreeMax.Y, (float)octreeMax.Z);
|
|
Vector3 min = new Vector3((float)octreeOrigin.X, (float)octreeOrigin.Y, (float)octreeOrigin.Z);
|
|
|
|
Console.WriteLine("DrawGlobalOctree " + min + " " + max);
|
|
|
|
var size = max - min;
|
|
var BoxSize = size / 2f;
|
|
var QuarterSize = BoxSize / 2f;
|
|
|
|
// DrawableBoundingBox.DrawBoundingBox(mvp, min, max, new Vector3(0));
|
|
DrawSubdivision(ref mvp, min, size, OctreeNodes, 0);
|
|
}
|
|
|
|
private void DrawSubdivision(ref Matrix4 mvp, Vector3 min, Vector3 size, List<KCL.OctreeNode> modelOctrees, int subdiv)
|
|
{
|
|
var BoxSize = size / 2f;
|
|
var QuarterSize = BoxSize / 2f;
|
|
|
|
int index = 0;
|
|
for (int z = 0; z < 2; z++)
|
|
{
|
|
for (int y = 0; y < 2; y++)
|
|
{
|
|
for (int x = 0; x < 2; x++)
|
|
{
|
|
var Boxmin = min + BoxSize * new Vector3(x,y,z);
|
|
var pos = BoxSize * new Vector3(x, y, z);
|
|
|
|
if (modelOctrees[index].IsSelected)
|
|
DrawableBoundingBox.DrawBoundingBox(mvp, QuarterSize, Boxmin + QuarterSize, System.Drawing.Color.Red);
|
|
else
|
|
DrawableBoundingBox.DrawBoundingBox(mvp, QuarterSize, Boxmin + QuarterSize, System.Drawing.Color.Green);
|
|
|
|
if (modelOctrees[index].Nodes.Count > 0)
|
|
DrawSubdivision(ref mvp, Boxmin, BoxSize, modelOctrees[index].Children, subdiv++);
|
|
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public GLShaderGeneric Shader;
|
|
|
|
public ShaderProgram defaultShaderProgram;
|
|
public ShaderProgram solidColorShaderProgram;
|
|
|
|
public override void Prepare(GL_ControlModern control)
|
|
{
|
|
string pathFrag = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader") + "\\KCL.frag";
|
|
string pathVert = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader") + "\\KCL.vert";
|
|
|
|
var defaultFrag = new FragmentShader(File.ReadAllText(pathFrag));
|
|
var defaultVert = new VertexShader(File.ReadAllText(pathVert));
|
|
|
|
var solidColorFrag = new FragmentShader(
|
|
@"#version 330
|
|
uniform vec4 color;
|
|
out vec4 FragColor;
|
|
|
|
void main(){
|
|
FragColor = color;
|
|
}");
|
|
|
|
var solidColorVert = new VertexShader(
|
|
@"#version 330
|
|
in vec3 vPosition;
|
|
in vec3 vNormal;
|
|
in vec3 vColor;
|
|
|
|
out vec3 normal;
|
|
out vec3 color;
|
|
out vec3 position;
|
|
|
|
uniform mat4 mtxMdl;
|
|
uniform mat4 mtxCam;
|
|
|
|
void main(){
|
|
normal = vNormal;
|
|
color = vColor;
|
|
position = vPosition;
|
|
|
|
gl_Position = mtxMdl * mtxCam * vec4(vPosition.xyz, 1.0);
|
|
}");
|
|
|
|
Shader = new GLShaderGeneric()
|
|
{
|
|
FragmentShader = File.ReadAllText(pathFrag),
|
|
VertexShader = File.ReadAllText(pathVert),
|
|
};
|
|
|
|
defaultShaderProgram = new ShaderProgram(defaultFrag, defaultVert, control);
|
|
solidColorShaderProgram = new ShaderProgram(solidColorFrag, solidColorVert, control);
|
|
|
|
}
|
|
|
|
public override void Prepare(GL_ControlLegacy control)
|
|
{
|
|
|
|
}
|
|
|
|
private void CheckBuffers()
|
|
{
|
|
if (!Runtime.OpenTKInitialized)
|
|
return;
|
|
|
|
bool buffersWereInitialized = ibo_elements != 0 && vbo_position != 0;
|
|
if (!buffersWereInitialized)
|
|
{
|
|
GenerateBuffers();
|
|
UpdateVertexData();
|
|
}
|
|
}
|
|
public override void Draw(GL_ControlLegacy control, Pass pass)
|
|
{
|
|
if (!Runtime.OpenTKInitialized || defaultShaderProgram == null)
|
|
return;
|
|
|
|
Matrix4 mvpMat = control.ModelMatrix * control.CameraMatrix * control.ProjectionMatrix;
|
|
|
|
Matrix4 invertedCamera = Matrix4.Identity;
|
|
if (invertedCamera.Determinant != 0)
|
|
invertedCamera = mvpMat.Inverted();
|
|
|
|
Vector3 lightDirection = new Vector3(0f, 0f, -1f);
|
|
Vector3 difLightDirection = Vector3.TransformNormal(lightDirection, invertedCamera).Normalized();
|
|
|
|
GL.Disable(EnableCap.Texture2D);
|
|
GL.Enable(EnableCap.DepthTest);
|
|
|
|
foreach (var model in models)
|
|
{
|
|
if (Runtime.RenderModels && model.Checked && model.Checked)
|
|
{
|
|
List<int> faces = model.getDisplayFace();
|
|
|
|
GL.Begin(PrimitiveType.Triangles);
|
|
foreach (var index in faces)
|
|
{
|
|
Vertex vert = model.vertices[index];
|
|
float normal = Vector3.Dot(difLightDirection, vert.nrm) * 0.5f + 0.5f;
|
|
GL.Color3(new Vector3(normal));
|
|
GL.Vertex3(vert.pos);
|
|
}
|
|
GL.End();
|
|
}
|
|
}
|
|
|
|
GL.Enable(EnableCap.Texture2D);
|
|
}
|
|
|
|
public override void Draw(GL_ControlModern control, Pass pass)
|
|
{
|
|
CheckBuffers();
|
|
|
|
if (!Runtime.OpenTKInitialized || pass == Pass.TRANSPARENT || defaultShaderProgram == null)
|
|
return;
|
|
|
|
Matrix4 camMat = control.ModelMatrix * control.CameraMatrix * control.ProjectionMatrix;
|
|
|
|
if (DrawGlobalOctrees)
|
|
DrawGlobalOctree(ref camMat);
|
|
|
|
control.CurrentShader = defaultShaderProgram;
|
|
|
|
control.UpdateModelMatrix(
|
|
Matrix4.CreateScale(Runtime.previewScale));
|
|
|
|
SetRenderSettings(defaultShaderProgram);
|
|
|
|
|
|
GL.Disable(EnableCap.CullFace);
|
|
|
|
GL.Uniform3(defaultShaderProgram["difLightDirection"], Vector3.TransformNormal(new Vector3(0f, 0f, -1f), camMat.Inverted()).Normalized());
|
|
GL.Uniform3(defaultShaderProgram["difLightColor"], new Vector3(1));
|
|
GL.Uniform3(defaultShaderProgram["ambLightColor"], new Vector3(1));
|
|
|
|
defaultShaderProgram.EnableVertexAttributes();
|
|
|
|
foreach (KCL.KCLModel mdl in models)
|
|
{
|
|
DrawModel(mdl, defaultShaderProgram);
|
|
}
|
|
|
|
defaultShaderProgram.DisableVertexAttributes();
|
|
|
|
GL.UseProgram(0);
|
|
GL.Disable(EnableCap.DepthTest);
|
|
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)
|
|
return;
|
|
|
|
SetVertexAttributes(m, shader);
|
|
|
|
if (m.Checked)
|
|
{
|
|
if ((m.IsSelected))
|
|
{
|
|
DrawModelSelection(m, shader);
|
|
}
|
|
else
|
|
{
|
|
if (Runtime.RenderModelWireframe)
|
|
{
|
|
DrawModelWireframe(m, shader);
|
|
}
|
|
|
|
if (Runtime.RenderModels)
|
|
{
|
|
GL.DrawElements(PrimitiveType.Triangles, m.displayFaceSize, DrawElementsType.UnsignedInt, m.Offset);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void DrawModelSelection(KCL.KCLModel p, ShaderProgram shader)
|
|
{
|
|
//This part needs to be reworked for proper outline. Currently would make model disappear
|
|
|
|
GL.DrawElements(PrimitiveType.Triangles, p.displayFaceSize, DrawElementsType.UnsignedInt, p.Offset);
|
|
|
|
GL.Enable(EnableCap.StencilTest);
|
|
// use vertex color for wireframe color
|
|
GL.Uniform1(shader["colorOverride"], 1);
|
|
GL.PolygonMode(MaterialFace.Front, PolygonMode.Line);
|
|
GL.Enable(EnableCap.LineSmooth);
|
|
GL.LineWidth(1.5f);
|
|
GL.DrawElements(PrimitiveType.Triangles, p.displayFaceSize, DrawElementsType.UnsignedInt, p.Offset);
|
|
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
|
|
GL.Uniform1(shader["colorOverride"], 0);
|
|
|
|
GL.Enable(EnableCap.DepthTest);
|
|
}
|
|
private void SetVertexAttributes(KCL.KCLModel m, ShaderProgram shader)
|
|
{
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
|
|
GL.VertexAttribPointer(shader.GetAttribute("vPosition"), 3, VertexAttribPointerType.Float, false, KCL.DisplayVertex.Size, 0);
|
|
GL.VertexAttribPointer(shader.GetAttribute("vNormal"), 3, VertexAttribPointerType.Float, false, KCL.DisplayVertex.Size, 12);
|
|
GL.VertexAttribPointer(shader.GetAttribute("vColor"), 3, VertexAttribPointerType.Float, false, KCL.DisplayVertex.Size, 24);
|
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo_elements);
|
|
}
|
|
private static void DrawModelWireframe(KCL.KCLModel p, ShaderProgram shader)
|
|
{
|
|
// use vertex color for wireframe color
|
|
GL.Uniform1(shader["colorOverride"], 1);
|
|
GL.PolygonMode(MaterialFace.Front, PolygonMode.Line);
|
|
GL.Enable(EnableCap.LineSmooth);
|
|
GL.LineWidth(1.5f);
|
|
GL.DrawElements(PrimitiveType.Triangles, p.displayFaceSize, DrawElementsType.UnsignedInt, p.Offset);
|
|
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
|
|
GL.Uniform1(shader["colorOverride"], 0);
|
|
}
|
|
|
|
/* public override BoundingBox GetSelectionBox()
|
|
{
|
|
Vector3 Min = new Vector3(0);
|
|
Vector3 Max = new Vector3(0);
|
|
|
|
foreach (var model in models)
|
|
{
|
|
foreach (var vertex in model.vertices)
|
|
{
|
|
Min.X = Math.Min(Min.X, vertex.pos.X);
|
|
Min.Y = Math.Min(Min.Y, vertex.pos.Y);
|
|
Min.Z = Math.Min(Min.Z, vertex.pos.Z);
|
|
Max.X = Math.Max(Max.X, vertex.pos.X);
|
|
Max.Y = Math.Max(Max.Y, vertex.pos.Y);
|
|
Max.Z = Math.Max(Max.Z, vertex.pos.Z);
|
|
}
|
|
}
|
|
|
|
return new BoundingBox()
|
|
{
|
|
minX = Min.X,
|
|
minY = Min.Y,
|
|
minZ = Min.Z,
|
|
maxX = Max.X,
|
|
maxY = Max.Y,
|
|
maxZ = Max.Z,
|
|
};
|
|
}
|
|
|
|
public override LocalOrientation GetLocalOrientation(int partIndex)
|
|
{
|
|
return new LocalOrientation(position);
|
|
}
|
|
|
|
public override bool TryStartDragging(DragActionType actionType, int hoveredPart, out LocalOrientation localOrientation, out bool dragExclusively)
|
|
{
|
|
localOrientation = new LocalOrientation(position);
|
|
dragExclusively = false;
|
|
return Selected;
|
|
}
|
|
|
|
public override bool IsInRange(float range, float rangeSquared, Vector3 pos)
|
|
{
|
|
range = 20000; //Make the range large for now. Todo go back to this
|
|
|
|
BoundingBox box = GetSelectionBox();
|
|
|
|
if (pos.X < box.maxX + range && pos.X > box.minX - range &&
|
|
pos.Y < box.maxY + range && pos.Y > box.minY - range &&
|
|
pos.Z < box.maxZ + range && pos.Z > box.minZ - range)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
public override uint SelectAll(GL_ControlBase control)
|
|
{
|
|
Selected = true;
|
|
return REDRAW;
|
|
}
|
|
|
|
public override uint SelectDefault(GL_ControlBase control)
|
|
{
|
|
Selected = true;
|
|
return REDRAW;
|
|
}
|
|
|
|
public override uint Select(int partIndex, GL_ControlBase control)
|
|
{
|
|
Selected = true;
|
|
return REDRAW;
|
|
}
|
|
|
|
public override uint Deselect(int partIndex, GL_ControlBase control)
|
|
{
|
|
Selected = false;
|
|
return REDRAW;
|
|
}
|
|
|
|
public override uint DeselectAll(GL_ControlBase control)
|
|
{
|
|
Selected = false;
|
|
return REDRAW;
|
|
}
|
|
|
|
public override Vector3 Position
|
|
{
|
|
get
|
|
{
|
|
return position;
|
|
}
|
|
set
|
|
{
|
|
position = value;
|
|
}
|
|
}*/
|
|
}
|
|
|
|
}
|