diff --git a/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs b/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs index 6aa15e3..08d59f8 100644 --- a/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs +++ b/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs @@ -1279,6 +1279,8 @@ namespace CodeWalker.GameFiles public Archetype Archetype { get; set; } //cached by GameFileCache on loading... public Vector3 BBMin;//oriented archetype AABBmin public Vector3 BBMax;//oriented archetype AABBmax + public Vector3 BBCenter; //oriented archetype AABB center + public Vector3 BBExtent; //oriented archetype AABB extent public Vector3 BSCenter; //oriented archetype BS center public float BSRadius;//cached from archetype @@ -1377,20 +1379,7 @@ namespace CodeWalker.GameFiles Archetype = arch; if (Archetype != null) { - float smax = Math.Max(Scale.X, Scale.Z); - BSRadius = Archetype.BSRadius * smax; - BSCenter = Orientation.Multiply(Archetype.BSCenter) * Scale; - if (Orientation == Quaternion.Identity) - { - BBMin = (Archetype.BBMin * Scale) + Position; - BBMax = (Archetype.BBMax * Scale) + Position; - } - else - { - BBMin = Position - BSRadius; - BBMax = Position + BSRadius; - ////not ideal: should transform all 8 corners! - } + UpdateBB(); if (Archetype.Type == MetaName.CMloArchetypeDef) { @@ -1415,6 +1404,13 @@ namespace CodeWalker.GameFiles { BSRadius = _CEntityDef.lodDist;//need something so it doesn't get culled... } + if (BBMin == BBMax) + { + BBMin = Position - BSRadius; + BBMax = Position + BSRadius;//it's not ideal + BBCenter = (BBMax + BBMin) * 0.5f; + BBExtent = (BBMax - BBMin) * 0.5f; + } } else if (IsMlo) // archetype is no longer an mlo { @@ -1465,17 +1461,32 @@ namespace CodeWalker.GameFiles if (Archetype != null) { BSCenter = Orientation.Multiply(Archetype.BSCenter) * Scale; - } - if ((Archetype != null) && (Orientation == Quaternion.Identity)) - { - BBMin = (Archetype.BBMin * Scale) + Position; - BBMax = (Archetype.BBMax * Scale) + Position; - } - else - { - BBMin = Position - (BSRadius); - BBMax = Position + (BSRadius); - ////not ideal: should transform all 8 corners! + BSRadius = Archetype.BSRadius * Math.Max(Scale.X, Scale.Z); + if (Orientation == Quaternion.Identity) + { + BBMin = (Archetype.BBMin * Scale) + Position; + BBMax = (Archetype.BBMax * Scale) + Position; + BBCenter = (BBMax + BBMin) * 0.5f; + BBExtent = (BBMax - BBMin) * 0.5f; + BBExtent = BBExtent.Abs(); + } + else + { + var mat = Matrix.Transformation(Vector3.Zero, Quaternion.Identity, Scale, Vector3.Zero, Orientation, Position); + var matabs = mat; + matabs.Column1 = mat.Column1.Abs(); + matabs.Column2 = mat.Column2.Abs(); + matabs.Column3 = mat.Column3.Abs(); + matabs.Column4 = mat.Column4.Abs(); + var bbcenter = (Archetype.BBMax + Archetype.BBMin) * 0.5f; + var bbextent = (Archetype.BBMax - Archetype.BBMin) * 0.5f; + var ncenter = Vector3.TransformCoordinate(bbcenter, mat); + var nextent = Vector3.TransformNormal(bbextent, matabs); + BBCenter = ncenter; + BBExtent = nextent; + BBMin = ncenter - nextent; + BBMax = ncenter + nextent; + } } } @@ -1533,11 +1544,7 @@ namespace CodeWalker.GameFiles MloInstance.UpdateEntities(); } - if (Archetype != null) - { - BSCenter = Orientation.Multiply(Archetype.BSCenter) * Scale; - } - + UpdateBB(); UpdateWidgetPosition(); UpdateWidgetOrientation(); } diff --git a/CodeWalker.Core/Utils/Vectors.cs b/CodeWalker.Core/Utils/Vectors.cs index ee8d91e..e86d1f4 100644 --- a/CodeWalker.Core/Utils/Vectors.cs +++ b/CodeWalker.Core/Utils/Vectors.cs @@ -40,6 +40,11 @@ namespace CodeWalker } } + public static Vector3 Abs(this Vector3 v) + { + return new Vector3(Math.Abs(v.X), Math.Abs(v.Y), Math.Abs(v.Z)); + } + public static Vector4 Floor(this Vector4 v) { diff --git a/CodeWalker.Core/World/Camera.cs b/CodeWalker.Core/World/Camera.cs index a13371c..f25b34c 100644 --- a/CodeWalker.Core/World/Camera.cs +++ b/CodeWalker.Core/World/Camera.cs @@ -334,6 +334,18 @@ namespace CodeWalker.World } return true; } + public bool ContainsAABBNoClip(ref Vector3 cen, ref Vector3 e) + { + var c = cen - Position; + for (int i = 0; i < 5; i++) + { + var pn = Planes[i].Normal; + var d = (c.X * pn.X) + (c.Y * pn.Y) + (c.Z * pn.Z); //Vector3.Dot(c, pn);// + var r = (e.X * (pn.X > 0 ? pn.X : -pn.X)) + (e.Y * (pn.Y > 0 ? pn.Y : -pn.Y)) + (e.Z * (pn.Z > 0 ? pn.Z : -pn.Z)); //Vector3.Dot(e, pn.Abs()); // + if ((d + r) < 0) return false; + } + return true; + } public bool ContainsAABBNoClipNoOpt(ref Vector3 bmin, ref Vector3 bmax) { var c = (bmax + bmin) * 0.5f - Position; diff --git a/Rendering/Renderer.cs b/Rendering/Renderer.cs index 4ff5c02..d72748b 100644 --- a/Rendering/Renderer.cs +++ b/Rendering/Renderer.cs @@ -82,6 +82,7 @@ namespace CodeWalker.Rendering public bool markerdepthclip = Settings.Default.MarkerDepthClip; + private RenderLodManager LodManager = new RenderLodManager(); private List renderworldentities = new List(); //used when rendering world view. private List renderworldrenderables = new List(); @@ -1520,6 +1521,11 @@ namespace CodeWalker.Rendering renderworldentities.Clear(); renderworldrenderables.Clear(); + + //LodManager.Update(renderworldVisibleYmapDict, ref camera.Position, currentElapsedTime); + + + VisibleYmaps.Clear(); foreach (var ymap in renderworldVisibleYmapDict.Values) { @@ -1839,11 +1845,10 @@ namespace CodeWalker.Rendering { if (!RenderIsEntityFinalRender(ent)) return; - var bscent = ent.Position + ent.BSCenter - camera.Position; - float bsrad = ent.BSRadius; - if (!camera.ViewFrustum.ContainsSphereNoClipNoOpt(ref bscent, bsrad)) + + if (!camera.ViewFrustum.ContainsAABBNoClip(ref ent.BBCenter, ref ent.BBExtent)) { - return; //frustum cull + return; } @@ -3348,5 +3353,101 @@ namespace CodeWalker.Rendering + + + + + + + + + + + + + + + + + + + + + + public class RenderLodManager + { + + + private Dictionary EntityDict = new Dictionary(); //visible entities and their current child counts + + + public void Update(Dictionary ymaps, ref Vector3 position, float elapsed) + { + EntityDict.Clear(); + + foreach (var ymap in ymaps.Values) + { + YmapFile pymap = ymap.Parent; + if (ymap._CMapData.parent != 0) //ensure parent references on ymaps + { + ymaps.TryGetValue(ymap._CMapData.parent, out pymap); + if (ymap.Parent != pymap) + { + ymap.Parent = pymap; + if (ymap.RootEntities != null) //parent changed or first set, make sure to link entities hierarchy + { + for (int i = 0; i < ymap.RootEntities.Length; i++) + { + var ent = ymap.RootEntities[i]; + int pind = ent._CEntityDef.parentIndex; + if (pind >= 0) //connect root entities to parents if they have them.. + { + YmapEntityDef p = null; + if ((pymap != null) && (pymap.AllEntities != null)) + { + if ((pind < pymap.AllEntities.Length)) + { + p = pymap.AllEntities[pind]; + ent.Parent = p; + ent.ParentName = p._CEntityDef.archetypeName; + } + } + else + { }//should only happen if parent ymap not loaded yet... + } + } + } + } + } + if (ymap.AllEntities != null) //add visible entities to the dict, increment entity parent child counts + { + for (int i = 0; i < ymap.AllEntities.Length; i++) + { + var ent = ymap.AllEntities[i]; + //ent.BBMin + + + } + + } + } + + + + + } + + + } + + + + + + + + + + }