diff --git a/CodeWalker.Core/World/Space.cs b/CodeWalker.Core/World/Space.cs index 77f5b08..1ae815f 100644 --- a/CodeWalker.Core/World/Space.cs +++ b/CodeWalker.Core/World/Space.cs @@ -1007,7 +1007,7 @@ namespace CodeWalker.World var pos = cam.Position; var min = pos - dist; var max = pos + dist; - var items = BoundsStore.GetItems(ref min, ref max); + var items = BoundsStore.GetItems(ref min, ref max, layers); boundslist.AddRange(items); } @@ -1721,24 +1721,24 @@ namespace CodeWalker.World RootNode.TrySplit(SplitThreshold); } - public List GetItems(ref Vector3 min, ref Vector3 max) + public List GetItems(ref Vector3 min, ref Vector3 max, bool[] layers = null) { VisibleItems.Clear(); if (RootNode != null) { - RootNode.GetItems(ref min, ref max, VisibleItems); + RootNode.GetItems(ref min, ref max, VisibleItems, layers); } return VisibleItems; } - public List GetItems(ref Ray ray) + public List GetItems(ref Ray ray, bool[] layers = null) { VisibleItems.Clear(); if (RootNode != null) { - RootNode.GetItems(ref ray, VisibleItems); + RootNode.GetItems(ref ray, VisibleItems, layers); } return VisibleItems; @@ -1817,7 +1817,7 @@ namespace CodeWalker.World Items = newItems; } - public void GetItems(ref Vector3 min, ref Vector3 max, List items) + public void GetItems(ref Vector3 min, ref Vector3 max, List items, bool[] layers = null) { if ((max.X >= BBMin.X) && (min.X <= BBMax.X) && (max.Y >= BBMin.Y) && (min.Y <= BBMax.Y)) { @@ -1826,6 +1826,10 @@ namespace CodeWalker.World for (int i = 0; i < Items.Count; i++) { var item = Items[i]; + + if ((layers != null) && (item.Layer < 3) && (!layers[item.Layer])) + { continue; } + if ((max.X >= item.Min.X) && (min.X <= item.Max.X) && (max.Y >= item.Min.Y) && (min.Y <= item.Max.Y)) { items.Add(item); @@ -1839,13 +1843,13 @@ namespace CodeWalker.World var c = Children[i]; if (c != null) { - c.GetItems(ref min, ref max, items); + c.GetItems(ref min, ref max, items, layers); } } } } } - public void GetItems(ref Ray ray, List items) + public void GetItems(ref Ray ray, List items, bool[] layers = null) { var box = new BoundingBox(BBMin, BBMax); if (ray.Intersects(ref box)) @@ -1855,6 +1859,10 @@ namespace CodeWalker.World for (int i = 0; i < Items.Count; i++) { var item = Items[i]; + + if ((layers != null) && (item.Layer < 3) && (!layers[item.Layer])) + { continue; } + box = new BoundingBox(item.Min, item.Max); if (ray.Intersects(box)) { @@ -1869,7 +1877,7 @@ namespace CodeWalker.World var c = Children[i]; if (c != null) { - c.GetItems(ref ray, items); + c.GetItems(ref ray, items, layers); } } } diff --git a/Rendering/Renderable.cs b/Rendering/Renderable.cs index 062e20e..fe56fed 100644 --- a/Rendering/Renderable.cs +++ b/Rendering/Renderable.cs @@ -1846,38 +1846,97 @@ namespace CodeWalker.Rendering } - public class RenderableBoundComposite : RenderableCacheItem + public class RenderableBoundComposite : RenderableCacheItem { public RenderableBoundGeometry[] Geometries; - public override void Init(BoundComposite bound) + public override void Init(Bounds bound) { Key = bound; + if (bound is BoundComposite boundcomp) + { + InitBoundComp(boundcomp); + } + else + { + var rgeom = new RenderableBoundGeometry(this); + var xform = Matrix.Identity; + if (bound is BoundBox boundbox) + { + rgeom.Init(boundbox, ref xform); + } + else if (bound is BoundSphere boundsph) + { + rgeom.Init(boundsph, ref xform); + } + else if (bound is BoundCylinder boundcyl) + { + rgeom.Init(boundcyl, ref xform); + } + else if (bound is BoundCapsule boundcap) + { + rgeom.Init(boundcap, ref xform); + } + else if (bound is BoundDisc boundisc) + { + rgeom.Init(boundisc, ref xform); + } + else + { } + + Geometries = new[] { rgeom }; + DataSize = 64;//just a guesstimate + } + } + + private void InitBoundComp(BoundComposite bound) + { if (bound.Children == null) { return; } RenderableBoundGeometry[] geoms = new RenderableBoundGeometry[bound.Children.data_items.Length]; + var childTransforms = bound.ChildrenTransformation1 ?? bound.ChildrenTransformation2; long dsize = 0; for (int i = 0; i < bound.Children.data_items.Length; i++) { + var rgeom = new RenderableBoundGeometry(this); var child = bound.Children.data_items[i]; - if (child is BoundGeometry) + var xform = ((childTransforms != null) && (i < childTransforms.Length)) ? childTransforms[i] : Matrix.Identity; xform.Column4 = new Vector4(0.0f, 0.0f, 0.0f, 1.0f); + if (child is BoundGeometry bgeom) + { + rgeom.Init(bgeom); + } + else if (child is BoundCapsule bcap) + { + rgeom.Init(bcap, ref xform); + } + else if (child is BoundSphere bsph) + { + rgeom.Init(bsph, ref xform); + } + else if (child is BoundBox bbox) + { + rgeom.Init(bbox, ref xform); + } + else if (child is BoundCylinder bcyl) + { + rgeom.Init(bcyl, ref xform); + } + else if (child is BoundDisc bdisc) + { + rgeom.Init(bdisc, ref xform); + } + else if (child != null) + { } + if (rgeom.Initialised) { - var rgeom = new RenderableBoundGeometry(); - rgeom.Init(child as BoundGeometry); - rgeom.Owner = this; geoms[i] = rgeom; dsize += rgeom.TotalDataSize; } - else - { - //other types of bound might be here, eg BoundBox - geoms[i] = null;//not really necessary - } } Geometries = geoms; @@ -1888,11 +1947,13 @@ namespace CodeWalker.Rendering public override void Load(Device device) { - if (Geometries == null) return; - foreach (var geom in Geometries) + if (Geometries != null) { - if (geom == null) continue; - geom.Load(device); + foreach (var geom in Geometries) + { + if (geom == null) continue; + geom.Load(device); + } } //LastUseTime = DateTime.Now; //reset usage timer IsLoaded = true; @@ -1901,11 +1962,13 @@ namespace CodeWalker.Rendering public override void Unload() { IsLoaded = false; - if (Geometries == null) return; - foreach (var geom in Geometries) + if (Geometries != null) { - if (geom == null) continue; - geom.Unload(); + foreach (var geom in Geometries) + { + if (geom == null) continue; + geom.Unload(); + } } LoadQueued = false; } @@ -1922,7 +1985,6 @@ namespace CodeWalker.Rendering public Buffer VertexBuffer { get; set; } //public Buffer IndexBuffer { get; set; } public VertexBufferBinding VBBinding; - public BoundGeometry BoundGeom; public VertexType VertexType { get; set; } = VertexType.Default; public int VertexStride { get; set; } = 36; public int VertexCount { get; set; } = 0; @@ -1939,9 +2001,30 @@ namespace CodeWalker.Rendering public GpuSBuffer CapsuleBuffer { get; set; } public GpuSBuffer CylinderBuffer { get; set; } + + public Bounds Bound; + public BoundGeometry BoundGeom; + public Vector3 CenterGeom; + public Vector3 BBMin; + public Vector3 BBMax; + public Vector3 BBOffset = Vector3.Zero; + public Quaternion BBOrientation = Quaternion.Identity; + + public bool Initialised = false; + + + public RenderableBoundGeometry(RenderableBoundComposite owner) + { + Owner = owner; + } + public void Init(BoundGeometry bgeom) { + Bound = bgeom; BoundGeom = bgeom; + CenterGeom = bgeom.CenterGeom; + BBMin = bgeom.BoundingBoxMin; + BBMax = bgeom.BoundingBoxMax; if ((bgeom.Polygons == null) || (bgeom.Vertices == null)) { @@ -2077,7 +2160,141 @@ namespace CodeWalker.Rendering VertexDataSize = (uint)(VertexCount * VertexStride); TotalDataSize = VertexDataSize; + Initialised = true; } + public void Init(BoundCapsule bcap, ref Matrix xform) + { + Matrix rmat = xform; + rmat.TranslationVector = Vector3.Zero; + + Bound = bcap; + BBMin = bcap.BoundingBoxMin; + BBMax = bcap.BoundingBoxMax; + BBOffset = xform.TranslationVector; + BBOrientation = Quaternion.RotationMatrix(rmat); + + var mat = (BoundsMaterialType)bcap.MaterialIndex; + var colourf = BoundsMaterialTypes.GetMaterialColour(mat); + var colour = (uint)colourf.ToRgba(); + + float extent = bcap.BoundingSphereRadius - bcap.Margin; + + var rcap = new RenderableCapsule(); + rcap.Colour = colour; + rcap.Point1 = Vector3.TransformCoordinate(bcap.Center - new Vector3(0, extent, 0), xform); + rcap.Orientation = BBOrientation; + rcap.Length = extent * 2.0f; + rcap.Radius = bcap.Margin; + + Capsules = new[] { rcap }; + + Initialised = true; + } + public void Init(BoundSphere bsph, ref Matrix xform) + { + Bound = bsph; + BBMin = bsph.BoundingBoxMin; + BBMax = bsph.BoundingBoxMax; + BBOffset = xform.TranslationVector; + + var mat = (BoundsMaterialType)bsph.MaterialIndex; + var colourf = BoundsMaterialTypes.GetMaterialColour(mat); + var colour = (uint)colourf.ToRgba(); + + var rsph = new RenderableSphere(); + rsph.Colour = colour; + rsph.Center = Vector3.TransformCoordinate(bsph.Center, xform); + rsph.Radius = bsph.BoundingSphereRadius; + + Spheres = new[] { rsph }; + + Initialised = true; + } + public void Init(BoundBox bbox, ref Matrix xform) + { + Matrix rmat = xform; + rmat.TranslationVector = Vector3.Zero; + + Bound = bbox; + BBMin = bbox.BoundingBoxMin; + BBMax = bbox.BoundingBoxMax; + BBOffset = xform.TranslationVector; + BBOrientation = Quaternion.RotationMatrix(rmat); + + var mat = (BoundsMaterialType)bbox.MaterialIndex; + var colourf = BoundsMaterialTypes.GetMaterialColour(mat); + var colour = (uint)colourf.ToRgba(); + + var extent = (bbox.BoundingBoxMax - bbox.BoundingBoxMin).Abs(); + + var rbox = new RenderableBox(); + rbox.Colour = colour; + rbox.Corner = Vector3.TransformCoordinate(bbox.BoundingBoxMin, xform); + rbox.Edge1 = Vector3.TransformNormal(new Vector3(extent.X, 0, 0), xform); + rbox.Edge2 = Vector3.TransformNormal(new Vector3(0, extent.Y, 0), xform); + rbox.Edge3 = Vector3.TransformNormal(new Vector3(0, 0, extent.Z), xform); + + Boxes = new[] { rbox }; + + Initialised = true; + } + public void Init(BoundCylinder bcyl, ref Matrix xform) + { + Matrix rmat = xform; + rmat.TranslationVector = Vector3.Zero; + + Bound = bcyl; + BBMin = bcyl.BoundingBoxMin; + BBMax = bcyl.BoundingBoxMax; + BBOffset = xform.TranslationVector; + BBOrientation = Quaternion.RotationMatrix(rmat); + + var mat = (BoundsMaterialType)bcyl.MaterialIndex; + var colourf = BoundsMaterialTypes.GetMaterialColour(mat); + var colour = (uint)colourf.ToRgba(); + + var extent = (bcyl.BoundingBoxMax - bcyl.BoundingBoxMin).Abs(); + var length = extent.Y; + var radius = extent.X * 0.5f; + + var rcyl = new RenderableCylinder(); + rcyl.Colour = colour; + rcyl.Point1 = Vector3.TransformCoordinate(bcyl.Center - new Vector3(0, length * 0.5f, 0), xform); + rcyl.Orientation = BBOrientation; + rcyl.Length = length; + rcyl.Radius = radius; + + Cylinders = new[] { rcyl }; + + Initialised = true; + } + public void Init(BoundDisc bdisc, ref Matrix xform) + { + Matrix rmat = xform; + rmat.TranslationVector = Vector3.Zero; + + Bound = bdisc; + BBMin = bdisc.BoundingBoxMin; + BBMax = bdisc.BoundingBoxMax; + BBOffset = xform.TranslationVector; + BBOrientation = Quaternion.LookAtLH(Vector3.Zero, Vector3.UnitX, Vector3.UnitZ) * Quaternion.RotationMatrix(rmat); + + var mat = (BoundsMaterialType)bdisc.MaterialIndex; + var colourf = BoundsMaterialTypes.GetMaterialColour(mat); + var colour = (uint)colourf.ToRgba(); + + var rcyl = new RenderableCylinder(); + rcyl.Colour = colour; + rcyl.Point1 = Vector3.TransformCoordinate(bdisc.Center - new Vector3(bdisc.Margin, 0, 0), xform); + rcyl.Orientation = BBOrientation; + rcyl.Length = bdisc.Margin * 2.0f; + rcyl.Radius = bdisc.BoundingSphereRadius; + + Cylinders = new[] { rcyl }; + + Initialised = true; + } + private ushort AddVertex(Vector3 pos, Vector3 norm, uint colour, List list) { diff --git a/Rendering/RenderableCache.cs b/Rendering/RenderableCache.cs index facc1ad..ebe00c8 100644 --- a/Rendering/RenderableCache.cs +++ b/Rendering/RenderableCache.cs @@ -96,7 +96,7 @@ namespace CodeWalker.Rendering private RenderableCacheLookup renderables = new RenderableCacheLookup(Settings.Default.GPUGeometryCacheSize, Settings.Default.GPUCacheTime); private RenderableCacheLookup textures = new RenderableCacheLookup(Settings.Default.GPUTextureCacheSize, Settings.Default.GPUCacheTime); - private RenderableCacheLookup boundcomps = new RenderableCacheLookup(Settings.Default.GPUBoundCompCacheSize, Settings.Default.GPUCacheTime); + private RenderableCacheLookup boundcomps = new RenderableCacheLookup(Settings.Default.GPUBoundCompCacheSize, Settings.Default.GPUCacheTime); private RenderableCacheLookup instbatches = new RenderableCacheLookup(67108864, Settings.Default.GPUCacheTime); //64MB - todo: make this a setting private RenderableCacheLookup lodlights = new RenderableCacheLookup(33554432, Settings.Default.GPUCacheTime); //32MB - todo: make this a setting private RenderableCacheLookup distlodlights = new RenderableCacheLookup(33554432, Settings.Default.GPUCacheTime); //32MB - todo: make this a setting @@ -204,9 +204,9 @@ namespace CodeWalker.Rendering { return textures.Get(texture); } - public RenderableBoundComposite GetRenderableBoundComp(BoundComposite boundcomp) + public RenderableBoundComposite GetRenderableBoundComp(Bounds bound) { - return boundcomps.Get(boundcomp); + return boundcomps.Get(bound); } public RenderableInstanceBatch GetRenderableInstanceBatch(YmapGrassInstanceBatch batch) { diff --git a/Rendering/Renderer.cs b/Rendering/Renderer.cs index 9b96390..6b34822 100644 --- a/Rendering/Renderer.cs +++ b/Rendering/Renderer.cs @@ -1557,6 +1557,7 @@ namespace CodeWalker.Rendering { if (renderinteriors && (ent.MloInstance != null) && !MapViewEnabled) //render Mlo child entities... { + renderworldentities.Add(ent);//collisions rendering needs this RenderWorldAddInteriorEntities(ent); } } @@ -2808,19 +2809,19 @@ namespace CodeWalker.Rendering { RenderCollisionMesh(sdrawable.Bound, entity); } - //FragDrawable fdrawable = rndbl.Key as FragDrawable; - //if (fdrawable != null) - //{ - // if (fdrawable.Bound != null) - // { - // RenderCollisionMesh(fdrawable.Bound, entity); - // } - // var fbound = fdrawable.OwnerFragment?.PhysicsLODGroup?.PhysicsLOD1?.Bound; - // if (fbound != null) - // { - // RenderCollisionMesh(fbound, entity); - // } - //} + FragDrawable fdrawable = rndbl.Key as FragDrawable; + if (fdrawable != null) + { + if (fdrawable.Bound != null) + { + RenderCollisionMesh(fdrawable.Bound, entity); + } + var fbound = fdrawable.OwnerFragment?.PhysicsLODGroup?.PhysicsLOD1?.Bound; + if (fbound != null) + { + RenderCollisionMesh(fbound, entity);//TODO: these probably have extra transforms..! + } + } } if (renderskeletons && rndbl.HasSkeleton) { @@ -3111,53 +3112,31 @@ namespace CodeWalker.Rendering orientation = Quaternion.Identity; } - switch (bounds.Type) + RenderableBoundComposite rndbc = renderableCache.GetRenderableBoundComp(bounds); + if (rndbc.IsLoaded) { - case 10: //BoundComposite - BoundComposite boundcomp = bounds as BoundComposite; - if (boundcomp != null) - { - RenderableBoundComposite rndbc = renderableCache.GetRenderableBoundComp(boundcomp); - if (rndbc.IsLoaded) - { - RenderableBoundGeometryInst rbginst = new RenderableBoundGeometryInst(); - rbginst.Inst.Renderable = rndbc; - rbginst.Inst.Orientation = orientation; - rbginst.Inst.Scale = scale; - foreach (var geom in rndbc.Geometries) - { - if (geom == null) continue; - rbginst.Geom = geom; - rbginst.Inst.Position = position + orientation.Multiply(geom.BoundGeom.CenterGeom * scale); - rbginst.Inst.CamRel = rbginst.Inst.Position - camera.Position; - shaders.Enqueue(ref rbginst); - } + RenderableBoundGeometryInst rbginst = new RenderableBoundGeometryInst(); + rbginst.Inst.Renderable = rndbc; + rbginst.Inst.Orientation = orientation; + rbginst.Inst.Scale = scale; + foreach (var geom in rndbc.Geometries) + { + if (geom == null) continue; + rbginst.Geom = geom; + rbginst.Inst.Position = position + orientation.Multiply(geom.CenterGeom * scale); + rbginst.Inst.CamRel = rbginst.Inst.Position - camera.Position; + shaders.Enqueue(ref rbginst); + } - if (RenderedBoundCompsListEnable) //for later hit tests - { - var rb = new RenderedBoundComposite(); - rb.BoundComp = rndbc; - rb.Entity = entity; - RenderedBoundComps.Add(rb); - } - } - } - else - { } - break; - case 3: //BoundBox - found in drawables - TODO - BoundBox boundbox = bounds as BoundBox; - if (boundbox == null) - { } - break; - case 0: //BoundSphere - found in drawables - TODO - BoundSphere boundsphere = bounds as BoundSphere; - if (boundsphere == null) - { } - break; - default: - break; + if (RenderedBoundCompsListEnable) //for later hit tests + { + var rb = new RenderedBoundComposite(); + rb.BoundComp = rndbc; + rb.Entity = entity; + RenderedBoundComps.Add(rb); + } } + } diff --git a/Utils/MapUtils.cs b/Utils/MapUtils.cs index e320884..d62cf01 100644 --- a/Utils/MapUtils.cs +++ b/Utils/MapUtils.cs @@ -200,6 +200,8 @@ namespace CodeWalker public bool MultipleSelection { get; set; } public Vector3 MultipleSelectionCenter { get; set; } + public Vector3 BBOffset { get; set; } + public Quaternion BBOrientation { get; set; } public BoundingBox AABB { get; set; } public BoundingSphere BSphere { get; set; } public int GeometryIndex { get; set; } diff --git a/WorldForm.cs b/WorldForm.cs index ef71e44..1215d59 100644 --- a/WorldForm.cs +++ b/WorldForm.cs @@ -1248,6 +1248,10 @@ namespace CodeWalker mode = BoundsShaderMode.Sphere; } } + if (CurMouseHit.CollisionBounds != null) + { + ori = ori * CurMouseHit.BBOrientation; + } Renderer.RenderMouseHit(mode, clip, ref camrel, ref bbmin, ref bbmax, ref scale, ref ori, bsphrad); @@ -1534,6 +1538,11 @@ namespace CodeWalker Renderer.WhiteBoxes.Add(wbox); } } + if (selectionItem.CollisionBounds != null) + { + camrel += ori.Multiply(selectionItem.BBOffset); + ori = ori * selectionItem.BBOrientation; + } if (mode == BoundsShaderMode.Box) { @@ -2562,10 +2571,8 @@ namespace CodeWalker mray.Position = camera.MouseRay.Position + camera.Position; mray.Direction = camera.MouseRay.Direction; float hitdist = float.MaxValue; - Quaternion orinv = Quaternion.Invert(orientation); + Ray mraytrn = new Ray(); - mraytrn.Position = orinv.Multiply(camera.MouseRay.Position - camrel); - mraytrn.Direction = orinv.Multiply(mray.Direction); MapBox mb = new MapBox(); mb.CamRelPos = camrel;// rbginst.Inst.CamRel; @@ -2576,23 +2583,31 @@ namespace CodeWalker { if (geom == null) continue; - mb.BBMin = geom.BoundGeom.BoundingBoxMin; - mb.BBMax = geom.BoundGeom.BoundingBoxMax; + mb.BBMin = geom.BBMin; + mb.BBMax = geom.BBMax; + mb.CamRelPos = camrel + orientation.Multiply(geom.BBOffset); + mb.Orientation = orientation * geom.BBOrientation; - var cent = camrel + (mb.BBMin + mb.BBMax) * 0.5f; + var cent = mb.CamRelPos + (mb.BBMin + mb.BBMax) * 0.5f; if (cent.Length() > Renderer.renderboundsmaxdist) continue; Renderer.BoundingBoxes.Add(mb); + Quaternion orinv = Quaternion.Invert(mb.Orientation); + mraytrn.Position = orinv.Multiply(camera.MouseRay.Position - mb.CamRelPos); + mraytrn.Direction = orinv.Multiply(mray.Direction); + bbox.Minimum = mb.BBMin * scale; bbox.Maximum = mb.BBMax * scale; if (mraytrn.Intersects(ref bbox, out hitdist) && (hitdist < CurMouseHit.HitDist) && (hitdist > 0)) { - CurMouseHit.CollisionBounds = geom.BoundGeom; + CurMouseHit.CollisionBounds = geom.Bound; CurMouseHit.EntityDef = entity; CurMouseHit.Archetype = entity?.Archetype; CurMouseHit.HitDist = hitdist; - CurMouseHit.CamRel = camrel; + CurMouseHit.CamRel = mb.CamRelPos; + CurMouseHit.BBOffset = geom.BBOffset; + CurMouseHit.BBOrientation = geom.BBOrientation; CurMouseHit.AABB = bbox; } }