diff --git a/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs b/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs index aed4b21..5877f62 100644 --- a/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs +++ b/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs @@ -1681,6 +1681,9 @@ namespace CodeWalker.GameFiles public object LodManagerRenderable = null; + public LightInstance[] Lights { get; set; } + + public string Name { get @@ -2069,6 +2072,129 @@ namespace CodeWalker.GameFiles return _CEntityDef.ToString() + ((ChildList != null) ? (" (" + ChildList.Count.ToString() + " children) ") : " ") + _CEntityDef.lodLevel.ToString(); } + + + public void EnsureLights(DrawableBase db) + { + if (Lights != null) return; + if (Archetype == null) return; + if (db == null) return; + + var dd = db as Drawable; + var fd = db as FragDrawable; + LightAttributes_s[] lightAttrs = null; + Bounds b = null; + if (dd != null) + { + lightAttrs = dd.LightAttributes?.data_items; + b = dd.Bound; + } + else if (fd != null) + { + lightAttrs = fd.OwnerFragment?.LightAttributes?.data_items; + b = fd.OwnerFragment?.PhysicsLODGroup?.PhysicsLOD1?.Bound; + } + if (lightAttrs == null) return; + + var abmin = Vector3.Min(Archetype.BBMin, db.BoundingBoxMin); + var abmax = Vector3.Max(Archetype.BBMax, db.BoundingBoxMax); + if (b != null) + { + abmin = Vector3.Min(abmin, b.BoxMin); + abmax = Vector3.Max(abmax, b.BoxMax); + } + var bb = new BoundingBox(abmin, abmax).Transform(Position, Orientation, Scale); + var ints = new uint[7]; + ints[0] = (uint)(bb.Minimum.X * 10.0f); + ints[1] = (uint)(bb.Minimum.Y * 10.0f); + ints[2] = (uint)(bb.Minimum.Z * 10.0f); + ints[3] = (uint)(bb.Maximum.X * 10.0f); + ints[4] = (uint)(bb.Maximum.Y * 10.0f); + ints[5] = (uint)(bb.Maximum.Z * 10.0f); + + var lightInsts = new LightInstance[lightAttrs.Length]; + for (int i = 0; i < lightAttrs.Length; i++) + { + ints[6] = (uint)(i + 1); + var li = new LightInstance(); + li.Attributes = lightAttrs[i]; + li.Hash = ComputeLightHash(ints); + lightInsts[i] = li; + } + Lights = lightInsts; + + } + + + public static uint ComputeLightHash(uint[] ints, uint seed = 0) + { + var a2 = ints.Length; + var v3 = a2; + var v5 = (uint)(seed + 0xDEADBEEF + 4 * ints.Length); + var v6 = v5; + var v7 = v5; + + var c = 0; + for (var i = 0; i < (ints.Length - 4) / 3 + 1; i++, v3 -= 3, c += 3) + { + var v9 = ints[c + 2] + v5; + var v10 = ints[c + 1] + v6; + var v11 = ints[c] - v9; + var v13 = v10 + v9; + var v14 = (v7 + v11) ^ BitUtil.RotateLeft(v9, 4); + var v15 = v10 - v14; + var v17 = v13 + v14; + var v18 = v15 ^ BitUtil.RotateLeft(v14, 6); + var v19 = v13 - v18; + var v21 = v17 + v18; + var v22 = v19 ^ BitUtil.RotateLeft(v18, 8); + var v23 = v17 - v22; + var v25 = v21 + v22; + var v26 = v23 ^ BitUtil.RotateLeft(v22, 16); + var v27 = v21 - v26; + var v29 = v27 ^ BitUtil.RotateRight(v26, 13); + var v30 = v25 - v29; + v7 = v25 + v26; + v6 = v7 + v29; + v5 = v30 ^ BitUtil.RotateLeft(v29, 4); + } + + if (v3 == 3) + { + v5 += ints[c + 2]; + } + + if (v3 >= 2) + { + v6 += ints[c + 1]; + } + + if (v3 >= 1) + { + var v34 = (v6 ^ v5) - BitUtil.RotateLeft(v6, 14); + var v35 = (v34 ^ (v7 + ints[c])) - BitUtil.RotateLeft(v34, 11); + var v36 = (v35 ^ v6) - BitUtil.RotateRight(v35, 7); + var v37 = (v36 ^ v34) - BitUtil.RotateLeft(v36, 16); + var v38 = BitUtil.RotateLeft(v37, 4); + var v39 = (((v35 ^ v37) - v38) ^ v36) - BitUtil.RotateLeft((v35 ^ v37) - v38, 14); + return (v39 ^ v37) - BitUtil.RotateRight(v39, 8); + } + + return v5; + } + + + [TypeConverter(typeof(ExpandableObjectConverter))] + public class LightInstance + { + public LightAttributes_s Attributes { get; set; } //just for display purposes! + public uint Hash { get; set; } + + public override string ToString() + { + return Hash.ToString() + ": " + Attributes.Type.ToString(); + } + } } diff --git a/CodeWalker.Core/Utils/Utils.cs b/CodeWalker.Core/Utils/Utils.cs index d116221..296aa26 100644 --- a/CodeWalker.Core/Utils/Utils.cs +++ b/CodeWalker.Core/Utils/Utils.cs @@ -267,6 +267,14 @@ namespace CodeWalker if (flag) return SetBit(value, bit); else return ClearBit(value, bit); } + public static uint RotateLeft(uint value, int count) + { + return (value << count) | (value >> (32 - count)); + } + public static uint RotateRight(uint value, int count) + { + return (value >> count) | (value << (32 - count)); + } } diff --git a/CodeWalker/Project/Panels/GenerateLODLightsPanel.cs b/CodeWalker/Project/Panels/GenerateLODLightsPanel.cs index ea96403..f54c98c 100644 --- a/CodeWalker/Project/Panels/GenerateLODLightsPanel.cs +++ b/CodeWalker/Project/Panels/GenerateLODLightsPanel.cs @@ -94,11 +94,6 @@ namespace CodeWalker.Project.Panels { var lights = new List(); - var eemin = new Vector3(float.MaxValue); - var eemax = new Vector3(float.MinValue); - var semin = new Vector3(float.MaxValue); - var semax = new Vector3(float.MinValue); - //var rnd = new Random(); foreach (var ymap in projectYmaps) { @@ -118,28 +113,17 @@ namespace CodeWalker.Project.Panels UpdateStatus("Adding lights from " + ent.Archetype.Name + "..."); if (dwbl != null) { - Drawable ddwbl = dwbl as Drawable; - FragDrawable fdwbl = dwbl as FragDrawable; - LightAttributes_s[] lightAttrs = null; - if (ddwbl != null) - { - lightAttrs = ddwbl.LightAttributes?.data_items; - } - else if (fdwbl != null) - { - lightAttrs = fdwbl.OwnerFragment?.LightAttributes?.data_items; - } - if (lightAttrs != null) - { - eemin = Vector3.Min(eemin, ent.BBMin); - eemax = Vector3.Max(eemax, ent.BBMax); - semin = Vector3.Min(semin, ent.BBMin - ent._CEntityDef.lodDist); - semax = Vector3.Max(semax, ent.BBMax + ent._CEntityDef.lodDist); + var fphys = (dwbl as FragDrawable)?.OwnerFragmentPhys; + ent.EnsureLights(dwbl); + var elights = ent.Lights; + if (elights != null) + { - for (int li = 0; li ints, uint seed = 0) - { - var a2 = ints.Count; - var v3 = a2; - var v5 = (uint)(seed + 0xDEADBEEF + 4 * ints.Count); - var v6 = v5; - var v7 = v5; - - var c = 0; - for (var i = 0; i < (ints.Count - 4) / 3 + 1; i++, v3 -= 3, c += 3) - { - var v9 = ints[c + 2] + v5; - var v10 = ints[c + 1] + v6; - var v11 = ints[c] - v9; - var v13 = v10 + v9; - var v14 = (v7 + v11) ^ RotateLeft(v9, 4); - var v15 = v10 - v14; - var v17 = v13 + v14; - var v18 = v15 ^ RotateLeft(v14, 6); - var v19 = v13 - v18; - var v21 = v17 + v18; - var v22 = v19 ^ RotateLeft(v18, 8); - var v23 = v17 - v22; - var v25 = v21 + v22; - var v26 = v23 ^ RotateLeft(v22, 16); - var v27 = v21 - v26; - var v29 = v27 ^ RotateRight(v26, 13); - var v30 = v25 - v29; - v7 = v25 + v26; - v6 = v7 + v29; - v5 = v30 ^ RotateLeft(v29, 4); - } - - if (v3 == 3) - { - v5 += ints[c + 2]; - } - - if (v3 >= 2) - { - v6 += ints[c + 1]; - } - - if (v3 >= 1) - { - var v34 = (v6 ^ v5) - RotateLeft(v6, 14); - var v35 = (v34 ^ (v7 + ints[c])) - RotateLeft(v34, 11); - var v36 = (v35 ^ v6) - RotateRight(v35, 7); - var v37 = (v36 ^ v34) - RotateLeft(v36, 16); - var v38 = RotateLeft(v37, 4); - var v39 = (((v35 ^ v37) - v38) ^ v36) - RotateLeft((v35 ^ v37) - v38, 14); - return (v39 ^ v37) - RotateRight(v39, 8); - } - - return v5; - } - - private uint GetLightHash(YmapEntityDef ent, DrawableBase dwbl, int lightIndex) - { - unchecked - { - var len = 7; - - var ori = ent.Orientation; - var pos = ent.Position; - var abmin = Vector3.Min(ent.Archetype.BBMin, dwbl.BoundingBoxMin); - var abmax = Vector3.Max(ent.Archetype.BBMax, dwbl.BoundingBoxMax); - - Bounds b = null; - if (dwbl is Drawable ddwbl) - { - b = ddwbl.Bound; - } - if (dwbl is FragDrawable fdwbl) - { - b = fdwbl.OwnerFragment?.PhysicsLODGroup?.PhysicsLOD1?.Bound; - } - if (b != null) - { - abmin = Vector3.Min(abmin, b.BoxMin); - abmax = Vector3.Max(abmax, b.BoxMax); - } - - Vector3[] c = new Vector3[8]; - c[0] = abmin; - c[1] = new Vector3(abmin.X, abmin.Y, abmax.Z); - c[2] = new Vector3(abmin.X, abmax.Y, abmin.Z); - c[3] = new Vector3(abmin.X, abmax.Y, abmax.Z); - c[4] = new Vector3(abmax.X, abmin.Y, abmin.Z); - c[5] = new Vector3(abmax.X, abmin.Y, abmax.Z); - c[6] = new Vector3(abmax.X, abmax.Y, abmin.Z); - c[7] = abmax; - var bbmin = new Vector3(float.MaxValue); - var bbmax = new Vector3(float.MinValue); - for (int j = 0; j < 8; j++) - { - Vector3 corn = ori.Multiply(c[j]) + pos; - bbmin = Vector3.Min(bbmin, corn); - bbmax = Vector3.Max(bbmax, corn); - } - - - var ints = new uint[len]; - ints[0] = (uint)(bbmin.X * 10.0f); - ints[1] = (uint)(bbmin.Y * 10.0f); - ints[2] = (uint)(bbmin.Z * 10.0f); - ints[3] = (uint)(bbmax.X * 10.0f); - ints[4] = (uint)(bbmax.Y * 10.0f); - ints[5] = (uint)(bbmax.Z * 10.0f); - ints[6] = (uint)lightIndex + 1; - - return ComputeHash(ints); - } - } - - - private AABB_s GetAABB(YmapEntityDef ent) - { - var arch = ent.Archetype; - var ori = ent.Orientation; - Vector3 bbmin = ent.Position - ent.BSRadius; //sphere - Vector3 bbmax = ent.Position + ent.BSRadius; - if (arch != null) - { - Vector3[] c = new Vector3[8]; - Vector3 abmin = arch.BBMin * ent.Scale; //entity box - Vector3 abmax = arch.BBMax * ent.Scale; - c[0] = abmin; - c[1] = new Vector3(abmin.X, abmin.Y, abmax.Z); - c[2] = new Vector3(abmin.X, abmax.Y, abmin.Z); - c[3] = new Vector3(abmin.X, abmax.Y, abmax.Z); - c[4] = new Vector3(abmax.X, abmin.Y, abmin.Z); - c[5] = new Vector3(abmax.X, abmin.Y, abmax.Z); - c[6] = new Vector3(abmax.X, abmax.Y, abmin.Z); - c[7] = abmax; - bbmin = new Vector3(float.MaxValue); - bbmax = new Vector3(float.MinValue); - for (int j = 0; j < 8; j++) - { - Vector3 corn = ori.Multiply(c[j]) + ent.Position; - bbmin = Vector3.Min(bbmin, corn); - bbmax = Vector3.Max(bbmax, corn); - } - } - AABB_s b = new AABB_s(); - b.Min = new Vector4(bbmin, 0f); - b.Max = new Vector4(bbmax, 0f); - return b; - } - private AABB_s GetAABB2(YmapEntityDef ent) - { - var arch = ent.Archetype; - var ori = ent.Orientation; - var pos = ent.Position; - var sca = ent.Scale; - var mat = Matrix.Transformation(Vector3.Zero, Quaternion.Identity, sca, Vector3.Zero, ori, pos); - var matabs = mat; - matabs.Column1 = mat.Column1.Abs(); - matabs.Column2 = mat.Column2.Abs(); - matabs.Column3 = mat.Column3.Abs(); - matabs.Column4 = mat.Column4.Abs(); - Vector3 bbmin = pos - ent.BSRadius; //sphere - Vector3 bbmax = pos + ent.BSRadius; - if (arch != null) - { - var bbcenter = (arch.BBMax + arch.BBMin) * 0.5f; - var bbextent = (arch.BBMax - arch.BBMin) * 0.5f; - var ncenter = Vector3.TransformCoordinate(bbcenter, mat); - var nextent = Vector3.TransformNormal(bbextent, matabs); - bbmin = ncenter - nextent; - bbmax = ncenter + nextent; - } - AABB_s b = new AABB_s(); - b.Min = new Vector4(bbmin, 0f); - b.Max = new Vector4(bbmax, 0f); - return b; - } - - - - private static uint RotateLeft(uint value, int count) - { - return (value << count) | (value >> (32 - count)); - } - private static uint RotateRight(uint value, int count) - { - return (value >> count) | (value << (32 - count)); - } - private static int RotateLeft(int value, int count) - { - return (int)RotateLeft((uint)value, count); - } - private static int RotateRight(int value, int count) - { - return (int)RotateRight((uint)value, count); - } - public class Light { public MetaVECTOR3 position { get; set; } diff --git a/CodeWalker/Rendering/Renderer.cs b/CodeWalker/Rendering/Renderer.cs index 04fe10e..7622b8d 100644 --- a/CodeWalker/Rendering/Renderer.cs +++ b/CodeWalker/Rendering/Renderer.cs @@ -3263,15 +3263,20 @@ namespace CodeWalker.Rendering } - if (renderlights && shaders.deferred && (rndbl.Lights != null) && interiorent)//only interior ents making lights! todo: fix LOD lights + if (renderlights && shaders.deferred && (rndbl.Lights != null)) { - var linst = new RenderableLightInst(); - for (int i = 0; i < rndbl.Lights.Length; i++) + entity?.EnsureLights(rndbl.Key); + + if (interiorent)//only interior ents making lights! todo: fix LOD lights { - linst.EntityPosition = position; - linst.EntityRotation = orientation; - linst.Light = rndbl.Lights[i]; - shaders.Enqueue(ref linst); + var linst = new RenderableLightInst(); + for (int i = 0; i < rndbl.Lights.Length; i++) + { + linst.EntityPosition = position; + linst.EntityRotation = orientation; + linst.Light = rndbl.Lights[i]; + shaders.Enqueue(ref linst); + } } }