diff --git a/Classes/Animation.cs b/Classes/Animation.cs index 5e29e73..2f8e9f8 100644 --- a/Classes/Animation.cs +++ b/Classes/Animation.cs @@ -1,5 +1,4 @@ using System.ComponentModel; -using System.Drawing.Design; namespace PSXPrev { @@ -11,16 +10,12 @@ public class Animation [DisplayName("Frame Count"), ReadOnly(true)] public uint FrameCount { get; set; } - [DisplayName("Frames per Second"), ReadOnly(true)] + [DisplayName("Frames per Second")] public float FPS { get; set; } [DisplayName("Children"), ReadOnly(true)] public int ObjectCount { get; set; } - [DisplayName("Preview Model")] - [Editor(typeof(RootEntitySelectorEditor), typeof(UITypeEditor))] - public RootEntity RootEntity { get; set; } - [Browsable(false)] public AnimationObject RootAnimationObject { get; set; } } diff --git a/Classes/AnimationBatch.cs b/Classes/AnimationBatch.cs index b2f0d03..d5b4a3e 100644 --- a/Classes/AnimationBatch.cs +++ b/Classes/AnimationBatch.cs @@ -1,14 +1,13 @@ using OpenTK; - namespace PSXPrev { public class AnimationBatch { private Animation _animation; - private Scene _scene; + private readonly Scene _scene; private int _animationProcessIndex; - + public AnimationBatch(Scene scene) { _scene = scene; @@ -18,17 +17,20 @@ public void SetupAnimationBatch(Animation animation) { var objectCount = animation.ObjectCount; _scene.MeshBatch.Reset(objectCount + 1); + _scene.BoundsBatch.Reset(); + _scene.SkeletonBatch.Reset(); + _scene.GizmosMeshBatch.Reset(0); _animation = animation; - //_scene.LineBatch.Reset(); } - public void SetupAnimationFrame(int frame) + public void SetupAnimationFrame(int frame, AnimationObject animationObject = null, RootEntity selectedEntity = null) { + _scene.SkeletonBatch.Reset(); _animationProcessIndex = 0; - ProcessAnimationObject(_animation.RootAnimationObject, frame, null); + ProcessAnimationObject(_animation.RootAnimationObject, frame, null, animationObject, selectedEntity); } - private void ProcessAnimationObject(AnimationObject animationObject, int frameIndex, Matrix4? parentMatrix) + private void ProcessAnimationObject(AnimationObject animationObject, int frameIndex, Matrix4? parentMatrix, AnimationObject selectedAnimationObject = null, RootEntity selectedEntity = null) { var animationFrames = animationObject.AnimationFrames; var totalFrames = animationFrames.Count; @@ -39,81 +41,71 @@ private void ProcessAnimationObject(AnimationObject animationObject, int frameIn { continue; } - var sumFrame = animationFrames[f]; + var matrix = Matrix4.Identity; - var anyMatrix = sumFrame.AbsoluteMatrix; - if (anyMatrix != null) - { - //var modelMatrix = sumFrame.Matrix; - //if (modelMatrix != null) - //{ - // matrix = (Matrix4)modelMatrix; - //} - //else - //{ - if (sumFrame.Rotation != null) - { - var rotation = (Vector3)sumFrame.Rotation; - var r = GeomUtils.CreateR(rotation); - matrix = matrix * r; - } + var sumFrame = animationFrames[f]; - if (sumFrame.Scale != null) - { - var scale = (Vector3)sumFrame.Scale; - var s = GeomUtils.CreateS(scale.X); - matrix = matrix * s; - } + if (sumFrame.Rotation != null) + { + var r = Matrix4.CreateFromQuaternion(sumFrame.Rotation.Value); + matrix = matrix * r; + } + else if (sumFrame.EulerRotation != null) + { + var r = GeomUtils.CreateR(sumFrame.EulerRotation.Value); + matrix = matrix * r; + } - if (sumFrame.Translation != null) - { - var translation = (Vector3)sumFrame.Translation; - var t = GeomUtils.CreateT(translation); - matrix = matrix * t; - } + if (sumFrame.Scale != null) + { + var scale = (Vector3)sumFrame.Scale; + var s = GeomUtils.CreateS(scale.X); + matrix = matrix * s; + } - var absoluteMatrixValue = (bool)anyMatrix; - if (!absoluteMatrixValue) - { - matrix = matrix * localMatrix; - } - localMatrix = matrix; + if (sumFrame.Translation != null) + { + var translation = (Vector3)sumFrame.Translation; + var t = GeomUtils.CreateT(translation); + matrix = matrix * t; + } + + var absoluteMatrixValue = sumFrame.AbsoluteMatrix; + if (!absoluteMatrixValue) + { + matrix = matrix * localMatrix; } + localMatrix = matrix; } Matrix4 worldMatrix; if (parentMatrix != null) { - var parentMatrixValue = (Matrix4)parentMatrix; - worldMatrix = localMatrix * parentMatrixValue; - //if (animationObject.Visible) - //{ - // _scene.LineBatch.AddLine(new Line - // { - // p1 = Vector4.One * parentMatrixValue, - // p2 = Vector4.One * worldMatrix - // }); - //} + worldMatrix = localMatrix * parentMatrix.Value; + _scene.SkeletonBatch.AddLine(Vector3.TransformPosition(Vector3.One, parentMatrix.Value), Vector3.TransformPosition(Vector3.One, worldMatrix), animationObject == selectedAnimationObject ? Color.Blue : Color.Red); } else { worldMatrix = localMatrix; } - if (_animation.RootEntity != null) + if (selectedEntity != null) { - var childEntities = _animation.RootEntity.ChildEntities; - if (animationObject.TMDID > 0 && animationObject.TMDID <= childEntities.Length) + var objectId = animationObject.TMDID.GetValueOrDefault(); + if (objectId > 0) { - var model = (ModelEntity) childEntities[animationObject.TMDID - 1]; - _scene.MeshBatch.BindModelBatch(model, _animationProcessIndex++, worldMatrix); + var models = selectedEntity.GetModelsWithTMDID(objectId-1); + foreach (var model in models) + { + _scene.MeshBatch.BindModelBatch(model, _animationProcessIndex++, worldMatrix, _scene.TextureBinder); + } } } foreach (var childObject in animationObject.Children) { - ProcessAnimationObject(childObject, frameIndex, worldMatrix); + ProcessAnimationObject(childObject, frameIndex, worldMatrix, selectedAnimationObject, selectedEntity); } } } diff --git a/Classes/AnimationFrame.cs b/Classes/AnimationFrame.cs index e5bcb56..ff16a7f 100644 --- a/Classes/AnimationFrame.cs +++ b/Classes/AnimationFrame.cs @@ -1,14 +1,45 @@ using OpenTK; +using System.ComponentModel; namespace PSXPrev { public class AnimationFrame { - public bool? AbsoluteMatrix { get; set; } - public Vector3? Rotation { get; set; } + [Browsable(false)] + public AnimationObject AnimationObject { get; set; } + [Browsable(false)] + public bool AbsoluteMatrix { get; set; } + [Browsable(false)] + public Quaternion? Rotation { get; set; } + [Browsable(false)] + public Vector3? EulerRotation { get; set; } + [Browsable(false)] public Vector3? Scale { get; set; } + [Browsable(false)] public Vector3? Translation { get; set; } - public Matrix4? Matrix { get; set; } + + [ReadOnly(true)] public int FrameTime { get; set; } + + public float RotationX => Rotation?.X ?? 0f; + + + public float RotationY => Rotation?.Y ?? 0f; + + public float RotationZ => Rotation?.Z ?? 0f; + + public float ScaleX => Scale?.X ?? 0f; + + + public float ScaleY => Scale?.Y ?? 0f; + + public float ScaleZ => Scale?.Z ?? 0f; + + public float PositionX => Translation?.X ?? 0f; + + + public float PositionY => Translation?.Y ?? 0f; + + public float PositionZ => Translation?.Z ?? 0f; } } \ No newline at end of file diff --git a/Classes/AnimationObject.cs b/Classes/AnimationObject.cs index ebaddf5..21562d7 100644 --- a/Classes/AnimationObject.cs +++ b/Classes/AnimationObject.cs @@ -1,10 +1,5 @@ -using PSXPrev.Forms; -using System; using System.Collections.Generic; using System.ComponentModel; -using System.Drawing.Design; -using System.Windows.Forms; -using System.Windows.Forms.Design; namespace PSXPrev { @@ -22,17 +17,14 @@ public class AnimationObject [Browsable(false)] public Animation Animation { get; set; } - [DisplayName("Visible")] - public bool Visible { get; set; } - [Browsable(false)] public int ParentID { get; set; } - [DisplayName("TMD ID")] - public int TMDID { get; set; } + [ReadOnly(true)] + public int ID { get; set; } - [Browsable(false)] - public bool IsSelected { get; set; } + [DisplayName("TMD ID")] + public int? TMDID { get; set; } public AnimationObject() { diff --git a/Classes/BoundingBox.cs b/Classes/BoundingBox.cs index 3c2097c..472b711 100644 --- a/Classes/BoundingBox.cs +++ b/Classes/BoundingBox.cs @@ -21,42 +21,82 @@ public Vector3[] Corners } } - public float Magnitude => (Max - Min).Length; + public Vector3 Center => Vector3.Lerp(Min, Max, 0.5f); + + public Vector3 Extents => Size * 0.5f; + + public Vector3 Size => Max - Min; + + public float Magnitude => Size.Length; + + public float MagnitudeFromCenter + { + get + { + var min = Min; + var max = Max; + GetMinMax(ref min, ref max, Vector3.Zero); + return (max - min).Length; + } + } - public Vector3 Center => new Vector3(Min.X + Max.X * 0.5f, Min.Y + Max.Y * 0.5f, Min.Z + Max.Z * 0.5f); - public Vector3 Min; public Vector3 Max; - public void AddPoint(Vector3 point) + private bool _isSet; + + private void GetMinMax(ref Vector3 min, ref Vector3 max, Vector3 point) { - if (point.X < Min.X) + if (point.X < min.X) { - Min.X = point.X; + min.X = point.X; } - else if (point.X > Max.X) + else if (point.X > max.X) { - Max.X = point.X; + max.X = point.X; } - if (point.Y < Min.Y) + if (point.Y < min.Y) { - Min.Y = point.Y; + min.Y = point.Y; } - else if (point.Y > Max.Y) + else if (point.Y > max.Y) { - Max.Y = point.Y; + max.Y = point.Y; } - if (point.Z < Min.Z) + if (point.Z < min.Z) { - Min.Z = point.Z; + min.Z = point.Z; } - else if (point.Z > Max.Z) + else if (point.Z > max.Z) { - Max.Z = point.Z; + max.Z = point.Z; } } + public void AddPoints(Vector3[] points) + { + foreach (var point in points) + { + AddPoint(point); + } + } + + public void AddPoint(Vector3 point) + { + if (!_isSet) + { + Min = point; + Max = point; + _isSet = true; + } + else + { + GetMinMax(ref Min, ref Max, point); + } + + } + public override string ToString() { return $"({Min.X}, {Min.Y}, {Min.Z}) - ({Max.X}, {Max.Y}, {Max.Z})"; diff --git a/Classes/Color.cs b/Classes/Color.cs index fcb0141..87b6ed4 100644 --- a/Classes/Color.cs +++ b/Classes/Color.cs @@ -2,10 +2,22 @@ { public class Color { + public static readonly Color Red = new Color(1f, 0f, 0f); + public static readonly Color Green = new Color(0f, 1f, 0f); + public static readonly Color Blue = new Color(0f, 0f, 1f); + public static readonly Color White = new Color(1f, 1f, 1f); + public float R; public float G; public float B; + public Color(float r, float g, float b) + { + R = r; + G = g; + B = b; + } + public override string ToString() { return R + "|" + G + "|" + B; diff --git a/Classes/EntityBase.cs b/Classes/EntityBase.cs index 1804fda..5263368 100644 --- a/Classes/EntityBase.cs +++ b/Classes/EntityBase.cs @@ -1,23 +1,82 @@ -using System.Collections.Generic; +using OpenTK; using System.ComponentModel; using System.Globalization; -using System.Windows.Forms; namespace PSXPrev { public class EntityBase { [ReadOnly(true), DisplayName("Bounds")] - public BoundingBox Bounds3D { get; protected set; } - + public BoundingBox Bounds3D { get; set; } + + [Browsable(false)] + public Matrix4 LocalMatrix { get; set; } + + [Browsable(false)] + public Matrix4 WorldMatrix + { + get + { + var matrix = Matrix4.Identity; + var entity = this; + do + { + matrix = entity.LocalMatrix * matrix; + entity = entity.ParentEntity; + } while (entity != null); + return matrix; + } + } + + [DisplayName("Position X")] + public float PositionX + { + get => LocalMatrix.ExtractTranslation().X; + set + { + var translationValues = LocalMatrix.ExtractTranslation(); + translationValues.X = value; + ApplyTranslation(translationValues); + } + } + + [DisplayName("Position Y")] + public float PositionY + { + get => LocalMatrix.ExtractTranslation().Y; + set + { + var translationValues = LocalMatrix.ExtractTranslation(); + translationValues.Y = value; + ApplyTranslation(translationValues); + } + } + + [DisplayName("Position Z")] + public float PositionZ + { + get => LocalMatrix.ExtractTranslation().Z; + set + { + var translationValues = LocalMatrix.ExtractTranslation(); + translationValues.Z = value; + ApplyTranslation(translationValues); + } + } + [ReadOnly(true), DisplayName("Sub-Models")] public string ChildCount => ChildEntities == null ? "0" : ChildEntities.Length.ToString(CultureInfo.InvariantCulture); [Browsable(false)] public EntityBase[] ChildEntities { get; set; } - //[Browsable(false)] - //public EntityBase ParentEntity { get; protected set; } + [Browsable(false)] + public EntityBase ParentEntity { get; set; } + + protected EntityBase() + { + LocalMatrix = Matrix4.Identity; + } public virtual void ComputeBounds() { @@ -31,9 +90,22 @@ public virtual void ComputeBounds() } } - //public override string ToString() - //{ - // return EntityName; - //} + public void ComputeBoundsRecursively() + { + var entity = this; + do + { + entity.ComputeBounds(); + entity = entity.ParentEntity; + } while (entity != null); + } + + private void ApplyTranslation(Vector3 translationValues) + { + var translation = Matrix4.CreateTranslation(translationValues); + var rotation = Matrix4.CreateFromQuaternion(LocalMatrix.ExtractRotation()); + var scale = Matrix4.CreateScale(LocalMatrix.ExtractScale()); + LocalMatrix = translation * rotation * scale; + } } } diff --git a/Classes/FileReader.cs b/Classes/FileReader.cs index 8720594..0fb2554 100644 --- a/Classes/FileReader.cs +++ b/Classes/FileReader.cs @@ -10,10 +10,7 @@ public class FileReader : IDisposable public void Dispose() { - if (Reader != null) - { - Reader.Close(); - } + Reader?.Close(); } public void OpenFile(string filename) @@ -22,7 +19,7 @@ public void OpenFile(string filename) { return; } - FileStream file = File.Open(filename, FileMode.Open); + var file = File.Open(filename, FileMode.Open); Reader = new BinaryReader(file, Encoding.ASCII); } } diff --git a/Classes/GeomUtils.cs b/Classes/GeomUtils.cs index 88209e1..a799c86 100644 --- a/Classes/GeomUtils.cs +++ b/Classes/GeomUtils.cs @@ -2,7 +2,6 @@ using System.Text; using OpenTK; - namespace PSXPrev { public static class GeomUtils @@ -10,9 +9,12 @@ public static class GeomUtils public const string FloatFormat = "0.00000"; public const string IntegerFormat = "0"; public static string CompleteFloatFormat = "{0:0.00000}"; - public const float Deg2Rad = (float)((Math.PI * 2f) / 360.0f); + public static Vector3 XVector = new Vector3(1f, 0f, 0f); + public static Vector3 YVector = new Vector3(0f, 1f, 0f); + public static Vector3 ZVector = new Vector3(0f, 0f, 1f); + public static float VecDistance(Vector3 a, Vector3 b) { var x = a.X - b.X; @@ -47,13 +49,6 @@ public static object WriteIntArray(int[] intArray) return stringBuilder.ToString(); } - //public static Matrix4 CreateTRS(float s, Vector3 t, Vector3 r) - //{ - //var mat = glm.translate(new Matrix4(s), new Vector3(t.x, t.y, t.z)) * - // CreateR(r); - // return Matrix4.Identity; - //} - public static Matrix4 CreateT(Vector3 translation) { var mat = Matrix4.CreateTranslation(translation); @@ -74,12 +69,87 @@ public static Matrix4 CreateR(Vector3 rotation) return xRot * yRot * zRot; } - //public static Matrix4 CreateTRS(Vector3 translation, Vector3 rotation, Vector3 scale) - //{ - // var s = glm.scale(Matrix4.identity(), new Vector3(1f,1f,1f)); - // var r = CreateR(rotation); - // var t = glm.translate(Matrix4.identity(), translation); - // return r * t * s ; - //} + public static Vector3 UnProject(this Vector3 position, Matrix4 projection, Matrix4 view, float width, float height) + { + Vector4 vec; + vec.X = 2.0f * position.X / width - 1; + vec.Y = -(2.0f * position.Y / height - 1); + vec.Z = position.Z; + vec.W = 1.0f; + var viewInv = Matrix4.Invert(view); + var projInv = Matrix4.Invert(projection); + Vector4.Transform(ref vec, ref projInv, out vec); + Vector4.Transform(ref vec, ref viewInv, out vec); + if (vec.W > 0.000001f || vec.W < -0.000001f) + { + vec.X /= vec.W; + vec.Y /= vec.W; + vec.Z /= vec.W; + } + return vec.Xyz; + } + + public static Vector3 ProjectOnNormal(this Vector3 vector, Vector3 normal) + { + var num = Vector3.Dot(normal, normal); + if (num < Double.Epsilon) + { + return Vector3.Zero; + } + return normal * Vector3.Dot(vector, normal) / num; + } + + public static float BoxIntersect(Vector3 rayOrigin, Vector3 rayDirection, Vector3 boxMin, Vector3 boxMax) + { + var t1 = (boxMin.X - rayOrigin.X) / rayDirection.X; + var t2 = (boxMax.X - rayOrigin.X) / rayDirection.X; + var t3 = (boxMin.Y - rayOrigin.Y) / rayDirection.Y; + var t4 = (boxMax.Y - rayOrigin.Y) / rayDirection.Y; + var t5 = (boxMin.Z - rayOrigin.Z) / rayDirection.Z; + var t6 = (boxMax.Z - rayOrigin.Z) / rayDirection.Z; + + var aMin = t1 < t2 ? t1 : t2; + var bMin = t3 < t4 ? t3 : t4; + var cMin = t5 < t6 ? t5 : t6; + + var aMax = t1 > t2 ? t1 : t2; + var bMax = t3 > t4 ? t3 : t4; + var cMax = t5 > t6 ? t5 : t6; + + var fMax = aMin > bMin ? aMin : bMin; + var fMin = aMax < bMax ? aMax : bMax; + + var t7 = fMax > cMin ? fMax : cMin; + var t8 = fMin < cMax ? fMin : cMax; + + var t9 = (t8 < 0 || t7 > t8) ? -1 : t7; + + return t9; + } + + public static Vector3 PlaneIntersect(Vector3 rayOrigin, Vector3 rayDirection, Vector3 planeOrigin, Vector3 planeNormal) + { + var diff = rayOrigin - planeOrigin; + var prod1 = Vector3.Dot(diff, planeNormal); + var prod2 = Vector3.Dot(rayDirection, planeNormal); + var prod3 = prod1 / prod2; + return rayOrigin - rayDirection * prod3; + } + + public static void GetBoxMinMax(Vector3 center, Vector3 size, out Vector3 outMin, out Vector3 outMax, Matrix4? matrix = null) + { + var min = new Vector3(center.X - size.X, center.Y - size.Y, center.Z - size.Z); + var max = new Vector3(center.X + size.X, center.Y + size.Y, center.Z + size.Z); + if (matrix.HasValue) + { + outMin = Vector3.TransformPosition(min, matrix.Value); + outMax = Vector3.TransformPosition(max, matrix.Value); + } + else + { + outMin = min; + outMax = max; + } + } } } \ No newline at end of file diff --git a/Classes/HMDParser.cs b/Classes/HMDParser.cs index 0bd1f5f..4864032 100644 --- a/Classes/HMDParser.cs +++ b/Classes/HMDParser.cs @@ -80,8 +80,12 @@ private RootEntity ParseHMDEntities(BinaryReader reader) var coordCount = reader.ReadUInt32(); for (var c = 0; c < coordCount; c++) { - Matrix4 worldMatrix = ReadCoord(reader); - modelEntities[c].WorldMatrix = worldMatrix; + Matrix4 localMatrix = ReadCoord(reader); + modelEntities[c].LocalMatrix = localMatrix; + } + foreach (var modelEntity in modelEntities) + { + modelEntity.ParentEntity = rootEntity; } rootEntity.ChildEntities = modelEntities.ToArray(); rootEntity.ComputeBounds(); @@ -443,23 +447,23 @@ private Triangle TriangleFromPrimitive(Triangle.PrimitiveTypeEnum primitiveType, Colors = new[] { new Color - { - R = r0/256f, - G = g0/256f, - B = b0/256f - }, + ( + r0/256f, + g0/256f, + b0/256f + ), new Color - { - R = r1/256f, - G = g1/256f, - B = b1/256f - }, + ( + r1/256f, + g1/256f, + b1/256f + ), new Color - { - R = r2/256f, - G = g2/256f, - B = b2/256f - } + ( + r2/256f, + g2/256f, + b2/256f + ) }, Normals = new[] { diff --git a/Classes/Line.cs b/Classes/Line.cs index 43b154b..01ca2f3 100644 --- a/Classes/Line.cs +++ b/Classes/Line.cs @@ -2,9 +2,19 @@ namespace PSXPrev { - public class Line + public struct Line { - public Vector4 p1 { get; set; } - public Vector4 p2 { get; set; } + public Vector4 P1; + public Vector4 P2; + public Color Color; + public float Width; + + public Line (Vector4 p1, Vector4 p2, Color color, float width = 1f) + { + P1 = p1; + P2 = p2; + Color = color; + Width = width; + } } } diff --git a/Classes/LineBatch.cs b/Classes/LineBatch.cs index 105f060..0fdcb1e 100644 --- a/Classes/LineBatch.cs +++ b/Classes/LineBatch.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using OpenTK; using OpenTK.Graphics.OpenGL; @@ -15,12 +16,12 @@ public class LineBatch public LineBatch() { _lines = new List(100); - Reset(1); + ResetMeshes(1); } - public void AddLine(Line line) + public void AddLine(Vector3 p1, Vector3 p2, Color color) { - _lines.Add(line); + _lines.Add(new Line(new Vector4(p1), new Vector4(p2), color)); } public void Reset() @@ -28,7 +29,7 @@ public void Reset() _lines.Clear(); } - public void SetupAndDraw(Matrix4 viewMatrix, Matrix4 projectionMatrix) + public void SetupAndDraw(Matrix4 viewMatrix, Matrix4 projectionMatrix, float width = 1f) { var numLines = _lines.Count; if (numLines == 0) @@ -45,15 +46,15 @@ public void SetupAndDraw(Matrix4 viewMatrix, Matrix4 projectionMatrix) for (var l = 0; l < numLines; l++) { var line = _lines[l]; - FillVertex(line.p1, ref baseIndex, ref positionList, ref normalList, ref colorList, ref uvList); - FillVertex(line.p2, ref baseIndex, ref positionList, ref normalList, ref colorList, ref uvList); + FillVertex(line.P1, line.Color, ref baseIndex, ref positionList, ref normalList, ref colorList, ref uvList); + FillVertex(line.P2, line.Color, ref baseIndex, ref positionList, ref normalList, ref colorList, ref uvList); } var lineMesh = GetLine(0); lineMesh.SetData(numPoints, positionList, normalList, colorList, uvList); - Draw(viewMatrix, projectionMatrix); + Draw(viewMatrix, projectionMatrix, width); } - private static void FillVertex(Vector4 position, ref int baseIndex, ref float[] positionList, ref float[] normalList, ref float[] colorList, ref float[] uvList) + private static void FillVertex(Vector4 position, Color color, ref int baseIndex, ref float[] positionList, ref float[] normalList, ref float[] colorList, ref float[] uvList) { var index1 = baseIndex++; var index2 = baseIndex++; @@ -67,27 +68,23 @@ private static void FillVertex(Vector4 position, ref int baseIndex, ref float[] normalList[index2] = 0f; normalList[index3] = 0f; - colorList[index1] = 1f; - colorList[index2] = 1f; - colorList[index3] = 1f; + colorList[index1] = color.R; + colorList[index2] = color.G; + colorList[index3] = color.B; uvList[index1] = 0f; uvList[index2] = 0f; uvList[index3] = 0f; } - private void Reset(int nLines) + private void ResetMeshes(int nLines) { IsValid = true; if (_linesMesh != null) { foreach (var mesh in _linesMesh) { - if (mesh == null) - { - continue; - } - mesh.Delete(); + mesh?.Delete(); } } _linesMesh = new LineMesh[nLines]; @@ -104,23 +101,42 @@ private LineMesh GetLine(int index) return _linesMesh[index]; } - private void Draw(Matrix4 viewMatrix, Matrix4 projectionMatrix) + private void Draw(Matrix4 viewMatrix, Matrix4 projectionMatrix, float width = 1f) { if (!IsValid) { return; } - var line = _linesMesh[0]; if (line == null) { return; } - var modelMatrix = Matrix4.Identity; var mvpMatrix = modelMatrix * viewMatrix * projectionMatrix; GL.UniformMatrix4(Scene.UniformIndexMVP, false, ref mvpMatrix); - line.Draw(); + line.Draw(width); + } + + public void SetupEntityBounds(EntityBase entity) + { + if (entity == null) + { + return; + } + var corners = entity.Bounds3D.Corners; + AddLine(corners[0], corners[2], Color.White); + AddLine(corners[2], corners[4], Color.White); + AddLine(corners[4], corners[1], Color.White); + AddLine(corners[1], corners[0], Color.White); + AddLine(corners[6], corners[7], Color.White); + AddLine(corners[7], corners[5], Color.White); + AddLine(corners[5], corners[3], Color.White); + AddLine(corners[3], corners[6], Color.White); + AddLine(corners[4], corners[7], Color.White); + AddLine(corners[6], corners[2], Color.White); + AddLine(corners[1], corners[5], Color.White); + AddLine(corners[3], corners[0], Color.White); } } } diff --git a/Classes/LineMesh.cs b/Classes/LineMesh.cs index e5a0ec9..670a47c 100644 --- a/Classes/LineMesh.cs +++ b/Classes/LineMesh.cs @@ -36,10 +36,9 @@ private void GenBuffer() _colorBuffer = _ids[1]; _normalBuffer = _ids[2]; _uvBuffer = _ids[3]; - //_indexBuffer = _ids[4]; } - public void Draw() + public void Draw(float width = 1f) { GL.BindVertexArray(_meshId); @@ -59,13 +58,15 @@ public void Draw() GL.EnableVertexAttribArray((uint)Scene.AttributeIndexUv); GL.VertexAttribPointer((uint)Scene.AttributeIndexUv, 3, VertexAttribPointerType.Float, false, 0, IntPtr.Zero); + GL.LineWidth(width); GL.DrawArrays(PrimitiveType.Lines, 0, _numElements); + GL.LineWidth(1f); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); GL.BindVertexArray(0); } - public void SetData(int numElements, float[] positionList, float[] normalList, float[] colorList, float[] uvList)//, int[] indexList) + public void SetData(int numElements, float[] positionList, float[] normalList, float[] colorList, float[] uvList) { _numElements = numElements; @@ -84,10 +85,6 @@ public void SetData(int numElements, float[] positionList, float[] normalList, f GL.BindBuffer(BufferTarget.ArrayBuffer, _uvBuffer); BufferData(uvList); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); - - //GL.BindBuffer(BufferTarget.ArrayBuffer, _indexBuffer); - //BufferData(indexList); - //GL.BindBuffer(BufferTarget.ArrayBuffer, 0); } //public void SetData(int numElements, float[] positionList) diff --git a/Classes/ManifestResourceLoader.cs b/Classes/ManifestResourceLoader.cs index 73c8f17..d5f614c 100644 --- a/Classes/ManifestResourceLoader.cs +++ b/Classes/ManifestResourceLoader.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; +using System.Diagnostics; using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; namespace PSXPrev { @@ -13,10 +7,6 @@ public static class ManifestResourceLoader { public static string LoadTextFile(string textFileName) { - //var executingAssembly = Assembly.GetExecutingAssembly(); - //var pathToDots = textFileName.Replace("\\", "."); - //var location = string.Format("{0}.{1}", executingAssembly.GetName().Name, pathToDots); - using (var stream = File.OpenRead(textFileName)) { Debug.Assert(stream != null, "stream != null"); diff --git a/Classes/Mesh.cs b/Classes/Mesh.cs index c53aeac..d0f5a1c 100644 --- a/Classes/Mesh.cs +++ b/Classes/Mesh.cs @@ -10,7 +10,6 @@ public class Mesh private const int BufferCount = 4; public Matrix4 WorldMatrix { get; set; } - public bool Visible { get; set; } public uint Texture { get; set; } private readonly uint _meshId; @@ -20,7 +19,6 @@ public class Mesh private uint _colorBuffer; private uint _normalBuffer; private uint _uvBuffer; - //private uint _indexBuffer; private readonly uint[] _ids; @@ -29,7 +27,6 @@ public Mesh(uint meshId) _meshId = meshId; _ids = new uint[BufferCount]; WorldMatrix = Matrix4.Identity; - Visible = true; GenBuffer(); } @@ -45,10 +42,9 @@ private void GenBuffer() _colorBuffer = _ids[1]; _normalBuffer = _ids[2]; _uvBuffer = _ids[3]; - //_indexBuffer = _ids[4]; } - public void Draw(TextureBinder textureBinder) + public void Draw(TextureBinder textureBinder = null, bool wireframe = false) { GL.BindVertexArray(_meshId); @@ -68,18 +64,16 @@ public void Draw(TextureBinder textureBinder) GL.EnableVertexAttribArray((uint)Scene.AttributeIndexUv); GL.VertexAttribPointer((uint)Scene.AttributeIndexUv, 3, VertexAttribPointerType.Float, false, 0, IntPtr.Zero); - //GL.BindBuffer(BufferTarget.ArrayBuffer, _indexBuffer); - //GL.EnableVertexAttribArray((uint)Scene.AttributeIndexIndex); - //GL.VertexAttribIPointer((uint)Scene.AttributeIndexIndex, 3, VertexAttribIntegerType.Int, 0, IntPtr.Zero); - - if (Texture != 0) + if (textureBinder != null && Texture != 0) { textureBinder.BindTexture(Texture); } + GL.PolygonMode(MaterialFace.FrontAndBack, wireframe ? PolygonMode.Line : PolygonMode.Fill); GL.DrawArrays(PrimitiveType.Triangles, 0, _numElements); + GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); - if (Texture != 0) + if (textureBinder != null && Texture != 0) { textureBinder.Unbind(); } @@ -107,22 +101,18 @@ public void SetData(int numElements, float[] positionList, float[] normalList, f GL.BindBuffer(BufferTarget.ArrayBuffer, _uvBuffer); BufferData(uvList); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); - - //GL.BindBuffer(BufferTarget.ArrayBuffer, _indexBuffer); - //BufferData(indexList); - //GL.BindBuffer(BufferTarget.ArrayBuffer, 0); } - public void BufferData(float[] list) + private void BufferData(float[] list) { var size = (IntPtr)(list.Length * sizeof(float)); GL.BufferData(BufferTarget.ArrayBuffer, size, list, BufferUsageHint.StaticDraw); } - public void BufferData(int[] list) - { - var size = (IntPtr)(list.Length * sizeof(int)); - GL.BufferData(BufferTarget.ArrayBuffer, size, list, BufferUsageHint.StaticDraw); - } + //private void BufferData(int[] list) + //{ + // var size = (IntPtr)(list.Length * sizeof(int)); + // GL.BufferData(BufferTarget.ArrayBuffer, size, list, BufferUsageHint.StaticDraw); + //} } } \ No newline at end of file diff --git a/Classes/MeshBatch.cs b/Classes/MeshBatch.cs index 3ffb0f2..3ebe210 100644 --- a/Classes/MeshBatch.cs +++ b/Classes/MeshBatch.cs @@ -1,5 +1,6 @@ using OpenTK; using OpenTK.Graphics.OpenGL; +using System; namespace PSXPrev { @@ -16,195 +17,225 @@ public MeshBatch(Scene scene) _scene = scene; } - public void SetupEntityBatch(RootEntity rootEntity, bool focus = false) + public void SetupMultipleEntityBatch(RootEntity[] checkedEntities = null, ModelEntity selectedModel = null, RootEntity selectedEntity = null, TextureBinder textureBinder = null, bool updateMeshData = true, bool focus = false) { - var models = rootEntity.ChildEntities; - Reset(models.Length); - for (var m = 0; m < models.Length; m++) + var bounds = focus ? new BoundingBox() : null; + var modelCount = checkedEntities != null || selectedEntity != null || selectedModel != null ? 1 : 0; + if (checkedEntities != null) { - var model = (ModelEntity)models[m]; - BindMesh(model, m); + foreach (var entity in checkedEntities) + { + if (entity == selectedEntity) + { + continue; + } + modelCount += entity.ChildEntities.Length; + } } - if (focus) + if (selectedEntity != null) { - _scene.FocusOnBounds(rootEntity.Bounds3D); + foreach (var subEntity in selectedEntity.ChildEntities) + { + modelCount++; + if (focus) + { + bounds.AddPoints(subEntity.Bounds3D.Corners); + } + } + } + if (updateMeshData) + { + Reset(modelCount); + } + var modelIndex = 0; + if (checkedEntities != null) + { + foreach (var entity in checkedEntities) + { + if (entity == selectedEntity) + { + continue; + } + foreach (var subEntity in entity.ChildEntities) + { + if (subEntity == selectedModel) + { + continue; + } + BindMesh((ModelEntity)subEntity, modelIndex++, null, textureBinder, updateMeshData); + } + } + } + if (selectedEntity != null) + { + foreach (var subEntity in selectedEntity.ChildEntities) + { + if (subEntity == selectedModel) + { + continue; + } + BindMesh((ModelEntity)subEntity, modelIndex++, null, textureBinder, updateMeshData); + } + } + if (selectedModel != null) + { + BindMesh(selectedModel, modelIndex, null, textureBinder, updateMeshData); } - } - - public void SetupModelBatch(ModelEntity modelEntity, bool focus = false) - { - Reset(1); - BindMesh(modelEntity, 0); if (focus) { - _scene.FocusOnBounds(modelEntity.Bounds3D); + _scene.FocusOnBounds(bounds); } } - public void BindModelBatch(ModelEntity modelEntity, int index, Matrix4 matrix) + public void BindModelBatch(ModelEntity modelEntity, int index, Matrix4 matrix, TextureBinder textureBinder = null) { - BindMesh(modelEntity, index, matrix); + BindMesh(modelEntity, index, matrix, textureBinder); } - public void BindTestMesh(Matrix4 matrix, int index, bool isSelected) + public void BindCube(Matrix4 matrix, Color color, Vector3 center, Vector3 size, int index, TextureBinder textureBinder = null, bool updateMeshData = true) { - const int numTriangles = 12; - const int elementCount = numTriangles * 3 * 3; - const float cubeSize = 100f; - var baseIndex = 0; - //var indexList = new int[elementCount]; - var positionList = new float[elementCount]; - var normalList = new float[elementCount]; - var colorList = new float[elementCount]; - var uvList = new float[elementCount]; - var vertices = new[] + var mesh = GetMesh(index); + if (mesh == null) { - -cubeSize, -cubeSize, -cubeSize , - -cubeSize, -cubeSize, cubeSize , - cubeSize, -cubeSize, cubeSize , - -cubeSize, -cubeSize, -cubeSize , - cubeSize, -cubeSize, cubeSize , - cubeSize, -cubeSize, -cubeSize , - -cubeSize, cubeSize, -cubeSize , - cubeSize, cubeSize, -cubeSize , - cubeSize, cubeSize, cubeSize , - -cubeSize, cubeSize, -cubeSize , - cubeSize, cubeSize, cubeSize , - -cubeSize, cubeSize, cubeSize , - cubeSize, -cubeSize, cubeSize , - -cubeSize, -cubeSize, cubeSize , - -cubeSize, cubeSize, cubeSize , - cubeSize, -cubeSize, cubeSize , - -cubeSize, cubeSize, cubeSize , - cubeSize, cubeSize, cubeSize , - -cubeSize, -cubeSize, -cubeSize , - cubeSize, -cubeSize, -cubeSize , - cubeSize, cubeSize, -cubeSize , - -cubeSize, -cubeSize, -cubeSize , - cubeSize, cubeSize, -cubeSize , - -cubeSize, cubeSize, -cubeSize , - cubeSize, -cubeSize, -cubeSize , - cubeSize, -cubeSize, cubeSize , - cubeSize, cubeSize, cubeSize , - cubeSize, -cubeSize, -cubeSize , - cubeSize, cubeSize, cubeSize , - cubeSize, cubeSize, -cubeSize , - -cubeSize, -cubeSize, cubeSize , - -cubeSize, -cubeSize, -cubeSize , - -cubeSize, cubeSize, -cubeSize , - -cubeSize, -cubeSize, cubeSize , - -cubeSize, cubeSize, -cubeSize , - -cubeSize, cubeSize, cubeSize - }; - for (var t = 0; t < numTriangles; t++) + return; + } + if (updateMeshData) { - for (var i = 0; i < 3; i++) + const int numTriangles = 12; + const int elementCount = numTriangles * 3 * 3; + var baseIndex = 0; + var positionList = new float[elementCount]; + var normalList = new float[elementCount]; + var colorList = new float[elementCount]; + var uvList = new float[elementCount]; + var vertices = new[] { - var index1 = baseIndex++; - var index2 = baseIndex++; - var index3 = baseIndex++; - - positionList[index1] = vertices[index1]; - positionList[index2] = vertices[index2]; - positionList[index3] = vertices[index3]; - - normalList[index1] = 0f; - normalList[index2] = 0f; - normalList[index3] = 0f; - - if (isSelected) - { - colorList[index1] = 1f; - colorList[index2] = 0f; - } - else + center.X-size.X, center.Y-size.Y, center.Z-size.Z, + center.X-size.X, center.Y-size.Y, center.Z+size.Z, + center.X+size.X, center.Y-size.Y, center.Z+size.Z , + center.X-size.X, center.Y-size.Y, center.Z-size.Z, + center.X+size.X, center.Y-size.Y, center.Z+size.Z , + center.X+size.X, center.Y-size.Y, center.Z-size.Z, + center.X-size.X, center.Y+size.Y, center.Z-size.Z, + center.X+size.X, center.Y+size.Y, center.Z-size.Z , + center.X+size.X, center.Y+size.Y, center.Z+size.Z, + center.X-size.X, center.Y+size.Y, center.Z-size.Z, + center.X+size.X, center.Y+size.Y, center.Z+size.Z, + center.X-size.X, center.Y+size.Y, center.Z+size.Z , + center.X+size.X, center.Y-size.Y, center.Z+size.Z , + center.X-size.X, center.Y-size.Y, center.Z+size.Z, + center.X-size.X, center.Y+size.Y, center.Z+size.Z , + center.X+size.X, center.Y-size.Y, center.Z+size.Z , + center.X-size.X, center.Y+size.Y, center.Z+size.Z , + center.X+size.X, center.Y+size.Y, center.Z+size.Z, + center.X-size.X, center.Y-size.Y, center.Z-size.Z, + center.X+size.X, center.Y-size.Y, center.Z-size.Z, + center.X+size.X, center.Y+size.Y, center.Z-size.Z , + center.X-size.X, center.Y-size.Y, center.Z-size.Z, + center.X+size.X, center.Y+size.Y, center.Z-size.Z , + center.X-size.X, center.Y+size.Y, center.Z-size.Z, + center.X+size.X, center.Y-size.Y, center.Z-size.Z, + center.X+size.X, center.Y-size.Y, center.Z+size.Z , + center.X+size.X, center.Y+size.Y, center.Z+size.Z, + center.X+size.X, center.Y-size.Y, center.Z-size.Z, + center.X+size.X, center.Y+size.Y, center.Z+size.Z, + center.X+size.X, center.Y+size.Y, center.Z-size.Z , + center.X-size.X, center.Y-size.Y, center.Z+size.Z, + center.X-size.X, center.Y-size.Y, center.Z-size.Z, + center.X-size.X, center.Y+size.Y, center.Z-size.Z, + center.X-size.X, center.Y-size.Y, center.Z+size.Z, + center.X-size.X, center.Y+size.Y, center.Z-size.Z, + center.X-size.X, center.Y+size.Y, center.Z+size.Z + }; + for (var t = 0; t < numTriangles; t++) + { + for (var i = 0; i < 3; i++) { - colorList[index1] = 0f; - colorList[index2] = 1f; - } + var index1 = baseIndex++; + var index2 = baseIndex++; + var index3 = baseIndex++; + + positionList[index1] = vertices[index1]; + positionList[index2] = vertices[index2]; + positionList[index3] = vertices[index3]; - colorList[index3] = 0f; + normalList[index1] = 0f; + normalList[index2] = 0f; + normalList[index3] = 0f; - uvList[index1] = 0f; - uvList[index2] = 0f; - uvList[index3] = 0f; + colorList[index1] = color.R; + colorList[index2] = color.G; + colorList[index3] = color.B; - //indexList[index1] = t; - //indexList[index2] = t; - //indexList[index3] = t; + uvList[index1] = 0f; + uvList[index2] = 0f; + uvList[index3] = 0f; + } } + mesh.SetData(numTriangles * 3, positionList, normalList, colorList, uvList); } - var mesh = GetMesh(index); - if (mesh == null) + mesh.WorldMatrix = matrix; + if (textureBinder != null) { - return; + mesh.Texture = textureBinder.GetTexture(0); } - mesh.WorldMatrix = matrix; - mesh.Texture = _scene.TextureBinder.GetTexture(0); - mesh.SetData(numTriangles * 3, positionList, normalList, colorList, uvList); } - private void BindMesh(ModelEntity modelEntity, int index, Matrix4? matrix = null) + private void BindMesh(ModelEntity modelEntity, int index, Matrix4? matrix = null, TextureBinder textureBinder = null, bool updateMeshData = true) { - var numTriangles = modelEntity.Triangles.Length; - var elementCount = numTriangles * 3 * 3; - var baseIndex = 0; - //var indexList = new int[elementCount]; - var positionList = new float[elementCount]; - var normalList = new float[elementCount]; - var colorList = new float[elementCount]; - var uvList = new float[elementCount]; - for (var t = 0; t < numTriangles; t++) + var mesh = GetMesh(index); + if (mesh == null) { - var triangle = modelEntity.Triangles[t]; - for (var i = 0; i < 3; i++) + return; + } + if (updateMeshData) + { + var numTriangles = modelEntity.Triangles.Length; + var elementCount = numTriangles * 3 * 3; + var baseIndex = 0; + var positionList = new float[elementCount]; + var normalList = new float[elementCount]; + var colorList = new float[elementCount]; + var uvList = new float[elementCount]; + for (var t = 0; t < numTriangles; t++) { - var index1 = baseIndex++; - var index2 = baseIndex++; - var index3 = baseIndex++; - - var vertex = triangle.Vertices[i]; - positionList[index1] = vertex.X; - positionList[index2] = vertex.Y; - positionList[index3] = vertex.Z; + var triangle = modelEntity.Triangles[t]; + for (var i = 0; i < 3; i++) + { + var index1 = baseIndex++; + var index2 = baseIndex++; + var index3 = baseIndex++; - var normal = triangle.Normals[i]; - normalList[index1] = normal.X; - normalList[index2] = normal.Y; - normalList[index3] = normal.Z; + var vertex = triangle.Vertices[i]; + positionList[index1] = vertex.X; + positionList[index2] = vertex.Y; + positionList[index3] = vertex.Z; - var color = triangle.Colors[i]; - colorList[index1] = color.R; - colorList[index2] = color.G; - colorList[index3] = color.B; + var normal = triangle.Normals[i]; + normalList[index1] = normal.X; + normalList[index2] = normal.Y; + normalList[index3] = normal.Z; - var uv = triangle.Uv[i]; - uvList[index1] = uv.X; - uvList[index2] = uv.Y; - uvList[index3] = uv.Z; + var color = triangle.Colors[i]; + colorList[index1] = color.R; + colorList[index2] = color.G; + colorList[index3] = color.B; - //indexList[index1] = t; - //indexList[index2] = t; - //indexList[index3] = t; + var uv = triangle.Uv[i]; + uvList[index1] = uv.X; + uvList[index2] = uv.Y; + uvList[index3] = uv.Z; + } } + mesh.SetData(numTriangles * 3, positionList, normalList, colorList, uvList); } - var mesh = GetMesh(index); - if (mesh == null) + mesh.WorldMatrix = matrix ?? modelEntity.WorldMatrix; + if (textureBinder != null) { - return; + mesh.Texture = modelEntity.Texture != null ? textureBinder.GetTexture(modelEntity.TexturePage) : 0; } - mesh.WorldMatrix = matrix ?? modelEntity.WorldMatrix; - mesh.Visible = modelEntity.Visible; - mesh.SetData(numTriangles * 3, positionList, normalList, colorList, uvList); - mesh.Texture = modelEntity.Texture != null ? _scene.TextureBinder.GetTexture(modelEntity.TexturePage) : 0; } - //public void BindLine(Vector3 p1, Vector3 p2, int index, Matrix4 worldMatrix) - //{ - // var line = LineMesh.GetLine(index); - // line.WorldMatrix = worldMatrix; - //} - public void Reset(int nMeshes) { IsValid = true; @@ -212,11 +243,7 @@ public void Reset(int nMeshes) { foreach (var mesh in _meshes) { - if (mesh == null) - { - continue; - } - mesh.Delete(); + mesh?.Delete(); } } _meshes = new Mesh[nMeshes]; @@ -237,27 +264,23 @@ private Mesh GetMesh(int index) return _meshes[index]; } - public void Draw(Matrix4 viewMatrix, Matrix4 projectionMatrix, TextureBinder textureBinder) + public void Draw(Matrix4 viewMatrix, Matrix4 projectionMatrix, TextureBinder textureBinder = null, bool wireframe = false) { if (!IsValid) { return; } - foreach (var mesh in _meshes) { - if (mesh == null || !mesh.Visible) + if (mesh == null) { continue; } - var modelMatrix = mesh.WorldMatrix; var mvpMatrix = modelMatrix * viewMatrix * projectionMatrix; GL.UniformMatrix4(Scene.UniformIndexMVP, false, ref mvpMatrix); - - mesh.Draw(textureBinder); + mesh.Draw(textureBinder, wireframe); } } - } } \ No newline at end of file diff --git a/Classes/ModelEntity.cs b/Classes/ModelEntity.cs index 30cb86f..fd1630d 100644 --- a/Classes/ModelEntity.cs +++ b/Classes/ModelEntity.cs @@ -8,9 +8,6 @@ public class ModelEntity : EntityBase { [DisplayName("VRAM Page")] public int TexturePage { get; set; } - - [DisplayName("Visible")] - public bool Visible { get; set; } [ReadOnly(true), DisplayName("Normals")] public bool HasNormals { get; set; } @@ -21,7 +18,7 @@ public class ModelEntity : EntityBase [ReadOnly(true), DisplayName("Uvs")] public bool HasUvs { get; set; } - [ReadOnly(true)] + [ReadOnly(true), DisplayName("Relative Addresses")] public bool RelativeAddresses { get; set; } [ReadOnly(true), DisplayName("Total Triangles")] @@ -30,30 +27,22 @@ public class ModelEntity : EntityBase [Browsable(false)] public Triangle[] Triangles { get; set; } - //[Browsable(false)] - //public MissingTriangle[] MissingTriangles { get; set; } - [Browsable(false)] public Texture Texture { get; set; } - - [Browsable(false)] - public Matrix4 WorldMatrix { get; set; } - - public ModelEntity() - { - Visible = true; - WorldMatrix = Matrix4.Identity; - } + + [DisplayName("TMD ID")] + public int TMDID { get; set; } public override void ComputeBounds() { base.ComputeBounds(); var bounds = new BoundingBox(); + var worldMatrix = WorldMatrix; foreach (var triangle in Triangles) { foreach (var vertex in triangle.Vertices) { - bounds.AddPoint((WorldMatrix * new Vector4(vertex)).Xyz); + bounds.AddPoint(Vector3.TransformPosition(vertex, worldMatrix)); } } Bounds3D = bounds; diff --git a/Classes/MtlExporter.cs b/Classes/MtlExporter.cs index b657c36..0720cf8 100644 --- a/Classes/MtlExporter.cs +++ b/Classes/MtlExporter.cs @@ -1,8 +1,6 @@ using System; -using System.Globalization; using System.IO; - namespace PSXPrev { public class MtlExporter : IDisposable @@ -11,13 +9,12 @@ public class MtlExporter : IDisposable private readonly int _modelIndex; private readonly bool[] _exportedPages = new bool[32]; - public MtlExporter(int modelIndex, string selectedPath) + public MtlExporter(string selectedPath, int modelIndex) { - _modelIndex = modelIndex; - _writer = new StreamWriter(selectedPath + "/mtl" + modelIndex + ".mtl"); + _writer = new StreamWriter($"{selectedPath}/mtl{modelIndex}.mtl"); } - public bool AddMaterial(Texture selectedTexture, int texturePage) + public bool AddMaterial(int texturePage) { if (_exportedPages[texturePage]) { @@ -30,7 +27,7 @@ public bool AddMaterial(Texture selectedTexture, int texturePage) _writer.WriteLine("Ks 0.00000 0.00000 0.00000"); _writer.WriteLine("d 1.00000"); _writer.WriteLine("illum 0"); - _writer.WriteLine("map_Kd {0}_{1}.png", _modelIndex, texturePage); + _writer.WriteLine("map_Kd {0}.png", texturePage); return true; } diff --git a/Classes/ObjExporter.cs b/Classes/ObjExporter.cs index 5bdef6d..c796f1d 100644 --- a/Classes/ObjExporter.cs +++ b/Classes/ObjExporter.cs @@ -2,90 +2,128 @@ using System.Globalization; using System.IO; - namespace PSXPrev { public class ObjExporter { - public ObjExporter() - { + private StreamWriter _streamWriter; + private PngExporter _pngExporter; + private MtlExporter _mtlExporter; + private string _selectedPath; + private bool _experimentalVertexColor; - } - - public void Export(RootEntity[] entities, string selectedPath, bool experimentalVertexColor = false) + public void Export(RootEntity[] entities, string selectedPath, bool experimentalVertexColor = false, bool joinEntities = false) { - var pngExporter = new PngExporter(); - for (var i = 0; i < entities.Length; i++) + _pngExporter = new PngExporter(); + _selectedPath = selectedPath; + _experimentalVertexColor = experimentalVertexColor; + if (!joinEntities) { - var entity = entities[i]; - var writer = new StreamWriter(selectedPath + "/obj" + i + ".obj"); - writer.WriteLine("mtllib mtl{0}.mtl", i); - using (var mtlExporter = new MtlExporter(i, selectedPath)) + for (var i = 0; i < entities.Length; i++) { - foreach (EntityBase childEntity in entity.ChildEntities) + var entity = entities[i]; + _mtlExporter = new MtlExporter(selectedPath, i); + _streamWriter = new StreamWriter($"{selectedPath}/obj{i}.obj"); + _streamWriter.WriteLine("mtllib mtl{0}.mtl", i); + foreach (var childEntity in entity.ChildEntities) { - var model = childEntity as ModelEntity; - if (model.Texture != null) - { - if (mtlExporter.AddMaterial(model.Texture, model.TexturePage)) - { - pngExporter.Export(model.Texture, i, model.TexturePage, selectedPath); - } - } - foreach (var triangle in model.Triangles) - { - var vertexColor0 = string.Empty; - var vertexColor1 = string.Empty; - var vertexColor2 = string.Empty; - var c0 = triangle.Colors[0]; - var c1 = triangle.Colors[1]; - var c2 = triangle.Colors[2]; - if (experimentalVertexColor) - { - vertexColor0 = string.Format(" {0} {1} {2}", (c0.R).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (c0.G).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (c0.B).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); - vertexColor1 = string.Format(" {0} {1} {2}", (c1.R).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (c1.G).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (c1.B).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); - vertexColor2 = string.Format(" {0} {1} {2}", (c2.R).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (c2.G).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (c2.B).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); - } - var v0 = model.WorldMatrix * new Vector4(triangle.Vertices[0]); - var v1 = model.WorldMatrix * new Vector4(triangle.Vertices[1]); - var v2 = model.WorldMatrix * new Vector4(triangle.Vertices[2]); - writer.WriteLine("v {0} {1} {2} {3}", (v0.X).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-v0.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-v0.Z).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), vertexColor0); - writer.WriteLine("v {0} {1} {2} {3}", (v1.X).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-v1.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-v1.Z).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), vertexColor1); - writer.WriteLine("v {0} {1} {2} {3}", (v2.X).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-v2.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-v2.Z).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), vertexColor2); - } - foreach (var triangle in model.Triangles) - { - var n0 = (model.WorldMatrix * new Vector4(triangle.Normals[0])).Normalized(); - var n1 = (model.WorldMatrix * new Vector4(triangle.Normals[1])).Normalized(); - var n2 = (model.WorldMatrix * new Vector4(triangle.Normals[2])).Normalized(); - writer.WriteLine("vn {0} {1} {2}", (n0.X).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-n0.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-n0.Z).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); - writer.WriteLine("vn {0} {1} {2}", (n1.X).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-n1.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-n1.Z).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); - writer.WriteLine("vn {0} {1} {2}", (n2.X).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-n2.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-n2.Z).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); - } - foreach (var triangle in model.Triangles) - { - var uv0 = triangle.Uv[0]; - var uv1 = triangle.Uv[1]; - var uv2 = triangle.Uv[2]; - writer.WriteLine("vt {0} {1}", uv0.X.ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (1f - uv0.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); - writer.WriteLine("vt {0} {1}", uv1.X.ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (1f - uv1.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); - writer.WriteLine("vt {0} {1}", uv2.X.ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (1f - uv2.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); - } + WriteModel(childEntity as ModelEntity); } var baseIndex = 1; + for (var j = 0; j < entity.ChildEntities.Length; j++) + { + var childEntity = entity.ChildEntities[j]; + WriteGroup(j, ref baseIndex, childEntity as ModelEntity); + } + _streamWriter.Dispose(); + _mtlExporter.Dispose(); + } + } + else + { + _mtlExporter = new MtlExporter(selectedPath, 0); + _streamWriter = new StreamWriter($"{selectedPath}/obj0.obj"); + _streamWriter.WriteLine("mtllib mtl0.mtl"); + foreach (var entity in entities) + { + foreach (EntityBase childEntity in entity.ChildEntities) + { + WriteModel(childEntity as ModelEntity); + } + } + var baseIndex = 1; + foreach (var entity in entities) + { for (int j = 0; j < entity.ChildEntities.Length; j++) { var childEntity = entity.ChildEntities[j]; - var model = childEntity as ModelEntity; - writer.WriteLine("g group" + j); - writer.WriteLine("usemtl mtl{0}", model.TexturePage); - for (var k = 0; k < model.Triangles.Length; k++) - { - writer.WriteLine("f {2}/{2}/{2} {1}/{1}/{1} {0}/{0}/{0}", baseIndex++, baseIndex++, baseIndex++); - } + WriteGroup(j, ref baseIndex, childEntity as ModelEntity); } - writer.Close(); } + _streamWriter.Dispose(); + _mtlExporter.Dispose(); + } + _mtlExporter.Dispose(); + } + + private void WriteModel(ModelEntity model) + { + if (model.Texture != null) + { + if (_mtlExporter.AddMaterial(model.TexturePage)) + { + _pngExporter.Export(model.Texture, model.TexturePage, _selectedPath); + } + } + var worldMatrix = model.WorldMatrix; + foreach (var triangle in model.Triangles) + { + var vertexColor0 = string.Empty; + var vertexColor1 = string.Empty; + var vertexColor2 = string.Empty; + var c0 = triangle.Colors[0]; + var c1 = triangle.Colors[1]; + var c2 = triangle.Colors[2]; + if (_experimentalVertexColor) + { + vertexColor0 = string.Format(" {0} {1} {2}", (c0.R).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (c0.G).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (c0.B).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); + vertexColor1 = string.Format(" {0} {1} {2}", (c1.R).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (c1.G).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (c1.B).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); + vertexColor2 = string.Format(" {0} {1} {2}", (c2.R).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (c2.G).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (c2.B).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); + } + var v0 = Vector3.TransformPosition(triangle.Vertices[0], worldMatrix); + var v1 = Vector3.TransformPosition(triangle.Vertices[1], worldMatrix); + var v2 = Vector3.TransformPosition(triangle.Vertices[2], worldMatrix); + _streamWriter.WriteLine("v {0} {1} {2} {3}", (v0.X).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-v0.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-v0.Z).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), vertexColor0); + _streamWriter.WriteLine("v {0} {1} {2} {3}", (v1.X).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-v1.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-v1.Z).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), vertexColor1); + _streamWriter.WriteLine("v {0} {1} {2} {3}", (v2.X).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-v2.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-v2.Z).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), vertexColor2); + } + foreach (var triangle in model.Triangles) + { + var n0 = Vector3.TransformNormal(triangle.Normals[0], worldMatrix); + var n1 = Vector3.TransformNormal(triangle.Normals[1], worldMatrix); + var n2 = Vector3.TransformNormal(triangle.Normals[2], worldMatrix); + _streamWriter.WriteLine("vn {0} {1} {2}", (n0.X).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-n0.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-n0.Z).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); + _streamWriter.WriteLine("vn {0} {1} {2}", (n1.X).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-n1.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-n1.Z).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); + _streamWriter.WriteLine("vn {0} {1} {2}", (n2.X).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-n2.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (-n2.Z).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); + } + foreach (var triangle in model.Triangles) + { + var uv0 = triangle.Uv[0]; + var uv1 = triangle.Uv[1]; + var uv2 = triangle.Uv[2]; + _streamWriter.WriteLine("vt {0} {1}", uv0.X.ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (1f - uv0.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); + _streamWriter.WriteLine("vt {0} {1}", uv1.X.ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (1f - uv1.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); + _streamWriter.WriteLine("vt {0} {1}", uv2.X.ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture), (1f - uv2.Y).ToString(GeomUtils.FloatFormat, CultureInfo.InvariantCulture)); + } + } + + private void WriteGroup(int groupIndex, ref int baseIndex, ModelEntity model) + { + _streamWriter.WriteLine("g group" + groupIndex); + _streamWriter.WriteLine("usemtl mtl{0}", model.TexturePage); + for (var k = 0; k < model.Triangles.Length; k++) + { + _streamWriter.WriteLine("f {2}/{2}/{2} {1}/{1}/{1} {0}/{0}/{0}", baseIndex++, baseIndex++, baseIndex++); } } } diff --git a/Classes/PMDParser.cs b/Classes/PMDParser.cs index 679a37b..27ef889 100644 --- a/Classes/PMDParser.cs +++ b/Classes/PMDParser.cs @@ -154,18 +154,20 @@ private RootEntity ParsePMD(BinaryReader reader) } reader.BaseStream.Seek(position + 4, SeekOrigin.Begin); } - EndObject: + EndObject: model.Triangles = triangles.ToArray(); models.Add(model); } - EndModel: + EndModel: if (models.Count > 0) { - var entity = new RootEntity + var entity = new RootEntity(); + foreach (var model in models) { - ChildEntities = models.ToArray() - }; + model.ParentEntity = entity; + } + entity.ChildEntities = models.ToArray(); entity.ComputeBounds(); return entity; } @@ -398,7 +400,7 @@ private Triangle[] ReadPolyFT4(BinaryReader reader, bool sharedVertices = false, ReadSharedVertices(reader, vo1, out v1x, out v1y, out v1z); ReadSharedVertices(reader, vo2, out v2x, out v2y, out v2z); ReadSharedVertices(reader, vo3, out v3x, out v3y, out v3z); - reader.BaseStream.Position = position; + reader.BaseStream.Position = position; } var triangle1 = TriangleFromPrimitive(Triangle.PrimitiveTypeEnum._poly_ft4, false, false, null, null, 0, 0, 0, 0, 0, 0, r, g, b, r, g, b, r, g, b, u0, v0, u1, v1, u2, v2, v0x, v0y, v0z, v1x, v1y, v1z, v2x, v2y, v2z); @@ -456,7 +458,7 @@ private Triangle[] ReadPolyF4(BinaryReader reader, bool sharedVertices = false, ReadSharedVertices(reader, vo3, out v3x, out v3y, out v3z); reader.BaseStream.Position = position; } - + var triangle1 = TriangleFromPrimitive(Triangle.PrimitiveTypeEnum._poly_f4, false, false, null, null, 0, 0, 0, 0, 0, 0, r0, g0, b0, r0, g0, b0, r0, g0, b0, 0, 0, 0, 0, 0, 0, v0x, v0y, v0z, v1x, v1y, v1z, v2x, v2y, v2z); var triangle2 = TriangleFromPrimitive(Triangle.PrimitiveTypeEnum._poly_f4, false, false, null, null, 0, 0, 0, 0, 0, @@ -795,11 +797,11 @@ private Triangle TriangleFromPrimitive(Triangle.PrimitiveTypeEnum primitiveType, Z = p2z }; ver3 = new Vector3 - { - X = p3x, - Y = p3y, - Z = p3z - }; + { + X = p3x, + Y = p3y, + Z = p3z + }; } Vector3 nor1, nor2, nor3; @@ -852,23 +854,23 @@ private Triangle TriangleFromPrimitive(Triangle.PrimitiveTypeEnum primitiveType, Colors = new[] { new Color - { - R = r0/256f, - G = g0/256f, - B = b0/256f - }, + ( + r0/256f, + g0/256f, + b0/256f + ), new Color - { - R = r1/256f, - G = g1/256f, - B = b1/256f - }, + ( + r1/256f, + g1/256f, + b1/256f + ), new Color - { - R = r2/256f, - G = g2/256f, - B = b2/256f - } + ( + r2/256f, + g2/256f, + b2/256f + ) }, Normals = new[] { diff --git a/Classes/PlyExporter.cs b/Classes/PlyExporter.cs index ec32eca..9775931 100644 --- a/Classes/PlyExporter.cs +++ b/Classes/PlyExporter.cs @@ -28,13 +28,13 @@ public void Export(RootEntity[] entities, string selectedPath) var numMaterials = 0; foreach (var entityBase in entity.ChildEntities) { - var model = (ModelEntity) entityBase; + var model = (ModelEntity)entityBase; faceCount += model.Triangles.Count(); var texturePage = model.TexturePage; if (!materialsDic.ContainsKey(texturePage)) { materialsDic.Add(texturePage, numMaterials++); - pngExporter.Export(model.Texture, i, texturePage, selectedPath); + pngExporter.Export(model.Texture, texturePage, selectedPath); } } var vertexCount = faceCount * 3; @@ -55,23 +55,24 @@ public void Export(RootEntity[] entities, string selectedPath) writer.WriteLine("property list uint8 int32 vertex_indices"); writer.WriteLine("element material {0}", numMaterials); writer.WriteLine("property uchar ambient_red"); - writer.WriteLine("property uchar ambient_green"); + writer.WriteLine("property uchar ambient_green"); writer.WriteLine("property uchar ambient_blue"); writer.WriteLine("property float32 ambient_coeff"); - writer.WriteLine("property uchar diffuse_red"); - writer.WriteLine("property uchar diffuse_green"); + writer.WriteLine("property uchar diffuse_red"); + writer.WriteLine("property uchar diffuse_green"); writer.WriteLine("property uchar diffuse_blue"); writer.WriteLine("property float32 diffuse_coeff"); writer.WriteLine("end_header"); foreach (var entityBase in entity.ChildEntities) { - var model = (ModelEntity) entityBase; + var model = (ModelEntity)entityBase; var materialIndex = materialsDic[model.TexturePage]; var triangles = model.Triangles; + var worldMatrix = model.WorldMatrix; foreach (var triangle in triangles) { - var vertex0 = model.WorldMatrix * new Vector4(triangle.Vertices[0]); - var normal0 = triangle.Normals[0]; + var vertex0 = Vector3.TransformPosition(triangle.Vertices[0], worldMatrix); + var normal0 = Vector3.TransformNormal(triangle.Normals[0], worldMatrix); var uv0 = triangle.Uv[0]; var color0 = triangle.Colors[0]; writer.WriteLine("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11}", @@ -80,8 +81,8 @@ public void Export(RootEntity[] entities, string selectedPath) uv0.X.ToString(GeomUtils.FloatFormat), (1f - uv0.Y).ToString(GeomUtils.FloatFormat), (color0.R * 255).ToString(GeomUtils.IntegerFormat), (color0.G * 255).ToString(GeomUtils.IntegerFormat), (color0.B * 255).ToString(GeomUtils.IntegerFormat), materialIndex); - var vertex1 = triangle.Vertices[1]; - var normal1 = triangle.Normals[1]; + var vertex1 = Vector3.TransformPosition(triangle.Vertices[1], worldMatrix); + var normal1 = Vector3.TransformNormal(triangle.Normals[1], worldMatrix); var uv1 = triangle.Uv[1]; var color1 = triangle.Colors[1]; writer.WriteLine("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11}", @@ -91,8 +92,8 @@ public void Export(RootEntity[] entities, string selectedPath) (color1.R * 255).ToString(GeomUtils.IntegerFormat), (color1.G * 255).ToString(GeomUtils.IntegerFormat), (color1.B * 255).ToString(GeomUtils.IntegerFormat), materialIndex ); - var vertex2 = triangle.Vertices[2]; - var normal2 = triangle.Normals[2]; + var vertex2 = Vector3.TransformPosition(triangle.Vertices[2], worldMatrix); + var normal2 = Vector3.TransformNormal(triangle.Normals[2], worldMatrix); var uv2 = triangle.Uv[2]; var color2 = triangle.Colors[2]; writer.WriteLine("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11}", diff --git a/Classes/PngExporter.cs b/Classes/PngExporter.cs index cee6f9d..6452f72 100644 --- a/Classes/PngExporter.cs +++ b/Classes/PngExporter.cs @@ -1,14 +1,12 @@ -using System.Drawing; -using System.Drawing.Imaging; - +using System.Drawing.Imaging; namespace PSXPrev { public class PngExporter { - public void Export(Texture selectedTexture, int modelIndex, int textureIndex, string selectedPath) + public void Export(Texture selectedTexture, int textureIndex, string selectedPath) { - selectedTexture.Bitmap.Save(selectedPath + "/" + modelIndex + "_" + textureIndex + ".png", ImageFormat.Png); + selectedTexture.Bitmap.Save(selectedPath + "/" + textureIndex + ".png", ImageFormat.Png); } public void Export(Texture[] selectedTextures, string selectedPath) @@ -16,7 +14,7 @@ public void Export(Texture[] selectedTextures, string selectedPath) for (var i = 0; i < selectedTextures.Length; i++) { var selectedTexture = selectedTextures[i]; - Export(selectedTexture, 0, i, selectedPath); + Export(selectedTexture, i, selectedPath); } } } diff --git a/Classes/RootEntity.cs b/Classes/RootEntity.cs index df9c1b0..9d10f6a 100644 --- a/Classes/RootEntity.cs +++ b/Classes/RootEntity.cs @@ -1,10 +1,12 @@ -using System.ComponentModel; - +using System.Collections.Generic; +using System.ComponentModel; namespace PSXPrev { public class RootEntity : EntityBase { + private readonly List _groupedModels = new List(); + [DisplayName("Name")] public string EntityName { get; set; } @@ -14,11 +16,7 @@ public override void ComputeBounds() var bounds = new BoundingBox(); foreach (var entity in ChildEntities) { - var corners = entity.Bounds3D.Corners; - foreach (var corner in corners) - { - bounds.AddPoint(corner); - } + bounds.AddPoints(entity.Bounds3D.Corners); } Bounds3D = bounds; } @@ -27,5 +25,19 @@ public override string ToString() { return EntityName; } + + public List GetModelsWithTMDID(int id) + { + _groupedModels.Clear(); + foreach (var entityBase in ChildEntities) + { + var model = (ModelEntity) entityBase; + if (model.TMDID == id) + { + _groupedModels.Add(model); + } + } + return _groupedModels; + } } } \ No newline at end of file diff --git a/Classes/Scene.cs b/Classes/Scene.cs index 103c305..f8392d9 100644 --- a/Classes/Scene.cs +++ b/Classes/Scene.cs @@ -1,59 +1,75 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.Linq; using System.Text; using OpenTK; using OpenTK.Graphics.OpenGL; - namespace PSXPrev { public class Scene { - public const float CameraFOV = 60.0f; - public const float CameraFOVRads = CameraFOV * ((float)Math.PI * 2f) / 360f; - public const float CameraFarClip = float.MaxValue; - public const float CameraMinDistance = 0.01f; - public const float MouseSensivity = 0.0035f; - public const float MaxCameraPitch = 0.9f; + private const float CameraFOV = 60.0f; + private const float CameraFOVRads = CameraFOV * ((float)Math.PI * 2f) / 360f; + private const float CameraNearClip = 0.1f; + private const float CameraFarClip = 500000f; + private const float CameraMinDistance = 0.01f; + private const float MaxCameraPitch = 0.9f; + private const float GizmoHeight = 0.075f; + private const float GizmoWidth = 0.005f; + private const float CameraDistanceIncrementFactor = 0.25f; + private const float CameraPanIncrementFactor = 0.5f; + + public static Vector3 XGizmoDimensions = new Vector3(GizmoHeight, GizmoWidth, GizmoWidth); + public static Vector3 YGizmoDimensions = new Vector3(GizmoWidth, GizmoHeight, GizmoWidth); + public static Vector3 ZGizmoDimensions = new Vector3(GizmoWidth, GizmoWidth, GizmoHeight); public static int AttributeIndexPosition = 0; public static int AttributeIndexNormal = 1; public static int AttributeIndexColour = 2; public static int AttributeIndexUv = 3; - public static int AttributeIndexIndex = 4; + //public static int AttributeIndexIndex = 4; public static int AttributeIndexTexture = 5; public static int UniformIndexMVP; - //public static int UniformIndexSelectedTriangle; public static int UniformIndexLightDirection; - //public static int UniformIndexLine; public const string AttributeNamePosition = "in_Position"; public const string AttributeNameNormal = "in_Normal"; public const string AttributeNameColour = "in_Color"; public const string AttributeNameUv = "in_Uv"; - //public const string AttributeNameIndex = "in_Index"; public const string AttributeNameTexture = "mainTex"; public const string UniformNameMVP = "mvpMatrix"; - //public const string UniformNameSelectedTriangle = "selectedIndex"; public const string UniformNameLightDirection = "lightDirection"; - //public const string UniformNameLine = "line"; - public MeshBatch MeshBatch { get; set; } - //public LineBatch LineBatch { get; set; } - public AnimationBatch AnimationBatch { get; set; } - public TextureBinder TextureBinder { get; set; } + public enum GizmoId + { + None, + XMover, + YMover, + ZMover + } + + public MeshBatch MeshBatch { get; private set; } + public MeshBatch GizmosMeshBatch { get; private set; } + public LineBatch BoundsBatch { get; private set; } + public LineBatch SkeletonBatch { get; private set; } + public AnimationBatch AnimationBatch { get; private set; } + public TextureBinder TextureBinder { get; private set; } private Vector4 _transformedLight; private Matrix4 _projectionMatrix; private Matrix4 _viewMatrix; + private bool _viewMatrixValid; private int _shaderProgram; + private Vector3 _rayOrigin; + private Vector3 _rayTarget; + private Vector3 _rayDirection; + private Vector3? _projected; private Color _clearColor; public Color ClearColor { - get { return _clearColor; } + get => _clearColor; set { GL.ClearColor(value.R, value.G, value.B, 0.0f); @@ -61,88 +77,57 @@ public Color ClearColor } } - private bool _wireFrame; - public bool WireFrame - { - get { return _wireFrame; } - set - { - GL.PolygonMode(MaterialFace.FrontAndBack, value ? PolygonMode.Line : PolygonMode.Fill); - //GL.CullFace(CullFaceMode.Back); - _wireFrame = value; - } - } + public bool Wireframe { get; set; } - private float _cameraDistanceIncrement = 1000f; - public float CameraDistanceIncrement - { - get { return _cameraDistanceIncrement; } - } + public bool ShowGizmos { get; set; } = true; - private Vector3 _cameraPosition; - public Vector3 CameraPosition - { - get { return _cameraPosition; } - set - { - _cameraPosition = value; - UpdateViewMatrix(); - } - } + public bool ShowBounds { get; set; } = true; + public bool ShowSkeleton { get; set; } - private Vector3 _lightRotation; - public Vector3 LightRotation - { - get { return _lightRotation; } - set - { - _lightRotation = value; - UpdateLightRotation(); - } - } + public float CameraDistanceIncrement => CameraDistanceToOrigin * CameraDistanceIncrementFactor; - private Vector3 _cameraCenter; - public Vector3 CameraCenter - { - get { return _cameraCenter; } - set - { - _cameraCenter = value; - UpdateViewMatrix(); - } - } + public float CameraPanIncrement => CameraDistanceToOrigin * CameraPanIncrementFactor; private float _cameraDistance; public float CameraDistance { - get { return _cameraDistance; } - set - { - _cameraDistance = Math.Max(CameraMinDistance, value); - UpdateViewMatrix(); - } + get => _cameraDistance; + set => _cameraDistance = Math.Max(CameraMinDistance, value); } private float _cameraYaw; public float CameraYaw { - get { return _cameraYaw; } - set - { - _cameraYaw = value; - UpdateViewMatrix(); - } + get => _cameraYaw; + set => _cameraYaw = value; } private float _cameraPitch; public float CameraPitch { - get { return _cameraPitch; } + get => _cameraPitch; + set => _cameraPitch = Math.Max(-MaxCameraPitch, Math.Min(MaxCameraPitch, value)); + } + + public float CameraX { get; set; } + + public float CameraY { get; set; } + + public Quaternion CameraRotation => _viewMatrix.Inverted().ExtractRotation(); + + public Vector3 CameraDirection => CameraRotation * GeomUtils.ZVector; + + public float CameraDistanceToOrigin => -_viewMatrix.ExtractTranslation().Z; + + private Vector3 _lightRotation; + public Vector3 LightRotation + { + get => _lightRotation; set { - _cameraPitch = Math.Max(-MaxCameraPitch, Math.Min(MaxCameraPitch, value)); - UpdateViewMatrix(); + _lightRotation = value; + UpdateLightRotation(); } } @@ -150,7 +135,7 @@ public void Initialise(float width, float height) { SetupGL(); SetupShaders(); - SetupMatrices(width, height, CameraFarClip); + SetupMatrices(width, height, CameraNearClip, CameraFarClip); SetupInternals(); LightRotation = new Vector3(1f, -1f, -1f); } @@ -158,7 +143,9 @@ public void Initialise(float width, float height) private void SetupInternals() { MeshBatch = new MeshBatch(this); - //LineBatch = new LineBatch(); + GizmosMeshBatch = new MeshBatch(this); + BoundsBatch = new LineBatch(); + SkeletonBatch = new LineBatch(); AnimationBatch = new AnimationBatch(this); TextureBinder = new TextureBinder(); } @@ -166,80 +153,65 @@ private void SetupInternals() private void SetupGL() { GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); - GL.ClearDepth(1.0f); - GL.Enable(EnableCap.DepthTest); - GL.Enable(EnableCap.Texture2D); - GL.DepthFunc(DepthFunction.Lequal); GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest); - WireFrame = false; + Wireframe = false; } private void SetupShaders() { var vertexShaderSource = ManifestResourceLoader.LoadTextFile("Shaders\\Shader.vert"); var fragmentShaderSource = ManifestResourceLoader.LoadTextFile("Shaders\\Shader.frag"); - _shaderProgram = GL.CreateProgram(); - var vertexShaderAddress = GL.CreateShader(ShaderType.VertexShader); GL.ShaderSource(vertexShaderAddress, vertexShaderSource); GL.CompileShader(vertexShaderAddress); GL.AttachShader(_shaderProgram, vertexShaderAddress); - var fragmentShaderAddress = GL.CreateShader(ShaderType.FragmentShader); GL.ShaderSource(fragmentShaderAddress, fragmentShaderSource); GL.CompileShader(fragmentShaderAddress); GL.AttachShader(_shaderProgram, fragmentShaderAddress); - var attributes = new Dictionary { {AttributeIndexPosition, AttributeNamePosition}, {AttributeIndexNormal, AttributeNameNormal}, {AttributeIndexColour, AttributeNameColour}, {AttributeIndexUv, AttributeNameUv}, - //{AttributeIndexIndex, AttributeNameIndex}, {AttributeIndexTexture, AttributeNameTexture} }; foreach (var vertexAttributeLocation in attributes) + { GL.BindAttribLocation(_shaderProgram, vertexAttributeLocation.Key, vertexAttributeLocation.Value); - + } GL.LinkProgram(_shaderProgram); - if (!GetLinkStatus()) { throw new Exception(GetInfoLog()); } - UniformIndexMVP = GL.GetUniformLocation(_shaderProgram, UniformNameMVP); - //UniformIndexSelectedTriangle = GL.GetUniformLocation(_shaderProgram, UniformNameSelectedTriangle); UniformIndexLightDirection = GL.GetUniformLocation(_shaderProgram, UniformNameLightDirection); - //UniformIndexLine = GL.GetUniformLocation(_shaderProgram, UniformNameLine); } - public bool GetLinkStatus() + private bool GetLinkStatus() { int[] parameters = { 0 }; GL.GetProgram(_shaderProgram, GetProgramParameterName.LinkStatus, parameters); return parameters[0] == 1; } - public string GetInfoLog() + private string GetInfoLog() { int[] infoLength = { 0 }; - GL.GetProgram(_shaderProgram, GetProgramParameterName.InfoLogLength , infoLength); + GL.GetProgram(_shaderProgram, GetProgramParameterName.InfoLogLength, infoLength); var bufSize = infoLength[0]; - - // Get the compile info. var il = new StringBuilder(bufSize); int bufferLength; GL.GetProgramInfoLog(_shaderProgram, bufSize, out bufferLength, il); - return il.ToString(); } - private void SetupMatrices(float width, float height, float farClip) + private void SetupMatrices(float width, float height, float nearClip, float farClip) { - _projectionMatrix = Matrix4.CreatePerspectiveFieldOfView(CameraFOVRads, width / height, 0.1f, farClip); + _projectionMatrix = Matrix4.CreatePerspectiveFieldOfView(CameraFOVRads, width / height, nearClip, farClip); } private void UpdateLightRotation() @@ -247,63 +219,184 @@ private void UpdateLightRotation() _transformedLight = GeomUtils.CreateR(_lightRotation) * Vector4.One; } - private void UpdateViewMatrix() + public void UpdateViewMatrix() { - var mat = Matrix4.CreateRotationY(_cameraYaw) * Matrix4.CreateRotationX(_cameraPitch); - var eye = mat * new Vector4(0f, 0f, -_cameraDistance, 1f); - _viewMatrix = Matrix4.LookAt(new Vector3(eye.X, eye.Y, eye.Z), _cameraCenter, new Vector3(0f, -1f, 0f)); + var translation = Matrix4.CreateTranslation(CameraX, -CameraY, 0f); + var rotation = Matrix4.CreateRotationY(_cameraYaw) * Matrix4.CreateRotationX(_cameraPitch); + var eye = rotation * new Vector4(0f, 0f, -_cameraDistance, 1f); + _viewMatrix = Matrix4.LookAt(new Vector3(eye.X, eye.Y, eye.Z), Vector3.Zero, new Vector3(0f, -1f, 0f)); + _viewMatrix *= translation; + _viewMatrixValid = true; } public void Draw() { + GL.Enable(EnableCap.DepthTest); + GL.Enable(EnableCap.Texture2D); + GL.DepthFunc(DepthFunction.Lequal); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - GL.UseProgram(_shaderProgram); - - //GL.Uniform1(UniformIndexSelectedTriangle, selectedTriangle); GL.Uniform3(UniformIndexLightDirection, _transformedLight.X, _transformedLight.Y, _transformedLight.Z); + MeshBatch.Draw(_viewMatrix, _projectionMatrix, TextureBinder, Wireframe); + if (ShowBounds) + { + BoundsBatch.SetupAndDraw(_viewMatrix, _projectionMatrix); + } + GL.Clear(ClearBufferMask.DepthBufferBit); + if (ShowGizmos) + { + GizmosMeshBatch.Draw(_viewMatrix, _projectionMatrix); + } + GL.Disable(EnableCap.DepthTest); + GL.Disable(EnableCap.Texture2D); + if (ShowSkeleton) + { + SkeletonBatch.SetupAndDraw(_viewMatrix, _projectionMatrix, 2f); + } + GL.UseProgram(0); + } - //GL.Uniform1(UniformIndexLine, 0); - MeshBatch.Draw(_viewMatrix, _projectionMatrix, TextureBinder); - - //GL.Uniform1(UniformIndexLine, 1); - //LineBatch.SetupAndDraw(_viewMatrix, _projectionMatrix); + public RootEntity GetRootEntityUnderMouse(RootEntity[] checkedEntities, RootEntity selectedEntity, int x, int y, float width, float height) + { + UpdatePicking(x, y, width, height); + var pickedEntities = new List>(); + if (checkedEntities != null) + { + foreach (var entity in checkedEntities) + { + if (entity == selectedEntity) + { + continue; + } + Vector3 boxMin; + Vector3 boxMax; + GeomUtils.GetBoxMinMax(entity.Bounds3D.Center, entity.Bounds3D.Extents, out boxMin, out boxMax); + var intersectionDistance = GeomUtils.BoxIntersect(_rayOrigin, _rayDirection, boxMin, boxMax); + if (intersectionDistance > 0f) + { + pickedEntities.Add(new Tuple(intersectionDistance, entity)); + } + } + } + if (selectedEntity != null) + { + Vector3 boxMin; + Vector3 boxMax; + GeomUtils.GetBoxMinMax(selectedEntity.Bounds3D.Center, selectedEntity.Bounds3D.Extents, out boxMin, out boxMax); + var intersectionDistance = GeomUtils.BoxIntersect(_rayOrigin, _rayDirection, boxMin, boxMax); + if (intersectionDistance > 0f) + { + pickedEntities.Add(new Tuple(intersectionDistance, selectedEntity)); + } + } + pickedEntities.Sort((a, b) => a.Item1.CompareTo(b.Item1)); + return pickedEntities.Count > 0 ? pickedEntities[0].Item2 : null; + } - GL.UseProgram(0); + public Vector3 GetBestPlaneNormal(Vector3 a, Vector3 b) + { + return Math.Abs(Vector3.Dot(CameraDirection, a)) > 0.5f ? a : b; } - + public void FocusOnBounds(BoundingBox bounds) { _cameraYaw = 0f; _cameraPitch = 0f; + CameraX = 0f; + CameraY = 0f; DistanceToFitBounds(bounds); } - //public void FocusOnHeight(float height) - //{ - // DistanceToFitHeight(height); - //} - public void UpdateTexture(Bitmap textureBitmap, int texturePage) { TextureBinder.UpdateTexture(textureBitmap, texturePage); } - public void DistanceToFitBounds(BoundingBox bounds) + private void DistanceToFitBounds(BoundingBox bounds) { - var center = CameraCenter; - var radius = bounds.Magnitude; + var radius = bounds.MagnitudeFromCenter; var distance = radius / (float)Math.Sin(CameraFOVRads * 0.5f) + 0.1f; - //var camDistance = boundSphereRadius / 2.0f / (float)Math.Tan(CameraFOVRads / 2.0f) * 2f; - _cameraDistanceIncrement = distance * 0.25f; CameraDistance = distance; + UpdateViewMatrix(); + } + + public GizmoId GetGizmoUnderPosition(int x, int y, float width, float height, EntityBase selectedEntityBase) + { + if (!ShowGizmos) + { + return GizmoId.None; + } + _projected = null; + if (selectedEntityBase != null) + { + UpdatePicking(x, y, width, height); + var matrix = selectedEntityBase.WorldMatrix; + var scaleMatrix = GetGizmoScaleMatrix(matrix.ExtractTranslation()); + var finalMatrix = scaleMatrix * matrix; + Vector3 xMin; + Vector3 xMax; + GeomUtils.GetBoxMinMax(XGizmoDimensions, XGizmoDimensions, out xMin, out xMax, finalMatrix); + if (GeomUtils.BoxIntersect(_rayOrigin, _rayDirection, xMin, xMax) > 0f) + { + return GizmoId.XMover; + } + Vector3 yMin; + Vector3 yMax; + GeomUtils.GetBoxMinMax(YGizmoDimensions, YGizmoDimensions, out yMin, out yMax, finalMatrix); + if (GeomUtils.BoxIntersect(_rayOrigin, _rayDirection, yMin, yMax) > 0f) + { + return GizmoId.YMover; + } + Vector3 zMin; + Vector3 zMax; + GeomUtils.GetBoxMinMax(ZGizmoDimensions, ZGizmoDimensions, out zMin, out zMax, finalMatrix); + if (GeomUtils.BoxIntersect(_rayOrigin, _rayDirection, zMin, zMax) > 0f) + { + return GizmoId.ZMover; + } + } + return GizmoId.None; } - //public void DistanceToFitHeight(float height) - //{ - // var camDistance = (height / 2.0f) / (float)Math.Tan(CameraFOVRads / 2.0f) * 2f; - // _cameraDistanceIncrement = camDistance * 0.25f; - // CameraDistance = camDistance; - //} + public Vector3 GetGizmoProjectionOffset(int x, int y, float width, float height, EntityBase entityBase, Vector3 planeNormal, Vector3 projectionNormal) + { + var worldMatrix = entityBase.WorldMatrix; + var planeOrigin = worldMatrix.ExtractTranslation(); + UpdatePicking(x, y, width, height); + var projected = GeomUtils.PlaneIntersect(_rayOrigin, _rayDirection, planeOrigin, planeNormal).ProjectOnNormal(projectionNormal); + Vector3 offset; + if (_projected != null) + { + var previousProjected = _projected.Value; + offset = new Vector3((int)(projected.X - previousProjected.X), (int)(projected.Y - previousProjected.Y), (int)(projected.Z - previousProjected.Z)); + } + else + { + offset = Vector3.Zero; + } + _projected = projected; + return Vector3.TransformVector(offset, worldMatrix.Inverted()); + } + + private void UpdatePicking(int x, int y, float width, float height) + { + if (!_viewMatrixValid) + { + return; + } + _rayOrigin = new Vector3(x, y, CameraNearClip).UnProject(_projectionMatrix, _viewMatrix, width, height); + _rayTarget = new Vector3(x, y, 1f).UnProject(_projectionMatrix, _viewMatrix, width, height); + _rayDirection = (_rayTarget - _rayOrigin).Normalized(); + } + + private float CameraDistanceFrom(Vector3 point) + { + return (_viewMatrix.Inverted().ExtractTranslation() - point).Length; + } + + public Matrix4 GetGizmoScaleMatrix(Vector3 position) + { + return Matrix4.CreateScale(CameraDistanceFrom(position)); + } } } \ No newline at end of file diff --git a/Classes/TMDParser.cs b/Classes/TMDParser.cs index f4e6fca..6883d80 100644 --- a/Classes/TMDParser.cs +++ b/Classes/TMDParser.cs @@ -1085,7 +1085,7 @@ private RootEntity ParseTmd(BinaryReader reader) HasColors = hasColors, HasUvs = hasUvs, TexturePage = key, - Visible = true + TMDID = o }; models.Add(model); } @@ -1095,10 +1095,12 @@ private RootEntity ParseTmd(BinaryReader reader) EndModel: if (models.Count > 0) { - var entity = new RootEntity + var entity = new RootEntity(); + foreach (var model in models) { - ChildEntities = (EntityBase[])models.ToArray() - }; + model.ParentEntity = entity; + } + entity.ChildEntities = models.ToArray(); entity.ComputeBounds(); return entity; } @@ -1161,23 +1163,23 @@ private Triangle TriangleFromPrimitive(Triangle.PrimitiveTypeEnum primitiveType, Colors = new[] { new Color - { - R = r0/256f, - G = g0/256f, - B = b0/256f - }, + ( + r0/256f, + g0/256f, + b0/256f + ), new Color - { - R = r1/256f, - G = g1/256f, - B = b1/256f - }, + ( + r1/256f, + g1/256f, + b1/256f + ), new Color - { - R = r2/256f, - G = g2/256f, - B = b2/256f - } + ( + r2/256f, + g2/256f, + b2/256f + ) }, Normals = new[] { diff --git a/Classes/TMDParserAlternative.cs b/Classes/TMDParserAlternative.cs index 3d69548..9006894 100644 --- a/Classes/TMDParserAlternative.cs +++ b/Classes/TMDParserAlternative.cs @@ -138,7 +138,8 @@ public void LookForTmd(BinaryReader reader, string fileTitle) //reader.BaseStream.Seek(checkOffset + 1, SeekOrigin.Begin); } Program.Logger.WriteLine(exp); - } finally + } + finally { reader.BaseStream.Seek(_offset + 1, SeekOrigin.Begin); } @@ -199,7 +200,7 @@ private RootEntity ParseTmd(BinaryReader reader, long startAddress) { var objBlock = objBlocks[o]; var scale = (float)Math.Pow(objBlock.Scale, 2); - if(scale == 0) + if (scale == 0) { scale = 1; } @@ -267,8 +268,7 @@ private RootEntity ParseTmd(BinaryReader reader, long startAddress) HasNormals = hasNormals, HasColors = hasColors, HasUvs = hasUvs, - TexturePage = key, - Visible = true + TexturePage = key }; models.Add(model); } @@ -278,10 +278,12 @@ private RootEntity ParseTmd(BinaryReader reader, long startAddress) EndModel: if (models.Count > 0) { - var entity = new RootEntity + var entity = new RootEntity(); + foreach (var model in models) { - ChildEntities = (EntityBase[])models.ToArray() - }; + model.ParentEntity = entity; + } + entity.ChildEntities = models.ToArray(); entity.ComputeBounds(); return entity; } @@ -372,7 +374,7 @@ private TMDPacketStructure CreatePolygonPacketStructure(byte flag, byte mode) Structure = packet }; } - + private Dictionary ExtractColumnsFromReader(BinaryReader reader, TMDPacketStructure packet, byte mode, Vector3[] vertices, Vector3[] normals) { var columns = new Dictionary(); @@ -416,7 +418,7 @@ private Dictionary ExtractColumnsFromReader(BinaryReader reader, var hasPrimitive = false; - if(code == 1) + if (code == 1) { var pakStruc = CreatePolygonPacketStructure(flag, mode); var columns = ExtractColumnsFromReader(reader, pakStruc, mode, vertices, normals); @@ -466,7 +468,7 @@ private void AddTrianglesToGroup(Dictionary> group, Dictiona var r = ((float)(byte)columns[$"R{i}"]) / 256.0f; var g = ((float)(byte)columns[$"G{i}"]) / 256.0f; var b = ((float)(byte)columns[$"B{i}"]) / 256.0f; - colors.Add(new Color { R = r, G = g, B = b }); + colors.Add(new Color(r, g, b)); } if (columns.ContainsKey($"NORM{i}")) { @@ -488,7 +490,7 @@ private void AddTrianglesToGroup(Dictionary> group, Dictiona tPage = (ushort)columns["TSB"] & 0x1F; } - var defaultColor = new Color { R = 1, G = 1, B = 1 }; + var defaultColor = new Color(1, 1, 1); var defaultTexcoord = new Vector3 { X = 0, Y = 0 }; var defaultNormal = new Vector3 { X = 0, Y = 0, Z = 0 }; var triColors = new[] { defaultColor, defaultColor, defaultColor }; diff --git a/Classes/TODParser.cs b/Classes/TODParser.cs index c85c0a9..0dcc1f2 100644 --- a/Classes/TODParser.cs +++ b/Classes/TODParser.cs @@ -27,7 +27,7 @@ public void LookForTOD(BinaryReader reader, string fileTitle) reader.BaseStream.Seek(0, SeekOrigin.Begin); ; - //var animations = new List(); + //var animations = new List(); while (reader.BaseStream.CanRead) { @@ -120,7 +120,7 @@ private Animation ParseTOD(BinaryReader reader) var rx = (reader.ReadInt32() / 4096f) * GeomUtils.Deg2Rad; var ry = (reader.ReadInt32() / 4096f) * GeomUtils.Deg2Rad; var rz = (reader.ReadInt32() / 4096f) * GeomUtils.Deg2Rad; - animationFrame.Rotation = new Vector3(rx, ry, rz); + animationFrame.EulerRotation = new Vector3(rx, ry, rz); } if (scaling != 0x00) { @@ -138,38 +138,38 @@ private Animation ParseTOD(BinaryReader reader) animationFrame.Translation = new Vector3(tx, ty, tz); } animationFrame.AbsoluteMatrix = matrixType == 0x00; - if ((reader.BaseStream.Position - packetTop) / 4 != packetLength) - { - return null; - } + //if ((reader.BaseStream.Position - packetTop) / 4 != packetLength) + //{ + // return null; + //} break; case 0x02: //TMD data ID animationObject.TMDID = reader.ReadUInt16(); reader.ReadUInt16(); - if ((reader.BaseStream.Position - packetTop) / 4 != packetLength) - { - return null; - } + //if ((reader.BaseStream.Position - packetTop) / 4 != packetLength) + //{ + // return null; + //} break; case 0x03: //Parent Object ID animationObject.ParentID = reader.ReadUInt16(); reader.ReadUInt16(); - if ((reader.BaseStream.Position - packetTop) / 4 != packetLength) - { - return null; - } + //if ((reader.BaseStream.Position - packetTop) / 4 != packetLength) + //{ + // return null; + //} break; case 0x04: float r00 = reader.ReadInt16() / 4096f; float r01 = reader.ReadInt16() / 4096f; float r02 = reader.ReadInt16() / 4096f; - float r10 = reader.ReadInt16()/ 4096f; - float r11 = reader.ReadInt16()/ 4096f; + float r10 = reader.ReadInt16() / 4096f; + float r11 = reader.ReadInt16() / 4096f; float r12 = reader.ReadInt16() / 4096f; - float r20 = reader.ReadInt16()/ 4096f; - float r21 = reader.ReadInt16()/ 4096f; + float r20 = reader.ReadInt16() / 4096f; + float r21 = reader.ReadInt16() / 4096f; float r22 = reader.ReadInt16() / 4096f; reader.ReadInt16(); @@ -178,17 +178,21 @@ private Animation ParseTOD(BinaryReader reader) var y = reader.ReadInt32(); var z = reader.ReadInt32(); + var matrix = new Matrix3( + new Vector3(r00, r01, r02), + new Vector3(r10, r11, r12), + new Vector3(r20, r21, r22) + ); + + animationFrame.Translation = new Vector3(x,y,z); + animationFrame.Rotation = matrix.ExtractRotation(); + animationFrame.Scale = matrix.ExtractScale(); animationFrame.AbsoluteMatrix = true; - animationFrame.Matrix = new Matrix4(new Matrix3( - new Vector3(r00, r10, r20), - new Vector3(r01, r11, r21), - new Vector3(r02, r12, r22) - )); - if ((reader.BaseStream.Position - packetTop) / 4 != packetLength) - { - return null; - } + //if ((reader.BaseStream.Position - packetTop) / 4 != packetLength) + //{ + // return null; + //} break; //case 0x08: //object control // switch (flag) @@ -208,7 +212,7 @@ private Animation ParseTOD(BinaryReader reader) foreach (var animationObject in animationObjects.Values) { - if (animationObjects.ContainsKey(animationObject.ParentID)) + if (animationObject.ParentID != 0 && animationObjects.ContainsKey(animationObject.ParentID)) { var parent = animationObjects[animationObject.ParentID]; animationObject.Parent = parent; @@ -221,7 +225,7 @@ private Animation ParseTOD(BinaryReader reader) animation.RootAnimationObject = rootAnimationObject; animation.FrameCount = frameCount; animation.ObjectCount = animationObjects.Count; - animation.FPS = 1f / resolution; + animation.FPS = 1f / resolution * 60f; return animation; } @@ -232,7 +236,7 @@ private AnimationFrame GetAnimationFrame(AnimationObject animationObject, int fr { return animationFrames[frameTime]; } - var frame = new AnimationFrame { FrameTime = frameTime }; + var frame = new AnimationFrame { FrameTime = frameTime, AnimationObject = animationObject }; animationFrames.Add(frameTime, frame); return frame; } @@ -243,7 +247,7 @@ private AnimationObject GetAnimationObject(Animation animation, Dictionary Bitmap.Width; [ReadOnly(true), DisplayName("Height")] - public int Height - { - get { return Bitmap.Height; } - } + public int Height => Bitmap.Height; [Browsable(false)] public Bitmap Bitmap { get; set; } diff --git a/Classes/TextureBinder.cs b/Classes/TextureBinder.cs index c75c684..a8748b2 100644 --- a/Classes/TextureBinder.cs +++ b/Classes/TextureBinder.cs @@ -39,8 +39,6 @@ public void BindTexture(uint texture) { GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, texture); - //GL.TexEnv(OpenGL.GL_TEXTURE_ENV, OpenGL.GL_COMBINE_RGB_ARB, OpenGL.GL_MODULATE); //Modulate RGB with RGB - //shaderProgram.SetUniform1(GL, Scene.AttributeIndexTexture, texture); GL.Uniform1(Scene.AttributeIndexTexture, texture); } diff --git a/Classes/Utils.cs b/Classes/Utils.cs index 12e0bbb..85acf55 100644 --- a/Classes/Utils.cs +++ b/Classes/Utils.cs @@ -1,7 +1,4 @@ -using System; -using System.Text; -using OpenTK; -using PSXPrev.Forms; +using PSXPrev.Forms; namespace PSXPrev { @@ -13,10 +10,5 @@ public static string ShowDialog(string caption, string text) prompt.ShowDialog(); return prompt.ResultText; } - - public static Vector3 CalculateNormal(Vector4 a, Vector4 b, Vector4 c) - { - return Vector3.Cross((b-a).Xyz.Normalized(), (c-a).Xyz.Normalized()); - } } } diff --git a/Forms/LauncherForm.Designer.cs b/Forms/LauncherForm.Designer.cs index 39ce1d3..cb7e301 100644 --- a/Forms/LauncherForm.Designer.cs +++ b/Forms/LauncherForm.Designer.cs @@ -104,6 +104,7 @@ private void InitializeComponent() this.FilenameText.Name = "FilenameText"; this.FilenameText.Size = new System.Drawing.Size(360, 20); this.FilenameText.TabIndex = 0; + this.FilenameText.TextChanged += new System.EventHandler(this.FilenameText_TextChanged); // // groupBox2 // @@ -256,6 +257,7 @@ private void InitializeComponent() // // ScanButton // + this.ScanButton.Enabled = false; this.ScanButton.Location = new System.Drawing.Point(297, 280); this.ScanButton.Name = "ScanButton"; this.ScanButton.Size = new System.Drawing.Size(75, 23); diff --git a/Forms/LauncherForm.cs b/Forms/LauncherForm.cs index db15692..262771a 100644 --- a/Forms/LauncherForm.cs +++ b/Forms/LauncherForm.cs @@ -1,11 +1,5 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.IO; using System.Windows.Forms; namespace PSXPrev.Forms @@ -58,6 +52,12 @@ private void SelectFolderButton_Click(object sender, EventArgs e) private void ScanButton_Click(object sender, EventArgs e) { Program.DoScan(FilenameText.Text, FilterText.Text, TMDCheckBox.Checked, TMDAltCheckBox.Checked, TIMCheckBox.Checked, TIMAltCheckBox.Checked, PMDCheckBox.Checked, TODCheckBox.Checked, HMDModelsCheckBox.Checked, LogCheckBox.Checked, NoVerboseCheckBox.Checked, DebugCheckBox.Checked); + Close(); + } + + private void FilenameText_TextChanged(object sender, EventArgs e) + { + ScanButton.Enabled = File.Exists(FilenameText.Text) || Directory.Exists(FilenameText.Text); } } } diff --git a/Forms/PreviewForm.Designer.cs b/Forms/PreviewForm.Designer.cs index 9b04908..b9f5b3a 100644 --- a/Forms/PreviewForm.Designer.cs +++ b/Forms/PreviewForm.Designer.cs @@ -45,23 +45,25 @@ private void InitializeComponent() this.texturePreviewPictureBox = new System.Windows.Forms.PictureBox(); this.exportBitmapButton = new System.Windows.Forms.Button(); this.vramTabPage = new System.Windows.Forms.TabPage(); - this.showUVCheckBox = new System.Windows.Forms.CheckBox(); this.btnClearPage = new System.Windows.Forms.Button(); this.vramPageLabel = new System.Windows.Forms.Label(); this.vramComboBox = new System.Windows.Forms.ComboBox(); this.vramPagePictureBox = new System.Windows.Forms.PictureBox(); this.animationsTabPage = new System.Windows.Forms.TabPage(); - this.animationEntityComboBox = new System.Windows.Forms.ComboBox(); this.animationPlayButton = new System.Windows.Forms.Button(); this.animationPropertyGrid = new System.Windows.Forms.PropertyGrid(); this.animationsTreeView = new System.Windows.Forms.TreeView(); this.cmsModelExport = new System.Windows.Forms.ContextMenuStrip(this.components); this.miOBJ = new System.Windows.Forms.ToolStripMenuItem(); this.miOBJVC = new System.Windows.Forms.ToolStripMenuItem(); + this.miOBJMerged = new System.Windows.Forms.ToolStripMenuItem(); + this.miOBJVCMerged = new System.Windows.Forms.ToolStripMenuItem(); this.exportSelectedToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.mainMenuStrip = new System.Windows.Forms.MenuStrip(); this.modelsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.wireframeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.showGizmosToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.showBoundsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.texturesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.exportSelectedToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.drawToVRAMToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -70,7 +72,9 @@ private void InitializeComponent() this.vRAMToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.clearPageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.clearAllPagesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.showUVToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.animationsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.showSkeletonToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripProgressBar1 = new System.Windows.Forms.ToolStripProgressBar(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); @@ -119,6 +123,7 @@ private void InitializeComponent() this.entitiesTreeView.Name = "entitiesTreeView"; this.entitiesTreeView.Size = new System.Drawing.Size(175, 399); this.entitiesTreeView.TabIndex = 9; + this.entitiesTreeView.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.entitiesTreeView_AfterCheck); this.entitiesTreeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.entitiesTreeView_AfterSelect); // // exportEntityButton @@ -127,7 +132,7 @@ private void InitializeComponent() this.exportEntityButton.Name = "exportEntityButton"; this.exportEntityButton.Size = new System.Drawing.Size(177, 34); this.exportEntityButton.TabIndex = 8; - this.exportEntityButton.Text = "Export Selected"; + this.exportEntityButton.Text = "Export Checked Models"; this.exportEntityButton.UseVisualStyleBackColor = true; this.exportEntityButton.Click += new System.EventHandler(this.exportEntityButton_Click); // @@ -226,13 +231,12 @@ private void InitializeComponent() this.exportBitmapButton.Name = "exportBitmapButton"; this.exportBitmapButton.Size = new System.Drawing.Size(177, 34); this.exportBitmapButton.TabIndex = 9; - this.exportBitmapButton.Text = "Export Selected"; + this.exportBitmapButton.Text = "Export Selected Textures"; this.exportBitmapButton.UseVisualStyleBackColor = true; this.exportBitmapButton.Click += new System.EventHandler(this.exportBitmapButton_Click); // // vramTabPage // - this.vramTabPage.Controls.Add(this.showUVCheckBox); this.vramTabPage.Controls.Add(this.btnClearPage); this.vramTabPage.Controls.Add(this.vramPageLabel); this.vramTabPage.Controls.Add(this.vramComboBox); @@ -244,19 +248,6 @@ private void InitializeComponent() this.vramTabPage.Text = "VRAM"; this.vramTabPage.UseVisualStyleBackColor = true; // - // showUVCheckBox - // - this.showUVCheckBox.AutoSize = true; - this.showUVCheckBox.Checked = true; - this.showUVCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; - this.showUVCheckBox.Location = new System.Drawing.Point(9, 310); - this.showUVCheckBox.Name = "showUVCheckBox"; - this.showUVCheckBox.Size = new System.Drawing.Size(71, 17); - this.showUVCheckBox.TabIndex = 16; - this.showUVCheckBox.Text = "Show UV"; - this.showUVCheckBox.UseVisualStyleBackColor = true; - this.showUVCheckBox.CheckedChanged += new System.EventHandler(this.showUVCheckBox_CheckedChanged); - // // btnClearPage // this.btnClearPage.Location = new System.Drawing.Point(177, 20); @@ -331,7 +322,6 @@ private void InitializeComponent() // // animationsTabPage // - this.animationsTabPage.Controls.Add(this.animationEntityComboBox); this.animationsTabPage.Controls.Add(this.animationPlayButton); this.animationsTabPage.Controls.Add(this.animationPropertyGrid); this.animationsTabPage.Controls.Add(this.animationsTreeView); @@ -342,14 +332,6 @@ private void InitializeComponent() this.animationsTabPage.Text = "Animations"; this.animationsTabPage.UseVisualStyleBackColor = true; // - // animationEntityComboBox - // - this.animationEntityComboBox.FormattingEnabled = true; - this.animationEntityComboBox.Location = new System.Drawing.Point(1, 385); - this.animationEntityComboBox.Name = "animationEntityComboBox"; - this.animationEntityComboBox.Size = new System.Drawing.Size(175, 21); - this.animationEntityComboBox.TabIndex = 17; - // // animationPlayButton // this.animationPlayButton.Enabled = false; @@ -357,17 +339,17 @@ private void InitializeComponent() this.animationPlayButton.Name = "animationPlayButton"; this.animationPlayButton.Size = new System.Drawing.Size(177, 34); this.animationPlayButton.TabIndex = 16; - this.animationPlayButton.Text = "Play/Stop"; + this.animationPlayButton.Text = "Play Animation"; this.animationPlayButton.UseVisualStyleBackColor = true; this.animationPlayButton.Click += new System.EventHandler(this.animationPlayButton_Click); // // animationPropertyGrid // this.animationPropertyGrid.HelpVisible = false; - this.animationPropertyGrid.Location = new System.Drawing.Point(1, 412); + this.animationPropertyGrid.Location = new System.Drawing.Point(1, 399); this.animationPropertyGrid.Name = "animationPropertyGrid"; this.animationPropertyGrid.PropertySort = System.Windows.Forms.PropertySort.NoSort; - this.animationPropertyGrid.Size = new System.Drawing.Size(175, 151); + this.animationPropertyGrid.Size = new System.Drawing.Size(175, 164); this.animationPropertyGrid.TabIndex = 15; this.animationPropertyGrid.ToolbarVisible = false; this.animationPropertyGrid.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.animationPropertyGrid_PropertyValueChanged); @@ -378,7 +360,7 @@ private void InitializeComponent() this.animationsTreeView.HideSelection = false; this.animationsTreeView.Location = new System.Drawing.Point(1, 3); this.animationsTreeView.Name = "animationsTreeView"; - this.animationsTreeView.Size = new System.Drawing.Size(175, 376); + this.animationsTreeView.Size = new System.Drawing.Size(175, 390); this.animationsTreeView.TabIndex = 10; this.animationsTreeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.animationsTreeView_AfterSelect); // @@ -386,29 +368,44 @@ private void InitializeComponent() // this.cmsModelExport.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.miOBJ, - this.miOBJVC}); + this.miOBJVC, + this.miOBJMerged, + this.miOBJVCMerged}); this.cmsModelExport.Name = "cmsModelExport"; + this.cmsModelExport.OwnerItem = this.exportSelectedToolStripMenuItem; this.cmsModelExport.RenderMode = System.Windows.Forms.ToolStripRenderMode.System; - this.cmsModelExport.Size = new System.Drawing.Size(301, 48); + this.cmsModelExport.Size = new System.Drawing.Size(347, 92); this.cmsModelExport.ItemClicked += new System.Windows.Forms.ToolStripItemClickedEventHandler(this.cmsModelExport_ItemClicked); // // miOBJ // this.miOBJ.Name = "miOBJ"; - this.miOBJ.Size = new System.Drawing.Size(300, 22); + this.miOBJ.Size = new System.Drawing.Size(346, 22); this.miOBJ.Text = "Wavefront .OBJ (Accepts Groups)"; // // miOBJVC // this.miOBJVC.Name = "miOBJVC"; - this.miOBJVC.Size = new System.Drawing.Size(300, 22); + this.miOBJVC.Size = new System.Drawing.Size(346, 22); this.miOBJVC.Text = "Wavefront .OBJ (Experimental Vertex Color)"; // + // miOBJMerged + // + this.miOBJMerged.Name = "miOBJMerged"; + this.miOBJMerged.Size = new System.Drawing.Size(346, 22); + this.miOBJMerged.Text = "Wavefront .OBJ (Merged-Accept Groups)"; + // + // miOBJVCMerged + // + this.miOBJVCMerged.Name = "miOBJVCMerged"; + this.miOBJVCMerged.Size = new System.Drawing.Size(346, 22); + this.miOBJVCMerged.Text = "Wavefront .OBJ (Merged-Experimental Vertex Color)"; + // // exportSelectedToolStripMenuItem // this.exportSelectedToolStripMenuItem.DropDown = this.cmsModelExport; this.exportSelectedToolStripMenuItem.Name = "exportSelectedToolStripMenuItem"; - this.exportSelectedToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.exportSelectedToolStripMenuItem.Size = new System.Drawing.Size(154, 22); this.exportSelectedToolStripMenuItem.Text = "Export Selected"; // // mainMenuStrip @@ -430,7 +427,9 @@ private void InitializeComponent() // this.modelsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.exportSelectedToolStripMenuItem, - this.wireframeToolStripMenuItem}); + this.wireframeToolStripMenuItem, + this.showGizmosToolStripMenuItem, + this.showBoundsToolStripMenuItem}); this.modelsToolStripMenuItem.Name = "modelsToolStripMenuItem"; this.modelsToolStripMenuItem.Size = new System.Drawing.Size(58, 20); this.modelsToolStripMenuItem.Text = "Models"; @@ -439,10 +438,30 @@ private void InitializeComponent() // this.wireframeToolStripMenuItem.CheckOnClick = true; this.wireframeToolStripMenuItem.Name = "wireframeToolStripMenuItem"; - this.wireframeToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.wireframeToolStripMenuItem.Size = new System.Drawing.Size(154, 22); this.wireframeToolStripMenuItem.Text = "Wireframe"; this.wireframeToolStripMenuItem.CheckedChanged += new System.EventHandler(this.wireframeToolStripMenuItem_CheckedChanged); // + // showGizmosToolStripMenuItem + // + this.showGizmosToolStripMenuItem.Checked = true; + this.showGizmosToolStripMenuItem.CheckOnClick = true; + this.showGizmosToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + this.showGizmosToolStripMenuItem.Name = "showGizmosToolStripMenuItem"; + this.showGizmosToolStripMenuItem.Size = new System.Drawing.Size(154, 22); + this.showGizmosToolStripMenuItem.Text = "Show Gizmos"; + this.showGizmosToolStripMenuItem.Click += new System.EventHandler(this.showGizmosToolStripMenuItem_Click); + // + // showBoundsToolStripMenuItem + // + this.showBoundsToolStripMenuItem.Checked = true; + this.showBoundsToolStripMenuItem.CheckOnClick = true; + this.showBoundsToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + this.showBoundsToolStripMenuItem.Name = "showBoundsToolStripMenuItem"; + this.showBoundsToolStripMenuItem.Size = new System.Drawing.Size(154, 22); + this.showBoundsToolStripMenuItem.Text = "Show Bounds"; + this.showBoundsToolStripMenuItem.Click += new System.EventHandler(this.showBoundsToolStripMenuItem_Click); + // // texturesToolStripMenuItem // this.texturesToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -486,7 +505,8 @@ private void InitializeComponent() // this.vRAMToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.clearPageToolStripMenuItem, - this.clearAllPagesToolStripMenuItem}); + this.clearAllPagesToolStripMenuItem, + this.showUVToolStripMenuItem}); this.vRAMToolStripMenuItem.Name = "vRAMToolStripMenuItem"; this.vRAMToolStripMenuItem.Size = new System.Drawing.Size(52, 20); this.vRAMToolStripMenuItem.Text = "VRAM"; @@ -505,12 +525,30 @@ private void InitializeComponent() this.clearAllPagesToolStripMenuItem.Text = "Clear All Pages"; this.clearAllPagesToolStripMenuItem.Click += new System.EventHandler(this.clearAllPagesToolStripMenuItem_Click); // + // showUVToolStripMenuItem + // + this.showUVToolStripMenuItem.CheckOnClick = true; + this.showUVToolStripMenuItem.Name = "showUVToolStripMenuItem"; + this.showUVToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.showUVToolStripMenuItem.Text = "Show UV"; + this.showUVToolStripMenuItem.Click += new System.EventHandler(this.showUVToolStripMenuItem_Click); + // // animationsToolStripMenuItem // + this.animationsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.showSkeletonToolStripMenuItem}); this.animationsToolStripMenuItem.Name = "animationsToolStripMenuItem"; this.animationsToolStripMenuItem.Size = new System.Drawing.Size(80, 20); this.animationsToolStripMenuItem.Text = "Animations"; // + // showSkeletonToolStripMenuItem + // + this.showSkeletonToolStripMenuItem.CheckOnClick = true; + this.showSkeletonToolStripMenuItem.Name = "showSkeletonToolStripMenuItem"; + this.showSkeletonToolStripMenuItem.Size = new System.Drawing.Size(151, 22); + this.showSkeletonToolStripMenuItem.Text = "Show Skeleton"; + this.showSkeletonToolStripMenuItem.CheckedChanged += new System.EventHandler(this.showSkeletonToolStripMenuItem_CheckedChanged); + // // statusStrip1 // this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -548,7 +586,7 @@ private void InitializeComponent() this.Name = "PreviewForm"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "PSXPrev Alpha 0.9.1"; + this.Text = "PSXPrev Alpha 0.9.2"; this.Load += new System.EventHandler(this.previewForm_Load); this.entitiesTabPage.ResumeLayout(false); this.menusTabControl.ResumeLayout(false); @@ -610,10 +648,14 @@ private void InitializeComponent() private System.Windows.Forms.PropertyGrid animationPropertyGrid; private System.Windows.Forms.TreeView animationsTreeView; private System.Windows.Forms.Button animationPlayButton; - private System.Windows.Forms.ComboBox animationEntityComboBox; private System.Windows.Forms.StatusStrip statusStrip1; private System.Windows.Forms.ToolStripProgressBar toolStripProgressBar1; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; - private System.Windows.Forms.CheckBox showUVCheckBox; + private System.Windows.Forms.ToolStripMenuItem miOBJMerged; + private System.Windows.Forms.ToolStripMenuItem miOBJVCMerged; + private System.Windows.Forms.ToolStripMenuItem showGizmosToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem showBoundsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem showUVToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem showSkeletonToolStripMenuItem; } } \ No newline at end of file diff --git a/Forms/PreviewForm.cs b/Forms/PreviewForm.cs index 294c439..5f30aac 100644 --- a/Forms/PreviewForm.cs +++ b/Forms/PreviewForm.cs @@ -1,92 +1,108 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.Globalization; -using System.Threading; using System.Timers; using System.Windows.Forms; using OpenTK; -using PSXPrev.Forms; using Timer = System.Timers.Timer; namespace PSXPrev { public partial class PreviewForm : Form { - private Timer _animateTimer; - private List _animations; - private Animation _curAnimation; - private int _curAnimationFrame; - private Action _refreshAction; + private enum MouseEventType + { + Down, + Up, + Move, + Wheel + } - private bool _inAnimationTab; + private enum EntitySelectionSource + { + None, + TreeView, + Click + } - //private bool _debug; - private float _lastMouseX; + private const float MouseSensivity = 0.0035f; - private float _lastMouseY; - private GLControl _openTkControl; - private bool _playing; - private Timer _redrawTimer; - private List _rootEntities; + private static Pen Black3Px = new Pen(System.Drawing.Color.Black, 3f); + private static Pen White1Px = new Pen(System.Drawing.Color.White, 1f); + private Timer _animateTimer; + private Timer _redrawTimer; + private readonly List _animations; + private readonly Action _refreshAction; + private GLControl _openTkControl; private Scene _scene; - - //private int _selectedTriangle; - private List _textures; - + private readonly List _rootEntities; + private readonly List _textures; private Texture[] _vramPage; - + private Scene.GizmoId _selectedGizmo; + private EntitySelectionSource _selectionSource; + private bool _playing; private bool _showUv = true; + private bool _inAnimationTab; + private float _lastMouseX; + private float _lastMouseY; + private int _curAnimationFrame; + private Animation _curAnimation; + private AnimationObject _curAnimationObject; + private RootEntity _curEntity; + private ModelEntity _curModel; - public PreviewForm(Action refreshAction, bool debug) + private bool Playing { - _refreshAction = refreshAction; + get => _playing; + set + { + _playing = value; + if (_playing) + { + animationPlayButton.Text = "Stop Animation"; + _animateTimer.Start(); + } + else + { + animationPlayButton.Text = "Play Animation"; + _animateTimer.Stop(); + } + } + } + public PreviewForm(Action refreshAction) + { + _refreshAction = refreshAction; _animations = new List(); _textures = new List(); _rootEntities = new List(); - - SetupCulture(); + _vramPage = new Texture[32]; + _scene = new Scene(); refreshAction(this); - - SetupInternals(); - Toolkit.Init(); - InitializeComponent(); SetupControls(); - //ResetSelectedTriangle(); } private void EntityAdded(RootEntity entity) { - // set textures for preview foreach (var entityBase in entity.ChildEntities) { var model = (ModelEntity)entityBase; model.TexturePage = Math.Min(31, Math.Max(0, model.TexturePage)); model.Texture = _vramPage[model.TexturePage]; } - entitiesTreeView.BeginUpdate(); var entityNode = entitiesTreeView.Nodes.Add(entity.EntityName); - animationEntityComboBox.Items.Add(entity); + entityNode.Tag = entity; for (var m = 0; m < entity.ChildEntities.Length; m++) { - // var model = (ModelEntity) entity.ChildEntities[m]; - var modelNode = new TreeNode("Sub-Model " + m); + var modelNode = new TreeNode("Sub-Model " + (m + 1)); + modelNode.Tag = entity.ChildEntities[m]; entityNode.Nodes.Add(modelNode); modelNode.HideCheckBox(); modelNode.HideCheckBox(); - //if (_debug) - // for (var t = 0; t < model.Triangles.Length; t++) - // { - // var triangleNode = new TreeNode("Triangle " + t); - // modelNode.Nodes.Add(triangleNode); - // triangleNode.HideCheckBox(); - // triangleNode.HideCheckBox(); - // } } entitiesTreeView.EndUpdate(); } @@ -100,7 +116,8 @@ private void TextureAdded(Texture texture, int index) private void AnimationAdded(Animation animation) { animationsTreeView.BeginUpdate(); - var animationNode = new TreeNode(animation.AnimationName) { Tag = animation }; + var animationNode = new TreeNode(animation.AnimationName); + animationNode.Tag = animation; animationsTreeView.Nodes.Add(animationNode); AddAnimationObject(animation.RootAnimationObject, animationNode); animationsTreeView.EndUpdate(); @@ -108,74 +125,61 @@ private void AnimationAdded(Animation animation) public void UpdateRootEntities(List entities) { - for (var i = 0; i < entities.Count; ++i) + foreach (var entity in entities) { - var entity = entities[i]; - if (!_rootEntities.Contains(entity)) + if (_rootEntities.Contains(entity)) { - _rootEntities.Add(entity); - EntityAdded(entity); + continue; } + _rootEntities.Add(entity); + EntityAdded(entity); } } public void UpdateTextures(List textures) { - for (var i = 0; i < textures.Count; ++i) + foreach (var texture in textures) { - var texture = textures[i]; - if (!_textures.Contains(texture)) + if (_textures.Contains(texture)) { - _textures.Add(texture); - var textureIndex = _textures.IndexOf(texture); - TextureAdded(texture, textureIndex); + continue; } + _textures.Add(texture); + var textureIndex = _textures.IndexOf(texture); + TextureAdded(texture, textureIndex); } } public void UpdateAnimations(List animations) { - for (var i = 0; i < animations.Count; ++i) + foreach (var animation in animations) { - var animation = animations[i]; - if (!_animations.Contains(animation)) + if (_animations.Contains(animation)) { - _animations.Add(animation); - AnimationAdded(animation); + continue; } + _animations.Add(animation); + AnimationAdded(animation); } } - public System.Drawing.Color SceneBackColor + private System.Drawing.Color SceneBackColor { set { if (_scene == null) + { throw new Exception("Window must be initialized"); - + } _scene.ClearColor = new Color - { - R = value.R / 255f, - G = value.G / 255f, - B = value.B / 255f - }; + ( + value.R / 255f, + value.G / 255f, + value.B / 255f + ); } } - private void SetupCulture() - { - var customCulture = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone(); - customCulture.NumberFormat.NumberDecimalSeparator = "."; - Thread.CurrentThread.CurrentCulture = customCulture; - } - - private void SetupInternals() - { - _vramPage = new Texture[32]; - //_debug = debug; - _scene = new Scene(); - } - private void SetupControls() { _openTkControl = new GLControl @@ -188,8 +192,10 @@ private void SetupControls() VSync = true }; _openTkControl.Load += openTKControl_Load; - _openTkControl.MouseWheel += openTkControl_MouseWhell; - _openTkControl.MouseMove += openTkControl_MouseEvent; + _openTkControl.MouseDown += delegate (object sender, MouseEventArgs e) { openTkControl_MouseEvent(e, MouseEventType.Down); }; + _openTkControl.MouseUp += delegate (object sender, MouseEventArgs e) { openTkControl_MouseEvent(e, MouseEventType.Up); }; + _openTkControl.MouseWheel += delegate (object sender, MouseEventArgs e) { openTkControl_MouseEvent(e, MouseEventType.Wheel); }; + _openTkControl.MouseMove += delegate (object sender, MouseEventArgs e) { openTkControl_MouseEvent(e, MouseEventType.Move); }; _openTkControl.Paint += _openTkControl_Paint; entitiesTabPage.Controls.Add(_openTkControl); } @@ -198,17 +204,12 @@ private void _openTkControl_Paint(object sender, PaintEventArgs e) { if (_inAnimationTab && _curAnimation != null) { - _scene.AnimationBatch.SetupAnimationFrame(_curAnimationFrame); + _scene.AnimationBatch.SetupAnimationFrame(_curAnimationFrame, _curAnimationObject, _curEntity); } _scene.Draw(); _openTkControl.SwapBuffers(); } - //private void ResetSelectedTriangle() - //{ - // _selectedTriangle = int.MaxValue; - //} - private void SetupScene() { _scene.Initialise(Width, Height); @@ -230,18 +231,16 @@ private void SetupTextures() private void SetupEntities() { - for (var e = 0; e < _rootEntities.Count; e++) + foreach (var entity in _rootEntities) { - var entity = _rootEntities[e]; EntityAdded(entity); } } private void SetupAnimations() { - for (var a = 0; a < _animations.Count; a++) + foreach (var animation in _animations) { - var animation = _animations[a]; AnimationAdded(animation); } } @@ -252,10 +251,19 @@ private void AddAnimationObject(AnimationObject parent, TreeNode parentNode) for (var o = 0; o < animationObjects.Count; o++) { var animationObject = animationObjects[o]; - var animationObjectNode = new TreeNode("Animation-Object " + o) { Tag = animationObject }; + var animationObjectNode = new TreeNode("Animation-Object " + (o + 1)); + animationObjectNode.Tag = animationObject; parentNode.Nodes.Add(animationObjectNode); animationObjectNode.HideCheckBox(); animationObjectNode.HideCheckBox(); + //foreach (var animationFrame in animationObject.AnimationFrames) + //{ + // var animationFrameNode = new TreeNode("Frame " + animationFrame.Value.FrameTime); + // animationFrameNode.Tag = animationFrame.Value; + // // animationFrameNode.HideCheckBox(); + // //animationFrameNode.HideCheckBox(); + // animationObjectNode.Nodes.Add(animationFrameNode); + //} AddAnimationObject(animationObject, animationObjectNode); } } @@ -279,19 +287,34 @@ private void previewForm_Load(object sender, EventArgs e) _redrawTimer.Interval = 1f / 60f; _redrawTimer.Elapsed += _redrawTimer_Elapsed; _redrawTimer.Start(); - _animateTimer = new Timer(); - _animateTimer.Interval = 1f / 60f; _animateTimer.Elapsed += _animateTimer_Elapsed; } + //private AnimationFrame GetSelectedAnimationFrame() + //{ + // var selectedNode = animationsTreeView.SelectedNode; + // if (selectedNode != null) + // { + // var selectedAnimationFrame = selectedNode.Tag as AnimationFrame; + // if (selectedAnimationFrame != null) + // { + // return selectedAnimationFrame; + // } + // } + // return null; + //} + private void _animateTimer_Elapsed(object sender, ElapsedEventArgs e) { if (_curAnimationFrame < _curAnimation.FrameCount) + { _curAnimationFrame++; + } else + { _curAnimationFrame = 0; - //animationTrackBar.Value = _curAnimationFrame; + } } private void _redrawTimer_Elapsed(object sender, ElapsedEventArgs e) @@ -299,18 +322,18 @@ private void _redrawTimer_Elapsed(object sender, ElapsedEventArgs e) Redraw(); } - private RootEntity[] GetSelectectedEntities() + private RootEntity[] GetCheckedEntities() { var selectedEntities = new List(); for (var i = 0; i < entitiesTreeView.Nodes.Count; i++) { var node = entitiesTreeView.Nodes[i]; if (node.Checked) + { selectedEntities.Add(_rootEntities[i]); + } } - if (selectedEntities.Count == 0) - return null; - return selectedEntities.ToArray(); + return selectedEntities.Count == 0 ? null : selectedEntities.ToArray(); } private DialogResult ShowEntityFolderSelect(out string path) @@ -336,28 +359,123 @@ private void exportBitmapButton_Click(object sender, EventArgs e) return; } var fbd = new FolderBrowserDialog { Description = "Select the output folder" }; - if (fbd.ShowDialog() == DialogResult.OK) + if (fbd.ShowDialog() != DialogResult.OK) + { + return; + } + var selectedTextures = new Texture[selectedCount]; + for (var i = 0; i < selectedCount; i++) { - var selectedTextures = new Texture[selectedCount]; - for (var i = 0; i < selectedCount; i++) - selectedTextures[i] = _textures[selectedIndices[i]]; - var exporter = new PngExporter(); - exporter.Export(selectedTextures, fbd.SelectedPath); - MessageBox.Show("Textures exported"); + selectedTextures[i] = _textures[selectedIndices[i]]; } + var exporter = new PngExporter(); + exporter.Export(selectedTextures, fbd.SelectedPath); + MessageBox.Show("Textures exported"); } - private void openTkControl_MouseWhell(object sender, MouseEventArgs e) + private void SelectEntity(RootEntity rootEntity) { - _scene.CameraDistance -= e.Delta * Scene.MouseSensivity * _scene.CameraDistanceIncrement; + _selectionSource = EntitySelectionSource.Click; + var rootIndex = _rootEntities.IndexOf(rootEntity); + entitiesTreeView.SelectedNode = entitiesTreeView.Nodes[rootIndex]; } - private void openTkControl_MouseEvent(object sender, MouseEventArgs e) + private void openTkControl_MouseEvent(MouseEventArgs e, MouseEventType t) { - if (e.Button == MouseButtons.Left) + if (t == MouseEventType.Wheel) { - _scene.CameraYaw -= (e.X - _lastMouseX) * Scene.MouseSensivity; - _scene.CameraPitch += (e.Y - _lastMouseY) * Scene.MouseSensivity; + _scene.CameraDistance -= e.Delta * MouseSensivity * _scene.CameraDistanceIncrement; + _scene.UpdateViewMatrix(); + UpdateGizmos(_selectedGizmo, false); + return; + } + var selectedEntityBase = (EntityBase)_curEntity ?? _curModel; + var selectedGizmo = _selectedGizmo; + var deltaX = e.X - _lastMouseX; + var deltaY = e.Y - _lastMouseY; + var mouseLeft = e.Button == MouseButtons.Left; + var mouseMiddle = e.Button == MouseButtons.Middle; + var mouseRight = e.Button == MouseButtons.Right; + var controlWidth = _openTkControl.Size.Width; + var controlHeight = _openTkControl.Size.Height; + switch (_selectedGizmo) + { + case Scene.GizmoId.None: + if (mouseLeft && t == MouseEventType.Down) + { + selectedGizmo = _scene.GetGizmoUnderPosition(e.Location.X, e.Location.Y, controlWidth, controlHeight, selectedEntityBase); + if (selectedGizmo == Scene.GizmoId.None) + { + var checkedEntities = GetCheckedEntities(); + var newSelectedEntity = _scene.GetRootEntityUnderMouse(checkedEntities, _curEntity, e.Location.X, e.Location.Y, controlWidth, controlHeight); + if (newSelectedEntity != null && newSelectedEntity != selectedEntityBase) + { + SelectEntity(newSelectedEntity); + } + } + } + else + { + var hasToUpdateViewMatrix = false; + if (mouseRight && t == MouseEventType.Move) + { + _scene.CameraYaw -= deltaX * MouseSensivity; + _scene.CameraPitch += deltaY * MouseSensivity; + hasToUpdateViewMatrix = true; + } + if (mouseMiddle && t == MouseEventType.Move) + { + _scene.CameraX += deltaX * MouseSensivity * _scene.CameraPanIncrement; + _scene.CameraY += deltaY * MouseSensivity * _scene.CameraPanIncrement; + hasToUpdateViewMatrix = true; + } + if (hasToUpdateViewMatrix) + { + _scene.UpdateViewMatrix(); + UpdateGizmos(_selectedGizmo, false); + } + } + break; + case Scene.GizmoId.XMover: + if (mouseLeft && t == MouseEventType.Move && selectedEntityBase != null) + { + var offset = _scene.GetGizmoProjectionOffset(e.Location.X, e.Location.Y, controlWidth, controlHeight, selectedEntityBase, _scene.GetBestPlaneNormal(GeomUtils.ZVector, GeomUtils.YVector), GeomUtils.XVector); + selectedEntityBase.PositionX += offset.X; + UpdateSelectedEntity(false); + } + else + { + selectedGizmo = Scene.GizmoId.None; + } + break; + case Scene.GizmoId.YMover: + if (mouseLeft && t == MouseEventType.Move && selectedEntityBase != null) + { + var offset = _scene.GetGizmoProjectionOffset(e.Location.X, e.Location.Y, controlWidth, controlHeight, selectedEntityBase, _scene.GetBestPlaneNormal(GeomUtils.ZVector, GeomUtils.XVector), GeomUtils.YVector); + selectedEntityBase.PositionY += offset.Y; + UpdateSelectedEntity(false); + } + else + { + selectedGizmo = Scene.GizmoId.None; + } + break; + case Scene.GizmoId.ZMover: + if (mouseLeft && t == MouseEventType.Move && selectedEntityBase != null) + { + var offset = _scene.GetGizmoProjectionOffset(e.Location.X, e.Location.Y, controlWidth, controlHeight, selectedEntityBase, _scene.GetBestPlaneNormal(GeomUtils.YVector, GeomUtils.XVector), GeomUtils.ZVector); + selectedEntityBase.PositionZ += offset.Z; + UpdateSelectedEntity(false); + } + else + { + selectedGizmo = Scene.GizmoId.None; + } + break; + } + if (selectedGizmo != _selectedGizmo) + { + UpdateGizmos(selectedGizmo); } _lastMouseX = e.X; _lastMouseY = e.Y; @@ -365,90 +483,92 @@ private void openTkControl_MouseEvent(object sender, MouseEventArgs e) private void entitiesTreeView_AfterSelect(object sender, TreeViewEventArgs e) { - var node = e.Node; - var nodeIndex = node.Index; - var nodeLevel = node.Level; - SelectModelOrEntity(nodeIndex, nodeLevel, true); - } - - private object SelectModelOrEntity(int nodeIndex, int nodeLevel, bool focus) - { - //_scene.LineBatch.Reset(); - ModelEntity model; - switch (nodeLevel) + if (_selectionSource == EntitySelectionSource.None) { - case 0: - var entity = GetSelectedEntity(nodeIndex); - //ResetSelectedTriangle(); - _scene.MeshBatch.SetupEntityBatch(entity, focus); - modelPropertyGrid.SelectedObject = entity; - return entity; - case 1: - model = GetSelectedModel(); - //ResetSelectedTriangle(); - _scene.MeshBatch.SetupModelBatch(model, focus); - modelPropertyGrid.SelectedObject = model; - return model; - case 2: - model = GetSelectedModel(true); - //_selectedTriangle = (ushort) nodeIndex; - _scene.MeshBatch.SetupModelBatch(model); - var triangle = model.Triangles[nodeIndex]; - modelPropertyGrid.SelectedObject = triangle; - return model; - } - return null; + _selectionSource = EntitySelectionSource.TreeView; + } + var selectedNode = entitiesTreeView.SelectedNode; + if (selectedNode != null) + { + _curEntity = selectedNode.Tag as RootEntity; + _curModel = selectedNode.Tag as ModelEntity; + } + UpdateSelectedEntity(); } - private Texture GetSelectedTexture(int? index = null) + private void UpdateGizmos(Scene.GizmoId selectedGizmo = Scene.GizmoId.None, bool updateMeshData = true) { - if (texturesListView.SelectedIndices.Count == 0) - return null; - var textureIndex = index ?? texturesListView.SelectedIndices[0]; - if (textureIndex < 0) - return null; - return _textures[textureIndex]; + if (updateMeshData) + { + _scene.GizmosMeshBatch.Reset(3); + } + var selectedEntityBase = (EntityBase)_curEntity ?? _curModel; + if (selectedEntityBase == null) + { + return; + } + var matrix = selectedEntityBase.WorldMatrix; + var scaleMatrix = _scene.GetGizmoScaleMatrix(matrix.ExtractTranslation()); + var finalMatrix = scaleMatrix * matrix; + _scene.GizmosMeshBatch.BindCube(finalMatrix, selectedGizmo == Scene.GizmoId.XMover ? Color.White : Color.Red, Scene.XGizmoDimensions, Scene.XGizmoDimensions, 0, null, updateMeshData); + _scene.GizmosMeshBatch.BindCube(finalMatrix, selectedGizmo == Scene.GizmoId.YMover ? Color.White : Color.Green, Scene.YGizmoDimensions, Scene.YGizmoDimensions, 1, null, updateMeshData); + _scene.GizmosMeshBatch.BindCube(finalMatrix, selectedGizmo == Scene.GizmoId.ZMover ? Color.White : Color.Blue, Scene.ZGizmoDimensions, Scene.ZGizmoDimensions, 2, null, updateMeshData); + _selectedGizmo = selectedGizmo; } - private RootEntity GetSelectedEntity(int? entityIndex = null) + private void UpdateSelectedEntity(bool updateMeshData = true) { - int index; - if (entitiesTreeView.SelectedNode == null) - return null; - if (entityIndex == null) - index = entitiesTreeView.SelectedNode.Index; + _scene.BoundsBatch.Reset(); + _scene.SkeletonBatch.Reset(); + var selectedEntityBase = (EntityBase)_curEntity ?? _curModel; + if (selectedEntityBase != null) + { + selectedEntityBase.ComputeBoundsRecursively(); + modelPropertyGrid.SelectedObject = selectedEntityBase; + var checkedEntities = GetCheckedEntities(); + _scene.BoundsBatch.SetupEntityBounds(selectedEntityBase); + _scene.MeshBatch.SetupMultipleEntityBatch(checkedEntities, _curModel, _curEntity, _scene.TextureBinder, updateMeshData, _selectionSource == EntitySelectionSource.TreeView && _curModel == null); + } else - index = (int)entityIndex; - if (index < 0) - return null; - var entity = _rootEntities[index]; - return entity; + { + modelPropertyGrid.SelectedObject = null; + _scene.MeshBatch.Reset(0); + _selectedGizmo = Scene.GizmoId.None; + } + UpdateGizmos(_selectedGizmo, updateMeshData); + _selectionSource = EntitySelectionSource.None; } - private ModelEntity GetSelectedModel(bool fromTriangle = false) + private void UpdateSelectedAnimation() { - var selectedNode = entitiesTreeView.SelectedNode; - if (selectedNode == null) + var selectedObject = (object) _curAnimationObject ?? _curAnimation; + if (selectedObject == null) { - return null; + return; } - var parentNode = selectedNode.Parent; - int childIndex; - int parentIndex; - if (!fromTriangle) + if (_curAnimation != null) { - childIndex = selectedNode.Index; - parentIndex = parentNode.Index; + _curAnimationFrame = 0; + _animateTimer.Interval = 1f / _curAnimation.FPS; + animationPlayButton.Enabled = true; + Playing = false; } - else + animationPropertyGrid.SelectedObject = selectedObject; + _scene.AnimationBatch.SetupAnimationBatch(_curAnimation); + } + + private Texture GetSelectedTexture(int? index = null) + { + if (texturesListView.SelectedIndices.Count == 0) { - childIndex = parentNode.Index; - parentIndex = parentNode.Parent.Index; + return null; } - if (childIndex < 0) + var textureIndex = index ?? texturesListView.SelectedIndices[0]; + if (textureIndex < 0) + { return null; - var model = (ModelEntity)_rootEntities[parentIndex].ChildEntities[childIndex]; - return model; + } + return _textures[textureIndex]; } private void drawToVRAMButton_Click(object sender, EventArgs e) @@ -488,37 +608,38 @@ private void modelPropertyGrid_PropertyValueChanged(object s, PropertyValueChang { var selectedNode = entitiesTreeView.SelectedNode; if (selectedNode == null) + { return; - var nodeLevel = selectedNode.Level; - var nodeIndex = selectedNode.Level; - if (nodeLevel == 0) + } + if (_curEntity != null) { - var entity = GetSelectedEntity(); - selectedNode.Text = entity.EntityName; + selectedNode.Text = _curEntity.EntityName; } - else + else if (_curModel != null) { - var model = GetSelectedModel(); - if (model != null) - { - model.TexturePage = Math.Min(31, Math.Max(0, model.TexturePage)); - model.Texture = _vramPage[model.TexturePage]; - } + _curModel.TexturePage = Math.Min(31, Math.Max(0, _curModel.TexturePage)); + _curModel.Texture = _vramPage[_curModel.TexturePage]; } - SelectModelOrEntity(nodeIndex, nodeLevel, false); + UpdateSelectedEntity(false); } private void texturePropertyGrid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) { var selectedNodes = texturesListView.SelectedItems; if (selectedNodes.Count == 0) + { return; + } var selectedNode = selectedNodes[0]; if (selectedNode == null) + { return; + } var texture = GetSelectedTexture(); if (texture == null) + { return; + } texture.X = Math.Min(255, Math.Max(0, texture.X)); texture.Y = Math.Min(255, Math.Max(0, texture.Y)); texture.TexturePage = Math.Min(31, Math.Max(0, texture.TexturePage)); @@ -548,7 +669,7 @@ private void ClearPage(int index) private void cmsModelExport_ItemClicked(object sender, ToolStripItemClickedEventArgs e) { - var entities = GetSelectectedEntities(); + var entities = GetCheckedEntities(); if (entities == null) { MessageBox.Show("Check the models to export first"); @@ -567,16 +688,16 @@ private void cmsModelExport_ItemClicked(object sender, ToolStripItemClickedEvent var objExporter = new ObjExporter(); objExporter.Export(entities, path, true); } - //if (e.ClickedItem == miPLY) - //{ - // var plyExporter = new PlyExporter(); - // plyExporter.Export(entities, path); - //} - //if (e.ClickedItem == miDAE) - //{ - // var daeExporter = new DaeExporter(); - // daeExporter.Export(entities, path); - //} + if (e.ClickedItem == miOBJMerged) + { + var objExporter = new ObjExporter(); + objExporter.Export(entities, path, false, true); + } + if (e.ClickedItem == miOBJVCMerged) + { + var objExporter = new ObjExporter(); + objExporter.Export(entities, path, true, true); + } MessageBox.Show("Models exported"); } } @@ -586,7 +707,9 @@ private void findByPageToolStripMenuItem_Click(object sender, EventArgs e) var pageIndexString = Utils.ShowDialog("Find by Page", "Type the page number"); int pageIndex; if (string.IsNullOrEmpty(pageIndexString)) + { return; + } if (!int.TryParse(pageIndexString, out pageIndex)) { MessageBox.Show("Invalid page number"); @@ -598,16 +721,14 @@ private void findByPageToolStripMenuItem_Click(object sender, EventArgs e) var item = texturesListView.Items[i]; item.Group = null; var texture = _textures[i]; - if (texture.TexturePage == pageIndex) + if (texture.TexturePage != pageIndex) { - item.Group = texturesListView.Groups[0]; - found++; + continue; } + item.Group = texturesListView.Groups[0]; + found++; } - if (found > 0) - MessageBox.Show(string.Format("Found {0} itens", found)); - else - MessageBox.Show("Nothing found"); + MessageBox.Show(found > 0 ? $"Found {found} items" : "Nothing found"); } private void texturesListView_SelectedIndexChanged(object sender, EventArgs e) @@ -619,7 +740,9 @@ private void texturesListView_SelectedIndexChanged(object sender, EventArgs e) } var texture = GetSelectedTexture(); if (texture == null) + { return; + } var bitmap = texture.Bitmap; texturePreviewPictureBox.Image = bitmap; texturePreviewPictureBox.Refresh(); @@ -632,23 +755,32 @@ private void DrawUV(EntityBase entity, Graphics graphics) { return; } - var modelEntity = entity as ModelEntity; - if (modelEntity != null && modelEntity.HasUvs) + if (entity is ModelEntity modelEntity && modelEntity.HasUvs) { foreach (var triangle in modelEntity.Triangles) { - graphics.DrawLine(Pens.Green, triangle.Uv[0].X * 255f, triangle.Uv[0].Y * 255f, triangle.Uv[1].X * 255f, triangle.Uv[1].Y * 255f); - graphics.DrawLine(Pens.Green, triangle.Uv[1].X * 255f, triangle.Uv[1].Y * 255f, triangle.Uv[2].X * 255f, triangle.Uv[2].Y * 255f); - graphics.DrawLine(Pens.Green, triangle.Uv[2].X * 255f, triangle.Uv[2].Y * 255f, triangle.Uv[0].X * 255f, triangle.Uv[0].Y * 255f); + graphics.DrawLine(Black3Px, triangle.Uv[0].X * 255f, triangle.Uv[0].Y * 255f, triangle.Uv[1].X * 255f, triangle.Uv[1].Y * 255f); + graphics.DrawLine(Black3Px, triangle.Uv[1].X * 255f, triangle.Uv[1].Y * 255f, triangle.Uv[2].X * 255f, triangle.Uv[2].Y * 255f); + graphics.DrawLine(Black3Px, triangle.Uv[2].X * 255f, triangle.Uv[2].Y * 255f, triangle.Uv[0].X * 255f, triangle.Uv[0].Y * 255f); } } - if (entity.ChildEntities != null) + if (entity is ModelEntity modelEntity2 && modelEntity2.HasUvs) { - foreach (var subEntity in entity.ChildEntities) + foreach (var triangle in modelEntity2.Triangles) { - DrawUV(subEntity, graphics); + graphics.DrawLine(White1Px, triangle.Uv[0].X * 255f, triangle.Uv[0].Y * 255f, triangle.Uv[1].X * 255f, triangle.Uv[1].Y * 255f); + graphics.DrawLine(White1Px, triangle.Uv[1].X * 255f, triangle.Uv[1].Y * 255f, triangle.Uv[2].X * 255f, triangle.Uv[2].Y * 255f); + graphics.DrawLine(White1Px, triangle.Uv[2].X * 255f, triangle.Uv[2].Y * 255f, triangle.Uv[0].X * 255f, triangle.Uv[0].Y * 255f); } } + if (entity.ChildEntities == null) + { + return; + } + foreach (var subEntity in entity.ChildEntities) + { + DrawUV(subEntity, graphics); + } } private void clearSearchToolStripMenuItem_Click(object sender, EventArgs e) @@ -663,13 +795,15 @@ private void clearSearchToolStripMenuItem_Click(object sender, EventArgs e) private void wireframeToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { - _scene.WireFrame = wireframeToolStripMenuItem.Checked; + _scene.Wireframe = wireframeToolStripMenuItem.Checked; } private void clearAllPagesToolStripMenuItem_Click(object sender, EventArgs e) { for (var i = 0; i < 32; i++) + { ClearPage(i); + } MessageBox.Show("Pages cleared"); } @@ -700,9 +834,9 @@ private void menusTabControl_SelectedIndexChanged(object sender, EventArgs e) break; case 3: _inAnimationTab = true; - entitiesTreeView.SelectedNode = null; _openTkControl.Parent = menusTabControl.TabPages[3]; _openTkControl.Show(); + UpdateSelectedAnimation(); break; default: _openTkControl.Parent = this; @@ -712,76 +846,40 @@ private void menusTabControl_SelectedIndexChanged(object sender, EventArgs e) } private void animationsTreeView_AfterSelect(object sender, TreeViewEventArgs e) - { - SelectAnimationOrObject(); - } - - private void SelectAnimationOrObject() { var selectedNode = animationsTreeView.SelectedNode; if (selectedNode == null) { - _curAnimation = null; - _curAnimationFrame = 0; - animationPlayButton.Enabled = false; return; } - Animation animation; - var result = selectedNode.Tag; - animationPropertyGrid.SelectedObject = result; - if (animationsTreeView.SelectedNode.Level == 0) + if (selectedNode.Tag is Animation animation) { - animation = (Animation)result; + _curAnimation = animation; + _curAnimationObject = null; } - else - { - var animationObject = (AnimationObject)selectedNode.Tag; - animation = animationObject.Animation; - UnselectAllAnimationObjects(animation.RootAnimationObject); - animationObject.IsSelected = true; - } - _curAnimation = animation; - _curAnimationFrame = 0; - animationPlayButton.Enabled = true; - _scene.AnimationBatch.SetupAnimationBatch(_curAnimation); - } - - private void UnselectAllAnimationObjects(AnimationObject rootAnimationObject) - { - foreach (var animationObject in rootAnimationObject.Children) + if (selectedNode.Tag is AnimationObject animationObject) { - animationObject.IsSelected = false; - UnselectAllAnimationObjects(animationObject); + _curAnimation = animationObject.Animation; + _curAnimationObject = animationObject; } + UpdateSelectedAnimation(); } private void animationPropertyGrid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) { - SelectAnimationOrObject(); + UpdateSelectedAnimation(); } private void animationPlayButton_Click(object sender, EventArgs e) { - if (_playing) - { - _animateTimer.Stop(); - _playing = false; - } - else - { - _animateTimer.Start(); - _playing = true; - } + Playing = !Playing; } public void UpdateProgress(int value, int max, bool complete, string message) { if (InvokeRequired) { - var invokeAction = new Action((a, b, c, d) => - UpdateProgress(a, b, c, d) - ); - + var invokeAction = new Action(UpdateProgress); Invoke(invokeAction, value, max, complete, message); } else @@ -803,23 +901,55 @@ public void ReloadItems() else { _refreshAction(this); - Redraw(); } } - private void showUVCheckBox_CheckedChanged(object sender, EventArgs e) + private void vramPagePictureBox_Paint(object sender, PaintEventArgs e) + { + if (!_showUv) + { + return; + } + var checkedEntities = GetCheckedEntities(); + if (checkedEntities != null) + { + foreach (var checkedEntity in checkedEntities) + { + if (checkedEntity == _curEntity) + { + continue; + } + DrawUV(checkedEntity, e.Graphics); + } + } + DrawUV(_curEntity, e.Graphics); + } + + private void entitiesTreeView_AfterCheck(object sender, TreeViewEventArgs e) { - _showUv = showUVCheckBox.Checked; + UpdateSelectedEntity(); + } + + private void showGizmosToolStripMenuItem_Click(object sender, EventArgs e) + { + _scene.ShowGizmos = showGizmosToolStripMenuItem.Checked; + } + + private void showBoundsToolStripMenuItem_Click(object sender, EventArgs e) + { + _scene.ShowBounds = showBoundsToolStripMenuItem.Checked; + } + + private void showUVToolStripMenuItem_Click(object sender, EventArgs e) + { + _showUv = showUVToolStripMenuItem.Checked; vramPagePictureBox.Refresh(); } - private void vramPagePictureBox_Paint(object sender, PaintEventArgs e) + private void showSkeletonToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { - if (_showUv) - { - DrawUV(GetSelectedEntity(), e.Graphics); - } + _scene.ShowSkeleton = showSkeletonToolStripMenuItem.Checked; } } } \ No newline at end of file diff --git a/Program.cs b/Program.cs index 812f708..a492ada 100644 --- a/Program.cs +++ b/Program.cs @@ -151,7 +151,7 @@ internal static void DoScan(string path, string filter, bool checkTmd, bool chec form.UpdateAnimations(AllAnimations); form.UpdateRootEntities(AllEntities); form.UpdateTextures(AllTextures); - }, debug); + }); var t = new Thread(new ThreadStart(delegate { @@ -328,13 +328,25 @@ private static void ScanFiles() { foreach (var parser in parsers) { - var stream = fileInfo.OpenRead(); - ProcessFile(stream, file, parser); + using (var stream = fileInfo.OpenRead()) + { + ProcessFile(stream, file, parser); + } } } } } } + else if (File.Exists(_path)) + { + Parallel.ForEach(parsers, parser => + { + using (var fs = File.Open(_path, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + ProcessFile(fs, _path, parser); + } + }); + } else { ProcessFiles(_path, _filter, parsers); diff --git a/Shaders/Shader.frag b/Shaders/Shader.frag index 84870ca..f89fa5d 100644 --- a/Shaders/Shader.frag +++ b/Shaders/Shader.frag @@ -4,17 +4,20 @@ in vec2 pass_Uv; in vec4 pass_Diffuse; in vec4 pass_Ambient; in float pass_NormalDotLight; +in float pass_NormalLength; out vec4 out_Color; -uniform mat4 mvpMatrix; -uniform vec3 lightDirection; uniform sampler2D mainTex; void main(void) { vec4 finalColor; - vec4 diffuseNorm = pass_Diffuse * pass_NormalDotLight; - vec4 tex2D = texture(mainTex, pass_Uv) * pass_Color; - finalColor = (pass_Ambient + diffuseNorm) * tex2D; + if (pass_NormalLength == 0.0) { + finalColor = pass_Color; + } else { + vec4 diffuseNorm = pass_Diffuse * pass_NormalDotLight; + vec4 tex2D = texture(mainTex, pass_Uv) * pass_Color; + finalColor = (pass_Ambient + diffuseNorm) * tex2D; + } out_Color = finalColor; } \ No newline at end of file diff --git a/Shaders/Shader.vert b/Shaders/Shader.vert index 7f3f05d..085bf82 100644 --- a/Shaders/Shader.vert +++ b/Shaders/Shader.vert @@ -7,6 +7,7 @@ in vec3 in_Uv; out vec4 pass_Color; out vec2 pass_Uv; out float pass_NormalDotLight; +out float pass_NormalLength; out vec4 pass_Diffuse; out vec4 pass_Ambient; @@ -18,8 +19,9 @@ const vec4 ambient = vec4(0.5, 0.5, 0.5, 1.0); const vec4 diffuse = vec4(0.75, 0.75, 0.75, 1.0); void main(void) { - gl_Position = mvpMatrix * vec4(in_Position, 1.0); + gl_Position = mvpMatrix * vec4(in_Position, 1.0); pass_NormalDotLight = clamp(dot(in_Normal, lightDirection), 0.0, 1.0); + pass_NormalLength = length(in_Normal); pass_Color = vec4(in_Color, 1.0); pass_Uv = in_Uv.st; pass_Ambient = ambient;