From 33dc83c0e0e9b1e1649926cbd4d0aee2269355d8 Mon Sep 17 00:00:00 2001 From: dexy Date: Mon, 6 Jan 2020 22:17:51 +1100 Subject: [PATCH] Collisions editing progress --- .../GameFiles/FileTypes/YbnFile.cs | 12 + CodeWalker.Core/GameFiles/GameFileCache.cs | 10 +- CodeWalker.Core/GameFiles/Resources/Bounds.cs | 1000 +++++++++++++++-- .../GameFiles/Resources/Clothes.cs | 10 + .../GameFiles/Resources/Drawable.cs | 6 + CodeWalker.Core/GameFiles/Resources/Frag.cs | 15 + .../GameFiles/Resources/ResourceBaseTypes.cs | 2 +- CodeWalker.Core/Utils/Vectors.cs | 22 + .../Panels/EditYbnBoundPolyPanel.Designer.cs | 87 +- Project/Panels/EditYbnBoundPolyPanel.cs | 95 +- Project/Panels/EditYbnBoundsPanel.Designer.cs | 178 +-- Project/Panels/EditYbnBoundsPanel.cs | 18 + Project/ProjectForm.cs | 151 +++ 13 files changed, 1390 insertions(+), 216 deletions(-) diff --git a/CodeWalker.Core/GameFiles/FileTypes/YbnFile.cs b/CodeWalker.Core/GameFiles/FileTypes/YbnFile.cs index 545e76f..a1e1a4f 100644 --- a/CodeWalker.Core/GameFiles/FileTypes/YbnFile.cs +++ b/CodeWalker.Core/GameFiles/FileTypes/YbnFile.cs @@ -62,5 +62,17 @@ namespace CodeWalker.GameFiles return data; } + + + + public bool RemoveBounds(Bounds b) + { + return false; + } + public bool RemovePoly(BoundPolygon p) + { + return false; + } + } } diff --git a/CodeWalker.Core/GameFiles/GameFileCache.cs b/CodeWalker.Core/GameFiles/GameFileCache.cs index ce70644..91c13ec 100644 --- a/CodeWalker.Core/GameFiles/GameFileCache.cs +++ b/CodeWalker.Core/GameFiles/GameFileCache.cs @@ -3516,7 +3516,7 @@ namespace CodeWalker.GameFiles } public void TestYbns() { - bool savetest = false; + bool savetest = true; var errorfiles = new List(); foreach (RpfFile file in AllRpfs) { @@ -3674,7 +3674,8 @@ namespace CodeWalker.GameFiles } public void TestYdrs() { - bool savetest = false; + bool savetest = true; + bool boundsonly = true; var errorfiles = new List(); foreach (RpfFile file in AllRpfs) { @@ -3701,6 +3702,9 @@ namespace CodeWalker.GameFiles if (fentry == null) { continue; } //shouldn't happen + if (boundsonly && (ydr.Drawable.Bound == null)) + { continue; } + var bytes = ydr.Save(); string origlen = TextUtil.GetBytesReadable(fentry.FileSize); @@ -3783,7 +3787,7 @@ namespace CodeWalker.GameFiles } public void TestYfts() { - bool savetest = false; + bool savetest = true; var errorfiles = new List(); foreach (RpfFile file in AllRpfs) { diff --git a/CodeWalker.Core/GameFiles/Resources/Bounds.cs b/CodeWalker.Core/GameFiles/Resources/Bounds.cs index bea721c..1d737e1 100644 --- a/CodeWalker.Core/GameFiles/Resources/Bounds.cs +++ b/CodeWalker.Core/GameFiles/Resources/Bounds.cs @@ -166,6 +166,7 @@ namespace CodeWalker.GameFiles public bool HasChanged { get; set; } = false; public BoundComposite Parent { get; set; } public YbnFile OwnerYbn { get; set; } + public object Owner { get; set; } public string OwnerName { get; set; } public string GetName() { @@ -195,10 +196,25 @@ namespace CodeWalker.GameFiles } return r; } + public object GetRootOwner() + { + var r = Owner; + var p = Parent; + while ((p != null) && (r == null)) + { + r = p.Owner; + p = p.Parent; + } + return r; + } public Matrix Transform { get; set; } = Matrix.Identity; //when it's the child of a bound composite public Matrix TransformInv { get; set; } = Matrix.Identity; + public BoundCompositeChildrenFlags CompositeFlags1 { get; set; } + public BoundCompositeChildrenFlags CompositeFlags2 { get; set; } + + public virtual Vector3 Scale { get @@ -786,19 +802,19 @@ namespace CodeWalker.GameFiles // structure data public uint Unknown_70h { get; set; } // 0x00000000 public uint Unknown_74h { get; set; } // 0x00000000 - public ulong Unknown_78h_Pointer { get; set; } + public ulong Vertices2Pointer { get; set; } public ushort Unknown_80h { get; set; } // 0x0000 public ushort Unknown_82h { get; set; } //des_.ydr's? some extra data to read..?? is this some extra poly count? - public uint Count1 { get; set; } + public uint Vertices2Count { get; set; } //always equal to VerticesCount public ulong PolygonsPointer { get; set; } public Vector3 Quantum { get; set; } public float Unknown_9Ch { get; set; } public Vector3 CenterGeom { get; set; } public float Unknown_ACh { get; set; } public ulong VerticesPointer { get; set; } - public ulong Unknown_B8h_Pointer { get; set; } - public ulong Unknown_C0h_Pointer { get; set; } - public ulong Unknown_C8h_Pointer { get; set; } + public ulong VertexColoursPointer { get; set; } + public ulong Unknown1CountsPointer { get; set; } + public ulong Unknown1DataPointer { get; set; } public uint VerticesCount { get; set; } public uint PolygonsCount { get; set; } public uint Unknown_D8h { get; set; } // 0x00000000 @@ -824,21 +840,21 @@ namespace CodeWalker.GameFiles public uint Unknown_12Ch { get; set; } // 0x00000000 - public BoundVertex_s[] p1data { get; set; } + public Vector3[] Vertices2 { get; set; }//found in some YFTs, same count as Vertices, and contents are similar public BoundPolygon[] Polygons { get; set; } public Vector3[] Vertices { get; set; } - public uint[] Unknown_B8h_Data { get; set; } - public uint[] Unknown_C0h_Data { get; set; } - public BoundGeomUnknown1 Unknown_C8h_Data { get; set; } + public BoundMaterialColour[] VertexColours { get; set; }//not sure, it seems like colours anyway, see eg. prologue03_10.ybn + public uint[] Unknown1Counts { get; set; } + public BoundGeomUnknown1 Unknown1Data { get; set; } public BoundMaterial_s[] Materials { get; set; } public BoundMaterialColour[] MaterialColours { get; set; } public byte[] PolygonMaterialIndices { get; set; } - private ResourceSystemStructBlock p1dataBlock = null; + private ResourceSystemStructBlock Vertices2Block = null; private ResourceSystemDataBlock PolygonsBlock = null; private ResourceSystemStructBlock VerticesBlock = null; - private ResourceSystemStructBlock Unknown_B8h_Block = null; - private ResourceSystemStructBlock Unknown_C0h_Block = null; + private ResourceSystemStructBlock VertexColoursBlock = null; + private ResourceSystemStructBlock Unknown1CountsBlock = null; private ResourceSystemStructBlock MaterialsBlock = null; private ResourceSystemStructBlock MaterialColoursBlock = null; private ResourceSystemStructBlock PolygonMaterialIndicesBlock = null; @@ -852,19 +868,19 @@ namespace CodeWalker.GameFiles this.Unknown_70h = reader.ReadUInt32(); this.Unknown_74h = reader.ReadUInt32(); - this.Unknown_78h_Pointer = reader.ReadUInt64(); + this.Vertices2Pointer = reader.ReadUInt64(); this.Unknown_80h = reader.ReadUInt16(); this.Unknown_82h = reader.ReadUInt16(); - this.Count1 = reader.ReadUInt32(); + this.Vertices2Count = reader.ReadUInt32(); this.PolygonsPointer = reader.ReadUInt64(); this.Quantum = reader.ReadVector3(); this.Unknown_9Ch = reader.ReadSingle(); this.CenterGeom = reader.ReadVector3(); this.Unknown_ACh = reader.ReadSingle(); this.VerticesPointer = reader.ReadUInt64(); - this.Unknown_B8h_Pointer = reader.ReadUInt64(); - this.Unknown_C0h_Pointer = reader.ReadUInt64(); - this.Unknown_C8h_Pointer = reader.ReadUInt64(); + this.VertexColoursPointer = reader.ReadUInt64(); + this.Unknown1CountsPointer = reader.ReadUInt64(); + this.Unknown1DataPointer = reader.ReadUInt64(); this.VerticesCount = reader.ReadUInt32(); this.PolygonsCount = reader.ReadUInt32(); this.Unknown_D8h = reader.ReadUInt32(); @@ -890,9 +906,16 @@ namespace CodeWalker.GameFiles this.Unknown_12Ch = reader.ReadUInt32(); - this.p1data = reader.ReadStructsAt(this.Unknown_78h_Pointer, this.VerticesCount); - if (p1data != null) - { } //seems to be in YFT's + var verts2 = reader.ReadStructsAt(this.Vertices2Pointer, this.Vertices2Count); + if (verts2 != null) //seems to be in YFT's + { + Vertices2 = new Vector3[verts2.Length]; + for (int i = 0; i < verts2.Length; i++) + { + var bv = verts2[i]; + Vertices2[i] = bv.Vector * Quantum; + } + } ReadPolygons(reader); @@ -903,16 +926,16 @@ namespace CodeWalker.GameFiles for (int i = 0; i < verts.Length; i++) { var bv = verts[i]; - Vertices[i] = new Vector3(bv.X, bv.Y, bv.Z) * Quantum; + Vertices[i] = bv.Vector * Quantum; } } - this.Unknown_B8h_Data = reader.ReadUintsAt(this.Unknown_B8h_Pointer, this.VerticesCount); + this.VertexColours = reader.ReadStructsAt(this.VertexColoursPointer, this.VerticesCount); - this.Unknown_C0h_Data = reader.ReadUintsAt(this.Unknown_C0h_Pointer, 8);//item counts - if (this.Unknown_C0h_Data != null) + this.Unknown1Counts = reader.ReadUintsAt(this.Unknown1CountsPointer, 8);//item counts + if (this.Unknown1Counts != null) { - this.Unknown_C8h_Data = reader.ReadBlockAt(this.Unknown_C8h_Pointer, this.Unknown_C0h_Data); + this.Unknown1Data = reader.ReadBlockAt(this.Unknown1DataPointer, this.Unknown1Counts); } this.Materials = reader.ReadStructsAt(this.MaterialsPointer, this.MaterialsCount); @@ -923,6 +946,8 @@ namespace CodeWalker.GameFiles + if (Vertices2Count != VerticesCount) + { }//no hit here if (Unknown_9Ch != 0) { } if (Unknown_ACh != 0) @@ -986,7 +1011,7 @@ namespace CodeWalker.GameFiles public Vector3 GetVertex(int index) { - return ((index < 0) || (index >= Vertices.Length)) ? Vector3.Zero : Vertices[index]; + return ((index >= 0) && (index < Vertices.Length)) ? Vertices[index] : Vector3.Zero; } public Vector3 GetVertexPos(int index) { @@ -1011,13 +1036,14 @@ namespace CodeWalker.GameFiles base.Write(writer, parameters); // update structure data - this.Unknown_78h_Pointer = (ulong)(this.p1dataBlock != null ? this.p1dataBlock.FilePosition : 0); + this.Vertices2Pointer = (ulong)(this.Vertices2Block != null ? this.Vertices2Block.FilePosition : 0); this.PolygonsPointer = (ulong)(this.PolygonsBlock != null ? this.PolygonsBlock.FilePosition : 0); this.VerticesPointer = (ulong)(this.VerticesBlock != null ? this.VerticesBlock.FilePosition : 0); - this.Unknown_B8h_Pointer = (ulong)(this.Unknown_B8h_Block != null ? this.Unknown_B8h_Block.FilePosition : 0); - this.Unknown_C0h_Pointer = (ulong)(this.Unknown_C0h_Block != null ? this.Unknown_C0h_Block.FilePosition : 0); - this.Unknown_C8h_Pointer = (ulong)(this.Unknown_C8h_Data != null ? this.Unknown_C8h_Data.FilePosition : 0); + this.VertexColoursPointer = (ulong)(this.VertexColoursBlock != null ? this.VertexColoursBlock.FilePosition : 0); + this.Unknown1CountsPointer = (ulong)(this.Unknown1CountsBlock != null ? this.Unknown1CountsBlock.FilePosition : 0); + this.Unknown1DataPointer = (ulong)(this.Unknown1Data != null ? this.Unknown1Data.FilePosition : 0); this.VerticesCount = (uint)(this.VerticesBlock != null ? this.VerticesBlock.ItemCount : 0); + this.Vertices2Count = this.VerticesCount; this.PolygonsCount = (uint)(this.Polygons != null ? this.Polygons.Length : 0); this.MaterialsPointer = (ulong)(this.MaterialsBlock != null ? this.MaterialsBlock.FilePosition : 0); this.MaterialColoursPointer = (ulong)(this.MaterialColoursBlock != null ? this.MaterialColoursBlock.FilePosition : 0); @@ -1029,19 +1055,19 @@ namespace CodeWalker.GameFiles // write structure data writer.Write(this.Unknown_70h); writer.Write(this.Unknown_74h); - writer.Write(this.Unknown_78h_Pointer); + writer.Write(this.Vertices2Pointer); writer.Write(this.Unknown_80h); writer.Write(this.Unknown_82h); - writer.Write(this.Count1); + writer.Write(this.Vertices2Count); writer.Write(this.PolygonsPointer); writer.Write(this.Quantum); writer.Write(this.Unknown_9Ch); writer.Write(this.CenterGeom); writer.Write(this.Unknown_ACh); writer.Write(this.VerticesPointer); - writer.Write(this.Unknown_B8h_Pointer); - writer.Write(this.Unknown_C0h_Pointer); - writer.Write(this.Unknown_C8h_Pointer); + writer.Write(this.VertexColoursPointer); + writer.Write(this.Unknown1CountsPointer); + writer.Write(this.Unknown1DataPointer); writer.Write(this.VerticesCount); writer.Write(this.PolygonsCount); writer.Write(this.Unknown_D8h); @@ -1072,11 +1098,21 @@ namespace CodeWalker.GameFiles /// public override IResourceBlock[] GetReferences() { + BuildMaterials(); + CalculateQuantum(); + var list = new List(base.GetReferences()); - if (p1data != null) + if (Vertices2 != null) { - p1dataBlock = new ResourceSystemStructBlock(p1data); - list.Add(p1dataBlock); + var verts = new List(); + foreach (var v in Vertices2) + { + var vq = v / Quantum; + var vs = new BoundVertex_s(vq); + verts.Add(vs); + } + Vertices2Block = new ResourceSystemStructBlock(verts.ToArray()); + list.Add(Vertices2Block); } if (Polygons != null) { @@ -1108,26 +1144,26 @@ namespace CodeWalker.GameFiles var verts = new List(); foreach (var v in Vertices) { - var vq = v / Quantum; //Vertices[i] = new Vector3(bv.X, bv.Y, bv.Z) * Quantum; + var vq = v / Quantum; var vs = new BoundVertex_s(vq); verts.Add(vs); } VerticesBlock = new ResourceSystemStructBlock(verts.ToArray()); list.Add(VerticesBlock); } - if (Unknown_B8h_Data != null) + if (VertexColours != null) { - Unknown_B8h_Block = new ResourceSystemStructBlock(Unknown_B8h_Data); - list.Add(Unknown_B8h_Block); + VertexColoursBlock = new ResourceSystemStructBlock(VertexColours); + list.Add(VertexColoursBlock); } - if (Unknown_C0h_Data != null) + if (Unknown1Counts != null) { - Unknown_C0h_Block = new ResourceSystemStructBlock(Unknown_C0h_Data); - list.Add(Unknown_C0h_Block); + Unknown1CountsBlock = new ResourceSystemStructBlock(Unknown1Counts); + list.Add(Unknown1CountsBlock); } - if (Unknown_C8h_Data != null) + if (Unknown1Data != null) { - list.Add(Unknown_C8h_Data);//this one is already a resource block! + list.Add(Unknown1Data);//this one is already a resource block! } if (Materials != null) { @@ -1390,11 +1426,98 @@ namespace CodeWalker.GameFiles res.Normal = n1; res.HitPolygon = polygon; res.HitBounds = this; - res.Material = polygon?.Material ?? new BoundMaterial_s(); + res.Material = polygon.Material; } res.TestedPolyCount++; } } + + + + public BoundMaterial_s GetMaterial(int polyIndex) + { + var matind = 0; + if ((PolygonMaterialIndices != null) && (polyIndex < PolygonMaterialIndices.Length)) + { + matind = PolygonMaterialIndices[polyIndex]; + } + if ((Materials != null) && (matind < Materials.Length)) + { + return Materials[matind]; + } + return new BoundMaterial_s(); + } + public void SetMaterial(int polyIndex, BoundMaterial_s mat) + { + //updates the shared material for the given poly. + var matind = 0; + if ((PolygonMaterialIndices != null) && (polyIndex < PolygonMaterialIndices.Length)) + { + matind = PolygonMaterialIndices[polyIndex]; + } + if ((Materials != null) && (matind < Materials.Length)) + { + Materials[matind] = mat; + } + } + + + public void CalculateQuantum() + { + var min = new Vector3(float.MaxValue); + var max = new Vector3(float.MinValue); + if (Vertices != null) + { + foreach (var v in Vertices) + { + min = Vector3.Min(min, v); + max = Vector3.Max(max, v); + } + } + if (Vertices2 != null) + { + foreach (var v in Vertices2) + { + min = Vector3.Min(min, v); + max = Vector3.Max(max, v); + } + } + var maxsiz = Vector3.Max(min.Abs(), max.Abs()); + var q = (maxsiz+Margin) / 32767.0f; + Quantum = q; + } + + public void BuildMaterials() + { + //update Materials and PolygonMaterialIndices arrays, using custom materials from polys and existing materials + + var matdict = new Dictionary(); + var matlist = new List(); + var polymats = new List(); + + if (Polygons != null) + { + foreach (var poly in Polygons) + { + var mat = poly.Material; + if (matdict.TryGetValue(mat, out byte matidx)) + { + polymats.Add(matidx); + } + else + { + matidx = (byte)matlist.Count; + matdict.Add(mat, matidx); + matlist.Add(mat); + polymats.Add(matidx); + } + } + } + + Materials = matlist.ToArray(); + PolygonMaterialIndices = polymats.ToArray(); + } + } [TC(typeof(EXP))] public class BoundBVH : BoundGeometry { @@ -1472,6 +1595,8 @@ namespace CodeWalker.GameFiles /// public override IResourceBlock[] GetReferences() { + BuildBVH(); + var list = new List(base.GetReferences()); if (BVH != null) list.Add(BVH); return list.ToArray(); @@ -1482,6 +1607,75 @@ namespace CodeWalker.GameFiles public void BuildBVH() { + if ((Polygons?.Length ?? 0) <= 0) //in some des_ drawables? + { + if (BVH != null) + { } + BVH = null; + return; + } + if (BVH != null) + { + //var tnodes = BVHBuilder.Unbuild(BVH); + } + + var items = new List(); + for (int i = 0; i < Polygons.Length; i++) + { + var poly = Polygons[i]; + if (poly != null) + { + var it = new BVHBuilderItem(); + it.Min = poly.BoxMin; + it.Max = poly.BoxMax; + it.Index = i; + it.Polygon = poly; + items.Add(it); + } + } + + var bvh = BVHBuilder.Build(items, 4); //geometries have BVH item threshold of 4 + + var newpolys = new BoundPolygon[items.Count]; + var newpolymats = new byte[items.Count]; + var itemlookup = new short[items.Count]; + for (int i = 0; i < items.Count; i++) + { + var poly = items[i]?.Polygon; + if (poly != null) + { + if (poly.Index < itemlookup.Length) + { + itemlookup[poly.Index] = (short)i; + } + else + { }//shouldn't happen + } + else + { }//shouldn't happen + } + for (int i = 0; i < items.Count; i++) + { + var poly = items[i]?.Polygon; + if (poly != null) + { + newpolys[i] = poly; + newpolymats[i] = (poly.Index < PolygonMaterialIndices.Length) ? PolygonMaterialIndices[poly.Index] : (byte)0;//is this necessary? + poly.Index = i; + if (poly is BoundPolygonTriangle ptri) + { + ptri.edgeIndex1 = ((ptri.edgeIndex1 >= 0) && (ptri.edgeIndex1 < itemlookup.Length)) ? itemlookup[ptri.edgeIndex1] : (short)-1; + ptri.edgeIndex2 = ((ptri.edgeIndex2 >= 0) && (ptri.edgeIndex2 < itemlookup.Length)) ? itemlookup[ptri.edgeIndex2] : (short)-1; + ptri.edgeIndex3 = ((ptri.edgeIndex3 >= 0) && (ptri.edgeIndex3 < itemlookup.Length)) ? itemlookup[ptri.edgeIndex3] : (short)-1; + } + } + } + Polygons = newpolys; + PolygonMaterialIndices = newpolymats; + + + + BVH = bvh; } @@ -1507,8 +1701,8 @@ namespace CodeWalker.GameFiles for (int t = 0; t < BVH.Trees.data_items.Length; t++) { var tree = BVH.Trees.data_items[t]; - box.Minimum = new Vector3(tree.MinX, tree.MinY, tree.MinZ) * q + c; - box.Maximum = new Vector3(tree.MaxX, tree.MaxY, tree.MaxZ) * q + c; + box.Minimum = tree.Min * q + c; + box.Maximum = tree.Max * q + c; if (!sph.Intersects(ref box)) { continue; } @@ -1517,8 +1711,8 @@ namespace CodeWalker.GameFiles while (nodeind < lastind) { var node = BVH.Nodes.data_items[nodeind]; - box.Minimum = new Vector3(node.MinX, node.MinY, node.MinZ) * q + c; - box.Maximum = new Vector3(node.MaxX, node.MaxY, node.MaxZ) * q + c; + box.Minimum = node.Min * q + c; + box.Maximum = node.Max * q + c; bool nodehit = sph.Intersects(ref box); bool nodeskip = !nodehit; if (node.ItemCount <= 0) //intermediate node with child nodes @@ -1549,7 +1743,6 @@ namespace CodeWalker.GameFiles return res; } - public override SpaceRayIntersectResult RayIntersect(ref Ray ray, float maxdist = float.MaxValue) { var res = new SpaceRayIntersectResult(); @@ -1575,8 +1768,8 @@ namespace CodeWalker.GameFiles for (int t = 0; t < BVH.Trees.data_items.Length; t++) { var tree = BVH.Trees.data_items[t]; - box.Minimum = new Vector3(tree.MinX, tree.MinY, tree.MinZ) * q + c; - box.Maximum = new Vector3(tree.MaxX, tree.MaxY, tree.MaxZ) * q + c; + box.Minimum = tree.Min * q + c; + box.Maximum = tree.Max * q + c; if (!ray.Intersects(ref box, out bvhboxhittest)) { continue; } if (bvhboxhittest > res.HitDist) @@ -1587,8 +1780,8 @@ namespace CodeWalker.GameFiles while (nodeind < lastind) { var node = BVH.Nodes.data_items[nodeind]; - box.Minimum = new Vector3(node.MinX, node.MinY, node.MinZ) * q + c; - box.Maximum = new Vector3(node.MaxX, node.MaxY, node.MaxZ) * q + c; + box.Minimum = node.Min * q + c; + box.Maximum = node.Max * q + c; bool nodehit = ray.Intersects(ref box, out bvhboxhittest); bool nodeskip = !nodehit || (bvhboxhittest > res.HitDist); if (node.ItemCount <= 0) //intermediate node with child nodes @@ -1710,10 +1903,35 @@ namespace CodeWalker.GameFiles xform.Column4 = new Vector4(0.0f, 0.0f, 0.0f, 1.0f); child.Transform = xform; child.TransformInv = Matrix.Invert(xform); + child.CompositeFlags1 = ((ChildrenFlags1 != null) && (i < ChildrenFlags1.Length)) ? ChildrenFlags1[i] : new BoundCompositeChildrenFlags(); + child.CompositeFlags2 = ((ChildrenFlags2 != null) && (i < ChildrenFlags2.Length)) ? ChildrenFlags2[i] : new BoundCompositeChildrenFlags(); } } } - + + //if ((ChildrenTransformation1 != null) && (ChildrenTransformation2 != null)) + //{ + // //if (ChildrenTransformation1.Length != ChildrenTransformation2.Length) + // //{ }//no hits + // //else + // //{ + // // for (int i = 0; i < ChildrenTransformation1.Length; i++) + // // { + // // if (ChildrenTransformation1[i] != ChildrenTransformation2[i]) + // // { }//no hits + // // } + // //} + //} + //else + //{ }//no hits + //if (ChildrenFlags1 != null) + //{ } + //else + //{ }//some props ydr's + //if (ChildrenFlags2 != null) + //{ } + //else + //{ }//some props ydr's } @@ -1753,6 +1971,11 @@ namespace CodeWalker.GameFiles /// public override IResourceBlock[] GetReferences() { + BuildBVH(); + UpdateChildrenFlags(); + UpdateChildrenBounds(); + UpdateChildrenTransformations(); + var list = new List(base.GetReferences()); if (Children != null) list.Add(Children); if (ChildrenTransformation1 != null) @@ -1787,13 +2010,134 @@ namespace CodeWalker.GameFiles - public void BuildBVH() { + if (Children?.data_items == null) + { + BVH = null; + return; + } + if (Children.data_items.Length <= 5) //composites only get BVHs if they have 6 or more children. + { + if (BVH != null) + { } + BVH = null; + return; + } + if (BVH != null) + { + //var tnodes = BVHBuilder.Unbuild(BVH); + } + else + { + //why are we here? yft's hit this... + if (!(Owner is FragPhysicsLOD) && !(Owner is FragPhysArchetype) && !(Owner is VerletCloth)) + { } + } + + + var items = new List(); + for (int i = 0; i < Children.data_items.Length; i++) + { + var child = Children.data_items[i]; + if (child != null) + { + var it = new BVHBuilderItem(); + it.Min = child.BoxMin; + it.Max = child.BoxMax; + it.Index = i; + it.Bounds = child; + items.Add(it); + } + } + + var bvh = BVHBuilder.Build(items, 1); //composites have BVH item threshold of 1 + + BVH = bvh; + } + public void UpdateChildrenFlags() + { + if (Children?.data_items == null) + { + ChildrenFlags1 = null; + ChildrenFlags2 = null; + return; + } + var cf1 = new List(); + var cf2 = new List(); + + foreach (var child in Children.data_items) + { + var f1 = new BoundCompositeChildrenFlags(); + var f2 = new BoundCompositeChildrenFlags(); + if (child != null) + { + f1 = child.CompositeFlags1; + f2 = child.CompositeFlags2; + } + cf1.Add(f1); + cf2.Add(f2); + } + + ChildrenFlags1 = cf1.ToArray(); + ChildrenFlags2 = cf2.ToArray(); + } + + public void UpdateChildrenBounds() + { + if (Children?.data_items == null) + { + ChildrenBoundingBoxes = null; + return; + } + + var cbl = new List(); + foreach (var child in Children.data_items) + { + var aabb = new AABB_s(); + if (child != null) + { + aabb.Min = new Vector4(child.BoxMin, float.Epsilon); + aabb.Max = new Vector4(child.BoxMax, child.Margin); + } + cbl.Add(aabb); + } + + ChildrenBoundingBoxes = cbl.ToArray(); + + } + + public void UpdateChildrenTransformations() + { + if (Children?.data_items == null) + { + ChildrenTransformation1 = null; + ChildrenTransformation2 = null; + return; + } + + var ct1 = new List(); + var ct2 = new List(); + foreach (var child in Children.data_items) + { + var m = Matrix.Identity; + if (child != null) + { + m = child.Transform; + } + m.Column4 = new Vector4(0.0f, float.Epsilon, float.Epsilon, 0.0f);//is this right? TODO: check! + ct1.Add(m); + ct2.Add(m); + } + + ChildrenTransformation1 = ct1.ToArray(); + ChildrenTransformation2 = ct2.ToArray(); + + } public override SpaceSphereIntersectResult SphereIntersect(ref BoundingSphere sph) @@ -1821,7 +2165,6 @@ namespace CodeWalker.GameFiles return res; } - public override SpaceRayIntersectResult RayIntersect(ref Ray ray, float maxdist = float.MaxValue) { var res = new SpaceRayIntersectResult(); @@ -1873,19 +2216,18 @@ namespace CodeWalker.GameFiles { get { - var matind = 0; - if ((Owner?.PolygonMaterialIndices != null) && (Index < Owner.PolygonMaterialIndices.Length)) - { - matind = Owner.PolygonMaterialIndices[Index]; - } - if ((Owner.Materials != null) && (matind < Owner.Materials.Length)) - { - return Owner.Materials[matind]; - } - return new BoundMaterial_s(); + if (MaterialCustom.HasValue) return MaterialCustom.Value; + return Owner?.GetMaterial(Index) ?? new BoundMaterial_s(); + } + set + { + MaterialCustom = value; } } + public BoundMaterial_s? MaterialCustom; //for editing, when assigning a new material. public int Index { get; set; } //for editing convenience, not stored + public abstract Vector3 BoxMin { get; } + public abstract Vector3 BoxMax { get; } public abstract Vector3 Scale { get; set; } public abstract Vector3 Position { get; set; } public abstract Quaternion Orientation { get; set; } @@ -1936,6 +2278,20 @@ namespace CodeWalker.GameFiles set { if (Owner != null) Owner.SetVertexPos(vertIndex3, value); } } + public override Vector3 BoxMin + { + get + { + return Vector3.Min(Vector3.Min(Vertex1, Vertex2), Vertex3); + } + } + public override Vector3 BoxMax + { + get + { + return Vector3.Max(Vector3.Max(Vertex1, Vertex2), Vertex3); + } + } public override Vector3 Scale { get @@ -2008,6 +2364,20 @@ namespace CodeWalker.GameFiles public uint unused0 { get; set; } public uint unused1 { get; set; } + public override Vector3 BoxMin + { + get + { + return Position - sphereRadius; + } + } + public override Vector3 BoxMax + { + get + { + return Position + sphereRadius; + } + } public override Vector3 Scale { get @@ -2079,6 +2449,20 @@ namespace CodeWalker.GameFiles set { if (Owner != null) Owner.SetVertexPos(capsuleIndex2, value); } } + public override Vector3 BoxMin + { + get + { + return Vector3.Min(Vertex1, Vertex2) - capsuleRadius; + } + } + public override Vector3 BoxMax + { + get + { + return Vector3.Max(Vertex1, Vertex2) + capsuleRadius; + } + } public override Vector3 Scale { get @@ -2170,6 +2554,20 @@ namespace CodeWalker.GameFiles set { if (Owner != null) Owner.SetVertexPos(boxIndex4, value); } } + public override Vector3 BoxMin + { + get + { + return Vector3.Min(Vector3.Min(Vector3.Min(Vertex1, Vertex2), Vertex3), Vertex4); + } + } + public override Vector3 BoxMax + { + get + { + return Vector3.Max(Vector3.Max(Vector3.Max(Vertex1, Vertex2), Vertex3), Vertex4); + } + } public override Vector3 Scale { get @@ -2253,6 +2651,20 @@ namespace CodeWalker.GameFiles set { if (Owner != null) Owner.SetVertexPos(cylinderIndex2, value); } } + public override Vector3 BoxMin + { + get + { + return Vector3.Min(Vertex1, Vertex2) - cylinderRadius;//not perfect but meh + } + } + public override Vector3 BoxMax + { + get + { + return Vector3.Max(Vertex1, Vertex2) + cylinderRadius;//not perfect but meh + } + } public override Vector3 Scale { get @@ -2327,6 +2739,12 @@ namespace CodeWalker.GameFiles Y = (short)v.Y; Z = (short)v.Z; } + + public Vector3 Vector + { + get { return new Vector3(X, Y, Z); } + set { X = (short)value.X; Y = (short)value.Y; Z = (short)value.Z; } + } } [TC(typeof(EXP))] public class BoundGeomUnknown1 : ResourceSystemBlock @@ -2352,7 +2770,7 @@ namespace CodeWalker.GameFiles public override void Read(ResourceDataReader reader, params object[] parameters) { - if (parameters?.Length < 1) + if ((parameters?.Length ?? 0) < 1) { return; } //shouldn't happen! var itemcounts = (uint[])parameters[0]; @@ -2404,41 +2822,41 @@ namespace CodeWalker.GameFiles } - [Flags] public enum EBoundCompositeFlags + [Flags] public enum EBoundCompositeFlags : uint { - NONE = 0, - UNKNOWN = 1, - MAP_WEAPON = 1 << 1, - MAP_DYNAMIC = 1 << 2, - MAP_ANIMAL = 1 << 3, - MAP_COVER = 1 << 4, - MAP_VEHICLE = 1 << 5, - VEHICLE_NOT_BVH = 1 << 6, - VEHICLE_BVH = 1 << 7, - VEHICLE_BOX = 1 << 8, - PED = 1 << 9, - RAGDOLL = 1 << 10, - ANIMAL = 1 << 11, - ANIMAL_RAGDOLL = 1 << 12, - OBJECT = 1 << 13, - OBJECT_ENV_CLOTH = 1 << 14, - PLANT = 1 << 15, - PROJECTILE = 1 << 16, - EXPLOSION = 1 << 17, - PICKUP = 1 << 18, - FOLIAGE = 1 << 19, - FORKLIFT_FORKS = 1 << 20, - TEST_WEAPON = 1 << 21, - TEST_CAMERA = 1 << 22, - TEST_AI = 1 << 23, - TEST_SCRIPT = 1 << 24, - TEST_VEHICLE_WHEEL = 1 << 25, - GLASS = 1 << 26, - MAP_RIVER = 1 << 27, - SMOKE = 1 << 28, - UNSMASHED = 1 << 29, - MAP_STAIRS = 1 << 30, - MAP_DEEP_SURFACE = 1 << 31, + NONE = 0u, + UNKNOWN = 1u, + MAP_WEAPON = 1u << 1, + MAP_DYNAMIC = 1u << 2, + MAP_ANIMAL = 1u << 3, + MAP_COVER = 1u << 4, + MAP_VEHICLE = 1u << 5, + VEHICLE_NOT_BVH = 1u << 6, + VEHICLE_BVH = 1u << 7, + VEHICLE_BOX = 1u << 8, + PED = 1u << 9, + RAGDOLL = 1u << 10, + ANIMAL = 1u << 11, + ANIMAL_RAGDOLL = 1u << 12, + OBJECT = 1u << 13, + OBJECT_ENV_CLOTH = 1u << 14, + PLANT = 1u << 15, + PROJECTILE = 1u << 16, + EXPLOSION = 1u << 17, + PICKUP = 1u << 18, + FOLIAGE = 1u << 19, + FORKLIFT_FORKS = 1u << 20, + TEST_WEAPON = 1u << 21, + TEST_CAMERA = 1u << 22, + TEST_AI = 1u << 23, + TEST_SCRIPT = 1u << 24, + TEST_VEHICLE_WHEEL = 1u << 25, + GLASS = 1u << 26, + MAP_RIVER = 1u << 27, + SMOKE = 1u << 28, + UNSMASHED = 1u << 29, + MAP_STAIRS = 1u << 30, + MAP_DEEP_SURFACE = 1u << 31, } [TC(typeof(EXP))] public struct BoundCompositeChildrenFlags { @@ -2472,7 +2890,6 @@ namespace CodeWalker.GameFiles public Vector4 Quantum { get; set; } // bounding box dimension / 2^16 public ResourceSimpleList64_s Trees { get; set; } - /// /// Reads the data-block from a stream. /// @@ -2490,7 +2907,6 @@ namespace CodeWalker.GameFiles this.QuantumInverse = reader.ReadStruct(); this.Quantum = reader.ReadStruct(); this.Trees = reader.ReadBlock>(); - } /// @@ -2543,9 +2959,20 @@ namespace CodeWalker.GameFiles public short NodeIndex1 { get; set; } public short NodeIndex2 { get; set; } + public Vector3 Min + { + get { return new Vector3(MinX, MinY, MinZ); } + set { MinX = (short)value.X; MinY = (short)value.Y; MinZ = (short)value.Z; } + } + public Vector3 Max + { + get { return new Vector3(MaxX, MaxY, MaxZ); } + set { MaxX = (short)value.X; MaxY = (short)value.Y; MaxZ = (short)value.Z; } + } + public override string ToString() { - return NodeIndex1.ToString() + ", " + NodeIndex2.ToString(); + return NodeIndex1.ToString() + ", " + NodeIndex2.ToString() + " (" + (NodeIndex2 - NodeIndex1).ToString() + " nodes)"; } } [TC(typeof(EXP))] public struct BVHNode_s @@ -2559,6 +2986,17 @@ namespace CodeWalker.GameFiles public short ItemId { get; set; } public short ItemCount { get; set; } + public Vector3 Min + { + get { return new Vector3(MinX, MinY, MinZ); } + set { MinX = (short)value.X; MinY = (short)value.Y; MinZ = (short)value.Z; } + } + public Vector3 Max + { + get { return new Vector3(MaxX, MaxY, MaxZ); } + set { MaxX = (short)value.X; MaxY = (short)value.Y; MaxZ = (short)value.Z; } + } + public override string ToString() { return ItemId.ToString() + ": " + ItemCount.ToString(); @@ -2566,6 +3004,352 @@ namespace CodeWalker.GameFiles } + public class BVHBuilder + { + public static int MaxNodeItemCount = 4; //item threshold: 1 for composites, 4 for geometries + public static int MaxTreeNodeCount = 127; //max number of nodes found in any tree + + + public static BVH Build(List items, int itemThreshold) + { + if (items == null) return null; + var bvh = new BVH(); + var min = new Vector3(float.MaxValue); + var max = new Vector3(float.MinValue); + var nodes = new List(); + var trees = new List(); + for (int i = 0; i < items.Count; i++) + { + var item = items[i]; + min = Vector3.Min(min, item.Min); + max = Vector3.Max(max, item.Max); + } + var cen = (min + max) * 0.5f; + bvh.BoundingBoxMin = new Vector4(min, float.NaN); + bvh.BoundingBoxMax = new Vector4(max, float.NaN); + bvh.BoundingBoxCenter = new Vector4(cen, float.NaN); + bvh.Quantum = new Vector4(Vector3.Max((min - cen).Abs(), (max - cen).Abs()) / 32767.0f, float.NaN); + bvh.QuantumInverse = new Vector4(1.0f / bvh.Quantum.XYZ(), float.NaN); + + var root = new BVHBuilderNode(); + root.Items = items; + root.Build(itemThreshold); + root.GatherNodes(nodes); + root.GatherTrees(trees); + + + if (itemThreshold > 1) //need to reorder items, since they need to be grouped by node for the node's item index + { + items.Clear(); + foreach (var node in nodes) + { + if (node.Items != null) + { + foreach (var item in node.Items) + { + item.Index = items.Count; + items.Add(item); + } + } + } + } + else //don't need to reorder items, since nodes only have one item and one item index + { } + + var bvhtrees = new List(); + var bvhnodes = new List(); + var qi = bvh.QuantumInverse.XYZ(); + var c = bvh.BoundingBoxCenter.XYZ(); + for (int i = 0; i < nodes.Count; i++) + { + var node = nodes[i]; + var id = ((node.Items?.Count ?? 0) > 0) ? node.Items[0].Index : 0; + var tn = node.TotalNodes; + var bn = new BVHNode_s(); + bn.Min = (node.Min - c) * qi; + bn.Max = (node.Max - c) * qi; + bn.ItemCount = (short)((tn <= 1) ? node.TotalItems : 0); + bn.ItemId = (short)((tn <= 1) ? id : node.TotalNodes); + bvhnodes.Add(bn); + } + + for (int i = 0; i < trees.Count; i++) + { + var tree = trees[i]; + var bt = new BVHTreeInfo_s(); + bt.Min = (tree.Min - c) * qi; + bt.Max = (tree.Max - c) * qi; + bt.NodeIndex1 = (short)tree.Index; + bt.NodeIndex2 = (short)(tree.Index + tree.TotalNodes); + bvhtrees.Add(bt); + } + + + bvh.Nodes = new ResourceSimpleList64b_s(); + bvh.Nodes.data_items = bvhnodes.ToArray(); + + bvh.Trees = new ResourceSimpleList64_s(); + bvh.Trees.data_items = bvhtrees.ToArray(); + + return bvh; + } + + public static BVHBuilderNode[] Unbuild(BVH bvh) + { + if ((bvh?.Trees?.data_items == null) || (bvh?.Nodes?.data_items == null)) return null; + + var nodes = new List(); + foreach (var tree in bvh.Trees.data_items) + { + var bnode = new BVHBuilderNode(); + bnode.Unbuild(bvh, tree.NodeIndex1, tree.NodeIndex2); + nodes.Add(bnode); + //MaxTreeNodeCount = Math.Max(MaxTreeNodeCount, tree.NodeIndex2 - tree.NodeIndex1); + } + return nodes.ToArray(); + } + + } + public class BVHBuilderNode + { + public List Children; + public List Items; + public Vector3 Min; + public Vector3 Max; + public int Index; + + public int TotalNodes + { + get + { + int c = 1; + if (Children != null) + { + foreach (var child in Children) + { + c += child.TotalNodes; + } + } + return c; + } + } + public int TotalItems + { + get + { + int c = Items?.Count ?? 0; + if (Children != null) + { + foreach (var child in Children) + { + c += child.TotalItems; + } + } + return c; + } + } + + public void Build(int itemThreshold) + { + UpdateMinMax(); + if (Items == null) return; + if (Items.Count <= itemThreshold) return; + + var avgsum = Vector3.Zero; + foreach (var item in Items) + { + avgsum += item.Min; + avgsum += item.Max; + } + var avg = avgsum * (0.5f / Items.Count); + int countx = 0, county = 0, countz = 0; + foreach (var item in Items) + { + var icen = (item.Min + item.Max) * 0.5f; + if (icen.X < avg.X) countx++; + if (icen.Y < avg.Y) county++; + if (icen.Z < avg.Z) countz++; + } + var target = Items.Count / 2.0f; + var dx = Math.Abs(target - countx); + var dy = Math.Abs(target - county); + var dz = Math.Abs(target - countz); + int axis = -1; + if ((dx <= dy) && (dx <= dz)) axis = 0; //x seems best + else if (dy <= dz) axis = 1; //y seems best + else axis = 2; //z seems best + + var l1 = new List(); + var l2 = new List(); + foreach (var item in Items) + { + var icen = (item.Min + item.Max) * 0.5f; + bool s = false; + switch (axis) + { + default: + case 0: s = (icen.X > avg.X); break; + case 1: s = (icen.Y > avg.Y); break; + case 2: s = (icen.Z > avg.Z); break; + } + if (s) l1.Add(item); + else l2.Add(item); + } + + if ((l1.Count == 0) || (l2.Count == 0)) //don't get stuck in a stack overflow... + { + var l3 = new List();//we can recover from this... + l3.AddRange(l1); + l3.AddRange(l2); + if (l3.Count > 0) + { + l3.Sort((a, b) => + { + var c = a.Min.CompareTo(b.Min); if (c != 0) return c; + return a.Max.CompareTo(b.Max); + }); + l1.Clear(); + l2.Clear(); + var hidx = l3.Count / 2; + for (int i = 0; i < hidx; i++) l1.Add(l3[i]); + for (int i = hidx; i < l3.Count; i++) l2.Add(l3[i]); + } + else + { return; }//nothing to see here? + } + + Items = null; + Children = new List(); + + var n1 = new BVHBuilderNode(); + n1.Items = l1; + n1.Build(itemThreshold); + Children.Add(n1); + + var n2 = new BVHBuilderNode(); + n2.Items = l2; + n2.Build(itemThreshold); + Children.Add(n2); + + Children.Sort((a, b) => + { + return b.TotalItems.CompareTo(a.TotalItems); + }); //is this necessary? + + } + public void UpdateMinMax() + { + var min = new Vector3(float.MaxValue); + var max = new Vector3(float.MinValue); + if (Items != null) + { + foreach (var item in Items) + { + min = Vector3.Min(min, item.Min); + max = Vector3.Max(max, item.Max); + } + } + if (Children != null) + { + foreach (var child in Children) + { + child.UpdateMinMax(); + min = Vector3.Min(min, child.Min); + max = Vector3.Max(max, child.Max); + } + } + Min = min; + Max = max; + } + public void GatherNodes(List nodes) + { + Index = nodes.Count; + nodes.Add(this); + if (Children != null) + { + foreach (var child in Children) + { + child.GatherNodes(nodes); + } + } + } + public void GatherTrees(List trees) + { + if ((TotalNodes > BVHBuilder.MaxTreeNodeCount) && ((Children?.Count ?? 0) > 0)) + { + foreach (var child in Children) + { + child.GatherTrees(trees); + } + } + else + { + trees.Add(this); + } + } + + public void Unbuild(BVH bvh, int nodeIndex1, int nodeIndex2) + { + var q = bvh.Quantum.XYZ(); + var c = bvh.BoundingBoxCenter.XYZ(); + int nodeind = nodeIndex1; + int lastind = nodeIndex2; + while (nodeind < lastind) + { + var node = bvh.Nodes.data_items[nodeind]; + if (node.ItemCount <= 0) //intermediate node with child nodes + { + Children = new List(); + var cind1 = nodeind + 1; + var lcind = nodeind + node.ItemId; //(child node count) + while (cind1 < lcind) + { + var cnode = bvh.Nodes.data_items[cind1]; + var ccount = (cnode.ItemCount <= 0) ? cnode.ItemId : 1; + var cind2 = cind1 + ccount; + var chi = new BVHBuilderNode(); + chi.Unbuild(bvh, cind1, cind2); + Children.Add(chi); + cind1 = cind2; + } + nodeind += node.ItemId; + } + else //leaf node, with polygons + { + Items = new List(); + for (int i = 0; i < node.ItemCount; i++) + { + var item = new BVHBuilderItem(); + item.Index = node.ItemId + i; + Items.Add(item); + } + //BVHBuilder.MaxNodeItemCount = Math.Max(BVHBuilder.MaxNodeItemCount, node.ItemCount); + nodeind++; + } + Min = node.Min * q + c; + Max = node.Max * q + c; + } + } + + public override string ToString() + { + var fstr = (Children != null) ? (TotalNodes.ToString() + ", 0 - ") : (Items != null) ? ("i, " + TotalItems.ToString() + " - ") : "error!"; + var cstr = (Children != null) ? (Children.Count.ToString() + " children") : ""; + var istr = (Items != null) ? (Items.Count.ToString() + " items") : ""; + if (string.IsNullOrEmpty(cstr)) return fstr + istr; + if (string.IsNullOrEmpty(istr)) return fstr + cstr; + return cstr + ", " + istr; + } + } + public class BVHBuilderItem + { + public Vector3 Min; + public Vector3 Max; + public int Index; + public Bounds Bounds; + public BoundPolygon Polygon; + } + [Flags] public enum EBoundMaterialFlags : ushort diff --git a/CodeWalker.Core/GameFiles/Resources/Clothes.cs b/CodeWalker.Core/GameFiles/Resources/Clothes.cs index 63d70ba..01412c4 100644 --- a/CodeWalker.Core/GameFiles/Resources/Clothes.cs +++ b/CodeWalker.Core/GameFiles/Resources/Clothes.cs @@ -648,6 +648,11 @@ namespace CodeWalker.GameFiles this.Unknown_140h_Pointer // offset ); + if (Bound != null) + { + Bound.Owner = this; + } + if (Unknown_70h?.data_items?.Length > 0) { } if (Unknown_80h?.data_items?.Length > 0) @@ -1132,6 +1137,11 @@ namespace CodeWalker.GameFiles this.BoundPointer // offset ); + if (Bound != null) + { + Bound.Owner = this; + } + } /// diff --git a/CodeWalker.Core/GameFiles/Resources/Drawable.cs b/CodeWalker.Core/GameFiles/Resources/Drawable.cs index b5888db..227a904 100644 --- a/CodeWalker.Core/GameFiles/Resources/Drawable.cs +++ b/CodeWalker.Core/GameFiles/Resources/Drawable.cs @@ -2768,6 +2768,12 @@ namespace CodeWalker.GameFiles this.Bound = reader.ReadBlockAt( this.BoundPointer // offset ); + + if (Bound != null) + { + Bound.Owner = this; + } + } catch (Exception ex) //sometimes error here for loading particles! different drawable type? base only? { diff --git a/CodeWalker.Core/GameFiles/Resources/Frag.cs b/CodeWalker.Core/GameFiles/Resources/Frag.cs index c003bad..eaf4b77 100644 --- a/CodeWalker.Core/GameFiles/Resources/Frag.cs +++ b/CodeWalker.Core/GameFiles/Resources/Frag.cs @@ -453,6 +453,11 @@ namespace CodeWalker.GameFiles FragMatrices = reader.ReadStructsAt(FragMatricesPointer, FragMatricesCount); Name = reader.ReadStringAt(NamePointer); + if (Bound != null) + { + Bound.Owner = this; + } + if ((Count3 != Count4)&&(Count4!=1)&&(Count3!=0)) { } if (FragMatricesInds != null) @@ -1272,6 +1277,11 @@ namespace CodeWalker.GameFiles } } } + + if (Bound != null) + { + Bound.Owner = this; + } } /// @@ -2123,6 +2133,11 @@ namespace CodeWalker.GameFiles this.Bound = reader.ReadBlockAt( this.BoundPointer // offset ); + + if (Bound != null) + { + Bound.Owner = this; + } } /// diff --git a/CodeWalker.Core/GameFiles/Resources/ResourceBaseTypes.cs b/CodeWalker.Core/GameFiles/Resources/ResourceBaseTypes.cs index 716d1a7..e9e24c0 100644 --- a/CodeWalker.Core/GameFiles/Resources/ResourceBaseTypes.cs +++ b/CodeWalker.Core/GameFiles/Resources/ResourceBaseTypes.cs @@ -828,7 +828,7 @@ namespace CodeWalker.GameFiles public uint EntriesCapacity { get; private set; } // reference data - public T[] data_items { get; private set; } + public T[] data_items { get; set; } private ResourceSystemStructBlock data_block;//used for saving. diff --git a/CodeWalker.Core/Utils/Vectors.cs b/CodeWalker.Core/Utils/Vectors.cs index 79ecd67..e41bf86 100644 --- a/CodeWalker.Core/Utils/Vectors.cs +++ b/CodeWalker.Core/Utils/Vectors.cs @@ -40,16 +40,38 @@ namespace CodeWalker } } + public static Vector3 Floor(this Vector3 v) + { + return new Vector3((float)Math.Floor(v.X), (float)Math.Floor(v.Y), (float)Math.Floor(v.Z)); + } + public static Vector3 Ceiling(this Vector3 v) + { + return new Vector3((float)Math.Ceiling(v.X), (float)Math.Ceiling(v.Y), (float)Math.Ceiling(v.Z)); + } + public static Vector3 Abs(this Vector3 v) { return new Vector3(Math.Abs(v.X), Math.Abs(v.Y), Math.Abs(v.Z)); } + public static int CompareTo(this Vector3 a, Vector3 b) + { + int c; + c = a.X.CompareTo(b.X); if (c != 0) return c; + c = a.Y.CompareTo(b.Y); if (c != 0) return c; + c = a.Z.CompareTo(b.Z); if (c != 0) return c; + return 0; + } + public static Vector4 Floor(this Vector4 v) { return new Vector4((float)Math.Floor(v.X), (float)Math.Floor(v.Y), (float)Math.Floor(v.Z), (float)Math.Floor(v.W)); } + public static Vector4 Ceiling(this Vector4 v) + { + return new Vector4((float)Math.Ceiling(v.X), (float)Math.Ceiling(v.Y), (float)Math.Ceiling(v.Z), (float)Math.Ceiling(v.W)); + } public static Vector4 Abs(this Vector4 v) { diff --git a/Project/Panels/EditYbnBoundPolyPanel.Designer.cs b/Project/Panels/EditYbnBoundPolyPanel.Designer.cs index 1a61ca1..5dbc20e 100644 --- a/Project/Panels/EditYbnBoundPolyPanel.Designer.cs +++ b/Project/Panels/EditYbnBoundPolyPanel.Designer.cs @@ -91,6 +91,9 @@ this.MatColourUpDown = new System.Windows.Forms.NumericUpDown(); this.label25 = new System.Windows.Forms.Label(); this.MatFlagsCheckedListBox = new System.Windows.Forms.CheckedListBox(); + this.UpdateSharedMaterialCheckBox = new System.Windows.Forms.CheckBox(); + this.DeleteButton = new System.Windows.Forms.Button(); + this.AddToProjectButton = new System.Windows.Forms.Button(); this.PolyTabControl.SuspendLayout(); this.TriangleTabPage.SuspendLayout(); this.SphereTabPage.SuspendLayout(); @@ -118,10 +121,10 @@ this.PolyTabControl.Controls.Add(this.CapsuleTabPage); this.PolyTabControl.Controls.Add(this.BoxTabPage); this.PolyTabControl.Controls.Add(this.CylinderTabPage); - this.PolyTabControl.Location = new System.Drawing.Point(0, 0); + this.PolyTabControl.Location = new System.Drawing.Point(0, 12); this.PolyTabControl.Name = "PolyTabControl"; this.PolyTabControl.SelectedIndex = 0; - this.PolyTabControl.Size = new System.Drawing.Size(564, 216); + this.PolyTabControl.Size = new System.Drawing.Size(564, 213); this.PolyTabControl.TabIndex = 0; // // TriangleTabPage @@ -146,7 +149,7 @@ this.TriangleTabPage.Location = new System.Drawing.Point(4, 22); this.TriangleTabPage.Name = "TriangleTabPage"; this.TriangleTabPage.Padding = new System.Windows.Forms.Padding(3); - this.TriangleTabPage.Size = new System.Drawing.Size(556, 190); + this.TriangleTabPage.Size = new System.Drawing.Size(556, 187); this.TriangleTabPage.TabIndex = 0; this.TriangleTabPage.Text = "Triangle"; this.TriangleTabPage.UseVisualStyleBackColor = true; @@ -160,7 +163,7 @@ this.SphereTabPage.Location = new System.Drawing.Point(4, 22); this.SphereTabPage.Name = "SphereTabPage"; this.SphereTabPage.Padding = new System.Windows.Forms.Padding(3); - this.SphereTabPage.Size = new System.Drawing.Size(556, 190); + this.SphereTabPage.Size = new System.Drawing.Size(556, 185); this.SphereTabPage.TabIndex = 1; this.SphereTabPage.Text = "Sphere"; this.SphereTabPage.UseVisualStyleBackColor = true; @@ -175,7 +178,7 @@ this.CapsuleTabPage.Controls.Add(this.label12); this.CapsuleTabPage.Location = new System.Drawing.Point(4, 22); this.CapsuleTabPage.Name = "CapsuleTabPage"; - this.CapsuleTabPage.Size = new System.Drawing.Size(556, 190); + this.CapsuleTabPage.Size = new System.Drawing.Size(556, 185); this.CapsuleTabPage.TabIndex = 2; this.CapsuleTabPage.Text = "Capsule"; this.CapsuleTabPage.UseVisualStyleBackColor = true; @@ -192,7 +195,7 @@ this.BoxTabPage.Controls.Add(this.label19); this.BoxTabPage.Location = new System.Drawing.Point(4, 22); this.BoxTabPage.Name = "BoxTabPage"; - this.BoxTabPage.Size = new System.Drawing.Size(556, 190); + this.BoxTabPage.Size = new System.Drawing.Size(556, 185); this.BoxTabPage.TabIndex = 3; this.BoxTabPage.Text = "Box"; this.BoxTabPage.UseVisualStyleBackColor = true; @@ -207,7 +210,7 @@ this.CylinderTabPage.Controls.Add(this.label15); this.CylinderTabPage.Location = new System.Drawing.Point(4, 22); this.CylinderTabPage.Name = "CylinderTabPage"; - this.CylinderTabPage.Size = new System.Drawing.Size(556, 190); + this.CylinderTabPage.Size = new System.Drawing.Size(556, 185); this.CylinderTabPage.TabIndex = 4; this.CylinderTabPage.Text = "Cylinder"; this.CylinderTabPage.UseVisualStyleBackColor = true; @@ -408,14 +411,15 @@ | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.MaterialTabControl.Controls.Add(this.MaterialTabPage); - this.MaterialTabControl.Location = new System.Drawing.Point(0, 218); + this.MaterialTabControl.Location = new System.Drawing.Point(0, 225); this.MaterialTabControl.Name = "MaterialTabControl"; this.MaterialTabControl.SelectedIndex = 0; - this.MaterialTabControl.Size = new System.Drawing.Size(564, 286); + this.MaterialTabControl.Size = new System.Drawing.Size(564, 279); this.MaterialTabControl.TabIndex = 1; // // MaterialTabPage // + this.MaterialTabPage.Controls.Add(this.UpdateSharedMaterialCheckBox); this.MaterialTabPage.Controls.Add(this.MatFlagsCheckedListBox); this.MaterialTabPage.Controls.Add(this.MatColourUpDown); this.MaterialTabPage.Controls.Add(this.label25); @@ -432,7 +436,7 @@ this.MaterialTabPage.Location = new System.Drawing.Point(4, 22); this.MaterialTabPage.Name = "MaterialTabPage"; this.MaterialTabPage.Padding = new System.Windows.Forms.Padding(3); - this.MaterialTabPage.Size = new System.Drawing.Size(556, 260); + this.MaterialTabPage.Size = new System.Drawing.Size(556, 253); this.MaterialTabPage.TabIndex = 0; this.MaterialTabPage.Text = "Material"; this.MaterialTabPage.UseVisualStyleBackColor = true; @@ -668,7 +672,7 @@ // MatTypeCombo // this.MatTypeCombo.FormattingEnabled = true; - this.MatTypeCombo.Location = new System.Drawing.Point(92, 9); + this.MatTypeCombo.Location = new System.Drawing.Point(92, 6); this.MatTypeCombo.Name = "MatTypeCombo"; this.MatTypeCombo.Size = new System.Drawing.Size(195, 21); this.MatTypeCombo.TabIndex = 20; @@ -677,7 +681,7 @@ // label20 // this.label20.AutoSize = true; - this.label20.Location = new System.Drawing.Point(39, 12); + this.label20.Location = new System.Drawing.Point(39, 9); this.label20.Name = "label20"; this.label20.Size = new System.Drawing.Size(47, 13); this.label20.TabIndex = 19; @@ -685,7 +689,7 @@ // // MatUnkUpDown // - this.MatUnkUpDown.Location = new System.Drawing.Point(92, 140); + this.MatUnkUpDown.Location = new System.Drawing.Point(92, 137); this.MatUnkUpDown.Maximum = new decimal(new int[] { 65535, 0, @@ -699,7 +703,7 @@ // label21 // this.label21.AutoSize = true; - this.label21.Location = new System.Drawing.Point(56, 142); + this.label21.Location = new System.Drawing.Point(56, 139); this.label21.Name = "label21"; this.label21.Size = new System.Drawing.Size(30, 13); this.label21.TabIndex = 29; @@ -707,7 +711,7 @@ // // MatPedDensityUpDown // - this.MatPedDensityUpDown.Location = new System.Drawing.Point(92, 114); + this.MatPedDensityUpDown.Location = new System.Drawing.Point(92, 111); this.MatPedDensityUpDown.Maximum = new decimal(new int[] { 255, 0, @@ -721,7 +725,7 @@ // label22 // this.label22.AutoSize = true; - this.label22.Location = new System.Drawing.Point(19, 116); + this.label22.Location = new System.Drawing.Point(19, 113); this.label22.Name = "label22"; this.label22.Size = new System.Drawing.Size(67, 13); this.label22.TabIndex = 27; @@ -729,7 +733,7 @@ // // MatRoomIDUpDown // - this.MatRoomIDUpDown.Location = new System.Drawing.Point(92, 88); + this.MatRoomIDUpDown.Location = new System.Drawing.Point(92, 85); this.MatRoomIDUpDown.Maximum = new decimal(new int[] { 255, 0, @@ -743,7 +747,7 @@ // label23 // this.label23.AutoSize = true; - this.label23.Location = new System.Drawing.Point(34, 90); + this.label23.Location = new System.Drawing.Point(34, 87); this.label23.Name = "label23"; this.label23.Size = new System.Drawing.Size(52, 13); this.label23.TabIndex = 25; @@ -751,7 +755,7 @@ // // MatProceduralIDUpDown // - this.MatProceduralIDUpDown.Location = new System.Drawing.Point(92, 62); + this.MatProceduralIDUpDown.Location = new System.Drawing.Point(92, 59); this.MatProceduralIDUpDown.Maximum = new decimal(new int[] { 255, 0, @@ -765,7 +769,7 @@ // label24 // this.label24.AutoSize = true; - this.label24.Location = new System.Drawing.Point(11, 64); + this.label24.Location = new System.Drawing.Point(11, 61); this.label24.Name = "label24"; this.label24.Size = new System.Drawing.Size(75, 13); this.label24.TabIndex = 23; @@ -773,7 +777,7 @@ // // MatColourUpDown // - this.MatColourUpDown.Location = new System.Drawing.Point(92, 36); + this.MatColourUpDown.Location = new System.Drawing.Point(92, 33); this.MatColourUpDown.Maximum = new decimal(new int[] { 255, 0, @@ -787,7 +791,7 @@ // label25 // this.label25.AutoSize = true; - this.label25.Location = new System.Drawing.Point(6, 38); + this.label25.Location = new System.Drawing.Point(6, 35); this.label25.Name = "label25"; this.label25.Size = new System.Drawing.Size(80, 13); this.label25.TabIndex = 21; @@ -816,17 +820,51 @@ "13 - Too Steep for Player", "14 - No Network Spawn", "15 - No Cam Collision Allow Clipping"}); - this.MatFlagsCheckedListBox.Location = new System.Drawing.Point(326, 9); + this.MatFlagsCheckedListBox.Location = new System.Drawing.Point(326, 6); this.MatFlagsCheckedListBox.Name = "MatFlagsCheckedListBox"; this.MatFlagsCheckedListBox.Size = new System.Drawing.Size(223, 244); this.MatFlagsCheckedListBox.TabIndex = 31; this.MatFlagsCheckedListBox.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.MatFlagsCheckedListBox_ItemCheck); // + // UpdateSharedMaterialCheckBox + // + this.UpdateSharedMaterialCheckBox.AutoSize = true; + this.UpdateSharedMaterialCheckBox.Location = new System.Drawing.Point(92, 172); + this.UpdateSharedMaterialCheckBox.Name = "UpdateSharedMaterialCheckBox"; + this.UpdateSharedMaterialCheckBox.Size = new System.Drawing.Size(170, 17); + this.UpdateSharedMaterialCheckBox.TabIndex = 32; + this.UpdateSharedMaterialCheckBox.Text = "Update shared material on edit"; + this.UpdateSharedMaterialCheckBox.UseVisualStyleBackColor = true; + // + // DeleteButton + // + this.DeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.DeleteButton.Location = new System.Drawing.Point(458, 7); + this.DeleteButton.Name = "DeleteButton"; + this.DeleteButton.Size = new System.Drawing.Size(95, 23); + this.DeleteButton.TabIndex = 38; + this.DeleteButton.Text = "Delete Polygon"; + this.DeleteButton.UseVisualStyleBackColor = true; + this.DeleteButton.Click += new System.EventHandler(this.DeleteButton_Click); + // + // AddToProjectButton + // + this.AddToProjectButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.AddToProjectButton.Location = new System.Drawing.Point(357, 7); + this.AddToProjectButton.Name = "AddToProjectButton"; + this.AddToProjectButton.Size = new System.Drawing.Size(95, 23); + this.AddToProjectButton.TabIndex = 37; + this.AddToProjectButton.Text = "Add to Project"; + this.AddToProjectButton.UseVisualStyleBackColor = true; + this.AddToProjectButton.Click += new System.EventHandler(this.AddToProjectButton_Click); + // // EditYbnBoundPolyPanel // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(565, 505); + this.Controls.Add(this.DeleteButton); + this.Controls.Add(this.AddToProjectButton); this.Controls.Add(this.MaterialTabControl); this.Controls.Add(this.PolyTabControl); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); @@ -922,5 +960,8 @@ private System.Windows.Forms.NumericUpDown MatColourUpDown; private System.Windows.Forms.Label label25; private System.Windows.Forms.CheckedListBox MatFlagsCheckedListBox; + private System.Windows.Forms.CheckBox UpdateSharedMaterialCheckBox; + private System.Windows.Forms.Button DeleteButton; + private System.Windows.Forms.Button AddToProjectButton; } } \ No newline at end of file diff --git a/Project/Panels/EditYbnBoundPolyPanel.cs b/Project/Panels/EditYbnBoundPolyPanel.cs index 93acf57..e422a4a 100644 --- a/Project/Panels/EditYbnBoundPolyPanel.cs +++ b/Project/Panels/EditYbnBoundPolyPanel.cs @@ -81,6 +81,8 @@ namespace CodeWalker.Project.Panels { if (CollisionPoly == null) { + AddToProjectButton.Enabled = false; + DeleteButton.Enabled = false; PolyTabControl.TabPages.Clear(); TriVertex1TextBox.Text = string.Empty; TriVertex2TextBox.Text = string.Empty; @@ -192,6 +194,10 @@ namespace CodeWalker.Project.Panels MatUnkUpDown.Value = m.Unk4; SetCheckedListBoxValues(MatFlagsCheckedListBox, (ushort)m.Flags); + var ybn = CollisionPoly.Owner?.GetRootYbn(); + AddToProjectButton.Enabled = (ybn != null) ? !ProjectForm.YbnExistsInProject(ybn) : false; + DeleteButton.Enabled = !AddToProjectButton.Enabled; + populatingui = false; } } @@ -226,6 +232,29 @@ namespace CodeWalker.Project.Panels } + private void UpdatePolyMaterial(BoundMaterial_s mat) + { + if (CollisionPoly == null) return; + var shared = UpdateSharedMaterialCheckBox.Checked && (CollisionPoly.Owner != null); + lock (ProjectForm.ProjectSyncRoot) + { + if (shared) + { + CollisionPoly.Owner.SetMaterial(CollisionPoly.Index, mat); + } + else + { + CollisionPoly.Material = mat; + } + ProjectForm.SetYbnHasChanged(true); + } + if ((ProjectForm.WorldForm != null) && (CollisionPoly.Owner != null)) + { + ProjectForm.WorldForm.UpdateCollisionBoundsGraphics(CollisionPoly.Owner); + } + } + + private void TriVertex1TextBox_TextChanged(object sender, EventArgs e) { @@ -561,49 +590,103 @@ namespace CodeWalker.Project.Panels { if (CollisionPoly == null) return; if (populatingui) return; - + var mat = CollisionPoly.Material; + var v = (byte)MatTypeCombo.SelectedIndex; + if (mat.Type != v) + { + mat.Type = v; + UpdatePolyMaterial(mat); + } } private void MatColourUpDown_ValueChanged(object sender, EventArgs e) { if (CollisionPoly == null) return; if (populatingui) return; - + var mat = CollisionPoly.Material; + var v = (byte)MatColourUpDown.Value; + if (mat.MaterialColorIndex != v) + { + mat.MaterialColorIndex = v; + UpdatePolyMaterial(mat); + } } private void MatProceduralIDUpDown_ValueChanged(object sender, EventArgs e) { if (CollisionPoly == null) return; if (populatingui) return; - + var mat = CollisionPoly.Material; + var v = (byte)MatProceduralIDUpDown.Value; + if (mat.ProceduralId != v) + { + mat.ProceduralId = v; + UpdatePolyMaterial(mat); + } } private void MatRoomIDUpDown_ValueChanged(object sender, EventArgs e) { if (CollisionPoly == null) return; if (populatingui) return; - + var mat = CollisionPoly.Material; + var v = (byte)MatRoomIDUpDown.Value; + if (mat.RoomId != v) + { + mat.RoomId = v; + UpdatePolyMaterial(mat); + } } private void MatPedDensityUpDown_ValueChanged(object sender, EventArgs e) { if (CollisionPoly == null) return; if (populatingui) return; - + var mat = CollisionPoly.Material; + var v = (byte)MatPedDensityUpDown.Value; + if (mat.PedDensity != v) + { + mat.PedDensity = v; + UpdatePolyMaterial(mat); + } } private void MatUnkUpDown_ValueChanged(object sender, EventArgs e) { if (CollisionPoly == null) return; if (populatingui) return; - + var mat = CollisionPoly.Material; + var v = (ushort)MatUnkUpDown.Value; + if (mat.Unk4 != v) + { + mat.Unk4 = v; + UpdatePolyMaterial(mat); + } } private void MatFlagsCheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e) { if (CollisionPoly == null) return; if (populatingui) return; + var mat = CollisionPoly.Material; + var v = (EBoundMaterialFlags)GetCheckedListBoxValues(MatFlagsCheckedListBox, e); + if (mat.Flags != v) + { + mat.Flags = v; + UpdatePolyMaterial(mat); + } + } + private void AddToProjectButton_Click(object sender, EventArgs e) + { + ProjectForm.SetProjectItem(CollisionPoly); + ProjectForm.AddCollisionPolyToProject(); + } + + private void DeleteButton_Click(object sender, EventArgs e) + { + ProjectForm.SetProjectItem(CollisionPoly); + ProjectForm.DeleteCollisionPoly(); } } } diff --git a/Project/Panels/EditYbnBoundsPanel.Designer.cs b/Project/Panels/EditYbnBoundsPanel.Designer.cs index 29937d6..7f950e0 100644 --- a/Project/Panels/EditYbnBoundsPanel.Designer.cs +++ b/Project/Panels/EditYbnBoundsPanel.Designer.cs @@ -64,16 +64,18 @@ this.label11 = new System.Windows.Forms.Label(); this.label5 = new System.Windows.Forms.Label(); this.GeometryTabPage = new System.Windows.Forms.TabPage(); - this.CenterGeomTextBox = new System.Windows.Forms.TextBox(); - this.label17 = new System.Windows.Forms.Label(); - this.QuantumTextBox = new System.Windows.Forms.TextBox(); - this.label18 = new System.Windows.Forms.Label(); - this.UnkFloat1TextBox = new System.Windows.Forms.TextBox(); - this.label19 = new System.Windows.Forms.Label(); + this.PolyCountLabel = new System.Windows.Forms.Label(); + this.VertexCountLabel = new System.Windows.Forms.Label(); this.UnkFloat2TextBox = new System.Windows.Forms.TextBox(); this.label20 = new System.Windows.Forms.Label(); - this.VertexCountLabel = new System.Windows.Forms.Label(); - this.PolyCountLabel = new System.Windows.Forms.Label(); + this.UnkFloat1TextBox = new System.Windows.Forms.TextBox(); + this.label19 = new System.Windows.Forms.Label(); + this.QuantumTextBox = new System.Windows.Forms.TextBox(); + this.label18 = new System.Windows.Forms.Label(); + this.CenterGeomTextBox = new System.Windows.Forms.TextBox(); + this.label17 = new System.Windows.Forms.Label(); + this.DeleteButton = new System.Windows.Forms.Button(); + this.AddToProjectButton = new System.Windows.Forms.Button(); this.BoundsTabControl.SuspendLayout(); this.BoundsTabPage.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.UnkTypeUpDown)).BeginInit(); @@ -99,6 +101,8 @@ // // BoundsTabPage // + this.BoundsTabPage.Controls.Add(this.DeleteButton); + this.BoundsTabPage.Controls.Add(this.AddToProjectButton); this.BoundsTabPage.Controls.Add(this.MaterialCombo); this.BoundsTabPage.Controls.Add(this.UnkTypeUpDown); this.BoundsTabPage.Controls.Add(this.label16); @@ -483,62 +487,23 @@ this.GeometryTabPage.Text = "Geometry"; this.GeometryTabPage.UseVisualStyleBackColor = true; // - // CenterGeomTextBox + // PolyCountLabel // - this.CenterGeomTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.CenterGeomTextBox.Location = new System.Drawing.Point(91, 6); - this.CenterGeomTextBox.Name = "CenterGeomTextBox"; - this.CenterGeomTextBox.Size = new System.Drawing.Size(458, 20); - this.CenterGeomTextBox.TabIndex = 4; - this.CenterGeomTextBox.TextChanged += new System.EventHandler(this.CenterGeomTextBox_TextChanged); + this.PolyCountLabel.AutoSize = true; + this.PolyCountLabel.Location = new System.Drawing.Point(88, 144); + this.PolyCountLabel.Name = "PolyCountLabel"; + this.PolyCountLabel.Size = new System.Drawing.Size(58, 13); + this.PolyCountLabel.TabIndex = 12; + this.PolyCountLabel.Text = "0 polygons"; // - // label17 + // VertexCountLabel // - this.label17.AutoSize = true; - this.label17.Location = new System.Drawing.Point(13, 9); - this.label17.Name = "label17"; - this.label17.Size = new System.Drawing.Size(72, 13); - this.label17.TabIndex = 3; - this.label17.Text = "Geom Center:"; - // - // QuantumTextBox - // - this.QuantumTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.QuantumTextBox.Location = new System.Drawing.Point(91, 32); - this.QuantumTextBox.Name = "QuantumTextBox"; - this.QuantumTextBox.Size = new System.Drawing.Size(458, 20); - this.QuantumTextBox.TabIndex = 6; - this.QuantumTextBox.TextChanged += new System.EventHandler(this.QuantumTextBox_TextChanged); - // - // label18 - // - this.label18.AutoSize = true; - this.label18.Location = new System.Drawing.Point(32, 35); - this.label18.Name = "label18"; - this.label18.Size = new System.Drawing.Size(53, 13); - this.label18.TabIndex = 5; - this.label18.Text = "Quantum:"; - // - // UnkFloat1TextBox - // - this.UnkFloat1TextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.UnkFloat1TextBox.Location = new System.Drawing.Point(91, 58); - this.UnkFloat1TextBox.Name = "UnkFloat1TextBox"; - this.UnkFloat1TextBox.Size = new System.Drawing.Size(458, 20); - this.UnkFloat1TextBox.TabIndex = 8; - this.UnkFloat1TextBox.TextChanged += new System.EventHandler(this.UnkFloat1TextBox_TextChanged); - // - // label19 - // - this.label19.AutoSize = true; - this.label19.Location = new System.Drawing.Point(20, 61); - this.label19.Name = "label19"; - this.label19.Size = new System.Drawing.Size(65, 13); - this.label19.TabIndex = 7; - this.label19.Text = "Unk Float 1:"; + this.VertexCountLabel.AutoSize = true; + this.VertexCountLabel.Location = new System.Drawing.Point(88, 124); + this.VertexCountLabel.Name = "VertexCountLabel"; + this.VertexCountLabel.Size = new System.Drawing.Size(53, 13); + this.VertexCountLabel.TabIndex = 11; + this.VertexCountLabel.Text = "0 vertices"; // // UnkFloat2TextBox // @@ -559,23 +524,84 @@ this.label20.TabIndex = 9; this.label20.Text = "Unk Float 2:"; // - // VertexCountLabel + // UnkFloat1TextBox // - this.VertexCountLabel.AutoSize = true; - this.VertexCountLabel.Location = new System.Drawing.Point(88, 124); - this.VertexCountLabel.Name = "VertexCountLabel"; - this.VertexCountLabel.Size = new System.Drawing.Size(53, 13); - this.VertexCountLabel.TabIndex = 11; - this.VertexCountLabel.Text = "0 vertices"; + this.UnkFloat1TextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.UnkFloat1TextBox.Location = new System.Drawing.Point(91, 58); + this.UnkFloat1TextBox.Name = "UnkFloat1TextBox"; + this.UnkFloat1TextBox.Size = new System.Drawing.Size(458, 20); + this.UnkFloat1TextBox.TabIndex = 8; + this.UnkFloat1TextBox.TextChanged += new System.EventHandler(this.UnkFloat1TextBox_TextChanged); // - // PolyCountLabel + // label19 // - this.PolyCountLabel.AutoSize = true; - this.PolyCountLabel.Location = new System.Drawing.Point(88, 144); - this.PolyCountLabel.Name = "PolyCountLabel"; - this.PolyCountLabel.Size = new System.Drawing.Size(58, 13); - this.PolyCountLabel.TabIndex = 12; - this.PolyCountLabel.Text = "0 polygons"; + this.label19.AutoSize = true; + this.label19.Location = new System.Drawing.Point(20, 61); + this.label19.Name = "label19"; + this.label19.Size = new System.Drawing.Size(65, 13); + this.label19.TabIndex = 7; + this.label19.Text = "Unk Float 1:"; + // + // QuantumTextBox + // + this.QuantumTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.QuantumTextBox.Location = new System.Drawing.Point(91, 32); + this.QuantumTextBox.Name = "QuantumTextBox"; + this.QuantumTextBox.Size = new System.Drawing.Size(458, 20); + this.QuantumTextBox.TabIndex = 6; + this.QuantumTextBox.TextChanged += new System.EventHandler(this.QuantumTextBox_TextChanged); + // + // label18 + // + this.label18.AutoSize = true; + this.label18.Location = new System.Drawing.Point(32, 35); + this.label18.Name = "label18"; + this.label18.Size = new System.Drawing.Size(53, 13); + this.label18.TabIndex = 5; + this.label18.Text = "Quantum:"; + // + // CenterGeomTextBox + // + this.CenterGeomTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.CenterGeomTextBox.Location = new System.Drawing.Point(91, 6); + this.CenterGeomTextBox.Name = "CenterGeomTextBox"; + this.CenterGeomTextBox.Size = new System.Drawing.Size(458, 20); + this.CenterGeomTextBox.TabIndex = 4; + this.CenterGeomTextBox.TextChanged += new System.EventHandler(this.CenterGeomTextBox_TextChanged); + // + // label17 + // + this.label17.AutoSize = true; + this.label17.Location = new System.Drawing.Point(13, 9); + this.label17.Name = "label17"; + this.label17.Size = new System.Drawing.Size(72, 13); + this.label17.TabIndex = 3; + this.label17.Text = "Geom Center:"; + // + // DeleteButton + // + this.DeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.DeleteButton.Location = new System.Drawing.Point(454, 238); + this.DeleteButton.Name = "DeleteButton"; + this.DeleteButton.Size = new System.Drawing.Size(95, 23); + this.DeleteButton.TabIndex = 36; + this.DeleteButton.Text = "Delete Bounds"; + this.DeleteButton.UseVisualStyleBackColor = true; + this.DeleteButton.Click += new System.EventHandler(this.DeleteButton_Click); + // + // AddToProjectButton + // + this.AddToProjectButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.AddToProjectButton.Location = new System.Drawing.Point(353, 238); + this.AddToProjectButton.Name = "AddToProjectButton"; + this.AddToProjectButton.Size = new System.Drawing.Size(95, 23); + this.AddToProjectButton.TabIndex = 35; + this.AddToProjectButton.Text = "Add to Project"; + this.AddToProjectButton.UseVisualStyleBackColor = true; + this.AddToProjectButton.Click += new System.EventHandler(this.AddToProjectButton_Click); // // EditYbnBoundsPanel // @@ -649,5 +675,7 @@ private System.Windows.Forms.Label label19; private System.Windows.Forms.Label PolyCountLabel; private System.Windows.Forms.Label VertexCountLabel; + private System.Windows.Forms.Button DeleteButton; + private System.Windows.Forms.Button AddToProjectButton; } } \ No newline at end of file diff --git a/Project/Panels/EditYbnBoundsPanel.cs b/Project/Panels/EditYbnBoundsPanel.cs index 6878b27..098b583 100644 --- a/Project/Panels/EditYbnBoundsPanel.cs +++ b/Project/Panels/EditYbnBoundsPanel.cs @@ -74,6 +74,8 @@ namespace CodeWalker.Project.Panels var b = CollisionBounds; if (b == null) { + AddToProjectButton.Enabled = false; + DeleteButton.Enabled = false; BBMinTextBox.Text = string.Empty; BBMaxTextBox.Text = string.Empty; BBCenterTextBox.Text = string.Empty; @@ -144,6 +146,10 @@ namespace CodeWalker.Project.Panels PolyCountLabel.Text = "0 polygons"; } + var ybn = b.GetRootYbn(); + AddToProjectButton.Enabled = (ybn != null) ? !ProjectForm.YbnExistsInProject(ybn) : false; + DeleteButton.Enabled = !AddToProjectButton.Enabled; + populatingui = false; } } @@ -447,5 +453,17 @@ namespace CodeWalker.Project.Panels } } } + + private void AddToProjectButton_Click(object sender, EventArgs e) + { + ProjectForm.SetProjectItem(CollisionBounds); + ProjectForm.AddCollisionBoundsToProject(); + } + + private void DeleteButton_Click(object sender, EventArgs e) + { + ProjectForm.SetProjectItem(CollisionBounds); + ProjectForm.DeleteCollisionBounds(); + } } } diff --git a/Project/ProjectForm.cs b/Project/ProjectForm.cs index a076723..91c5ffa 100644 --- a/Project/ProjectForm.cs +++ b/Project/ProjectForm.cs @@ -3048,6 +3048,157 @@ namespace CodeWalker.Project return CurrentProjectFile.ContainsYbn(ybn); } + public void NewCollisionBounds(BoundsType type, Bounds copy = null) + { + if (CurrentYbnFile == null) return; + + //////// TODO!! + + } + public void AddCollisionBoundsToProject() + { + try + { + if (CurrentCollisionBounds == null) return; + + CurrentYbnFile = CurrentCollisionBounds.GetRootYbn(); + if (CurrentYbnFile == null) + { + MessageBox.Show("Sorry, only YBN collisions can currently be added to the project. Embedded collisions TODO!"); + return; + } + + if (!YbnExistsInProject(CurrentYbnFile)) + { + var b = CurrentCollisionBounds; + CurrentYbnFile.HasChanged = true; + AddYbnToProject(CurrentYbnFile); + + CurrentCollisionBounds = b; //bug fix for some reason the treeview selects the project node here. + CurrentYbnFile = b.GetRootYbn(); + ProjectExplorer?.TrySelectCollisionBoundsTreeNode(b); + } + } + catch + { } + } + public bool DeleteCollisionBounds() + { + if (CurrentCollisionBounds == null) return false; + if (CurrentYbnFile == null) return false; + if (CurrentCollisionBounds.GetRootYbn() != CurrentYbnFile) return false; + + if (MessageBox.Show("Are you sure you want to delete this collision bounds?\n" + CurrentCollisionBounds.ToString() + "\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) + { + return true; + } + + bool res = false; + if (WorldForm != null) + { + lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... + { + res = CurrentYbnFile.RemoveBounds(CurrentCollisionBounds); + //WorldForm.SelectItem(null, null, null); + } + } + else + { + res = CurrentYbnFile.RemoveBounds(CurrentCollisionBounds); + } + if (!res) + { + MessageBox.Show("Unable to delete the collision bounds. This shouldn't happen!"); + } + + var delb = CurrentCollisionBounds; + + ProjectExplorer?.RemoveCollisionBoundsTreeNode(CurrentCollisionBounds); + ProjectExplorer?.SetYbnHasChanged(CurrentYbnFile, true); + + ClosePanel((EditYbnBoundsPanel p) => { return p.Tag == delb; }); + + CurrentCollisionBounds = null; + + return true; + } + + public void NewCollisionPoly(BoundPolygonType type, BoundPolygon copy = null) + { + if (CurrentYbnFile == null) return; + + //////// TODO!! + + } + public void AddCollisionPolyToProject() + { + try + { + if (CurrentCollisionPoly == null) return; + + CurrentYbnFile = CurrentCollisionPoly.Owner?.GetRootYbn(); + if (CurrentYbnFile == null) + { + MessageBox.Show("Sorry, only YBN collisions can currently be added to the project. Embedded collisions TODO!"); + return; + } + + if (!YbnExistsInProject(CurrentYbnFile)) + { + var p = CurrentCollisionPoly; + CurrentYbnFile.HasChanged = true; + AddYbnToProject(CurrentYbnFile); + + CurrentCollisionPoly = p; //bug fix for some reason the treeview selects the project node here. + CurrentCollisionBounds = p.Owner; + CurrentYbnFile = p.Owner?.GetRootYbn(); + ProjectExplorer?.TrySelectCollisionPolyTreeNode(p); + } + } + catch + { } + } + public bool DeleteCollisionPoly() + { + if (CurrentCollisionBounds == null) return false; + if (CurrentCollisionPoly == null) return false; + if (CurrentYbnFile == null) return false; + if (CurrentCollisionPoly.Owner != CurrentCollisionBounds) return false; + + if (MessageBox.Show("Are you sure you want to delete this collision poly?\n" + CurrentCollisionPoly.ToString() + "\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) + { + return true; + } + + bool res = false; + if (WorldForm != null) + { + lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... + { + res = CurrentYbnFile.RemovePoly(CurrentCollisionPoly); + //WorldForm.SelectItem(null, null, null); + } + } + else + { + res = CurrentYbnFile.RemovePoly(CurrentCollisionPoly); + } + if (!res) + { + MessageBox.Show("Unable to delete the collision poly. This shouldn't happen!"); + } + + var delp = CurrentCollisionPoly; + + //ProjectExplorer?.RemoveCollisionPolyTreeNode(CurrentCollisionPoly); + ProjectExplorer?.SetYbnHasChanged(CurrentYbnFile, true); + + ClosePanel((EditYbnBoundPolyPanel p) => { return p.Tag == delp; }); + + CurrentCollisionPoly = null; + + return true; + }