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> activeLightsWithLightVolume =
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 activeLightsWithLightVolume.Clear();
319 foreach (var activeLight
in activeLights)
321 if (activeLight.Range < 1.0f || activeLight.Color.A < 1 || activeLight.CurrentBrightness <= 0.0f) {
continue; }
322 activeLightsWithLightVolume.Add(activeLight);
326 if (activeLightsWithLightVolume.Count > GameSettings.CurrentConfig.Graphics.VisibleLightLimit &&
Screen.
Selected is { IsEditor:
false })
328 for (
int i = GameSettings.CurrentConfig.Graphics.VisibleLightLimit; i < activeLightsWithLightVolume.Count; i++)
330 activeLights.Remove(activeLightsWithLightVolume[i]);
333 activeLights.Sort((l1, l2) => l1.LastRecalculationTime.CompareTo(l2.LastRecalculationTime));
340 graphics.Clear(Color.Black);
341 graphics.BlendState = BlendState.NonPremultiplied;
342 spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
343 foreach (LightSource light
in activeLights)
345 if (light.IsBackground || light.CurrentBrightness <= 0.0f) {
continue; }
347 if (light.ParentBody?.UserData is Limb limb && !limb.Hide) { light.DrawSprite(spriteBatch, cam); }
355 graphics.BlendState = BlendState.Additive;
356 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
357 Level.Loaded?.BackgroundCreatureManager?.DrawLights(spriteBatch, cam);
358 foreach (LightSource light
in activeLights)
360 if (!light.IsBackground || light.CurrentBrightness <= 0.0f) {
continue; }
361 light.DrawLightVolume(spriteBatch, lightEffect, transform, recalculationCount < MaxLightVolumeRecalculationsPerFrame, ref recalculationCount);
362 light.DrawSprite(spriteBatch, cam);
364 GameMain.ParticleManager.Draw(spriteBatch,
true,
null, Particles.ParticleBlendState.Additive);
370 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, transformMatrix: spriteBatchTransform);
371 Dictionary<Hull, Rectangle> visibleHulls = GetVisibleHulls(cam);
372 foreach (KeyValuePair<Hull, Rectangle> hull
in visibleHulls)
374 GUI.DrawRectangle(spriteBatch,
375 new Vector2(hull.Value.X, -hull.Value.Y),
376 new Vector2(hull.Value.Width, hull.Value.Height),
377 hull.Key.AmbientLight == Color.TransparentBlack ? Color.Black : hull.Key.AmbientLight.Multiply(hull.Key.AmbientLight.A / 255.0f),
true);
381 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
383 glowColorHSV.Z = Math.Max(glowColorHSV.Z, 0.4f);
384 Color glowColor = ToolBoxCore.HSVToRGB(glowColorHSV.X, glowColorHSV.Y, glowColorHSV.Z);
385 Vector2 glowSpriteSize =
new Vector2(gapGlowTexture.Width, gapGlowTexture.Height);
386 foreach (var gap
in Gap.GapList)
388 if (gap.IsRoomToRoom || gap.Open <= 0.0f || gap.ConnectedWall ==
null) {
continue; }
390 float a = MathHelper.Lerp(0.5f, 1.0f,
391 PerlinNoise.GetPerlin((
float)Timing.TotalTime * 0.05f, gap.GlowEffectT));
393 float scale = MathHelper.Lerp(0.5f, 2.0f,
394 PerlinNoise.GetPerlin((
float)Timing.TotalTime * 0.01f, gap.GlowEffectT));
396 float rot = PerlinNoise.GetPerlin((
float)Timing.TotalTime * 0.001f, gap.GlowEffectT) * MathHelper.TwoPi;
398 Vector2 spriteScale =
new Vector2(gap.Rect.Width, gap.Rect.Height) / glowSpriteSize;
399 Vector2 drawPos =
new Vector2(gap.DrawPosition.X, -gap.DrawPosition.Y);
401 spriteBatch.Draw(gapGlowTexture,
407 scale: Math.Max(spriteScale.X, spriteScale.Y) * scale,
413 GameMain.GameScreen.DamageEffect.CurrentTechnique = GameMain.GameScreen.DamageEffect.Techniques[
"StencilShaderSolidColor"];
414 GameMain.GameScreen.DamageEffect.Parameters[
"solidColor"].SetValue(Color.Black.ToVector4());
415 spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, SamplerState.LinearWrap, transformMatrix: spriteBatchTransform, effect: GameMain.GameScreen.DamageEffect);
416 Submarine.DrawDamageable(spriteBatch, GameMain.GameScreen.DamageEffect);
419 graphics.BlendState = BlendState.Additive;
424 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
425 foreach (LightSource light
in activeLights)
428 if (light.IsBackground || light.ParentBody?.UserData is Limb || light.CurrentBrightness <= 0.0f) {
continue; }
429 light.DrawSprite(spriteBatch, cam);
433 if (highlightsVisible)
435 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
436 spriteBatch.Draw(
HighlightMap, Vector2.Zero, Color.White);
442 if (cam.Zoom > ObstructLightsBehindCharactersZoomThreshold)
445 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect:
SolidColorEffect, transformMatrix: spriteBatchTransform);
446 DrawCharacters(spriteBatch, cam, drawDeformSprites:
false);
449 DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques[
"DeformShaderSolidVertexColor"];
450 DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
451 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
452 DrawCharacters(spriteBatch, cam, drawDeformSprites:
true);
456 static void DrawCharacters(SpriteBatch spriteBatch, Camera cam,
bool drawDeformSprites)
458 foreach (Character character
in Character.CharacterList)
460 if (character.CurrentHull ==
null || !character.Enabled || !character.IsVisible || character.InvisibleTimer > 0.0f) {
continue; }
461 if (
Character.Controlled?.FocusedCharacter == character) {
continue; }
462 Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
464 character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
465 foreach (Limb limb
in character.AnimController.Limbs)
467 if (drawDeformSprites == (limb.DeformSprite ==
null)) {
continue; }
468 limb.Draw(spriteBatch, cam, lightColor);
470 foreach (var heldItem
in character.HeldItems)
472 heldItem.Draw(spriteBatch, editing:
false, overrideColor: Color.Black);
477 DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques[
"DeformShader"];
478 graphics.BlendState = BlendState.Additive;
482 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
484 spriteBatch.Draw(
LimbLightMap,
new Rectangle(cam.WorldView.X, -cam.WorldView.Y, cam.WorldView.Width, cam.WorldView.Height), Color.White);
491 foreach (LightSource light
in activeLights)
493 if (light.IsBackground || light.CurrentBrightness <= 0.0f) {
continue; }
494 light.DrawLightVolume(spriteBatch, lightEffect, transform, recalculationCount < MaxLightVolumeRecalculationsPerFrame, ref recalculationCount);
499 foreach (MapEntity e
in (
Submarine.VisibleEntities ?? MapEntity.MapEntityList))
501 if (e is Item item && !item.IsHidden && item.GetComponent<
Wire>() is
Wire wire)
503 wire.DebugDraw(spriteBatch, alpha: 0.4f);
508 lightEffect.World = transform;
510 GameMain.ParticleManager.Draw(spriteBatch,
false,
null, Particles.ParticleBlendState.Additive);
518 foreach (Character character
in Character.CharacterList)
520 if (character.Submarine ==
null || character.IsDead || !character.IsHuman) {
continue; }
525 void DrawHalo(Character character)
527 if (character ==
null || character.Removed) {
return; }
528 Vector2 haloDrawPos = character.DrawPosition;
529 haloDrawPos.Y = -haloDrawPos.Y;
533 Color haloColor = Color.White.Multiply(0.3f - ambientBrightness);
536 float scale = 512.0f / LightSource.LightTexture.Width;
538 LightSource.LightTexture, haloDrawPos,
null, haloColor, 0.0f,
539 new Vector2(LightSource.LightTexture.Width, LightSource.LightTexture.Height) / 2, scale, SpriteEffects.None, 0.0f);
548 graphics.SetRenderTarget(
null);
549 graphics.BlendState = BlendState.NonPremultiplied;
552 private readonly List<Entity> highlightedEntities =
new List<Entity>();
554 private bool UpdateHighlights(GraphicsDevice graphics, SpriteBatch spriteBatch, Matrix spriteBatchTransform, Camera cam)
556 if (GUI.DisableItemHighlights) {
return false; }
558 highlightedEntities.Clear();
561 if (
Character.Controlled.FocusedItem !=
null)
563 highlightedEntities.Add(
Character.Controlled.FocusedItem);
565 if (
Character.Controlled.FocusedCharacter !=
null)
567 highlightedEntities.Add(
Character.Controlled.FocusedCharacter);
569 foreach (MapEntity me
in MapEntity.HighlightedEntities)
571 if (me is Item item && item !=
Character.Controlled.FocusedItem)
573 highlightedEntities.Add(item);
577 if (highlightedEntities.Count == 0) {
return false; }
580 graphics.SetRenderTarget(HighlightMap);
581 SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques[
"SolidColor"];
582 SolidColorEffect.Parameters[
"color"].SetValue(Color.LightBlue.ToVector4());
583 SolidColorEffect.CurrentTechnique.Passes[0].Apply();
584 DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques[
"DeformShaderSolidColor"];
585 DeformableSprite.Effect.Parameters[
"solidColor"].SetValue(Color.LightBlue.ToVector4());
586 DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
587 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, samplerState: SamplerState.LinearWrap, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
588 foreach (Entity highlighted
in highlightedEntities)
590 if (highlighted is Item item)
592 if (item.IconStyle !=
null && (item !=
Character.Controlled.FocusedItem ||
Character.Controlled.FocusedItem ==
null))
598 item.Draw(spriteBatch,
false,
true);
601 else if (highlighted is Character character)
603 character.Draw(spriteBatch, cam);
609 spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive, samplerState: SamplerState.LinearWrap, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
610 foreach (Entity highlighted
in highlightedEntities)
612 if (highlighted is Item item)
614 if (item.IconStyle !=
null && (item !=
Character.Controlled.FocusedItem ||
Character.Controlled.FocusedItem ==
null))
616 SolidColorEffect.Parameters[
"color"].SetValue(item.IconStyle.Color.ToVector4());
617 SolidColorEffect.CurrentTechnique.Passes[0].Apply();
618 item.Draw(spriteBatch,
false,
true);
625 float phase = (float)(Math.Sin(Timing.TotalTime * 3.0f) + 1.0f) / 2.0f;
626 Vector4 overlayColor = Color.Black.ToVector4() * MathHelper.Lerp(0.5f, 0.9f, phase);
627 SolidColorEffect.Parameters[
"color"].SetValue(overlayColor);
628 SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques[
"SolidColorBlur"];
629 SolidColorEffect.CurrentTechnique.Passes[0].Apply();
630 DeformableSprite.Effect.Parameters[
"solidColor"].SetValue(overlayColor);
631 DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
632 spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, samplerState: SamplerState.LinearWrap, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
633 foreach (Entity highlighted
in highlightedEntities)
635 if (highlighted is Item item)
637 SolidColorEffect.Parameters[
"blurDistance"].SetValue(0.02f);
638 item.Draw(spriteBatch,
false,
true);
640 else if (highlighted is Character character)
642 SolidColorEffect.Parameters[
"blurDistance"].SetValue(0.05f);
643 character.Draw(spriteBatch, cam);
649 spriteBatch.Begin(blendState: BlendState.NonPremultiplied, samplerState: SamplerState.LinearWrap);
650 spriteBatch.Draw(highlightRaster,
651 new Rectangle(0, 0, HighlightMap.Width, HighlightMap.Height),
652 new Rectangle(0, 0, (
int)(HighlightMap.Width / currLightMapScale * 0.5f), (
int)(HighlightMap.Height / currLightMapScale * 0.5f)),
656 DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques[
"DeformShader"];
661 private readonly Dictionary<Hull, Rectangle> visibleHulls =
new Dictionary<Hull, Rectangle>();
662 private Dictionary<Hull, Rectangle> GetVisibleHulls(Camera cam)
664 visibleHulls.Clear();
665 foreach (Hull hull
in Hull.HullList)
667 if (hull.IsHidden) {
continue; }
669 hull.Submarine ==
null ?
671 new Rectangle((
int)(hull.Submarine.DrawPosition.X + hull.Rect.X), (
int)(hull.Submarine.DrawPosition.Y + hull.Rect.Y), hull.Rect.Width, hull.Rect.Height);
673 if (drawRect.Right < cam.WorldView.X || drawRect.X > cam.WorldView.Right ||
674 drawRect.Y - drawRect.Height > cam.WorldView.Y || drawRect.Y < cam.WorldView.Y - cam.WorldView.Height)
678 visibleHulls.Add(hull, drawRect);
685 if ((!LosEnabled ||
LosMode ==
LosMode.None) && ObstructVisionAmount <= 0.0f) {
return; }
686 if (ViewTarget ==
null)
return;
688 graphics.SetRenderTarget(LosTexture);
690 if (ObstructVisionAmount > 0.0f)
692 graphics.Clear(Color.Black);
693 Vector2 diff = lookAtPosition - ViewTarget.WorldPosition;
695 if (diff.LengthSquared() > 20.0f * 20.0f) { losOffset = diff; }
696 float rotation = MathUtils.VectorToAngle(losOffset);
699 const float MaxOffset = 256.0f;
701 float MinHorizontalScale = MathHelper.Lerp(3.5f, 1.5f, ObstructVisionAmount);
702 float MaxHorizontalScale = MinHorizontalScale * 1.25f;
703 float VerticalScale = MathHelper.Lerp(4.0f, 1.25f, ObstructVisionAmount);
706 float relativeOriginStartPosition = 0.1f;
707 float originStartPosition = visionCircle.Width * relativeOriginStartPosition * MinHorizontalScale;
708 float relativeOriginLookAtPosModifier = -0.055f;
709 float originLookAtPosModifier = visionCircle.Width * relativeOriginLookAtPosModifier;
711 Vector2 scale =
new Vector2(
712 MathHelper.Clamp(losOffset.Length() / MaxOffset, MinHorizontalScale, MaxHorizontalScale), VerticalScale);
714 spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cam.
Transform * Matrix.CreateScale(
new Vector3(GameSettings.CurrentConfig.Graphics.LightMapScale, GameSettings.CurrentConfig.Graphics.LightMapScale, 1.0f)));
715 spriteBatch.Draw(visionCircle,
new Vector2(ViewTarget.WorldPosition.X, -ViewTarget.WorldPosition.Y),
null, Color.White, rotation,
716 new Vector2(originStartPosition + (scale.X * originLookAtPosModifier), visionCircle.Height / 2), scale, SpriteEffects.None, 0.0f);
721 graphics.Clear(Color.White);
729 Vector2 pos = ViewTarget.DrawPosition;
730 bool centeredOnHead =
false;
735 pos = head.body.DrawPosition;
736 centeredOnHead =
true;
749 foreach (var ch
in convexHulls)
751 if (!ch.Enabled) {
continue; }
752 Vector2 currentViewPos = pos;
753 Vector2 defaultViewPos = ViewTarget.DrawPosition;
754 if (ch.ParentEntity?.Submarine !=
null)
756 defaultViewPos -= ch.ParentEntity.Submarine.DrawPosition;
757 currentViewPos -= ch.ParentEntity.Submarine.DrawPosition;
760 if (ch.LosIntersects(defaultViewPos, currentViewPos))
762 pos = ViewTarget.DrawPosition;
767 if (convexHulls !=
null)
769 List<VertexPositionColor> shadowVerts =
new List<VertexPositionColor>();
770 List<VertexPositionTexture> penumbraVerts =
new List<VertexPositionTexture>();
771 foreach (
ConvexHull convexHull
in convexHulls)
775 Vector2 relativeViewPos = pos;
794 if (shadowVerts.Count > 0)
798 graphics.DrawUserPrimitives(PrimitiveType.TriangleList, shadowVerts.ToArray(), 0, shadowVerts.Count / 3, VertexPositionColor.VertexDeclaration);
800 if (penumbraVerts.Count > 0)
804 graphics.DrawUserPrimitives(PrimitiveType.TriangleList, penumbraVerts.ToArray(), 0, penumbraVerts.Count / 3, VertexPositionTexture.VertexDeclaration);
809 graphics.SetRenderTarget(
null);
814 Vector2 pos = ViewTarget?.Position ?? cam.
Position;
815 spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cam.
Transform);
818 foreach (
ConvexHull convexHull
in convexHulls)
829 activeLights.Clear();
830 activeLightsWithLightVolume.Clear();
840 Multiplicative =
new BlendState
842 ColorSourceBlend = Blend.DestinationColor,
843 ColorDestinationBlend = Blend.SourceColor,
844 ColorBlendFunction = BlendFunction.Add
847 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
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)
Note that if there are multiple limbs of the same type, only the first (valid) limb is returned.
Vector2 RelativeOrigin
0 - 1