v1.0.20.1 (summer patch)
This commit is contained in:
@@ -9,15 +9,17 @@ namespace Barotrauma
|
||||
{
|
||||
private LightSource lightSource;
|
||||
|
||||
partial void UpdateProjSpecific(float growModifier)
|
||||
private float particleTimer;
|
||||
|
||||
partial void UpdateProjSpecific(float growModifier, float deltaTime)
|
||||
{
|
||||
if (this is DummyFireSource)
|
||||
{
|
||||
EmitParticles(size, WorldPosition, hull, growModifier, null);
|
||||
EmitParticles(size, WorldPosition, deltaTime, hull, growModifier, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitParticles(size, WorldPosition, hull, growModifier, OnChangeHull);
|
||||
EmitParticles(size, WorldPosition, deltaTime, hull, growModifier, OnChangeHull);
|
||||
}
|
||||
|
||||
lightSource.Color = new Color(1.0f, 0.45f, 0.3f) * Rand.Range(0.8f, 1.0f);
|
||||
@@ -25,23 +27,29 @@ namespace Barotrauma
|
||||
if (Vector2.DistanceSquared(lightSource.Position, position) > 5.0f) { lightSource.Position = position + Vector2.UnitY * 30.0f; }
|
||||
}
|
||||
|
||||
public static void EmitParticles(Vector2 size, Vector2 worldPosition, Hull hull, float growModifier, Particle.OnChangeHullHandler onChangeHull = null)
|
||||
public void EmitParticles(Vector2 size, Vector2 worldPosition, float deltaTime, Hull hull, float growModifier, Particle.OnChangeHullHandler onChangeHull = null)
|
||||
{
|
||||
float particleCount = Rand.Range(0.0f, size.X / 50.0f);
|
||||
var particlePrefab = ParticleManager.FindPrefab("flame");
|
||||
if (particlePrefab == null) { return; }
|
||||
|
||||
for (int i = 0; i < particleCount; i++)
|
||||
float particlesPerSecond = MathHelper.Clamp(size.X / 2.0f, 10.0f, 200.0f);
|
||||
|
||||
float particleInterval = 1.0f / particlesPerSecond;
|
||||
particleTimer += deltaTime;
|
||||
while (particleTimer > particleInterval)
|
||||
{
|
||||
particleTimer -= particleInterval;
|
||||
Vector2 particlePos = new Vector2(
|
||||
worldPosition.X + Rand.Range(0.0f, size.X),
|
||||
Rand.Range(worldPosition.Y - size.Y, worldPosition.Y + 20.0f));
|
||||
worldPosition.Y - size.Y + particlePrefab.CollisionRadius);
|
||||
|
||||
Vector2 particleVel = new Vector2(
|
||||
particlePos.X - (worldPosition.X + size.X / 2.0f),
|
||||
Math.Max((float)Math.Sqrt(size.X) * Rand.Range(0.0f, 15.0f) * growModifier, 0.0f));
|
||||
|
||||
particleVel.X = MathHelper.Clamp(particleVel.X, -200.0f, 200.0f);
|
||||
|
||||
var particle = GameMain.ParticleManager.CreateParticle("flame",
|
||||
|
||||
var particle = GameMain.ParticleManager.CreateParticle(particlePrefab,
|
||||
particlePos, particleVel, 0.0f, hull);
|
||||
|
||||
if (particle == null) { continue; }
|
||||
@@ -54,7 +62,7 @@ namespace Barotrauma
|
||||
if (Rand.Int(5) == 1)
|
||||
{
|
||||
var smokeParticle = GameMain.ParticleManager.CreateParticle("smoke",
|
||||
particlePos, new Vector2(particleVel.X, particleVel.Y * 0.1f), 0.0f, hull);
|
||||
particlePos, new Vector2(particleVel.X, particleVel.Y * 0.1f), 0.0f, hull);
|
||||
|
||||
if (smokeParticle != null)
|
||||
{
|
||||
|
||||
@@ -324,13 +324,13 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
|
||||
/*GUI.DrawLine(spriteBatch, new Vector2(drawRect.X, -WorldSurface), new Vector2(drawRect.Right, -WorldSurface), Color.Cyan * 0.5f);
|
||||
GUI.DrawLine(spriteBatch, new Vector2(drawRect.X, -WorldSurface), new Vector2(drawRect.Right, -WorldSurface), Color.Cyan * 0.5f);
|
||||
for (int i = 0; i < waveY.Length - 1; i++)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(drawRect.X + WaveWidth * i, -WorldSurface - waveY[i] - 10),
|
||||
new Vector2(drawRect.X + WaveWidth * (i + 1), -WorldSurface - waveY[i + 1] - 10), Color.Blue * 0.5f);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MapEntity e in linkedTo)
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (var edge in cell.Edges)
|
||||
{
|
||||
if (MathUtils.GetLineIntersection(worldPosition, cell.Center, edge.Point1 + cell.Translation, edge.Point2 + cell.Translation, out Vector2 intersection))
|
||||
if (MathUtils.GetLineSegmentIntersection(worldPosition, cell.Center, edge.Point1 + cell.Translation, edge.Point2 + cell.Translation, out Vector2 intersection))
|
||||
{
|
||||
intersectionFound = true;
|
||||
particlePos = intersection;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -32,13 +31,13 @@ namespace Barotrauma.Lights
|
||||
public bool IsHorizontal;
|
||||
public bool IsAxisAligned;
|
||||
|
||||
public Vector2 SubmarineDrawPos;
|
||||
|
||||
public Segment(SegmentPoint start, SegmentPoint end, ConvexHull convexHull)
|
||||
{
|
||||
if (start.Pos.Y > end.Pos.Y)
|
||||
{
|
||||
var temp = start;
|
||||
start = end;
|
||||
end = temp;
|
||||
(end, start) = (start, end);
|
||||
}
|
||||
|
||||
Start = start;
|
||||
@@ -87,19 +86,23 @@ namespace Barotrauma.Lights
|
||||
|
||||
private readonly Segment[] segments = new Segment[4];
|
||||
private readonly SegmentPoint[] vertices = new SegmentPoint[4];
|
||||
private readonly SegmentPoint[] losVertices = new SegmentPoint[4];
|
||||
private readonly VectorPair[] losOffsets = new VectorPair[4];
|
||||
|
||||
private readonly bool[] backFacing;
|
||||
private readonly bool[] ignoreEdge;
|
||||
private readonly SegmentPoint[] losVertices = new SegmentPoint[2];
|
||||
private readonly Vector2[] losOffsets = new Vector2[2];
|
||||
|
||||
private readonly bool isHorizontal;
|
||||
|
||||
private readonly int thickness;
|
||||
|
||||
public VertexPositionColor[] ShadowVertices { get; private set; }
|
||||
public VertexPositionTexture[] PenumbraVertices { get; private set; }
|
||||
public int ShadowVertexCount { get; private set; }
|
||||
public int PenumbraVertexCount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the maximum distance a LOS vertex can be moved to make it align with a nearby LOS segment
|
||||
/// </summary>
|
||||
public float? MaxMergeLosVerticesDist;
|
||||
|
||||
private readonly HashSet<ConvexHull> overlappingHulls = new HashSet<ConvexHull>();
|
||||
|
||||
public MapEntity ParentEntity { get; private set; }
|
||||
@@ -130,61 +133,59 @@ namespace Barotrauma.Lights
|
||||
|
||||
public Rectangle BoundingBox { get; private set; }
|
||||
|
||||
public ConvexHull(Vector2[] points, Color color, MapEntity parent)
|
||||
public ConvexHull(Rectangle rect, bool isHorizontal, MapEntity parent)
|
||||
{
|
||||
if (shadowEffect == null)
|
||||
{
|
||||
shadowEffect = new BasicEffect(GameMain.Instance.GraphicsDevice)
|
||||
shadowEffect ??= new BasicEffect(GameMain.Instance.GraphicsDevice)
|
||||
{
|
||||
VertexColorEnabled = true
|
||||
};
|
||||
}
|
||||
if (penumbraEffect == null)
|
||||
{
|
||||
penumbraEffect = new BasicEffect(GameMain.Instance.GraphicsDevice)
|
||||
penumbraEffect ??= new BasicEffect(GameMain.Instance.GraphicsDevice)
|
||||
{
|
||||
TextureEnabled = true,
|
||||
LightingEnabled = false,
|
||||
Texture = TextureLoader.FromFile("Content/Lights/penumbra.png")
|
||||
};
|
||||
}
|
||||
|
||||
ParentEntity = parent;
|
||||
|
||||
ShadowVertices = new VertexPositionColor[6 * 4];
|
||||
PenumbraVertices = new VertexPositionTexture[6 * 4];
|
||||
|
||||
backFacing = new bool[4];
|
||||
ignoreEdge = new bool[4];
|
||||
BoundingBox = rect;
|
||||
|
||||
float minX = points[0].X, minY = points[0].Y, maxX = points[0].X, maxY = points[0].Y;
|
||||
|
||||
for (int i = 1; i < vertices.Length; i++)
|
||||
{
|
||||
if (points[i].X < minX) minX = points[i].X;
|
||||
if (points[i].Y < minY) minY = points[i].Y;
|
||||
|
||||
if (points[i].X > maxX) maxX = points[i].X;
|
||||
if (points[i].Y > minY) maxY = points[i].Y;
|
||||
}
|
||||
|
||||
BoundingBox = new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY));
|
||||
|
||||
isHorizontal = BoundingBox.Width > BoundingBox.Height;
|
||||
this.isHorizontal = isHorizontal;
|
||||
if (ParentEntity is Structure structure)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(!structure.Removed);
|
||||
Debug.Assert(!structure.Removed);
|
||||
isHorizontal = structure.IsHorizontal;
|
||||
}
|
||||
else if (ParentEntity is Item item)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(!item.Removed);
|
||||
Debug.Assert(!item.Removed);
|
||||
var door = item.GetComponent<Door>();
|
||||
if (door != null) { isHorizontal = door.IsHorizontal; }
|
||||
}
|
||||
|
||||
SetVertices(points);
|
||||
|
||||
Vector2[] verts = new Vector2[]
|
||||
{
|
||||
new Vector2(rect.X, rect.Bottom),
|
||||
new Vector2(rect.Right, rect.Bottom),
|
||||
new Vector2(rect.Right, rect.Y),
|
||||
new Vector2(rect.X, rect.Y),
|
||||
};
|
||||
|
||||
Vector2[] losVerts;
|
||||
if (this.isHorizontal)
|
||||
{
|
||||
thickness = rect.Height;
|
||||
losVerts = new Vector2[] { new Vector2(rect.X, rect.Center.Y), new Vector2(rect.Right, rect.Center.Y) };
|
||||
}
|
||||
else
|
||||
{
|
||||
thickness = rect.Width;
|
||||
losVerts = new Vector2[] { new Vector2(rect.Center.X, rect.Y), new Vector2(rect.Center.X, rect.Bottom) };
|
||||
}
|
||||
SetVertices(verts, losVerts);
|
||||
Enabled = true;
|
||||
|
||||
var chList = HullLists.Find(h => h.Submarine == parent.Submarine);
|
||||
@@ -196,249 +197,123 @@ namespace Barotrauma.Lights
|
||||
|
||||
foreach (ConvexHull ch in chList.List)
|
||||
{
|
||||
MergeOverlappingSegments(ch);
|
||||
ch.MergeOverlappingSegments(this);
|
||||
MergeLosVertices(ch);
|
||||
ch.MergeLosVertices(this);
|
||||
}
|
||||
|
||||
chList.List.Add(this);
|
||||
}
|
||||
|
||||
private void MergeOverlappingSegments(ConvexHull ch)
|
||||
private void MergeLosVertices(ConvexHull ch, bool refreshOtherOverlappingHulls = true)
|
||||
{
|
||||
if (ch == this) { return; }
|
||||
|
||||
if (isHorizontal == ch.isHorizontal)
|
||||
//merge dist in the direction parallel to the segment
|
||||
//(e.g. how far up/down we can stretch a vertical segment)
|
||||
float mergeDistParallel = MathHelper.Clamp(ch.thickness * 0.65f, 16, 512);
|
||||
if (MaxMergeLosVerticesDist.HasValue)
|
||||
{
|
||||
//hide segments that are roughly at the some position as some other segment (e.g. the ends of two adjacent wall pieces)
|
||||
float mergeDist = 16;
|
||||
float mergeDistSqr = mergeDist * mergeDist;
|
||||
|
||||
Rectangle intersection = Rectangle.Intersect(BoundingBox, ch.BoundingBox);
|
||||
int intersectionArea = intersection.Width * intersection.Height;
|
||||
int bboxArea = BoundingBox.Width * BoundingBox.Height;
|
||||
int otherBboxArea = ch.BoundingBox.Width * ch.BoundingBox.Height;
|
||||
if (Math.Abs(intersectionArea - bboxArea) < mergeDistSqr) { return; }
|
||||
if (Math.Abs(intersectionArea - otherBboxArea) < mergeDistSqr) { return; }
|
||||
|
||||
for (int i = 0; i < segments.Length; i++)
|
||||
{
|
||||
for (int j = 0; j < ch.segments.Length; j++)
|
||||
{
|
||||
if (segments[i].IsHorizontal != ch.segments[j].IsHorizontal) { continue; }
|
||||
if (ignoreEdge[i] || ch.ignoreEdge[j]) { continue; }
|
||||
|
||||
//the segments must be at different sides of the convex hulls to be merged
|
||||
//(e.g. the right edge of a wall piece and the left edge of another one)
|
||||
var segment1Center = (segments[i].Start.Pos + segments[i].End.Pos) / 2.0f;
|
||||
var segment2Center = (ch.segments[j].Start.Pos + ch.segments[j].End.Pos) / 2.0f;
|
||||
if (Vector2.Dot(segment1Center - BoundingBox.Center.ToVector2(), segment2Center - ch.BoundingBox.Center.ToVector2()) > 0) { continue; }
|
||||
|
||||
if (Vector2.DistanceSquared(segments[i].Start.Pos, ch.segments[j].Start.Pos) < mergeDistSqr &&
|
||||
Vector2.DistanceSquared(segments[i].End.Pos, ch.segments[j].End.Pos) < mergeDistSqr)
|
||||
{
|
||||
ignoreEdge[i] = true;
|
||||
ch.ignoreEdge[j] = true;
|
||||
MergeSegments(segments[i], ch.segments[j], true);
|
||||
}
|
||||
else if (Vector2.DistanceSquared(segments[i].Start.Pos, ch.segments[j].End.Pos) < mergeDistSqr &&
|
||||
Vector2.DistanceSquared(segments[i].End.Pos, ch.segments[j].Start.Pos) < mergeDistSqr)
|
||||
{
|
||||
ignoreEdge[i] = true;
|
||||
ch.ignoreEdge[j] = true;
|
||||
MergeSegments(segments[i], ch.segments[j], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < segments.Length; i++)
|
||||
{
|
||||
if (ignoreEdge[i]) { continue; }
|
||||
if (Vector2.DistanceSquared(segments[i].Start.Pos, segments[i].End.Pos) < 1.0f) { continue; }
|
||||
for (int j = 0; j < ch.segments.Length; j++)
|
||||
{
|
||||
if (ch.ignoreEdge[j]) { continue; }
|
||||
if (Vector2.DistanceSquared(ch.segments[j].Start.Pos, ch.segments[j].End.Pos) < 1.0f) { continue; }
|
||||
if (IsSegmentAInB(segments[i], ch.segments[j]))
|
||||
{
|
||||
ignoreEdge[i] = true;
|
||||
if (Vector2.DistanceSquared(ch.segments[j].Start.Pos, segments[i].Start.Pos) < 4.0f)
|
||||
{
|
||||
ch.ShiftSegmentPoint(j, false, segments[i].End.Pos);
|
||||
}
|
||||
else if (Vector2.DistanceSquared(ch.segments[j].Start.Pos, segments[i].End.Pos) < 4.0f)
|
||||
{
|
||||
ch.ShiftSegmentPoint(j, false, segments[i].Start.Pos);
|
||||
}
|
||||
|
||||
if (Vector2.DistanceSquared(ch.segments[j].End.Pos, segments[i].Start.Pos) < 4.0f)
|
||||
{
|
||||
ch.ShiftSegmentPoint(j, true, segments[i].End.Pos);
|
||||
}
|
||||
else if (Vector2.DistanceSquared(ch.segments[j].End.Pos, segments[i].End.Pos) < 4.0f)
|
||||
{
|
||||
ch.ShiftSegmentPoint(j, true, segments[i].Start.Pos);
|
||||
}
|
||||
}
|
||||
else if (IsSegmentAInB(ch.segments[j], segments[i]))
|
||||
{
|
||||
ch.ignoreEdge[j] = true;
|
||||
|
||||
if (Vector2.DistanceSquared(segments[i].Start.Pos, ch.segments[j].Start.Pos) < 4.0f)
|
||||
{
|
||||
ShiftSegmentPoint(i, false, ch.segments[j].End.Pos);
|
||||
}
|
||||
else if (Vector2.DistanceSquared(segments[i].Start.Pos, ch.segments[j].End.Pos) < 4.0f)
|
||||
{
|
||||
ShiftSegmentPoint(i, false, ch.segments[j].Start.Pos);
|
||||
}
|
||||
|
||||
if (Vector2.DistanceSquared(segments[i].End.Pos, ch.segments[j].Start.Pos) < 4.0f)
|
||||
{
|
||||
ShiftSegmentPoint(i, true, ch.segments[j].End.Pos);
|
||||
}
|
||||
else if (Vector2.DistanceSquared(segments[i].End.Pos, ch.segments[j].End.Pos) < 4.0f)
|
||||
{
|
||||
ShiftSegmentPoint(i, true, ch.segments[j].Start.Pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//ignore edges that are inside some other convex hull
|
||||
for (int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
if (ch.IsPointInside(vertices[i].Pos))
|
||||
{
|
||||
if (ch.IsPointInside(vertices[(i + 1) % vertices.Length].Pos))
|
||||
{
|
||||
ignoreEdge[i] = true;
|
||||
overlappingHulls.Add(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ShiftSegmentPoint(int segmentIndex, bool end, Vector2 newPos)
|
||||
{
|
||||
var segment = segments[segmentIndex];
|
||||
|
||||
losOffsets[segmentIndex] ??= new VectorPair();
|
||||
bool flipped = false;
|
||||
if (Vector2.DistanceSquared(vertices[segmentIndex].Pos, segment.Start.Pos) > Vector2.DistanceSquared(vertices[segmentIndex].Pos, segment.End.Pos))
|
||||
{
|
||||
flipped = true;
|
||||
}
|
||||
if (end == !flipped)
|
||||
{
|
||||
losOffsets[segmentIndex].B = newPos;
|
||||
mergeDistParallel = Math.Max(mergeDistParallel, MaxMergeLosVerticesDist.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
losOffsets[segmentIndex].A = newPos;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsSegmentAInB(Segment a, Segment b)
|
||||
{
|
||||
if (Vector2.DistanceSquared(a.Start.Pos, a.End.Pos) > Vector2.DistanceSquared(b.Start.Pos, b.End.Pos))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector2 min = new Vector2(Math.Min(b.Start.Pos.X, b.End.Pos.X), Math.Min(b.Start.Pos.Y, b.End.Pos.Y));
|
||||
min.X -= 1.0f; min.Y -= 1.0f;
|
||||
|
||||
if (a.Start.Pos.X < min.X) { return false; }
|
||||
if (a.Start.Pos.Y < min.Y) { return false; }
|
||||
if (a.End.Pos.X < min.X) { return false; }
|
||||
if (a.End.Pos.Y < min.Y) { return false; }
|
||||
|
||||
Vector2 max = new Vector2(Math.Max(b.Start.Pos.X, b.End.Pos.X), Math.Max(b.Start.Pos.Y, b.End.Pos.Y));
|
||||
max.X += 1.0f; max.Y += 1.0f;
|
||||
|
||||
if (a.Start.Pos.X > max.X) { return false; }
|
||||
if (a.Start.Pos.Y > max.Y) { return false; }
|
||||
if (a.End.Pos.X > max.X) { return false; }
|
||||
if (a.End.Pos.Y > max.Y) { return false; }
|
||||
|
||||
float startDist = MathUtils.LineToPointDistanceSquared(b.Start.Pos, b.End.Pos, a.Start.Pos);
|
||||
if (startDist > 1.0f) { return false; }
|
||||
float endDist = MathUtils.LineToPointDistanceSquared(b.Start.Pos, b.End.Pos, a.End.Pos);
|
||||
if (endDist > 1.0f) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsPointInside(Vector2 point)
|
||||
{
|
||||
if (!BoundingBox.Contains(point)) { return false; }
|
||||
|
||||
Vector2 center = (vertices[0].Pos + vertices[1].Pos + vertices[2].Pos + vertices[3].Pos) * 0.25f;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Vector2 segmentVector = vertices[(i + 1) % 4].Pos - vertices[i].Pos;
|
||||
Vector2 centerToVertex = center - vertices[i].Pos;
|
||||
Vector2 pointToVertex = point - vertices[i].Pos;
|
||||
|
||||
float dotCenter = Vector2.Dot(centerToVertex, segmentVector);
|
||||
float dotPoint = Vector2.Dot(pointToVertex, segmentVector);
|
||||
|
||||
if ((dotCenter > 0f && dotPoint < 0f) || (dotCenter < 0f && dotPoint > 0f)) { return false; }
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void MergeSegments(Segment segment1, Segment segment2, bool startPointsMatch)
|
||||
{
|
||||
int startPointIndex = -1, endPointIndex = -1;
|
||||
for (int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
if (vertices[i].Pos.NearlyEquals(segment1.Start.Pos))
|
||||
startPointIndex = i;
|
||||
else if (vertices[i].Pos.NearlyEquals(segment1.End.Pos))
|
||||
endPointIndex = i;
|
||||
}
|
||||
if (startPointIndex == -1 || endPointIndex == -1) { return; }
|
||||
|
||||
int startPoint2Index = -1, endPoint2Index = -1;
|
||||
for (int i = 0; i < segment2.ConvexHull.vertices.Length; i++)
|
||||
{
|
||||
if (segment2.ConvexHull.vertices[i].Pos.NearlyEquals(segment2.Start.Pos))
|
||||
startPoint2Index = i;
|
||||
else if (segment2.ConvexHull.vertices[i].Pos.NearlyEquals(segment2.End.Pos))
|
||||
endPoint2Index = i;
|
||||
}
|
||||
if (startPoint2Index == -1 || endPoint2Index == -1) { return; }
|
||||
|
||||
if (startPointsMatch)
|
||||
{
|
||||
losVertices[startPointIndex].Pos = segment2.ConvexHull.losVertices[startPoint2Index].Pos =
|
||||
(segment1.Start.Pos + segment2.Start.Pos) / 2.0f;
|
||||
losVertices[endPointIndex].Pos = segment2.ConvexHull.losVertices[endPoint2Index].Pos =
|
||||
(segment1.End.Pos + segment2.End.Pos) / 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Vector2.DistanceSquared(losVertices[startPointIndex].Pos, segment1.Start.Pos) <
|
||||
Vector2.DistanceSquared(losVertices[startPointIndex].Pos, segment1.End.Pos))
|
||||
Rectangle inflatedAABB = ch.BoundingBox;
|
||||
inflatedAABB.Inflate(2, 2);
|
||||
//if this los segment isn't touching the other's bounding box,
|
||||
//don't extend the segment by more than 50% of it's length
|
||||
if (!inflatedAABB.Contains(losVertices[0].Pos) &&
|
||||
!inflatedAABB.Contains(losVertices[1].Pos))
|
||||
{
|
||||
losVertices[startPointIndex].Pos = segment2.ConvexHull.losVertices[startPoint2Index].Pos =
|
||||
(segment1.Start.Pos + segment2.End.Pos) / 2.0f;
|
||||
losVertices[endPointIndex].Pos = segment2.ConvexHull.losVertices[endPoint2Index].Pos =
|
||||
(segment1.End.Pos + segment2.Start.Pos) / 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
losVertices[startPointIndex].Pos = segment2.ConvexHull.losVertices[startPoint2Index].Pos =
|
||||
(segment1.End.Pos + segment2.Start.Pos) / 2.0f;
|
||||
losVertices[endPointIndex].Pos = segment2.ConvexHull.losVertices[endPoint2Index].Pos =
|
||||
(segment1.Start.Pos + segment2.End.Pos) / 2.0f;
|
||||
mergeDistParallel = Math.Min(mergeDistParallel, Vector2.Distance(losVertices[0].Pos, losVertices[1].Pos) * 0.5f);
|
||||
}
|
||||
}
|
||||
//merge dist in the direction perpendicular to the segment
|
||||
//(e.g. how far right/left we can stretch a vertical segment)
|
||||
//do not allow more than ~half of the thickness, because that'd make the segment go outside the convex hull
|
||||
float mergeDistPerpendicular = Math.Min(mergeDistParallel, thickness * 0.35f);
|
||||
|
||||
overlappingHulls.Add(segment2.ConvexHull);
|
||||
segment2.ConvexHull.overlappingHulls.Add(this);
|
||||
Vector2 center = (losVertices[0].Pos + losVertices[1].Pos) / 2;
|
||||
|
||||
bool changed = false;
|
||||
for (int i = 0; i < losVertices.Length; i++)
|
||||
{
|
||||
Vector2 segmentDir = Vector2.Normalize(losVertices[i].Pos - center);
|
||||
//check if the closest point on the other convex hull segment is close enough, disregarding any offsets
|
||||
//otherwise we might end up moving the vertex too much if we stretch it to an already-offset segment
|
||||
if (!isCloseEnough(
|
||||
MathUtils.GetClosestPointOnLineSegment(ch.losVertices[0].Pos, ch.losVertices[1].Pos, losVertices[i].Pos),
|
||||
losVertices[i].Pos))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//check the offset position of the segment next
|
||||
Vector2 closest = MathUtils.GetClosestPointOnLineSegment(
|
||||
ch.losVertices[0].Pos + ch.losOffsets[0],
|
||||
ch.losVertices[1].Pos + ch.losOffsets[1],
|
||||
losVertices[i].Pos);
|
||||
if (!isCloseEnough(closest, losVertices[i].Pos)) { continue; }
|
||||
|
||||
//find where the segments would intersect if they had infinite length
|
||||
// if it's close to the closest point, let's use that instead to keep
|
||||
// the direction of the segment unchanged (i.e. vertical segment stays vertical)
|
||||
if (MathUtils.GetLineIntersection(
|
||||
ch.losVertices[0].Pos + ch.losOffsets[0], ch.losVertices[1].Pos + ch.losOffsets[1],
|
||||
losVertices[0].Pos, losVertices[1].Pos,
|
||||
areLinesInfinite: true, out Vector2 intersection) &&
|
||||
//the intersection needs to be outwards from the vertex we're checking
|
||||
Vector2.Dot(segmentDir, intersection - losVertices[i].Pos) > 0 &&
|
||||
//the intersection needs to be close enough to the default position of the vertex and the closest point
|
||||
//(we don't want to merge the segments somewhere close to infinity!)
|
||||
(Vector2.DistanceSquared(intersection, losVertices[i].Pos) < mergeDistParallel * mergeDistParallel ||
|
||||
Vector2.DistanceSquared(intersection, closest) < 16.0f * 16.0f))
|
||||
{
|
||||
closest = intersection;
|
||||
}
|
||||
|
||||
//don't move the vertices of the segment too close to each other
|
||||
if (Vector2.DistanceSquared(losVertices[1 - i].Pos + losOffsets[1 - i], closest) < mergeDistPerpendicular * mergeDistPerpendicular)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
losOffsets[i] = closest - losVertices[i].Pos;
|
||||
overlappingHulls.Add(ch);
|
||||
ch.overlappingHulls.Add(this);
|
||||
changed = true;
|
||||
|
||||
bool isCloseEnough(Vector2 closest, Vector2 vertex)
|
||||
{
|
||||
float dist = Vector2.Distance(closest, vertex);
|
||||
if (dist < 0.001f) { return true; }
|
||||
if (dist > mergeDistParallel) { return false; }
|
||||
|
||||
Vector2 closestDir = (closest - vertex) / dist;
|
||||
|
||||
float dot = Math.Abs(Vector2.Dot(segmentDir, closestDir));
|
||||
float distAlongAxis = dist * dot;
|
||||
if (distAlongAxis > mergeDistParallel) { return false; }
|
||||
|
||||
float distPerpendicular = dist * (1.0f - dot);
|
||||
if (distPerpendicular > mergeDistPerpendicular) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (changed && refreshOtherOverlappingHulls)
|
||||
{
|
||||
foreach (var overlapping in overlappingHulls)
|
||||
{
|
||||
overlapping.MergeLosVertices(this, refreshOtherOverlappingHulls: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool LosIntersects(Vector2 pos1, Vector2 pos2)
|
||||
{
|
||||
return MathUtils.LineSegmentsIntersect(
|
||||
losVertices[0].Pos + losOffsets[0], losVertices[1].Pos + losOffsets[1],
|
||||
pos1, pos2);
|
||||
}
|
||||
|
||||
public void Rotate(Vector2 origin, float amount)
|
||||
@@ -447,7 +322,7 @@ namespace Barotrauma.Lights
|
||||
Matrix.CreateTranslation(-origin.X, -origin.Y, 0.0f) *
|
||||
Matrix.CreateRotationZ(amount) *
|
||||
Matrix.CreateTranslation(origin.X, origin.Y, 0.0f);
|
||||
SetVertices(vertices.Select(v => v.Pos).ToArray(), rotationMatrix: rotationMatrix);
|
||||
SetVertices(vertices.Select(v => v.Pos).ToArray(), losVertices.Select(v => v.Pos).ToArray(), rotationMatrix: rotationMatrix);
|
||||
}
|
||||
|
||||
private void CalculateDimensions()
|
||||
@@ -456,11 +331,10 @@ namespace Barotrauma.Lights
|
||||
|
||||
for (int i = 1; i < vertices.Length; i++)
|
||||
{
|
||||
if (vertices[i].Pos.X < minX) minX = vertices[i].Pos.X;
|
||||
if (vertices[i].Pos.Y < minY) minY = vertices[i].Pos.Y;
|
||||
|
||||
if (vertices[i].Pos.X > maxX) maxX = vertices[i].Pos.X;
|
||||
if (vertices[i].Pos.Y > minY) maxY = vertices[i].Pos.Y;
|
||||
minX = Math.Min(minX, vertices[i].Pos.X);
|
||||
minY = Math.Min(minY, vertices[i].Pos.Y);
|
||||
maxX = Math.Max(maxX, vertices[i].Pos.X);
|
||||
maxY = Math.Max(maxY, vertices[i].Pos.Y);
|
||||
}
|
||||
|
||||
BoundingBox = new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY));
|
||||
@@ -471,21 +345,17 @@ namespace Barotrauma.Lights
|
||||
for (int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
vertices[i].Pos += amount;
|
||||
losVertices[i].Pos += amount;
|
||||
|
||||
losOffsets[i] = null;
|
||||
|
||||
segments[i].Start.Pos += amount;
|
||||
segments[i].End.Pos += amount;
|
||||
}
|
||||
for (int i = 0; i < losVertices.Length; i++)
|
||||
{
|
||||
losVertices[i].Pos += amount;
|
||||
}
|
||||
|
||||
LastVertexChangeTime = (float)Timing.TotalTime;
|
||||
|
||||
overlappingHulls.Clear();
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
ignoreEdge[i] = false;
|
||||
}
|
||||
|
||||
CalculateDimensions();
|
||||
|
||||
@@ -497,8 +367,8 @@ namespace Barotrauma.Lights
|
||||
overlappingHulls.Clear();
|
||||
foreach (ConvexHull ch in chList.List)
|
||||
{
|
||||
MergeOverlappingSegments(ch);
|
||||
ch.MergeOverlappingSegments(this);
|
||||
MergeLosVertices(ch);
|
||||
ch.MergeLosVertices(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -511,23 +381,23 @@ namespace Barotrauma.Lights
|
||||
foreach (ConvexHull ch in chList.List)
|
||||
{
|
||||
ch.overlappingHulls.Clear();
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int i = 0; i < ch.losOffsets.Length; i++)
|
||||
{
|
||||
ch.ignoreEdge[i] = false;
|
||||
ch.losOffsets[i] = Vector2.Zero;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < chList.List.Count; i++)
|
||||
{
|
||||
for (int j = i + 1; j < chList.List.Count; j++)
|
||||
{
|
||||
chList.List[i].MergeOverlappingSegments(chList.List[j]);
|
||||
chList.List[j].MergeOverlappingSegments(chList.List[i]);
|
||||
chList.List[i].MergeLosVertices(chList.List[j]);
|
||||
chList.List[j].MergeLosVertices(chList.List[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVertices(Vector2[] points, bool mergeOverlappingSegments = true, Matrix? rotationMatrix = null)
|
||||
public void SetVertices(Vector2[] points, Vector2[] losPoints, bool mergeOverlappingSegments = true, Matrix? rotationMatrix = null)
|
||||
{
|
||||
Debug.Assert(points.Length == 4, "Only rectangular convex hulls are supported");
|
||||
|
||||
@@ -535,39 +405,24 @@ namespace Barotrauma.Lights
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
vertices[i] = new SegmentPoint(points[i], this);
|
||||
losVertices[i] = new SegmentPoint(points[i], this);
|
||||
losOffsets[i] = null;
|
||||
vertices[i] = new SegmentPoint(points[i], this);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
ignoreEdge[i] = false;
|
||||
losVertices[i] = new SegmentPoint(losPoints[i], this);
|
||||
losOffsets[i] = Vector2.Zero;
|
||||
}
|
||||
|
||||
overlappingHulls.Clear();
|
||||
|
||||
int margin = 0;
|
||||
if (Math.Abs(points[0].X - points[2].X) < Math.Abs(points[0].Y - points[2].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[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);
|
||||
}
|
||||
|
||||
if (rotationMatrix.HasValue)
|
||||
{
|
||||
for (int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
vertices[i].Pos = Vector2.Transform(vertices[i].Pos, rotationMatrix.Value);
|
||||
}
|
||||
for (int i = 0; i < losVertices.Length; i++)
|
||||
{
|
||||
losVertices[i].Pos = Vector2.Transform(losVertices[i].Pos, rotationMatrix.Value);
|
||||
}
|
||||
}
|
||||
@@ -588,7 +443,7 @@ namespace Barotrauma.Lights
|
||||
overlappingHulls.Clear();
|
||||
foreach (ConvexHull ch in chList.List)
|
||||
{
|
||||
MergeOverlappingSegments(ch);
|
||||
MergeLosVertices(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -610,31 +465,17 @@ namespace Barotrauma.Lights
|
||||
/// <summary>
|
||||
/// Returns the segments that are facing towards viewPosition
|
||||
/// </summary>
|
||||
public void GetVisibleSegments(Vector2 viewPosition, List<Segment> visibleSegments, bool ignoreEdges)
|
||||
public void GetVisibleSegments(Vector2 viewPosition, List<Segment> visibleSegments)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (ignoreEdge[i] && ignoreEdges) { continue; }
|
||||
|
||||
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(
|
||||
-(pos2.Y - pos1.Y),
|
||||
pos2.X - pos1.X);
|
||||
|
||||
if (Vector2.Dot(N, L) > 0)
|
||||
if (IsSegmentFacing(vertices[i].WorldPos, vertices[(i + 1) % 4].WorldPos, viewPosition))
|
||||
{
|
||||
visibleSegments.Add(segments[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void RefreshWorldPositions()
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
@@ -662,34 +503,12 @@ namespace Barotrauma.Lights
|
||||
|
||||
ShadowVertexCount = 0;
|
||||
|
||||
//compute facing of each edge, using N*L
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int i = 0; i < losVertices.Length; i++)
|
||||
{
|
||||
if (ignoreEdge[i])
|
||||
{
|
||||
backFacing[i] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector2 firstVertex = losVertices[i].Pos;
|
||||
Vector2 secondVertex = losVertices[(i+1) % 4].Pos;
|
||||
|
||||
Vector2 L = lightSourcePos - ((firstVertex + secondVertex) / 2.0f);
|
||||
|
||||
Vector2 N = new Vector2(
|
||||
-(secondVertex.Y - firstVertex.Y),
|
||||
secondVertex.X - firstVertex.X);
|
||||
|
||||
backFacing[i] = (Vector2.Dot(N, L) < 0);
|
||||
}
|
||||
|
||||
ShadowVertexCount = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (!backFacing[i]) { continue; }
|
||||
int currentIndex = i;
|
||||
Vector3 vertexPos0 = new Vector3(losOffsets[currentIndex]?.A ?? losVertices[currentIndex].Pos, 0.0f);
|
||||
Vector3 vertexPos1 = new Vector3(losOffsets[currentIndex]?.B ?? losVertices[(currentIndex + 1) % 4].Pos, 0.0f);
|
||||
int nextIndex = (currentIndex + 1) % 2;
|
||||
Vector3 vertexPos0 = new Vector3(losVertices[currentIndex].Pos + losOffsets[currentIndex], 0.0f);
|
||||
Vector3 vertexPos1 = new Vector3(losVertices[nextIndex].Pos + losOffsets[nextIndex], 0.0f);
|
||||
|
||||
if (Vector3.DistanceSquared(vertexPos0, vertexPos1) < 1.0f) { continue; }
|
||||
|
||||
@@ -740,9 +559,24 @@ namespace Barotrauma.Lights
|
||||
ShadowVertexCount += 6;
|
||||
}
|
||||
|
||||
if (IsSegmentFacing(losVertices[0].Pos, losVertices[1].Pos, lightSourcePos))
|
||||
{
|
||||
Array.Reverse(ShadowVertices);
|
||||
}
|
||||
|
||||
CalculateLosPenumbraVertices(lightSourcePos);
|
||||
}
|
||||
|
||||
private static bool IsSegmentFacing(Vector2 segmentPos1, Vector2 segmentPos2, Vector2 viewPosition)
|
||||
{
|
||||
Vector2 segmentMid = (segmentPos1 + segmentPos2) / 2;
|
||||
Vector2 segmentDiff = segmentPos2 - segmentPos1;
|
||||
Vector2 segmentNormal = new Vector2(-segmentDiff.Y, segmentDiff.X);
|
||||
|
||||
Vector2 viewDirection = viewPosition - segmentMid;
|
||||
return Vector2.Dot(segmentNormal, viewDirection) > 0;
|
||||
}
|
||||
|
||||
private void CalculateLosPenumbraVertices(Vector2 lightSourcePos)
|
||||
{
|
||||
Vector3 offset = Vector3.Zero;
|
||||
@@ -752,73 +586,104 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
|
||||
PenumbraVertexCount = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int i = 0; i < losVertices.Length; i++)
|
||||
{
|
||||
int currentIndex = i;
|
||||
int prevIndex = (i + 3) % 4;
|
||||
int nextIndex = (i + 1) % 4;
|
||||
bool disjointed = losOffsets[i]?.A != null;
|
||||
Vector2 vertexPos0 = losOffsets[currentIndex]?.A ?? losVertices[currentIndex].Pos;
|
||||
Vector2 vertexPos1 = losOffsets[currentIndex]?.B ?? losVertices[nextIndex].Pos;
|
||||
int nextIndex = (i + 1) % 2;
|
||||
Vector2 vertexPos0 = losVertices[currentIndex].Pos + losOffsets[currentIndex];
|
||||
Vector2 vertexPos1 = losVertices[nextIndex].Pos + losOffsets[nextIndex];
|
||||
|
||||
if (Vector2.DistanceSquared(vertexPos0, vertexPos1) < 1.0f) { continue; }
|
||||
|
||||
Vector3 penumbraStart = new Vector3(vertexPos0, 0.0f);
|
||||
|
||||
if (backFacing[currentIndex] && (disjointed || (!backFacing[prevIndex])))
|
||||
PenumbraVertices[PenumbraVertexCount] = new VertexPositionTexture
|
||||
{
|
||||
Vector3 penumbraStart = new Vector3(vertexPos0, 0.0f);
|
||||
Position = penumbraStart + offset,
|
||||
TextureCoordinate = new Vector2(0.0f, 1.0f)
|
||||
};
|
||||
|
||||
PenumbraVertices[PenumbraVertexCount] = new VertexPositionTexture
|
||||
{
|
||||
Position = penumbraStart + offset,
|
||||
TextureCoordinate = new Vector2(0.0f, 1.0f)
|
||||
};
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
PenumbraVertices[PenumbraVertexCount + j + 1] = new VertexPositionTexture();
|
||||
Vector3 vertexDir = penumbraStart - new Vector3(lightSourcePos, 0);
|
||||
vertexDir.Normalize();
|
||||
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
PenumbraVertices[PenumbraVertexCount + j + 1] = new VertexPositionTexture();
|
||||
Vector3 vertexDir = penumbraStart - new Vector3(lightSourcePos, 0);
|
||||
vertexDir.Normalize();
|
||||
Vector3 normal = (j == 0) ? new Vector3(-vertexDir.Y, vertexDir.X, 0.0f) : new Vector3(vertexDir.Y, -vertexDir.X, 0.0f) * 0.05f;
|
||||
|
||||
Vector3 normal = (j == 0) ? new Vector3(-vertexDir.Y, vertexDir.X, 0.0f) : new Vector3(vertexDir.Y, -vertexDir.X, 0.0f) * 0.05f;
|
||||
vertexDir = penumbraStart - (new Vector3(lightSourcePos, 0) - normal * 20.0f);
|
||||
vertexDir.Normalize();
|
||||
PenumbraVertices[PenumbraVertexCount + j + 1].Position = new Vector3(lightSourcePos, 0) + vertexDir * 9000 + offset;
|
||||
|
||||
vertexDir = penumbraStart - (new Vector3(lightSourcePos, 0) - normal * 20.0f);
|
||||
vertexDir.Normalize();
|
||||
PenumbraVertices[PenumbraVertexCount + j + 1].Position = new Vector3(lightSourcePos, 0) + vertexDir * 9000 + offset;
|
||||
|
||||
PenumbraVertices[PenumbraVertexCount + j + 1].TextureCoordinate = (j == 0) ? new Vector2(0.05f, 0.0f) : new Vector2(1.0f, 0.0f);
|
||||
}
|
||||
|
||||
PenumbraVertexCount += 3;
|
||||
PenumbraVertices[PenumbraVertexCount + j + 1].TextureCoordinate = (j == 0) ? new Vector2(0.05f, 0.0f) : new Vector2(1.0f, 0.0f);
|
||||
}
|
||||
|
||||
disjointed = losOffsets[i]?.B != null;
|
||||
if (backFacing[currentIndex] && (disjointed || (!backFacing[nextIndex])))
|
||||
PenumbraVertexCount += 3;
|
||||
|
||||
penumbraStart = new Vector3(vertexPos1, 0.0f);
|
||||
|
||||
PenumbraVertices[PenumbraVertexCount] = new VertexPositionTexture
|
||||
{
|
||||
Vector3 penumbraStart = new Vector3(vertexPos1, 0.0f);
|
||||
Position = penumbraStart + offset,
|
||||
TextureCoordinate = new Vector2(0.0f, 1.0f)
|
||||
};
|
||||
|
||||
PenumbraVertices[PenumbraVertexCount] = new VertexPositionTexture
|
||||
{
|
||||
Position = penumbraStart + offset,
|
||||
TextureCoordinate = new Vector2(0.0f, 1.0f)
|
||||
};
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
PenumbraVertices[PenumbraVertexCount + (1 - j) + 1] = new VertexPositionTexture();
|
||||
Vector3 vertexDir = penumbraStart - new Vector3(lightSourcePos, 0);
|
||||
vertexDir.Normalize();
|
||||
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
PenumbraVertices[PenumbraVertexCount + (1 - j) + 1] = new VertexPositionTexture();
|
||||
Vector3 vertexDir = penumbraStart - new Vector3(lightSourcePos, 0);
|
||||
vertexDir.Normalize();
|
||||
Vector3 normal = (j == 0) ? new Vector3(-vertexDir.Y, vertexDir.X, 0.0f) : new Vector3(vertexDir.Y, -vertexDir.X, 0.0f) * 0.05f;
|
||||
|
||||
Vector3 normal = (j == 0) ? new Vector3(-vertexDir.Y, vertexDir.X, 0.0f) : new Vector3(vertexDir.Y, -vertexDir.X, 0.0f) * 0.05f;
|
||||
vertexDir = penumbraStart - (new Vector3(lightSourcePos, 0) + normal * 20.0f);
|
||||
vertexDir.Normalize();
|
||||
PenumbraVertices[PenumbraVertexCount + (1 - j) + 1].Position = new Vector3(lightSourcePos, 0) + vertexDir * 9000 + offset;
|
||||
|
||||
vertexDir = penumbraStart - (new Vector3(lightSourcePos, 0) + normal * 20.0f);
|
||||
vertexDir.Normalize();
|
||||
PenumbraVertices[PenumbraVertexCount + (1 - j) + 1].Position = new Vector3(lightSourcePos, 0) + vertexDir * 9000 + offset;
|
||||
|
||||
PenumbraVertices[PenumbraVertexCount + (1 - j) + 1].TextureCoordinate = (j == 0) ? new Vector2(0.05f, 0.0f) : new Vector2(1.0f, 0.0f);
|
||||
}
|
||||
|
||||
PenumbraVertexCount += 3;
|
||||
PenumbraVertices[PenumbraVertexCount + (1 - j) + 1].TextureCoordinate = (j == 0) ? new Vector2(0.05f, 0.0f) : new Vector2(1.0f, 0.0f);
|
||||
}
|
||||
|
||||
PenumbraVertexCount += 3;
|
||||
}
|
||||
}
|
||||
|
||||
public void DebugDraw(SpriteBatch spriteBatch)
|
||||
{
|
||||
//RecalculateAll(Submarine.MainSub);
|
||||
//RefreshWorldPositions();
|
||||
|
||||
DrawLine(losVertices[0].Pos, losVertices[1].Pos, Color.Gray * 0.5f, width: 3);
|
||||
DrawLine(losVertices[0].Pos + losOffsets[0], losVertices[1].Pos + losOffsets[1], Color.LightGreen, width: 2);
|
||||
DrawLine(GameMain.GameScreen.Cam.Position + Vector2.One * 1000, GameMain.GameScreen.Cam.Position - Vector2.One * 1000, Color.Magenta, width: 2);
|
||||
|
||||
if (GameMain.LightManager.LightingEnabled)
|
||||
{
|
||||
for (int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
Vector2 start = vertices[i].Pos;
|
||||
Vector2 end = vertices[(i + 1) % 4].Pos;
|
||||
DrawLine(
|
||||
start,
|
||||
end, Color.Yellow * 0.5f,
|
||||
width: 4);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawLine(Vector2 vertexPos0, Vector2 vertexPos1, Color color, int width)
|
||||
{
|
||||
if (ParentEntity != null && ParentEntity.Submarine != null)
|
||||
{
|
||||
vertexPos0 += ParentEntity.Submarine.DrawPosition;
|
||||
vertexPos1 += ParentEntity.Submarine.DrawPosition;
|
||||
}
|
||||
float alpha = 1.0f;
|
||||
if (LightManager.ViewTarget != null)
|
||||
{
|
||||
alpha = IsSegmentFacing(vertexPos0, vertexPos1, LightManager.ViewTarget.WorldPosition) ? 1.0f : 0.5f;
|
||||
}
|
||||
vertexPos0.Y = -vertexPos0.Y;
|
||||
vertexPos1.Y = -vertexPos1.Y;
|
||||
GUI.DrawLine(spriteBatch, vertexPos0, vertexPos1, color * alpha, width: width);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -889,16 +754,13 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
HullLists.Remove(chList);
|
||||
}
|
||||
foreach (ConvexHull ch2 in overlappingHulls)
|
||||
//create a new list because MergeLosVertices can edit overlappingHulls
|
||||
foreach (ConvexHull ch2 in overlappingHulls.ToList())
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
ch2.ignoreEdge[i] = false;
|
||||
}
|
||||
ch2.overlappingHulls.Remove(this);
|
||||
foreach (ConvexHull ch in chList.List)
|
||||
{
|
||||
ch.MergeOverlappingSegments(ch2);
|
||||
ch.MergeLosVertices(ch2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Extensions;
|
||||
using System.Threading;
|
||||
|
||||
namespace Barotrauma.Lights
|
||||
{
|
||||
@@ -22,6 +23,9 @@ namespace Barotrauma.Lights
|
||||
/// </summary>
|
||||
const float ObstructLightsBehindCharactersZoomThreshold = 0.5f;
|
||||
|
||||
private Thread rayCastThread;
|
||||
private Queue<RayCastTask> pendingRayCasts = new Queue<RayCastTask>();
|
||||
|
||||
public static Entity ViewTarget { get; set; }
|
||||
|
||||
private float currLightMapScale;
|
||||
@@ -58,6 +62,8 @@ namespace Barotrauma.Lights
|
||||
|
||||
private readonly List<LightSource> lights;
|
||||
|
||||
public bool DebugLos;
|
||||
|
||||
public bool LosEnabled = true;
|
||||
public float LosAlpha = 1f;
|
||||
public LosMode LosMode = LosMode.Transparent;
|
||||
@@ -68,6 +74,8 @@ namespace Barotrauma.Lights
|
||||
|
||||
private readonly Texture2D visionCircle;
|
||||
|
||||
private readonly Texture2D gapGlowTexture;
|
||||
|
||||
private Vector2 losOffset;
|
||||
|
||||
private int recalculationCount;
|
||||
@@ -85,8 +93,16 @@ namespace Barotrauma.Lights
|
||||
|
||||
AmbientLight = new Color(20, 20, 20, 255);
|
||||
|
||||
rayCastThread = new Thread(UpdateRayCasts)
|
||||
{
|
||||
Name = "LightManager Raycast thread",
|
||||
IsBackground = true //this should kill the thread if the game crashes
|
||||
};
|
||||
rayCastThread.Start();
|
||||
|
||||
visionCircle = Sprite.LoadTexture("Content/Lights/visioncircle.png");
|
||||
highlightRaster = Sprite.LoadTexture("Content/UI/HighlightRaster.png");
|
||||
gapGlowTexture = Sprite.LoadTexture("Content/Lights/pointlight_rays.png");
|
||||
|
||||
GameMain.Instance.ResolutionChanged += () =>
|
||||
{
|
||||
@@ -100,15 +116,12 @@ namespace Barotrauma.Lights
|
||||
LosEffect = EffectLoader.Load("Effects/losshader");
|
||||
SolidColorEffect = EffectLoader.Load("Effects/solidcolor");
|
||||
|
||||
if (lightEffect == null)
|
||||
{
|
||||
lightEffect = new BasicEffect(GameMain.Instance.GraphicsDevice)
|
||||
lightEffect ??= new BasicEffect(GameMain.Instance.GraphicsDevice)
|
||||
{
|
||||
VertexColorEnabled = true,
|
||||
TextureEnabled = true,
|
||||
Texture = LightSource.LightTexture
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -176,6 +189,51 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class RayCastTask
|
||||
{
|
||||
public LightSource LightSource;
|
||||
public Vector2 DrawPos;
|
||||
public float Rotation;
|
||||
|
||||
public RayCastTask(LightSource lightSource, Vector2 drawPos, float rotation)
|
||||
{
|
||||
LightSource = lightSource;
|
||||
DrawPos = drawPos;
|
||||
Rotation = rotation;
|
||||
}
|
||||
|
||||
public void Calculate()
|
||||
{
|
||||
LightSource.RayCastTask(DrawPos, Rotation);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly object mutex = new object();
|
||||
|
||||
public void AddRayCastTask(LightSource lightSource, Vector2 drawPos, float rotation)
|
||||
{
|
||||
lock (mutex)
|
||||
{
|
||||
if (pendingRayCasts.Any(p => p.LightSource == lightSource)) { return; }
|
||||
pendingRayCasts.Enqueue(new RayCastTask(lightSource, drawPos, rotation));
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateRayCasts()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
lock (mutex)
|
||||
{
|
||||
while (pendingRayCasts.Count > 0)
|
||||
{
|
||||
pendingRayCasts.Dequeue().Calculate();
|
||||
}
|
||||
}
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, RenderTarget2D backgroundObstructor = null)
|
||||
{
|
||||
if (!LightingEnabled) { return; }
|
||||
@@ -288,8 +346,8 @@ namespace Barotrauma.Lights
|
||||
foreach (LightSource light in activeLights)
|
||||
{
|
||||
if (!light.IsBackground || light.CurrentBrightness <= 0.0f) { continue; }
|
||||
light.DrawSprite(spriteBatch, cam);
|
||||
light.DrawLightVolume(spriteBatch, lightEffect, transform, recalculationCount < MaxLightVolumeRecalculationsPerFrame, ref recalculationCount);
|
||||
light.DrawSprite(spriteBatch, cam);
|
||||
}
|
||||
GameMain.ParticleManager.Draw(spriteBatch, true, null, Particles.ParticleBlendState.Additive);
|
||||
spriteBatch.End();
|
||||
@@ -308,15 +366,46 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
spriteBatch.End();
|
||||
|
||||
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColor"];
|
||||
SolidColorEffect.Parameters["color"].SetValue(AmbientLight.Opaque().ToVector4());
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform, effect: SolidColorEffect);
|
||||
Submarine.DrawDamageable(spriteBatch, null);
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
|
||||
Vector3 glowColorHSV = ToolBox.RGBToHSV(AmbientLight);
|
||||
glowColorHSV.Z = Math.Max(glowColorHSV.Z, 0.4f);
|
||||
Color glowColor = ToolBox.HSVToRGB(glowColorHSV.X, glowColorHSV.Y, glowColorHSV.Z);
|
||||
Vector2 glowSpriteSize = new Vector2(gapGlowTexture.Width, gapGlowTexture.Height);
|
||||
foreach (var gap in Gap.GapList)
|
||||
{
|
||||
if (gap.IsRoomToRoom || gap.Open <= 0.0f || gap.ConnectedWall == null) { continue; }
|
||||
|
||||
float a = MathHelper.Lerp(0.5f, 1.0f,
|
||||
PerlinNoise.GetPerlin((float)Timing.TotalTime * 0.05f, gap.GlowEffectT));
|
||||
|
||||
float scale = MathHelper.Lerp(0.5f, 2.0f,
|
||||
PerlinNoise.GetPerlin((float)Timing.TotalTime * 0.01f, gap.GlowEffectT));
|
||||
|
||||
float rot = PerlinNoise.GetPerlin((float)Timing.TotalTime * 0.001f, gap.GlowEffectT) * MathHelper.TwoPi;
|
||||
|
||||
Vector2 spriteScale = new Vector2(gap.Rect.Width, gap.Rect.Height) / glowSpriteSize;
|
||||
Vector2 drawPos = new Vector2(gap.DrawPosition.X, -gap.DrawPosition.Y);
|
||||
|
||||
spriteBatch.Draw(gapGlowTexture,
|
||||
drawPos,
|
||||
null,
|
||||
glowColor * a,
|
||||
rot,
|
||||
glowSpriteSize / 2,
|
||||
scale: Math.Max(spriteScale.X, spriteScale.Y) * scale,
|
||||
SpriteEffects.None,
|
||||
layerDepth: 0);
|
||||
}
|
||||
spriteBatch.End();
|
||||
|
||||
GameMain.GameScreen.DamageEffect.CurrentTechnique = GameMain.GameScreen.DamageEffect.Techniques["StencilShaderSolidColor"];
|
||||
GameMain.GameScreen.DamageEffect.Parameters["solidColor"].SetValue(Color.Black.ToVector4());
|
||||
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, SamplerState.LinearWrap, transformMatrix: spriteBatchTransform, effect: GameMain.GameScreen.DamageEffect);
|
||||
Submarine.DrawDamageable(spriteBatch, GameMain.GameScreen.DamageEffect);
|
||||
spriteBatch.End();
|
||||
|
||||
graphics.BlendState = BlendState.Additive;
|
||||
|
||||
|
||||
//draw the focused item and character to highlight them,
|
||||
//and light sprites (done before drawing the actual light volumes so we can make characters obstruct the highlights and sprites)
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
@@ -389,6 +478,17 @@ namespace Barotrauma.Lights
|
||||
light.DrawLightVolume(spriteBatch, lightEffect, transform, recalculationCount < MaxLightVolumeRecalculationsPerFrame, ref recalculationCount);
|
||||
}
|
||||
|
||||
if (ConnectionPanel.ShouldDebugDrawWiring)
|
||||
{
|
||||
foreach (MapEntity e in (Submarine.VisibleEntities ?? MapEntity.mapEntityList))
|
||||
{
|
||||
if (e is Item item && item.GetComponent<Wire>() is Wire wire)
|
||||
{
|
||||
wire.DebugDraw(spriteBatch, alpha: 0.4f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lightEffect.World = transform;
|
||||
|
||||
GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.Additive);
|
||||
@@ -566,7 +666,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
public void UpdateObstructVision(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, Vector2 lookAtPosition)
|
||||
{
|
||||
if ((!LosEnabled || LosMode == LosMode.None) && !ObstructVision) return;
|
||||
if ((!LosEnabled || LosMode == LosMode.None) && !ObstructVision) { return; }
|
||||
if (ViewTarget == null) return;
|
||||
|
||||
graphics.SetRenderTarget(LosTexture);
|
||||
@@ -598,23 +698,52 @@ namespace Barotrauma.Lights
|
||||
if (LosEnabled && LosMode != LosMode.None && ViewTarget != null)
|
||||
{
|
||||
Vector2 pos = ViewTarget.DrawPosition;
|
||||
bool centeredOnHead = false;
|
||||
if (ViewTarget is Character character &&
|
||||
character.AnimController?.GetLimb(LimbType.Head) is Limb head &&
|
||||
!head.IsSevered && !head.Removed)
|
||||
{
|
||||
pos = head.body.DrawPosition;
|
||||
centeredOnHead = true;
|
||||
}
|
||||
|
||||
Rectangle camView = new Rectangle(cam.WorldView.X, cam.WorldView.Y - cam.WorldView.Height, cam.WorldView.Width, cam.WorldView.Height);
|
||||
|
||||
Matrix shadowTransform = cam.ShaderTransform
|
||||
* Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f;
|
||||
|
||||
var convexHulls = ConvexHull.GetHullsInRange(ViewTarget.Position, cam.WorldView.Width*0.75f, ViewTarget.Submarine);
|
||||
var convexHulls = ConvexHull.GetHullsInRange(ViewTarget.Position, cam.WorldView.Width * 0.75f, ViewTarget.Submarine);
|
||||
|
||||
//make sure the head isn't peeking through any LOS segments, and if it is,
|
||||
//center the LOS on the character's collider instead
|
||||
if (centeredOnHead)
|
||||
{
|
||||
foreach (var ch in convexHulls)
|
||||
{
|
||||
Vector2 currentViewPos = pos;
|
||||
Vector2 defaultViewPos = ViewTarget.DrawPosition;
|
||||
if (ch.ParentEntity?.Submarine != null)
|
||||
{
|
||||
defaultViewPos -= ch.ParentEntity.Submarine.DrawPosition;
|
||||
currentViewPos -= ch.ParentEntity.Submarine.DrawPosition;
|
||||
}
|
||||
//check if a line from the character's collider to the head intersects with the los segment (= head poking through it)
|
||||
if (ch.LosIntersects(defaultViewPos, currentViewPos))
|
||||
{
|
||||
pos = ViewTarget.DrawPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (convexHulls != null)
|
||||
{
|
||||
List<VertexPositionColor> shadowVerts = new List<VertexPositionColor>();
|
||||
List<VertexPositionTexture> penumbraVerts = new List<VertexPositionTexture>();
|
||||
foreach (ConvexHull convexHull in convexHulls)
|
||||
{
|
||||
if (!convexHull.Enabled || !convexHull.Intersects(camView)) continue;
|
||||
if (!convexHull.Enabled || !convexHull.Intersects(camView)) { continue; }
|
||||
|
||||
Vector2 relativeLightPos = pos;
|
||||
if (convexHull.ParentEntity?.Submarine != null) relativeLightPos -= convexHull.ParentEntity.Submarine.Position;
|
||||
if (convexHull.ParentEntity?.Submarine != null) { relativeLightPos -= convexHull.ParentEntity.Submarine.Position; }
|
||||
|
||||
convexHull.CalculateLosVertices(relativeLightPos);
|
||||
|
||||
@@ -647,6 +776,21 @@ namespace Barotrauma.Lights
|
||||
graphics.SetRenderTarget(null);
|
||||
}
|
||||
|
||||
public void DebugDrawLos(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
Vector2 pos = ViewTarget?.Position ?? cam.Position;
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cam.Transform);
|
||||
var convexHulls = ConvexHull.GetHullsInRange(pos, cam.WorldView.Width * 0.75f, ViewTarget?.Submarine);
|
||||
Rectangle camView = new Rectangle(cam.WorldView.X, cam.WorldView.Y - cam.WorldView.Height, cam.WorldView.Width, cam.WorldView.Height);
|
||||
foreach (ConvexHull convexHull in convexHulls)
|
||||
{
|
||||
if (!convexHull.Enabled || !convexHull.Intersects(camView)) { continue; }
|
||||
if (convexHull.ParentEntity is Structure { CastShadow: false }) { continue; }
|
||||
convexHull.DebugDraw(spriteBatch);
|
||||
}
|
||||
spriteBatch.End();
|
||||
}
|
||||
|
||||
public void ClearLights()
|
||||
{
|
||||
lights.Clear();
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
public bool Persistent;
|
||||
|
||||
|
||||
public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; private set; } = new Dictionary<Identifier, SerializableProperty>();
|
||||
|
||||
[Serialize("1.0,1.0,1.0,1.0", IsPropertySaveable.Yes, alwaysUseInstanceValues: true), Editable]
|
||||
@@ -228,6 +229,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
//do we need to recalculate the vertices of the light volume
|
||||
private bool needsRecalculation;
|
||||
private bool needsRecalculationWhenUpToDate;
|
||||
public bool NeedsRecalculation
|
||||
{
|
||||
get { return needsRecalculation; }
|
||||
@@ -241,12 +243,30 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
needsRecalculation = value;
|
||||
if (needsRecalculation && state != LightVertexState.UpToDate)
|
||||
{
|
||||
//if we're currently recalculating light vertices, mark that we need to recalculate them again after it's done
|
||||
needsRecalculationWhenUpToDate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//when were the vertices of the light volume last calculated
|
||||
public float LastRecalculationTime { get; private set; }
|
||||
|
||||
|
||||
private enum LightVertexState
|
||||
{
|
||||
UpToDate,
|
||||
PendingRayCasts,
|
||||
PendingVertexRecalculation,
|
||||
}
|
||||
|
||||
private LightVertexState state;
|
||||
|
||||
private Vector2 calculatedDrawPos;
|
||||
|
||||
private readonly Dictionary<Submarine, Vector2> diffToSub;
|
||||
|
||||
private DynamicVertexBuffer lightVolumeBuffer;
|
||||
@@ -255,7 +275,6 @@ namespace Barotrauma.Lights
|
||||
private int indexCount;
|
||||
|
||||
private Vector2 translateVertices;
|
||||
private float rotateVertices;
|
||||
|
||||
private readonly LightSourceParams lightSourceParams;
|
||||
|
||||
@@ -295,7 +314,6 @@ namespace Barotrauma.Lights
|
||||
|
||||
if (Math.Abs(rotation - prevCalculatedRotation) < RotationRecalculationThreshold && vertices != null)
|
||||
{
|
||||
rotateVertices = rotation - prevCalculatedRotation;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -647,13 +665,19 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly List<Segment> visibleSegments = new List<Segment>();
|
||||
private static readonly List<SegmentPoint> points = new List<SegmentPoint>();
|
||||
private static readonly List<Vector2> output = new List<Vector2>();
|
||||
private static readonly SegmentPoint[] boundaryCorners = new SegmentPoint[4];
|
||||
private List<Vector2> FindRaycastHits()
|
||||
private static readonly object mutex = new object();
|
||||
|
||||
private readonly List<Segment> visibleSegments = new List<Segment>();
|
||||
private readonly List<SegmentPoint> points = new List<SegmentPoint>();
|
||||
private readonly List<Vector2> verts = new List<Vector2>();
|
||||
private readonly SegmentPoint[] boundaryCorners = new SegmentPoint[4];
|
||||
private void FindRaycastHits()
|
||||
{
|
||||
if (!CastShadows || Range < 1.0f || Color.A < 1) { return null; }
|
||||
if (!CastShadows || Range < 1.0f || Color.A < 1)
|
||||
{
|
||||
state = LightVertexState.PendingVertexRecalculation;
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null) { drawPos += ParentSub.DrawPosition; }
|
||||
@@ -666,8 +690,18 @@ namespace Barotrauma.Lights
|
||||
if (!chList.IsHidden.Contains(hull))
|
||||
{
|
||||
//find convexhull segments that are close enough and facing towards the light source
|
||||
hull.RefreshWorldPositions();
|
||||
hull.GetVisibleSegments(drawPos, visibleSegments, ignoreEdges: false);
|
||||
lock (mutex)
|
||||
{
|
||||
hull.RefreshWorldPositions();
|
||||
hull.GetVisibleSegments(drawPos, visibleSegments);
|
||||
foreach (var visibleSegment in visibleSegments)
|
||||
{
|
||||
if (visibleSegment.ConvexHull?.ParentEntity?.Submarine != null)
|
||||
{
|
||||
visibleSegment.SubmarineDrawPos = visibleSegment.ConvexHull.ParentEntity.Submarine.DrawPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (ConvexHull hull in chList.List)
|
||||
@@ -676,17 +710,19 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
//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
|
||||
state = LightVertexState.PendingRayCasts;
|
||||
GameMain.LightManager.AddRayCastTask(this, drawPos, rotation);
|
||||
}
|
||||
|
||||
//(might be more effective to calculate if we actually need these extra points)
|
||||
|
||||
public void RayCastTask(Vector2 drawPos, float rotation)
|
||||
{
|
||||
Vector2 drawOffset = Vector2.Zero;
|
||||
float boundsExtended = TextureRange;
|
||||
if (OverrideLightTexture != null)
|
||||
{
|
||||
float cosAngle = (float)Math.Cos(Rotation);
|
||||
float sinAngle = -(float)Math.Sin(Rotation);
|
||||
float cosAngle = (float)Math.Cos(rotation);
|
||||
float sinAngle = -(float)Math.Sin(rotation);
|
||||
|
||||
var overrideTextureDims = new Vector2(OverrideLightTexture.SourceRect.Width, OverrideLightTexture.SourceRect.Height);
|
||||
|
||||
@@ -706,6 +742,10 @@ namespace Barotrauma.Lights
|
||||
drawOffset.Y = origin.X * sinAngle + origin.Y * cosAngle;
|
||||
}
|
||||
|
||||
//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)
|
||||
Vector2 boundsMin = drawPos + drawOffset + new Vector2(-boundsExtended, -boundsExtended);
|
||||
Vector2 boundsMax = drawPos + drawOffset + new Vector2(boundsExtended, boundsExtended);
|
||||
boundaryCorners[0] = new SegmentPoint(boundsMax, null);
|
||||
@@ -719,197 +759,197 @@ namespace Barotrauma.Lights
|
||||
visibleSegments.Add(s);
|
||||
}
|
||||
|
||||
//Generate new points at the intersections between segments
|
||||
//This is necessary for the light volume to generate properly on some subs
|
||||
for (int i = 0; i < visibleSegments.Count; i++)
|
||||
lock (mutex)
|
||||
{
|
||||
Vector2 p1a = visibleSegments[i].Start.WorldPos;
|
||||
Vector2 p1b = visibleSegments[i].End.WorldPos;
|
||||
|
||||
for (int j = i + 1; j < visibleSegments.Count; j++)
|
||||
//Generate new points at the intersections between segments
|
||||
//This is necessary for the light volume to generate properly on some subs
|
||||
for (int i = 0; i < visibleSegments.Count; i++)
|
||||
{
|
||||
//ignore intersections between parallel axis-aligned segments
|
||||
if (visibleSegments[i].IsAxisAligned && visibleSegments[j].IsAxisAligned &&
|
||||
visibleSegments[i].IsHorizontal == visibleSegments[j].IsHorizontal)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Vector2 p1a = visibleSegments[i].Start.WorldPos;
|
||||
Vector2 p1b = visibleSegments[i].End.WorldPos;
|
||||
|
||||
Vector2 p2a = visibleSegments[j].Start.WorldPos;
|
||||
Vector2 p2b = visibleSegments[j].End.WorldPos;
|
||||
|
||||
if (Vector2.DistanceSquared(p1a, p2a) < 5.0f ||
|
||||
Vector2.DistanceSquared(p1a, p2b) < 5.0f ||
|
||||
Vector2.DistanceSquared(p1b, p2a) < 5.0f ||
|
||||
Vector2.DistanceSquared(p1b, p2b) < 5.0f)
|
||||
for (int j = i + 1; j < visibleSegments.Count; j++)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool intersects;
|
||||
Vector2 intersection = Vector2.Zero;
|
||||
if (visibleSegments[i].IsAxisAligned)
|
||||
{
|
||||
intersects = MathUtils.GetAxisAlignedLineIntersection(p2a, p2b, p1a, p1b, visibleSegments[i].IsHorizontal, out intersection);
|
||||
}
|
||||
else if (visibleSegments[j].IsAxisAligned)
|
||||
{
|
||||
intersects = MathUtils.GetAxisAlignedLineIntersection(p1a, p1b, p2a, p2b, visibleSegments[j].IsHorizontal, out intersection);
|
||||
}
|
||||
else
|
||||
{
|
||||
intersects = MathUtils.GetLineIntersection(p1a, p1b, p2a, p2b, out intersection);
|
||||
}
|
||||
|
||||
if (intersects)
|
||||
{
|
||||
SegmentPoint start = visibleSegments[i].Start;
|
||||
SegmentPoint end = visibleSegments[i].End;
|
||||
SegmentPoint mid = new SegmentPoint(intersection, null);
|
||||
if (visibleSegments[i].ConvexHull?.ParentEntity?.Submarine != null)
|
||||
{
|
||||
mid.Pos -= visibleSegments[i].ConvexHull.ParentEntity.Submarine.DrawPosition;
|
||||
}
|
||||
|
||||
if (Vector2.DistanceSquared(start.WorldPos, mid.WorldPos) < 5.0f ||
|
||||
Vector2.DistanceSquared(end.WorldPos, mid.WorldPos) < 5.0f)
|
||||
//ignore intersections between parallel axis-aligned segments
|
||||
if (visibleSegments[i].IsAxisAligned && visibleSegments[j].IsAxisAligned &&
|
||||
visibleSegments[i].IsHorizontal == visibleSegments[j].IsHorizontal)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Segment seg1 = new Segment(start, mid, visibleSegments[i].ConvexHull)
|
||||
{
|
||||
IsHorizontal = visibleSegments[i].IsHorizontal,
|
||||
};
|
||||
Vector2 p2a = visibleSegments[j].Start.WorldPos;
|
||||
Vector2 p2b = visibleSegments[j].End.WorldPos;
|
||||
|
||||
Segment seg2 = new Segment(mid, end, visibleSegments[i].ConvexHull)
|
||||
if (Vector2.DistanceSquared(p1a, p2a) < 5.0f ||
|
||||
Vector2.DistanceSquared(p1a, p2b) < 5.0f ||
|
||||
Vector2.DistanceSquared(p1b, p2a) < 5.0f ||
|
||||
Vector2.DistanceSquared(p1b, p2b) < 5.0f)
|
||||
{
|
||||
IsHorizontal = visibleSegments[i].IsHorizontal
|
||||
};
|
||||
continue;
|
||||
}
|
||||
|
||||
visibleSegments[i] = seg1;
|
||||
visibleSegments.Insert(i + 1, seg2);
|
||||
bool intersects;
|
||||
Vector2 intersection = Vector2.Zero;
|
||||
if (visibleSegments[i].IsAxisAligned)
|
||||
{
|
||||
intersects = MathUtils.GetAxisAlignedLineIntersection(p2a, p2b, p1a, p1b, visibleSegments[i].IsHorizontal, out intersection);
|
||||
}
|
||||
else if (visibleSegments[j].IsAxisAligned)
|
||||
{
|
||||
intersects = MathUtils.GetAxisAlignedLineIntersection(p1a, p1b, p2a, p2b, visibleSegments[j].IsHorizontal, out intersection);
|
||||
}
|
||||
else
|
||||
{
|
||||
intersects = MathUtils.GetLineSegmentIntersection(p1a, p1b, p2a, p2b, out intersection);
|
||||
}
|
||||
|
||||
if (intersects)
|
||||
{
|
||||
SegmentPoint start = visibleSegments[i].Start;
|
||||
SegmentPoint end = visibleSegments[i].End;
|
||||
SegmentPoint mid = new SegmentPoint(intersection, null);
|
||||
mid.Pos -= visibleSegments[i].SubmarineDrawPos;
|
||||
|
||||
if (Vector2.DistanceSquared(start.WorldPos, mid.WorldPos) < 5.0f ||
|
||||
Vector2.DistanceSquared(end.WorldPos, mid.WorldPos) < 5.0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Segment seg1 = new Segment(start, mid, visibleSegments[i].ConvexHull)
|
||||
{
|
||||
IsHorizontal = visibleSegments[i].IsHorizontal,
|
||||
};
|
||||
|
||||
Segment seg2 = new Segment(mid, end, visibleSegments[i].ConvexHull)
|
||||
{
|
||||
IsHorizontal = visibleSegments[i].IsHorizontal
|
||||
};
|
||||
|
||||
visibleSegments[i] = seg1;
|
||||
visibleSegments.Insert(i + 1, seg2);
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
points.Clear();
|
||||
//remove segments that fall out of bounds
|
||||
for (int i = 0; i < visibleSegments.Count; i++)
|
||||
{
|
||||
Segment s = visibleSegments[i];
|
||||
if (Math.Abs(s.Start.WorldPos.X - drawPos.X - drawOffset.X) > boundsExtended + 1.0f ||
|
||||
Math.Abs(s.Start.WorldPos.Y - drawPos.Y - drawOffset.Y) > boundsExtended + 1.0f ||
|
||||
Math.Abs(s.End.WorldPos.X - drawPos.X - drawOffset.X) > boundsExtended + 1.0f ||
|
||||
Math.Abs(s.End.WorldPos.Y - drawPos.Y - drawOffset.Y) > boundsExtended + 1.0f)
|
||||
{
|
||||
visibleSegments.RemoveAt(i);
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
points.Add(s.Start);
|
||||
points.Add(s.End);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
points.Clear();
|
||||
//remove segments that fall out of bounds
|
||||
for (int i = 0; i < visibleSegments.Count; i++)
|
||||
{
|
||||
Segment s = visibleSegments[i];
|
||||
if (Math.Abs(s.Start.WorldPos.X - drawPos.X - drawOffset.X) > boundsExtended + 1.0f ||
|
||||
Math.Abs(s.Start.WorldPos.Y - drawPos.Y - drawOffset.Y) > boundsExtended + 1.0f ||
|
||||
Math.Abs(s.End.WorldPos.X - drawPos.X - drawOffset.X) > boundsExtended + 1.0f ||
|
||||
Math.Abs(s.End.WorldPos.Y - drawPos.Y - drawOffset.Y) > boundsExtended + 1.0f)
|
||||
//remove points that are very close to each other
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
{
|
||||
visibleSegments.RemoveAt(i);
|
||||
i--;
|
||||
for (int j = Math.Min(i + 4, points.Count - 1); j > i; j--)
|
||||
{
|
||||
if (Math.Abs(points[i].WorldPos.X - points[j].WorldPos.X) < 6 &&
|
||||
Math.Abs(points[i].WorldPos.Y - points[j].WorldPos.Y) < 6)
|
||||
{
|
||||
points.RemoveAt(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
var compareCCW = new CompareSegmentPointCW(drawPos);
|
||||
try
|
||||
{
|
||||
points.Add(s.Start);
|
||||
points.Add(s.End);
|
||||
points.Sort(compareCCW);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("Constructing light volumes failed! Light pos: " + drawPos + ", Hull verts:\n");
|
||||
foreach (SegmentPoint sp in points)
|
||||
{
|
||||
sb.AppendLine(sp.Pos.ToString());
|
||||
}
|
||||
DebugConsole.ThrowError(sb.ToString(), e);
|
||||
}
|
||||
|
||||
visibleSegments.Sort((s1, s2) =>
|
||||
MathUtils.LineToPointDistanceSquared(s1.Start.WorldPos, s1.End.WorldPos, drawPos)
|
||||
.CompareTo(MathUtils.LineToPointDistanceSquared(s2.Start.WorldPos, s2.End.WorldPos, drawPos)));
|
||||
|
||||
verts.Clear();
|
||||
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
|
||||
var intersection1 = RayCast(drawPos, drawPos + dir * boundsExtended * 2 - dirNormal, visibleSegments);
|
||||
if (intersection1.index < 0) { return; }
|
||||
var intersection2 = RayCast(drawPos, drawPos + dir * boundsExtended * 2 + dirNormal, visibleSegments);
|
||||
if (intersection2.index < 0) { return; }
|
||||
|
||||
Segment seg1 = visibleSegments[intersection1.index];
|
||||
Segment seg2 = visibleSegments[intersection2.index];
|
||||
|
||||
bool isPoint1 = MathUtils.LineToPointDistanceSquared(seg1.Start.WorldPos, seg1.End.WorldPos, p.WorldPos) < 25.0f;
|
||||
bool isPoint2 = MathUtils.LineToPointDistanceSquared(seg2.Start.WorldPos, seg2.End.WorldPos, p.WorldPos) < 25.0f;
|
||||
|
||||
if (isPoint1 && isPoint2)
|
||||
{
|
||||
//hit at the current segmentpoint -> place the segmentpoint into the list
|
||||
verts.Add(p.WorldPos);
|
||||
|
||||
foreach (ConvexHullList hullList in convexHullsInRange)
|
||||
{
|
||||
hullList.IsHidden.Remove(p.ConvexHull);
|
||||
hullList.IsHidden.Remove(seg1.ConvexHull);
|
||||
hullList.IsHidden.Remove(seg2.ConvexHull);
|
||||
}
|
||||
}
|
||||
else if (intersection1.index != intersection2.index)
|
||||
{
|
||||
//the raycasts landed on different segments
|
||||
//we definitely want to generate new geometry here
|
||||
verts.Add(isPoint1 ? p.WorldPos : intersection1.pos);
|
||||
verts.Add(isPoint2 ? p.WorldPos : intersection2.pos);
|
||||
|
||||
foreach (ConvexHullList hullList in convexHullsInRange)
|
||||
{
|
||||
hullList.IsHidden.Remove(p.ConvexHull);
|
||||
hullList.IsHidden.Remove(seg1.ConvexHull);
|
||||
hullList.IsHidden.Remove(seg2.ConvexHull);
|
||||
}
|
||||
}
|
||||
//if neither of the conditions above are met, we just assume
|
||||
//that the raycasts both resulted on the same segment
|
||||
//and creating geometry here would be wasteful
|
||||
}
|
||||
}
|
||||
|
||||
//remove points that are very close to each other
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
for (int i = 0; i < verts.Count - 1; i++)
|
||||
{
|
||||
for (int j = Math.Min(i + 4, points.Count-1); j > i; j--)
|
||||
for (int j = Math.Min(i + 4, verts.Count - 1); j > i; j--)
|
||||
{
|
||||
if (Math.Abs(points[i].WorldPos.X - points[j].WorldPos.X) < 6 &&
|
||||
Math.Abs(points[i].WorldPos.Y - points[j].WorldPos.Y) < 6)
|
||||
if (Math.Abs(verts[i].X - verts[j].X) < 6 &&
|
||||
Math.Abs(verts[i].Y - verts[j].Y) < 6)
|
||||
{
|
||||
points.RemoveAt(j);
|
||||
verts.RemoveAt(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var compareCCW = new CompareSegmentPointCW(drawPos);
|
||||
try
|
||||
{
|
||||
points.Sort(compareCCW);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("Constructing light volumes failed! Light pos: " + drawPos + ", Hull verts:\n");
|
||||
foreach (SegmentPoint sp in points)
|
||||
{
|
||||
sb.AppendLine(sp.Pos.ToString());
|
||||
}
|
||||
DebugConsole.ThrowError(sb.ToString(), e);
|
||||
}
|
||||
|
||||
visibleSegments.Sort((s1, s2) =>
|
||||
MathUtils.LineToPointDistanceSquared(s1.Start.WorldPos, s1.End.WorldPos, drawPos)
|
||||
.CompareTo(MathUtils.LineToPointDistanceSquared(s2.Start.WorldPos, s2.End.WorldPos, drawPos)));
|
||||
|
||||
output.Clear();
|
||||
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
|
||||
var intersection1 = RayCast(drawPos, drawPos + dir * boundsExtended * 2 - dirNormal, visibleSegments);
|
||||
if (intersection1.index < 0) { return null; }
|
||||
var intersection2 = RayCast(drawPos, drawPos + dir * boundsExtended * 2 + dirNormal, visibleSegments);
|
||||
if (intersection2.index < 0) { return null; }
|
||||
|
||||
Segment seg1 = visibleSegments[intersection1.index];
|
||||
Segment seg2 = visibleSegments[intersection2.index];
|
||||
|
||||
bool isPoint1 = MathUtils.LineToPointDistanceSquared(seg1.Start.WorldPos, seg1.End.WorldPos, p.WorldPos) < 25.0f;
|
||||
bool isPoint2 = MathUtils.LineToPointDistanceSquared(seg2.Start.WorldPos, seg2.End.WorldPos, p.WorldPos) < 25.0f;
|
||||
|
||||
if (isPoint1 && isPoint2)
|
||||
{
|
||||
//hit at the current segmentpoint -> place the segmentpoint into the list
|
||||
output.Add(p.WorldPos);
|
||||
|
||||
foreach (ConvexHullList hullList in convexHullsInRange)
|
||||
{
|
||||
hullList.IsHidden.Remove(p.ConvexHull);
|
||||
hullList.IsHidden.Remove(seg1.ConvexHull);
|
||||
hullList.IsHidden.Remove(seg2.ConvexHull);
|
||||
}
|
||||
}
|
||||
else if (intersection1.index != intersection2.index)
|
||||
{
|
||||
//the raycasts landed on different segments
|
||||
//we definitely want to generate new geometry here
|
||||
output.Add(isPoint1 ? p.WorldPos : intersection1.pos);
|
||||
output.Add(isPoint2 ? p.WorldPos : intersection2.pos);
|
||||
|
||||
foreach (ConvexHullList hullList in convexHullsInRange)
|
||||
{
|
||||
hullList.IsHidden.Remove(p.ConvexHull);
|
||||
hullList.IsHidden.Remove(seg1.ConvexHull);
|
||||
hullList.IsHidden.Remove(seg2.ConvexHull);
|
||||
}
|
||||
}
|
||||
//if neither of the conditions above are met, we just assume
|
||||
//that the raycasts both resulted on the same segment
|
||||
//and creating geometry here would be wasteful
|
||||
}
|
||||
|
||||
//remove points that are very close to each other
|
||||
for (int i = 0; i < output.Count - 1; i++)
|
||||
{
|
||||
for (int j = Math.Min(i + 4, output.Count - 1); j > i; j--)
|
||||
{
|
||||
if (Math.Abs(output[i].X - output[j].X) < 6 &&
|
||||
Math.Abs(output[i].Y - output[j].Y) < 6)
|
||||
{
|
||||
output.RemoveAt(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
calculatedDrawPos = drawPos;
|
||||
state = LightVertexState.PendingVertexRecalculation;
|
||||
}
|
||||
|
||||
private static (int index, Vector2 pos) RayCast(Vector2 rayStart, Vector2 rayEnd, List<Segment> segments)
|
||||
@@ -954,7 +994,7 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
else
|
||||
{
|
||||
intersects = MathUtils.GetLineIntersection(rayStart, rayEnd, s.Start.WorldPos, s.End.WorldPos, out intersection);
|
||||
intersects = MathUtils.GetLineSegmentIntersection(rayStart, rayEnd, s.Start.WorldPos, s.End.WorldPos, out intersection);
|
||||
}
|
||||
|
||||
if (intersects)
|
||||
@@ -987,8 +1027,7 @@ namespace Barotrauma.Lights
|
||||
indices = new short[indexCount];
|
||||
}
|
||||
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null) { drawPos += ParentSub.DrawPosition; }
|
||||
Vector2 drawPos = calculatedDrawPos;
|
||||
|
||||
float cosAngle = (float)Math.Cos(Rotation);
|
||||
float sinAngle = -(float)Math.Sin(Rotation);
|
||||
@@ -1042,7 +1081,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
//calculate normal of first segment
|
||||
Vector2 nDiff1 = vertex - nextVertex;
|
||||
float tx = nDiff1.X; nDiff1.X = -nDiff1.Y; nDiff1.Y = tx;
|
||||
nDiff1 = new Vector2(-nDiff1.Y, nDiff1.X);
|
||||
nDiff1 /= Math.Max(Math.Abs(nDiff1.X), Math.Abs(nDiff1.Y));
|
||||
//if the normal is pointing towards the light origin
|
||||
//rather than away from it, invert it
|
||||
@@ -1050,21 +1089,23 @@ namespace Barotrauma.Lights
|
||||
|
||||
//calculate normal of second segment
|
||||
Vector2 nDiff2 = prevVertex - vertex;
|
||||
tx = nDiff2.X; nDiff2.X = -nDiff2.Y; nDiff2.Y = tx;
|
||||
nDiff2 /= Math.Max(Math.Abs(nDiff2.X),Math.Abs(nDiff2.Y));
|
||||
nDiff2 = new Vector2(-nDiff2.Y, nDiff2.X);
|
||||
nDiff2 /= Math.Max(Math.Abs(nDiff2.X), Math.Abs(nDiff2.Y));
|
||||
//if the normal is pointing towards the light origin
|
||||
//rather than away from it, invert it
|
||||
if (Vector2.DistanceSquared(nDiff2, rawDiff) > Vector2.DistanceSquared(-nDiff2, rawDiff)) nDiff2 = -nDiff2;
|
||||
|
||||
//add the normals together and use some magic numbers to create
|
||||
//a somewhat useful/good-looking blur
|
||||
Vector2 nDiff = nDiff1 * 40.0f;
|
||||
if (MathUtils.GetLineIntersection(vertex + (nDiff1 * 40.0f), nextVertex + (nDiff1 * 40.0f), vertex + (nDiff2 * 40.0f), prevVertex + (nDiff2 * 40.0f), true, out Vector2 intersection))
|
||||
float blurDistance = 40.0f;
|
||||
Vector2 nDiff = nDiff1 * blurDistance;
|
||||
if (MathUtils.GetLineIntersection(vertex + (nDiff1 * blurDistance), nextVertex + (nDiff1 * blurDistance), vertex + (nDiff2 * blurDistance), prevVertex + (nDiff2 * blurDistance), true, out Vector2 intersection))
|
||||
{
|
||||
nDiff = intersection - vertex;
|
||||
if (nDiff.LengthSquared() > 10000.0f)
|
||||
if (nDiff.LengthSquared() > 100.0f * 100.0f)
|
||||
{
|
||||
nDiff /= Math.Max(Math.Abs(nDiff.X), Math.Abs(nDiff.Y)); nDiff *= 100.0f;
|
||||
nDiff /= Math.Max(Math.Abs(nDiff.X), Math.Abs(nDiff.Y));
|
||||
nDiff *= 100.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1162,7 +1203,6 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
|
||||
translateVertices = Vector2.Zero;
|
||||
rotateVertices = 0.0f;
|
||||
prevCalculatedPosition = position;
|
||||
prevCalculatedRotation = rotation;
|
||||
}
|
||||
@@ -1340,31 +1380,41 @@ namespace Barotrauma.Lights
|
||||
|
||||
if (NeedsRecalculation && allowRecalculation)
|
||||
{
|
||||
recalculationCount++;
|
||||
var verts = FindRaycastHits();
|
||||
if (verts == null)
|
||||
if (state == LightVertexState.UpToDate)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError($"Failed to generate vertices for a light source. Range: {Range}, color: {Color}, brightness: {CurrentBrightness}, parent: {ParentBody?.UserData ?? "Unknown"}");
|
||||
#endif
|
||||
Enabled = false;
|
||||
return;
|
||||
recalculationCount++;
|
||||
FindRaycastHits();
|
||||
}
|
||||
else if (state == LightVertexState.PendingVertexRecalculation)
|
||||
{
|
||||
if (verts == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError($"Failed to generate vertices for a light source. Range: {Range}, color: {Color}, brightness: {CurrentBrightness}, parent: {ParentBody?.UserData ?? "Unknown"}");
|
||||
#endif
|
||||
Enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
CalculateLightVertices(verts);
|
||||
CalculateLightVertices(verts);
|
||||
|
||||
LastRecalculationTime = (float)Timing.TotalTime;
|
||||
NeedsRecalculation = false;
|
||||
LastRecalculationTime = (float)Timing.TotalTime;
|
||||
NeedsRecalculation = needsRecalculationWhenUpToDate;
|
||||
needsRecalculationWhenUpToDate = false;
|
||||
|
||||
state = LightVertexState.UpToDate;
|
||||
}
|
||||
}
|
||||
|
||||
if (vertexCount == 0) { return; }
|
||||
|
||||
Vector2 offset = ParentSub == null ? Vector2.Zero : ParentSub.DrawPosition;
|
||||
lightEffect.World =
|
||||
Matrix.CreateTranslation(-new Vector3(position, 0.0f)) *
|
||||
Matrix.CreateRotationZ(rotateVertices - MathHelper.ToRadians(LightSourceParams.Rotation)) *
|
||||
Matrix.CreateRotationZ(MathHelper.ToRadians(LightSourceParams.Rotation)) *
|
||||
Matrix.CreateTranslation(new Vector3(position + offset + translateVertices, 0.0f)) *
|
||||
transform;
|
||||
|
||||
if (vertexCount == 0) { return; }
|
||||
|
||||
lightEffect.DiffuseColor = (new Vector3(Color.R, Color.G, Color.B) * (Color.A / 255.0f * CurrentBrightness)) / 255.0f;
|
||||
if (OverrideLightTexture != null)
|
||||
|
||||
@@ -738,8 +738,8 @@ namespace Barotrauma
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, rect);
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
|
||||
|
||||
Vector2 topLeft = rectCenter + viewOffset;
|
||||
Vector2 bottomRight = rectCenter + (viewOffset + new Vector2(Width, Height));
|
||||
Vector2 topLeft = rectCenter + viewOffset - rect.Location.ToVector2();
|
||||
Vector2 bottomRight = topLeft + new Vector2(Width, Height);
|
||||
Vector2 mapTileSize = mapTiles[0, 0].size * generationParams.MapTileScale;
|
||||
|
||||
int startX = (int)Math.Floor(-topLeft.X / mapTileSize.X) - 1;
|
||||
|
||||
@@ -56,12 +56,12 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
private static readonly List<RoundSound> roundSounds = new List<RoundSound>();
|
||||
private static readonly Dictionary<string, RoundSound> roundSoundByPath = new Dictionary<string, RoundSound>();
|
||||
public static RoundSound? Load(ContentXElement element, bool stream = false)
|
||||
{
|
||||
if (GameMain.SoundManager?.Disabled ?? true) { return null; }
|
||||
|
||||
var filename = element.GetAttributeContentPath("file") ?? element.GetAttributeContentPath("sound");
|
||||
|
||||
if (filename is null)
|
||||
{
|
||||
string errorMsg = "Error when loading round sound (" + element + ") - file path not set";
|
||||
@@ -70,7 +70,11 @@ namespace Barotrauma
|
||||
return null;
|
||||
}
|
||||
|
||||
Sound? existingSound = roundSounds.Find(s => s.Filename == filename?.FullPath && s.Stream == stream && s.Sound is { Disposed: false })?.Sound;
|
||||
Sound? existingSound = null;
|
||||
if (roundSoundByPath.TryGetValue(filename.FullPath, out RoundSound? rs) && rs.Sound is { Disposed: false })
|
||||
{
|
||||
existingSound = rs.Sound;
|
||||
}
|
||||
|
||||
if (existingSound is null)
|
||||
{
|
||||
@@ -99,7 +103,10 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
RoundSound newSound = new RoundSound(element, existingSound);
|
||||
|
||||
if (filename is not null && !newSound.Stream)
|
||||
{
|
||||
roundSoundByPath.TryAdd(filename.FullPath, newSound);
|
||||
}
|
||||
roundSounds.Add(newSound);
|
||||
return newSound;
|
||||
}
|
||||
@@ -124,24 +131,14 @@ namespace Barotrauma
|
||||
roundSound.Sound = existingSound;
|
||||
}
|
||||
|
||||
private static void Remove(RoundSound roundSound)
|
||||
{
|
||||
#warning TODO: what is going on here????
|
||||
roundSound.Sound?.Dispose();
|
||||
|
||||
if (roundSounds.Contains(roundSound)) { roundSounds.Remove(roundSound); }
|
||||
foreach (RoundSound otherSound in roundSounds)
|
||||
{
|
||||
if (otherSound.Sound == roundSound.Sound) { otherSound.Sound = null; }
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveAllRoundSounds()
|
||||
{
|
||||
for (int i = roundSounds.Count - 1; i >= 0; i--)
|
||||
foreach (var roundSound in roundSounds)
|
||||
{
|
||||
Remove(roundSounds[i]);
|
||||
roundSound.Sound?.Dispose();
|
||||
}
|
||||
roundSounds.Clear();
|
||||
roundSoundByPath.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,21 +55,11 @@ namespace Barotrauma
|
||||
{
|
||||
if (!CastShadow) { return; }
|
||||
|
||||
if (convexHulls == null)
|
||||
{
|
||||
convexHulls = new List<ConvexHull>();
|
||||
}
|
||||
|
||||
Vector2 halfSize = size / 2;
|
||||
Vector2[] verts = new Vector2[]
|
||||
{
|
||||
position + new Vector2(-halfSize.X, halfSize.Y),
|
||||
position + new Vector2(halfSize.X, halfSize.Y),
|
||||
position + new Vector2(halfSize.X, -halfSize.Y),
|
||||
position + new Vector2(-halfSize.X, -halfSize.Y),
|
||||
};
|
||||
|
||||
var h = new ConvexHull(verts, Color.Black, this);
|
||||
convexHulls ??= new List<ConvexHull>();
|
||||
var h = new ConvexHull(
|
||||
new Rectangle((position - size / 2).ToPoint(), size.ToPoint()),
|
||||
IsHorizontal,
|
||||
this);
|
||||
if (Math.Abs(rotation) > 0.001f)
|
||||
{
|
||||
h.Rotate(position, rotation);
|
||||
|
||||
@@ -116,11 +116,11 @@ namespace Barotrauma
|
||||
|
||||
foreach (MapEntity e in entitiesToRender)
|
||||
{
|
||||
if (!e.DrawOverWater) continue;
|
||||
if (!e.DrawOverWater) { continue; }
|
||||
|
||||
if (predicate != null)
|
||||
{
|
||||
if (!predicate(e)) continue;
|
||||
if (!predicate(e)) { continue; }
|
||||
}
|
||||
|
||||
e.Draw(spriteBatch, editing, false);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -18,7 +19,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
List<Submarine> subsToMove = submarine.GetConnectedSubs();
|
||||
var subsToMove = submarine.GetConnectedSubs();
|
||||
foreach (Submarine dockedSub in subsToMove)
|
||||
{
|
||||
if (dockedSub == submarine) { continue; }
|
||||
@@ -51,7 +52,6 @@ namespace Barotrauma
|
||||
sub.PhysicsBody.SetTransformIgnoreContacts(sub.PhysicsBody.SimPosition + ConvertUnits.ToSimUnits(moveAmount), 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (closestSub != null && subsToMove.Contains(closestSub))
|
||||
{
|
||||
GameMain.GameScreen.Cam.Position += moveAmount;
|
||||
|
||||
@@ -67,6 +67,10 @@ namespace Barotrauma
|
||||
else if (ConnectedDoor != null)
|
||||
{
|
||||
sprite = iconSprites["Door"];
|
||||
if (ConnectedDoor.IsHorizontal && Ladders == null)
|
||||
{
|
||||
clr = Color.Yellow;
|
||||
}
|
||||
}
|
||||
else if (Ladders != null)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user