diff --git a/CodeWalker/Project/Panels/EditYtypMloPortalPanel.Designer.cs b/CodeWalker/Project/Panels/EditYtypMloPortalPanel.Designer.cs index 99f7f9378..04d009ac3 100644 --- a/CodeWalker/Project/Panels/EditYtypMloPortalPanel.Designer.cs +++ b/CodeWalker/Project/Panels/EditYtypMloPortalPanel.Designer.cs @@ -46,6 +46,7 @@ private void InitializeComponent() this.FlagsCheckedListBox = new System.Windows.Forms.CheckedListBox(); this.AddEntityButton = new System.Windows.Forms.Button(); this.DeleteButton = new System.Windows.Forms.Button(); + this.FlipPortalButton = new System.Windows.Forms.Button(); this.SuspendLayout(); // // FlagsTextBox @@ -152,7 +153,7 @@ private void InitializeComponent() // // CornersTextBox // - this.CornersTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.CornersTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.CornersTextBox.Location = new System.Drawing.Point(107, 243); this.CornersTextBox.Multiline = true; @@ -218,6 +219,17 @@ private void InitializeComponent() this.DeleteButton.UseVisualStyleBackColor = true; this.DeleteButton.Click += new System.EventHandler(this.DeleteButton_Click); // + // FlipPortalButton + // + this.FlipPortalButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.FlipPortalButton.Location = new System.Drawing.Point(449, 243); + this.FlipPortalButton.Name = "FlipPortalButton"; + this.FlipPortalButton.Size = new System.Drawing.Size(95, 23); + this.FlipPortalButton.TabIndex = 39; + this.FlipPortalButton.Text = "Flip Portal"; + this.FlipPortalButton.UseVisualStyleBackColor = true; + this.FlipPortalButton.Click += new System.EventHandler(this.FlipPortalButton_Click); + // // EditYtypMloPortalPanel // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -225,6 +237,7 @@ private void InitializeComponent() this.ClientSize = new System.Drawing.Size(565, 505); this.Controls.Add(this.AddEntityButton); this.Controls.Add(this.DeleteButton); + this.Controls.Add(this.FlipPortalButton); this.Controls.Add(this.FlagsCheckedListBox); this.Controls.Add(this.label6); this.Controls.Add(this.CornersTextBox); @@ -267,5 +280,6 @@ private void InitializeComponent() private System.Windows.Forms.CheckedListBox FlagsCheckedListBox; private System.Windows.Forms.Button AddEntityButton; private System.Windows.Forms.Button DeleteButton; + private System.Windows.Forms.Button FlipPortalButton; } } \ No newline at end of file diff --git a/CodeWalker/Project/Panels/EditYtypMloPortalPanel.cs b/CodeWalker/Project/Panels/EditYtypMloPortalPanel.cs index 97f79d0df..78cd975c8 100644 --- a/CodeWalker/Project/Panels/EditYtypMloPortalPanel.cs +++ b/CodeWalker/Project/Panels/EditYtypMloPortalPanel.cs @@ -31,7 +31,7 @@ public void SetPortal(MCMloPortalDef portal) Tag = portal; UpdateFormTitle(); MloInstanceData instance = ProjectForm.TryGetMloInstance(portal?.OwnerMlo); - //ProjectForm.WorldForm?.SelectMloPortal(portal, instance); + ProjectForm.WorldForm?.SelectObject(portal, instance); UpdateControls(); } @@ -266,5 +266,35 @@ private void DeleteButton_Click(object sender, EventArgs e) ProjectForm.SetProjectItem(CurrentPortal); ProjectForm.DeleteMloPortal(); } + + private void FlipPortalButton_Click(object sender, EventArgs e) + { + if (CurrentPortal == null || CurrentPortal.Corners == null || CurrentPortal.Corners.Length < 3) return; + + lock (ProjectForm.ProjectSyncRoot) + { + var corners = CurrentPortal.Corners.ToList(); + corners.Reverse(); + CurrentPortal.Corners = corners.ToArray(); + uint tempRoom = CurrentPortal._Data.roomFrom; + CurrentPortal._Data.roomFrom = CurrentPortal._Data.roomTo; + CurrentPortal._Data.roomTo = tempRoom; + populatingui = true; + StringBuilder sb = new StringBuilder(); + foreach (var corner in CurrentPortal.Corners) + { + if (sb.Length > 0) sb.AppendLine(); + sb.Append(FloatUtil.GetVector3String(new Vector3(corner.X, corner.Y, corner.Z))); + } + CornersTextBox.Text = sb.ToString(); + RoomFromTextBox.Text = CurrentPortal._Data.roomFrom.ToString(); + RoomToTextBox.Text = CurrentPortal._Data.roomTo.ToString(); + populatingui = false; + CurrentPortal.OwnerMlo?.UpdatePortalCounts(); //Is this necessary if the counter doesn't change? + ProjectForm.SetYtypHasChanged(true); + UpdateFormTitle(); + UpdateProjectExplorer(); + } + } } } diff --git a/CodeWalker/Project/ProjectForm.cs b/CodeWalker/Project/ProjectForm.cs index 8654d616f..58cdca74d 100644 --- a/CodeWalker/Project/ProjectForm.cs +++ b/CodeWalker/Project/ProjectForm.cs @@ -7640,6 +7640,7 @@ public void OnWorldSelectionChanged(MapSelection sel) var mlo = sel.MloEntityDef; var room = sel.MloRoomDef; + var portal = sel.MloPortalDef; var ent = sel.EntityDef; var cargen = sel.CarGenerator; var lodlight = sel.LodLight; @@ -7659,7 +7660,7 @@ public void OnWorldSelectionChanged(MapSelection sel) var scenarioedge = sel.ScenarioEdge; var audiopl = sel.Audio; Archetype arch = mlo?.Archetype ?? ent?.MloParent?.Archetype ?? ent?.Archetype; - YtypFile ytyp = mlo?.Archetype?.Ytyp ?? ent?.MloParent?.Archetype?.Ytyp ?? ent?.Archetype?.Ytyp ?? room?.OwnerMlo?.Ytyp; + YtypFile ytyp = mlo?.Archetype?.Ytyp ?? ent?.MloParent?.Archetype?.Ytyp ?? ent?.Archetype?.Ytyp ?? room?.OwnerMlo?.Ytyp ?? portal?.OwnerMlo?.Ytyp; YmapFile ymap = ent?.Ymap ?? cargen?.Ymap ?? lodlight?.Ymap ?? boxoccluder?.Ymap ?? occludetri?.Ymap ?? grassbatch?.Ymap ?? mlo?.Ymap; YbnFile ybn = collbound?.GetRootYbn(); YndFile ynd = pathnode?.Ynd; @@ -7716,6 +7717,10 @@ public void OnWorldSelectionChanged(MapSelection sel) { ProjectExplorer?.TrySelectMloRoomTreeNode(room); } + if (wasmult || (portal != CurrentMloPortal)) + { + ProjectExplorer?.TrySelectMloPortalTreeNode(portal); + } } else if (YbnExistsInProject(ybn)) { @@ -7791,7 +7796,7 @@ public void OnWorldSelectionChanged(MapSelection sel) } CurrentMloRoom = room; - CurrentMloPortal = null; + CurrentMloPortal = portal; CurrentMloEntitySet = null; CurrentYmapFile = ymap; CurrentYtypFile = ytyp; diff --git a/CodeWalker/World/MapSelection.cs b/CodeWalker/World/MapSelection.cs index 2f4871150..0fd39f065 100644 --- a/CodeWalker/World/MapSelection.cs +++ b/CodeWalker/World/MapSelection.cs @@ -60,6 +60,7 @@ public struct MapSelection public YmapOccludeModelTriangle OccludeModelTri { get; set; } public YmapEntityDef MloEntityDef { get; set; } public MCMloRoomDef MloRoomDef { get; set; } + public MCMloPortalDef MloPortalDef { get; set; } public WaterQuad WaterQuad { get; set; } public WaterCalmingQuad CalmingQuad { get; set; } public WaterWaveQuad WaveQuad { get; set; } @@ -121,7 +122,8 @@ public bool HasValue (MloEntityDef != null) || (ScenarioNode != null) || (Audio != null) || - (MloRoomDef != null); + (MloRoomDef != null) || + (MloPortalDef != null); } } @@ -158,7 +160,8 @@ public bool CheckForChanges(MapSelection mhit) || (TrainTrackNode != mhit.TrainTrackNode) || (ScenarioNode != mhit.ScenarioNode) || (Audio != mhit.Audio) - || (MloRoomDef != mhit.MloRoomDef); + || (MloRoomDef != mhit.MloRoomDef) + || (MloPortalDef != mhit.MloPortalDef); } public bool CheckForChanges() { @@ -188,7 +191,8 @@ public bool CheckForChanges() || (TrainTrackNode != null) || (ScenarioNode != null) || (Audio != null) - || (MloRoomDef != null); + || (MloRoomDef != null) + || (MloPortalDef != null); } @@ -284,7 +288,7 @@ public string GetNameString(string defval) } else if (OccludeModelTri != null) { - name = "OccludeModel " + (OccludeModelTri.Ymap?.Name ?? "") + ": " + (OccludeModelTri.Model?.Index??0).ToString() + ":" + OccludeModelTri.Index.ToString(); + name = "OccludeModel " + (OccludeModelTri.Ymap?.Name ?? "") + ": " + (OccludeModelTri.Model?.Index ?? 0).ToString() + ":" + OccludeModelTri.Index.ToString(); } else if (WaterQuad != null) { @@ -330,6 +334,10 @@ public string GetNameString(string defval) { name = "MloRoomDef " + MloRoomDef.RoomName; } + if (MloPortalDef != null) + { + name = "MloPortalDef " + MloPortalDef.Name; + } if (EntityExtension != null) { name += ": " + EntityExtension.Name; @@ -1557,6 +1565,15 @@ public static MapSelection FromProjectObject(WorldForm worldForm, object o, obje ms.BBOrientation = instance.Owner.Orientation; } } + else if (o is MCMloPortalDef portal) + { + if (parent is MloInstanceData instance) + { + ms.MloPortalDef = portal; + ms.BBOffset = instance.Owner.Position; + ms.BBOrientation = instance.Owner.Orientation; + } + } else if (o is Bounds b) { ms.CollisionBounds = b; @@ -1588,9 +1605,9 @@ public static MapSelection FromProjectObject(WorldForm worldForm, object o, obje ms.NavPoint = point; ms.AABB = new BoundingBox(new Vector3(-nrad), new Vector3(nrad)); } - else if (o is YnvPortal portal) + else if (o is YnvPortal ynvportal) { - ms.NavPortal = portal; + ms.NavPortal = ynvportal; ms.AABB = new BoundingBox(new Vector3(-nrad), new Vector3(nrad)); } else if (o is YndNode node) diff --git a/CodeWalker/WorldForm.cs b/CodeWalker/WorldForm.cs index 8f641ab5b..c73a9b3b6 100644 --- a/CodeWalker/WorldForm.cs +++ b/CodeWalker/WorldForm.cs @@ -1508,6 +1508,25 @@ private void RenderSelection(ref MapSelection selectionItem) Renderer.SelectionLineVerts.Add(p1); Renderer.SelectionLineVerts.Add(p2); } + if (pcl >= 3) + { + Vector3 edge1 = portal.Corners[1].XYZ() - portal.Corners[0].XYZ(); + Vector3 normal = Vector3.Cross(edge1, portal.Corners[2].XYZ() - portal.Corners[0].XYZ()); + float len = normal.Length(); + if (len > 1e-6f) + { + normal /= len; + edge1.Normalize(); + Renderer.RenderSelectionArrowOutline( + mlop + mlo.Orientation.Multiply(portal.Center), + mlo.Orientation.Multiply(normal), + mlo.Orientation.Multiply(Vector3.Normalize(Vector3.Cross(edge1, normal))), + Quaternion.Identity, + 0.5f, 0.05f, + ((portal._Data.flags & 4) > 0) ? cblu : caqu + ); + } + } } } if (mloa.rooms != null) @@ -1538,6 +1557,51 @@ private void RenderSelection(ref MapSelection selectionItem) } } } + if (selectionItem.MloPortalDef != null) + { + var portal = selectionItem.MloPortalDef; + var mlop = selectionItem.BBOffset; + var mloOrientation = selectionItem.BBOrientation; + if (portal.Corners != null && portal.Corners.Length > 0) + { + VertexTypePC p1 = new VertexTypePC(); + VertexTypePC p2 = new VertexTypePC(); + p2.Colour = caqu; + if ((portal._Data.flags & 4) > 0) + { + p2.Colour = cblu; + } + var pcl = portal.Corners.Length; + for (int ic = 0; ic < pcl; ic++) + { + var icn = ic + 1; if (icn >= pcl) icn = 0; + p1.Colour = (ic == 0) ? cred : p2.Colour; // highlight index 0 and winding direction + p1.Position = mlop + mloOrientation.Multiply(portal.Corners[ic].XYZ()); + p2.Position = mlop + mloOrientation.Multiply(portal.Corners[icn].XYZ()); + Renderer.SelectionLineVerts.Add(p1); + Renderer.SelectionLineVerts.Add(p2); + } + if (pcl >= 3) + { + Vector3 edge1 = portal.Corners[1].XYZ() - portal.Corners[0].XYZ(); + Vector3 normal = Vector3.Cross(edge1, portal.Corners[2].XYZ() - portal.Corners[0].XYZ()); + float len = normal.Length(); + if (len > 1e-6f) + { + normal /= len; + edge1.Normalize(); + Renderer.RenderSelectionArrowOutline( + mlop + mloOrientation.Multiply(portal.Center), + mloOrientation.Multiply(normal), + mloOrientation.Multiply(Vector3.Normalize(Vector3.Cross(edge1, normal))), + Quaternion.Identity, + 0.5f, 0.05f, + ((portal._Data.flags & 4) > 0) ? cblu : caqu + ); + } + } + } + } if (selectionItem.MloRoomDef != null) { camrel += ori.Multiply(selectionItem.BBOffset);