diff --git a/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs b/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs index 368bb16..1fb2f73 100644 --- a/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs +++ b/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs @@ -589,6 +589,28 @@ namespace CodeWalker.GameFiles //how to rebuild these here? the LODlights array is on the child ymap... //for now, they are being updated as they are edited in project window } + public void BuildBoxOccluders() + { + if (BoxOccluders == null) return; + if (BoxOccluders.Length == 0) return; + + var boxes = new BoxOccluder[BoxOccluders.Length]; + for (int i = 0; i < BoxOccluders.Length; i++) + { + var box = BoxOccluders[i]; + box.UpdateBoxStruct(); + boxes[i] = box._Box; + } + + CBoxOccluders = boxes; + + } + public void BuildOccludeModels() + { + if (OccludeModels == null) return; + if (OccludeModels.Length == 0) return; + //nothing to do here, has to be done later due to embedded data + } public byte[] Save() { @@ -601,11 +623,11 @@ namespace CodeWalker.GameFiles BuildInstances(); BuildLodLights(); BuildDistantLodLights(); + BuildBoxOccluders(); + BuildOccludeModels(); //TODO: //BuildTimecycleModifiers(); //already being saved - update them.. - //BuildBoxOccluders(); - //BuildOccludeModels(); //BuildContainerLods(); @@ -658,14 +680,12 @@ namespace CodeWalker.GameFiles mapdata.carGenerators = mb.AddItemArrayPtr(MetaName.CCarGen, CCarGens); - //clear everything out for now - TODO: fix + + + //clear everything else out for now - TODO: fix if (mapdata.containerLods.Count1 != 0) LogSaveWarning("containerLods were not saved. (TODO!)"); - if (mapdata.occludeModels.Count1 != 0) LogSaveWarning("occludeModels were not saved. (TODO!)"); - if (mapdata.boxOccluders.Count1 != 0) LogSaveWarning("boxOccluders were not saved. (TODO!)"); if (mapdata.instancedData.PropInstanceList.Count1 != 0) LogSaveWarning("instancedData.PropInstanceList was not saved. (TODO!)"); mapdata.containerLods = new Array_Structure(); - mapdata.occludeModels = new Array_Structure(); - mapdata.boxOccluders = new Array_Structure(); if ((GrassInstanceBatches != null) && (GrassInstanceBatches.Length > 0)) { @@ -720,6 +740,32 @@ namespace CodeWalker.GameFiles mapdata.DistantLODLightsSOA = new CDistantLODLight(); } + if ((CBoxOccluders != null) && (CBoxOccluders.Length > 0)) + { + mapdata.boxOccluders = mb.AddItemArrayPtr(MetaName.BoxOccluder, CBoxOccluders); + } + else + { + mapdata.boxOccluders = new Array_Structure(); + } + if ((OccludeModels != null) && (OccludeModels.Length > 0)) + { + COccludeModels = new OccludeModel[OccludeModels.Length]; + for (int i = 0; i < OccludeModels.Length; i++) + { + var model = OccludeModels[i]; + model.BuildVertices(); + model.BuildData(); + var cocc = model._OccludeModel; + cocc.verts = mb.AddDataBlockPtr(model.Data, (MetaName)MetaStructureEntryDataType.UnsignedByte);//17 + COccludeModels[i] = cocc; + } + mapdata.occludeModels = mb.AddItemArrayPtr(MetaName.OccludeModel, COccludeModels); + } + else + { + mapdata.occludeModels = new Array_Structure(); + } var block = new CBlockDesc(); @@ -751,9 +797,17 @@ namespace CodeWalker.GameFiles mb.AddStructureInfo(MetaName.CDistantLODLight); mb.AddStructureInfo(MetaName.CBlockDesc); mb.AddStructureInfo(MetaName.CMapData); - mb.AddStructureInfo(MetaName.CEntityDef); - mb.AddStructureInfo(MetaName.CMloInstanceDef); - mb.AddStructureInfo(MetaName.CTimeCycleModifier); + if ((AllEntities != null) && (AllEntities.Length > 0)) + { + mb.AddStructureInfo(MetaName.CEntityDef); + mb.AddStructureInfo(MetaName.CMloInstanceDef); + mb.AddEnumInfo(MetaName.rage__eLodType); //LODTYPES_ + mb.AddEnumInfo(MetaName.rage__ePriorityLevel); //PRI_ + } + if ((CTimeCycleModifiers != null) && (CTimeCycleModifiers.Length > 0)) + { + mb.AddStructureInfo(MetaName.CTimeCycleModifier); + } if ((CCarGens != null) && (CCarGens.Length > 0)) { mb.AddStructureInfo(MetaName.CCarGen); @@ -766,9 +820,14 @@ namespace CodeWalker.GameFiles { mb.AddStructureInfo(MetaName.FloatXYZ); } - - mb.AddEnumInfo(MetaName.rage__eLodType); //LODTYPES_ - mb.AddEnumInfo(MetaName.rage__ePriorityLevel); //PRI_ + if ((CBoxOccluders != null) && (CBoxOccluders.Length > 0)) + { + mb.AddStructureInfo(MetaName.BoxOccluder); + } + if ((COccludeModels != null) && (COccludeModels.Length > 0)) + { + mb.AddStructureInfo(MetaName.OccludeModel); + } Meta meta = mb.GetMeta(); @@ -1090,6 +1149,131 @@ namespace CodeWalker.GameFiles return true; } + + public void AddBoxOccluder(YmapBoxOccluder box) + { + if (box == null) return; + var boxes = new List(); + if (BoxOccluders != null) boxes.AddRange(BoxOccluders); + box.Ymap = this; + box.Index = boxes.Count; + boxes.Add(box); + BoxOccluders = boxes.ToArray(); + + HasChanged = true; + } + + public bool RemoveBoxOccluder(YmapBoxOccluder box) + { + if (box == null) return false; + var newboxes = new List(); + if (BoxOccluders != null) + { + foreach (var oldbox in BoxOccluders) + { + if (oldbox != box) + { + oldbox.Index = newboxes.Count; + newboxes.Add(oldbox); + } + } + if (newboxes.Count == BoxOccluders.Length) + { + return false;//nothing removed... wasn't present? + } + } + + BoxOccluders = newboxes.ToArray(); + + HasChanged = true; + + return true; + } + + + public void AddOccludeModel(YmapOccludeModel model) + { + if (model == null) return; + var models = new List(); + if (OccludeModels != null) models.AddRange(OccludeModels); + model.Ymap = this; + models.Add(model); + OccludeModels = models.ToArray(); + + HasChanged = true; + } + + public bool RemoveOccludeModel(YmapOccludeModel model) + { + if (model == null) return false; + var newmodels = new List(); + if (OccludeModels != null) + { + foreach (var oldmodel in OccludeModels) + { + if (oldmodel != model) + { + oldmodel.Index = newmodels.Count; + newmodels.Add(oldmodel); + } + } + if (newmodels.Count == OccludeModels.Length) + { + return false;//nothing removed... wasn't present? + } + } + + OccludeModels = newmodels.ToArray(); + + HasChanged = true; + + return true; + } + + + public void AddOccludeModelTriangle(YmapOccludeModelTriangle tri) + { + if (tri == null) return; + if (tri.Model == null) return; + + var tris = tri.Model.Triangles.ToList(); + tri.Index = tris.Count; + tris.Add(tri); + tri.Model.Triangles = tris.ToArray(); + + //tri.Model.BuildBVH(); + //... + + HasChanged = true; + } + + public bool RemoveOccludeModelTriangle(YmapOccludeModelTriangle tri) + { + if (tri == null) return false; + if (tri.Model == null) return false; + + var newtris = new List(); + if (tri.Model.Triangles != null) + { + foreach (var oldtri in tri.Model.Triangles) + { + if (oldtri != tri) + { + oldtri.Index = newtris.Count; + newtris.Add(oldtri); + } + } + } + tri.Model.Triangles = newtris.ToArray(); + //tri.Model.BuildBVH(); + //... + + HasChanged = true; + + return true; + } + + public void AddGrassBatch(YmapGrassInstanceBatch newbatch) { List batches = new List(); @@ -1197,6 +1381,10 @@ namespace CodeWalker.GameFiles { flags = SetBit(flags, 1); //2 } + if ((BoxOccluders != null) || (OccludeModels != null)) + { + contentFlags = SetBit(contentFlags, 5); //32 + } bool change = false; @@ -1329,6 +1517,29 @@ namespace CodeWalker.GameFiles smax = Vector3.Max(smax, (DistantLODLights.BBMax + 3000.0f)); } + if (BoxOccluders != null) + { + foreach (var box in BoxOccluders) + { + var siz = box.Size.Length() * 0.5f;//should really use box rotation instead.... + emin = Vector3.Min(emin, box.Position - siz); + emax = Vector3.Max(emax, box.Position + siz); + smin = Vector3.Min(smin, box.Position - siz);//check this! for some vanilla ymaps it seems right, others not + smax = Vector3.Max(smax, box.Position + siz);//occluders don't seem to have a loddist + } + } + + if (OccludeModels != null) + { + foreach (var model in OccludeModels) + { + emin = Vector3.Min(emin, (model.BVH?.Box.Minimum ?? model._OccludeModel.bmin));//this needs to be updated! + emax = Vector3.Max(emax, (model.BVH?.Box.Maximum ?? model._OccludeModel.bmax)); + smin = Vector3.Min(smin, (model.BVH?.Box.Minimum ?? model._OccludeModel.bmin));//check this! for some vanilla ymaps it seems right, others not + smax = Vector3.Max(smax, (model.BVH?.Box.Maximum ?? model._OccludeModel.bmax));//occluders don't seem to have a loddist + } + } + bool change = false; if (_CMapData.entitiesExtentsMin != emin) { @@ -2854,6 +3065,21 @@ namespace CodeWalker.GameFiles public byte[] Indices { get; set; } public int Index { get; set; } + public YmapOccludeModelTriangle[] Triangles { get; set; } + public TriangleBVH BVH { get; set; } + + public FlagsUint Flags + { + get + { + return _OccludeModel.flags; + } + set + { + _OccludeModel.flags = value; + } + } + public YmapOccludeModel(YmapFile ymap, OccludeModel model) { Ymap = ymap; @@ -2875,11 +3101,118 @@ namespace CodeWalker.GameFiles } + public void BuildTriangles() + { + if ((Vertices == null) || (Indices == null)) + { + Triangles = null; + return; + } + var tris = new List(); + for (int i = 0; i < Indices.Length; i += 3) + { + var tri = new YmapOccludeModelTriangle(this, Vertices[Indices[i]], Vertices[Indices[i+1]], Vertices[Indices[i+2]], tris.Count); + tris.Add(tri); + } + Triangles = tris.ToArray(); + } + public void BuildBVH() + { + if (Triangles == null) + { + BVH = null; + return; + } + + BVH = new TriangleBVH(Triangles); + + } + public void BuildVertices() + { + //create vertices and indices arrays from Triangles + if (Triangles == null) + { + Vertices = null; + Indices = null; + return; + } + var vdict = new Dictionary(); + var verts = new List(); + var inds = new List(); + byte ensureVert(Vector3 v) + { + if (vdict.TryGetValue(v, out byte b)) + { + return b; + } + if (verts.Count > 255) + { + return 0; + } + var i = (byte)verts.Count; + vdict[v] = i; + verts.Add(v); + return i; + } + for (int i = 0; i < Triangles.Length; i++) + { + var tri = Triangles[i]; + inds.Add(ensureVert(tri.Corner1)); + inds.Add(ensureVert(tri.Corner2)); + inds.Add(ensureVert(tri.Corner3)); + } + Vertices = verts.ToArray(); + Indices = inds.ToArray(); + } + public void BuildData() + { + //create Data from vertices and indices arrays + if (Vertices == null) return; + if (Indices == null) return; + var dlen = (Vertices.Length * 12) + (Indices.Length * 1); + var d = new byte[dlen]; + var vbytes = MetaTypes.ConvertArrayToBytes(Vertices); + var ibytes = Indices; + Buffer.BlockCopy(vbytes, 0, d, 0, vbytes.Length); + Buffer.BlockCopy(ibytes, 0, d, vbytes.Length, ibytes.Length); + Data = d; + var min = new Vector3(float.MaxValue); + var max = new Vector3(float.MinValue); + for (int i = 0; i < Vertices.Length; i++) + { + min = Vector3.Min(min, Vertices[i]); + max = Vector3.Max(max, Vertices[i]); + } + _OccludeModel.bmin = min; + _OccludeModel.bmax = max; + _OccludeModel.Unused0 = min.X; + _OccludeModel.Unused1 = max.X; + _OccludeModel.dataSize = (uint)dlen; + _OccludeModel.numVertsInBytes = (ushort)vbytes.Length; + _OccludeModel.numTris = (ushort)((ibytes.Length / 3) + 32768);//is this actually a flag lurking..? + //_OccludeModel.flags = ... + } + + public YmapOccludeModelTriangle RayIntersect(ref Ray ray, ref float hitdist) + { + if (Triangles == null) + { + BuildTriangles(); + BuildBVH(); + } + else if (BVH == null) + { + BuildBVH(); + } + if (BVH == null) return null; + return BVH.RayIntersect(ref ray, ref hitdist) as YmapOccludeModelTriangle; + } + public EditorVertex[] GetTriangleVertices() { if ((Vertices == null) || (Indices == null)) return null; EditorVertex[] res = new EditorVertex[Indices.Length];//changing from indexed to nonindexed triangle list - var colour = new Color4(1.0f, 1.0f, 1.0f, 0.2f); //todo: colours for occlude models? currently transparent white + var colour = new Color4(1.0f, 0.0f, 0.0f, 0.8f); //todo: colours for occluders? var colourval = (uint)colour.ToRgba(); for (int i = 0; i < Indices.Length; i++) { @@ -2888,7 +3221,6 @@ namespace CodeWalker.GameFiles } return res; } - public EditorVertex[] GetPathVertices() { return null; @@ -2897,10 +3229,32 @@ namespace CodeWalker.GameFiles { return null; } + + public override string ToString() + { + return Index.ToString() + ": " + (Vertices?.Length ?? 0).ToString() + " vertices, " + (Triangles?.Length ?? 0).ToString() + " triangles"; + } } [TypeConverter(typeof(ExpandableObjectConverter))] - public class YmapBoxOccluder + public class YmapOccludeModelTriangle : TriangleBVHItem + { + public YmapOccludeModel Model { get; set; } + public YmapFile Ymap { get { return Model?.Ymap; } } + public int Index { get; set; } + + public YmapOccludeModelTriangle(YmapOccludeModel model, Vector3 v1, Vector3 v2, Vector3 v3, int i) + { + Model = model; + Corner1 = v1; + Corner2 = v2; + Corner3 = v3; + Index = i; + } + } + + [TypeConverter(typeof(ExpandableObjectConverter))] + public class YmapBoxOccluder : BasePathData { public BoxOccluder _Box; public BoxOccluder Box { get { return _Box; } set { _Box = value; } } @@ -2916,6 +3270,7 @@ namespace CodeWalker.GameFiles public int Index { get; set; } + public YmapBoxOccluder(YmapFile ymap, BoxOccluder box) { Ymap = ymap; @@ -2934,6 +3289,68 @@ namespace CodeWalker.GameFiles } + public void UpdateBoxStruct() + { + _Box.iCenterX = (short)Math.Round(Position.X * 4.0f); + _Box.iCenterY = (short)Math.Round(Position.Y * 4.0f); + _Box.iCenterZ = (short)Math.Round(Position.Z * 4.0f); + _Box.iLength = (short)Math.Round(Size.X * 4.0f); + _Box.iWidth = (short)Math.Round(Size.Y * 4.0f); + _Box.iHeight = (short)Math.Round(Size.Z * 4.0f); + + var dir = Orientation.Multiply(Vector3.UnitX) * 0.5f; + _Box.iSinZ = (short)Math.Round(dir.X * 32767.0f); + _Box.iCosZ = (short)Math.Round(dir.Y * 32767.0f); + } + + + public void SetSize(Vector3 s) + { + Size = s; + BBMin = Size * -0.5f; + BBMax = Size * 0.5f; + } + + + public EditorVertex[] GetTriangleVertices() + { + Vector3 xform(float x, float y, float z) + { + return Orientation.Multiply(new Vector3(x, y, z)) + Position; + } + EditorVertex[] res = new EditorVertex[36]; + var colour = new Color4(0.0f, 0.0f, 1.0f, 0.8f); //todo: colours for occluders? + var c = (uint)colour.ToRgba(); + var s = Size * 0.5f; + var v0 = new EditorVertex() { Position = xform(-s.X, -s.Y, -s.Z), Colour = c }; + var v1 = new EditorVertex() { Position = xform(-s.X, -s.Y, +s.Z), Colour = c }; + var v2 = new EditorVertex() { Position = xform(-s.X, +s.Y, -s.Z), Colour = c }; + var v3 = new EditorVertex() { Position = xform(-s.X, +s.Y, +s.Z), Colour = c }; + var v4 = new EditorVertex() { Position = xform(+s.X, -s.Y, -s.Z), Colour = c }; + var v5 = new EditorVertex() { Position = xform(+s.X, -s.Y, +s.Z), Colour = c }; + var v6 = new EditorVertex() { Position = xform(+s.X, +s.Y, -s.Z), Colour = c }; + var v7 = new EditorVertex() { Position = xform(+s.X, +s.Y, +s.Z), Colour = c }; + res[00] = v0; res[01] = v1; res[02] = v2; res[03] = v2; res[04] = v1; res[05] = v3; + res[06] = v2; res[07] = v3; res[08] = v6; res[09] = v6; res[10] = v3; res[11] = v7; + res[12] = v1; res[13] = v5; res[14] = v3; res[15] = v3; res[16] = v5; res[17] = v7; + res[18] = v6; res[19] = v7; res[20] = v4; res[21] = v4; res[22] = v7; res[23] = v5; + res[24] = v4; res[25] = v5; res[26] = v0; res[27] = v0; res[28] = v5; res[29] = v1; + res[30] = v2; res[31] = v6; res[32] = v0; res[33] = v0; res[34] = v6; res[35] = v4; + return res; + } + public EditorVertex[] GetPathVertices() + { + return null; + } + public Vector4[] GetNodePositions() + { + return null; + } + + public override string ToString() + { + return Index.ToString() + ": " + FloatUtil.GetVector3String(Position); + } } } diff --git a/CodeWalker.Core/Utils/TriangleBVH.cs b/CodeWalker.Core/Utils/TriangleBVH.cs new file mode 100644 index 0000000..ef80a19 --- /dev/null +++ b/CodeWalker.Core/Utils/TriangleBVH.cs @@ -0,0 +1,218 @@ +using SharpDX; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CodeWalker +{ + public class TriangleBVH : TriangleBVHNode + { + + public TriangleBVH(TriangleBVHItem[] tris, int depth = 8) + { + if (tris == null) return; + var min = new Vector3(float.MaxValue); + var max = new Vector3(float.MinValue); + for (int i = 0; i < tris.Length; i++) + { + var tri = tris[i]; + tri.UpdateBox(); + min = Vector3.Min(min, tri.Box.Minimum); + max = Vector3.Max(max, tri.Box.Maximum); + } + Box = new BoundingBox(min, max); + + Build(tris, depth); + + } + } + + public class TriangleBVHNode + { + public TriangleBVHItem[] Triangles { get; set; } + public TriangleBVHNode Node1 { get; set; } + public TriangleBVHNode Node2 { get; set; } + public BoundingBox Box { get; set; } + + public void Build(TriangleBVHItem[] tris, int depth) + { + if (tris.Length <= 10) depth = 0; + if (depth <= 0) + { + Triangles = tris; + Node1 = null; + Node2 = null; + } + else + { + var min = Box.Minimum; + var max = Box.Maximum; + var cen = Box.Center; + var siz = Box.Size; + BoundingBox b1, b2; + if ((siz.X >= siz.Y) && (siz.X >= siz.Z)) + { + b1 = new BoundingBox(min, new Vector3(cen.X, max.Y, max.Z)); + b2 = new BoundingBox(new Vector3(cen.X, min.Y, min.Z), max); + } + else if (siz.Y >= siz.Z) + { + b1 = new BoundingBox(min, new Vector3(max.X, cen.Y, max.Z)); + b2 = new BoundingBox(new Vector3(min.X, cen.Y, min.Z), max); + } + else + { + b1 = new BoundingBox(min, new Vector3(max.X, max.Y, cen.Z)); + b2 = new BoundingBox(new Vector3(min.X, min.Y, cen.Z), max); + } + var l1 = new List(); + var l2 = new List(); + for (int i = 0; i < tris.Length; i++) + { + var tri = tris[i]; + if (tri.Box.Contains(b1) != ContainmentType.Disjoint)// (tri.Box.Intersects(b1)) + { + l1.Add(tri); + } + if (tri.Box.Contains(b2) != ContainmentType.Disjoint)// (tri.Box.Intersects(b2)) + { + l2.Add(tri); + } + } + if (l1.Count > 0) + { + Node1 = new TriangleBVHNode(); + Node1.Box = b1; + Node1.Build(l1.ToArray(), depth - 1); + } + if (l2.Count > 0) + { + Node2 = new TriangleBVHNode(); + Node2.Box = b2; + Node2.Build(l2.ToArray(), depth - 1); + } + } + } + + + public TriangleBVHItem RayIntersect(ref Ray ray, ref float hitdist) + { + if (ray.Intersects(Box) == false) return null; + + TriangleBVHItem hit = null; + if (Triangles != null) + { + for (int i = 0; i < Triangles.Length; i++) + { + var tri = Triangles[i]; + var v1 = tri.Corner1; + var v2 = tri.Corner2; + var v3 = tri.Corner3; + if (ray.Intersects(ref v1, ref v2, ref v3, out float d) && (d < hitdist) && (d > 0)) + { + hitdist = d; + hit = tri; + } + } + } + if (Node1 != null) + { + var hd = hitdist; + var h = Node1.RayIntersect(ref ray, ref hd); + if ((h != null) && (hd < hitdist)) + { + hitdist = hd; + hit = h; + } + } + if (Node2 != null) + { + var hd = hitdist; + var h = Node2.RayIntersect(ref ray, ref hd); + if ((h != null) && (hd < hitdist)) + { + hitdist = hd; + hit = h; + } + } + + return hit; + } + + } + + public abstract class TriangleBVHItem + { + public Vector3 Corner1 { get; set; } + public Vector3 Corner2 { get; set; } + public Vector3 Corner3 { get; set; } + public BoundingBox Box { get; set; } + + public Vector3 Center + { + get + { + return (Corner1 + Corner2 + Corner3) * 0.3333333f; + } + set + { + var delta = value - Center; + Corner1 += delta; + Corner2 += delta; + Corner3 += delta; + } + } + public Quaternion Orientation + { + get + { + return _Orientation; + } + set + { + var inv = Quaternion.Invert(_Orientation); + var delta = value * inv; + var cen = Center; + Corner1 = cen + delta.Multiply(Corner1 - cen); + Corner2 = cen + delta.Multiply(Corner2 - cen); + Corner3 = cen + delta.Multiply(Corner3 - cen); + _Orientation = value; + } + } + private Quaternion _Orientation = Quaternion.Identity; + public Vector3 Scale + { + get + { + return _Scale; + } + set + { + var inv = Quaternion.Invert(_Orientation); + var delta = value / _Scale; + var cen = Center; + Corner1 = cen + _Orientation.Multiply(inv.Multiply(Corner1 - cen) * delta); + Corner2 = cen + _Orientation.Multiply(inv.Multiply(Corner2 - cen) * delta); + Corner3 = cen + _Orientation.Multiply(inv.Multiply(Corner3 - cen) * delta); + _Scale = value; + } + } + private Vector3 _Scale = Vector3.One; + + public void UpdateBox() + { + var min = new Vector3(float.MaxValue); + var max = new Vector3(float.MinValue); + min = Vector3.Min(min, Corner1); + min = Vector3.Min(min, Corner2); + min = Vector3.Min(min, Corner3); + max = Vector3.Max(max, Corner1); + max = Vector3.Max(max, Corner2); + max = Vector3.Max(max, Corner3); + Box = new BoundingBox(min, max); + } + + + } + +} diff --git a/CodeWalker/Project/Panels/EditYmapBoxOccluderPanel.Designer.cs b/CodeWalker/Project/Panels/EditYmapBoxOccluderPanel.Designer.cs new file mode 100644 index 0000000..b2372dd --- /dev/null +++ b/CodeWalker/Project/Panels/EditYmapBoxOccluderPanel.Designer.cs @@ -0,0 +1,166 @@ + +namespace CodeWalker.Project.Panels +{ + partial class EditYmapBoxOccluderPanel + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(EditYmapBoxOccluderPanel)); + this.GoToButton = new System.Windows.Forms.Button(); + this.CenterTextBox = new System.Windows.Forms.TextBox(); + this.label31 = new System.Windows.Forms.Label(); + this.DeleteButton = new System.Windows.Forms.Button(); + this.AddToProjectButton = new System.Windows.Forms.Button(); + this.SizeTextBox = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.SinCosZTextBox = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // GoToButton + // + this.GoToButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.GoToButton.Location = new System.Drawing.Point(478, 6); + this.GoToButton.Name = "GoToButton"; + this.GoToButton.Size = new System.Drawing.Size(68, 23); + this.GoToButton.TabIndex = 87; + this.GoToButton.Text = "Go to"; + this.GoToButton.UseVisualStyleBackColor = true; + this.GoToButton.Click += new System.EventHandler(this.GoToButton_Click); + // + // CenterTextBox + // + this.CenterTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.CenterTextBox.Location = new System.Drawing.Point(82, 8); + this.CenterTextBox.Name = "CenterTextBox"; + this.CenterTextBox.Size = new System.Drawing.Size(390, 20); + this.CenterTextBox.TabIndex = 86; + this.CenterTextBox.TextChanged += new System.EventHandler(this.CenterTextBox_TextChanged); + // + // label31 + // + this.label31.AutoSize = true; + this.label31.Location = new System.Drawing.Point(4, 11); + this.label31.Name = "label31"; + this.label31.Size = new System.Drawing.Size(41, 13); + this.label31.TabIndex = 85; + this.label31.Text = "Center:"; + // + // DeleteButton + // + this.DeleteButton.Location = new System.Drawing.Point(183, 95); + this.DeleteButton.Name = "DeleteButton"; + this.DeleteButton.Size = new System.Drawing.Size(95, 23); + this.DeleteButton.TabIndex = 107; + this.DeleteButton.Text = "Delete Box"; + this.DeleteButton.UseVisualStyleBackColor = true; + this.DeleteButton.Click += new System.EventHandler(this.DeleteButton_Click); + // + // AddToProjectButton + // + this.AddToProjectButton.Location = new System.Drawing.Point(82, 95); + this.AddToProjectButton.Name = "AddToProjectButton"; + this.AddToProjectButton.Size = new System.Drawing.Size(95, 23); + this.AddToProjectButton.TabIndex = 106; + this.AddToProjectButton.Text = "Add to Project"; + this.AddToProjectButton.UseVisualStyleBackColor = true; + this.AddToProjectButton.Click += new System.EventHandler(this.AddToProjectButton_Click); + // + // SizeTextBox + // + this.SizeTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.SizeTextBox.Location = new System.Drawing.Point(82, 34); + this.SizeTextBox.Name = "SizeTextBox"; + this.SizeTextBox.Size = new System.Drawing.Size(390, 20); + this.SizeTextBox.TabIndex = 109; + this.SizeTextBox.TextChanged += new System.EventHandler(this.SizeTextBox_TextChanged); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(4, 37); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(30, 13); + this.label1.TabIndex = 108; + this.label1.Text = "Size:"; + // + // SinCosZTextBox + // + this.SinCosZTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.SinCosZTextBox.Location = new System.Drawing.Point(82, 60); + this.SinCosZTextBox.Name = "SinCosZTextBox"; + this.SinCosZTextBox.Size = new System.Drawing.Size(390, 20); + this.SinCosZTextBox.TabIndex = 111; + this.SinCosZTextBox.TextChanged += new System.EventHandler(this.SinCosZTextBox_TextChanged); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(4, 63); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(56, 13); + this.label2.TabIndex = 110; + this.label2.Text = "Sin,Cos Z:"; + // + // EditYmapBoxOccluderPanel + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(553, 407); + this.Controls.Add(this.SinCosZTextBox); + this.Controls.Add(this.label2); + this.Controls.Add(this.SizeTextBox); + this.Controls.Add(this.label1); + this.Controls.Add(this.DeleteButton); + this.Controls.Add(this.AddToProjectButton); + this.Controls.Add(this.GoToButton); + this.Controls.Add(this.CenterTextBox); + this.Controls.Add(this.label31); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "EditYmapBoxOccluderPanel"; + this.Text = "Box Occluder"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button GoToButton; + private System.Windows.Forms.TextBox CenterTextBox; + private System.Windows.Forms.Label label31; + private System.Windows.Forms.Button DeleteButton; + private System.Windows.Forms.Button AddToProjectButton; + private System.Windows.Forms.TextBox SizeTextBox; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox SinCosZTextBox; + private System.Windows.Forms.Label label2; + } +} \ No newline at end of file diff --git a/CodeWalker/Project/Panels/EditYmapBoxOccluderPanel.cs b/CodeWalker/Project/Panels/EditYmapBoxOccluderPanel.cs new file mode 100644 index 0000000..22c45cd --- /dev/null +++ b/CodeWalker/Project/Panels/EditYmapBoxOccluderPanel.cs @@ -0,0 +1,162 @@ +using CodeWalker.GameFiles; +using SharpDX; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CodeWalker.Project.Panels +{ + public partial class EditYmapBoxOccluderPanel : ProjectPanel + { + public ProjectForm ProjectForm; + public YmapBoxOccluder CurrentBoxOccluder { get; set; } + + private bool populatingui = false; + + + public EditYmapBoxOccluderPanel(ProjectForm owner) + { + ProjectForm = owner; + InitializeComponent(); + } + + + public void SetBoxOccluder(YmapBoxOccluder box) + { + CurrentBoxOccluder = box; + Tag = box; + LoadBoxOccluder(); + UpdateFormTitle(); + } + + private void UpdateFormTitle() + { + Text = "BoxOccluder: " + (CurrentBoxOccluder?.Index.ToString() ?? "(none)"); + } + + + private void LoadBoxOccluder() + { + + if (CurrentBoxOccluder == null) + { + ////Panel.Enabled = false; + AddToProjectButton.Enabled = false; + DeleteButton.Enabled = false; + CenterTextBox.Text = string.Empty; + SizeTextBox.Text = string.Empty; + SinCosZTextBox.Text = string.Empty; + } + else + { + populatingui = true; + var b = CurrentBoxOccluder; + ////Panel.Enabled = true; + AddToProjectButton.Enabled = !ProjectForm.YmapExistsInProject(CurrentBoxOccluder.Ymap); + DeleteButton.Enabled = !AddToProjectButton.Enabled; + CenterTextBox.Text = FloatUtil.GetVector3String(b.Position); + SizeTextBox.Text = FloatUtil.GetVector3String(b.Size); + var dir = b.Orientation.Multiply(Vector3.UnitX) * 0.5f; + SinCosZTextBox.Text = FloatUtil.GetVector2String(new Vector2(dir.X, dir.Y)); + populatingui = false; + + if (ProjectForm.WorldForm != null) + { + ProjectForm.WorldForm.SelectObject(CurrentBoxOccluder); + } + + } + } + + private void UpdateGraphics() + { + if (CurrentBoxOccluder == null) return; + if (ProjectForm?.WorldForm == null) return; + + ProjectForm.WorldForm.UpdateBoxOccluderGraphics(CurrentBoxOccluder); + } + + private void GoToButton_Click(object sender, EventArgs e) + { + if (CurrentBoxOccluder == null) return; + if (ProjectForm?.WorldForm == null) return; + ProjectForm.WorldForm.GoToPosition(CurrentBoxOccluder.Position, CurrentBoxOccluder.Size * 2.0f); + } + + private void AddToProjectButton_Click(object sender, EventArgs e) + { + if (CurrentBoxOccluder == null) return; + if (ProjectForm == null) return; + ProjectForm.SetProjectItem(CurrentBoxOccluder); + ProjectForm.AddBoxOccluderToProject(); + } + + private void DeleteButton_Click(object sender, EventArgs e) + { + ProjectForm.SetProjectItem(CurrentBoxOccluder); + ProjectForm.DeleteBoxOccluder(); + } + + private void CenterTextBox_TextChanged(object sender, EventArgs e) + { + if (populatingui) return; + if (CurrentBoxOccluder == null) return; + var v = FloatUtil.ParseVector3String(CenterTextBox.Text); + lock (ProjectForm.ProjectSyncRoot) + { + if (CurrentBoxOccluder.Position != v) + { + CurrentBoxOccluder.Position = v; + UpdateGraphics(); + ProjectForm.SetYmapHasChanged(true); + ProjectForm.WorldForm?.SetWidgetPosition(v); + } + } + + ProjectForm.ProjectExplorer?.UpdateBoxOccluderTreeNode(CurrentBoxOccluder); + + } + + private void SizeTextBox_TextChanged(object sender, EventArgs e) + { + if (populatingui) return; + if (CurrentBoxOccluder == null) return; + var v = FloatUtil.ParseVector3String(SizeTextBox.Text); + lock (ProjectForm.ProjectSyncRoot) + { + if (CurrentBoxOccluder.Size != v) + { + CurrentBoxOccluder.SetSize(v); + UpdateGraphics(); + ProjectForm.SetYmapHasChanged(true); + ProjectForm.WorldForm?.SetWidgetScale(v); + } + } + } + + private void SinCosZTextBox_TextChanged(object sender, EventArgs e) + { + if (populatingui) return; + if (CurrentBoxOccluder == null) return; + var v = FloatUtil.ParseVector2String(SinCosZTextBox.Text); + float angl = (float)Math.Atan2(v.Y, v.X); + var q = Quaternion.RotationYawPitchRoll(0.0f, 0.0f, angl); + lock (ProjectForm.ProjectSyncRoot) + { + if (CurrentBoxOccluder.Orientation != q) + { + CurrentBoxOccluder.Orientation = q; + UpdateGraphics(); + ProjectForm.SetYmapHasChanged(true); + ProjectForm.WorldForm?.SetWidgetRotation(q); + } + } + } + } +} diff --git a/CodeWalker/Project/Panels/EditYmapBoxOccluderPanel.resx b/CodeWalker/Project/Panels/EditYmapBoxOccluderPanel.resx new file mode 100644 index 0000000..0960cbe --- /dev/null +++ b/CodeWalker/Project/Panels/EditYmapBoxOccluderPanel.resx @@ -0,0 +1,409 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAMAICAAAAAAGACoDAAANgAAABAQAAAAABgAaAMAAN4MAABAQAAAAAAYACgyAABGEAAAKAAAACAA + AABAAAAAAQAYAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////v8/u3v+Pn6//7+//////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //7+/vX3/rzA3OHl9fz9//////////////////////////////////////////////////////////// + //////////////////////////////////////////////////7//+zv+3Z6qcLI5Pr7//////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////7+/+br+15in6+33vf5//////////////////7+//7+//////////////////// + //////////////////////////////3+//v8//v8//3+//////////////////////7+/+Ho+1dana20 + 4/b4//////////z9//P2/+Tp/ezw/vz9//////////////////////////////////////////7///X4 + /9Pa+tPa+/H1//z9//////////////////7+/93k+SsscaSr3PX3//////7+//L1/7W98AcWgrvC8Pj6 + //////////////////////////////////////////7+/+bs/xohiAEJdrvF9+7y//z9//////////// + //7+/9rh+CEkapmh0/T3//////j6/9HZ/AEHcgEEb9LZ+/r7//////////////////////////////// + //////////7//+/z/3F+zAAAXwQLcZai3fb4//////////////3+/97l/E9Tmaau4fT3/////+/0/1dd + sAAAV7a/8/H1//7+//////////////////////////////////////////////r8/+jv/46Y3QUUf6Ot + 5PX4//////////////3+/9zj+3Z6wLe/7fX4//////D0/212xnaAzerw//z9//////////////////// + //////////////////////////////////v8/+/z/+Dm+/D0//z9//////////7+//j6/9Pd+UhLjb/H + 9/D0//3+//n7/+nt/+jt//n7//////////////////////////////////////////////////////// + //7///7+//7+//7+//////////r8/+7z/83W+ImU2A0UdFNarr/K9env//X4//z9//3+//7///////// + //////////////////////////////////////////////////////////////////7///j6/+Pq/255 + xhckjE5XsVVftUlTqwAKeTA9nr3H8+7z//v8//////////////////////////////////////////// + //////////////////////////////7+//b4/9Tc+Sc0mRonj8rV/crX/ZSb48rX/brG8wwWgQAEdJei + 4efu//n7//7+//z9//z9//z9//z9//3+//////////////////////////////3+//f5/+3y/+nv/+ft + /8vV+io2mImU2M7c/7vG9yIvlQAOfCg4mM3Y/s/c/4aR1AQRfGtzwtni/ebt/9vi/tri/tXd+9Tc+O3x + /vz9//////////////////////////n6/87V+FVftkRPrFlnvSEqjQoUfmJvwWFvvg0TfQQIcxEchwAD + cy89n19rvVVitQwZgwAAaiMrkT9NqTVBoiw3mhQihig1mNLX+fv8//////////////////////////b5 + /52l4EFLqoCK03yF0VBctGhyw52o5GVrvQAAaneBzsHM+jA3mhYgiTtIpJOf3ouW2AAAbmh0wbbA8bS+ + 7qiz5pCb16+56e/z//3+//////////////////////////v8//H1/+vw/+zx/+nv/7/J9YqP3MbP/8LM + +hwqkFZftaCp5EhRrcTQ+9jj/8rW/UJMqn6J0ebt//X3//f5//b4//X3//f5//z9//////////////// + //////////7+//z9//3+//////////3+/+7z/6at64iP3aWs7XN8zRIfhyUykp2o5MHM+oKM0xonjY6X + 2+jv//v8//////7+//n7//b5//r7//7///////////////////7+//f5/+rw/9Pa9fL0/v7///////// + //v8//H1/+Tr/7i/91liu0NPq0VQrS06m0NNqDdCoYqU1+nv//v8//////////n7/9zi/qSt59ri/fL1 + //v8//7///////z9//D0/8rT+h0sjkVQrPD0//////////////////////z9/+7z/8LL9Jqk4aGq6LW/ + 8c3W9+Xs/vH1//v8//////////////f5/6at5gAAbxIfh6u16+Po/fr7//////b5/6ev5gAIeAAPernC + 8fX4//////////3+//v8//z9//////3+//j6//P3//P2//b4//r8//7+//7+//v8//r8//3+//////v8 + /+Xr/nuIzwAAbBseg5Sb2fb5//////f5/8DF8pWe3d/n/vT3//39//////v8/+zx/87V9+3x/v3+//// + //3+//j6//X4//v8//////////n7/+Dm/snR9fD0//39//z8/fv8/+3y/8LK9aGq4dfd9/n7//////z9 + //b5//X4//v8//////////7+/+7z/4aP1gEPet7k/f39//////f5/83U+ZCZ2u3x/v7+//////P3/215 + wgAJd7fB8/L1//7+//////3+//j6//f5//r8//7+//////////////////////////////j6/87W/AAA + X2duue3y//7+//////D0/05asBQfidzj/P39//////X4/6Su6AAAXBccgtff/vv8//////////////// + //////////////////////////////////////P3/3F8xhYli9Xe/fn6/////////+3y/1pltQAJd9be + /fv8//////z9/+rw/36I0Bknjs/W+vv8//////////////////////////////////////////////// + //////f5/8HI7tnf+/X4//7+/////////+/0/3R7xgAAb9ng/Pz9//////////n7/+Ln/dLY+fP2//3+ + //////////////////////////////////////////////////////3+//r7//v8//7+//////////// + //b4/7/F84eP0e/0//7+//////////7+//z9//v8//3+//////////////////////////////////// + //////////////////////////////////////////////////z9//b5//X4//v8//////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////w////4 + P///+D////g8//D4MH/geCB/4Dggf+A4IH/wOCD/+DAB//hgAf//gAP//wAAB/AAAAPwAAAD8AAAA/AA + AAfjAAEHgYADAQPgBwEDEAEBAghgAQwIIEH8CCB//Bggf/wYMH/8ODD///h/////////////KAAAABAA + AAAgAAAAAQAYAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///+vv/fL1/v///wAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///4+Vx7/F5v///wAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAP///4CHtrS62////////////////////wAAAAAAAAAAAP////H0/vf6/v// + /////////4yTwrrB4f///+zw+7rA6P39/////wAAAAAAAAAAAP///56l2BkcguXr/P///////42Uw8jO + 6P///ysvjWVqtP///////wAAAAAAAAAAAP////D0/0hPpsDG6////////6y02d7k8////3qAx+/z/f// + /wAAAAAAAAAAAAAAAAAAAP///////////////8zT8V5ns1Rcrdzh9f///////////wAAAAAAAAAAAAAA + AAAAAP////////7+/6ix3nmBxFthtmdwu09WqbC54/v9//r8//j6//39/wAAAAAAAAAAAOjt/H6I0FJc + skpSqHF+wRMahFZhs4iT1AsNc1pgrm52v2RsuO/z/gAAAP////////L2/cLJ7rrD64+V4DY+ozU+mYmU + 0X2Hy1hfss7V8urv/PP2/v///wAAAP///+Pp+d/k9////////+Pp/4uR3ysymW14xYOM0fD0/P///+Xq + +ri/6Pj6/wAAAOrv/j5DnbS75P////////////X4/+/0/ubr+/r7/////////9rh+hgZhKGo2QAAAPDz + /eLn+f////j6/2Nqttrg9////+Hn+P3+//3+/1hescLJ6/////L2/eru/AAAAAAAAAAAAP///8rR70tR + p/3+//v8/zY6jNPY7////09WqWpwu////wAAAAAAAAAAAAAAAAAAAAAAAPb4/vr7//////v8/5Wd1eHm + +P////v8//T3/wAAAAAAAAAAAAAAAP//AAD8PwAA/D8AAPwDAACAAwAAgAMAAIAHAADABwAAwAEAAMAB + AAAAAQAAAAEAAAABAAAAAQAAwAcAAOAPAAAoAAAAQAAAAIAAAAABABgAAAAAAAAwAAAAAAAAAAAAAAAA + AAAAAAAA//////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////v7//f7//P3//P3//P3/ + /f7//v7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v7//P3/ + +fv/+fv/+Pr/+fv/+vv//P3//v////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////f7/+fr/8/b/7PL/5+3/6e/+9Pf/+vv//v7///////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////P3/9/r/6O7/cXe1UVaet7z17fL/+Pr//f3///////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////+/z/9Pj/4Oj/NzyCUlOd2dz/6O//9Pf//P3///// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////+vv/8vb/2+P9X2OmREGLnqPd + 4+v/8vb/+/z///////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////+vv/8fb/ + 1N35bXK1JSRtbHGz5O7/8fX/+/z///////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////+vv/8PX/3Ob/U1eaDwtXjZLT4+z/8fX/+/z///////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////+vv/8fb/2eP+MjR6AAA+c3i34Or/8fX/+/z///////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////+vv/8vb/1d/7MS91AAA1UFSS4On/8vb/+/z///// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////+vv/8fb/2OL+NjZ7AAArX2Ok + 4uz/8fX/+/z///////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////+vv/8fb/ + 2eP/LjJ1DAxKfYTE4Or/8fX/+/z//////////////////////////////v7//v7//f7//f7//v7//v// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////+vv/8PX/3OX/gILIR0eVeoHC3eb/8fX/+/z//////////////////////v7//P3/+fv/+Pr/ + +Pr/+Pr/+vv//P3//v7///////////////////////////////////////////////////////////// + /////////////////////////////v7//f7//P3/+vv/+vv/+/z//f3//v7///////////////////// + ////////////////////////+vv/8PX/2eP9ZWeqHx1obnOz4Or/8fX/+/z//////////////////v7/ + +/z/9fj/8vb/8PX/7vT/8fb/9fj/+fr//f7///////////////////////////////////////////// + /////////////////////////////////////////v///P3/+Pr/9fj/9fj/9Pj/9Pf/9vn/+/z//v7/ + ////////////////////////////////////////+vv/8fb/2eP9ODp9AAA5jZDQ5O7/8PX/+/z///// + /////////v7/+/z/9Pf/7fP/5u//wsz6j5XfuMDx7fL/9vn//P3///////////////////////////// + /////////////////////////////////////////////////////////f7/+Pr/8/b/5+3/2eH/2uP/ + 5u3/7fP/8/b/+vv//f7/////////////////////////////////////+vv/8PX/3ef/U1ebBgVKio/O + 4uz/8fX/+/z//////////v///P3/9fj/7fP/4uv/hIzZHSWPAABmU1i14ub/9/r/+/z///////////// + /////////////////////////////////////////////////////////////////////////P3/9Pf/ + 7/X/09z/TlSzNzWYj5bh5O7/6/L/8vb/+fv//f7/////////////////////////////////+vv/8fX/ + 2eP/QUWIEhBZbnSz3uj/8fb/+/z//////////f7/+Pr/7/T/6PH/iI7cAABvAABqAABncXjK6O//9fj/ + +/z///////////////////////////////////////////////////////////////////////////// + ////////+/z/8/f/2uD/Z27EAABnAABiBgl4jJTd5vD/6O//8vX/+fv//f7///////////////////// + ////////+vv/8fb/2OP/Mjd6AQE6ZGup4er/8fX/+/z/////////+vz/8fX/6/T/xM/8ExyJAABwAABu + GySRxc387fT/9ff//P3///////////////////////////////////////////////////////////// + ////////////////////////+vz/8/f/1Nr/MzqhAABhAxOBAARyBgp5jpLg5Oz/7PP/9Pf/+vz//v7/ + ////////////////////////+vv/8fb/2eP/KCtvBwZOjJHS4Or/8fX/+/z//////f7/9/n/7fP/3+j/ + UFq3AABtAAZ3BAh6mZ/n5vD/7vP/+Pr//v7///////////////////////////////////////////// + ////////////////////////////////////////+/z/9Pj/6e//sbb1KzWcAABwBhaBAAFyAgp6fITR + 1d777/T/+Pr//f7/////////////////////////+vv/8PX/3+j/WF2hBglTnaTj5O3/8PX/+/z///// + /P3/9Pf/6vL/k5riAAByAAR0AABrY2vE4ur/6vH/9ff//P3///////////////////////////////// + /////////////////////////////////////////////////////////f3/9/n/7fL/5O3/ytX/RU6w + AABpAA5+AABuAABnhord6e7/+fv//f7/////////////////////////+vv/7/T/3+j/k5jbT1KdgYjJ + 3uf+8fX/+/z/////+/z/9fn/4ef/NDqhAABnAABrJjCU0Nn/5/D/8fX/+vv//v7///////////////// + /////////////////////////////////////////////////////////////////////////v7/+/z/ + 9vn/7vP/6vP/ztb/O0CmAABpAABrQkuoxMn57PH/+Pr//f7/////////////////////////+vv/8PX/ + 2+X/en/CUFGak5nY3+j/8fX//P3//////P3/9fj/4en/i5DbNT2hIyuTpqzv4uz/7vP/9/n//f7///// + //////////////////////////////////////////////////////////////////////////////// + /////////////v7//P3/9vn/7/P/6vL/ytH/X2i9XWi7wsf/6e//8/f/+Pr//v7///////////////// + ////////+vv/8PX/3OX/WF2hW1ylvMD+3uf/8PX/+/z//////f7/9vn/7fP/4uj/j5Pgf4LV3+X/6fD/ + 9Pf//P3///////////////////////////////////////////////////////////////////////// + /////////////////////////////////v///P3/+Pr/8vX/7fP/5+//5u7/6vD/8PT/9vn//P3//v7/ + /////////////////////f7/9/n/7fP/0tz9LDJzNjh/nqTk2uT/7fL/9/n//f7//f7/+fv/8/b/7PL/ + 3eX/zM//5ev/9fj/+fv//v7///////////////////////////////////////////////////////// + /////////////////////////////////////////////////////v///f3/+vv/9/n/9vn/9fj/9vn/ + +fr//P3//v7//////////////v///f7/+vv/9vn/7/T/5vD/2Ob/VFubERNdoajk4u//5O7/7vP/9vj/ + +fr/+vv/+Pr/9fj/9Pj/9fj/9fj/+Pr//P3///////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v///v7/ + /f7//P3//P3//f3//v7//v///////////////f7/+vz/9vn/8fX/7vT/5O3/3eb/z9n/cHjICxN5d37L + z9n/2eP/5O3/6/L/8PT/9Pf/9/n/+vv/+vv/+/z//P3//f3//v7///////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////P3/+Pr/8/b/7vT/6vL/z9r+jZjeQUeq + IiuQCBN3AAFrBRB8Nj2iUViym6XlydH/4+z/6/L/8PT/9/n/+/z//f7//v////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////f3/9/n/8fX/6/L/3uf/ + mKTkLzibAABoAAB0Fx+HDBh7FSGDAg16AABYAABlCBB/Ji2UhYza1+D/6PL/7fL/9Pf/+vv//f7///// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////v7//P3/9/n/ + 8PT/7PT/z9j/XmO+AABtAABcMDSXoajsu8X7VV+5hYzblZ/fTVSxFSKMAABkAABnAAN2Qkmpsbrz5e3/ + 6vH/8fX/+Pr//P3//v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////P3/9/n/8PX/7PT/vcn3LTOZAABaAgR1ZWzD0Nf/5vL/1OP/l53lzs3/6fP/4+7/sLzwZ23CBxSD + AABnAABlHiaSmqHo3+j/5+//7/T/9vn//P3//v7///////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////v7/ + /v7//v7//v7//f7/+/z/9vj/7vP/7PX/tcLzEBeGAABkPEWlqLPt2eX/4e7/3On/uMX1gofVe3vPhYzY + z93+5/X/4e3/lJ3gHiOPAABtAABqChiEbHLIytD/5/D/7PL/8/f/+Pr/+fr/+Pr/+Pr/+Pr/+Pr/+Pr/ + +Pr/+fv/+vv/+/z//f7//v7///////////////////////////////////////////////////////// + /v7//f7/+/z/+fv/9/n/9vj/9fj/9Pf/8fX/7PL/4uv/l6HgDhF7AAN4iZDe0d7/3uz/4vD/w83/VVm3 + ICiSAAFyAABlAABwaHTD1N//2un/3er/w838ZW3BEyOJJzKVAQ16NDmfwsn75fD/5u7/7PL/7vP/7fP/ + 7fP/7fL/7fP/7vP/7/T/8fb/9Pj/9vn/+fr//f3//v////////////////////////////////////// + /////////////v7//P3/+Pr/9Pf/8fX/7vT/7PL/6/L/6fH/5u7/6vX/tsD0CQx4AAFwkZvi7ff/4vD/ + 4fD/z9j/OkGlAABiAABwBxWAAAt7BBN+P0uofYLUztb/4O7/6fb/6fP/qa7xQkyoBg56AABqMjugx8/+ + 5fH/4Ov/4On/3uj/3eb/3+j/3uj/1+L/0d3/1d7/3+f/7fL/9vj/+vz//v7///////////////////// + /////////////////////////////f7/+fr/8/f/6/L/2d//v8j6vcf5ucP1wMv8wM3+vMj6PkqoAABo + UF25usP7tsPyvsr6sLrwQ0utAABqAAV1OUameIDRKDWZAAd2GyeOLDecmaHntsL0pbLom6riq7LzUlu0 + AANzBhR/AAZ0NT+ja3bBY2i/XGG6UViyWl65XGG7XGC6TVWvQU6pPkalODygqK7p8vb/+vz//v7///// + /////////////////////////////////////////////P3/9/n/7/T/wcj2R0ysExeFERmGDxuIFB6K + FBqICxSEAABsAAByDBiDCRSBBRCADhaFCRODAAh4AxF/AAl4CxeDHSaPAAp6AAN0AA19AAd3CBOBEBqH + BhGBAAh5AABwAAByAAh5BhSCAxWCAABsAABvAABlAABnAABxAABjAABmAABhAABdAABYAABhCAt/q7Lr + 8/f/+vv//v7//////////////////////////////////////////////////P3/+fv/3uT/SE2vAABn + CBB/GiCMLzmfLTWcGByJFRyKGCOOMj2gHymRDxiGGyOPLDCXBRF/AAh3BhaCEyKMICqTKC2WNDqfIzCV + Awx6Eh+JHiaPAAR3AAZ5CxSDICWQX2q7Q1CqAA1+AAFxDxuHiZTbVGC4dHnQnabrTVqzY23EUV62Slau + LjaZXWm9sLjz5ez/9vn/+fv//v7//////////////////////////////////////////////////P3/ + +Pv/4+n+e4LPfoPVpqv2vsf/zNX/zdb/xtH/v8v8pK7spKfysLb3vcr4ws784ej/hI/YAAZ1AAJzVF25 + yM//3Of/5+//i5LcAABpMzyfp6vxoKznlqHhqbbtx9H/8fz/kpvfAABiAABph4zc5PD/2OP/193/3un/ + 1+D/2OH/1+D/0Nr/zNL/3+j/6/L/7/T/9vn//P3//v////////////////////////////////////// + /////////////f7/+Pr/9Pf/6vD/5u3/3+b/4uv/6PD/5+//5O3/5/P/sL3sXmS7mZzoz9f/3+z/4e// + mKLiEiKKCBF/KTWZr7T06/f/3ev/VF2zChSBipPcz9v+4u7/3ur/3ev/5/X/qrPrISmSDRJ2Xmq/3ur/ + 4uv/6vH/7fP/7fL/7/T/7vP/7fP/7fP/8PX/8fX/9Pf/+Pr/+/z//v7///////////////////////// + /////////////////////////////v7//P3/+Pr/9vn/9Pf/8vb/8vb/8/b/9Pf/7/T/6/L/tL/ubXLH + en/Ti43gqavy0t3/nafjMj6fJzaaAAV1GyeOYmW7Nz6fAABgNj6i1N//3uz/2uX/3Oj/5PH/wcj7FR2J + AAN0gong0tr/6fH/7/P/9vj/+Pr/+fv/+fv/+Pr/+Pr/+Pr/+fv/+vv//P3//f7//v////////////// + /////////////////////////////////////////////////v7//f7//P3/+/z/+/z/+/z//f3//f7/ + +fv/8fX/5Oz/jpbfc3jObnXLcXfOk5rks7b4iY3dR1KvDhuEAABoAABlEBV9U12ytcD13Or/3en/3ej/ + 1eL/q7fvGR+MKDKZbnnNxc/76PD/8fX/+fr//f7//v///////v7//f7//f3//P3//f3//f7//v////// + /////////////////////////////////////////////////////v7//f7//P3//P3//f7//v7///// + /////////////////f7/9vn/7/T/yNH5lJrleoDVmZ3pmpzpc3nPfoTWf4bYVFy3HSaLZ3PGsrb8v8r8 + y9n9q7jre4LRf4fUgIvXAwZ1AABrhYjb0NX/6PH/8PX/+Pr//f7//////////v///f3/+vv/+Pr/9/r/ + 9/n/+Pr/+/z//f7//v7//////////////////////////////////////v///f7/+/z/+fr/9vj/9/n/ + +vz/+vv/+/z//v7//////////////////v7/+vz/8/f/7PL/2uT/t8H1srP6vcH+nKTnSlOxV2C7TVaz + WGS8QUqmSlSuSFOtR1GtbXTKVl23ARB5AAh2AABnd33P3eP/4ur/7/T/9/n//P3//////////////P3/ + 9/n/8vb/7PH/6fD/7PL/7vP/8vb/9vn/+/z//f7//////////////////////////////v7/+/z/+Pr/ + 8/b/7/T/8Pb/6vH/3eP97vL++fr//P3//////////////////////f7/+vv/9fj/7/T/5+//z9f+t7v4 + uLn9Z2zFLzucFCGIMz6gGCCMAAd4AAl2Dx2EER+GXWK8c3XLKzKXd4LP4er/6/L/8PX/9/n//P3//v// + /////////v7/+fv/8/b/7PP/y9H/i4/erLbt4er/5e3/7fP/8/b/+fv//f3//v7///////////////// + /v7/+/z/9vj/8PT/6/L/3+n/x9H9aHTAZGvG3+b9+Pr/+/z//////////////////////////v7/+/z/ + +Pr/8vb/6/H/3OX+wMn4maDmdHrPWGG6T1a1eoHWcHfOTlayUlq1SlKubHjAxMj/0dn/4+v/7PL/8vb/ + +Pr//P3//v7//////////////f7/+fr/7vP/xsv5YGXAHymRKjKYYWS9rbLz4u3/6/P/8vb/+fr//f7/ + /////////////v//+/z/9vj/7fL/5e3/xs7/Y23BIiiSAABeLTab3+b/9/r/+/z///////////////// + /////////////////f7/+vz/9vj/8PX/6vH/3eb/ydL8xM/6uMPyt733w8j/zNb/1Nz/3OT/4uz/5u7/ + 7fP/8vb/9vj/+vz//f7//////////////////////f7/+fv/7vP/jpHiAAJ1CxaBER6GAABoFRmGbXbH + 0Nf/7PL/9fj//P3//////////////v7/+fv/8/f/4Of/hYvbKDGZAABuAABdAAZyi5La5+7/9vn/+/z/ + /////////////////////////////////////v7//P3/+fv/9ff/8vb/7/X/7fP/6/L/5u3/5ez/6fD/ + 7PP/7/T/8fX/9Pf/9/n/+vv//P3//v7//v///////////////////////v7/+fv/8fb/2eH9fIbQExqH + AABrAAp6AAFyAABwS0+uztX39vn/+vz//////////////f7/+Pr/8ff/qbLpAABrAABhAABwDBWAfobX + 5e3/8PX/9vn//f3//////////v///f7/+/z/+vv/+vv/+vz//P3//v7//v///v7//P3/+vz/+Pr/9/n/ + 9vj/9vj/9vj/9vj/9/n/+fr/+/z//P3//f7//v7//f7//P3/+/z/+vz/+/z//P3//v7//////v7/+/z/ + 9fj/7/T/5/H/uML1U1e1AAh5AABuAABvMjmdv8bz9vr/+vv//////////////f7/+fv/7/T/iY7aDxSA + GiONa3XHsr7w4Oj/6/H/9Pf/+vz//v7//////v///P3/+Pr/9Pf/8/f/9fj/9fj/9vn/+/z//v7///// + /////////v7//f7//P3/+/z/+/z//P3//f7//v///////////////v7/+/z/9/n/9vn/9vn/9Pj/9vn/ + +/z//v7//////f7/+vz/9fj/7/T/6vL/3ef/i5PbGRqJBQl5jJbZ6vH/9Pj/+/z//////////////f7/ + +fv/8fT/1Nn9t7/0wcr54er/7fT/8fX/9fj/+vv//f7//////////f3/+Pr/8PT/6/L/3uX/ztb/5Or/ + 8/f/+Pr//f7//////////////f7/+vz/+Pr/+fv/+fv/+vv//f3//v///////////////P3/9/n/7vL/ + 193/ztf/5u3/7vP/9Pf/+/z//v7//////v7//P3/+Pr/8fX/7PP/5/D/sLfxoKnk4+r/8vf/9/n//f3/ + /////////////v7/+/z/9vn/9Pf/8vb/8fb/8fX/9Pf/+Pr//P3//v7//////////v7/+vv/8vb/5+7/ + y9H/WWO9KSmSkZXj6vD/+Pv//P3//////////f7/+Pr/9fj/8vb/6O7/7vP/9fj/+Pr//f7///////// + /v//+vv/8vb/7PP/hYraKiqKlp7i6PD/7fP/9ff/+/z//v7//////////f7/+vv/9ff/8fX/8PX/8vb/ + 8/f/9vn/+/z//v7//////////////////f7/+/z/+vv/+fr/+fr/+vv//P3//v7///////////////// + /P3/9fj/7PL/1d7/RUysAABhAABlg4ja6/D/+Pr//P3/////////+/z/9fj/6e7/2eD/h4/bnaXg7PH/ + 9fj/+/z//////////v7/+Pr/8PX/y9X1JDGVAABaERWDoKnp6PH/7vP/9/n//P3//////////////v7/ + /P3/+vv/+fv/+fv/+vv//P3//v7//////////////////////////v7//v7//v7//v7//v////////// + /////////////v7/+fv/8PX/7PX/ipPdAABsAABlQ1Cp3Ob/7vP/9/n//f7/////////+fv/9Pj/yNH5 + Ule2DBJ8Ljie0df+8fb/+fv//v7//////v7/+Pr/7/X/hY3YAABxAAl7AABuEBaEs7nz6fH/8fX/+vv/ + /v7//////////////////v///v7//v7//v7///////////////////////////////////////////// + /////////////////////////////f3/9vn/7PL/0tn/LzidAQFsAAB0iZHb6vP/8PT/+fv//v////// + /v7/+Pr/8vf/r7rqAAV4AABdPUen1N//7PL/9vn//f7//////v7/+fr/7/T/yc75S1G0AABrARKAAABp + Qker0df/7fP/9/n//f7///////////////////////////////////////////////////////////// + /////////////////////////////////////////////P3/9/n/5+7/cXXNAAd2AABuMDebzdT97PL/ + 9vj//P3//////////v7/9/n/7/X/tL/uFCCLAABqHSqRvcf46fD/9Pf//f3/////////+vv/8vX/6vH/ + yM3+JC2XAABtAAV2Agx9q7Ly7vT/9vn//f7///////////////////////////////////////////// + /////////////////////////////////////////////////////////////P3/9/r/4uj/WWO1AAVx + KTaYu8T07fT/8vb/+vv//v7//////////v7/9/n/7vX/vsn1Iy2SAABrAQ99mp/o6PD/9Pf//P3///// + /////P3/9/n/7vP/6fL/s7z2DBB/AABeQ0uttrr56e7/+Pr//f7///////////////////////////// + /////////////////////////////////////////////////////////////////////////////P3/ + +fv/4ef6g4zNbXfFw8v27fT/8vb/+Pr//f3//////////////v7/9/n/7vT/yNL7MjucAABtBxF/nKLo + 6fH/9Pf//P3//////////v7/+/z/9fj/7fL/6/T/jZXbLzScrrP14en/7fL/+fv//v7///////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////f7/+vz/8PP91dr34+f/8vb/8/f/9/r//P3//v///////////////v7/+Pr/8PX/1N3/ + QUqmAQRxBQ98m6Dm7PL/9fj//P3//////////////v7/+/z/9ff/8PX/5ez/ytH94ej/8vb/9vj/+/z/ + /v7///////////////////////////////////////////////////////////////////////////// + /////////////////////////////v7//P3/+vz/+fv/+Pr/+Pr/+vv//f3//v////////////////// + /v//+fv/9Pf/2+L/SVGtAABsLTaZytL58fX/9/n//f7//////////////////v7/+/z/9/n/9fj/9vn/ + 9fj/9vj/+vz//f7///////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////v7//f7//f3//f3//f3//v7//v////// + ////////////////////+/z/9vn/6e//mZ7gTVarr7bp6/H/9fj/+vv//v7///////////////////// + /v7//f7/+/z/+/z/+/z//P3//v7///////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////f3/+Pr/9fj/6e7/4+n/8fb/9Pf/+Pr//f3///////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////v7//P3/+fv/+fv/+vv/+Pr/+vv/ + /P3//v7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v7//f7/ + /f3//P3//f7//v7//v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////4D/////////AH////////8Af////////wB/////////AH////////8Af////////wB/////// + //AH////////8Af////////wB/////////AH////////8AfwP//////wB8Af//+Af/AHgB///wA/8AcA + H///AB/wBgAf//8AD/AGAB///wAH8AYAH///AAPwBAAf//8AA/AEAD///wAD8AQAP///AAPwBAB///+A + A/AEAP///8AD4AAA////4AcAAAH////wDgAAAf/////8AAAH//////gAAAf/////4AAAAf/////gAAAA + ////+AAAAAAAD//AAAAAAAAH/4AAAAAAAAf/gAAAAAAAB/+AAAAAAAAH/4AAAAAAAAf/gAAAAAAAB/+A + AAAAAAAP/4AAAAAAAB//wAAAAABAf/4HwAAAAYAf8APAAAADgA/gA+AAAAMAA8AD8AAABwADgAP8AAAf + AAOAA/4AAB8AA4ADAAAAAQADgAIAcA4AgAOABgBwDgBAA4AMAGAMADADwDwAYAwAOAfg+ABgBAAeH//4 + AEAEAB////gAwAYAH///+ADABgAf///4AcAGAB////gBwAcAH///+APAB4A////8B+AHwH//////4A// + ///////gD/////////Af//////////////8= + + + \ No newline at end of file diff --git a/CodeWalker/Project/Panels/EditYmapOccludeModelPanel.Designer.cs b/CodeWalker/Project/Panels/EditYmapOccludeModelPanel.Designer.cs new file mode 100644 index 0000000..740855b --- /dev/null +++ b/CodeWalker/Project/Panels/EditYmapOccludeModelPanel.Designer.cs @@ -0,0 +1,287 @@ + +namespace CodeWalker.Project.Panels +{ + partial class EditYmapOccludeModelPanel + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(EditYmapOccludeModelPanel)); + this.OccludeModelTabControl = new System.Windows.Forms.TabControl(); + this.ModelTabPage = new System.Windows.Forms.TabPage(); + this.ModelDeleteButton = new System.Windows.Forms.Button(); + this.ModelAddToProjectButton = new System.Windows.Forms.Button(); + this.TriangleTabPage = new System.Windows.Forms.TabPage(); + this.TriangleDeleteButton = new System.Windows.Forms.Button(); + this.TriangleAddToProjectButton = new System.Windows.Forms.Button(); + this.TriangleGoToButton = new System.Windows.Forms.Button(); + this.TriangleCenterTextBox = new System.Windows.Forms.TextBox(); + this.label31 = new System.Windows.Forms.Label(); + this.TriangleCorner1TextBox = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.TriangleCorner2TextBox = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.TriangleCorner3TextBox = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.ModelFlagsTextBox = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.OccludeModelTabControl.SuspendLayout(); + this.ModelTabPage.SuspendLayout(); + this.TriangleTabPage.SuspendLayout(); + this.SuspendLayout(); + // + // OccludeModelTabControl + // + this.OccludeModelTabControl.Controls.Add(this.ModelTabPage); + this.OccludeModelTabControl.Controls.Add(this.TriangleTabPage); + this.OccludeModelTabControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.OccludeModelTabControl.Location = new System.Drawing.Point(0, 0); + this.OccludeModelTabControl.Name = "OccludeModelTabControl"; + this.OccludeModelTabControl.SelectedIndex = 0; + this.OccludeModelTabControl.Size = new System.Drawing.Size(553, 407); + this.OccludeModelTabControl.TabIndex = 0; + // + // ModelTabPage + // + this.ModelTabPage.Controls.Add(this.ModelFlagsTextBox); + this.ModelTabPage.Controls.Add(this.label4); + this.ModelTabPage.Controls.Add(this.ModelDeleteButton); + this.ModelTabPage.Controls.Add(this.ModelAddToProjectButton); + this.ModelTabPage.Location = new System.Drawing.Point(4, 22); + this.ModelTabPage.Name = "ModelTabPage"; + this.ModelTabPage.Padding = new System.Windows.Forms.Padding(3); + this.ModelTabPage.Size = new System.Drawing.Size(545, 381); + this.ModelTabPage.TabIndex = 0; + this.ModelTabPage.Text = "Model"; + this.ModelTabPage.UseVisualStyleBackColor = true; + // + // ModelDeleteButton + // + this.ModelDeleteButton.Location = new System.Drawing.Point(176, 89); + this.ModelDeleteButton.Name = "ModelDeleteButton"; + this.ModelDeleteButton.Size = new System.Drawing.Size(95, 23); + this.ModelDeleteButton.TabIndex = 111; + this.ModelDeleteButton.Text = "Delete Model"; + this.ModelDeleteButton.UseVisualStyleBackColor = true; + this.ModelDeleteButton.Click += new System.EventHandler(this.ModelDeleteButton_Click); + // + // ModelAddToProjectButton + // + this.ModelAddToProjectButton.Location = new System.Drawing.Point(75, 89); + this.ModelAddToProjectButton.Name = "ModelAddToProjectButton"; + this.ModelAddToProjectButton.Size = new System.Drawing.Size(95, 23); + this.ModelAddToProjectButton.TabIndex = 110; + this.ModelAddToProjectButton.Text = "Add to Project"; + this.ModelAddToProjectButton.UseVisualStyleBackColor = true; + this.ModelAddToProjectButton.Click += new System.EventHandler(this.ModelAddToProjectButton_Click); + // + // TriangleTabPage + // + this.TriangleTabPage.Controls.Add(this.TriangleCorner3TextBox); + this.TriangleTabPage.Controls.Add(this.label3); + this.TriangleTabPage.Controls.Add(this.TriangleCorner2TextBox); + this.TriangleTabPage.Controls.Add(this.label2); + this.TriangleTabPage.Controls.Add(this.TriangleCorner1TextBox); + this.TriangleTabPage.Controls.Add(this.label1); + this.TriangleTabPage.Controls.Add(this.TriangleDeleteButton); + this.TriangleTabPage.Controls.Add(this.TriangleAddToProjectButton); + this.TriangleTabPage.Controls.Add(this.TriangleGoToButton); + this.TriangleTabPage.Controls.Add(this.TriangleCenterTextBox); + this.TriangleTabPage.Controls.Add(this.label31); + 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(545, 381); + this.TriangleTabPage.TabIndex = 1; + this.TriangleTabPage.Text = "Triangle"; + this.TriangleTabPage.UseVisualStyleBackColor = true; + // + // TriangleDeleteButton + // + this.TriangleDeleteButton.Location = new System.Drawing.Point(176, 121); + this.TriangleDeleteButton.Name = "TriangleDeleteButton"; + this.TriangleDeleteButton.Size = new System.Drawing.Size(95, 23); + this.TriangleDeleteButton.TabIndex = 109; + this.TriangleDeleteButton.Text = "Delete Triangle"; + this.TriangleDeleteButton.UseVisualStyleBackColor = true; + this.TriangleDeleteButton.Click += new System.EventHandler(this.TriangleDeleteButton_Click); + // + // TriangleAddToProjectButton + // + this.TriangleAddToProjectButton.Location = new System.Drawing.Point(75, 121); + this.TriangleAddToProjectButton.Name = "TriangleAddToProjectButton"; + this.TriangleAddToProjectButton.Size = new System.Drawing.Size(95, 23); + this.TriangleAddToProjectButton.TabIndex = 108; + this.TriangleAddToProjectButton.Text = "Add to Project"; + this.TriangleAddToProjectButton.UseVisualStyleBackColor = true; + this.TriangleAddToProjectButton.Click += new System.EventHandler(this.TriangleAddToProjectButton_Click); + // + // TriangleGoToButton + // + this.TriangleGoToButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.TriangleGoToButton.Location = new System.Drawing.Point(471, 4); + this.TriangleGoToButton.Name = "TriangleGoToButton"; + this.TriangleGoToButton.Size = new System.Drawing.Size(68, 23); + this.TriangleGoToButton.TabIndex = 87; + this.TriangleGoToButton.Text = "Go to"; + this.TriangleGoToButton.UseVisualStyleBackColor = true; + this.TriangleGoToButton.Click += new System.EventHandler(this.TriangleGoToButton_Click); + // + // TriangleCenterTextBox + // + this.TriangleCenterTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TriangleCenterTextBox.Location = new System.Drawing.Point(75, 6); + this.TriangleCenterTextBox.Name = "TriangleCenterTextBox"; + this.TriangleCenterTextBox.Size = new System.Drawing.Size(390, 20); + this.TriangleCenterTextBox.TabIndex = 86; + this.TriangleCenterTextBox.TextChanged += new System.EventHandler(this.TriangleCenterTextBox_TextChanged); + // + // label31 + // + this.label31.AutoSize = true; + this.label31.Location = new System.Drawing.Point(8, 9); + this.label31.Name = "label31"; + this.label31.Size = new System.Drawing.Size(41, 13); + this.label31.TabIndex = 85; + this.label31.Text = "Center:"; + // + // TriangleCorner1TextBox + // + this.TriangleCorner1TextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TriangleCorner1TextBox.Location = new System.Drawing.Point(75, 32); + this.TriangleCorner1TextBox.Name = "TriangleCorner1TextBox"; + this.TriangleCorner1TextBox.Size = new System.Drawing.Size(390, 20); + this.TriangleCorner1TextBox.TabIndex = 111; + this.TriangleCorner1TextBox.TextChanged += new System.EventHandler(this.TriangleCorner1TextBox_TextChanged); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(8, 35); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(50, 13); + this.label1.TabIndex = 110; + this.label1.Text = "Corner 1:"; + // + // TriangleCorner2TextBox + // + this.TriangleCorner2TextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TriangleCorner2TextBox.Location = new System.Drawing.Point(75, 58); + this.TriangleCorner2TextBox.Name = "TriangleCorner2TextBox"; + this.TriangleCorner2TextBox.Size = new System.Drawing.Size(390, 20); + this.TriangleCorner2TextBox.TabIndex = 113; + this.TriangleCorner2TextBox.TextChanged += new System.EventHandler(this.TriangleCorner2TextBox_TextChanged); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(8, 61); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(50, 13); + this.label2.TabIndex = 112; + this.label2.Text = "Corner 2:"; + // + // TriangleCorner3TextBox + // + this.TriangleCorner3TextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TriangleCorner3TextBox.Location = new System.Drawing.Point(75, 84); + this.TriangleCorner3TextBox.Name = "TriangleCorner3TextBox"; + this.TriangleCorner3TextBox.Size = new System.Drawing.Size(390, 20); + this.TriangleCorner3TextBox.TabIndex = 115; + this.TriangleCorner3TextBox.TextChanged += new System.EventHandler(this.TriangleCorner3TextBox_TextChanged); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(8, 87); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(50, 13); + this.label3.TabIndex = 114; + this.label3.Text = "Corner 3:"; + // + // ModelFlagsTextBox + // + this.ModelFlagsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ModelFlagsTextBox.Location = new System.Drawing.Point(75, 6); + this.ModelFlagsTextBox.Name = "ModelFlagsTextBox"; + this.ModelFlagsTextBox.Size = new System.Drawing.Size(390, 20); + this.ModelFlagsTextBox.TabIndex = 119; + this.ModelFlagsTextBox.TextChanged += new System.EventHandler(this.ModelFlagsTextBox_TextChanged); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(8, 9); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(35, 13); + this.label4.TabIndex = 118; + this.label4.Text = "Flags:"; + // + // EditYmapOccludeModelPanel + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(553, 407); + this.Controls.Add(this.OccludeModelTabControl); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "EditYmapOccludeModelPanel"; + this.Text = "Occlude Model"; + this.OccludeModelTabControl.ResumeLayout(false); + this.ModelTabPage.ResumeLayout(false); + this.ModelTabPage.PerformLayout(); + this.TriangleTabPage.ResumeLayout(false); + this.TriangleTabPage.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TabControl OccludeModelTabControl; + private System.Windows.Forms.TabPage ModelTabPage; + private System.Windows.Forms.TabPage TriangleTabPage; + private System.Windows.Forms.Button TriangleGoToButton; + private System.Windows.Forms.TextBox TriangleCenterTextBox; + private System.Windows.Forms.Label label31; + private System.Windows.Forms.Button TriangleDeleteButton; + private System.Windows.Forms.Button TriangleAddToProjectButton; + private System.Windows.Forms.Button ModelDeleteButton; + private System.Windows.Forms.Button ModelAddToProjectButton; + private System.Windows.Forms.TextBox TriangleCorner3TextBox; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox TriangleCorner2TextBox; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox TriangleCorner1TextBox; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox ModelFlagsTextBox; + private System.Windows.Forms.Label label4; + } +} \ No newline at end of file diff --git a/CodeWalker/Project/Panels/EditYmapOccludeModelPanel.cs b/CodeWalker/Project/Panels/EditYmapOccludeModelPanel.cs new file mode 100644 index 0000000..c31b53e --- /dev/null +++ b/CodeWalker/Project/Panels/EditYmapOccludeModelPanel.cs @@ -0,0 +1,245 @@ +using CodeWalker.GameFiles; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace CodeWalker.Project.Panels +{ + public partial class EditYmapOccludeModelPanel : ProjectPanel + { + public ProjectForm ProjectForm; + public YmapOccludeModel CurrentOccludeModel { get; set; } + public YmapOccludeModelTriangle CurrentTriangle { get; set; } + + private bool populatingui = false; + + + public EditYmapOccludeModelPanel(ProjectForm owner) + { + ProjectForm = owner; + InitializeComponent(); + } + + + public void SetOccludeModel(YmapOccludeModel model) + { + CurrentOccludeModel = model; + CurrentTriangle = null; + Tag = model; + LoadOccludeModel(); + LoadTriangle(); + UpdateFormTitle(); + OccludeModelTabControl.SelectedTab = ModelTabPage; + } + public void SetOccludeModelTriangle(YmapOccludeModelTriangle tri) + { + CurrentTriangle = tri; + CurrentOccludeModel = tri?.Model; + Tag = tri?.Model; + LoadOccludeModel(); + LoadTriangle(); + UpdateFormTitle(); + OccludeModelTabControl.SelectedTab = TriangleTabPage; + } + + private void UpdateGraphics() + { + var m = CurrentOccludeModel ?? CurrentTriangle?.Model; + if (m == null) return; + if (ProjectForm?.WorldForm == null) return; + + ProjectForm.WorldForm.UpdateOccludeModelGraphics(m); + } + + private void UpdateFormTitle() + { + Text = "OccludeModel: " + (CurrentOccludeModel?.Index.ToString() ?? "(none)"); + } + + + private void LoadOccludeModel() + { + + if (CurrentOccludeModel == null) + { + ////Panel.Enabled = false; + ModelAddToProjectButton.Enabled = false; + ModelDeleteButton.Enabled = false; + ModelFlagsTextBox.Text = string.Empty; + } + else + { + populatingui = true; + var m = CurrentOccludeModel; + ////Panel.Enabled = true; + ModelAddToProjectButton.Enabled = !ProjectForm.YmapExistsInProject(CurrentOccludeModel.Ymap); + ModelDeleteButton.Enabled = !ModelAddToProjectButton.Enabled; + ModelFlagsTextBox.Text = m.Flags.Value.ToString(); + populatingui = false; + + //if (ProjectForm.WorldForm != null) + //{ + // ProjectForm.WorldForm.SelectObject(CurrentOccludeModel); + //} + + } + } + private void LoadTriangle() + { + + if (CurrentTriangle == null) + { + ////Panel.Enabled = false; + TriangleAddToProjectButton.Enabled = false; + TriangleDeleteButton.Enabled = false; + TriangleCenterTextBox.Text = string.Empty; + TriangleCorner1TextBox.Text = string.Empty; + TriangleCorner2TextBox.Text = string.Empty; + TriangleCorner3TextBox.Text = string.Empty; + } + else + { + populatingui = true; + var t = CurrentTriangle; + ////Panel.Enabled = true; + TriangleAddToProjectButton.Enabled = !ProjectForm.YmapExistsInProject(CurrentTriangle.Ymap); + TriangleDeleteButton.Enabled = !TriangleAddToProjectButton.Enabled; + TriangleCenterTextBox.Text = FloatUtil.GetVector3String(t.Center); + TriangleCorner1TextBox.Text = FloatUtil.GetVector3String(t.Corner1); + TriangleCorner2TextBox.Text = FloatUtil.GetVector3String(t.Corner2); + TriangleCorner3TextBox.Text = FloatUtil.GetVector3String(t.Corner3); + populatingui = false; + + //if (ProjectForm.WorldForm != null) + //{ + // ProjectForm.WorldForm.SelectObject(CurrentTriangle); + //} + + } + } + + private void TriangleGoToButton_Click(object sender, EventArgs e) + { + if (CurrentTriangle == null) return; + if (ProjectForm?.WorldForm == null) return; + ProjectForm.WorldForm.GoToPosition(CurrentTriangle.Center, CurrentTriangle.Box.Size * 2.0f); + } + + private void TriangleAddToProjectButton_Click(object sender, EventArgs e) + { + if (CurrentTriangle == null) return; + if (ProjectForm == null) return; + ProjectForm.SetProjectItem(CurrentTriangle); + ProjectForm.AddOccludeModelTriangleToProject(); + } + + private void TriangleDeleteButton_Click(object sender, EventArgs e) + { + ProjectForm.SetProjectItem(CurrentTriangle); + ProjectForm.DeleteOccludeModelTriangle(); + } + + private void ModelAddToProjectButton_Click(object sender, EventArgs e) + { + if (CurrentOccludeModel == null) return; + if (ProjectForm == null) return; + ProjectForm.SetProjectItem(CurrentOccludeModel); + ProjectForm.AddOccludeModelToProject(); + } + + private void ModelDeleteButton_Click(object sender, EventArgs e) + { + ProjectForm.SetProjectItem(CurrentOccludeModel); + ProjectForm.DeleteOccludeModel(); + } + + private void ModelFlagsTextBox_TextChanged(object sender, EventArgs e) + { + if (populatingui) return; + if (CurrentOccludeModel == null) return; + uint.TryParse(ModelFlagsTextBox.Text, out uint f); + lock (ProjectForm.ProjectSyncRoot) + { + if (CurrentOccludeModel.Flags != f) + { + CurrentOccludeModel.Flags = f; + ProjectForm.SetYmapHasChanged(true); + } + } + } + + private void TriangleCenterTextBox_TextChanged(object sender, EventArgs e) + { + if (populatingui) return; + if (CurrentTriangle == null) return; + var v = FloatUtil.ParseVector3String(TriangleCenterTextBox.Text); + lock (ProjectForm.ProjectSyncRoot) + { + if (CurrentTriangle.Center != v) + { + CurrentTriangle.Center = v; + UpdateGraphics(); + ProjectForm.SetYmapHasChanged(true); + ProjectForm.WorldForm?.SetWidgetPosition(v); + } + } + } + + private void TriangleCorner1TextBox_TextChanged(object sender, EventArgs e) + { + if (populatingui) return; + if (CurrentTriangle == null) return; + var v = FloatUtil.ParseVector3String(TriangleCorner1TextBox.Text); + lock (ProjectForm.ProjectSyncRoot) + { + if (CurrentTriangle.Corner1 != v) + { + CurrentTriangle.Corner1 = v; + UpdateGraphics(); + ProjectForm.SetYmapHasChanged(true); + ProjectForm.WorldForm?.SetWidgetPosition(CurrentTriangle.Center); + } + } + } + + private void TriangleCorner2TextBox_TextChanged(object sender, EventArgs e) + { + if (populatingui) return; + if (CurrentTriangle == null) return; + var v = FloatUtil.ParseVector3String(TriangleCorner2TextBox.Text); + lock (ProjectForm.ProjectSyncRoot) + { + if (CurrentTriangle.Corner2 != v) + { + CurrentTriangle.Corner2 = v; + UpdateGraphics(); + ProjectForm.SetYmapHasChanged(true); + ProjectForm.WorldForm?.SetWidgetPosition(CurrentTriangle.Center); + } + } + } + + private void TriangleCorner3TextBox_TextChanged(object sender, EventArgs e) + { + if (populatingui) return; + if (CurrentTriangle == null) return; + var v = FloatUtil.ParseVector3String(TriangleCorner3TextBox.Text); + lock (ProjectForm.ProjectSyncRoot) + { + if (CurrentTriangle.Corner3 != v) + { + CurrentTriangle.Corner3 = v; + UpdateGraphics(); + ProjectForm.SetYmapHasChanged(true); + ProjectForm.WorldForm?.SetWidgetPosition(CurrentTriangle.Center); + } + } + } + } +} diff --git a/CodeWalker/Project/Panels/EditYmapOccludeModelPanel.resx b/CodeWalker/Project/Panels/EditYmapOccludeModelPanel.resx new file mode 100644 index 0000000..0960cbe --- /dev/null +++ b/CodeWalker/Project/Panels/EditYmapOccludeModelPanel.resx @@ -0,0 +1,409 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAMAICAAAAAAGACoDAAANgAAABAQAAAAABgAaAMAAN4MAABAQAAAAAAYACgyAABGEAAAKAAAACAA + AABAAAAAAQAYAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////v8/u3v+Pn6//7+//////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //7+/vX3/rzA3OHl9fz9//////////////////////////////////////////////////////////// + //////////////////////////////////////////////////7//+zv+3Z6qcLI5Pr7//////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////7+/+br+15in6+33vf5//////////////////7+//7+//////////////////// + //////////////////////////////3+//v8//v8//3+//////////////////////7+/+Ho+1dana20 + 4/b4//////////z9//P2/+Tp/ezw/vz9//////////////////////////////////////////7///X4 + /9Pa+tPa+/H1//z9//////////////////7+/93k+SsscaSr3PX3//////7+//L1/7W98AcWgrvC8Pj6 + //////////////////////////////////////////7+/+bs/xohiAEJdrvF9+7y//z9//////////// + //7+/9rh+CEkapmh0/T3//////j6/9HZ/AEHcgEEb9LZ+/r7//////////////////////////////// + //////////7//+/z/3F+zAAAXwQLcZai3fb4//////////////3+/97l/E9Tmaau4fT3/////+/0/1dd + sAAAV7a/8/H1//7+//////////////////////////////////////////////r8/+jv/46Y3QUUf6Ot + 5PX4//////////////3+/9zj+3Z6wLe/7fX4//////D0/212xnaAzerw//z9//////////////////// + //////////////////////////////////v8/+/z/+Dm+/D0//z9//////////7+//j6/9Pd+UhLjb/H + 9/D0//3+//n7/+nt/+jt//n7//////////////////////////////////////////////////////// + //7///7+//7+//7+//////////r8/+7z/83W+ImU2A0UdFNarr/K9env//X4//z9//3+//7///////// + //////////////////////////////////////////////////////////////////7///j6/+Pq/255 + xhckjE5XsVVftUlTqwAKeTA9nr3H8+7z//v8//////////////////////////////////////////// + //////////////////////////////7+//b4/9Tc+Sc0mRonj8rV/crX/ZSb48rX/brG8wwWgQAEdJei + 4efu//n7//7+//z9//z9//z9//z9//3+//////////////////////////////3+//f5/+3y/+nv/+ft + /8vV+io2mImU2M7c/7vG9yIvlQAOfCg4mM3Y/s/c/4aR1AQRfGtzwtni/ebt/9vi/tri/tXd+9Tc+O3x + /vz9//////////////////////////n6/87V+FVftkRPrFlnvSEqjQoUfmJvwWFvvg0TfQQIcxEchwAD + cy89n19rvVVitQwZgwAAaiMrkT9NqTVBoiw3mhQihig1mNLX+fv8//////////////////////////b5 + /52l4EFLqoCK03yF0VBctGhyw52o5GVrvQAAaneBzsHM+jA3mhYgiTtIpJOf3ouW2AAAbmh0wbbA8bS+ + 7qiz5pCb16+56e/z//3+//////////////////////////v8//H1/+vw/+zx/+nv/7/J9YqP3MbP/8LM + +hwqkFZftaCp5EhRrcTQ+9jj/8rW/UJMqn6J0ebt//X3//f5//b4//X3//f5//z9//////////////// + //////////7+//z9//3+//////////3+/+7z/6at64iP3aWs7XN8zRIfhyUykp2o5MHM+oKM0xonjY6X + 2+jv//v8//////7+//n7//b5//r7//7///////////////////7+//f5/+rw/9Pa9fL0/v7///////// + //v8//H1/+Tr/7i/91liu0NPq0VQrS06m0NNqDdCoYqU1+nv//v8//////////n7/9zi/qSt59ri/fL1 + //v8//7///////z9//D0/8rT+h0sjkVQrPD0//////////////////////z9/+7z/8LL9Jqk4aGq6LW/ + 8c3W9+Xs/vH1//v8//////////////f5/6at5gAAbxIfh6u16+Po/fr7//////b5/6ev5gAIeAAPernC + 8fX4//////////3+//v8//z9//////3+//j6//P3//P2//b4//r8//7+//7+//v8//r8//3+//////v8 + /+Xr/nuIzwAAbBseg5Sb2fb5//////f5/8DF8pWe3d/n/vT3//39//////v8/+zx/87V9+3x/v3+//// + //3+//j6//X4//v8//////////n7/+Dm/snR9fD0//39//z8/fv8/+3y/8LK9aGq4dfd9/n7//////z9 + //b5//X4//v8//////////7+/+7z/4aP1gEPet7k/f39//////f5/83U+ZCZ2u3x/v7+//////P3/215 + wgAJd7fB8/L1//7+//////3+//j6//f5//r8//7+//////////////////////////////j6/87W/AAA + X2duue3y//7+//////D0/05asBQfidzj/P39//////X4/6Su6AAAXBccgtff/vv8//////////////// + //////////////////////////////////////P3/3F8xhYli9Xe/fn6/////////+3y/1pltQAJd9be + /fv8//////z9/+rw/36I0Bknjs/W+vv8//////////////////////////////////////////////// + //////f5/8HI7tnf+/X4//7+/////////+/0/3R7xgAAb9ng/Pz9//////////n7/+Ln/dLY+fP2//3+ + //////////////////////////////////////////////////////3+//r7//v8//7+//////////// + //b4/7/F84eP0e/0//7+//////////7+//z9//v8//3+//////////////////////////////////// + //////////////////////////////////////////////////z9//b5//X4//v8//////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////w////4 + P///+D////g8//D4MH/geCB/4Dggf+A4IH/wOCD/+DAB//hgAf//gAP//wAAB/AAAAPwAAAD8AAAA/AA + AAfjAAEHgYADAQPgBwEDEAEBAghgAQwIIEH8CCB//Bggf/wYMH/8ODD///h/////////////KAAAABAA + AAAgAAAAAQAYAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///+vv/fL1/v///wAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///4+Vx7/F5v///wAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAP///4CHtrS62////////////////////wAAAAAAAAAAAP////H0/vf6/v// + /////////4yTwrrB4f///+zw+7rA6P39/////wAAAAAAAAAAAP///56l2BkcguXr/P///////42Uw8jO + 6P///ysvjWVqtP///////wAAAAAAAAAAAP////D0/0hPpsDG6////////6y02d7k8////3qAx+/z/f// + /wAAAAAAAAAAAAAAAAAAAP///////////////8zT8V5ns1Rcrdzh9f///////////wAAAAAAAAAAAAAA + AAAAAP////////7+/6ix3nmBxFthtmdwu09WqbC54/v9//r8//j6//39/wAAAAAAAAAAAOjt/H6I0FJc + skpSqHF+wRMahFZhs4iT1AsNc1pgrm52v2RsuO/z/gAAAP////////L2/cLJ7rrD64+V4DY+ozU+mYmU + 0X2Hy1hfss7V8urv/PP2/v///wAAAP///+Pp+d/k9////////+Pp/4uR3ysymW14xYOM0fD0/P///+Xq + +ri/6Pj6/wAAAOrv/j5DnbS75P////////////X4/+/0/ubr+/r7/////////9rh+hgZhKGo2QAAAPDz + /eLn+f////j6/2Nqttrg9////+Hn+P3+//3+/1hescLJ6/////L2/eru/AAAAAAAAAAAAP///8rR70tR + p/3+//v8/zY6jNPY7////09WqWpwu////wAAAAAAAAAAAAAAAAAAAAAAAPb4/vr7//////v8/5Wd1eHm + +P////v8//T3/wAAAAAAAAAAAAAAAP//AAD8PwAA/D8AAPwDAACAAwAAgAMAAIAHAADABwAAwAEAAMAB + AAAAAQAAAAEAAAABAAAAAQAAwAcAAOAPAAAoAAAAQAAAAIAAAAABABgAAAAAAAAwAAAAAAAAAAAAAAAA + AAAAAAAA//////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////v7//f7//P3//P3//P3/ + /f7//v7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v7//P3/ + +fv/+fv/+Pr/+fv/+vv//P3//v////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////f7/+fr/8/b/7PL/5+3/6e/+9Pf/+vv//v7///////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////P3/9/r/6O7/cXe1UVaet7z17fL/+Pr//f3///////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////+/z/9Pj/4Oj/NzyCUlOd2dz/6O//9Pf//P3///// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////+vv/8vb/2+P9X2OmREGLnqPd + 4+v/8vb/+/z///////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////+vv/8fb/ + 1N35bXK1JSRtbHGz5O7/8fX/+/z///////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////+vv/8PX/3Ob/U1eaDwtXjZLT4+z/8fX/+/z///////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////+vv/8fb/2eP+MjR6AAA+c3i34Or/8fX/+/z///////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////+vv/8vb/1d/7MS91AAA1UFSS4On/8vb/+/z///// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////+vv/8fb/2OL+NjZ7AAArX2Ok + 4uz/8fX/+/z///////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////+vv/8fb/ + 2eP/LjJ1DAxKfYTE4Or/8fX/+/z//////////////////////////////v7//v7//f7//f7//v7//v// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////+vv/8PX/3OX/gILIR0eVeoHC3eb/8fX/+/z//////////////////////v7//P3/+fv/+Pr/ + +Pr/+Pr/+vv//P3//v7///////////////////////////////////////////////////////////// + /////////////////////////////v7//f7//P3/+vv/+vv/+/z//f3//v7///////////////////// + ////////////////////////+vv/8PX/2eP9ZWeqHx1obnOz4Or/8fX/+/z//////////////////v7/ + +/z/9fj/8vb/8PX/7vT/8fb/9fj/+fr//f7///////////////////////////////////////////// + /////////////////////////////////////////v///P3/+Pr/9fj/9fj/9Pj/9Pf/9vn/+/z//v7/ + ////////////////////////////////////////+vv/8fb/2eP9ODp9AAA5jZDQ5O7/8PX/+/z///// + /////////v7/+/z/9Pf/7fP/5u//wsz6j5XfuMDx7fL/9vn//P3///////////////////////////// + /////////////////////////////////////////////////////////f7/+Pr/8/b/5+3/2eH/2uP/ + 5u3/7fP/8/b/+vv//f7/////////////////////////////////////+vv/8PX/3ef/U1ebBgVKio/O + 4uz/8fX/+/z//////////v///P3/9fj/7fP/4uv/hIzZHSWPAABmU1i14ub/9/r/+/z///////////// + /////////////////////////////////////////////////////////////////////////P3/9Pf/ + 7/X/09z/TlSzNzWYj5bh5O7/6/L/8vb/+fv//f7/////////////////////////////////+vv/8fX/ + 2eP/QUWIEhBZbnSz3uj/8fb/+/z//////////f7/+Pr/7/T/6PH/iI7cAABvAABqAABncXjK6O//9fj/ + +/z///////////////////////////////////////////////////////////////////////////// + ////////+/z/8/f/2uD/Z27EAABnAABiBgl4jJTd5vD/6O//8vX/+fv//f7///////////////////// + ////////+vv/8fb/2OP/Mjd6AQE6ZGup4er/8fX/+/z/////////+vz/8fX/6/T/xM/8ExyJAABwAABu + GySRxc387fT/9ff//P3///////////////////////////////////////////////////////////// + ////////////////////////+vz/8/f/1Nr/MzqhAABhAxOBAARyBgp5jpLg5Oz/7PP/9Pf/+vz//v7/ + ////////////////////////+vv/8fb/2eP/KCtvBwZOjJHS4Or/8fX/+/z//////f7/9/n/7fP/3+j/ + UFq3AABtAAZ3BAh6mZ/n5vD/7vP/+Pr//v7///////////////////////////////////////////// + ////////////////////////////////////////+/z/9Pj/6e//sbb1KzWcAABwBhaBAAFyAgp6fITR + 1d777/T/+Pr//f7/////////////////////////+vv/8PX/3+j/WF2hBglTnaTj5O3/8PX/+/z///// + /P3/9Pf/6vL/k5riAAByAAR0AABrY2vE4ur/6vH/9ff//P3///////////////////////////////// + /////////////////////////////////////////////////////////f3/9/n/7fL/5O3/ytX/RU6w + AABpAA5+AABuAABnhord6e7/+fv//f7/////////////////////////+vv/7/T/3+j/k5jbT1KdgYjJ + 3uf+8fX/+/z/////+/z/9fn/4ef/NDqhAABnAABrJjCU0Nn/5/D/8fX/+vv//v7///////////////// + /////////////////////////////////////////////////////////////////////////v7/+/z/ + 9vn/7vP/6vP/ztb/O0CmAABpAABrQkuoxMn57PH/+Pr//f7/////////////////////////+vv/8PX/ + 2+X/en/CUFGak5nY3+j/8fX//P3//////P3/9fj/4en/i5DbNT2hIyuTpqzv4uz/7vP/9/n//f7///// + //////////////////////////////////////////////////////////////////////////////// + /////////////v7//P3/9vn/7/P/6vL/ytH/X2i9XWi7wsf/6e//8/f/+Pr//v7///////////////// + ////////+vv/8PX/3OX/WF2hW1ylvMD+3uf/8PX/+/z//////f7/9vn/7fP/4uj/j5Pgf4LV3+X/6fD/ + 9Pf//P3///////////////////////////////////////////////////////////////////////// + /////////////////////////////////v///P3/+Pr/8vX/7fP/5+//5u7/6vD/8PT/9vn//P3//v7/ + /////////////////////f7/9/n/7fP/0tz9LDJzNjh/nqTk2uT/7fL/9/n//f7//f7/+fv/8/b/7PL/ + 3eX/zM//5ev/9fj/+fv//v7///////////////////////////////////////////////////////// + /////////////////////////////////////////////////////v///f3/+vv/9/n/9vn/9fj/9vn/ + +fr//P3//v7//////////////v///f7/+vv/9vn/7/T/5vD/2Ob/VFubERNdoajk4u//5O7/7vP/9vj/ + +fr/+vv/+Pr/9fj/9Pj/9fj/9fj/+Pr//P3///////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v///v7/ + /f7//P3//P3//f3//v7//v///////////////f7/+vz/9vn/8fX/7vT/5O3/3eb/z9n/cHjICxN5d37L + z9n/2eP/5O3/6/L/8PT/9Pf/9/n/+vv/+vv/+/z//P3//f3//v7///////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////P3/+Pr/8/b/7vT/6vL/z9r+jZjeQUeq + IiuQCBN3AAFrBRB8Nj2iUViym6XlydH/4+z/6/L/8PT/9/n/+/z//f7//v////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////f3/9/n/8fX/6/L/3uf/ + mKTkLzibAABoAAB0Fx+HDBh7FSGDAg16AABYAABlCBB/Ji2UhYza1+D/6PL/7fL/9Pf/+vv//f7///// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////v7//P3/9/n/ + 8PT/7PT/z9j/XmO+AABtAABcMDSXoajsu8X7VV+5hYzblZ/fTVSxFSKMAABkAABnAAN2Qkmpsbrz5e3/ + 6vH/8fX/+Pr//P3//v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////P3/9/n/8PX/7PT/vcn3LTOZAABaAgR1ZWzD0Nf/5vL/1OP/l53lzs3/6fP/4+7/sLzwZ23CBxSD + AABnAABlHiaSmqHo3+j/5+//7/T/9vn//P3//v7///////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////v7/ + /v7//v7//v7//f7/+/z/9vj/7vP/7PX/tcLzEBeGAABkPEWlqLPt2eX/4e7/3On/uMX1gofVe3vPhYzY + z93+5/X/4e3/lJ3gHiOPAABtAABqChiEbHLIytD/5/D/7PL/8/f/+Pr/+fr/+Pr/+Pr/+Pr/+Pr/+Pr/ + +Pr/+fv/+vv/+/z//f7//v7///////////////////////////////////////////////////////// + /v7//f7/+/z/+fv/9/n/9vj/9fj/9Pf/8fX/7PL/4uv/l6HgDhF7AAN4iZDe0d7/3uz/4vD/w83/VVm3 + ICiSAAFyAABlAABwaHTD1N//2un/3er/w838ZW3BEyOJJzKVAQ16NDmfwsn75fD/5u7/7PL/7vP/7fP/ + 7fP/7fL/7fP/7vP/7/T/8fb/9Pj/9vn/+fr//f3//v////////////////////////////////////// + /////////////v7//P3/+Pr/9Pf/8fX/7vT/7PL/6/L/6fH/5u7/6vX/tsD0CQx4AAFwkZvi7ff/4vD/ + 4fD/z9j/OkGlAABiAABwBxWAAAt7BBN+P0uofYLUztb/4O7/6fb/6fP/qa7xQkyoBg56AABqMjugx8/+ + 5fH/4Ov/4On/3uj/3eb/3+j/3uj/1+L/0d3/1d7/3+f/7fL/9vj/+vz//v7///////////////////// + /////////////////////////////f7/+fr/8/f/6/L/2d//v8j6vcf5ucP1wMv8wM3+vMj6PkqoAABo + UF25usP7tsPyvsr6sLrwQ0utAABqAAV1OUameIDRKDWZAAd2GyeOLDecmaHntsL0pbLom6riq7LzUlu0 + AANzBhR/AAZ0NT+ja3bBY2i/XGG6UViyWl65XGG7XGC6TVWvQU6pPkalODygqK7p8vb/+vz//v7///// + /////////////////////////////////////////////P3/9/n/7/T/wcj2R0ysExeFERmGDxuIFB6K + FBqICxSEAABsAAByDBiDCRSBBRCADhaFCRODAAh4AxF/AAl4CxeDHSaPAAp6AAN0AA19AAd3CBOBEBqH + BhGBAAh5AABwAAByAAh5BhSCAxWCAABsAABvAABlAABnAABxAABjAABmAABhAABdAABYAABhCAt/q7Lr + 8/f/+vv//v7//////////////////////////////////////////////////P3/+fv/3uT/SE2vAABn + CBB/GiCMLzmfLTWcGByJFRyKGCOOMj2gHymRDxiGGyOPLDCXBRF/AAh3BhaCEyKMICqTKC2WNDqfIzCV + Awx6Eh+JHiaPAAR3AAZ5CxSDICWQX2q7Q1CqAA1+AAFxDxuHiZTbVGC4dHnQnabrTVqzY23EUV62Slau + LjaZXWm9sLjz5ez/9vn/+fv//v7//////////////////////////////////////////////////P3/ + +Pv/4+n+e4LPfoPVpqv2vsf/zNX/zdb/xtH/v8v8pK7spKfysLb3vcr4ws784ej/hI/YAAZ1AAJzVF25 + yM//3Of/5+//i5LcAABpMzyfp6vxoKznlqHhqbbtx9H/8fz/kpvfAABiAABph4zc5PD/2OP/193/3un/ + 1+D/2OH/1+D/0Nr/zNL/3+j/6/L/7/T/9vn//P3//v////////////////////////////////////// + /////////////f7/+Pr/9Pf/6vD/5u3/3+b/4uv/6PD/5+//5O3/5/P/sL3sXmS7mZzoz9f/3+z/4e// + mKLiEiKKCBF/KTWZr7T06/f/3ev/VF2zChSBipPcz9v+4u7/3ur/3ev/5/X/qrPrISmSDRJ2Xmq/3ur/ + 4uv/6vH/7fP/7fL/7/T/7vP/7fP/7fP/8PX/8fX/9Pf/+Pr/+/z//v7///////////////////////// + /////////////////////////////v7//P3/+Pr/9vn/9Pf/8vb/8vb/8/b/9Pf/7/T/6/L/tL/ubXLH + en/Ti43gqavy0t3/nafjMj6fJzaaAAV1GyeOYmW7Nz6fAABgNj6i1N//3uz/2uX/3Oj/5PH/wcj7FR2J + AAN0gong0tr/6fH/7/P/9vj/+Pr/+fv/+fv/+Pr/+Pr/+Pr/+fv/+vv//P3//f7//v////////////// + /////////////////////////////////////////////////v7//f7//P3/+/z/+/z/+/z//f3//f7/ + +fv/8fX/5Oz/jpbfc3jObnXLcXfOk5rks7b4iY3dR1KvDhuEAABoAABlEBV9U12ytcD13Or/3en/3ej/ + 1eL/q7fvGR+MKDKZbnnNxc/76PD/8fX/+fr//f7//v///////v7//f7//f3//P3//f3//f7//v////// + /////////////////////////////////////////////////////v7//f7//P3//P3//f7//v7///// + /////////////////f7/9vn/7/T/yNH5lJrleoDVmZ3pmpzpc3nPfoTWf4bYVFy3HSaLZ3PGsrb8v8r8 + y9n9q7jre4LRf4fUgIvXAwZ1AABrhYjb0NX/6PH/8PX/+Pr//f7//////////v///f3/+vv/+Pr/9/r/ + 9/n/+Pr/+/z//f7//v7//////////////////////////////////////v///f7/+/z/+fr/9vj/9/n/ + +vz/+vv/+/z//v7//////////////////v7/+vz/8/f/7PL/2uT/t8H1srP6vcH+nKTnSlOxV2C7TVaz + WGS8QUqmSlSuSFOtR1GtbXTKVl23ARB5AAh2AABnd33P3eP/4ur/7/T/9/n//P3//////////////P3/ + 9/n/8vb/7PH/6fD/7PL/7vP/8vb/9vn/+/z//f7//////////////////////////////v7/+/z/+Pr/ + 8/b/7/T/8Pb/6vH/3eP97vL++fr//P3//////////////////////f7/+vv/9fj/7/T/5+//z9f+t7v4 + uLn9Z2zFLzucFCGIMz6gGCCMAAd4AAl2Dx2EER+GXWK8c3XLKzKXd4LP4er/6/L/8PX/9/n//P3//v// + /////////v7/+fv/8/b/7PP/y9H/i4/erLbt4er/5e3/7fP/8/b/+fv//f3//v7///////////////// + /v7/+/z/9vj/8PT/6/L/3+n/x9H9aHTAZGvG3+b9+Pr/+/z//////////////////////////v7/+/z/ + +Pr/8vb/6/H/3OX+wMn4maDmdHrPWGG6T1a1eoHWcHfOTlayUlq1SlKubHjAxMj/0dn/4+v/7PL/8vb/ + +Pr//P3//v7//////////////f7/+fr/7vP/xsv5YGXAHymRKjKYYWS9rbLz4u3/6/P/8vb/+fr//f7/ + /////////////v//+/z/9vj/7fL/5e3/xs7/Y23BIiiSAABeLTab3+b/9/r/+/z///////////////// + /////////////////f7/+vz/9vj/8PX/6vH/3eb/ydL8xM/6uMPyt733w8j/zNb/1Nz/3OT/4uz/5u7/ + 7fP/8vb/9vj/+vz//f7//////////////////////f7/+fv/7vP/jpHiAAJ1CxaBER6GAABoFRmGbXbH + 0Nf/7PL/9fj//P3//////////////v7/+fv/8/f/4Of/hYvbKDGZAABuAABdAAZyi5La5+7/9vn/+/z/ + /////////////////////////////////////v7//P3/+fv/9ff/8vb/7/X/7fP/6/L/5u3/5ez/6fD/ + 7PP/7/T/8fX/9Pf/9/n/+vv//P3//v7//v///////////////////////v7/+fv/8fb/2eH9fIbQExqH + AABrAAp6AAFyAABwS0+uztX39vn/+vz//////////////f7/+Pr/8ff/qbLpAABrAABhAABwDBWAfobX + 5e3/8PX/9vn//f3//////////v///f7/+/z/+vv/+vv/+vz//P3//v7//v///v7//P3/+vz/+Pr/9/n/ + 9vj/9vj/9vj/9vj/9/n/+fr/+/z//P3//f7//v7//f7//P3/+/z/+vz/+/z//P3//v7//////v7/+/z/ + 9fj/7/T/5/H/uML1U1e1AAh5AABuAABvMjmdv8bz9vr/+vv//////////////f7/+fv/7/T/iY7aDxSA + GiONa3XHsr7w4Oj/6/H/9Pf/+vz//v7//////v///P3/+Pr/9Pf/8/f/9fj/9fj/9vn/+/z//v7///// + /////////v7//f7//P3/+/z/+/z//P3//f7//v///////////////v7/+/z/9/n/9vn/9vn/9Pj/9vn/ + +/z//v7//////f7/+vz/9fj/7/T/6vL/3ef/i5PbGRqJBQl5jJbZ6vH/9Pj/+/z//////////////f7/ + +fv/8fT/1Nn9t7/0wcr54er/7fT/8fX/9fj/+vv//f7//////////f3/+Pr/8PT/6/L/3uX/ztb/5Or/ + 8/f/+Pr//f7//////////////f7/+vz/+Pr/+fv/+fv/+vv//f3//v///////////////P3/9/n/7vL/ + 193/ztf/5u3/7vP/9Pf/+/z//v7//////v7//P3/+Pr/8fX/7PP/5/D/sLfxoKnk4+r/8vf/9/n//f3/ + /////////////v7/+/z/9vn/9Pf/8vb/8fb/8fX/9Pf/+Pr//P3//v7//////////v7/+vv/8vb/5+7/ + y9H/WWO9KSmSkZXj6vD/+Pv//P3//////////f7/+Pr/9fj/8vb/6O7/7vP/9fj/+Pr//f7///////// + /v//+vv/8vb/7PP/hYraKiqKlp7i6PD/7fP/9ff/+/z//v7//////////f7/+vv/9ff/8fX/8PX/8vb/ + 8/f/9vn/+/z//v7//////////////////f7/+/z/+vv/+fr/+fr/+vv//P3//v7///////////////// + /P3/9fj/7PL/1d7/RUysAABhAABlg4ja6/D/+Pr//P3/////////+/z/9fj/6e7/2eD/h4/bnaXg7PH/ + 9fj/+/z//////////v7/+Pr/8PX/y9X1JDGVAABaERWDoKnp6PH/7vP/9/n//P3//////////////v7/ + /P3/+vv/+fv/+fv/+vv//P3//v7//////////////////////////v7//v7//v7//v7//v////////// + /////////////v7/+fv/8PX/7PX/ipPdAABsAABlQ1Cp3Ob/7vP/9/n//f7/////////+fv/9Pj/yNH5 + Ule2DBJ8Ljie0df+8fb/+fv//v7//////v7/+Pr/7/X/hY3YAABxAAl7AABuEBaEs7nz6fH/8fX/+vv/ + /v7//////////////////v///v7//v7//v7///////////////////////////////////////////// + /////////////////////////////f3/9vn/7PL/0tn/LzidAQFsAAB0iZHb6vP/8PT/+fv//v////// + /v7/+Pr/8vf/r7rqAAV4AABdPUen1N//7PL/9vn//f7//////v7/+fr/7/T/yc75S1G0AABrARKAAABp + Qker0df/7fP/9/n//f7///////////////////////////////////////////////////////////// + /////////////////////////////////////////////P3/9/n/5+7/cXXNAAd2AABuMDebzdT97PL/ + 9vj//P3//////////v7/9/n/7/X/tL/uFCCLAABqHSqRvcf46fD/9Pf//f3/////////+vv/8vX/6vH/ + yM3+JC2XAABtAAV2Agx9q7Ly7vT/9vn//f7///////////////////////////////////////////// + /////////////////////////////////////////////////////////////P3/9/r/4uj/WWO1AAVx + KTaYu8T07fT/8vb/+vv//v7//////////v7/9/n/7vX/vsn1Iy2SAABrAQ99mp/o6PD/9Pf//P3///// + /////P3/9/n/7vP/6fL/s7z2DBB/AABeQ0uttrr56e7/+Pr//f7///////////////////////////// + /////////////////////////////////////////////////////////////////////////////P3/ + +fv/4ef6g4zNbXfFw8v27fT/8vb/+Pr//f3//////////////v7/9/n/7vT/yNL7MjucAABtBxF/nKLo + 6fH/9Pf//P3//////////v7/+/z/9fj/7fL/6/T/jZXbLzScrrP14en/7fL/+fv//v7///////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////f7/+vz/8PP91dr34+f/8vb/8/f/9/r//P3//v///////////////v7/+Pr/8PX/1N3/ + QUqmAQRxBQ98m6Dm7PL/9fj//P3//////////////v7/+/z/9ff/8PX/5ez/ytH94ej/8vb/9vj/+/z/ + /v7///////////////////////////////////////////////////////////////////////////// + /////////////////////////////v7//P3/+vz/+fv/+Pr/+Pr/+vv//f3//v////////////////// + /v//+fv/9Pf/2+L/SVGtAABsLTaZytL58fX/9/n//f7//////////////////v7/+/z/9/n/9fj/9vn/ + 9fj/9vj/+vz//f7///////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////v7//f7//f3//f3//f3//v7//v////// + ////////////////////+/z/9vn/6e//mZ7gTVarr7bp6/H/9fj/+vv//v7///////////////////// + /v7//f7/+/z/+/z/+/z//P3//v7///////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////f3/+Pr/9fj/6e7/4+n/8fb/9Pf/+Pr//f3///////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////v7//P3/+fv/+fv/+vv/+Pr/+vv/ + /P3//v7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v7//f7/ + /f3//P3//f7//v7//v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////4D/////////AH////////8Af////////wB/////////AH////////8Af////////wB/////// + //AH////////8Af////////wB/////////AH////////8AfwP//////wB8Af//+Af/AHgB///wA/8AcA + H///AB/wBgAf//8AD/AGAB///wAH8AYAH///AAPwBAAf//8AA/AEAD///wAD8AQAP///AAPwBAB///+A + A/AEAP///8AD4AAA////4AcAAAH////wDgAAAf/////8AAAH//////gAAAf/////4AAAAf/////gAAAA + ////+AAAAAAAD//AAAAAAAAH/4AAAAAAAAf/gAAAAAAAB/+AAAAAAAAH/4AAAAAAAAf/gAAAAAAAB/+A + AAAAAAAP/4AAAAAAAB//wAAAAABAf/4HwAAAAYAf8APAAAADgA/gA+AAAAMAA8AD8AAABwADgAP8AAAf + AAOAA/4AAB8AA4ADAAAAAQADgAIAcA4AgAOABgBwDgBAA4AMAGAMADADwDwAYAwAOAfg+ABgBAAeH//4 + AEAEAB////gAwAYAH///+ADABgAf///4AcAGAB////gBwAcAH///+APAB4A////8B+AHwH//////4A// + ///////gD/////////Af//////////////8= + + + \ No newline at end of file diff --git a/CodeWalker/Project/Panels/EditYmapPanel.cs b/CodeWalker/Project/Panels/EditYmapPanel.cs index 74a3832..7b177f9 100644 --- a/CodeWalker/Project/Panels/EditYmapPanel.cs +++ b/CodeWalker/Project/Panels/EditYmapPanel.cs @@ -325,17 +325,9 @@ namespace CodeWalker.Project.Panels private void CalcYmapExtents() { + if (populatingui) return; if (Ymap == null) return; - var allents = Ymap.AllEntities; - var allbatches = Ymap.GrassInstanceBatches; - - if ((allents == null) && (allbatches == null)) - { - MessageBox.Show("No items to calculate extents from."); - return; - } - lock (ProjectForm.ProjectSyncRoot) { if (Ymap.CalcExtents()) diff --git a/CodeWalker/Project/Panels/ProjectExplorerPanel.cs b/CodeWalker/Project/Panels/ProjectExplorerPanel.cs index f0108ba..182a389 100644 --- a/CodeWalker/Project/Panels/ProjectExplorerPanel.cs +++ b/CodeWalker/Project/Panels/ProjectExplorerPanel.cs @@ -268,6 +268,32 @@ namespace CodeWalker.Project.Panels llnode.Tag = lodlight; } } + if ((ymap.BoxOccluders != null) && (ymap.BoxOccluders.Length > 0)) + { + var boxocclsnode = node.Nodes.Add("Box Occluders (" + ymap.BoxOccluders.Length.ToString() + ")"); + boxocclsnode.Name = "BoxOccluders"; + boxocclsnode.Tag = ymap; + var boxes = ymap.BoxOccluders; + for (int i = 0; i < boxes.Length; i++) + { + var box = boxes[i]; + var boxnode = boxocclsnode.Nodes.Add(box.ToString()); + boxnode.Tag = box; + } + } + if ((ymap.OccludeModels != null) && (ymap.OccludeModels.Length > 0)) + { + var occlmodsnode = node.Nodes.Add("Occlude Models (" + ymap.OccludeModels.Length.ToString() + ")"); + occlmodsnode.Name = "OccludeModels"; + occlmodsnode.Tag = ymap; + var models = ymap.OccludeModels; + for (int i = 0; i < models.Length; i++) + { + var model = models[i]; + var modnode = occlmodsnode.Nodes.Add(model.ToString()); + modnode.Tag = model; + } + } if ((ymap.GrassInstanceBatches != null) && (ymap.GrassInstanceBatches.Length > 0)) { var grassbatchesnodes = node.Nodes.Add("Grass Batches (" + ymap.GrassInstanceBatches.Length.ToString() + ")"); @@ -1040,6 +1066,48 @@ namespace CodeWalker.Project.Panels } return null; } + public TreeNode FindBoxOccluderTreeNode(YmapBoxOccluder box) + { + if (box == null) return null; + TreeNode ymapnode = FindYmapTreeNode(box.Ymap); + if (ymapnode == null) return null; + var boxesnode = GetChildTreeNode(ymapnode, "BoxOccluders"); + if (boxesnode == null) return null; + for (int i = 0; i < boxesnode.Nodes.Count; i++) + { + TreeNode boxnode = boxesnode.Nodes[i]; + if (boxnode.Tag == box) return boxnode; + } + return null; + } + public TreeNode FindOccludeModelTreeNode(YmapOccludeModel model) + { + if (model == null) return null; + TreeNode ymapnode = FindYmapTreeNode(model.Ymap); + if (ymapnode == null) return null; + var modelsnode = GetChildTreeNode(ymapnode, "OccludeModels"); + if (modelsnode == null) return null; + for (int i = 0; i < modelsnode.Nodes.Count; i++) + { + TreeNode modelnode = modelsnode.Nodes[i]; + if (modelnode.Tag == model) return modelnode; + } + return null; + } + public TreeNode FindOccludeModelTriangleTreeNode(YmapOccludeModelTriangle tri) + { + if (tri == null) return null; + TreeNode ymapnode = FindYmapTreeNode(tri.Ymap); + if (ymapnode == null) return null; + var modelsnode = GetChildTreeNode(ymapnode, "OccludeModels"); + if (modelsnode == null) return null; + for (int i = 0; i < modelsnode.Nodes.Count; i++) + { + TreeNode modelnode = modelsnode.Nodes[i]; + if (modelnode.Tag == tri.Model) return modelnode; + } + return null; + } public TreeNode FindGrassTreeNode(YmapGrassInstanceBatch batch) { if (batch == null) return null; @@ -1519,6 +1587,53 @@ namespace CodeWalker.Project.Panels } } } + public void TrySelectBoxOccluderTreeNode(YmapBoxOccluder box) + { + TreeNode boxnode = FindBoxOccluderTreeNode(box); + if (boxnode != null) + { + if (ProjectTreeView.SelectedNode == boxnode) + { + OnItemSelected?.Invoke(box); + } + else + { + ProjectTreeView.SelectedNode = boxnode; + } + } + } + public void TrySelectOccludeModelTreeNode(YmapOccludeModel model) + { + TreeNode modelnode = FindOccludeModelTreeNode(model); + if (modelnode != null) + { + if (ProjectTreeView.SelectedNode == modelnode) + { + OnItemSelected?.Invoke(model); + } + else + { + ProjectTreeView.SelectedNode = modelnode; + } + } + } + public void TrySelectOccludeModelTriangleTreeNode(YmapOccludeModelTriangle tri) + { + TreeNode trinode = FindOccludeModelTriangleTreeNode(tri); + if (trinode != null) + { + if (ProjectTreeView.SelectedNode == trinode) + { + OnItemSelected?.Invoke(tri); + } + else + { + trinode.Tag = tri;//hack to allow the model's node to be selected instead + ProjectTreeView.SelectedNode = trinode; + trinode.Tag = tri.Model; + } + } + } public void TrySelectGrassBatchTreeNode(YmapGrassInstanceBatch grassBatch) { TreeNode grassNode = FindGrassTreeNode(grassBatch); @@ -2024,6 +2139,22 @@ namespace CodeWalker.Project.Panels tn.Text = lodlight.ToString(); } } + public void UpdateBoxOccluderTreeNode(YmapBoxOccluder box) + { + var tn = FindBoxOccluderTreeNode(box); + if (tn != null) + { + tn.Text = box.ToString(); + } + } + public void UpdateOccludeModelTreeNode(YmapOccludeModel model) + { + var tn = FindOccludeModelTreeNode(model); + if (tn != null) + { + tn.Text = model.ToString(); + } + } public void UpdatePathNodeTreeNode(YndNode node) { var tn = FindPathNodeTreeNode(node); @@ -2143,6 +2274,50 @@ namespace CodeWalker.Project.Panels } } } + public void RemoveBoxOccluderTreeNode(YmapBoxOccluder box) + { + var ymap = box?.Ymap; + var tn = FindBoxOccluderTreeNode(box); + if ((tn != null) && (tn.Parent != null) && (box != null)) + { + var pn = tn.Parent; + var yn = pn.Parent; + yn.Nodes.Remove(pn); + pn = yn.Nodes.Add("Box Occluders (" + (ymap?.BoxOccluders?.Length.ToString() ?? "0") + ")"); + pn.Name = "BoxOccluders"; + pn.Tag = ymap; + if (ymap.BoxOccluders != null) + { + foreach (var b in ymap.BoxOccluders) + { + var ntn = pn.Nodes.Add(b.ToString()); + ntn.Tag = b; + } + } + } + } + public void RemoveOccludeModelTreeNode(YmapOccludeModel model) + { + var ymap = model?.Ymap; + var tn = FindOccludeModelTreeNode(model); + if ((tn != null) && (tn.Parent != null) && (model != null)) + { + var pn = tn.Parent; + var yn = pn.Parent; + yn.Nodes.Remove(pn); + pn = yn.Nodes.Add("Occlude Models (" + (ymap?.OccludeModels?.Length.ToString() ?? "0") + ")"); + pn.Name = "OccludeModels"; + pn.Tag = ymap; + if (ymap.OccludeModels != null) + { + foreach (var m in ymap.OccludeModels) + { + var ntn = pn.Nodes.Add(m.ToString()); + ntn.Tag = m; + } + } + } + } public void RemoveGrassBatchTreeNode(YmapGrassInstanceBatch batch) { var tn = FindGrassTreeNode(batch); diff --git a/CodeWalker/Project/ProjectForm.cs b/CodeWalker/Project/ProjectForm.cs index dcac3bd..f8bc134 100644 --- a/CodeWalker/Project/ProjectForm.cs +++ b/CodeWalker/Project/ProjectForm.cs @@ -43,6 +43,9 @@ namespace CodeWalker.Project private YmapEntityDef CurrentEntity; private YmapCarGen CurrentCarGen; private YmapLODLight CurrentLodLight; + private YmapBoxOccluder CurrentBoxOccluder; + private YmapOccludeModel CurrentOccludeModel; + private YmapOccludeModelTriangle CurrentOccludeModelTri; private YmapGrassInstanceBatch CurrentGrassBatch; private YtypFile CurrentYtypFile; @@ -395,6 +398,27 @@ namespace CodeWalker.Project (panel) => { panel.SetLodLight(CurrentLodLight); }, //updateFunc (panel) => { return panel.CurrentLodLight == CurrentLodLight; }); //findFunc } + public void ShowEditYmapBoxOccluderPanel(bool promote) + { + ShowPanel(promote, + () => { return new EditYmapBoxOccluderPanel(this); }, //createFunc + (panel) => { panel.SetBoxOccluder(CurrentBoxOccluder); }, //updateFunc + (panel) => { return panel.CurrentBoxOccluder == CurrentBoxOccluder; }); //findFunc + } + public void ShowEditYmapOccludeModelPanel(bool promote) + { + ShowPanel(promote, + () => { return new EditYmapOccludeModelPanel(this); }, //createFunc + (panel) => { panel.SetOccludeModel(CurrentOccludeModel); }, //updateFunc + (panel) => { return panel.CurrentOccludeModel == CurrentOccludeModel; }); //findFunc + } + public void ShowEditYmapOccludeModelTrianglePanel(bool promote) + { + ShowPanel(promote, + () => { return new EditYmapOccludeModelPanel(this); }, //createFunc + (panel) => { panel.SetOccludeModelTriangle(CurrentOccludeModelTri); }, //updateFunc + (panel) => { return panel.CurrentOccludeModel == CurrentOccludeModel; }); //findFunc + } public void ShowEditYmapGrassBatchPanel(bool promote) { ShowPanel(promote, @@ -642,6 +666,18 @@ namespace CodeWalker.Project { ShowEditYmapLodLightPanel(promote); } + else if (CurrentBoxOccluder != null) + { + ShowEditYmapBoxOccluderPanel(promote); + } + else if (CurrentOccludeModelTri != null) + { + ShowEditYmapOccludeModelTrianglePanel(promote); + } + else if (CurrentOccludeModel != null) + { + ShowEditYmapOccludeModelPanel(promote); + } else if (CurrentGrassBatch != null) { ShowEditYmapGrassBatchPanel(promote); @@ -769,6 +805,9 @@ namespace CodeWalker.Project CurrentEntity = item as YmapEntityDef; CurrentCarGen = item as YmapCarGen; CurrentLodLight = item as YmapLODLight; + CurrentBoxOccluder = item as YmapBoxOccluder; + CurrentOccludeModelTri = item as YmapOccludeModelTriangle; + CurrentOccludeModel = (item as YmapOccludeModel) ?? CurrentOccludeModelTri?.Model; CurrentGrassBatch = item as YmapGrassInstanceBatch; CurrentYtypFile = item as YtypFile; CurrentArchetype = item as Archetype; @@ -841,6 +880,18 @@ namespace CodeWalker.Project { CurrentYmapFile = CurrentLodLight.Ymap; } + else if (CurrentBoxOccluder != null) + { + CurrentYmapFile = CurrentBoxOccluder.Ymap; + } + else if (CurrentOccludeModel != null) + { + CurrentYmapFile = CurrentOccludeModel.Ymap; + } + else if (CurrentOccludeModelTri != null) + { + CurrentYmapFile = CurrentOccludeModelTri.Ymap; + } else if (CurrentGrassBatch != null) { CurrentYmapFile = CurrentGrassBatch.Ymap; @@ -1571,6 +1622,9 @@ namespace CodeWalker.Project else if (sel.CollisionBounds != null) return NewCollisionBounds(sel.CollisionBounds.Type, sel.CollisionBounds, copyPosition, selectNew); else if (sel.EntityDef != null) return NewEntity(sel.EntityDef, copyPosition, selectNew); else if (sel.CarGenerator != null) return NewCarGen(sel.CarGenerator, copyPosition, selectNew); + else if (sel.LodLight != null) return NewLodLight(sel.LodLight, copyPosition, selectNew); + else if (sel.BoxOccluder != null) return NewBoxOccluder(sel.BoxOccluder, copyPosition, selectNew); + else if (sel.OccludeModelTri != null) return NewOccludeModelTriangle(sel.OccludeModelTri, copyPosition, selectNew); else if (sel.PathNode != null) return NewPathNode(sel.PathNode, copyPosition, selectNew); else if (sel.NavPoly != null) return NewNavPoly(sel.NavPoly, copyPosition, selectNew); else if (sel.NavPoint != null) return NewNavPoint(sel.NavPoint, copyPosition, selectNew); @@ -1596,6 +1650,9 @@ namespace CodeWalker.Project else if (sel.CollisionBounds != null) DeleteCollisionBounds(); else if (sel.EntityDef != null) DeleteEntity(); else if (sel.CarGenerator != null) DeleteCarGen(); + else if (sel.LodLight != null) DeleteLodLight(); + else if (sel.BoxOccluder != null) DeleteBoxOccluder(); + else if (sel.OccludeModelTri != null) DeleteOccludeModelTriangle(); else if (sel.PathNode != null) DeletePathNode(); else if (sel.NavPoly != null) DeleteNavPoly(); else if (sel.NavPoint != null) DeleteNavPoint(); @@ -1613,6 +1670,9 @@ namespace CodeWalker.Project else if (sel.CollisionBounds != null) SetProjectItem(sel.CollisionBounds, false); else if (sel.EntityDef != null) SetProjectItem(sel.EntityDef, false); else if (sel.CarGenerator != null) SetProjectItem(sel.CarGenerator, false); + else if (sel.LodLight != null) SetProjectItem(sel.LodLight, false); + else if (sel.BoxOccluder != null) SetProjectItem(sel.BoxOccluder, false); + else if (sel.OccludeModelTri != null) SetProjectItem(sel.OccludeModelTri, false); else if (sel.PathNode != null) SetProjectItem(sel.PathNode, false); else if (sel.NavPoly != null) SetProjectItem(sel.NavPoly, false); else if (sel.NavPoint != null) SetProjectItem(sel.NavPoint, false); @@ -2439,6 +2499,364 @@ namespace CodeWalker.Project return CurrentLodLight == lodlight; } + public YmapBoxOccluder NewBoxOccluder(YmapBoxOccluder copy = null, bool copyPosition = false, bool selectNew = true) + { + if (CurrentYmapFile == null) return null; + + Vector3 pos = GetSpawnPos(10.0f); + + YmapBoxOccluder bo; + + if (copy != null) + { + bo = new YmapBoxOccluder(CurrentYmapFile, copy._Box); + } + else + { + bo = new YmapBoxOccluder(CurrentYmapFile, new BoxOccluder()); + //... + } + + if (!copyPosition || (copy == null)) + { + bo.Position = pos; + } + + + + if (WorldForm != null) + { + lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... + { + CurrentYmapFile.AddBoxOccluder(bo); + } + + WorldForm.UpdateBoxOccluderGraphics(bo); + + } + else + { + CurrentYmapFile.AddBoxOccluder(bo); + } + + + if (selectNew) + { + LoadProjectTree(); + ProjectExplorer?.TrySelectBoxOccluderTreeNode(bo); + CurrentBoxOccluder = bo; + ShowEditYmapBoxOccluderPanel(false); + } + return bo; + } + public void AddBoxOccluderToProject() + { + if (CurrentBoxOccluder == null) return; + + if (!YmapExistsInProject(CurrentBoxOccluder.Ymap)) + { + var box = CurrentBoxOccluder; + + CurrentYmapFile = box.Ymap; + CurrentYmapFile.HasChanged = true; + AddYmapToProject(CurrentYmapFile); + + CurrentBoxOccluder = box; //bug fix for some reason the treeview selects the project node here. + CurrentYmapFile = box.Ymap; + ProjectExplorer?.TrySelectBoxOccluderTreeNode(box); + } + } + public bool DeleteBoxOccluder() + { + if (CurrentYmapFile == null) return false; + if (CurrentBoxOccluder == null) return false; + if (CurrentBoxOccluder.Ymap != CurrentYmapFile) return false; + + //if (MessageBox.Show("Are you sure you want to delete this box occluder?\n" + CurrentBoxOccluder.ToString() + "\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) + //{ + // return true; + //} + + var delbox = CurrentBoxOccluder; + + bool res = false; + if (WorldForm != null) + { + lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... + { + res = CurrentYmapFile.RemoveBoxOccluder(CurrentBoxOccluder); + //WorldForm.SelectItem(null, null, null); + } + } + else + { + res = CurrentYmapFile.RemoveBoxOccluder(CurrentBoxOccluder); + } + if (!res) + { + MessageBox.Show("Unable to delete the box occluder. This shouldn't happen!"); + } + + ProjectExplorer?.RemoveBoxOccluderTreeNode(CurrentBoxOccluder); + ProjectExplorer?.SetYmapHasChanged(CurrentYmapFile, true); + + ClosePanel((EditYmapBoxOccluderPanel p) => { return p.Tag == delbox; }); + + CurrentBoxOccluder = null; + CurrentYmapFile = null; + + if (WorldForm != null) + { + WorldForm.SelectItem(null); + } + + return true; + } + public bool IsCurrentBoxOccluder(YmapBoxOccluder box) + { + return CurrentBoxOccluder == box; + } + + public YmapOccludeModel NewOccludeModel(YmapOccludeModel copy = null, bool copyPosition = false, bool selectNew = true) + { + if (CurrentYmapFile == null) return null; + + Vector3 pos = GetSpawnPos(10.0f); + + YmapOccludeModel om; + + if (copy != null) + { + om = new YmapOccludeModel(CurrentYmapFile, copy._OccludeModel); + } + else + { + om = new YmapOccludeModel(CurrentYmapFile, new OccludeModel()); + //... + } + + if (!copyPosition || (copy == null)) + { + //om.Center = pos; + } + + + + if (WorldForm != null) + { + lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... + { + CurrentYmapFile.AddOccludeModel(om); + } + + WorldForm.UpdateOccludeModelGraphics(om); + + } + else + { + CurrentYmapFile.AddOccludeModel(om); + } + + + if (selectNew) + { + LoadProjectTree(); + ProjectExplorer?.TrySelectOccludeModelTreeNode(om); + CurrentOccludeModel = om; + ShowEditYmapOccludeModelPanel(false); + } + return om; + } + public void AddOccludeModelToProject() + { + if (CurrentOccludeModel == null) return; + + if (!YmapExistsInProject(CurrentOccludeModel.Ymap)) + { + var model = CurrentOccludeModel; + + CurrentYmapFile = model.Ymap; + CurrentYmapFile.HasChanged = true; + AddYmapToProject(CurrentYmapFile); + + CurrentOccludeModel = model; //bug fix for some reason the treeview selects the project node here. + CurrentYmapFile = model.Ymap; + ProjectExplorer?.TrySelectOccludeModelTreeNode(model); + } + } + public bool DeleteOccludeModel() + { + if (CurrentYmapFile == null) return false; + if (CurrentOccludeModel == null) return false; + if (CurrentOccludeModel.Ymap != CurrentYmapFile) return false; + + //if (MessageBox.Show("Are you sure you want to delete this occlude model?\n" + CurrentOccludeModel.ToString() + "\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) + //{ + // return true; + //} + + var delmodel = CurrentOccludeModel; + + bool res = false; + if (WorldForm != null) + { + lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... + { + res = CurrentYmapFile.RemoveOccludeModel(CurrentOccludeModel); + //WorldForm.SelectItem(null, null, null); + } + } + else + { + res = CurrentYmapFile.RemoveOccludeModel(CurrentOccludeModel); + } + if (!res) + { + MessageBox.Show("Unable to delete the occlude model. This shouldn't happen!"); + } + + ProjectExplorer?.RemoveOccludeModelTreeNode(CurrentOccludeModel); + ProjectExplorer?.SetYmapHasChanged(CurrentYmapFile, true); + + ClosePanel((EditYmapOccludeModelPanel p) => { return p.Tag == delmodel; }); + + CurrentOccludeModel = null; + CurrentYmapFile = null; + + if (WorldForm != null) + { + WorldForm.SelectItem(null); + } + + return true; + } + public bool IsCurrentOccludeModel(YmapOccludeModel model) + { + return CurrentOccludeModel == model; + } + + public YmapOccludeModelTriangle NewOccludeModelTriangle(YmapOccludeModelTriangle copy = null, bool copyPosition = false, bool selectNew = true) + { + if (CurrentYmapFile == null) return null; + + Vector3 pos = GetSpawnPos(10.0f); + + YmapOccludeModelTriangle ot; + + if (copy != null) + { + ot = new YmapOccludeModelTriangle(copy.Model, copy.Corner1, copy.Corner2, copy.Corner3, copy.Model.Triangles?.Length ?? 0); + } + else + { + ot = new YmapOccludeModelTriangle(CurrentOccludeModel, pos, pos + Vector3.UnitY, pos + Vector3.UnitX, CurrentOccludeModel?.Triangles?.Length ?? 0); + //... + } + + if (!copyPosition || (copy == null)) + { + //om.Center = pos; + } + + + + if (WorldForm != null) + { + lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... + { + CurrentYmapFile.AddOccludeModelTriangle(ot); + } + + WorldForm.UpdateOccludeModelGraphics(ot.Model); + + } + else + { + CurrentYmapFile.AddOccludeModelTriangle(ot); + } + + + if (selectNew) + { + LoadProjectTree(); + ProjectExplorer?.TrySelectOccludeModelTriangleTreeNode(ot); + CurrentOccludeModel = ot.Model; + CurrentOccludeModelTri = ot; + ShowEditYmapOccludeModelTrianglePanel(false); + } + return ot; + } + public void AddOccludeModelTriangleToProject() + { + if (CurrentOccludeModelTri == null) return; + + if (!YmapExistsInProject(CurrentOccludeModelTri.Ymap)) + { + var tri = CurrentOccludeModelTri; + + CurrentYmapFile = tri.Ymap; + CurrentYmapFile.HasChanged = true; + AddYmapToProject(CurrentYmapFile); + + CurrentOccludeModelTri = tri; //bug fix for some reason the treeview selects the project node here. + CurrentOccludeModel = tri.Model; + CurrentYmapFile = tri.Ymap; + ProjectExplorer?.TrySelectOccludeModelTriangleTreeNode(tri); + } + } + public bool DeleteOccludeModelTriangle() + { + if (CurrentYmapFile == null) return false; + if (CurrentOccludeModelTri == null) return false; + if (CurrentOccludeModelTri.Ymap != CurrentYmapFile) return false; + + //if (MessageBox.Show("Are you sure you want to delete this occlude model triangle?\n" + CurrentOccludeModelTri.ToString() + "\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) + //{ + // return true; + //} + + var deltri = CurrentOccludeModelTri; + + bool res = false; + if (WorldForm != null) + { + lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... + { + res = CurrentYmapFile.RemoveOccludeModelTriangle(CurrentOccludeModelTri); + //WorldForm.SelectItem(null, null, null); + } + } + else + { + res = CurrentYmapFile.RemoveOccludeModelTriangle(CurrentOccludeModelTri); + } + if (!res) + { + MessageBox.Show("Unable to delete the occlude model triangle. This shouldn't happen!"); + } + + ProjectExplorer?.UpdateOccludeModelTreeNode(CurrentOccludeModelTri?.Model); + ProjectExplorer?.SetYmapHasChanged(CurrentYmapFile, true); + + ClosePanel((EditYmapOccludeModelPanel p) => { return p.CurrentTriangle == deltri; }); + + CurrentOccludeModelTri = null; + CurrentOccludeModel = null; + CurrentYmapFile = null; + + if (WorldForm != null) + { + WorldForm.UpdateOccludeModelGraphics(deltri.Model); + WorldForm.SelectItem(null); + } + + return true; + } + public bool IsCurrentOccludeModelTriangle(YmapOccludeModelTriangle tri) + { + return CurrentOccludeModelTri == tri; + } + private void ImportMenyooXml() { if (CurrentProjectFile == null) @@ -7043,6 +7461,8 @@ namespace CodeWalker.Project var ent = sel.EntityDef; var cargen = sel.CarGenerator; var lodlight = sel.LodLight; + var boxoccluder = sel.BoxOccluder; + var occludetri = sel.OccludeModelTri; var grassbatch = sel.GrassBatch; var collvert = sel.CollisionVertex; var collpoly = sel.CollisionPoly; @@ -7058,7 +7478,7 @@ namespace CodeWalker.Project 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; - YmapFile ymap = ent?.Ymap ?? cargen?.Ymap ?? lodlight?.Ymap ?? grassbatch?.Ymap ?? mlo?.Ymap; + YmapFile ymap = ent?.Ymap ?? cargen?.Ymap ?? lodlight?.Ymap ?? boxoccluder?.Ymap ?? occludetri?.Ymap ?? grassbatch?.Ymap ?? mlo?.Ymap; YbnFile ybn = collbound?.GetRootYbn(); YndFile ynd = pathnode?.Ynd; YnvFile ynv = navpoly?.Ynv ?? navpoint?.Ynv ?? navportal?.Ynv; @@ -7081,6 +7501,14 @@ namespace CodeWalker.Project { ProjectExplorer?.TrySelectLodLightTreeNode(lodlight); } + if (wasmult || (boxoccluder != CurrentBoxOccluder)) + { + ProjectExplorer?.TrySelectBoxOccluderTreeNode(boxoccluder); + } + if (wasmult || (occludetri != CurrentOccludeModelTri)) + { + ProjectExplorer?.TrySelectOccludeModelTriangleTreeNode(occludetri); + } if (wasmult || (grassbatch != CurrentGrassBatch)) { ProjectExplorer?.TrySelectGrassBatchTreeNode(grassbatch); @@ -7185,6 +7613,9 @@ namespace CodeWalker.Project CurrentEntity = ent ?? mlo; CurrentCarGen = cargen; CurrentLodLight = lodlight; + CurrentBoxOccluder = boxoccluder; + CurrentOccludeModelTri = occludetri; + CurrentOccludeModel = occludetri?.Model; CurrentGrassBatch = grassbatch; CurrentYbnFile = ybn; CurrentCollisionVertex = collvert; @@ -7256,6 +7687,14 @@ namespace CodeWalker.Project { OnWorldLodLightModified(sel.LodLight); } + else if (sel.BoxOccluder != null) + { + OnWorldBoxOccluderModified(sel.BoxOccluder); + } + else if (sel.OccludeModelTri != null) + { + OnWorldOccludeModelTriModified(sel.OccludeModelTri); + } else if (sel.PathNode != null) { OnWorldPathNodeModified(sel.PathNode, sel.PathLink); @@ -7437,6 +7876,76 @@ namespace CodeWalker.Project } } + } + private void OnWorldBoxOccluderModified(YmapBoxOccluder box) + { + if (box?.Ymap == null) return; + + if (CurrentProjectFile == null) + { + NewProject(); + } + + if (!YmapExistsInProject(box.Ymap)) + { + box.Ymap.HasChanged = true; + AddYmapToProject(box.Ymap); + ProjectExplorer?.TrySelectBoxOccluderTreeNode(box); + } + + if (box != CurrentBoxOccluder) + { + CurrentBoxOccluder = box; + ProjectExplorer?.TrySelectBoxOccluderTreeNode(box); + } + + if (box == CurrentBoxOccluder) + { + ShowEditYmapBoxOccluderPanel(false); + + ProjectExplorer?.UpdateBoxOccluderTreeNode(box); + + if (box.Ymap != null) + { + SetYmapHasChanged(true); + } + } + + } + private void OnWorldOccludeModelTriModified(YmapOccludeModelTriangle tri) + { + if (tri?.Ymap == null) return; + + if (CurrentProjectFile == null) + { + NewProject(); + } + + if (!YmapExistsInProject(tri.Ymap)) + { + tri.Ymap.HasChanged = true; + AddYmapToProject(tri.Ymap); + ProjectExplorer?.TrySelectOccludeModelTriangleTreeNode(tri); + } + + if (tri != CurrentOccludeModelTri) + { + CurrentOccludeModelTri = tri; + ProjectExplorer?.TrySelectOccludeModelTriangleTreeNode(tri); + } + + if (tri == CurrentOccludeModelTri) + { + ShowEditYmapOccludeModelTrianglePanel(false); + + //ProjectExplorer?.UpdateOccludeModelTriangleTreeNode(tri); + + if (tri.Ymap != null) + { + SetYmapHasChanged(true); + } + } + } private void OnWorldCollisionVertexModified(BoundVertex vert) { diff --git a/CodeWalker/Project/UndoStep.cs b/CodeWalker/Project/UndoStep.cs index a2edf8f..d7a93f2 100644 --- a/CodeWalker/Project/UndoStep.cs +++ b/CodeWalker/Project/UndoStep.cs @@ -597,6 +597,259 @@ namespace CodeWalker.Project } + public abstract class BoxOccluderUndoStep : UndoStep + { + public YmapBoxOccluder BoxOccluder { get; set; } + + protected void UpdateGraphics(WorldForm wf) + { + if (BoxOccluder != null) + { + wf.UpdateBoxOccluderGraphics(BoxOccluder); + } + } + } + public class BoxOccluderPositionUndoStep : BoxOccluderUndoStep + { + public Vector3 StartPosition { get; set; } + public Vector3 EndPosition { get; set; } + + public BoxOccluderPositionUndoStep(YmapBoxOccluder box, Vector3 startpos) + { + BoxOccluder = box; + StartPosition = startpos; + EndPosition = box?.Position ?? Vector3.Zero; + } + + private void Update(WorldForm wf, ref MapSelection sel, Vector3 p) + { + BoxOccluder.Position = p; + + if (BoxOccluder != sel.BoxOccluder) wf.SelectObject(BoxOccluder); + wf.SetWidgetPosition(p); + + UpdateGraphics(wf); + } + + public override void Undo(WorldForm wf, ref MapSelection sel) + { + Update(wf, ref sel, StartPosition); + } + + public override void Redo(WorldForm wf, ref MapSelection sel) + { + Update(wf, ref sel, EndPosition); + } + + public override string ToString() + { + return "BoxOccluder " + (BoxOccluder?.Index.ToString() ?? "") + ": Position"; + } + } + public class BoxOccluderRotationUndoStep : BoxOccluderUndoStep + { + public Quaternion StartRotation { get; set; } + public Quaternion EndRotation { get; set; } + + public BoxOccluderRotationUndoStep(YmapBoxOccluder box, Quaternion startrot) + { + BoxOccluder = box; + StartRotation = startrot; + EndRotation = box?.Orientation ?? Quaternion.Identity; + } + + + private void Update(WorldForm wf, ref MapSelection sel, Quaternion q) + { + BoxOccluder.Orientation = q; + + if (BoxOccluder != sel.BoxOccluder) wf.SelectObject(BoxOccluder); + wf.SetWidgetRotation(q); + + UpdateGraphics(wf); + } + + public override void Undo(WorldForm wf, ref MapSelection sel) + { + Update(wf, ref sel, StartRotation); + } + + public override void Redo(WorldForm wf, ref MapSelection sel) + { + Update(wf, ref sel, EndRotation); + } + + public override string ToString() + { + return "BoxOccluder " + (BoxOccluder?.Index.ToString() ?? "") + ": Rotation"; + } + } + public class BoxOccluderScaleUndoStep : BoxOccluderUndoStep + { + public Vector3 StartScale { get; set; } + public Vector3 EndScale { get; set; } + + public BoxOccluderScaleUndoStep(YmapBoxOccluder box, Vector3 startscale) + { + BoxOccluder = box; + StartScale = startscale; + EndScale = box?.Size ?? new Vector3(1.0f); + } + + private void Update(WorldForm wf, ref MapSelection sel, Vector3 s) + { + BoxOccluder.SetSize(s); + + if (BoxOccluder != sel.BoxOccluder) wf.SelectObject(BoxOccluder); + wf.SetWidgetScale(s); + + UpdateGraphics(wf); + } + + + public override void Undo(WorldForm wf, ref MapSelection sel) + { + Update(wf, ref sel, StartScale); + } + + public override void Redo(WorldForm wf, ref MapSelection sel) + { + Update(wf, ref sel, EndScale); + } + + public override string ToString() + { + return "BoxOccluder " + (BoxOccluder?.Index.ToString() ?? "") + ": Scale"; + } + } + + + public abstract class OccludeModelTriUndoStep : UndoStep + { + public YmapOccludeModelTriangle OccludeModelTri { get; set; } + + protected void UpdateGraphics(WorldForm wf) + { + if (OccludeModelTri != null) + { + wf.UpdateOccludeModelGraphics(OccludeModelTri.Model); + } + } + } + public class OccludeModelTriPositionUndoStep : OccludeModelTriUndoStep + { + public Vector3 StartPosition { get; set; } + public Vector3 EndPosition { get; set; } + + public OccludeModelTriPositionUndoStep(YmapOccludeModelTriangle tri, Vector3 startpos) + { + OccludeModelTri = tri; + StartPosition = startpos; + EndPosition = tri?.Center ?? Vector3.Zero; + } + + private void Update(WorldForm wf, ref MapSelection sel, Vector3 p) + { + OccludeModelTri.Center = p; + + if (OccludeModelTri != sel.OccludeModelTri) wf.SelectObject(OccludeModelTri); + wf.SetWidgetPosition(p); + + UpdateGraphics(wf); + } + + public override void Undo(WorldForm wf, ref MapSelection sel) + { + Update(wf, ref sel, StartPosition); + } + + public override void Redo(WorldForm wf, ref MapSelection sel) + { + Update(wf, ref sel, EndPosition); + } + + public override string ToString() + { + return "OccludeModel Triangle " + (OccludeModelTri?.Index.ToString() ?? "") + ": Position"; + } + } + public class OccludeModelTriRotationUndoStep : OccludeModelTriUndoStep + { + public Quaternion StartRotation { get; set; } + public Quaternion EndRotation { get; set; } + + public OccludeModelTriRotationUndoStep(YmapOccludeModelTriangle tri, Quaternion startrot) + { + OccludeModelTri = tri; + StartRotation = startrot; + EndRotation = tri?.Orientation ?? Quaternion.Identity; + } + + + private void Update(WorldForm wf, ref MapSelection sel, Quaternion q) + { + OccludeModelTri.Orientation = q; + + if (OccludeModelTri != sel.OccludeModelTri) wf.SelectObject(OccludeModelTri); + wf.SetWidgetRotation(q); + + UpdateGraphics(wf); + } + + public override void Undo(WorldForm wf, ref MapSelection sel) + { + Update(wf, ref sel, StartRotation); + } + + public override void Redo(WorldForm wf, ref MapSelection sel) + { + Update(wf, ref sel, EndRotation); + } + + public override string ToString() + { + return "OccludeModel Triangle " + (OccludeModelTri?.Index.ToString() ?? "") + ": Rotation"; + } + } + public class OccludeModelTriScaleUndoStep : OccludeModelTriUndoStep + { + public Vector3 StartScale { get; set; } + public Vector3 EndScale { get; set; } + + public OccludeModelTriScaleUndoStep(YmapOccludeModelTriangle tri, Vector3 startscale) + { + OccludeModelTri = tri; + StartScale = startscale; + EndScale = tri?.Scale ?? new Vector3(1.0f); + } + + private void Update(WorldForm wf, ref MapSelection sel, Vector3 s) + { + OccludeModelTri.Scale = s; + + if (OccludeModelTri != sel.OccludeModelTri) wf.SelectObject(OccludeModelTri); + wf.SetWidgetScale(s); + + UpdateGraphics(wf); + } + + + public override void Undo(WorldForm wf, ref MapSelection sel) + { + Update(wf, ref sel, StartScale); + } + + public override void Redo(WorldForm wf, ref MapSelection sel) + { + Update(wf, ref sel, EndScale); + } + + public override string ToString() + { + return "OccludeModel Triangle " + (OccludeModelTri?.Index.ToString() ?? "") + ": Scale"; + } + } + public class CollisionPositionUndoStep : UndoStep diff --git a/CodeWalker/Rendering/Renderer.cs b/CodeWalker/Rendering/Renderer.cs index dc35e55..ae606f6 100644 --- a/CodeWalker/Rendering/Renderer.cs +++ b/CodeWalker/Rendering/Renderer.cs @@ -936,6 +936,16 @@ namespace CodeWalker.Rendering SelectionTriVerts.Add(v1); } + public void RenderSelectionTriangleOutline(Vector3 p1, Vector3 p2, Vector3 p3, uint col) + { + SelectionLineVerts.Add(new VertexTypePC() { Position = p1, Colour = col }); + SelectionLineVerts.Add(new VertexTypePC() { Position = p2, Colour = col }); + SelectionLineVerts.Add(new VertexTypePC() { Position = p2, Colour = col }); + SelectionLineVerts.Add(new VertexTypePC() { Position = p3, Colour = col }); + SelectionLineVerts.Add(new VertexTypePC() { Position = p3, Colour = col }); + SelectionLineVerts.Add(new VertexTypePC() { Position = p1, Colour = col }); + } + public void RenderSelectionCone(Vector3 position, Vector3 ax, Vector3 ay, Vector3 dir, float radius, float height, uint col) { const int Reso = 36; diff --git a/CodeWalker/World/MapSelection.cs b/CodeWalker/World/MapSelection.cs index b1afb75..4493d0f 100644 --- a/CodeWalker/World/MapSelection.cs +++ b/CodeWalker/World/MapSelection.cs @@ -54,7 +54,7 @@ namespace CodeWalker public YmapGrassInstanceBatch GrassBatch { get; set; } public YmapLODLight LodLight { get; set; } public YmapBoxOccluder BoxOccluder { get; set; } - public YmapOccludeModel OccludeModel { get; set; } + public YmapOccludeModelTriangle OccludeModelTri { get; set; } public YmapEntityDef MloEntityDef { get; set; } public MCMloRoomDef MloRoomDef { get; set; } public WaterQuad WaterQuad { get; set; } @@ -110,7 +110,7 @@ namespace CodeWalker (TrainTrackNode != null) || (LodLight != null) || (BoxOccluder != null) || - (OccludeModel != null) || + (OccludeModelTri != null) || (MloEntityDef != null) || (ScenarioNode != null) || (Audio != null) || @@ -137,7 +137,7 @@ namespace CodeWalker || (LodLight != mhit.LodLight) || (GrassBatch != mhit.GrassBatch) || (BoxOccluder != mhit.BoxOccluder) - || (OccludeModel != mhit.OccludeModel) + || (OccludeModelTri != mhit.OccludeModelTri) || (WaterQuad != mhit.WaterQuad) || (CollisionBounds != mhit.CollisionBounds) || (CollisionPoly != mhit.CollisionPoly) @@ -164,7 +164,7 @@ namespace CodeWalker || (LodLight != null) || (GrassBatch != null) || (BoxOccluder != null) - || (OccludeModel != null) + || (OccludeModelTri != null) || (WaterQuad != null) || (CollisionBounds != null) || (CollisionPoly != null) @@ -193,7 +193,7 @@ namespace CodeWalker CarGenerator = null; GrassBatch = null; BoxOccluder = null; - OccludeModel = null; + OccludeModelTri = null; WaterQuad = null; CollisionBounds = null; CollisionPoly = null; @@ -269,9 +269,9 @@ namespace CodeWalker { name = "BoxOccluder " + (BoxOccluder.Ymap?.Name ?? "") + ": " + BoxOccluder.Index.ToString(); } - else if (OccludeModel != null) + else if (OccludeModelTri != null) { - name = "OccludeModel " + (OccludeModel.Ymap?.Name ?? "") + ": " + OccludeModel.Index.ToString(); + name = "OccludeModel " + (OccludeModelTri.Ymap?.Name ?? "") + ": " + (OccludeModelTri.Model?.Index??0).ToString() + ":" + OccludeModelTri.Index.ToString(); } else if (WaterQuad != null) { @@ -337,6 +337,8 @@ namespace CodeWalker if (EntityDef != null) return true; if (CarGenerator != null) return true; if (LodLight != null) return true; + if (BoxOccluder != null) return true; + if (OccludeModelTri != null) return true; if (CollisionBounds != null) return true; if (CollisionPoly != null) return true; if (CollisionVertex != null) return true; @@ -423,6 +425,24 @@ namespace CodeWalker case WidgetMode.Scale: return new LodLightScaleUndoStep(LodLight, startScale); } } + else if (BoxOccluder != null) + { + switch (mode) + { + case WidgetMode.Position: return new BoxOccluderPositionUndoStep(BoxOccluder, startPos); + case WidgetMode.Rotation: return new BoxOccluderRotationUndoStep(BoxOccluder, startRot); + case WidgetMode.Scale: return new BoxOccluderScaleUndoStep(BoxOccluder, startScale); + } + } + else if (OccludeModelTri != null) + { + switch (mode) + { + case WidgetMode.Position: return new OccludeModelTriPositionUndoStep(OccludeModelTri, startPos); + case WidgetMode.Rotation: return new OccludeModelTriRotationUndoStep(OccludeModelTri, startRot); + case WidgetMode.Scale: return new OccludeModelTriScaleUndoStep(OccludeModelTri, startScale); + } + } else if (PathNode != null) { switch (mode) @@ -498,6 +518,14 @@ namespace CodeWalker { res = true; } + else if (BoxOccluder != null) + { + res = true; + } + else if (OccludeModelTri != null) + { + res = true; + } else if (NavPoly != null) { res = true; @@ -576,6 +604,14 @@ namespace CodeWalker { return LodLight.Position; } + else if (BoxOccluder != null) + { + return BoxOccluder.Position; + } + else if (OccludeModelTri != null) + { + return OccludeModelTri.Center; + } else if (NavPoly != null) { return NavPoly.Position; @@ -642,6 +678,14 @@ namespace CodeWalker { return LodLight.Orientation; } + else if (BoxOccluder != null) + { + return BoxOccluder.Orientation; + } + else if (OccludeModelTri != null) + { + return OccludeModelTri.Orientation; + } else if (NavPoly != null) { return Quaternion.Identity; @@ -705,6 +749,14 @@ namespace CodeWalker { return WidgetAxis.XYZ; } + else if (BoxOccluder != null) + { + return WidgetAxis.Z; + } + else if (OccludeModelTri != null) + { + return WidgetAxis.XYZ; + } else if (NavPoly != null) { return WidgetAxis.XYZ; @@ -768,6 +820,14 @@ namespace CodeWalker { return LodLight.Scale; } + else if (BoxOccluder != null) + { + return BoxOccluder.Size; + } + else if (OccludeModelTri != null) + { + return OccludeModelTri.Scale; + } else if (NavPoly != null) { return Vector3.One; @@ -811,6 +871,14 @@ namespace CodeWalker } return false; } + if (BoxOccluder != null) + { + return false; + } + if (OccludeModelTri != null) + { + return false; + } if (CollisionBounds != null) { return false; @@ -841,6 +909,8 @@ namespace CodeWalker else if (EntityDef != null) return true; else if (CarGenerator != null) return true; else if (LodLight != null) return true; + else if (BoxOccluder != null) return true; + else if (OccludeModelTri != null) return true; else if (PathNode != null) return true; else if (NavPoly != null) return true; else if (NavPoint != null) return true; @@ -962,6 +1032,14 @@ namespace CodeWalker { LodLight.SetPosition(newpos); } + else if (BoxOccluder != null) + { + BoxOccluder.Position = newpos; + } + else if (OccludeModelTri != null) + { + OccludeModelTri.Center = newpos; + } else if (PathNode != null) { PathNode.SetPosition(newpos); @@ -1074,6 +1152,14 @@ namespace CodeWalker { LodLight.SetOrientation(newrot); } + else if (BoxOccluder != null) + { + BoxOccluder.Orientation = newrot; + } + else if (OccludeModelTri != null) + { + OccludeModelTri.Orientation = newrot; + } else if (ScenarioNode != null) { ScenarioNode.SetOrientation(newrot); @@ -1165,6 +1251,14 @@ namespace CodeWalker { LodLight.SetScale(newscale); } + else if (BoxOccluder != null) + { + BoxOccluder.SetSize(newscale); + } + else if (OccludeModelTri != null) + { + OccludeModelTri.Scale = newscale; + } } @@ -1205,12 +1299,14 @@ namespace CodeWalker { if (MultipleSelectionItems != null) { - Dictionary pathYnds = new Dictionary(); - Dictionary navYnvs = new Dictionary(); - Dictionary trainTracks = new Dictionary(); - Dictionary scenarioYmts = new Dictionary(); - Dictionary bounds = new Dictionary(); - Dictionary lodlights = new Dictionary(); + var pathYnds = new Dictionary(); + var navYnvs = new Dictionary(); + var trainTracks = new Dictionary(); + var scenarioYmts = new Dictionary(); + var bounds = new Dictionary(); + var lodlights = new Dictionary(); + var boxoccls = new Dictionary(); + var occlmods = new Dictionary(); foreach (var item in MultipleSelectionItems) { @@ -1254,6 +1350,14 @@ namespace CodeWalker { lodlights[item.LodLight.LodLights] = 1; } + if (item.BoxOccluder != null) + { + boxoccls[item.BoxOccluder] = 1; + } + if (item.OccludeModelTri?.Model != null) + { + occlmods[item.OccludeModelTri.Model] = 1; + } } foreach (var kvp in bounds) { @@ -1282,6 +1386,14 @@ namespace CodeWalker wf.UpdateLodLightGraphics(kvp.Key.LodLights[0]); } } + foreach (var kvp in boxoccls) + { + wf.UpdateBoxOccluderGraphics(kvp.Key); + } + foreach (var kvp in occlmods) + { + wf.UpdateOccludeModelGraphics(kvp.Key); + } } else { @@ -1325,6 +1437,14 @@ namespace CodeWalker { wf.UpdateLodLightGraphics(LodLight); } + else if (BoxOccluder != null) + { + wf.UpdateBoxOccluderGraphics(BoxOccluder); + } + else if (OccludeModelTri?.Model != null) + { + wf.UpdateOccludeModelGraphics(OccludeModelTri?.Model); + } } } @@ -1338,6 +1458,8 @@ namespace CodeWalker else if (EntityDef != null) return EntityDef; else if (CarGenerator != null) return CarGenerator; else if (LodLight != null) return LodLight; + else if (BoxOccluder != null) return BoxOccluder; + else if (OccludeModelTri != null) return OccludeModelTri; else if (PathNode != null) return PathNode; else if (NavPoly != null) return NavPoly; else if (NavPoint != null) return NavPoint; @@ -1382,6 +1504,16 @@ namespace CodeWalker ms.LodLight = lodlight; ms.AABB = new BoundingBox(new Vector3(-nrad), new Vector3(nrad)); } + else if (o is YmapBoxOccluder boxoccl) + { + ms.BoxOccluder = boxoccl; + ms.AABB = new BoundingBox(boxoccl.BBMin, boxoccl.BBMax); + } + else if (o is YmapOccludeModelTriangle occltri) + { + ms.OccludeModelTri = occltri; + ms.AABB = new BoundingBox(occltri.Box.Minimum, occltri.Box.Maximum); + } else if (o is YmapGrassInstanceBatch batch) { ms.GrassBatch = batch; diff --git a/CodeWalker/World/WorldInfoForm.cs b/CodeWalker/World/WorldInfoForm.cs index 48b4450..78fdb5f 100644 --- a/CodeWalker/World/WorldInfoForm.cs +++ b/CodeWalker/World/WorldInfoForm.cs @@ -117,10 +117,10 @@ namespace CodeWalker.World SelectionEntityTabPage.Text = "Box Occluder"; SelEntityPropertyGrid.SelectedObject = item.BoxOccluder; } - else if (item.OccludeModel != null) + else if (item.OccludeModelTri != null) { - SelectionEntityTabPage.Text = "Occlude Model"; - SelEntityPropertyGrid.SelectedObject = item.OccludeModel; + SelectionEntityTabPage.Text = "Occlude Model Triangle"; + SelEntityPropertyGrid.SelectedObject = item.OccludeModelTri; } else if (item.WaterQuad != null) { diff --git a/CodeWalker/WorldForm.cs b/CodeWalker/WorldForm.cs index 823acde..dd35c56 100644 --- a/CodeWalker/WorldForm.cs +++ b/CodeWalker/WorldForm.cs @@ -1225,9 +1225,11 @@ namespace CodeWalker { ori = CurMouseHit.BoxOccluder.Orientation; } - if (CurMouseHit.OccludeModel != null) + if (CurMouseHit.OccludeModelTri != null) { - //ori = CurMouseHit.OccludeModel.Orientation; + var otri = CurMouseHit.OccludeModelTri; + Renderer.RenderSelectionTriangleOutline(otri.Corner1, otri.Corner2, otri.Corner3, 0xFFFFFFFF); + return; } if (CurMouseHit.MloEntityDef != null) { @@ -1531,6 +1533,14 @@ namespace CodeWalker bbmin = bo.BBMin; bbmax = bo.BBMax; } + if (selectionItem.OccludeModelTri != null) + { + var ot = selectionItem.OccludeModelTri; + var om = ot.Model; + bbmin = om._OccludeModel.bmin; + bbmax = om._OccludeModel.bmax; + Renderer.RenderSelectionTriangleOutline(ot.Corner1, ot.Corner2, ot.Corner3, cgrn); + } if (selectionItem.NavPoly != null) { Renderer.RenderSelectionNavPoly(selectionItem.NavPoly); @@ -1961,6 +1971,23 @@ namespace CodeWalker Renderer.Invalidate(lodlight); } } + public void UpdateBoxOccluderGraphics(YmapBoxOccluder box) + { + //lock (Renderer.RenderSyncRoot) + { + Renderer.Invalidate(box); + } + } + public void UpdateOccludeModelGraphics(YmapOccludeModel model) + { + model.BuildBVH(); + model.BuildVertices(); + + //lock (Renderer.RenderSyncRoot) + { + Renderer.Invalidate(model); + } + } public void UpdateGrassBatchGraphics(YmapGrassInstanceBatch grassBatch) { //lock (Renderer.RenderSyncRoot) @@ -2815,13 +2842,15 @@ namespace CodeWalker var bo = ymap.BoxOccluders[i]; if ((bo.Position - camera.Position).Length() > dmax) continue; + Renderer.RenderBasePath(bo); + MapBox mb = new MapBox(); mb.CamRelPos = bo.Position - camera.Position; mb.BBMin = bo.BBMin; mb.BBMax = bo.BBMax; mb.Orientation = bo.Orientation; mb.Scale = Vector3.One; - Renderer.BoundingBoxes.Add(mb); + //Renderer.BoundingBoxes.Add(mb); Quaternion orinv = Quaternion.Invert(bo.Orientation); Ray mraytrn = new Ray(); @@ -2829,10 +2858,11 @@ namespace CodeWalker mraytrn.Direction = orinv.Multiply(mray.Direction); bbox.Minimum = mb.BBMin; bbox.Maximum = mb.BBMax; - if (mraytrn.Intersects(ref bbox, out hitdist) && (hitdist < CurMouseHit.HitDist) && (hitdist > 0)) + if (mraytrn.Intersects(ref bbox, out float hd) && (hd < CurMouseHit.HitDist) && (hd > 0)) { + hitdist = hd; CurMouseHit.BoxOccluder = bo; - CurMouseHit.OccludeModel = null; + CurMouseHit.OccludeModelTri = null; CurMouseHit.HitDist = hitdist; CurMouseHit.CamRel = mb.CamRelPos; CurMouseHit.AABB = bbox; @@ -2847,24 +2877,14 @@ namespace CodeWalker Renderer.RenderBasePath(om); - MapBox mb = new MapBox(); - mb.CamRelPos = -camera.Position; - mb.BBMin = om._OccludeModel.bmin; - mb.BBMax = om._OccludeModel.bmax; - mb.Orientation = Quaternion.Identity;// bo.Orientation; - mb.Scale = Vector3.One; - Renderer.BoundingBoxes.Add(mb); - - - bbox.Minimum = mb.BBMin; - bbox.Maximum = mb.BBMax; - if (mray.Intersects(ref bbox, out hitdist) && (hitdist < CurMouseHit.HitDist) && (hitdist > 0)) + var hittri = om.RayIntersect(ref mray, ref hitdist); + if ((hittri != null) && (hitdist < CurMouseHit.HitDist)) { CurMouseHit.BoxOccluder = null; - CurMouseHit.OccludeModel = om; + CurMouseHit.OccludeModelTri = hittri; CurMouseHit.HitDist = hitdist; - CurMouseHit.CamRel = mb.CamRelPos; - CurMouseHit.AABB = bbox; + CurMouseHit.CamRel = -camera.Position; + CurMouseHit.AABB = hittri.Box; } } @@ -3672,13 +3692,21 @@ namespace CodeWalker } else if (item.BoxOccluder != null) { - SelectionEntityTabPage.Text = "Box Occluder"; + SelectionEntityTabPage.Text = "BoxOccluder"; SelEntityPropertyGrid.SelectedObject = item.BoxOccluder; + ymap = item.BoxOccluder.Ymap; + ToolbarCopyButton.Enabled = true; + ToolbarDeleteItemButton.Enabled = true; + ToolbarDeleteItemButton.Text = "Delete Box Occluder"; } - else if (item.OccludeModel != null) + else if (item.OccludeModelTri != null) { - SelectionEntityTabPage.Text = "Occlude Model"; - SelEntityPropertyGrid.SelectedObject = item.OccludeModel; + SelectionEntityTabPage.Text = "OccludeTriangle"; + SelEntityPropertyGrid.SelectedObject = item.OccludeModelTri; + ymap = item.OccludeModelTri.Ymap; + ToolbarCopyButton.Enabled = true; + ToolbarDeleteItemButton.Enabled = true; + ToolbarDeleteItemButton.Text = "Delete Occlude Model Triangle"; } else if (item.WaterQuad != null) { @@ -5058,6 +5086,9 @@ namespace CodeWalker else if (item.CollisionBounds != null) DeleteCollisionBounds(item.CollisionBounds); else if (item.EntityDef != null) DeleteEntity(item.EntityDef); else if (item.CarGenerator != null) DeleteCarGen(item.CarGenerator); + else if (item.LodLight != null) DeleteLodLight(item.LodLight); + else if (item.BoxOccluder != null) DeleteBoxOccluder(item.BoxOccluder); + else if (item.OccludeModelTri != null) DeleteOccludeModelTriangle(item.OccludeModelTri); else if (item.PathNode != null) DeletePathNode(item.PathNode); else if (item.NavPoly != null) DeleteNavPoly(item.NavPoly); else if (item.NavPoint != null) DeleteNavPoint(item.NavPoint); @@ -5115,6 +5146,52 @@ namespace CodeWalker SelectItem(null); } } + private void DeleteLodLight(YmapLODLight lodlight) + { + if (lodlight == null) return; + + //project not open, or lodlight not selected there, just remove the lodlight from the ymap... + var ymap = lodlight.Ymap; + if (!ymap.RemoveLodLight(lodlight)) + { + MessageBox.Show("Unable to remove LOD light."); + } + else + { + SelectItem(null); + } + } + private void DeleteBoxOccluder(YmapBoxOccluder box) + { + if (box == null) return; + + //project not open, or box not selected there, just remove the box from the ymap... + var ymap = box.Ymap; + if (!ymap.RemoveBoxOccluder(box)) + { + MessageBox.Show("Unable to remove box occluder."); + } + else + { + SelectItem(null); + } + } + private void DeleteOccludeModelTriangle(YmapOccludeModelTriangle tri) + { + if (tri == null) return; + + //project not open, or tri not selected there, just remove the tri from the ymap... + var ymap = tri.Ymap; + if (!ymap.RemoveOccludeModelTriangle(tri)) + { + MessageBox.Show("Unable to remove occlude model triangle."); + } + else + { + UpdateOccludeModelGraphics(tri.Model); + SelectItem(null); + } + } private void DeletePathNode(YndNode pathnode) { if (pathnode == null) return;