diff --git a/Subsurface/Content/Items/Electricity/lamp.png b/Subsurface/Content/Items/Electricity/lamp.png index 05848b2ae..529fa81a1 100644 Binary files a/Subsurface/Content/Items/Electricity/lamp.png and b/Subsurface/Content/Items/Electricity/lamp.png differ diff --git a/Subsurface/Content/Items/Electricity/lights.xml b/Subsurface/Content/Items/Electricity/lights.xml index ecbcfe351..04e0f4f93 100644 --- a/Subsurface/Content/Items/Electricity/lights.xml +++ b/Subsurface/Content/Items/Electricity/lights.xml @@ -10,8 +10,8 @@ - - + + @@ -20,8 +20,25 @@ - + + + + + + + + + + + + + + diff --git a/Subsurface/Source/Items/Components/Door.cs b/Subsurface/Source/Items/Components/Door.cs index 3ed69e783..a4ce54086 100644 --- a/Subsurface/Source/Items/Components/Door.cs +++ b/Subsurface/Source/Items/Components/Door.cs @@ -56,10 +56,15 @@ namespace Barotrauma.Items.Components get { if (linkedGap != null) return linkedGap; + foreach (MapEntity e in item.linkedTo) { - linkedGap = e as Gap; - if (linkedGap != null) return linkedGap; + linkedGap = e as Gap; + if (linkedGap != null) + { + linkedGap.PassAmbientLight = window != Rectangle.Empty; + return linkedGap; + } } Rectangle rect = item.Rect; if (isHorizontal) @@ -75,6 +80,7 @@ namespace Barotrauma.Items.Components linkedGap = new Gap(rect, Item.Submarine); linkedGap.Submarine = item.Submarine; + linkedGap.PassAmbientLight = window != Rectangle.Empty; linkedGap.Open = openState; item.linkedTo.Add(linkedGap); return linkedGap; diff --git a/Subsurface/Source/Map/Gap.cs b/Subsurface/Source/Map/Gap.cs index afc3071f4..5790aec50 100644 --- a/Subsurface/Source/Map/Gap.cs +++ b/Subsurface/Source/Map/Gap.cs @@ -30,8 +30,13 @@ namespace Barotrauma private float higherSurface; private float lowerSurface; + private Vector2 lerpedFlowForce; + //if set to true, hull connections of this gap won't be updated when changes are being done to hulls public bool DisableHullRechecks; + + //can ambient light get through the gap even if it's not open + public bool PassAmbientLight; public float Open { @@ -48,8 +53,6 @@ namespace Barotrauma get { return lerpedFlowForce; } } - private Vector2 lerpedFlowForce; - public Hull FlowTargetHull { get { return flowTargetHull; } diff --git a/Subsurface/Source/Map/Hull.cs b/Subsurface/Source/Map/Hull.cs index 83693d7da..9667555b4 100644 --- a/Subsurface/Source/Map/Hull.cs +++ b/Subsurface/Source/Map/Hull.cs @@ -723,7 +723,6 @@ namespace Barotrauma } var entities = EntityGrid.GetEntities(entityGrids, position, useWorldCoordinates); - foreach (Hull hull in entities) { if (Submarine.RectContains(useWorldCoordinates ? hull.WorldRect : hull.rect, position)) return hull; @@ -731,7 +730,7 @@ namespace Barotrauma return null; } - + //returns the water block which contains the point (or null if it isn't inside any) public static Hull FindHullOld(Vector2 position, Hull guess = null, bool useWorldCoordinates = true) { diff --git a/Subsurface/Source/Map/Levels/Level.cs b/Subsurface/Source/Map/Levels/Level.cs index c3adb7194..1dfe397b6 100644 --- a/Subsurface/Source/Map/Levels/Level.cs +++ b/Subsurface/Source/Map/Levels/Level.cs @@ -181,7 +181,7 @@ namespace Barotrauma backgroundColor = generationParams.BackgroundColor; float avgValue = (backgroundColor.R + backgroundColor.G + backgroundColor.G) / 3; - GameMain.LightManager.AmbientLight = new Color(backgroundColor * (60.0f / avgValue), 1.0f); + GameMain.LightManager.AmbientLight = new Color(backgroundColor * (10.0f / avgValue), 1.0f); float minWidth = Submarine.MainSub == null ? 0.0f : Math.Max(Submarine.MainSub.Borders.Width, Submarine.MainSub.Borders.Height); minWidth = Math.Max(minWidth, 6500.0f); diff --git a/Subsurface/Source/Map/Lights/LightManager.cs b/Subsurface/Source/Map/Lights/LightManager.cs index 3095465a7..71d658f7b 100644 --- a/Subsurface/Source/Map/Lights/LightManager.cs +++ b/Subsurface/Source/Map/Lights/LightManager.cs @@ -8,7 +8,9 @@ namespace Barotrauma.Lights { class LightManager { - //public static Vector2 ViewPos; + private const float AmbientLightUpdateInterval = 0.2f; + private const float AmbientLightFalloff = 0.8f; + private static Entity viewTarget; public static Entity ViewTarget @@ -35,12 +37,17 @@ namespace Barotrauma.Lights public bool ObstructVision; private Texture2D visionCircle; + + private Dictionary hullAmbientLights = new Dictionary(); + private Dictionary smoothedHullAmbientLights = new Dictionary(); + + private float ambientLightUpdateTimer; public LightManager(GraphicsDevice graphics) { lights = new List(); - AmbientLight = new Color(60, 60, 60, 255); + AmbientLight = new Color(20, 20, 20, 255); visionCircle = Sprite.LoadTexture("Content/Lights/visioncircle.png"); @@ -53,7 +60,10 @@ namespace Barotrauma.Lights losTexture = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight); - if (alphaClearTexture==null) + hullAmbientLights = new Dictionary(); + smoothedHullAmbientLights = new Dictionary(); + + if (alphaClearTexture == null) { alphaClearTexture = TextureLoader.FromFile("Content/Lights/alphaOne.png"); } @@ -77,7 +87,38 @@ namespace Barotrauma.Lights } } - public void UpdateLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam) + public void Update(float deltaTime) + { + if (ambientLightUpdateTimer > 0.0f) + { + ambientLightUpdateTimer -= deltaTime; + } + else + { + CalculateAmbientLights(); + + ambientLightUpdateTimer = AmbientLightUpdateInterval; + } + + foreach (Hull hull in hullAmbientLights.Keys) + { + if (!smoothedHullAmbientLights.ContainsKey(hull)) + { + smoothedHullAmbientLights.Add(hull, Color.TransparentBlack); + } + } + + foreach (Hull hull in smoothedHullAmbientLights.Keys.ToList()) + { + Color targetColor = Color.TransparentBlack; + + hullAmbientLights.TryGetValue(hull, out targetColor); + + smoothedHullAmbientLights[hull] = Color.Lerp(smoothedHullAmbientLights[hull], targetColor, deltaTime); + } + } + + public void UpdateLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, Effect blur) { if (!LightingEnabled) return; @@ -94,7 +135,7 @@ namespace Barotrauma.Lights foreach (LightSource light in lights) { - if (light.Color.A < 0.01f || light.Range < 1.0f || !light.CastShadows) continue; + if (light.Color.A < 1 || light.Range < 1.0f || !light.CastShadows) continue; if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, light.Range, viewRect)) continue; //clear alpha to 1 @@ -117,8 +158,7 @@ namespace Barotrauma.Lights ClearAlphaToOne(graphics, spriteBatch); - - + spriteBatch.Begin(SpriteSortMode.Deferred, CustomBlendStates.MultiplyWithAlpha, null, null, null, null, cam.Transform); GameMain.ParticleManager.Draw(spriteBatch, false, Particles.ParticleBlendState.Additive); @@ -126,7 +166,7 @@ namespace Barotrauma.Lights foreach (LightSource light in lights) { - if (light.Color.A < 0.01f || light.Range < 1.0f || light.CastShadows) continue; + if (light.Color.A < 1 || light.Range < 1.0f || light.CastShadows) continue; //if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, light.Range, viewRect)) continue; light.Draw(spriteBatch); @@ -147,6 +187,27 @@ namespace Barotrauma.Lights } spriteBatch.End(); + + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, null, null, null, cam.Transform); + + foreach (Hull hull in smoothedHullAmbientLights.Keys) + { + if (smoothedHullAmbientLights[hull].A < 0.01f) continue; + + var drawRect = + hull.Submarine == null ? + hull.Rect : + new Rectangle((int)(hull.Submarine.DrawPosition.X + hull.Rect.X), (int)(hull.Submarine.DrawPosition.Y + hull.Rect.Y), hull.Rect.Width, hull.Rect.Height); + + GUI.DrawRectangle(spriteBatch, + new Vector2(drawRect.X, -drawRect.Y), + new Vector2(hull.Rect.Width, hull.Rect.Height), + smoothedHullAmbientLights[hull] * 0.5f, true); + } + + spriteBatch.End(); + + //clear alpha, to avoid messing stuff up later ClearAlphaToOne(graphics, spriteBatch); @@ -173,8 +234,6 @@ namespace Barotrauma.Lights spriteBatch.Draw(visionCircle, new Vector2(ViewTarget.WorldPosition.X, -ViewTarget.WorldPosition.Y), null, Color.White, rotation, new Vector2(LightSource.LightTexture.Width*0.2f, LightSource.LightTexture.Height/2), scale, SpriteEffects.None, 0.0f); - - } else { @@ -209,6 +268,86 @@ namespace Barotrauma.Lights } graphics.SetRenderTarget(null); } + + + private void CalculateAmbientLights() + { + hullAmbientLights.Clear(); + + foreach (LightSource light in lights) + { + if (light.Color.A < 1f || light.Range < 1.0f) continue; + + var newAmbientLights = AmbientLightHulls(light); + foreach (Hull hull in newAmbientLights.Keys) + { + if (hullAmbientLights.ContainsKey(hull)) + { + //hull already lit by some other light source -> add the ambient lights up + hullAmbientLights[hull] = new Color( + hullAmbientLights[hull].R + newAmbientLights[hull].R, + hullAmbientLights[hull].G + newAmbientLights[hull].G, + hullAmbientLights[hull].B + newAmbientLights[hull].B, + hullAmbientLights[hull].A + newAmbientLights[hull].A); + } + else + { + hullAmbientLights.Add(hull, newAmbientLights[hull]); + } + } + } + } + + /// + /// Add ambient light to the hull the lightsource is inside + all adjacent hulls connected by a gap + /// + private Dictionary AmbientLightHulls(LightSource light) + { + Dictionary hullAmbientLight = new Dictionary(); + + var hull = Hull.FindHull(light.WorldPosition); + if (hull == null) return hullAmbientLight; + + return AmbientLightHulls(hull, hullAmbientLight, light.Color * (light.Range/2000.0f)); + } + + /// + /// A flood fill algorithm that adds ambient light to all hulls the starting hull is connected to + /// + private Dictionary AmbientLightHulls(Hull hull, Dictionary hullAmbientLight, Color currColor) + { + if (hullAmbientLight.ContainsKey(hull)) + { + if (hullAmbientLight[hull].A > currColor.A) + return hullAmbientLight; + else + hullAmbientLight[hull] = currColor; + } + else + { + hullAmbientLight.Add(hull, currColor); + } + + foreach (Gap g in hull.ConnectedGaps) + { + for (int i = 0; i < g.linkedTo.Count;i++ ) + { + if (g.linkedTo[i] is Hull) + { + if (g.linkedTo[i] == hull) continue; + + Color nextHullLight = currColor * AmbientLightFalloff; + if (!g.PassAmbientLight) nextHullLight *= g.Open; + + if (nextHullLight.A < 10) continue; + + hullAmbientLight = AmbientLightHulls((Hull)g.linkedTo[i], hullAmbientLight, nextHullLight); + } + } + } + + return hullAmbientLight; + } private void ClearAlphaToOne(GraphicsDevice graphics, SpriteBatch spriteBatch) { @@ -217,7 +356,7 @@ namespace Barotrauma.Lights spriteBatch.End(); } - public void DrawLightMap(SpriteBatch spriteBatch, Camera cam, Effect effect) + public void DrawLightMap(SpriteBatch spriteBatch, Effect effect) { if (!LightingEnabled) return; @@ -227,11 +366,11 @@ namespace Barotrauma.Lights spriteBatch.End(); } - public void DrawLOS(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, Effect effect) + public void DrawLOS(SpriteBatch spriteBatch, Effect effect) { if (!LosEnabled || ViewTarget == null) return; - spriteBatch.Begin(SpriteSortMode.Deferred, CustomBlendStates.Multiplicative, null, null, null); + spriteBatch.Begin(SpriteSortMode.Deferred, CustomBlendStates.Multiplicative, null, null, null, effect); spriteBatch.Draw(losTexture, Vector2.Zero, Color.White); spriteBatch.End(); @@ -264,9 +403,6 @@ namespace Barotrauma.Lights public static BlendState Multiplicative { get; private set; } public static BlendState WriteToAlpha { get; private set; } public static BlendState MultiplyWithAlpha { get; private set; } - - - } } diff --git a/Subsurface/Source/Map/Lights/LightSource.cs b/Subsurface/Source/Map/Lights/LightSource.cs index 5412b025e..03fff7bfb 100644 --- a/Subsurface/Source/Map/Lights/LightSource.cs +++ b/Subsurface/Source/Map/Lights/LightSource.cs @@ -306,20 +306,21 @@ namespace Barotrauma.Lights Vector2 center = new Vector2(LightTexture.Width / 2, LightTexture.Height / 2); float scale = range / (lightTexture.Width / 2.0f); - spriteBatch.Draw(lightTexture, new Vector2(WorldPosition.X, -WorldPosition.Y), null, color, 0, center, scale, SpriteEffects.None, 1); + spriteBatch.Draw(lightTexture, new Vector2(WorldPosition.X, -WorldPosition.Y), null, color * (color.A / 255.0f), 0, center, scale, SpriteEffects.None, 1); } else { - overrideLightTexture.Draw(spriteBatch, - new Vector2(WorldPosition.X, -WorldPosition.Y), Color, - overrideLightTexture.Origin, -Rotation, - new Vector2(overrideLightTexture.size.X/overrideLightTexture.SourceRect.Width, overrideLightTexture.size.Y/overrideLightTexture.SourceRect.Height)); + overrideLightTexture.Draw(spriteBatch, + new Vector2(WorldPosition.X, -WorldPosition.Y), color * (color.A / 255.0f), + overrideLightTexture.Origin, -Rotation, + new Vector2(overrideLightTexture.size.X / overrideLightTexture.SourceRect.Width, overrideLightTexture.size.Y / overrideLightTexture.SourceRect.Height)); } } if (LightSprite != null) { LightSprite.Draw(spriteBatch, new Vector2(WorldPosition.X, -WorldPosition.Y), Color, LightSprite.Origin); + } } diff --git a/Subsurface/Source/Screens/GameScreen.cs b/Subsurface/Source/Screens/GameScreen.cs index aa1bd038d..55a217098 100644 --- a/Subsurface/Source/Screens/GameScreen.cs +++ b/Subsurface/Source/Screens/GameScreen.cs @@ -128,6 +128,8 @@ namespace Barotrauma { cam.TargetPos = Lights.LightManager.ViewTarget.WorldPosition; } + + GameMain.LightManager.Update((float)deltaTime); cam.MoveCamera((float)deltaTime); foreach (Submarine sub in Submarine.Loaded) @@ -205,7 +207,7 @@ namespace Barotrauma GameMain.LightManager.ObstructVision = Character.Controlled != null && Character.Controlled.ObstructVision; - GameMain.LightManager.UpdateLightMap(graphics, spriteBatch, cam); + GameMain.LightManager.UpdateLightMap(graphics, spriteBatch, cam, lightBlur.Effect); if (Character.Controlled != null) { GameMain.LightManager.UpdateObstructVision(graphics, spriteBatch, cam, Character.Controlled.CursorWorldPosition); @@ -339,8 +341,7 @@ namespace Barotrauma spriteBatch.End(); - - GameMain.LightManager.DrawLightMap(spriteBatch, cam, lightBlur.Effect); + GameMain.LightManager.DrawLightMap(spriteBatch, lightBlur.Effect); spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, SamplerState.LinearWrap, @@ -355,7 +356,7 @@ namespace Barotrauma if (Character.Controlled != null) { - GameMain.LightManager.DrawLOS(graphics, spriteBatch, cam, lightBlur.Effect); + GameMain.LightManager.DrawLOS(spriteBatch, lightBlur.Effect); } } diff --git a/Subsurface/Submarines/Aegir Mark III.sub b/Subsurface/Submarines/Aegir Mark III.sub index 2d0af9d3e..79c236a1a 100644 Binary files a/Subsurface/Submarines/Aegir Mark III.sub and b/Subsurface/Submarines/Aegir Mark III.sub differ