mirror of
https://github.com/KillzXGaming/Switch-Toolbox
synced 2024-12-21 10:23:07 +00:00
5081e39414
Fixed MKAGPDX models a bit so they aren't all missing mesh data. Skinned ones are still buggy! BMD wip support using SuperBMDLib. Adjusted gui loading a little bit.
960 lines
33 KiB
C#
960 lines
33 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Windows.Forms;
|
|
using Switch_Toolbox.Library;
|
|
using GL_EditorFramework.Interfaces;
|
|
using OpenTK.Graphics.OpenGL;
|
|
using OpenTK;
|
|
using Switch_Toolbox.Library.Rendering;
|
|
using GL_EditorFramework.GL_Core;
|
|
using System.Drawing;
|
|
using Switch_Toolbox.Library.IO;
|
|
using Switch_Toolbox.Library.Forms;
|
|
using GL_EditorFramework.EditorDrawables;
|
|
using FirstPlugin.Forms;
|
|
using static GL_EditorFramework.EditorDrawables.EditorSceneBase;
|
|
|
|
namespace FirstPlugin
|
|
{
|
|
public class KCL : TreeNodeFile, IFileFormat
|
|
{
|
|
public FileType FileType { get; set; } = FileType.Collision;
|
|
|
|
public bool CanSave { get; set; }
|
|
public string[] Description { get; set; } = new string[] { "KCL" };
|
|
public string[] Extension { get; set; } = new string[] { "*.kcl" };
|
|
public string FileName { get; set; }
|
|
public string FilePath { get; set; }
|
|
public IFileInfo IFileInfo { get; set; }
|
|
|
|
public bool Identify(System.IO.Stream stream)
|
|
{
|
|
using (var reader = new Switch_Toolbox.Library.IO.FileReader(stream, true))
|
|
{
|
|
reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;
|
|
return reader.ReadUInt32() == 0x02020000;
|
|
}
|
|
}
|
|
|
|
public Type[] Types
|
|
{
|
|
get
|
|
{
|
|
List<Type> types = new List<Type>();
|
|
types.Add(typeof(MenuExt));
|
|
return types.ToArray();
|
|
}
|
|
}
|
|
|
|
byte[] data;
|
|
|
|
STToolStripItem EndiannessToolstrip;
|
|
|
|
public KCL()
|
|
{
|
|
ContextMenuStrip = new STContextMenuStrip();
|
|
ContextMenuStrip.Items.Add(new STToolStripItem("Save", Save));
|
|
ContextMenuStrip.Items.Add(new STToolStripItem("Export", Export));
|
|
ContextMenuStrip.Items.Add(new STToolStripItem("Replace", Replace));
|
|
ContextMenuStrip.Items.Add(new STToolStripItem("Open Material Editor", OpenMaterialEditor));
|
|
EndiannessToolstrip = new STToolStripItem("Big Endian Mode", SwapEndianess) { Checked = true };
|
|
ContextMenuStrip.Items.Add(EndiannessToolstrip);
|
|
CanSave = true;
|
|
IFileInfo = new IFileInfo();
|
|
}
|
|
|
|
public void OpenMaterialEditor(object sender, EventArgs args)
|
|
{
|
|
CollisionMaterialEditor editor = new CollisionMaterialEditor();
|
|
editor.LoadCollisionValues(kcl, Renderer);
|
|
|
|
if (editor.ShowDialog() == DialogResult.OK)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
public DrawableContainer DrawableContainer = new DrawableContainer();
|
|
|
|
public void Load(System.IO.Stream stream)
|
|
{
|
|
Text = FileName;
|
|
Renderer = new KCLRendering();
|
|
|
|
DrawableContainer = new DrawableContainer()
|
|
{
|
|
Name = FileName,
|
|
Drawables = new List<AbstractGlDrawable>() { Renderer },
|
|
};
|
|
|
|
stream.Position = 0;
|
|
data = stream.ToArray();
|
|
Read(data);
|
|
}
|
|
|
|
class MenuExt : IFileMenuExtension
|
|
{
|
|
public STToolStripItem[] NewFileMenuExtensions => null;
|
|
public STToolStripItem[] NewFromFileMenuExtensions => newFileExt;
|
|
public STToolStripItem[] ToolsMenuExtensions => null;
|
|
public STToolStripItem[] TitleBarExtensions => null;
|
|
public STToolStripItem[] CompressionMenuExtensions => null;
|
|
public STToolStripItem[] ExperimentalMenuExtensions => null;
|
|
public STToolStripItem[] EditMenuExtensions => null;
|
|
public ToolStripButton[] IconButtonMenuExtensions => null;
|
|
|
|
STToolStripItem[] newFileExt = new STToolStripItem[2];
|
|
|
|
public MenuExt()
|
|
{
|
|
newFileExt[0] = new STToolStripItem("KCL (Switch)", CreateNew);
|
|
newFileExt[1] = new STToolStripItem("KCL (Wii U)", CreateNew);
|
|
}
|
|
|
|
public void CreateNew(object sender, EventArgs args)
|
|
{
|
|
var ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
|
|
|
|
if (sender.ToString() == "KCL (Wii U)")
|
|
ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;
|
|
|
|
OpenFileDialog opn = new OpenFileDialog();
|
|
opn.Filter = "Supported Formats|*.obj";
|
|
if (opn.ShowDialog() != DialogResult.OK) return;
|
|
var mod = EditorCore.Common.OBJ.Read(new MemoryStream(File.ReadAllBytes(opn.FileName)), null);
|
|
var f = MarioKart.MK7.KCL.FromOBJ(mod);
|
|
|
|
string name = System.IO.Path.GetFileNameWithoutExtension(opn.FileName);
|
|
|
|
KCL kcl = new KCL();
|
|
kcl.Text = name;
|
|
kcl.IFileInfo = new IFileInfo();
|
|
kcl.FileName = name;
|
|
kcl.Renderer = new KCLRendering();
|
|
|
|
kcl.DrawableContainer = new DrawableContainer()
|
|
{
|
|
Name = kcl.FileName,
|
|
Drawables = new List<AbstractGlDrawable>() { kcl.Renderer },
|
|
};
|
|
|
|
kcl.Read(f.Write(ByteOrder));
|
|
|
|
ObjectEditor editor = new ObjectEditor(kcl);
|
|
editor.Text = name;
|
|
LibraryGUI.CreateMdiWindow(editor);
|
|
}
|
|
}
|
|
|
|
public void Unload()
|
|
{
|
|
ObjectEditor.RemoveContainer(DrawableContainer);
|
|
}
|
|
public byte[] Save()
|
|
{
|
|
return data;
|
|
}
|
|
public enum GameSet : ushort
|
|
{
|
|
MarioOdyssey = 0x0,
|
|
MarioKart8D = 0x1,
|
|
Splatoon2 = 0x2,
|
|
}
|
|
|
|
public enum CollisionType_MarioOdssey : ushort
|
|
{
|
|
|
|
}
|
|
public enum CollisionType_MK8D : ushort
|
|
{
|
|
Road_Default = 0,
|
|
Road_Bumpy = 2,
|
|
Road_Sand = 4,
|
|
Offroad_Sand = 6,
|
|
Road_HeavySand = 8,
|
|
Road_IcyRoad = 9,
|
|
OrangeBooster = 10,
|
|
AntiGravityPanel = 11,
|
|
Latiku = 16,
|
|
Wall5 = 17,
|
|
Wall4 = 19,
|
|
Wall = 23,
|
|
Latiku2 = 28,
|
|
Glider = 31,
|
|
SidewalkSlope = 32,
|
|
Road_Dirt = 33,
|
|
Unsolid = 56,
|
|
Water = 60,
|
|
Road_Stone = 64,
|
|
Wall1 = 81,
|
|
Wall2 = 84,
|
|
FinishLine = 93,
|
|
RedFlowerEffect = 95,
|
|
Wall3 = 113,
|
|
WhiteFlowerEffect = 127,
|
|
Road_Metal = 128,
|
|
Road_3DS_MP_Piano = 129,
|
|
Road_RoyalR_Grass = 134,
|
|
TopPillar = 135,
|
|
YoshiCuiruit_Grass = 144,
|
|
YellowFlowerEffect = 159,
|
|
|
|
Road_MetalGating = 160,
|
|
Road_3DS_MP_Xylophone = 161,
|
|
Road_3DS_MP_Vibraphone = 193,
|
|
SNES_RR_road = 227,
|
|
Offroad_Mud = 230,
|
|
Trick = 4096,
|
|
BoosterStunt = 4106,
|
|
TrickEndOfRamp = 4108,
|
|
Trick3 = 4130,
|
|
Trick6 = 4160,
|
|
Trick4 = 4224,
|
|
Trick5 = 8192,
|
|
BoostTrick = 8202,
|
|
}
|
|
|
|
public void Save(object sender, EventArgs args)
|
|
{
|
|
SaveFileDialog sfd = new SaveFileDialog();
|
|
sfd.Filter = "Supported Formats|*.kcl";
|
|
sfd.FileName = Text;
|
|
sfd.DefaultExt = ".kcl";
|
|
|
|
if (sfd.ShowDialog() == DialogResult.OK)
|
|
{
|
|
STFileSaver.SaveFileFormat(this, sfd.FileName);
|
|
}
|
|
}
|
|
|
|
private Syroot.BinaryData.ByteOrder endianness;
|
|
public Syroot.BinaryData.ByteOrder Endianness
|
|
{
|
|
get
|
|
{
|
|
return endianness;
|
|
}
|
|
set
|
|
{
|
|
endianness = value;
|
|
if (value == Syroot.BinaryData.ByteOrder.BigEndian)
|
|
EndiannessToolstrip.Checked = true;
|
|
else
|
|
EndiannessToolstrip.Checked = false;
|
|
}
|
|
}
|
|
|
|
public void Export(object sender, EventArgs args)
|
|
{
|
|
if (kcl == null)
|
|
return;
|
|
|
|
SaveFileDialog sfd = new SaveFileDialog();
|
|
sfd.Filter = "Supported Formats|*.obj";
|
|
sfd.FileName = Text;
|
|
sfd.DefaultExt = ".obj";
|
|
|
|
if (sfd.ShowDialog() == DialogResult.OK)
|
|
{
|
|
kcl.ToOBJ().toWritableObj().WriteObj(sfd.FileName + ".obj");
|
|
}
|
|
}
|
|
|
|
public void Replace(object sender, EventArgs args)
|
|
{
|
|
OpenFileDialog ofd = new OpenFileDialog();
|
|
ofd.Filter = "Supported Formats|*.obj";
|
|
|
|
if (ofd.ShowDialog() == DialogResult.OK)
|
|
{
|
|
var mod = EditorCore.Common.OBJ.Read(new MemoryStream(File.ReadAllBytes(ofd.FileName)), null);
|
|
if (mod.Faces.Count > 65535)
|
|
{
|
|
MessageBox.Show("this model has too many faces, only models with less than 65535 triangles can be converted");
|
|
return;
|
|
}
|
|
kcl = MarioKart.MK7.KCL.FromOBJ(mod);
|
|
data = kcl.Write(Endianness);
|
|
Read(data);
|
|
Renderer.UpdateVertexData();
|
|
}
|
|
}
|
|
|
|
public void SwapEndianess(object sender, EventArgs args)
|
|
{
|
|
if (EndiannessToolstrip.Checked)
|
|
{
|
|
EndiannessToolstrip.Checked = false;
|
|
Endianness = Syroot.BinaryData.ByteOrder.LittleEndian;
|
|
}
|
|
else
|
|
{
|
|
EndiannessToolstrip.Checked = true;
|
|
Endianness = Syroot.BinaryData.ByteOrder.BigEndian;
|
|
}
|
|
}
|
|
|
|
Viewport viewport
|
|
{
|
|
get
|
|
{
|
|
var editor = LibraryGUI.GetObjectEditor();
|
|
return editor.GetViewport();
|
|
}
|
|
set
|
|
{
|
|
var editor = LibraryGUI.GetObjectEditor();
|
|
editor.LoadViewport(value);
|
|
}
|
|
}
|
|
|
|
public KCLRendering Renderer;
|
|
bool DrawablesLoaded = false;
|
|
public override void OnClick(TreeView treeView)
|
|
{
|
|
if (Runtime.UseOpenGL)
|
|
{
|
|
if (viewport == null)
|
|
{
|
|
viewport = new Viewport(ObjectEditor.GetDrawableContainers());
|
|
viewport.Dock = DockStyle.Fill;
|
|
}
|
|
|
|
if (!DrawablesLoaded)
|
|
{
|
|
ObjectEditor.AddContainer(DrawableContainer);
|
|
DrawablesLoaded = true;
|
|
}
|
|
|
|
viewport.ReloadDrawables(DrawableContainer);
|
|
LibraryGUI.LoadEditor(viewport);
|
|
|
|
viewport.Text = Text;
|
|
}
|
|
}
|
|
|
|
public MarioKart.MK7.KCL kcl = null;
|
|
public void Read(byte[] file_data)
|
|
{
|
|
data = file_data;
|
|
|
|
try
|
|
{
|
|
Endianness = Syroot.BinaryData.ByteOrder.LittleEndian;
|
|
kcl = new MarioKart.MK7.KCL(file_data, Syroot.BinaryData.ByteOrder.LittleEndian);
|
|
}
|
|
catch
|
|
{
|
|
Endianness = Syroot.BinaryData.ByteOrder.BigEndian;
|
|
kcl = new MarioKart.MK7.KCL(file_data, Syroot.BinaryData.ByteOrder.BigEndian);
|
|
}
|
|
Read(kcl);
|
|
}
|
|
public void Read(MarioKart.MK7.KCL kcl)
|
|
{
|
|
Vector3 min = new Vector3();
|
|
Vector3 max = new Vector3();
|
|
|
|
Nodes.Clear();
|
|
Renderer.models.Clear();
|
|
|
|
int CurModelIndx = 0;
|
|
foreach (MarioKart.MK7.KCL.KCLModel mdl in kcl.Models)
|
|
{
|
|
KCLModel kclmodel = new KCLModel();
|
|
|
|
kclmodel.Text = "Model " + CurModelIndx;
|
|
|
|
int ft = 0;
|
|
foreach (var plane in mdl.Planes)
|
|
{
|
|
var triangle = mdl.GetTriangle(plane);
|
|
var normal = triangle.Normal;
|
|
var pointA = triangle.PointA;
|
|
var pointB = triangle.PointB;
|
|
var pointC = triangle.PointC;
|
|
|
|
Vertex vtx = new Vertex();
|
|
Vertex vtx2 = new Vertex();
|
|
Vertex vtx3 = new Vertex();
|
|
|
|
vtx.pos = new Vector3(Vec3D_To_Vec3(pointA));
|
|
vtx2.pos = new Vector3(Vec3D_To_Vec3(pointB));
|
|
vtx3.pos = new Vector3(Vec3D_To_Vec3(pointC));
|
|
vtx.nrm = new Vector3(Vec3D_To_Vec3(normal));
|
|
vtx2.nrm = new Vector3(Vec3D_To_Vec3(normal));
|
|
vtx3.nrm = new Vector3(Vec3D_To_Vec3(normal));
|
|
|
|
KCLModel.Face face = new KCLModel.Face();
|
|
face.Text = triangle.Collision.ToString();
|
|
face.MaterialFlag = triangle.Collision;
|
|
|
|
var col = MarioKart.MK7.KCLColors.GetMaterialColor(plane.CollisionType);
|
|
Vector3 ColorSet = new Vector3(col.R, col.G, col.B);
|
|
|
|
vtx.col = new Vector4(ColorSet, 1);
|
|
vtx2.col = new Vector4(ColorSet, 1);
|
|
vtx3.col = new Vector4(ColorSet, 1);
|
|
|
|
kclmodel.faces.Add(ft);
|
|
kclmodel.faces.Add(ft + 1);
|
|
kclmodel.faces.Add(ft + 2);
|
|
|
|
ft += 3;
|
|
|
|
kclmodel.vertices.Add(vtx);
|
|
kclmodel.vertices.Add(vtx2);
|
|
kclmodel.vertices.Add(vtx3);
|
|
|
|
#region FindMaxMin
|
|
if (triangle.PointA.X < min.X) min.X = (float)triangle.PointA.X;
|
|
if (triangle.PointA.Y < min.Y) min.Y = (float)triangle.PointA.Y;
|
|
if (triangle.PointA.Z < min.Z) min.Z = (float)triangle.PointA.Z;
|
|
if (triangle.PointA.X > max.X) max.X = (float)triangle.PointA.X;
|
|
if (triangle.PointA.Y > max.Y) max.Y = (float)triangle.PointA.Y;
|
|
if (triangle.PointA.Z > max.Z) max.Z = (float)triangle.PointA.Z;
|
|
|
|
if (triangle.PointB.X < min.X) min.X = (float)triangle.PointB.X;
|
|
if (triangle.PointB.Y < min.Y) min.Y = (float)triangle.PointB.Y;
|
|
if (triangle.PointB.Z < min.Z) min.Z = (float)triangle.PointB.Z;
|
|
if (triangle.PointB.X > max.X) max.X = (float)triangle.PointB.X;
|
|
if (triangle.PointB.Y > max.Y) max.Y = (float)triangle.PointB.Y;
|
|
if (triangle.PointB.Z > max.Z) max.Z = (float)triangle.PointB.Z;
|
|
|
|
if (triangle.PointC.X < min.X) min.X = (float)triangle.PointC.X;
|
|
if (triangle.PointC.Y < min.Y) min.Y = (float)triangle.PointC.Y;
|
|
if (triangle.PointC.Z < min.Z) min.Z = (float)triangle.PointC.Z;
|
|
if (triangle.PointC.X > max.X) max.X = (float)triangle.PointC.X;
|
|
if (triangle.PointC.Y > max.Y) max.Y = (float)triangle.PointC.Y;
|
|
if (triangle.PointC.Z > max.Z) max.Z = (float)triangle.PointC.Z;
|
|
#endregion
|
|
}
|
|
|
|
Renderer.Max = max;
|
|
Renderer.Min = min;
|
|
Renderer.models.Add(kclmodel);
|
|
Nodes.Add(kclmodel);
|
|
|
|
CurModelIndx++;
|
|
}
|
|
}
|
|
|
|
public class KCLRendering : AbstractGlDrawable
|
|
{
|
|
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 GameSet GameMaterialSet = GameSet.MarioKart8D;
|
|
public List<KCLModel> models = new List<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;
|
|
|
|
DisplayVertex[] Vertices;
|
|
int[] Faces;
|
|
|
|
int poffset = 0;
|
|
int voffset = 0;
|
|
List<DisplayVertex> Vs = new List<DisplayVertex>();
|
|
List<int> Ds = new List<int>();
|
|
foreach (KCLModel m in models)
|
|
{
|
|
m.Offset = poffset * 4;
|
|
List<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<DisplayVertex>(BufferTarget.ArrayBuffer, (IntPtr)(Vertices.Length * 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()
|
|
{
|
|
var size = Max - Min;
|
|
var BoxSize = size / 2f;
|
|
for (int k = 0; k < 2; k++)
|
|
{
|
|
for (int l = 0; l < 2; l++)
|
|
{
|
|
for (int m = 0; m < 2; m++)
|
|
{
|
|
var Boxmin = Min + new Vector3(BoxSize.X * m, BoxSize.Y * l, BoxSize.Z * k);
|
|
var pos = new Vector3(BoxSize.X * m, BoxSize.Y * l, BoxSize.Z * k);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}");
|
|
|
|
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)
|
|
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)
|
|
return;
|
|
|
|
control.CurrentShader = defaultShaderProgram;
|
|
|
|
control.UpdateModelMatrix(
|
|
Matrix4.CreateScale(Runtime.previewScale));
|
|
|
|
SetRenderSettings(defaultShaderProgram);
|
|
|
|
Matrix4 camMat = control.ModelMatrix * control.CameraMatrix * control.ProjectionMatrix;
|
|
|
|
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 (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(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(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(KCLModel m, ShaderProgram shader)
|
|
{
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
|
|
GL.VertexAttribPointer(shader.GetAttribute("vPosition"), 3, VertexAttribPointerType.Float, false, DisplayVertex.Size, 0);
|
|
GL.VertexAttribPointer(shader.GetAttribute("vNormal"), 3, VertexAttribPointerType.Float, false, DisplayVertex.Size, 12);
|
|
GL.VertexAttribPointer(shader.GetAttribute("vColor"), 3, VertexAttribPointerType.Float, false, DisplayVertex.Size, 24);
|
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo_elements);
|
|
}
|
|
private static void DrawModelWireframe(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;
|
|
}
|
|
}*/
|
|
}
|
|
|
|
//Convert KCL lib vec3 to opentk one so i can use the cross and dot methods
|
|
public static Vector3 Vec3D_To_Vec3(System.Windows.Media.Media3D.Vector3D v)
|
|
{
|
|
return new Vector3((float)v.X, (float)v.Y, (float)v.Z);
|
|
}
|
|
public struct DisplayVertex
|
|
{
|
|
// Used for rendering.
|
|
public Vector3 pos;
|
|
public Vector3 nrm;
|
|
public Vector3 col;
|
|
|
|
public static int Size = 4 * (3 + 3 + 3);
|
|
}
|
|
public class KCLModel : STGenericObject
|
|
{
|
|
public KCLModel()
|
|
{
|
|
ImageKey = "mesh";
|
|
SelectedImageKey = "mesh";
|
|
|
|
Checked = true;
|
|
}
|
|
|
|
public int[] display;
|
|
public int Offset; // For Rendering
|
|
|
|
public int strip = 0x40;
|
|
public int displayFaceSize = 0;
|
|
|
|
public class Face : TreeNode
|
|
{
|
|
public int MaterialFlag = 0;
|
|
|
|
}
|
|
|
|
public List<DisplayVertex> CreateDisplayVertices()
|
|
{
|
|
// rearrange faces
|
|
display = getDisplayFace().ToArray();
|
|
|
|
List<DisplayVertex> displayVertList = new List<DisplayVertex>();
|
|
|
|
if (faces.Count <= 3)
|
|
return displayVertList;
|
|
|
|
foreach (Vertex v in vertices)
|
|
{
|
|
DisplayVertex displayVert = new DisplayVertex()
|
|
{
|
|
pos = v.pos,
|
|
nrm = v.nrm,
|
|
col = v.col.Xyz,
|
|
};
|
|
|
|
displayVertList.Add(displayVert);
|
|
}
|
|
|
|
return displayVertList;
|
|
}
|
|
|
|
public List<int> getDisplayFace()
|
|
{
|
|
if ((strip >> 4) == 4)
|
|
{
|
|
displayFaceSize = faces.Count;
|
|
return faces;
|
|
}
|
|
else
|
|
{
|
|
List<int> f = new List<int>();
|
|
|
|
int startDirection = 1;
|
|
int p = 0;
|
|
int f1 = faces[p++];
|
|
int f2 = faces[p++];
|
|
int faceDirection = startDirection;
|
|
int f3;
|
|
do
|
|
{
|
|
f3 = faces[p++];
|
|
if (f3 == 0xFFFF)
|
|
{
|
|
f1 = faces[p++];
|
|
f2 = faces[p++];
|
|
faceDirection = startDirection;
|
|
}
|
|
else
|
|
{
|
|
faceDirection *= -1;
|
|
if ((f1 != f2) && (f2 != f3) && (f3 != f1))
|
|
{
|
|
if (faceDirection > 0)
|
|
{
|
|
f.Add(f3);
|
|
f.Add(f2);
|
|
f.Add(f1);
|
|
}
|
|
else
|
|
{
|
|
f.Add(f2);
|
|
f.Add(f3);
|
|
f.Add(f1);
|
|
}
|
|
}
|
|
f1 = f2;
|
|
f2 = f3;
|
|
}
|
|
} while (p < faces.Count);
|
|
|
|
displayFaceSize = f.Count;
|
|
return f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|