From 844097b132a6a777ef925205cce3852828b19706 Mon Sep 17 00:00:00 2001 From: Regalis Date: Sat, 25 Feb 2017 21:24:38 +0200 Subject: [PATCH 01/10] Initial steps in making the light rendering use light volumes instead of shadow volumes to allow rendering the lights in one batch. So far just disabled shadow rendering and cleaned up some unnecessary stuff --- Subsurface/Source/Map/Lights/ConvexHull.cs | 53 +++++++++++++++ Subsurface/Source/Map/Lights/LightManager.cs | 37 +--------- Subsurface/Source/Map/Lights/LightSource.cs | 71 ++++---------------- 3 files changed, 70 insertions(+), 91 deletions(-) diff --git a/Subsurface/Source/Map/Lights/ConvexHull.cs b/Subsurface/Source/Map/Lights/ConvexHull.cs index c48285988..d0e3fb589 100644 --- a/Subsurface/Source/Map/Lights/ConvexHull.cs +++ b/Subsurface/Source/Map/Lights/ConvexHull.cs @@ -397,6 +397,59 @@ namespace Barotrauma.Lights } } + public static List GetHullsInRange(Vector2 position, float range, Submarine ParentSub) + { + List list = new List(); + + foreach (ConvexHullList chList in ConvexHull.HullLists) + { + Vector2 lightPos = position; + if (ParentSub == null) + { + //light and the convexhull are both outside + if (chList.Submarine == null) + { + list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox))); + + } + //light is outside, convexhull inside a sub + else + { + if (!MathUtils.CircleIntersectsRectangle(lightPos - chList.Submarine.WorldPosition, range, chList.Submarine.Borders)) continue; + + lightPos -= (chList.Submarine.WorldPosition - chList.Submarine.HiddenSubPosition); + + list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox))); + } + } + else + { + //light is inside, convexhull outside + if (chList.Submarine == null) continue; + + //light and convexhull are both inside the same sub + if (chList.Submarine == ParentSub) + { + list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox))); + } + //light and convexhull are inside different subs + else + { + lightPos -= (chList.Submarine.Position - ParentSub.Position); + + Rectangle subBorders = chList.Submarine.Borders; + subBorders.Location += chList.Submarine.HiddenSubPosition.ToPoint() - new Point(0, chList.Submarine.Borders.Height); + + if (!MathUtils.CircleIntersectsRectangle(lightPos, range, subBorders)) continue; + + list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox))); + } + } + } + + return list; + } + public void DrawShadows(GraphicsDevice graphicsDevice, Camera cam, LightSource light, Matrix transform, bool los = true) { if (!Enabled) return; diff --git a/Subsurface/Source/Map/Lights/LightManager.cs b/Subsurface/Source/Map/Lights/LightManager.cs index b3d4c8382..4040be2ab 100644 --- a/Subsurface/Source/Map/Lights/LightManager.cs +++ b/Subsurface/Source/Map/Lights/LightManager.cs @@ -133,45 +133,19 @@ namespace Barotrauma.Lights //clear to some small ambient light graphics.Clear(AmbientLight); + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, null, null, null, cam.Transform); + foreach (LightSource light in lights) { if (light.Color.A < 1 || light.Range < 1.0f || !light.CastShadows) continue; if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, light.Range, viewRect)) continue; - - //clear alpha to 1 - ClearAlphaToOne(graphics, spriteBatch); - - //draw all shadows - //write only to the alpha channel, which sets alpha to 0 - graphics.RasterizerState = RasterizerState.CullNone; - graphics.BlendState = CustomBlendStates.WriteToAlpha; - light.DrawShadows(graphics, cam, shadowTransform); - - //draw the light shape - //where Alpha is 0, nothing will be written - spriteBatch.Begin(SpriteSortMode.Deferred, CustomBlendStates.MultiplyWithAlpha, null, null, null, null, cam.Transform); light.Draw(spriteBatch); - spriteBatch.End(); } - - ClearAlphaToOne(graphics, spriteBatch); - - spriteBatch.Begin(SpriteSortMode.Deferred, CustomBlendStates.MultiplyWithAlpha, null, null, null, null, cam.Transform); - GameMain.ParticleManager.Draw(spriteBatch, false, Particles.ParticleBlendState.Additive); - - foreach (LightSource light in lights) - { - if (light.Color.A < 1 || light.Range < 1.0f || light.CastShadows) continue; - //if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, light.Range, viewRect)) continue; - - light.Draw(spriteBatch); - } - if (Character.Controlled != null) { if (Character.Controlled.ClosestItem != null) @@ -185,10 +159,6 @@ namespace Barotrauma.Lights Character.Controlled.ClosestCharacter.Draw(spriteBatch); } } - spriteBatch.End(); - - - spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, null, null, null, cam.Transform); foreach (Hull hull in smoothedHullAmbientLights.Keys) { @@ -207,7 +177,6 @@ namespace Barotrauma.Lights spriteBatch.End(); - //clear alpha, to avoid messing stuff up later ClearAlphaToOne(graphics, spriteBatch); @@ -253,7 +222,7 @@ namespace Barotrauma.Lights Matrix shadowTransform = cam.ShaderTransform * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f; - var convexHulls = LightSource.GetHullsInRange(viewTarget.Position, cam.WorldView.Width*0.75f, viewTarget.Submarine); + var convexHulls = ConvexHull.GetHullsInRange(viewTarget.Position, cam.WorldView.Width*0.75f, viewTarget.Submarine); if (convexHulls != null) { diff --git a/Subsurface/Source/Map/Lights/LightSource.cs b/Subsurface/Source/Map/Lights/LightSource.cs index f6d21525d..0b64f0206 100644 --- a/Subsurface/Source/Map/Lights/LightSource.cs +++ b/Subsurface/Source/Map/Lights/LightSource.cs @@ -136,7 +136,7 @@ namespace Barotrauma.Lights GameMain.LightManager.AddLight(this); } - public void DrawShadows(GraphicsDevice graphics, Camera cam, Matrix shadowTransform) + /*public void DrawShadows(GraphicsDevice graphics, Camera cam, Matrix shadowTransform) { if (!CastShadows) return; if (range < 1.0f || color.A < 0.01f) return; @@ -161,9 +161,9 @@ namespace Barotrauma.Lights foreach (ConvexHull ch in outsideHulls) { ch.DrawShadows(graphics, cam, this, shadowTransform, false); - } - } - + } + } + private List GetHullsInRange(Submarine sub) { //find the current list of hulls in range @@ -237,62 +237,20 @@ namespace Barotrauma.Lights } return chList.List; - } + }*/ - public static List GetHullsInRange(Vector2 position, float range, Submarine ParentSub) + private void CalculateFanVertices() { - List list = new List(); + if (!CastShadows) return; + if (range < 1.0f || color.A < 0.01f) return; - foreach (ConvexHullList chList in ConvexHull.HullLists) - { - Vector2 lightPos = position; - if (ParentSub == null) - { - //light and the convexhull are both outside - if (chList.Submarine == null) - { - list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox))); - - } - //light is outside, convexhull inside a sub - else - { - if (!MathUtils.CircleIntersectsRectangle(lightPos - chList.Submarine.WorldPosition, range, chList.Submarine.Borders)) continue; - - lightPos -= (chList.Submarine.WorldPosition - chList.Submarine.HiddenSubPosition); - - list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox))); - } - } - else - { - //light is inside, convexhull outside - if (chList.Submarine == null) continue; - - //light and convexhull are both inside the same sub - if (chList.Submarine == ParentSub) - { - list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox))); - } - //light and convexhull are inside different subs - else - { - lightPos -= (chList.Submarine.Position - ParentSub.Position); - - Rectangle subBorders = chList.Submarine.Borders; - subBorders.Location += chList.Submarine.HiddenSubPosition.ToPoint() - new Point(0, chList.Submarine.Borders.Height); - - if (!MathUtils.CircleIntersectsRectangle(lightPos, range, subBorders)) continue; - - list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox))); - } - } - } - - - return list; + var hulls = ConvexHull.GetHullsInRange(position, range, ParentSub); + + //TODO: calculate fan based on hulls + + //http://www.redblobgames.com/articles/visibility/ + //http://roy-t.nl/index.php/2014/02/27/2d-lighting-and-shadows-preview/ } - public void Draw(SpriteBatch spriteBatch) { @@ -323,7 +281,6 @@ namespace Barotrauma.Lights if (LightSprite != null) { LightSprite.Draw(spriteBatch, drawPos, Color, LightSprite.Origin, -Rotation, 1, SpriteEffect); - } } From bcabe4ab393ff1bb89316ae90b6399ead98a0053 Mon Sep 17 00:00:00 2001 From: Regalis Date: Sat, 25 Feb 2017 21:50:11 +0200 Subject: [PATCH 02/10] Disabled convexhull shadow caching --- Subsurface/Source/Map/Lights/ConvexHull.cs | 52 +++++++--------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/Subsurface/Source/Map/Lights/ConvexHull.cs b/Subsurface/Source/Map/Lights/ConvexHull.cs index d0e3fb589..f35a96c45 100644 --- a/Subsurface/Source/Map/Lights/ConvexHull.cs +++ b/Subsurface/Source/Map/Lights/ConvexHull.cs @@ -7,7 +7,7 @@ using System.Linq; namespace Barotrauma.Lights { - class CachedShadow : IDisposable + /*class CachedShadow : IDisposable { public VertexBuffer ShadowBuffer; @@ -40,7 +40,7 @@ namespace Barotrauma.Lights { ShadowBuffer.Dispose(); } - } + }*/ class ConvexHullList { @@ -71,7 +71,9 @@ namespace Barotrauma.Lights static BasicEffect shadowEffect; static BasicEffect penumbraEffect; - private Dictionary cachedShadows; + //private Dictionary cachedShadows; + + public VertexBuffer ShadowBuffer; private Vector2[] vertices; private Vector2[] losVertices; @@ -124,7 +126,7 @@ namespace Barotrauma.Lights parentEntity = parent; - cachedShadows = new Dictionary(); + //cachedShadows = new Dictionary(); shadowVertices = new VertexPositionColor[6 * 2]; penumbraVertices = new VertexPositionTexture[6]; @@ -191,8 +193,6 @@ namespace Barotrauma.Lights public void Move(Vector2 amount) { - ClearCachedShadows(); - for (int i = 0; i < vertices.Length; i++) { vertices[i] += amount; @@ -204,8 +204,6 @@ namespace Barotrauma.Lights public void SetVertices(Vector2[] points) { - ClearCachedShadows(); - vertices = points; losVertices = points; @@ -231,7 +229,7 @@ namespace Barotrauma.Lights CalculateDimensions(); } - private void RemoveCachedShadow(Lights.LightSource light) + /*private void RemoveCachedShadow(Lights.LightSource light) { CachedShadow shadow = null; cachedShadows.TryGetValue(light, out shadow); @@ -251,7 +249,7 @@ namespace Barotrauma.Lights cachedShadow.Value.Dispose(); } cachedShadows.Clear(); - } + }*/ public bool Intersects(Rectangle rect) { @@ -468,29 +466,13 @@ namespace Barotrauma.Lights } } - - CachedShadow cachedShadow = null; - if (!cachedShadows.TryGetValue(light, out cachedShadow) || - Vector2.DistanceSquared(lightSourcePos, cachedShadow.LightPos) > 1.0f) - { - CalculateShadowVertices(lightSourcePos, los); - - if (cachedShadow != null) - { - cachedShadow.LightPos = lightSourcePos; - cachedShadow.ShadowBuffer.SetData(shadowVertices, 0, shadowVertices.Length); - cachedShadow.ShadowVertexCount = shadowVertexCount; - } - else - { - cachedShadow = new CachedShadow(shadowVertices, lightSourcePos, shadowVertexCount, 0); - RemoveCachedShadow(light); - cachedShadows.Add(light, cachedShadow); - } - } - - graphicsDevice.SetVertexBuffer(cachedShadow.ShadowBuffer); - shadowVertexCount = cachedShadow.ShadowVertexCount; + + CalculateShadowVertices(lightSourcePos, los); + ShadowBuffer = new VertexBuffer(GameMain.CurrGraphicsDevice, VertexPositionColor.VertexDeclaration, 6 * 2, BufferUsage.None); + ShadowBuffer.SetData(shadowVertices, 0, shadowVertices.Length); + + graphicsDevice.SetVertexBuffer(ShadowBuffer); + shadowVertexCount = shadowVertices.Length; DrawShadows(graphicsDevice, cam, transform, los); } @@ -546,8 +528,6 @@ namespace Barotrauma.Lights public void Remove() { - ClearCachedShadows(); - var chList = HullLists.Find(x => x.Submarine == parentEntity.Submarine); if (chList != null) @@ -559,8 +539,6 @@ namespace Barotrauma.Lights } } } - - } } From abfe2261d2d50df9c74b85d2f8e27b74ef9439b5 Mon Sep 17 00:00:00 2001 From: Regalis Date: Sun, 26 Feb 2017 01:17:22 +0200 Subject: [PATCH 03/10] - ConvexHulls consist of Segments and SegmentPoints which keep references to each other - LightSources fetch a list of non-backfacing ConvexHull segments within their range, and sort the points counter-clockwise (TODO: calculate triangles from the points) - fixed incorrectly working CircleIntersectsRectangle method --- Subsurface/Source/Map/Lights/ConvexHull.cs | 155 +++++++++++++++----- Subsurface/Source/Map/Lights/LightSource.cs | 35 ++++- Subsurface/Source/Utils/MathUtils.cs | 23 ++- 3 files changed, 163 insertions(+), 50 deletions(-) diff --git a/Subsurface/Source/Map/Lights/ConvexHull.cs b/Subsurface/Source/Map/Lights/ConvexHull.cs index f35a96c45..5a56766e4 100644 --- a/Subsurface/Source/Map/Lights/ConvexHull.cs +++ b/Subsurface/Source/Map/Lights/ConvexHull.cs @@ -65,6 +65,32 @@ namespace Barotrauma.Lights } } + class Segment + { + public SegmentPoint Start; + public SegmentPoint End; + + public Segment(SegmentPoint start, SegmentPoint end) + { + Start = start; + End = end; + } + } + + class SegmentPoint + { + public Vector2 Pos; + public Segment[] Segments; + + public Vector2 WorldPos; + + public SegmentPoint(Vector2 pos, Segment[] segments) + { + Pos = pos; + Segments = segments; + } + } + class ConvexHull { public static List HullLists = new List(); @@ -75,9 +101,12 @@ namespace Barotrauma.Lights public VertexBuffer ShadowBuffer; - private Vector2[] vertices; - private Vector2[] losVertices; - private int primitiveCount; + Segment[] segments = new Segment[4]; + SegmentPoint[] vertices = new SegmentPoint[4]; + SegmentPoint[] losVertices = new SegmentPoint[4]; + + //private Vector2[] vertices; + //private Vector2[] losVertices; private bool[] backFacing; private bool[] ignoreEdge; @@ -132,12 +161,11 @@ namespace Barotrauma.Lights penumbraVertices = new VertexPositionTexture[6]; //vertices = points; - primitiveCount = points.Length; SetVertices(points); //CalculateDimensions(); - backFacing = new bool[primitiveCount]; - ignoreEdge = new bool[primitiveCount]; + backFacing = new bool[4]; + ignoreEdge = new bool[4]; Enabled = true; @@ -161,10 +189,10 @@ namespace Barotrauma.Lights { for (int i = 0; i < vertices.Length; i++) { - if (vertices[i].X >= ch.boundingBox.X && vertices[i].X <= ch.boundingBox.Right && - vertices[i].Y >= ch.boundingBox.Y && vertices[i].Y <= ch.boundingBox.Bottom) + if (vertices[i].Pos.X >= ch.boundingBox.X && vertices[i].Pos.X <= ch.boundingBox.Right && + vertices[i].Pos.Y >= ch.boundingBox.Y && vertices[i].Pos.Y <= ch.boundingBox.Bottom) { - Vector2 p = vertices[(i + 1) % vertices.Length]; + Vector2 p = vertices[(i + 1) % vertices.Length].Pos; if (p.X >= ch.boundingBox.X && p.X <= ch.boundingBox.Right && p.Y >= ch.boundingBox.Y && p.Y <= ch.boundingBox.Bottom) @@ -181,11 +209,11 @@ namespace Barotrauma.Lights for (int i = 0; i < vertices.Length; i++) { - if (minX == null || vertices[i].X < minX) minX = vertices[i].X; - if (minY == null || vertices[i].Y < minY) minY = vertices[i].Y; + if (minX == null || vertices[i].Pos.X < minX) minX = vertices[i].Pos.X; + if (minY == null || vertices[i].Pos.Y < minY) minY = vertices[i].Pos.Y; - if (maxX == null || vertices[i].X > maxX) maxX = vertices[i].X; - if (maxY == null || vertices[i].Y > minY) maxY = vertices[i].Y; + if (maxX == null || vertices[i].Pos.X > maxX) maxX = vertices[i].Pos.X; + if (maxY == null || vertices[i].Pos.Y > minY) maxY = vertices[i].Pos.Y; } boundingBox = new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY)); @@ -195,8 +223,8 @@ namespace Barotrauma.Lights { for (int i = 0; i < vertices.Length; i++) { - vertices[i] += amount; - losVertices[i] += amount; + vertices[i].Pos += amount; + losVertices[i].Pos += amount; } CalculateDimensions(); @@ -204,26 +232,38 @@ namespace Barotrauma.Lights public void SetVertices(Vector2[] points) { - vertices = points; - losVertices = points; + Debug.Assert(points.Length == 4, "Only rectangular convex hulls are supported"); + for (int i = 0; i < 4; i++) + { + vertices[i] = new SegmentPoint(points[i], new Segment[2]); + losVertices[i] = new SegmentPoint(points[i], new Segment[2]); + + } + for (int i = 0; i < 4; i++) + { + segments[i] = new Segment(vertices[i], vertices[(i + 1) % 4]); + + vertices[i].Segments[1] = segments[i]; + vertices[(i + 1) % 4].Segments[0] = segments[i]; + + } + int margin = 0; if (Math.Abs(points[0].X - points[2].X) < Math.Abs(points[0].Y - points[1].Y)) { - losVertices = new Vector2[] { - new Vector2(points[0].X+margin, points[0].Y), - new Vector2(points[1].X+margin, points[1].Y), - new Vector2(points[2].X-margin, points[2].Y), - new Vector2(points[3].X-margin, points[3].Y)}; + losVertices[0].Pos = new Vector2(points[0].X + margin, points[0].Y); + losVertices[1].Pos = new Vector2(points[1].X + margin, points[1].Y); + losVertices[2].Pos = new Vector2(points[2].X - margin, points[2].Y); + losVertices[3].Pos = new Vector2(points[3].X - margin, points[3].Y); } else { - losVertices = new Vector2[] { - new Vector2(points[0].X, points[0].Y +margin), - new Vector2(points[1].X, points[1].Y - margin), - new Vector2(points[2].X, points[2].Y - margin), - new Vector2(points[3].X, points[3].Y + margin)}; + losVertices[0].Pos = new Vector2(points[0].X, points[0].Y + margin); + losVertices[1].Pos = new Vector2(points[1].X, points[1].Y - margin); + losVertices[2].Pos = new Vector2(points[2].X, points[2].Y - margin); + losVertices[3].Pos = new Vector2(points[3].X, points[3].Y + margin); } CalculateDimensions(); @@ -263,6 +303,44 @@ namespace Barotrauma.Lights } return transformedBounds.Intersects(rect); } + + /// + /// Returns the segments that are facing towards viewPosition + /// + public List GetVisibleSegments(Vector2 viewPosition) + { + List visibleFaces = new List(); + + for (int i = 0; i < 4; i++) + { + if (ignoreEdge[i]) continue; + + Vector2 middle = (segments[i].Start.Pos + segments[i].End.Pos) / 2; + + Vector2 L = viewPosition - middle; + + Vector2 N = new Vector2( + -(segments[i].End.Pos.Y - segments[i].Start.Pos.Y), + segments[i].End.Pos.X - segments[i].Start.Pos.X); + + if (Vector2.Dot(N, L) < 0) + { + visibleFaces.Add(segments[i]); + } + } + + return visibleFaces; + } + + + public void RefreshWorldPositions() + { + if (parentEntity == null || parentEntity.Submarine == null) return; + for (int i = 0; i < 4; i++) + { + vertices[i].WorldPos = vertices[i].Pos + parentEntity.Submarine.DrawPosition; + } + } private void CalculateShadowVertices(Vector2 lightSourcePos, bool los = true) { @@ -271,7 +349,7 @@ namespace Barotrauma.Lights var vertices = los ? losVertices : this.vertices; //compute facing of each edge, using N*L - for (int i = 0; i < primitiveCount; i++) + for (int i = 0; i < 4; i++) { if (ignoreEdge[i]) { @@ -279,12 +357,10 @@ namespace Barotrauma.Lights continue; } - Vector2 firstVertex = new Vector2(vertices[i].X, vertices[i].Y); - int secondIndex = (i + 1) % primitiveCount; - Vector2 secondVertex = new Vector2(vertices[secondIndex].X, vertices[secondIndex].Y); - Vector2 middle = (firstVertex + secondVertex) / 2; + Vector2 firstVertex = vertices[i].Pos; + Vector2 secondVertex = vertices[(i+1) % 4].Pos; - Vector2 L = lightSourcePos - middle; + Vector2 L = lightSourcePos - ((firstVertex + secondVertex) / 2.0f); Vector2 N = new Vector2( -(secondVertex.Y - firstVertex.Y), @@ -297,10 +373,10 @@ namespace Barotrauma.Lights //belong to the shadow int startingIndex = 0; int endingIndex = 0; - for (int i = 0; i < primitiveCount; i++) + for (int i = 0; i < 4; i++) { int currentEdge = i; - int nextEdge = (i + 1) % primitiveCount; + int nextEdge = (i + 1) % 4; if (backFacing[currentEdge] && !backFacing[nextEdge]) endingIndex = nextEdge; @@ -313,7 +389,7 @@ namespace Barotrauma.Lights if (endingIndex > startingIndex) shadowVertexCount = endingIndex - startingIndex + 1; else - shadowVertexCount = primitiveCount + 1 - startingIndex + endingIndex; + shadowVertexCount = 4 + 1 - startingIndex + endingIndex; //shadowVertices = new VertexPositionColor[shadowVertexCount * 2]; @@ -322,7 +398,7 @@ namespace Barotrauma.Lights int svCount = 0; while (svCount != shadowVertexCount * 2) { - Vector3 vertexPos = new Vector3(vertices[currentIndex], 0.0f); + Vector3 vertexPos = new Vector3(vertices[currentIndex].Pos, 0.0f); int i = los ? svCount : svCount + 1; int j = los ? svCount + 1 : svCount; @@ -336,14 +412,13 @@ namespace Barotrauma.Lights shadowVertices[j] = new VertexPositionColor(); shadowVertices[j].Color = shadowVertices[i].Color; - Vector3 L2P = vertexPos - new Vector3(lightSourcePos, 0); L2P.Normalize(); shadowVertices[j].Position = new Vector3(lightSourcePos, 0) + L2P * 9000; svCount += 2; - currentIndex = (currentIndex + 1) % primitiveCount; + currentIndex = (currentIndex + 1) % 4; } if (los) @@ -356,7 +431,7 @@ namespace Barotrauma.Lights { for (int n = 0; n < 4; n += 3) { - Vector3 penumbraStart = new Vector3((n == 0) ? vertices[startingIndex] : vertices[endingIndex], 0.0f); + Vector3 penumbraStart = new Vector3((n == 0) ? vertices[startingIndex].Pos : vertices[endingIndex].Pos, 0.0f); penumbraVertices[n] = new VertexPositionTexture(); penumbraVertices[n].Position = penumbraStart; diff --git a/Subsurface/Source/Map/Lights/LightSource.cs b/Subsurface/Source/Map/Lights/LightSource.cs index 0b64f0206..f37ed9fa9 100644 --- a/Subsurface/Source/Map/Lights/LightSource.cs +++ b/Subsurface/Source/Map/Lights/LightSource.cs @@ -162,7 +162,7 @@ namespace Barotrauma.Lights { ch.DrawShadows(graphics, cam, this, shadowTransform, false); } - } + } private List GetHullsInRange(Submarine sub) { @@ -239,17 +239,33 @@ namespace Barotrauma.Lights return chList.List; }*/ - private void CalculateFanVertices() + private List CalculateFanVertices() { - if (!CastShadows) return; - if (range < 1.0f || color.A < 0.01f) return; + if (!CastShadows) return null; + if (range < 1.0f || color.A < 0.01f) return null; var hulls = ConvexHull.GetHullsInRange(position, range, ParentSub); - //TODO: calculate fan based on hulls + List points = new List(); + foreach (ConvexHull hull in hulls) + { + hull.RefreshWorldPositions(); + points.AddRange(hull.GetVisibleSegments(position).Select(s => s.End)); + } + + Vector2 drawPos = position; + if (ParentSub != null) drawPos += ParentSub.DrawPosition; + + //sort points counter-clockwise + var compareCCW = new CompareSegmentPointCCW(drawPos); + points.Sort(compareCCW); + + //TODO: calculate triangles from points //http://www.redblobgames.com/articles/visibility/ //http://roy-t.nl/index.php/2014/02/27/2d-lighting-and-shadows-preview/ + + return points.Select(p => p.WorldPos).ToList(); } public void Draw(SpriteBatch spriteBatch) @@ -281,7 +297,14 @@ namespace Barotrauma.Lights if (LightSprite != null) { LightSprite.Draw(spriteBatch, drawPos, Color, LightSprite.Origin, -Rotation, 1, SpriteEffect); - } + } + + var verts = CalculateFanVertices(); + + foreach (var vert in verts) + { + GUI.DrawLine(spriteBatch, drawPos, new Vector2(vert.X, -vert.Y), Color.White); + } } public void FlipX() diff --git a/Subsurface/Source/Utils/MathUtils.cs b/Subsurface/Source/Utils/MathUtils.cs index ccdf61cc5..8215b79b9 100644 --- a/Subsurface/Source/Utils/MathUtils.cs +++ b/Subsurface/Source/Utils/MathUtils.cs @@ -276,15 +276,16 @@ namespace Barotrauma public static bool CircleIntersectsRectangle(Vector2 circlePos, float radius, Rectangle rect) { float xDist = Math.Abs(circlePos.X - rect.Center.X); + float yDist = Math.Abs(circlePos.Y - rect.Center.Y); + int halfWidth = rect.Width / 2; + int halfHeight = rect.Height / 2; if (xDist > (halfWidth + radius)) { return false; } - if (xDist <= (halfWidth)) { return true; } + if (yDist > (halfHeight + radius)) { return false; } - float yDist = Math.Abs(circlePos.Y - rect.Center.Y); - int halfHeight = rect.Height / 2; - if (yDist > (halfHeight + radius)) { return false; } + if (xDist <= (halfWidth)) { return true; } if (yDist <= (halfHeight)) { return true; } float distSqX = xDist - halfWidth; @@ -475,4 +476,18 @@ namespace Barotrauma return Math.Sign(d2 - d1); } } + + class CompareSegmentPointCCW : IComparer + { + private Vector2 center; + + public CompareSegmentPointCCW(Vector2 center) + { + this.center = center; + } + public int Compare(Lights.SegmentPoint a, Lights.SegmentPoint b) + { + return CompareCCW.Compare(a.WorldPos, b.WorldPos, center); + } + } } From f3f875e641e7ea0e470456b81a1c60c7ad9adb7a Mon Sep 17 00:00:00 2001 From: Regalis Date: Sun, 26 Feb 2017 18:44:18 +0200 Subject: [PATCH 04/10] Calculating light volumes works now. Very poorly optimized at the moment, todo: cache volumes and only recalculate when needed --- Subsurface/Source/Map/Lights/ConvexHull.cs | 47 +++-- Subsurface/Source/Map/Lights/LightManager.cs | 27 ++- Subsurface/Source/Map/Lights/LightSource.cs | 174 ++++++++++++++++--- Subsurface/Source/Utils/MathUtils.cs | 48 ++++- 4 files changed, 255 insertions(+), 41 deletions(-) diff --git a/Subsurface/Source/Map/Lights/ConvexHull.cs b/Subsurface/Source/Map/Lights/ConvexHull.cs index 5a56766e4..7ac0d6c67 100644 --- a/Subsurface/Source/Map/Lights/ConvexHull.cs +++ b/Subsurface/Source/Map/Lights/ConvexHull.cs @@ -74,20 +74,30 @@ namespace Barotrauma.Lights { Start = start; End = end; + + start.Segment = this; + end.Segment = this; } } - class SegmentPoint + struct SegmentPoint { - public Vector2 Pos; - public Segment[] Segments; - + public Vector2 Pos; public Vector2 WorldPos; - public SegmentPoint(Vector2 pos, Segment[] segments) + public Segment Segment; + + public SegmentPoint(Vector2 pos) { Pos = pos; - Segments = segments; + WorldPos = pos; + + Segment = null; + } + + public override string ToString() + { + return Pos.ToString(); } } @@ -225,6 +235,9 @@ namespace Barotrauma.Lights { vertices[i].Pos += amount; losVertices[i].Pos += amount; + + segments[i].Start.Pos += amount; + segments[i].End.Pos += amount; } CalculateDimensions(); @@ -236,16 +249,16 @@ namespace Barotrauma.Lights for (int i = 0; i < 4; i++) { - vertices[i] = new SegmentPoint(points[i], new Segment[2]); - losVertices[i] = new SegmentPoint(points[i], new Segment[2]); + vertices[i] = new SegmentPoint(points[i]); + losVertices[i] = new SegmentPoint(points[i]); } for (int i = 0; i < 4; i++) { segments[i] = new Segment(vertices[i], vertices[(i + 1) % 4]); - vertices[i].Segments[1] = segments[i]; - vertices[(i + 1) % 4].Segments[0] = segments[i]; + //vertices[i].Segments[1] = segments[i]; + //vertices[(i + 1) % 4].Segments[0] = segments[i]; } @@ -315,15 +328,18 @@ namespace Barotrauma.Lights { if (ignoreEdge[i]) continue; - Vector2 middle = (segments[i].Start.Pos + segments[i].End.Pos) / 2; + Vector2 pos1 = vertices[i].WorldPos; + Vector2 pos2 = vertices[(i + 1) % 4].WorldPos; + + Vector2 middle = (pos1 + pos2) / 2; Vector2 L = viewPosition - middle; Vector2 N = new Vector2( - -(segments[i].End.Pos.Y - segments[i].Start.Pos.Y), - segments[i].End.Pos.X - segments[i].Start.Pos.X); + -(pos2.Y - pos1.Y), + pos2.X - pos1.X); - if (Vector2.Dot(N, L) < 0) + if (Vector2.Dot(N, L) > 0) { visibleFaces.Add(segments[i]); } @@ -339,6 +355,9 @@ namespace Barotrauma.Lights for (int i = 0; i < 4; i++) { vertices[i].WorldPos = vertices[i].Pos + parentEntity.Submarine.DrawPosition; + segments[i].Start.WorldPos = segments[i].Start.Pos + parentEntity.Submarine.DrawPosition; + segments[i].End.WorldPos = segments[i].End.Pos + parentEntity.Submarine.DrawPosition; + } } diff --git a/Subsurface/Source/Map/Lights/LightManager.cs b/Subsurface/Source/Map/Lights/LightManager.cs index 4040be2ab..21364e4f9 100644 --- a/Subsurface/Source/Map/Lights/LightManager.cs +++ b/Subsurface/Source/Map/Lights/LightManager.cs @@ -25,6 +25,8 @@ namespace Barotrauma.Lights public Color AmbientLight; RenderTarget2D lightMap, losTexture; + + BasicEffect lightEffect; private static Texture2D alphaClearTexture; @@ -60,6 +62,15 @@ namespace Barotrauma.Lights losTexture = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight); + if (lightEffect == null) + { + lightEffect = new BasicEffect(GameMain.CurrGraphicsDevice); + lightEffect.VertexColorEnabled = false; + + lightEffect.TextureEnabled = true; + lightEffect.Texture = LightSource.LightTexture; + } + hullAmbientLights = new Dictionary(); smoothedHullAmbientLights = new Dictionary(); @@ -132,16 +143,23 @@ namespace Barotrauma.Lights //clear to some small ambient light graphics.Clear(AmbientLight); + graphics.BlendState = BlendState.Additive; spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, null, null, null, cam.Transform); + + Matrix transform = cam.ShaderTransform + * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f; + Vector3 offset = Vector3.Zero;// new Vector3(Submarine.MainSub.DrawPosition.X, Submarine.MainSub.DrawPosition.Y, 0.0f); + + lightEffect.World = Matrix.CreateTranslation(offset) * transform; + foreach (LightSource light in lights) { if (light.Color.A < 1 || light.Range < 1.0f || !light.CastShadows) continue; if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, light.Range, viewRect)) continue; - light.Draw(spriteBatch); - + light.Draw(spriteBatch, lightEffect); } GameMain.ParticleManager.Draw(spriteBatch, false, Particles.ParticleBlendState.Additive); @@ -178,9 +196,10 @@ namespace Barotrauma.Lights spriteBatch.End(); //clear alpha, to avoid messing stuff up later - ClearAlphaToOne(graphics, spriteBatch); - + //ClearAlphaToOne(graphics, spriteBatch); + graphics.SetRenderTarget(null); + graphics.BlendState = BlendState.AlphaBlend; } public void UpdateObstructVision(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, Vector2 lookAtPosition) diff --git a/Subsurface/Source/Map/Lights/LightSource.cs b/Subsurface/Source/Map/Lights/LightSource.cs index f37ed9fa9..cd303ff82 100644 --- a/Subsurface/Source/Map/Lights/LightSource.cs +++ b/Subsurface/Source/Map/Lights/LightSource.cs @@ -239,43 +239,156 @@ namespace Barotrauma.Lights return chList.List; }*/ - private List CalculateFanVertices() + private List FindRaycastHits() { if (!CastShadows) return null; if (range < 1.0f || color.A < 0.01f) return null; + Vector2 drawPos = position; + if (ParentSub != null) drawPos += ParentSub.DrawPosition; + var hulls = ConvexHull.GetHullsInRange(position, range, ParentSub); - + + //find convexhull segments that are close enough and facing towards the light source + List visibleSegments = new List(); List points = new List(); foreach (ConvexHull hull in hulls) { hull.RefreshWorldPositions(); - points.AddRange(hull.GetVisibleSegments(position).Select(s => s.End)); + + var visibleHullSegments = hull.GetVisibleSegments(drawPos); + visibleSegments.AddRange(visibleHullSegments); + + foreach (Segment s in visibleHullSegments) + { + points.Add(s.Start); + points.Add(s.End); + } } + //add a square-shaped boundary to make sure we've got something to construct the triangles from + //even if there aren't enough hull segments around the light source + + //(might be more effective to calculate if we actually need these extra points) + var boundaryCorners = new List { + new SegmentPoint(new Vector2(drawPos.X + range*2, drawPos.Y + range*2)), + new SegmentPoint(new Vector2(drawPos.X + range*2, drawPos.Y - range*2)), + new SegmentPoint(new Vector2(drawPos.X - range*2, drawPos.Y - range*2)), + new SegmentPoint(new Vector2(drawPos.X - range*2, drawPos.Y + range*2)) + }; + + points.AddRange(boundaryCorners); + + var compareCCW = new CompareSegmentPointCW(drawPos); + points.Sort(compareCCW); + + List output = new List(); + + //remove points that are very close to each other + for (int i = 0; i < points.Count - 1; i++) + { + if (Math.Abs(points[i].WorldPos.X - points[i + 1].WorldPos.X) < 3 && + Math.Abs(points[i].WorldPos.Y - points[i + 1].WorldPos.Y) < 3) + { + points.RemoveAt(i + 1); + } + } + + foreach (SegmentPoint p in points) + { + Vector2 dir = Vector2.Normalize(p.WorldPos - drawPos); + Vector2 dirNormal = new Vector2(-dir.Y, dir.X)*3; + + //do two slightly offset raycasts to hit the segment itself and whatever's behind it + Vector2 intersection1 = RayCast(drawPos, drawPos + dir * range * 2 - dirNormal, visibleSegments); + Vector2 intersection2 = RayCast(drawPos, drawPos + dir * range * 2 + dirNormal, visibleSegments); + + //hit almost the same position -> only add one vertex to output + if ((Math.Abs(intersection1.X - intersection2.X) < 5 && + Math.Abs(intersection1.Y - intersection2.Y) < 5)) + { + output.Add(intersection1); + } + else + { + output.Add(intersection1); + output.Add(intersection2); + } + } + + return output; + } + + private Vector2 RayCast(Vector2 rayStart, Vector2 rayEnd, List segments) + { + float closestDist = 0.0f; + Vector2? closestIntersection = null; + + foreach (Segment s in segments) + { + Vector2? intersection = MathUtils.GetAxisAlignedLineIntersection(rayStart, rayEnd, s.Start.WorldPos, s.End.WorldPos); + + if (intersection != null) + { + float dist = Vector2.Distance((Vector2)intersection, rayStart); + if (closestIntersection == null || dist < closestDist) + { + closestDist = dist; + closestIntersection = intersection; + } + } + } + + return closestIntersection == null ? rayEnd : (Vector2)closestIntersection; + } + + private void CalculateVertices(List encounters, + out VertexPositionTexture[] vertexArray, out short[] indexArray) + { + List vertices = new List(); + Vector2 drawPos = position; if (ParentSub != null) drawPos += ParentSub.DrawPosition; - //sort points counter-clockwise - var compareCCW = new CompareSegmentPointCCW(drawPos); - points.Sort(compareCCW); + // Add a vertex for the center of the mesh + vertices.Add(new VertexPositionTexture(new Vector3(drawPos.X, drawPos.Y, 0), + new Vector2(0.5f, 0.5f))); - //TODO: calculate triangles from points - - //http://www.redblobgames.com/articles/visibility/ - //http://roy-t.nl/index.php/2014/02/27/2d-lighting-and-shadows-preview/ + // Add all the other encounter points as vertices + // storing their world position as UV coordinates + foreach (Vector2 vertex in encounters) + { + Vector2 diff = vertex - drawPos; - return points.Select(p => p.WorldPos).ToList(); - } - - public void Draw(SpriteBatch spriteBatch) + vertices.Add(new VertexPositionTexture(new Vector3(vertex.X, vertex.Y, 0), + new Vector2(0.5f, 0.5f) + diff / range / 2)); + } + + // Compute the indices to form triangles + List indices = new List(); + for (int i = 0; i < encounters.Count - 1; i++) + { + indices.Add(0); + indices.Add((short)((i + 2) % vertices.Count)); + indices.Add((short)((i + 1) % vertices.Count)); + } + + indices.Add(0); + indices.Add((short)(1)); + indices.Add((short)(vertices.Count - 1)); + + vertexArray = vertices.ToArray(); + indexArray = indices.ToArray(); + } + + public void Draw(SpriteBatch spriteBatch, BasicEffect lightEffect) { Vector2 drawPos = position; if (ParentSub != null) drawPos += ParentSub.DrawPosition; drawPos.Y = -drawPos.Y; - if (range > 1.0f) + if (range > 1.0f && false) { if (overrideLightTexture == null) { @@ -296,15 +409,36 @@ namespace Barotrauma.Lights if (LightSprite != null) { - LightSprite.Draw(spriteBatch, drawPos, Color, LightSprite.Origin, -Rotation, 1, SpriteEffect); + //LightSprite.Draw(spriteBatch, drawPos, Color, LightSprite.Origin, -Rotation, 1, SpriteEffect); } - var verts = CalculateFanVertices(); + var verts = FindRaycastHits(); - foreach (var vert in verts) + /*for (int i = 0; i < verts.Count; i++) { - GUI.DrawLine(spriteBatch, drawPos, new Vector2(vert.X, -vert.Y), Color.White); - } + Color[] clrs = new Color[] { Color.Green, Color.Cyan, Color.Red, Color.White, Color.Magenta }; + + Color clr = clrs[i % clrs.Length]; + + // GUI.DrawString(spriteBatch, new Vector2(verts[i].X, -verts[i].Y), verts[i].ToString(), clr); + GUI.DrawString(spriteBatch, new Vector2(verts[i].X, -verts[i].Y), i.ToString(), clr); + GUI.DrawLine(spriteBatch, drawPos, new Vector2(verts[i].X, -verts[i].Y), clr, 0,3); + }*/ + + // Generate a triangle list from the encounter points + VertexPositionTexture[] vertices; + short[] indices; + CalculateVertices(verts, out vertices, out indices); + + if (vertices.Length == 0) return; + + lightEffect.DiffuseColor = (new Vector3(color.R, color.G, color.B) * (color.A / 255.0f)) / 255.0f;// color.ToVector3(); + lightEffect.CurrentTechnique.Passes[0].Apply(); + + GameMain.CurrGraphicsDevice.DrawUserIndexedPrimitives + ( + PrimitiveType.TriangleList, vertices, 0, vertices.Length, indices, 0, indices.Length / 3 + ); } public void FlipX() diff --git a/Subsurface/Source/Utils/MathUtils.cs b/Subsurface/Source/Utils/MathUtils.cs index 8215b79b9..279fc3088 100644 --- a/Subsurface/Source/Utils/MathUtils.cs +++ b/Subsurface/Source/Utils/MathUtils.cs @@ -208,6 +208,48 @@ namespace Barotrauma return a1 + t * b; } + /// + /// Get the point where line segment (a1, a2) intersects the axis-aligned line segment (axisAligned1, axisAligned2) + /// + public static Vector2? GetAxisAlignedLineIntersection(Vector2 a1, Vector2 a2, Vector2 axisAligned1, Vector2 axisAligned2) + { + if (Math.Abs(axisAligned1.X - axisAligned2.X) < 1.0f) + { + if (Math.Sign(a1.X - axisAligned1.X) == Math.Sign(a2.X - axisAligned1.X)) + return null; + + if (Math.Max(a1.Y, a2.Y) < Math.Min(axisAligned1.Y, axisAligned2.Y)) + return null; + + if (Math.Min(a1.Y, a2.Y) > Math.Max(axisAligned1.Y, axisAligned2.Y)) + return null; + } + else + { + if (Math.Sign(a1.Y - axisAligned1.Y) == Math.Sign(a2.Y - axisAligned1.Y)) + return null; + + if (Math.Max(a1.X, a2.X) < Math.Min(axisAligned1.X, axisAligned2.X)) + return null; + + if (Math.Min(a1.X, a2.X) > Math.Max(axisAligned1.X, axisAligned2.X)) + return null; + } + + Vector2 b = a2 - a1; + Vector2 d = axisAligned2 - axisAligned1; + float bDotDPerp = b.X * d.Y - b.Y * d.X; + + Vector2 c = axisAligned1 - a1; + float t = (c.X * d.Y - c.Y * d.X) / bDotDPerp; + if (t < 0 || t > 1) return null; + + float u = (c.X * b.Y - c.Y * b.X) / bDotDPerp; + if (u < 0 || u > 1) return null; + + return a1 + t * b; + } + public static Vector2? GetLineRectangleIntersection(Vector2 a1, Vector2 a2, Rectangle rect) { Vector2? intersection = GetLineIntersection(a1, a2, @@ -477,17 +519,17 @@ namespace Barotrauma } } - class CompareSegmentPointCCW : IComparer + class CompareSegmentPointCW : IComparer { private Vector2 center; - public CompareSegmentPointCCW(Vector2 center) + public CompareSegmentPointCW(Vector2 center) { this.center = center; } public int Compare(Lights.SegmentPoint a, Lights.SegmentPoint b) { - return CompareCCW.Compare(a.WorldPos, b.WorldPos, center); + return -CompareCCW.Compare(a.WorldPos, b.WorldPos, center); } } } From 68a0320935f5c899188b3c92bc3e1bc5d75b9db8 Mon Sep 17 00:00:00 2001 From: Regalis Date: Mon, 27 Feb 2017 00:41:40 +0200 Subject: [PATCH 05/10] LightSources cache the light vertices in vertex buffers and only recalculate if needed --- Subsurface/Source/GameMain.cs | 12 +- Subsurface/Source/Map/Lights/ConvexHull.cs | 55 +++- Subsurface/Source/Map/Lights/LightManager.cs | 9 +- Subsurface/Source/Map/Lights/LightSource.cs | 324 ++++++++++++------- 4 files changed, 263 insertions(+), 137 deletions(-) diff --git a/Subsurface/Source/GameMain.cs b/Subsurface/Source/GameMain.cs index fb6ac0329..e8c171971 100644 --- a/Subsurface/Source/GameMain.cs +++ b/Subsurface/Source/GameMain.cs @@ -103,6 +103,15 @@ namespace Barotrauma { get { return NetworkMember as GameClient; } } + + /// + /// Total seconds elapsed after startup + /// + public double TotalElapsedTime + { + get; + private set; + } public GameMain() { @@ -297,11 +306,12 @@ namespace Barotrauma protected override void Update(GameTime gameTime) { Timing.Accumulator += gameTime.ElapsedGameTime.TotalSeconds; - bool paused = true; while (Timing.Accumulator >= Timing.Step) { + TotalElapsedTime = gameTime.TotalGameTime.TotalSeconds; + fixedTime.IsRunningSlowly = gameTime.IsRunningSlowly; TimeSpan addTime = new TimeSpan(0, 0, 0, 0, 16); fixedTime.ElapsedGameTime = addTime; diff --git a/Subsurface/Source/Map/Lights/ConvexHull.cs b/Subsurface/Source/Map/Lights/ConvexHull.cs index 7ac0d6c67..2740c7693 100644 --- a/Subsurface/Source/Map/Lights/ConvexHull.cs +++ b/Subsurface/Source/Map/Lights/ConvexHull.cs @@ -110,7 +110,7 @@ namespace Barotrauma.Lights //private Dictionary cachedShadows; public VertexBuffer ShadowBuffer; - + Segment[] segments = new Segment[4]; SegmentPoint[] vertices = new SegmentPoint[4]; SegmentPoint[] losVertices = new SegmentPoint[4]; @@ -136,10 +136,28 @@ namespace Barotrauma.Lights } + private bool enabled; public bool Enabled + { + get + { + return enabled; + } + set + { + if (enabled == value) return; + enabled = value; + LastVertexChangeTime = (float)GameMain.Instance.TotalElapsedTime; + } + } + + /// + /// The elapsed gametime when the vertices of this hull last changed + /// + public float LastVertexChangeTime { get; - set; + private set; } public Rectangle BoundingBox @@ -197,6 +215,8 @@ namespace Barotrauma.Lights private void UpdateIgnoredEdges(ConvexHull ch) { + if (ch == this) return; + //ignore edges that are inside some other convex hull for (int i = 0; i < vertices.Length; i++) { if (vertices[i].Pos.X >= ch.boundingBox.X && vertices[i].Pos.X <= ch.boundingBox.Right && @@ -233,13 +253,15 @@ namespace Barotrauma.Lights { for (int i = 0; i < vertices.Length; i++) { - vertices[i].Pos += amount; - losVertices[i].Pos += amount; + vertices[i].Pos += amount; + losVertices[i].Pos += amount; - segments[i].Start.Pos += amount; - segments[i].End.Pos += amount; + segments[i].Start.Pos += amount; + segments[i].End.Pos += amount; } + LastVertexChangeTime = (float)GameMain.Instance.TotalElapsedTime; + CalculateDimensions(); } @@ -247,6 +269,8 @@ namespace Barotrauma.Lights { Debug.Assert(points.Length == 4, "Only rectangular convex hulls are supported"); + LastVertexChangeTime = (float)GameMain.Instance.TotalElapsedTime; + for (int i = 0; i < 4; i++) { vertices[i] = new SegmentPoint(points[i]); @@ -256,10 +280,6 @@ namespace Barotrauma.Lights for (int i = 0; i < 4; i++) { segments[i] = new Segment(vertices[i], vertices[(i + 1) % 4]); - - //vertices[i].Segments[1] = segments[i]; - //vertices[(i + 1) % 4].Segments[0] = segments[i]; - } int margin = 0; @@ -280,6 +300,21 @@ namespace Barotrauma.Lights } CalculateDimensions(); + + if (parentEntity == null || ignoreEdge == null) return; + for (int i = 0; i<4; i++) + { + ignoreEdge[i] = false; + } + + var chList = HullLists.Find(x => x.Submarine == parentEntity.Submarine); + if (chList != null) + { + foreach (ConvexHull ch in chList.List) + { + UpdateIgnoredEdges(ch); + } + } } /*private void RemoveCachedShadow(Lights.LightSource light) diff --git a/Subsurface/Source/Map/Lights/LightManager.cs b/Subsurface/Source/Map/Lights/LightManager.cs index 21364e4f9..b1ae2f9f9 100644 --- a/Subsurface/Source/Map/Lights/LightManager.cs +++ b/Subsurface/Source/Map/Lights/LightManager.cs @@ -94,7 +94,8 @@ namespace Barotrauma.Lights { foreach (LightSource light in lights) { - light.NeedsHullUpdate = true; + light.NeedsHullCheck = true; + light.NeedsRecalculation = true; } } @@ -152,16 +153,16 @@ namespace Barotrauma.Lights Vector3 offset = Vector3.Zero;// new Vector3(Submarine.MainSub.DrawPosition.X, Submarine.MainSub.DrawPosition.Y, 0.0f); - lightEffect.World = Matrix.CreateTranslation(offset) * transform; - foreach (LightSource light in lights) { if (light.Color.A < 1 || light.Range < 1.0f || !light.CastShadows) continue; if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, light.Range, viewRect)) continue; - light.Draw(spriteBatch, lightEffect); + light.Draw(spriteBatch, lightEffect, transform); } + lightEffect.World = Matrix.CreateTranslation(offset) * transform; + GameMain.ParticleManager.Draw(spriteBatch, false, Particles.ParticleBlendState.Additive); if (Character.Controlled != null) diff --git a/Subsurface/Source/Map/Lights/LightSource.cs b/Subsurface/Source/Map/Lights/LightSource.cs index cd303ff82..4368b05f3 100644 --- a/Subsurface/Source/Map/Lights/LightSource.cs +++ b/Subsurface/Source/Map/Lights/LightSource.cs @@ -15,27 +15,35 @@ namespace Barotrauma.Lights private List hullsInRange; private Color color; - private float range; - - public SpriteEffects SpriteEffect = SpriteEffects.None; - + + private Sprite overrideLightTexture; private Texture2D texture; + public SpriteEffects SpriteEffect = SpriteEffects.None; public Sprite LightSprite; - private Sprite overrideLightTexture; - public Submarine ParentSub; public bool CastShadows; - //what was the range of the light when HullsInRange were last updated - private float prevHullUpdateRange; + //what was the range of the light when lightvolumes were last calculated + private float prevCalculatedRange; + private Vector2 prevCalculatedPosition; - private Vector2 prevHullUpdatePosition; + //do we need to recheck which convex hulls are within range + //(e.g. position or range of the lightsource has changed) + public bool NeedsHullCheck = true; + //do we need to recalculate the vertices of the light volume + public bool NeedsRecalculation = true; - public bool NeedsHullUpdate; + //when were the vertices of the light volume last calculated + private float lastRecalculationTime; + + private DynamicVertexBuffer lightVolumeBuffer; + private DynamicIndexBuffer lightVolumeIndexBuffer; + private int vertexCount; + private int indexCount; private Vector2 position; public Vector2 Position @@ -46,10 +54,11 @@ namespace Barotrauma.Lights if (position == value) return; position = value; - if (Vector2.Distance(prevHullUpdatePosition, position) < 5.0f) return; + if (Vector2.Distance(prevCalculatedPosition, position) < 5.0f) return; - NeedsHullUpdate = true; - prevHullUpdatePosition = position; + NeedsHullCheck = true; + NeedsRecalculation = true; + prevCalculatedPosition = position; } } @@ -90,10 +99,11 @@ namespace Barotrauma.Lights { range = MathHelper.Clamp(value, 0.0f, 2048.0f); - if (Math.Abs(prevHullUpdateRange - range) < 10.0f) return; + if (Math.Abs(prevCalculatedRange - range) < 10.0f) return; - NeedsHullUpdate = true; - prevHullUpdateRange = range; + NeedsHullCheck = true; + NeedsRecalculation = true; + prevCalculatedRange = range; } } @@ -130,9 +140,9 @@ namespace Barotrauma.Lights this.color = color; CastShadows = true; - + texture = LightTexture; - + GameMain.LightManager.AddLight(this); } @@ -162,82 +172,112 @@ namespace Barotrauma.Lights { ch.DrawShadows(graphics, cam, this, shadowTransform, false); } - } - - private List GetHullsInRange(Submarine sub) - { - //find the current list of hulls in range - var chList = hullsInRange.Find(x => x.Submarine == sub); - - //not found -> create one - if (chList == null) - { - chList = new ConvexHullList(sub); - hullsInRange.Add(chList); - } - - Vector2 lightPos = position; - if (ParentSub == null) - { - //light and the convexhull are both outside - if (sub == null) - { - if (NeedsHullUpdate) - { - var fullChList = ConvexHull.HullLists.Find(x => x.Submarine == sub); - if (fullChList != null) - chList.List = fullChList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)); - } - } - //light is outside, convexhull inside a sub - else - { - lightPos -= sub.Position; - - Rectangle subBorders = sub.Borders; - subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height); - - //only draw if the light overlaps with the sub - if (!MathUtils.CircleIntersectsRectangle(lightPos, range, subBorders)) return null; - - var fullChList = ConvexHull.HullLists.Find(x => x.Submarine == sub); - chList.List = fullChList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)); - } - } - else - { - //light is inside, convexhull outside - if (sub == null) return null; - - //light and convexhull are both inside the same sub - if (sub == ParentSub) - { - if (NeedsHullUpdate) - { - var fullChList = ConvexHull.HullLists.Find(x => x.Submarine == sub); - chList.List = fullChList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)); - } - } - //light and convexhull are inside different subs - else - { - if (sub.DockedTo.Contains(ParentSub) && !NeedsHullUpdate) return chList.List; - - lightPos -= (sub.Position - ParentSub.Position); - - Rectangle subBorders = sub.Borders; - subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height); - - //only draw if the light overlaps with the sub - if (!MathUtils.CircleIntersectsRectangle(lightPos, range, subBorders)) return null; - - var fullChList = ConvexHull.HullLists.Find(x => x.Submarine == sub); - chList.List = fullChList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)); - } - } - - return chList.List; }*/ + + /// + /// Update the contents of ConvexHullList and check if we need to recalculate vertices + /// + private void RefreshConvexHullList(ConvexHullList chList, Vector2 lightPos, Submarine sub) + { + var fullChList = ConvexHull.HullLists.Find(x => x.Submarine == sub); + chList.List = fullChList.List.FindAll(ch => ch.Enabled && MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)); + + NeedsHullCheck = true; + } + + /// + /// Recheck which convex hulls are in range (if needed), + /// and check if we need to recalculate vertices due to changes in the convex hulls + /// + private void CheckHullsInRange() + { + List subs = new List(Submarine.Loaded); + subs.Add(null); + + foreach (Submarine sub in subs) + { + //find the list of convexhulls that belong to the sub + var chList = hullsInRange.Find(x => x.Submarine == sub); + + //not found -> create one + if (chList == null) + { + chList = new ConvexHullList(sub); + hullsInRange.Add(chList); + NeedsRecalculation = true; + } + + if (chList.List.Any(ch => ch.LastVertexChangeTime > lastRecalculationTime)) + { + NeedsRecalculation = true; + } + + Vector2 lightPos = position; + if (ParentSub == null) + { + //light and the convexhulls are both outside + if (sub == null) + { + if (NeedsHullCheck) + { + RefreshConvexHullList(chList, lightPos, null); + } + } + //light is outside, convexhulls inside a sub + else + { + lightPos -= sub.Position; + + Rectangle subBorders = sub.Borders; + subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height); + + //only draw if the light overlaps with the sub + if (!MathUtils.CircleIntersectsRectangle(lightPos, range, subBorders)) + { + if (chList.List.Count > 0) NeedsRecalculation = true; + chList.List.Clear(); + continue; + } + + RefreshConvexHullList(chList, lightPos, sub); + } + } + else + { + //light is inside, convexhull outside + if (sub == null) continue; + + //light and convexhull are both inside the same sub + if (sub == ParentSub) + { + if (NeedsHullCheck) + { + RefreshConvexHullList(chList, lightPos, sub); + } + } + //light and convexhull are inside different subs + else + { + if (sub.DockedTo.Contains(ParentSub) && !NeedsHullCheck) continue; + + lightPos -= (sub.Position - ParentSub.Position); + + Rectangle subBorders = sub.Borders; + subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height); + + //only draw if the light overlaps with the sub + if (!MathUtils.CircleIntersectsRectangle(lightPos, range, subBorders)) + { + if (chList.List.Count > 0) NeedsRecalculation = true; + chList.List.Clear(); + continue; + } + + RefreshConvexHullList(chList, lightPos, sub); + } + } + } + } private List FindRaycastHits() { @@ -247,7 +287,11 @@ namespace Barotrauma.Lights Vector2 drawPos = position; if (ParentSub != null) drawPos += ParentSub.DrawPosition; - var hulls = ConvexHull.GetHullsInRange(position, range, ParentSub); + var hulls = new List();// ConvexHull.GetHullsInRange(position, range, ParentSub); + foreach (ConvexHullList chList in hullsInRange) + { + hulls.AddRange(chList.List); + } //find convexhull segments that are close enough and facing towards the light source List visibleSegments = new List(); @@ -256,6 +300,11 @@ namespace Barotrauma.Lights { hull.RefreshWorldPositions(); + if (hull.ParentEntity is Item) + { + int gfhdfgh = 1; + } + var visibleHullSegments = hull.GetVisibleSegments(drawPos); visibleSegments.AddRange(visibleHullSegments); @@ -342,8 +391,7 @@ namespace Barotrauma.Lights return closestIntersection == null ? rayEnd : (Vector2)closestIntersection; } - private void CalculateVertices(List encounters, - out VertexPositionTexture[] vertexArray, out short[] indexArray) + private void CalculateLightVertices(List rayCastHits) { List vertices = new List(); @@ -351,22 +399,22 @@ namespace Barotrauma.Lights if (ParentSub != null) drawPos += ParentSub.DrawPosition; // Add a vertex for the center of the mesh - vertices.Add(new VertexPositionTexture(new Vector3(drawPos.X, drawPos.Y, 0), + vertices.Add(new VertexPositionTexture(new Vector3(position.X, position.Y, 0), new Vector2(0.5f, 0.5f))); // Add all the other encounter points as vertices // storing their world position as UV coordinates - foreach (Vector2 vertex in encounters) + foreach (Vector2 vertex in rayCastHits) { Vector2 diff = vertex - drawPos; - vertices.Add(new VertexPositionTexture(new Vector3(vertex.X, vertex.Y, 0), + vertices.Add(new VertexPositionTexture(new Vector3(position.X + diff.X, position.Y + diff.Y, 0), new Vector2(0.5f, 0.5f) + diff / range / 2)); } // Compute the indices to form triangles List indices = new List(); - for (int i = 0; i < encounters.Count - 1; i++) + for (int i = 0; i < rayCastHits.Count - 1; i++) { indices.Add(0); indices.Add((short)((i + 2) % vertices.Count)); @@ -377,12 +425,38 @@ namespace Barotrauma.Lights indices.Add((short)(1)); indices.Add((short)(vertices.Count - 1)); - vertexArray = vertices.ToArray(); - indexArray = indices.ToArray(); + vertexCount = vertices.Count; + indexCount = indices.Count; + + //TODO: a better way to determine the size of the vertex buffer and handle changes in size? + //now we just create a buffer for 64 verts and make it larger if needed + if (lightVolumeBuffer == null) + { + lightVolumeBuffer = new DynamicVertexBuffer(GameMain.CurrGraphicsDevice, VertexPositionTexture.VertexDeclaration, Math.Max(64, (int)(vertexCount*1.5)), BufferUsage.None); + lightVolumeIndexBuffer = new DynamicIndexBuffer(GameMain.CurrGraphicsDevice, typeof(short), Math.Max(64*3, (int)(indexCount * 1.5)), BufferUsage.None); + } + else if (vertexCount > lightVolumeBuffer.VertexCount) + { + lightVolumeBuffer.Dispose(); + lightVolumeIndexBuffer.Dispose(); + + lightVolumeBuffer = new DynamicVertexBuffer(GameMain.CurrGraphicsDevice, VertexPositionTexture.VertexDeclaration, (int)(vertexCount*1.5), BufferUsage.None); + lightVolumeIndexBuffer = new DynamicIndexBuffer(GameMain.CurrGraphicsDevice, typeof(short), (int)(indexCount * 1.5), BufferUsage.None); + } + + lightVolumeBuffer.SetData(vertices.ToArray()); + lightVolumeIndexBuffer.SetData(indices.ToArray()); } - public void Draw(SpriteBatch spriteBatch, BasicEffect lightEffect) + public void Draw(SpriteBatch spriteBatch, BasicEffect lightEffect, Matrix transform) { + CheckHullsInRange(); + + Vector3 offset = ParentSub == null ? Vector3.Zero : + new Vector3(ParentSub.DrawPosition.X, ParentSub.DrawPosition.Y, 0.0f); + + lightEffect.World = Matrix.CreateTranslation(offset) * transform; + Vector2 drawPos = position; if (ParentSub != null) drawPos += ParentSub.DrawPosition; @@ -412,32 +486,26 @@ namespace Barotrauma.Lights //LightSprite.Draw(spriteBatch, drawPos, Color, LightSprite.Origin, -Rotation, 1, SpriteEffect); } - var verts = FindRaycastHits(); - - /*for (int i = 0; i < verts.Count; i++) + if (NeedsRecalculation) { - Color[] clrs = new Color[] { Color.Green, Color.Cyan, Color.Red, Color.White, Color.Magenta }; + var verts = FindRaycastHits(); + CalculateLightVertices(verts); - Color clr = clrs[i % clrs.Length]; - - // GUI.DrawString(spriteBatch, new Vector2(verts[i].X, -verts[i].Y), verts[i].ToString(), clr); - GUI.DrawString(spriteBatch, new Vector2(verts[i].X, -verts[i].Y), i.ToString(), clr); - GUI.DrawLine(spriteBatch, drawPos, new Vector2(verts[i].X, -verts[i].Y), clr, 0,3); - }*/ - - // Generate a triangle list from the encounter points - VertexPositionTexture[] vertices; - short[] indices; - CalculateVertices(verts, out vertices, out indices); + lastRecalculationTime = (float)GameMain.Instance.TotalElapsedTime; + NeedsRecalculation = false; + } - if (vertices.Length == 0) return; + if (vertexCount == 0) return; lightEffect.DiffuseColor = (new Vector3(color.R, color.G, color.B) * (color.A / 255.0f)) / 255.0f;// color.ToVector3(); lightEffect.CurrentTechnique.Passes[0].Apply(); - - GameMain.CurrGraphicsDevice.DrawUserIndexedPrimitives + + GameMain.CurrGraphicsDevice.SetVertexBuffer(lightVolumeBuffer); + GameMain.CurrGraphicsDevice.Indices = lightVolumeIndexBuffer; + + GameMain.CurrGraphicsDevice.DrawIndexedPrimitives ( - PrimitiveType.TriangleList, vertices, 0, vertices.Length, indices, 0, indices.Length / 3 + PrimitiveType.TriangleList, 0, 0, indexCount / 3 ); } @@ -463,6 +531,18 @@ namespace Barotrauma.Lights { if (LightSprite != null) LightSprite.Remove(); + if (lightVolumeBuffer != null) + { + lightVolumeBuffer.Dispose(); + lightVolumeBuffer = null; + } + + if (lightVolumeIndexBuffer != null) + { + lightVolumeIndexBuffer.Dispose(); + lightVolumeIndexBuffer = null; + } + GameMain.LightManager.RemoveLight(this); } } From 22d40077fa858268f858240a1a61d2689d085188 Mon Sep 17 00:00:00 2001 From: Regalis Date: Mon, 27 Feb 2017 18:53:34 +0200 Subject: [PATCH 06/10] Fixed exception in LightSource if ConvexHullList for hulls outside the sub hasn't been generated (i.e. if switching to game mode using console commands), removed some debug code --- Subsurface/Source/Map/Lights/LightSource.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Subsurface/Source/Map/Lights/LightSource.cs b/Subsurface/Source/Map/Lights/LightSource.cs index 4368b05f3..f5b80f5f1 100644 --- a/Subsurface/Source/Map/Lights/LightSource.cs +++ b/Subsurface/Source/Map/Lights/LightSource.cs @@ -180,6 +180,8 @@ namespace Barotrauma.Lights private void RefreshConvexHullList(ConvexHullList chList, Vector2 lightPos, Submarine sub) { var fullChList = ConvexHull.HullLists.Find(x => x.Submarine == sub); + if (fullChList == null) return; + chList.List = fullChList.List.FindAll(ch => ch.Enabled && MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)); NeedsHullCheck = true; @@ -299,12 +301,7 @@ namespace Barotrauma.Lights foreach (ConvexHull hull in hulls) { hull.RefreshWorldPositions(); - - if (hull.ParentEntity is Item) - { - int gfhdfgh = 1; - } - + var visibleHullSegments = hull.GetVisibleSegments(drawPos); visibleSegments.AddRange(visibleHullSegments); From 4568f34f39feed9bf0470442257e9f9196ee565a Mon Sep 17 00:00:00 2001 From: juanjp600 Date: Tue, 28 Feb 2017 19:19:02 -0300 Subject: [PATCH 07/10] Rotating lights and overridden textures The flashlight has the correct texture now, but something still seems off about the UV coordinates. Scaling is probably incorrect. --- Subsurface/Source/Map/Lights/LightSource.cs | 53 ++++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/Subsurface/Source/Map/Lights/LightSource.cs b/Subsurface/Source/Map/Lights/LightSource.cs index f5b80f5f1..c96e4f9fe 100644 --- a/Subsurface/Source/Map/Lights/LightSource.cs +++ b/Subsurface/Source/Map/Lights/LightSource.cs @@ -62,10 +62,18 @@ namespace Barotrauma.Lights } } + private float rotation; public float Rotation { - get; - set; + get { return rotation; } + set + { + if (rotation == value) return; + rotation = value; + + NeedsHullCheck = true; + NeedsRecalculation = true; + } } public Vector2 WorldPosition @@ -395,18 +403,41 @@ namespace Barotrauma.Lights Vector2 drawPos = position; if (ParentSub != null) drawPos += ParentSub.DrawPosition; + float cosAngle = (float)Math.Cos(Rotation); + float sinAngle = -(float)Math.Sin(Rotation); + + Vector2 uvOffset = Vector2.Zero; + Vector2 overrideTextureDims = Vector2.One; + if (overrideLightTexture != null) + { + overrideTextureDims = new Vector2(overrideLightTexture.SourceRect.Width, overrideLightTexture.SourceRect.Height); + uvOffset = (overrideLightTexture.Origin / overrideLightTexture.size) - new Vector2(0.5f, 0.5f); + } + // Add a vertex for the center of the mesh vertices.Add(new VertexPositionTexture(new Vector3(position.X, position.Y, 0), - new Vector2(0.5f, 0.5f))); + new Vector2(0.5f, 0.5f) + uvOffset)); // Add all the other encounter points as vertices // storing their world position as UV coordinates foreach (Vector2 vertex in rayCastHits) { - Vector2 diff = vertex - drawPos; + Vector2 rawDiff = vertex - drawPos; + Vector2 diff = rawDiff; + diff /= range*2.0f; + if (overrideLightTexture != null) + { + diff /= (overrideLightTexture.size / overrideTextureDims); + Vector2 originDiff = diff; - vertices.Add(new VertexPositionTexture(new Vector3(position.X + diff.X, position.Y + diff.Y, 0), - new Vector2(0.5f, 0.5f) + diff / range / 2)); + diff.X = originDiff.X * cosAngle - originDiff.Y * sinAngle; + diff.Y = originDiff.X * sinAngle + originDiff.Y * cosAngle; + + diff += uvOffset; + } + + vertices.Add(new VertexPositionTexture(new Vector3(position.X + rawDiff.X, position.Y + rawDiff.Y, 0), + new Vector2(0.5f, 0.5f) + diff)); } // Compute the indices to form triangles @@ -495,11 +526,19 @@ namespace Barotrauma.Lights if (vertexCount == 0) return; lightEffect.DiffuseColor = (new Vector3(color.R, color.G, color.B) * (color.A / 255.0f)) / 255.0f;// color.ToVector3(); + if (overrideLightTexture != null) + { + lightEffect.Texture = overrideLightTexture.Texture; + } + else + { + lightEffect.Texture = LightTexture; + } lightEffect.CurrentTechnique.Passes[0].Apply(); GameMain.CurrGraphicsDevice.SetVertexBuffer(lightVolumeBuffer); GameMain.CurrGraphicsDevice.Indices = lightVolumeIndexBuffer; - + GameMain.CurrGraphicsDevice.DrawIndexedPrimitives ( PrimitiveType.TriangleList, 0, 0, indexCount / 3 From 84a8232c1ac02f430885b64fed23041aeb21d8fe Mon Sep 17 00:00:00 2001 From: juanjp600 Date: Tue, 28 Feb 2017 19:38:25 -0300 Subject: [PATCH 08/10] Fixed override sprite scaling Now it looks right. --- Subsurface/Source/Map/Lights/LightSource.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Subsurface/Source/Map/Lights/LightSource.cs b/Subsurface/Source/Map/Lights/LightSource.cs index c96e4f9fe..4474d6a36 100644 --- a/Subsurface/Source/Map/Lights/LightSource.cs +++ b/Subsurface/Source/Map/Lights/LightSource.cs @@ -411,7 +411,7 @@ namespace Barotrauma.Lights if (overrideLightTexture != null) { overrideTextureDims = new Vector2(overrideLightTexture.SourceRect.Width, overrideLightTexture.SourceRect.Height); - uvOffset = (overrideLightTexture.Origin / overrideLightTexture.size) - new Vector2(0.5f, 0.5f); + uvOffset = (overrideLightTexture.Origin / overrideTextureDims) - new Vector2(0.5f, 0.5f); } // Add a vertex for the center of the mesh @@ -427,11 +427,11 @@ namespace Barotrauma.Lights diff /= range*2.0f; if (overrideLightTexture != null) { - diff /= (overrideLightTexture.size / overrideTextureDims); Vector2 originDiff = diff; diff.X = originDiff.X * cosAngle - originDiff.Y * sinAngle; diff.Y = originDiff.X * sinAngle + originDiff.Y * cosAngle; + diff *= (overrideTextureDims / overrideLightTexture.size) * 2.0f; diff += uvOffset; } From 3868b703878046ceaa8c64658839518b447145f3 Mon Sep 17 00:00:00 2001 From: juanjp600 Date: Wed, 1 Mar 2017 13:41:37 -0300 Subject: [PATCH 09/10] Fixed windowed door shadows --- Subsurface/Source/Items/Components/Door.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Subsurface/Source/Items/Components/Door.cs b/Subsurface/Source/Items/Components/Door.cs index ec03b232e..a592d749f 100644 --- a/Subsurface/Source/Items/Components/Door.cs +++ b/Subsurface/Source/Items/Components/Door.cs @@ -368,7 +368,7 @@ namespace Barotrauma.Items.Components LinkedGap.ConnectedDoor = this; LinkedGap.Open = openState; - Vector2[] corners = GetConvexHullCorners(doorRect); + Vector2[] corners = GetConvexHullCorners(Rectangle.Empty); convexHull = new ConvexHull(corners, Color.Black, item); if (window != Rectangle.Empty) convexHull2 = new ConvexHull(corners, Color.Black, item); From 1f607c201828ca43ea9a08368891259068ca02cd Mon Sep 17 00:00:00 2001 From: juanjp600 Date: Wed, 1 Mar 2017 13:43:00 -0300 Subject: [PATCH 10/10] Made windowed door's shadow match the sprite more closely --- Subsurface/Content/Items/Door/doors.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Subsurface/Content/Items/Door/doors.xml b/Subsurface/Content/Items/Door/doors.xml index f4326c5ed..f6c6f3c78 100644 --- a/Subsurface/Content/Items/Door/doors.xml +++ b/Subsurface/Content/Items/Door/doors.xml @@ -34,7 +34,7 @@ - +