Unstable 1.2.4.0
This commit is contained in:
@@ -133,6 +133,8 @@ namespace Barotrauma.Lights
|
||||
|
||||
public Rectangle BoundingBox { get; private set; }
|
||||
|
||||
public bool IsInvalid { get; private set; }
|
||||
|
||||
public ConvexHull(Rectangle rect, bool isHorizontal, MapEntity parent)
|
||||
{
|
||||
shadowEffect ??= new BasicEffect(GameMain.Instance.GraphicsDevice)
|
||||
@@ -481,15 +483,34 @@ namespace Barotrauma.Lights
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
vertices[i].WorldPos = vertices[i].Pos;
|
||||
ValidateVertex(vertices[i].WorldPos, "vertices[i].Pos");
|
||||
segments[i].Start.WorldPos = segments[i].Start.Pos;
|
||||
ValidateVertex(segments[i].Start.WorldPos, "segments[i].Start.Pos");
|
||||
segments[i].End.WorldPos = segments[i].End.Pos;
|
||||
ValidateVertex(segments[i].End.WorldPos, "segments[i].End.Pos");
|
||||
}
|
||||
if (ParentEntity == null || ParentEntity.Submarine == null) { return; }
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
vertices[i].WorldPos += ParentEntity.Submarine.DrawPosition;
|
||||
ValidateVertex(vertices[i].WorldPos, "vertices[i].WorldPos");
|
||||
segments[i].Start.WorldPos += ParentEntity.Submarine.DrawPosition;
|
||||
ValidateVertex(segments[i].Start.WorldPos, "segments[i].Start.WorldPos");
|
||||
segments[i].End.WorldPos += ParentEntity.Submarine.DrawPosition;
|
||||
ValidateVertex(segments[i].End.WorldPos, "segments[i].End.WorldPos");
|
||||
}
|
||||
|
||||
void ValidateVertex(Vector2 vertex, string debugName)
|
||||
{
|
||||
if (!MathUtils.IsValid(vertex))
|
||||
{
|
||||
IsInvalid = true;
|
||||
string errorMsg = $"Invalid vertex on convex hull ({debugName}: {vertex}, parent entity: {ParentEntity?.ToString() ?? "null"}).";
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("ConvexHull.RefreshWorldPositions:InvalidVertex", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -234,6 +234,15 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
public void DebugDrawVertices(SpriteBatch spriteBatch)
|
||||
{
|
||||
foreach (LightSource light in lights)
|
||||
{
|
||||
if (!light.Enabled) { continue; }
|
||||
light.DebugDrawVertices(spriteBatch);
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, RenderTarget2D backgroundObstructor = null)
|
||||
{
|
||||
if (!LightingEnabled) { return; }
|
||||
@@ -259,7 +268,8 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
if (!light.Enabled) { continue; }
|
||||
if ((light.Color.A < 1 || light.Range < 1.0f) && !light.LightSourceParams.OverrideLightSpriteAlpha.HasValue) { continue; }
|
||||
|
||||
//above the top boundary of the level (in an inactive respawn shuttle?)
|
||||
if (Level.Loaded != null && light.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
|
||||
if (light.ParentBody != null)
|
||||
{
|
||||
light.ParentBody.UpdateDrawPosition();
|
||||
@@ -801,6 +811,8 @@ namespace Barotrauma.Lights
|
||||
|
||||
public void ClearLights()
|
||||
{
|
||||
activeLights.Clear();
|
||||
activeLightsWithLightVolume.Clear();
|
||||
lights.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +37,9 @@ namespace Barotrauma.Lights
|
||||
TextureRange = range;
|
||||
if (OverrideLightTexture != null)
|
||||
{
|
||||
TextureRange += Math.Max(
|
||||
Math.Abs(OverrideLightTexture.RelativeOrigin.X - 0.5f) * OverrideLightTexture.size.X,
|
||||
Math.Abs(OverrideLightTexture.RelativeOrigin.Y - 0.5f) * OverrideLightTexture.size.Y);
|
||||
TextureRange *= 1.0f + Math.Max(
|
||||
Math.Abs(OverrideLightTexture.RelativeOrigin.X - 0.5f),
|
||||
Math.Abs(OverrideLightTexture.RelativeOrigin.Y - 0.5f));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,7 +238,11 @@ namespace Barotrauma.Lights
|
||||
private bool needsRecalculationWhenUpToDate;
|
||||
public bool NeedsRecalculation
|
||||
{
|
||||
get { return needsRecalculation; }
|
||||
get
|
||||
{
|
||||
if (ParentBody?.UserData is Item it && it.Prefab.Identifier == "flashlight") { return true; }
|
||||
return needsRecalculation;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!needsRecalculation && value)
|
||||
@@ -708,6 +712,7 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
foreach (ConvexHull hull in chList.List)
|
||||
{
|
||||
if (hull.IsInvalid) { continue; }
|
||||
if (!chList.IsHidden.Contains(hull))
|
||||
{
|
||||
//find convexhull segments that are close enough and facing towards the light source
|
||||
@@ -735,6 +740,7 @@ namespace Barotrauma.Lights
|
||||
GameMain.LightManager.AddRayCastTask(this, drawPos, rotation);
|
||||
}
|
||||
|
||||
const float MinPointDistance = 6;
|
||||
|
||||
public void RayCastTask(Vector2 drawPos, float rotation)
|
||||
{
|
||||
@@ -877,12 +883,11 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
const float MinPointDistance = 6;
|
||||
|
||||
//remove points that are very close to each other
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
//+= 2 because the points are added in pairs above, i.e. 0 and 1 belong to the same segment
|
||||
for (int i = 0; i < points.Count; i += 2)
|
||||
{
|
||||
for (int j = Math.Min(i + 4, points.Count - 1); j > i; j--)
|
||||
for (int j = Math.Min(i + 2, points.Count - 1); j > i; j--)
|
||||
{
|
||||
if (Math.Abs(points[i].WorldPos.X - points[j].WorldPos.X) < MinPointDistance &&
|
||||
Math.Abs(points[i].WorldPos.Y - points[j].WorldPos.Y) < MinPointDistance)
|
||||
@@ -892,14 +897,14 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
var compareCCW = new CompareSegmentPointCW(drawPos);
|
||||
try
|
||||
{
|
||||
points.Sort(compareCCW);
|
||||
var compareCW = new CompareSegmentPointCW(drawPos);
|
||||
points.Sort(compareCW);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("Constructing light volumes failed! Light pos: " + drawPos + ", Hull verts:\n");
|
||||
StringBuilder sb = new StringBuilder($"Constructing light volumes failed ({nameof(CompareSegmentPointCW)})! Light pos: {drawPos}, Hull verts:\n");
|
||||
foreach (SegmentPoint sp in points)
|
||||
{
|
||||
sb.AppendLine(sp.Pos.ToString());
|
||||
@@ -914,7 +919,11 @@ namespace Barotrauma.Lights
|
||||
verts.Clear();
|
||||
foreach (SegmentPoint p in points)
|
||||
{
|
||||
Vector2 dir = Vector2.Normalize(p.WorldPos - drawPos);
|
||||
Vector2 diff = p.WorldPos - drawPos;
|
||||
float dist = diff.Length();
|
||||
//light source exactly at the segment point, don't cast a shadow (normalizing the vector would lead to NaN)
|
||||
if (dist <= 0.0001f) { continue; }
|
||||
Vector2 dir = diff / dist;
|
||||
Vector2 dirNormal = new Vector2(-dir.Y, dir.X) * MinPointDistance;
|
||||
|
||||
//do two slightly offset raycasts to hit the segment itself and whatever's behind it
|
||||
@@ -940,9 +949,36 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
//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);
|
||||
markAsVisible = true;
|
||||
if (isPoint1)
|
||||
{
|
||||
TryAddPoints(intersection2.pos, p.WorldPos, drawPos, verts);
|
||||
markAsVisible = true;
|
||||
}
|
||||
else if (isPoint2)
|
||||
{
|
||||
TryAddPoints(intersection1.pos, p.WorldPos, drawPos, verts);
|
||||
markAsVisible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//didn't hit either point, completely obstructed
|
||||
verts.Add(intersection1.pos);
|
||||
verts.Add(intersection2.pos);
|
||||
}
|
||||
static void TryAddPoints(Vector2 intersection, Vector2 point, Vector2 refPos, List<Vector2> verts)
|
||||
{
|
||||
//* 0.8f because we don't care about obstacles that are very close (intersecting walls),
|
||||
//only about obstacles that are clearly between the point and the refPos
|
||||
bool intersectionCloserThanPoint = Vector2.DistanceSquared(intersection, refPos) < Vector2.DistanceSquared(point, refPos) * 0.8f;
|
||||
//if the raycast hit a segment that's closer than the point we're aiming towards,
|
||||
//it means we didn't hit a segment behind the point, but something that's obstructing it
|
||||
//= we don't want to add vertex at that obstructed point, it could make the light go through obstacles
|
||||
if (!intersectionCloserThanPoint)
|
||||
{
|
||||
verts.Add(point);
|
||||
}
|
||||
verts.Add(intersection);
|
||||
}
|
||||
}
|
||||
if (markAsVisible)
|
||||
{
|
||||
@@ -959,15 +995,32 @@ namespace Barotrauma.Lights
|
||||
//remove points that are very close to each other
|
||||
for (int i = 0; i < verts.Count - 1; i++)
|
||||
{
|
||||
for (int j = Math.Min(i + 4, verts.Count - 1); j > i; j--)
|
||||
for (int j = verts.Count - 1; j > i; j--)
|
||||
{
|
||||
if (Math.Abs(verts[i].X - verts[j].X) < 6 &&
|
||||
Math.Abs(verts[i].Y - verts[j].Y) < 6)
|
||||
if (Math.Abs(verts[i].X - verts[j].X) < MinPointDistance &&
|
||||
Math.Abs(verts[i].Y - verts[j].Y) < MinPointDistance)
|
||||
{
|
||||
verts.RemoveAt(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var compareCW = new CompareCW(drawPos);
|
||||
verts.Sort(compareCW);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder($"Constructing light volumes failed ({nameof(CompareSegmentPointCW)})! Light pos: {drawPos}, verts:\n");
|
||||
foreach (Vector2 v in verts)
|
||||
{
|
||||
sb.AppendLine(v.ToString());
|
||||
}
|
||||
DebugConsole.ThrowError(sb.ToString(), e);
|
||||
}
|
||||
|
||||
|
||||
calculatedDrawPos = drawPos;
|
||||
state = LightVertexState.PendingVertexRecalculation;
|
||||
}
|
||||
@@ -1114,7 +1167,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
//add the normals together and use some magic numbers to create
|
||||
//a somewhat useful/good-looking blur
|
||||
float blurDistance = 40.0f;
|
||||
float blurDistance = 25.0f;
|
||||
Vector2 nDiff = nDiff1 * blurDistance;
|
||||
if (MathUtils.GetLineIntersection(vertex + (nDiff1 * blurDistance), nextVertex + (nDiff1 * blurDistance), vertex + (nDiff2 * blurDistance), prevVertex + (nDiff2 * blurDistance), true, out Vector2 intersection))
|
||||
{
|
||||
@@ -1230,7 +1283,8 @@ namespace Barotrauma.Lights
|
||||
/// <param name="spriteBatch"></param>
|
||||
public void DrawSprite(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (GameMain.DebugDraw)
|
||||
//uncomment if you want to visualize the bounds of the light volume
|
||||
/*if (GameMain.DebugDraw)
|
||||
{
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null)
|
||||
@@ -1269,7 +1323,7 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
GUI.DrawLine(spriteBatch, boundaryCorners[i].Pos, boundaryCorners[(i + 1) % 4].Pos, Color.White, 0, 3);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
if (DeformableLightSprite != null)
|
||||
{
|
||||
@@ -1367,6 +1421,38 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
public void DebugDrawVertices(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (Range < 1.0f || Color.A < 1 || CurrentBrightness <= 0.0f) { return; }
|
||||
|
||||
//commented out because this is mostly just useful in very specific situations, otherwise it just makes debugdraw very messy
|
||||
//(you may also need to add a condition here that only draws this for the specific light you're interested in)
|
||||
if (GameMain.DebugDraw && vertices != null)
|
||||
{
|
||||
if (ParentBody?.UserData is Item it && it.Prefab.Identifier == "flashlight")
|
||||
|
||||
for (int i = 1; i < vertices.Length - 1; i += 2)
|
||||
{
|
||||
Vector2 vert1 = new Vector2(vertices[i].Position.X, vertices[i].Position.Y);
|
||||
int nextIndex = (i + 2) % vertices.Length;
|
||||
//the first vertex is the one at the position of the light source, skip that one
|
||||
//(we just want to draw lines between the vertices at the circumference of the light volume)
|
||||
if (nextIndex == 0) { nextIndex++; }
|
||||
Vector2 vert2 = new Vector2(vertices[nextIndex].Position.X, vertices[nextIndex].Position.Y);
|
||||
if (ParentSub != null)
|
||||
{
|
||||
vert1 += ParentSub.DrawPosition;
|
||||
vert2 += ParentSub.DrawPosition;
|
||||
}
|
||||
vert1.Y = -vert1.Y;
|
||||
vert2.Y = -vert2.Y;
|
||||
|
||||
var randomColor = ToolBox.GradientLerp(i / (float)vertices.Length, Color.Magenta, Color.Blue, Color.Yellow, Color.Green, Color.Cyan, Color.Red, Color.Purple, Color.Yellow);
|
||||
GUI.DrawLine(spriteBatch, vert1, vert2, randomColor * 0.8f, width: 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawLightVolume(SpriteBatch spriteBatch, BasicEffect lightEffect, Matrix transform, bool allowRecalculation, ref int recalculationCount)
|
||||
{
|
||||
if (Range < 1.0f || Color.A < 1 || CurrentBrightness <= 0.0f) { return; }
|
||||
|
||||
Reference in New Issue
Block a user