diff --git a/Classes/EntityBase.cs b/Classes/EntityBase.cs index 5263368..527bac2 100644 --- a/Classes/EntityBase.cs +++ b/Classes/EntityBase.cs @@ -6,6 +6,11 @@ namespace PSXPrev { public class EntityBase { + private EntityBase[] _childEntities; + + [DisplayName("Name")] + public string EntityName { get; set; } + [ReadOnly(true), DisplayName("Bounds")] public BoundingBox Bounds3D { get; set; } @@ -68,11 +73,25 @@ public float PositionZ public string ChildCount => ChildEntities == null ? "0" : ChildEntities.Length.ToString(CultureInfo.InvariantCulture); [Browsable(false)] - public EntityBase[] ChildEntities { get; set; } + public EntityBase[] ChildEntities + { + get => _childEntities; + set + { + for (var i = 0; i < value.Length; i++) + { + value[i].EntityName = "Sub-Model " + i; + } + _childEntities = value; + } + } [Browsable(false)] public EntityBase ParentEntity { get; set; } + [Browsable(false)] + public float IntersectionDistance { get; set; } + protected EntityBase() { LocalMatrix = Matrix4.Identity; @@ -107,5 +126,10 @@ private void ApplyTranslation(Vector3 translationValues) var scale = Matrix4.CreateScale(LocalMatrix.ExtractScale()); LocalMatrix = translation * rotation * scale; } + + public override string ToString() + { + return EntityName; + } } } diff --git a/Classes/RootEntity.cs b/Classes/RootEntity.cs index 9d10f6a..7c959c3 100644 --- a/Classes/RootEntity.cs +++ b/Classes/RootEntity.cs @@ -7,9 +7,6 @@ public class RootEntity : EntityBase { private readonly List _groupedModels = new List(); - [DisplayName("Name")] - public string EntityName { get; set; } - public override void ComputeBounds() { base.ComputeBounds(); @@ -21,11 +18,6 @@ public override void ComputeBounds() Bounds3D = bounds; } - public override string ToString() - { - return EntityName; - } - public List GetModelsWithTMDID(int id) { _groupedModels.Clear(); diff --git a/Classes/Scene.cs b/Classes/Scene.cs index f8392d9..100b08d 100644 --- a/Classes/Scene.cs +++ b/Classes/Scene.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.Globalization; using System.Text; using OpenTK; using OpenTK.Graphics.OpenGL; @@ -64,7 +65,7 @@ public enum GizmoId private Vector3 _rayOrigin; private Vector3 _rayTarget; private Vector3 _rayDirection; - private Vector3? _projected; + private Vector3? _intersected; private Color _clearColor; public Color ClearColor @@ -256,41 +257,90 @@ public void Draw() GL.UseProgram(0); } - public RootEntity GetRootEntityUnderMouse(RootEntity[] checkedEntities, RootEntity selectedEntity, int x, int y, float width, float height) + private List _lastPickedEntities; + private int _lastPickedIndex; + + public EntityBase GetEntityUnderMouse(RootEntity[] checkedEntities, EntityBase selectedRootEntity, EntityBase selectedEntity, int x, int y, float width, float height, bool selectRoot = false) { UpdatePicking(x, y, width, height); - var pickedEntities = new List>(); - if (checkedEntities != null) + var pickedEntities = new List(); + if (!selectRoot) { - foreach (var entity in checkedEntities) + if (checkedEntities != null) { - 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) + foreach (var entity in checkedEntities) { - pickedEntities.Add(new Tuple(intersectionDistance, entity)); + if (entity.ChildEntities != null) + foreach (var subEntity in entity.ChildEntities) + { + CheckEntity(subEntity, pickedEntities); + } } } + else if (selectedEntity != null) + { + if (selectedEntity.ChildEntities != null) + foreach (var subEntity in selectedEntity.ChildEntities) + { + CheckEntity(subEntity, pickedEntities); + } + } + else + { + if (selectedRootEntity?.ChildEntities != null) + foreach (var subEntity in selectedRootEntity.ChildEntities) + { + CheckEntity(subEntity, pickedEntities); + } + } + } + pickedEntities.Sort((a, b) => a.IntersectionDistance.CompareTo(b.IntersectionDistance)); + if (!ListsMatches(pickedEntities, _lastPickedEntities)) + { + _lastPickedIndex = 0; + } + var pickedEntity = pickedEntities.Count > 0 ? pickedEntities[_lastPickedIndex] : null; + if (_lastPickedIndex < pickedEntities.Count - 1) + { + _lastPickedIndex++; } - if (selectedEntity != null) + else { - 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) + _lastPickedIndex = 0; + } + _lastPickedEntities = pickedEntities; + return pickedEntity; + } + + private static bool ListsMatches(List a, List b) + { + if (a == null || b == null) + { + return false; + } + if (a.Count != b.Count) + { + return false; + } + for (var i = 0; i < a.Count; i++) + { + if (!a[i].Equals(b[i])) { - pickedEntities.Add(new Tuple(intersectionDistance, selectedEntity)); + return false; } } - pickedEntities.Sort((a, b) => a.Item1.CompareTo(b.Item1)); - return pickedEntities.Count > 0 ? pickedEntities[0].Item2 : null; + return true; + } + + private void CheckEntity(EntityBase entity, List pickedEntities) + { + GeomUtils.GetBoxMinMax(entity.Bounds3D.Center, entity.Bounds3D.Extents, out var boxMin, out var boxMax); + var intersectionDistance = GeomUtils.BoxIntersect(_rayOrigin, _rayDirection, boxMin, boxMax); + if (intersectionDistance > 0f) + { + entity.IntersectionDistance = intersectionDistance; + pickedEntities.Add(entity); + } } public Vector3 GetBestPlaneNormal(Vector3 a, Vector3 b) @@ -326,30 +376,25 @@ public GizmoId GetGizmoUnderPosition(int x, int y, float width, float height, En { 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); + GeomUtils.GetBoxMinMax(XGizmoDimensions, XGizmoDimensions, out var xMin, out var 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); + + GeomUtils.GetBoxMinMax(YGizmoDimensions, YGizmoDimensions, out var yMin, out var 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); + + GeomUtils.GetBoxMinMax(ZGizmoDimensions, ZGizmoDimensions, out var zMin, out var zMax, finalMatrix); if (GeomUtils.BoxIntersect(_rayOrigin, _rayDirection, zMin, zMax) > 0f) { return GizmoId.ZMover; @@ -363,18 +408,19 @@ public Vector3 GetGizmoProjectionOffset(int x, int y, float width, float height, var worldMatrix = entityBase.WorldMatrix; var planeOrigin = worldMatrix.ExtractTranslation(); UpdatePicking(x, y, width, height); - var projected = GeomUtils.PlaneIntersect(_rayOrigin, _rayDirection, planeOrigin, planeNormal).ProjectOnNormal(projectionNormal); + var intersected = GeomUtils.PlaneIntersect(_rayOrigin, _rayDirection, planeOrigin, planeNormal); Vector3 offset; - if (_projected != null) + if (_intersected != null) { - var previousProjected = _projected.Value; - offset = new Vector3((int)(projected.X - previousProjected.X), (int)(projected.Y - previousProjected.Y), (int)(projected.Z - previousProjected.Z)); + var previousIntersected = _intersected.Value; + offset = new Vector3((int)(intersected.X - previousIntersected.X), (int)(intersected.Y - previousIntersected.Y), (int)(intersected.Z - previousIntersected.Z)); + offset = offset.ProjectOnNormal(projectionNormal); } else { offset = Vector3.Zero; } - _projected = projected; + _intersected = intersected; return Vector3.TransformVector(offset, worldMatrix.Inverted()); } @@ -398,5 +444,10 @@ public Matrix4 GetGizmoScaleMatrix(Vector3 position) { return Matrix4.CreateScale(CameraDistanceFrom(position)); } + + public void ResetIntersection() + { + _intersected = null; + } } } \ No newline at end of file diff --git a/Forms/PreviewForm.Designer.cs b/Forms/PreviewForm.Designer.cs index b9f5b3a..7b4a5d2 100644 --- a/Forms/PreviewForm.Designer.cs +++ b/Forms/PreviewForm.Designer.cs @@ -372,40 +372,39 @@ private void InitializeComponent() 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(347, 92); + this.cmsModelExport.Size = new System.Drawing.Size(355, 92); this.cmsModelExport.ItemClicked += new System.Windows.Forms.ToolStripItemClickedEventHandler(this.cmsModelExport_ItemClicked); // // miOBJ // this.miOBJ.Name = "miOBJ"; - this.miOBJ.Size = new System.Drawing.Size(346, 22); - this.miOBJ.Text = "Wavefront .OBJ (Accepts Groups)"; + this.miOBJ.Size = new System.Drawing.Size(354, 22); + this.miOBJ.Text = "Wavefront .OBJ"; // // miOBJVC // this.miOBJVC.Name = "miOBJVC"; - this.miOBJVC.Size = new System.Drawing.Size(346, 22); + this.miOBJVC.Size = new System.Drawing.Size(354, 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)"; + this.miOBJMerged.Size = new System.Drawing.Size(354, 22); + this.miOBJMerged.Text = "Wavefront .OBJ - Merged"; // // miOBJVCMerged // this.miOBJVCMerged.Name = "miOBJVCMerged"; - this.miOBJVCMerged.Size = new System.Drawing.Size(346, 22); - this.miOBJVCMerged.Text = "Wavefront .OBJ (Merged-Experimental Vertex Color)"; + this.miOBJVCMerged.Size = new System.Drawing.Size(354, 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(154, 22); + this.exportSelectedToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.exportSelectedToolStripMenuItem.Text = "Export Selected"; // // mainMenuStrip @@ -438,7 +437,7 @@ private void InitializeComponent() // this.wireframeToolStripMenuItem.CheckOnClick = true; this.wireframeToolStripMenuItem.Name = "wireframeToolStripMenuItem"; - this.wireframeToolStripMenuItem.Size = new System.Drawing.Size(154, 22); + this.wireframeToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.wireframeToolStripMenuItem.Text = "Wireframe"; this.wireframeToolStripMenuItem.CheckedChanged += new System.EventHandler(this.wireframeToolStripMenuItem_CheckedChanged); // @@ -448,7 +447,7 @@ private void InitializeComponent() 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.Size = new System.Drawing.Size(180, 22); this.showGizmosToolStripMenuItem.Text = "Show Gizmos"; this.showGizmosToolStripMenuItem.Click += new System.EventHandler(this.showGizmosToolStripMenuItem_Click); // @@ -458,7 +457,7 @@ private void InitializeComponent() 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.Size = new System.Drawing.Size(180, 22); this.showBoundsToolStripMenuItem.Text = "Show Bounds"; this.showBoundsToolStripMenuItem.Click += new System.EventHandler(this.showBoundsToolStripMenuItem_Click); // @@ -476,28 +475,28 @@ private void InitializeComponent() // exportSelectedToolStripMenuItem1 // this.exportSelectedToolStripMenuItem1.Name = "exportSelectedToolStripMenuItem1"; - this.exportSelectedToolStripMenuItem1.Size = new System.Drawing.Size(154, 22); + this.exportSelectedToolStripMenuItem1.Size = new System.Drawing.Size(155, 22); this.exportSelectedToolStripMenuItem1.Text = "Export Selected"; this.exportSelectedToolStripMenuItem1.Click += new System.EventHandler(this.exportBitmapButton_Click); // // drawToVRAMToolStripMenuItem // this.drawToVRAMToolStripMenuItem.Name = "drawToVRAMToolStripMenuItem"; - this.drawToVRAMToolStripMenuItem.Size = new System.Drawing.Size(154, 22); + this.drawToVRAMToolStripMenuItem.Size = new System.Drawing.Size(155, 22); this.drawToVRAMToolStripMenuItem.Text = "Draw to VRAM"; this.drawToVRAMToolStripMenuItem.Click += new System.EventHandler(this.drawToVRAMButton_Click); // // findByPageToolStripMenuItem // this.findByPageToolStripMenuItem.Name = "findByPageToolStripMenuItem"; - this.findByPageToolStripMenuItem.Size = new System.Drawing.Size(154, 22); + this.findByPageToolStripMenuItem.Size = new System.Drawing.Size(155, 22); this.findByPageToolStripMenuItem.Text = "Find by Page"; this.findByPageToolStripMenuItem.Click += new System.EventHandler(this.findByPageToolStripMenuItem_Click); // // clearSearchToolStripMenuItem // this.clearSearchToolStripMenuItem.Name = "clearSearchToolStripMenuItem"; - this.clearSearchToolStripMenuItem.Size = new System.Drawing.Size(154, 22); + this.clearSearchToolStripMenuItem.Size = new System.Drawing.Size(155, 22); this.clearSearchToolStripMenuItem.Text = "Clear Results"; this.clearSearchToolStripMenuItem.Click += new System.EventHandler(this.clearSearchToolStripMenuItem_Click); // @@ -586,7 +585,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.2"; + this.Text = "PSXPrev Alpha 0.9.3"; this.Load += new System.EventHandler(this.previewForm_Load); this.entitiesTabPage.ResumeLayout(false); this.menusTabControl.ResumeLayout(false); diff --git a/Forms/PreviewForm.cs b/Forms/PreviewForm.cs index 5f30aac..117e474 100644 --- a/Forms/PreviewForm.cs +++ b/Forms/PreviewForm.cs @@ -40,6 +40,7 @@ private enum EntitySelectionSource private readonly List _textures; private Texture[] _vramPage; private Scene.GizmoId _selectedGizmo; + private Scene.GizmoId _hoveredGizmo; private EntitySelectionSource _selectionSource; private bool _playing; private bool _showUv = true; @@ -49,8 +50,8 @@ private enum EntitySelectionSource private int _curAnimationFrame; private Animation _curAnimation; private AnimationObject _curAnimationObject; - private RootEntity _curEntity; - private ModelEntity _curModel; + private RootEntity _selectedRootEntity; + private ModelEntity _selectedModelEntity; private bool Playing { @@ -98,8 +99,9 @@ private void EntityAdded(RootEntity entity) entityNode.Tag = entity; for (var m = 0; m < entity.ChildEntities.Length; m++) { - var modelNode = new TreeNode("Sub-Model " + (m + 1)); - modelNode.Tag = entity.ChildEntities[m]; + var entityChildEntity = entity.ChildEntities[m]; + var modelNode = new TreeNode(entityChildEntity.EntityName); + modelNode.Tag = entityChildEntity; entityNode.Nodes.Add(modelNode); modelNode.HideCheckBox(); modelNode.HideCheckBox(); @@ -204,7 +206,7 @@ private void _openTkControl_Paint(object sender, PaintEventArgs e) { if (_inAnimationTab && _curAnimation != null) { - _scene.AnimationBatch.SetupAnimationFrame(_curAnimationFrame, _curAnimationObject, _curEntity); + _scene.AnimationBatch.SetupAnimationFrame(_curAnimationFrame, _curAnimationObject, _selectedRootEntity); } _scene.Draw(); _openTkControl.SwapBuffers(); @@ -373,11 +375,24 @@ private void exportBitmapButton_Click(object sender, EventArgs e) MessageBox.Show("Textures exported"); } - private void SelectEntity(RootEntity rootEntity) + private void SelectEntity(EntityBase entity) { _selectionSource = EntitySelectionSource.Click; - var rootIndex = _rootEntities.IndexOf(rootEntity); - entitiesTreeView.SelectedNode = entitiesTreeView.Nodes[rootIndex]; + if (entity is RootEntity rootEntity) + { + var rootIndex = _rootEntities.IndexOf(rootEntity); + entitiesTreeView.SelectedNode = entitiesTreeView.Nodes[rootIndex]; + } + else + { + if (entity.ParentEntity is RootEntity rootEntityFromSub) + { + var rootIndex = _rootEntities.IndexOf(rootEntityFromSub); + var rootNode = entitiesTreeView.Nodes[rootIndex]; + var subIndex = Array.IndexOf(rootEntityFromSub.ChildEntities, entity); + entitiesTreeView.SelectedNode = rootNode.Nodes[subIndex]; + } + } } private void openTkControl_MouseEvent(MouseEventArgs e, MouseEventType t) @@ -386,11 +401,10 @@ private void openTkControl_MouseEvent(MouseEventArgs e, MouseEventType t) { _scene.CameraDistance -= e.Delta * MouseSensivity * _scene.CameraDistanceIncrement; _scene.UpdateViewMatrix(); - UpdateGizmos(_selectedGizmo, false); + UpdateGizmos(_selectedGizmo, _hoveredGizmo, false); return; } - var selectedEntityBase = (EntityBase)_curEntity ?? _curModel; - var selectedGizmo = _selectedGizmo; + var selectedEntityBase = (EntityBase)_selectedRootEntity ?? _selectedModelEntity; var deltaX = e.X - _lastMouseX; var deltaY = e.Y - _lastMouseY; var mouseLeft = e.Button == MouseButtons.Left; @@ -398,21 +412,27 @@ private void openTkControl_MouseEvent(MouseEventArgs e, MouseEventType t) var mouseRight = e.Button == MouseButtons.Right; var controlWidth = _openTkControl.Size.Width; var controlHeight = _openTkControl.Size.Height; + var hoveredGizmo = _scene.GetGizmoUnderPosition(e.Location.X, e.Location.Y, controlWidth, controlHeight, selectedEntityBase); + var selectedGizmo = _selectedGizmo; 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) + if (hoveredGizmo == 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) + var newSelectedEntity = _scene.GetEntityUnderMouse(checkedEntities, _selectedRootEntity, _selectedModelEntity, e.Location.X, e.Location.Y, controlWidth, controlHeight); + if (newSelectedEntity != null)// && newSelectedEntity != selectedEntityBase) { SelectEntity(newSelectedEntity); } } + else + { + selectedGizmo = hoveredGizmo; + _scene.ResetIntersection(); + } } else { @@ -432,14 +452,14 @@ private void openTkControl_MouseEvent(MouseEventArgs e, MouseEventType t) if (hasToUpdateViewMatrix) { _scene.UpdateViewMatrix(); - UpdateGizmos(_selectedGizmo, false); + UpdateGizmos(_selectedGizmo, _hoveredGizmo, 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); + var offset = _scene.GetGizmoProjectionOffset(e.Location.X, e.Location.Y, controlWidth, controlHeight, selectedEntityBase, _scene.CameraDirection, GeomUtils.XVector); //_scene.GetBestPlaneNormal(GeomUtils.ZVector, GeomUtils.YVector) selectedEntityBase.PositionX += offset.X; UpdateSelectedEntity(false); } @@ -451,7 +471,7 @@ private void openTkControl_MouseEvent(MouseEventArgs e, MouseEventType t) 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); + var offset = _scene.GetGizmoProjectionOffset(e.Location.X, e.Location.Y, controlWidth, controlHeight, selectedEntityBase, _scene.CameraDirection, GeomUtils.YVector); //_scene.GetBestPlaneNormal(GeomUtils.ZVector, GeomUtils.XVector) selectedEntityBase.PositionY += offset.Y; UpdateSelectedEntity(false); } @@ -463,7 +483,7 @@ private void openTkControl_MouseEvent(MouseEventArgs e, MouseEventType t) 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); + var offset = _scene.GetGizmoProjectionOffset(e.Location.X, e.Location.Y, controlWidth, controlHeight, selectedEntityBase, _scene.CameraDirection, GeomUtils.ZVector); //_scene.GetBestPlaneNormal(GeomUtils.YVector, GeomUtils.XVector) selectedEntityBase.PositionZ += offset.Z; UpdateSelectedEntity(false); } @@ -473,9 +493,9 @@ private void openTkControl_MouseEvent(MouseEventArgs e, MouseEventType t) } break; } - if (selectedGizmo != _selectedGizmo) + if (selectedGizmo != _selectedGizmo || hoveredGizmo != _hoveredGizmo) { - UpdateGizmos(selectedGizmo); + UpdateGizmos(selectedGizmo, hoveredGizmo); } _lastMouseX = e.X; _lastMouseY = e.Y; @@ -490,19 +510,19 @@ private void entitiesTreeView_AfterSelect(object sender, TreeViewEventArgs e) var selectedNode = entitiesTreeView.SelectedNode; if (selectedNode != null) { - _curEntity = selectedNode.Tag as RootEntity; - _curModel = selectedNode.Tag as ModelEntity; + _selectedRootEntity = selectedNode.Tag as RootEntity; + _selectedModelEntity = selectedNode.Tag as ModelEntity; } UpdateSelectedEntity(); } - private void UpdateGizmos(Scene.GizmoId selectedGizmo = Scene.GizmoId.None, bool updateMeshData = true) + private void UpdateGizmos(Scene.GizmoId selectedGizmo = Scene.GizmoId.None, Scene.GizmoId hoveredGizmo = Scene.GizmoId.None, bool updateMeshData = true) { if (updateMeshData) { _scene.GizmosMeshBatch.Reset(3); } - var selectedEntityBase = (EntityBase)_curEntity ?? _curModel; + var selectedEntityBase = (EntityBase)_selectedRootEntity ?? _selectedModelEntity; if (selectedEntityBase == null) { return; @@ -510,32 +530,34 @@ private void UpdateGizmos(Scene.GizmoId selectedGizmo = Scene.GizmoId.None, bool 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); + _scene.GizmosMeshBatch.BindCube(finalMatrix, hoveredGizmo == Scene.GizmoId.XMover|| selectedGizmo == Scene.GizmoId.XMover ? Color.White : Color.Red, Scene.XGizmoDimensions, Scene.XGizmoDimensions, 0, null, updateMeshData); + _scene.GizmosMeshBatch.BindCube(finalMatrix, hoveredGizmo == Scene.GizmoId.YMover|| selectedGizmo == Scene.GizmoId.YMover ? Color.White : Color.Green, Scene.YGizmoDimensions, Scene.YGizmoDimensions, 1, null, updateMeshData); + _scene.GizmosMeshBatch.BindCube(finalMatrix, hoveredGizmo == Scene.GizmoId.ZMover|| selectedGizmo == Scene.GizmoId.ZMover ? Color.White : Color.Blue, Scene.ZGizmoDimensions, Scene.ZGizmoDimensions, 2, null, updateMeshData); _selectedGizmo = selectedGizmo; + _hoveredGizmo = hoveredGizmo; } private void UpdateSelectedEntity(bool updateMeshData = true) { _scene.BoundsBatch.Reset(); _scene.SkeletonBatch.Reset(); - var selectedEntityBase = (EntityBase)_curEntity ?? _curModel; + var selectedEntityBase = (EntityBase)_selectedRootEntity ?? _selectedModelEntity; 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); + _scene.MeshBatch.SetupMultipleEntityBatch(checkedEntities, _selectedModelEntity, _selectedRootEntity, _scene.TextureBinder, updateMeshData, _selectionSource == EntitySelectionSource.TreeView && _selectedModelEntity == null); } else { modelPropertyGrid.SelectedObject = null; _scene.MeshBatch.Reset(0); _selectedGizmo = Scene.GizmoId.None; + _hoveredGizmo = Scene.GizmoId.None; } - UpdateGizmos(_selectedGizmo, updateMeshData); + UpdateGizmos(_selectedGizmo, _hoveredGizmo, updateMeshData); _selectionSource = EntitySelectionSource.None; } @@ -611,14 +633,14 @@ private void modelPropertyGrid_PropertyValueChanged(object s, PropertyValueChang { return; } - if (_curEntity != null) + if (_selectedRootEntity != null) { - selectedNode.Text = _curEntity.EntityName; + selectedNode.Text = _selectedRootEntity.EntityName; } - else if (_curModel != null) + else if (_selectedModelEntity != null) { - _curModel.TexturePage = Math.Min(31, Math.Max(0, _curModel.TexturePage)); - _curModel.Texture = _vramPage[_curModel.TexturePage]; + _selectedModelEntity.TexturePage = Math.Min(31, Math.Max(0, _selectedModelEntity.TexturePage)); + _selectedModelEntity.Texture = _vramPage[_selectedModelEntity.TexturePage]; } UpdateSelectedEntity(false); } @@ -916,14 +938,14 @@ private void vramPagePictureBox_Paint(object sender, PaintEventArgs e) { foreach (var checkedEntity in checkedEntities) { - if (checkedEntity == _curEntity) + if (checkedEntity == _selectedRootEntity) { continue; } DrawUV(checkedEntity, e.Graphics); } } - DrawUV(_curEntity, e.Graphics); + DrawUV(_selectedRootEntity, e.Graphics); } private void entitiesTreeView_AfterCheck(object sender, TreeViewEventArgs e) diff --git a/tutorial b/tutorial new file mode 100644 index 0000000..1ec0e31 --- /dev/null +++ b/tutorial @@ -0,0 +1,69 @@ + + + + + Here is a brief PSXPrev tutorial. + CenterMiddle + + + First, open PSXPrev.exe + CenterMiddle + + + Then, select a folder, file or ISO file to scan + CenterMiddle + + + In this sample, I will scan a file from "Xena - Warrior Princess" that I know contains models and textures + CenterMiddle + + + Tick TMD and TIM to scan for models and textures + CenterMiddle + + + Wait the scan completion. This may take a while... + CenterMiddle + + + After the scan has been completed, you can select a model from the list to work with + CenterMiddle + + + Some models contains sub-models that should be aligned manually before exporting + CenterMiddle + + + If you want to view a root model or a series of root models in the viewport, select or tick them on the left list + CenterMiddle + + + I'm ticking the Xena model on the list + CenterMiddle + + + Go to the texture tabs and search the textures the model uses + CenterMiddle + + + I know Xena model is on the file offset 688128, so all the textures may be on near offsets of the same file + CenterMiddle + + + Shift+click to select a series of textures, then click "Draw to VRAM", so the textures will be available on the model viewport + CenterMiddle + + + From now on, you can manually move the body parts with the gizmos to adjust the model + CenterMiddle + + + After the model has been adjusted, you can export it on the "Models>Export Selected" menu + CenterMiddle + + + F2 + F3 + F4 + F9 + \ No newline at end of file