1 using Microsoft.Xna.Framework;
2 using Microsoft.Xna.Framework.Graphics;
3 using System.Collections.Generic;
8 using System.Threading;
18 const int MaxLightVolumeRecalculationsPerFrame = 5;
24 const float ObstructLightsBehindCharactersZoomThreshold = 0.5f;
26 private Thread rayCastThread;
27 private Queue<RayCastTask> pendingRayCasts =
new Queue<RayCastTask>();
31 private float currLightMapScale;
56 private readonly Texture2D highlightRaster;
58 private BasicEffect lightEffect;
63 private readonly List<LightSource> lights;
75 private readonly Texture2D visionCircle;
77 private readonly Texture2D gapGlowTexture;
79 private Vector2 losOffset;
81 private int recalculationCount;
85 public IEnumerable<LightSource>
Lights
87 get {
return lights; }
92 lights =
new List<LightSource>(100);
96 rayCastThread =
new Thread(UpdateRayCasts)
98 Name =
"LightManager Raycast thread",
101 rayCastThread.Start();
103 visionCircle =
Sprite.LoadTexture(
"Content/Lights/visioncircle.png");
104 highlightRaster =
Sprite.LoadTexture(
"Content/UI/HighlightRaster.png");
105 gapGlowTexture =
Sprite.LoadTexture(
"Content/Lights/pointlight_rays.png");
109 CreateRenderTargets(graphics);
112 CrossThread.RequestExecutionOnMainThread(() =>
114 CreateRenderTargets(graphics);
116 LosEffect = EffectLoader.Load(
"Effects/losshader");
121 VertexColorEnabled =
true,
122 TextureEnabled =
true,
128 private void CreateRenderTargets(GraphicsDevice graphics)
130 var pp = graphics.PresentationParameters;
132 currLightMapScale = GameSettings.CurrentConfig.Graphics.LightMapScale;
143 RenderTarget2D CreateRenderTarget()
145 return new RenderTarget2D(graphics,
147 pp.BackBufferFormat, pp.DepthStencilFormat, pp.MultiSampleCount,
148 RenderTargetUsage.DiscardContents);
154 (
int)(
GameMain.
GraphicsHeight * GameSettings.CurrentConfig.Graphics.LightMapScale),
false, SurfaceFormat.Color, DepthFormat.None);
159 if (!lights.Contains(light)) { lights.Add(light); }
164 lights.Remove(light);
176 private readonly List<LightSource> activeLights =
new List<LightSource>(capacity: 100);
177 private readonly List<LightSource> activeShadowCastingLights =
new List<LightSource>(capacity: 100);
184 time = (time + deltaTime) % 100000.0f;
187 if (!light.
Enabled) {
continue; }
192 private sealed
class RayCastTask
195 public Vector2 DrawPos;
196 public float Rotation;
198 public RayCastTask(
LightSource lightSource, Vector2 drawPos,
float rotation)
205 public void Calculate()
211 private static readonly
object mutex =
new object();
217 if (pendingRayCasts.Any(p => p.LightSource == lightSource)) {
return; }
218 pendingRayCasts.Enqueue(
new RayCastTask(lightSource, drawPos, rotation));
222 private void UpdateRayCasts()
228 while (pendingRayCasts.Count > 0)
230 pendingRayCasts.Dequeue().Calculate();
241 if (!light.
Enabled) {
continue; }
246 public void RenderLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch,
Camera cam, RenderTarget2D backgroundObstructor =
null)
250 if (Math.Abs(currLightMapScale - GameSettings.CurrentConfig.Graphics.LightMapScale) > 0.01f)
253 CreateRenderTargets(graphics);
256 Matrix spriteBatchTransform = cam.
Transform * Matrix.CreateScale(
new Vector3(GameSettings.CurrentConfig.Graphics.LightMapScale, GameSettings.CurrentConfig.Graphics.LightMapScale, 1.0f));
260 bool highlightsVisible = UpdateHighlights(graphics, spriteBatch, spriteBatchTransform, cam);
265 recalculationCount = 0;
266 activeLights.Clear();
269 if (!light.
Enabled) {
continue; }
287 float spriteRange = Math.Max(
292 range = Math.Max(Math.Max(spriteRange, targetSize), range);
294 if (!MathUtils.CircleIntersectsRectangle(light.
WorldPosition, range, viewRect)) {
continue; }
296 light.
Priority = lightPriority(range, light);
299 while (i < activeLights.Count && light.
Priority < activeLights[i].Priority)
303 activeLights.Insert(i, light);
307 float lightPriority(
float range,
LightSource light)
318 activeShadowCastingLights.Clear();
319 foreach (var activeLight
in activeLights)
321 if (!activeLight.CastShadows) {
continue; }
322 if (activeLight.Range < 1.0f || activeLight.Color.A < 1 || activeLight.CurrentBrightness <= 0.0f) {
continue; }
323 activeShadowCastingLights.Add(activeLight);
327 if (activeShadowCastingLights.Count > GameSettings.CurrentConfig.Graphics.VisibleLightLimit &&
Screen.
Selected is { IsEditor:
false })
329 for (
int i = GameSettings.CurrentConfig.Graphics.VisibleLightLimit; i < activeShadowCastingLights.Count; i++)
331 activeLights.Remove(activeShadowCastingLights[i]);
334 activeLights.Sort((l1, l2) => l1.LastRecalculationTime.CompareTo(l2.LastRecalculationTime));
341 graphics.Clear(Color.Black);
342 graphics.BlendState = BlendState.NonPremultiplied;
343 spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
344 foreach (LightSource light
in activeLights)
346 if (light.IsBackground || light.CurrentBrightness <= 0.0f) {
continue; }
348 if (light.ParentBody?.UserData is Limb limb && !limb.Hide) { light.DrawSprite(spriteBatch, cam); }
356 graphics.BlendState = BlendState.Additive;
357 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
358 Level.Loaded?.BackgroundCreatureManager?.DrawLights(spriteBatch, cam);
359 foreach (LightSource light
in activeLights)
361 if (!light.IsBackground || light.CurrentBrightness <= 0.0f) {
continue; }
362 light.DrawLightVolume(spriteBatch, lightEffect, transform, recalculationCount < MaxLightVolumeRecalculationsPerFrame, ref recalculationCount);
363 light.DrawSprite(spriteBatch, cam);
365 GameMain.ParticleManager.Draw(spriteBatch,
true,
null, Particles.ParticleBlendState.Additive);
371 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, transformMatrix: spriteBatchTransform);
372 Dictionary<Hull, Rectangle> visibleHulls = GetVisibleHulls(cam);
373 foreach (KeyValuePair<Hull, Rectangle> hull
in visibleHulls)
375 GUI.DrawRectangle(spriteBatch,
376 new Vector2(hull.Value.X, -hull.Value.Y),
377 new Vector2(hull.Value.Width, hull.Value.Height),
378 hull.Key.AmbientLight == Color.TransparentBlack ? Color.Black : hull.Key.AmbientLight.Multiply(hull.Key.AmbientLight.A / 255.0f),
true);
382 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
384 glowColorHSV.Z = Math.Max(glowColorHSV.Z, 0.4f);
385 Color glowColor = ToolBoxCore.HSVToRGB(glowColorHSV.X, glowColorHSV.Y, glowColorHSV.Z);
386 Vector2 glowSpriteSize =
new Vector2(gapGlowTexture.Width, gapGlowTexture.Height);
387 foreach (var gap
in Gap.GapList)
389 if (gap.IsRoomToRoom || gap.Open <= 0.0f || gap.ConnectedWall ==
null) {
continue; }
391 float a = MathHelper.Lerp(0.5f, 1.0f,
392 PerlinNoise.GetPerlin((
float)Timing.TotalTime * 0.05f, gap.GlowEffectT));
394 float scale = MathHelper.Lerp(0.5f, 2.0f,
395 PerlinNoise.GetPerlin((
float)Timing.TotalTime * 0.01f, gap.GlowEffectT));
397 float rot = PerlinNoise.GetPerlin((
float)Timing.TotalTime * 0.001f, gap.GlowEffectT) * MathHelper.TwoPi;
399 Vector2 spriteScale =
new Vector2(gap.Rect.Width, gap.Rect.Height) / glowSpriteSize;
400 Vector2 drawPos =
new Vector2(gap.DrawPosition.X, -gap.DrawPosition.Y);
402 spriteBatch.Draw(gapGlowTexture,
408 scale: Math.Max(spriteScale.X, spriteScale.Y) * scale,
414 GameMain.GameScreen.DamageEffect.CurrentTechnique = GameMain.GameScreen.DamageEffect.Techniques[
"StencilShaderSolidColor"];
415 GameMain.GameScreen.DamageEffect.Parameters[
"solidColor"].SetValue(Color.Black.ToVector4());
416 spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, SamplerState.LinearWrap, transformMatrix: spriteBatchTransform, effect: GameMain.GameScreen.DamageEffect);
417 Submarine.DrawDamageable(spriteBatch, GameMain.GameScreen.DamageEffect);
420 graphics.BlendState = BlendState.Additive;
425 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
426 foreach (LightSource light
in activeLights)
429 if (light.IsBackground || light.ParentBody?.UserData is Limb || light.CurrentBrightness <= 0.0f) {
continue; }
430 light.DrawSprite(spriteBatch, cam);
434 if (highlightsVisible)
436 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
437 spriteBatch.Draw(
HighlightMap, Vector2.Zero, Color.White);
443 if (cam.Zoom > ObstructLightsBehindCharactersZoomThreshold)
446 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect:
SolidColorEffect, transformMatrix: spriteBatchTransform);
447 DrawCharacters(spriteBatch, cam, drawDeformSprites:
false);
450 DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques[
"DeformShaderSolidVertexColor"];
451 DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
452 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
453 DrawCharacters(spriteBatch, cam, drawDeformSprites:
true);
457 static void DrawCharacters(SpriteBatch spriteBatch, Camera cam,
bool drawDeformSprites)
459 foreach (Character character
in Character.CharacterList)
461 if (character.CurrentHull ==
null || !character.Enabled || !character.IsVisible || character.InvisibleTimer > 0.0f) {
continue; }
462 if (
Character.Controlled?.FocusedCharacter == character) {
continue; }
463 Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
465 character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
466 foreach (Limb limb
in character.AnimController.Limbs)
468 if (drawDeformSprites == (limb.DeformSprite ==
null)) {
continue; }
469 limb.Draw(spriteBatch, cam, lightColor);
471 foreach (var heldItem
in character.HeldItems)
473 heldItem.Draw(spriteBatch, editing:
false, overrideColor: Color.Black);
478 DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques[
"DeformShader"];
479 graphics.BlendState = BlendState.Additive;
483 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
485 spriteBatch.Draw(
LimbLightMap,
new Rectangle(cam.WorldView.X, -cam.WorldView.Y, cam.WorldView.Width, cam.WorldView.Height), Color.White);
492 foreach (LightSource light
in activeLights)
494 if (light.IsBackground || light.CurrentBrightness <= 0.0f) {
continue; }
495 light.DrawLightVolume(spriteBatch, lightEffect, transform, recalculationCount < MaxLightVolumeRecalculationsPerFrame, ref recalculationCount);
500 foreach (MapEntity e
in (
Submarine.VisibleEntities ?? MapEntity.MapEntityList))
502 if (e is Item item && !item.IsHidden && item.GetComponent<
Wire>() is
Wire wire)
504 wire.DebugDraw(spriteBatch, alpha: 0.4f);
509 lightEffect.World = transform;
511 GameMain.ParticleManager.Draw(spriteBatch,
false,
null, Particles.ParticleBlendState.Additive);
519 foreach (Character character
in Character.CharacterList)
521 if (character.Submarine ==
null || character.IsDead || !character.IsHuman) {
continue; }
526 void DrawHalo(Character character)
528 if (character ==
null || character.Removed) {
return; }
529 Vector2 haloDrawPos = character.DrawPosition;
530 haloDrawPos.Y = -haloDrawPos.Y;
534 Color haloColor = Color.White.Multiply(0.3f - ambientBrightness);
537 float scale = 512.0f / LightSource.LightTexture.Width;
539 LightSource.LightTexture, haloDrawPos,
null, haloColor, 0.0f,
540 new Vector2(LightSource.LightTexture.Width, LightSource.LightTexture.Height) / 2, scale, SpriteEffects.None, 0.0f);
549 graphics.SetRenderTarget(
null);
550 graphics.BlendState = BlendState.NonPremultiplied;
553 private readonly List<Entity> highlightedEntities =
new List<Entity>();
555 private bool UpdateHighlights(GraphicsDevice graphics, SpriteBatch spriteBatch, Matrix spriteBatchTransform, Camera cam)
557 if (GUI.DisableItemHighlights) {
return false; }
559 highlightedEntities.Clear();
562 if (
Character.Controlled.FocusedItem !=
null)
564 highlightedEntities.Add(
Character.Controlled.FocusedItem);
566 if (
Character.Controlled.FocusedCharacter !=
null)
568 highlightedEntities.Add(
Character.Controlled.FocusedCharacter);
570 foreach (MapEntity me
in MapEntity.HighlightedEntities)
572 if (me is Item item && item !=
Character.Controlled.FocusedItem)
574 highlightedEntities.Add(item);
578 if (highlightedEntities.Count == 0) {
return false; }
581 graphics.SetRenderTarget(HighlightMap);
582 SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques[
"SolidColor"];
583 SolidColorEffect.Parameters[
"color"].SetValue(Color.LightBlue.ToVector4());
584 SolidColorEffect.CurrentTechnique.Passes[0].Apply();
585 DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques[
"DeformShaderSolidColor"];
586 DeformableSprite.Effect.Parameters[
"solidColor"].SetValue(Color.LightBlue.ToVector4());
587 DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
588 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, samplerState: SamplerState.LinearWrap, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
589 foreach (Entity highlighted
in highlightedEntities)
591 if (highlighted is Item item)
593 if (item.IconStyle !=
null && (item !=
Character.Controlled.FocusedItem ||
Character.Controlled.FocusedItem ==
null))
599 item.Draw(spriteBatch,
false,
true);
602 else if (highlighted is Character character)
604 character.Draw(spriteBatch, cam);
610 spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive, samplerState: SamplerState.LinearWrap, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
611 foreach (Entity highlighted
in highlightedEntities)
613 if (highlighted is Item item)
615 if (item.IconStyle !=
null && (item !=
Character.Controlled.FocusedItem ||
Character.Controlled.FocusedItem ==
null))
617 SolidColorEffect.Parameters[
"color"].SetValue(item.IconStyle.Color.ToVector4());
618 SolidColorEffect.CurrentTechnique.Passes[0].Apply();
619 item.Draw(spriteBatch,
false,
true);
626 float phase = (float)(Math.Sin(Timing.TotalTime * 3.0f) + 1.0f) / 2.0f;
627 Vector4 overlayColor = Color.Black.ToVector4() * MathHelper.Lerp(0.5f, 0.9f, phase);
628 SolidColorEffect.Parameters[
"color"].SetValue(overlayColor);
629 SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques[
"SolidColorBlur"];
630 SolidColorEffect.CurrentTechnique.Passes[0].Apply();
631 DeformableSprite.Effect.Parameters[
"solidColor"].SetValue(overlayColor);
632 DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
633 spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, samplerState: SamplerState.LinearWrap, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
634 foreach (Entity highlighted
in highlightedEntities)
636 if (highlighted is Item item)
638 SolidColorEffect.Parameters[
"blurDistance"].SetValue(0.02f);
639 item.Draw(spriteBatch,
false,
true);
641 else if (highlighted is Character character)
643 SolidColorEffect.Parameters[
"blurDistance"].SetValue(0.05f);
644 character.Draw(spriteBatch, cam);
650 spriteBatch.Begin(blendState: BlendState.NonPremultiplied, samplerState: SamplerState.LinearWrap);
651 spriteBatch.Draw(highlightRaster,
652 new Rectangle(0, 0, HighlightMap.Width, HighlightMap.Height),
653 new Rectangle(0, 0, (
int)(HighlightMap.Width / currLightMapScale * 0.5f), (
int)(HighlightMap.Height / currLightMapScale * 0.5f)),
657 DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques[
"DeformShader"];
662 private readonly Dictionary<Hull, Rectangle> visibleHulls =
new Dictionary<Hull, Rectangle>();
663 private Dictionary<Hull, Rectangle> GetVisibleHulls(Camera cam)
665 visibleHulls.Clear();
666 foreach (Hull hull
in Hull.HullList)
668 if (hull.IsHidden) {
continue; }
670 hull.Submarine ==
null ?
672 new Rectangle((
int)(hull.Submarine.DrawPosition.X + hull.Rect.X), (
int)(hull.Submarine.DrawPosition.Y + hull.Rect.Y), hull.Rect.Width, hull.Rect.Height);
674 if (drawRect.Right < cam.WorldView.X || drawRect.X > cam.WorldView.Right ||
675 drawRect.Y - drawRect.Height > cam.WorldView.Y || drawRect.Y < cam.WorldView.Y - cam.WorldView.Height)
679 visibleHulls.Add(hull, drawRect);
686 if ((!LosEnabled ||
LosMode ==
LosMode.None) && ObstructVisionAmount <= 0.0f) {
return; }
687 if (ViewTarget ==
null)
return;
689 graphics.SetRenderTarget(LosTexture);
691 if (ObstructVisionAmount > 0.0f)
693 graphics.Clear(Color.Black);
694 Vector2 diff = lookAtPosition - ViewTarget.WorldPosition;
696 if (diff.LengthSquared() > 20.0f * 20.0f) { losOffset = diff; }
697 float rotation = MathUtils.VectorToAngle(losOffset);
700 const float MaxOffset = 256.0f;
702 float MinHorizontalScale = MathHelper.Lerp(3.5f, 1.5f, ObstructVisionAmount);
703 float MaxHorizontalScale = MinHorizontalScale * 1.25f;
704 float VerticalScale = MathHelper.Lerp(4.0f, 1.25f, ObstructVisionAmount);
707 float relativeOriginStartPosition = 0.1f;
708 float originStartPosition = visionCircle.Width * relativeOriginStartPosition * MinHorizontalScale;
709 float relativeOriginLookAtPosModifier = -0.055f;
710 float originLookAtPosModifier = visionCircle.Width * relativeOriginLookAtPosModifier;
712 Vector2 scale =
new Vector2(
713 MathHelper.Clamp(losOffset.Length() / MaxOffset, MinHorizontalScale, MaxHorizontalScale), VerticalScale);
715 spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cam.
Transform * Matrix.CreateScale(
new Vector3(GameSettings.CurrentConfig.Graphics.LightMapScale, GameSettings.CurrentConfig.Graphics.LightMapScale, 1.0f)));
716 spriteBatch.Draw(visionCircle,
new Vector2(ViewTarget.WorldPosition.X, -ViewTarget.WorldPosition.Y),
null, Color.White, rotation,
717 new Vector2(originStartPosition + (scale.X * originLookAtPosModifier), visionCircle.Height / 2), scale, SpriteEffects.None, 0.0f);
722 graphics.Clear(Color.White);
730 Vector2 pos = ViewTarget.DrawPosition;
731 bool centeredOnHead =
false;
736 pos = head.body.DrawPosition;
737 centeredOnHead =
true;
750 foreach (var ch
in convexHulls)
752 if (!ch.Enabled) {
continue; }
753 Vector2 currentViewPos = pos;
754 Vector2 defaultViewPos = ViewTarget.DrawPosition;
755 if (ch.ParentEntity?.Submarine !=
null)
757 defaultViewPos -= ch.ParentEntity.Submarine.DrawPosition;
758 currentViewPos -= ch.ParentEntity.Submarine.DrawPosition;
761 if (ch.LosIntersects(defaultViewPos, currentViewPos))
763 pos = ViewTarget.DrawPosition;
768 if (convexHulls !=
null)
770 List<VertexPositionColor> shadowVerts =
new List<VertexPositionColor>();
771 List<VertexPositionTexture> penumbraVerts =
new List<VertexPositionTexture>();
772 foreach (
ConvexHull convexHull
in convexHulls)
776 Vector2 relativeViewPos = pos;
795 if (shadowVerts.Count > 0)
799 graphics.DrawUserPrimitives(PrimitiveType.TriangleList, shadowVerts.ToArray(), 0, shadowVerts.Count / 3, VertexPositionColor.VertexDeclaration);
801 if (penumbraVerts.Count > 0)
805 graphics.DrawUserPrimitives(PrimitiveType.TriangleList, penumbraVerts.ToArray(), 0, penumbraVerts.Count / 3, VertexPositionTexture.VertexDeclaration);
810 graphics.SetRenderTarget(
null);
815 Vector2 pos = ViewTarget?.Position ?? cam.
Position;
816 spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cam.
Transform);
819 foreach (
ConvexHull convexHull
in convexHulls)
830 activeLights.Clear();
831 activeShadowCastingLights.Clear();
841 Multiplicative =
new BlendState
843 ColorSourceBlend = Blend.DestinationColor,
844 ColorDestinationBlend = Blend.SourceColor,
845 ColorBlendFunction = BlendFunction.Add
848 public static BlendState Multiplicative {
get;
private set; }
static Character? Controlled
readonly AnimController AnimController
static int GraphicsHeight
Action ResolutionChanged
NOTE: Use very carefully. You need to ensure that you ALWAYS unsubscribe from this when you no longer...
static bool ShouldDebugDrawWiring
void DrawElectricity(SpriteBatch spriteBatch)
static IEnumerable< ElectricalDischarger > List
static bool IsPositionAboveLevel(Vector2 worldPosition)
Is the position above the upper boundary of the level ("outside bounds", where nothing should be able...
VertexPositionTexture[] PenumbraVertices
bool Intersects(Rectangle rect)
static List< ConvexHull > GetHullsInRange(Vector2 position, float range, Submarine ParentSub)
static BasicEffect shadowEffect
void DebugDraw(SpriteBatch spriteBatch)
static BasicEffect penumbraEffect
VertexPositionColor[] ShadowVertices
void CalculateLosVertices(Vector2 lightSourcePos)
void DebugDrawLos(SpriteBatch spriteBatch, Camera cam)
float ObstructVisionAmount
RenderTarget2D HighlightMap
LightManager(GraphicsDevice graphics)
RenderTarget2D LosTexture
void AddRayCastTask(LightSource lightSource, Vector2 drawPos, float rotation)
void Update(float deltaTime)
void RemoveLight(LightSource light)
void DebugDrawVertices(SpriteBatch spriteBatch)
static int ActiveLightCount
IEnumerable< LightSource > Lights
void RenderLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, RenderTarget2D backgroundObstructor=null)
RenderTarget2D LimbLightMap
void AddLight(LightSource light)
void UpdateObstructVision(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, Vector2 lookAtPosition)
void RayCastTask(Vector2 drawPos, float rotation)
void DebugDrawVertices(SpriteBatch spriteBatch)
Vector2 LightTextureTargetSize
HashSet< Submarine > HullsUpToDate
static Texture2D LightTexture
LightSourceParams LightSourceParams
float? OverrideLightSpriteAlpha
void UpdateDrawPosition(bool interpolate=true)
Limb GetLimb(LimbType limbType, bool excludeSevered=true, bool excludeLimbsWithSecondaryType=false, bool useSecondaryType=false)
Note that if there are multiple limbs of the same type, only the first (valid) limb is returned.
Vector2 RelativeOrigin
0 - 1
@ Character
Characters only