From 8df9133e84a828d8d0bb19e4f7f5bbb1d90623d0 Mon Sep 17 00:00:00 2001 From: Regalis11 Date: Sun, 11 Oct 2015 21:04:42 +0300 Subject: [PATCH] Lighting optimization (caching shadow vertices & only checking hulls in range if the position or range of the light changes), ragdoll optimization, itemcomponent optimization, dragging stunned/dead characters --- .../Source/Characters/AnimController.cs | 1 + Subsurface/Source/Characters/Character.cs | 40 +++-- Subsurface/Source/Characters/CharacterHUD.cs | 2 +- .../Source/Characters/FishAnimController.cs | 6 +- .../Characters/HumanoidAnimController.cs | 144 +++++++++++------- Subsurface/Source/DebugConsole.cs | 2 +- Subsurface/Source/GameMain.cs | 2 +- .../Source/Items/Components/ItemComponent.cs | 28 ++-- .../{Container.cs => ItemContainer.cs} | 30 ++-- .../Items/Components/Signal/LightComponent.cs | 18 +-- .../Source/Items/Components/Signal/Wire.cs | 2 + Subsurface/Source/Items/Inventory.cs | 2 +- Subsurface/Source/Items/Item.cs | 8 +- Subsurface/Source/Map/Hull.cs | 13 +- Subsurface/Source/Map/Levels/Level.cs | 31 ---- Subsurface/Source/Map/Lights/ConvexHull.cs | 79 ++++++++-- Subsurface/Source/Map/Lights/LightManager.cs | 43 ++++-- Subsurface/Source/Map/Lights/LightSource.cs | 38 ++++- Subsurface/Source/Map/MapEntity.cs | 42 ++++- Subsurface/Source/Map/Submarine.cs | 4 +- Subsurface/Source/Map/WayPoint.cs | 8 + Subsurface/Source/PlayerInput.cs | 7 +- Subsurface/Source/Screens/GameScreen.cs | 16 +- Subsurface/Subsurface.csproj | 2 +- Subsurface_Solution.sln | 10 +- 25 files changed, 377 insertions(+), 201 deletions(-) rename Subsurface/Source/Items/Components/{Container.cs => ItemContainer.cs} (91%) diff --git a/Subsurface/Source/Characters/AnimController.cs b/Subsurface/Source/Characters/AnimController.cs index f2574a8eb..ef64d4aab 100644 --- a/Subsurface/Source/Characters/AnimController.cs +++ b/Subsurface/Source/Characters/AnimController.cs @@ -57,5 +57,6 @@ namespace Subsurface public virtual void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle) { } + public virtual void DragCharacter(Character target) { } } } diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index 20c15154b..2d868a6f8 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -578,14 +578,14 @@ namespace Subsurface maxDist = ConvertUnits.ToSimUnits(maxDist); - foreach (Character c in Character.CharacterList) + foreach (Character c in CharacterList) { if (c == this) continue; if (Vector2.Distance(SimPosition, c.SimPosition) > maxDist) continue; float dist = Vector2.Distance(mouseSimPos, c.SimPosition); - if (dist < maxDist && closestCharacter==null || dist /// Control the character according to player input /// @@ -659,7 +675,7 @@ namespace Subsurface closestCharacter = FindClosestCharacter(mouseSimPos); if (closestCharacter != null) { - if (closestCharacter != selectedCharacter) selectedCharacter = null; + // if (closestCharacter != selectedCharacter) selectedCharacter = null; if (!closestCharacter.IsHumanoid) closestCharacter = null; } @@ -697,21 +713,25 @@ namespace Subsurface } else { - if (Vector2.Distance(selectedCharacter.SimPosition, SimPosition) > 2.0f) selectedCharacter = null; + if (Vector2.Distance(selectedCharacter.SimPosition, SimPosition) > 2.0f || + (!selectedCharacter.isDead && selectedCharacter.Stun <= 0.0f)) + { + ToggleSelectedCharacter(selectedCharacter); + } } if (GetInputState(InputType.Select)) { if (selectedCharacter != null) { - selectedCharacter = null; + ToggleSelectedCharacter(selectedCharacter); } - else if (closestCharacter != null && closestCharacter.isDead && closestCharacter.IsHumanoid) + else if (closestCharacter != null && closestCharacter.IsHumanoid && + (closestCharacter.isDead || closestCharacter.AnimController.StunTimer > 0.0f)) { selectedCharacter = closestCharacter; } - } - + } DisableControls = false; } @@ -741,7 +761,7 @@ namespace Subsurface public virtual void Update(Camera cam, float deltaTime) { - //AnimController.SimplePhysicsEnabled = (Character.controlled!=this && Vector2.Distance(cam.WorldViewCenter, Position)>5000.0f); + AnimController.SimplePhysicsEnabled = (Character.controlled!=this && Vector2.Distance(cam.WorldViewCenter, Position)>5000.0f); if (isDead) return; @@ -825,7 +845,7 @@ namespace Subsurface Vector2 pos = ConvertUnits.ToDisplayUnits(AnimController.Limbs[0].SimPosition); pos.Y = -pos.Y; - if (this == Character.controlled) return; + if (this == controlled) return; if (IsNetworkPlayer) { diff --git a/Subsurface/Source/Characters/CharacterHUD.cs b/Subsurface/Source/Characters/CharacterHUD.cs index 703fc9108..576641154 100644 --- a/Subsurface/Source/Characters/CharacterHUD.cs +++ b/Subsurface/Source/Characters/CharacterHUD.cs @@ -54,7 +54,7 @@ namespace Subsurface //if (Vector2.Distance(selectedCharacter.SimPosition, SimPosition) > 2.0f) selectedCharacter = null; } - if (character.ClosestCharacter != null && character.ClosestCharacter.IsDead) + if (character.ClosestCharacter != null && (character.ClosestCharacter.IsDead || character.ClosestCharacter.Stun > 0.0f)) { Vector2 startPos = character.Position + (character.ClosestCharacter.Position - character.Position) * 0.7f; startPos = cam.WorldToScreen(startPos); diff --git a/Subsurface/Source/Characters/FishAnimController.cs b/Subsurface/Source/Characters/FishAnimController.cs index 096a9193b..a0bfc27b8 100644 --- a/Subsurface/Source/Characters/FishAnimController.cs +++ b/Subsurface/Source/Characters/FishAnimController.cs @@ -225,11 +225,9 @@ namespace Subsurface RefLimb.body.Rotation + MathUtils.GetShortestAngle(RefLimb.body.Rotation, movementAngle) : HeadAngle*Dir); - RefLimb.pullJoint.Enabled = true; - RefLimb.pullJoint.WorldAnchorB = - RefLimb.SimPosition + movement * 0.1f; + RefLimb.body.LinearVelocity = movement; - RefLimb.body.SmoothRotate(0.0f); + //RefLimb.body.SmoothRotate(0.0f); foreach (Limb l in Limbs) { diff --git a/Subsurface/Source/Characters/HumanoidAnimController.cs b/Subsurface/Source/Characters/HumanoidAnimController.cs index 062b66cce..0b633fe01 100644 --- a/Subsurface/Source/Characters/HumanoidAnimController.cs +++ b/Subsurface/Source/Characters/HumanoidAnimController.cs @@ -36,66 +36,77 @@ namespace Subsurface //if (inWater) stairs = null; + if (onFloorTimer <= 0.0f && !SimplePhysicsEnabled) + { Vector2 rayStart = colliderPos; // at the bottom of the player sprite Vector2 rayEnd = rayStart - new Vector2(0.0f, TorsoPosition); if (stairs != null) rayEnd.Y -= 0.5f; - if (Anim != Animation.UsingConstruction) ResetPullJoints(); - - //do a raytrace straight down from the torso to figure - //out whether the ragdoll is standing on ground - float closestFraction = 1; - Structure closestStructure = null; - GameMain.World.RayCast((fixture, point, normal, fraction) => - { - switch (fixture.CollisionCategories) + //do a raytrace straight down from the torso to figure + //out whether the ragdoll is standing on ground + float closestFraction = 1; + Structure closestStructure = null; + GameMain.World.RayCast((fixture, point, normal, fraction) => { - case Physics.CollisionStairs: - if (inWater && TargetMovement.Y < 0.5f) return -1; + switch (fixture.CollisionCategories) + { + case Physics.CollisionStairs: + if (inWater && TargetMovement.Y < 0.5f) return -1; + Structure structure = fixture.Body.UserData as Structure; + if (stairs == null && structure != null) + { + if (LowestLimb.SimPosition.Y < structure.SimPosition.Y) + { + return -1; + } + else + { + stairs = structure; + } + } + break; + case Physics.CollisionPlatform: + Structure platform = fixture.Body.UserData as Structure; + if (IgnorePlatforms || LowestLimb.Position.Y < platform.Rect.Y) return -1; + break; + case Physics.CollisionWall: + break; + default: + return -1; + } + + onGround = true; + if (fraction < closestFraction) + { + closestFraction = fraction; + Structure structure = fixture.Body.UserData as Structure; - if (stairs == null && structure != null) - { - if (LowestLimb.SimPosition.Y < structure.SimPosition.Y) - { - return -1; - } - else - { - stairs = structure; - } - } - break; - case Physics.CollisionPlatform: - Structure platform = fixture.Body.UserData as Structure; - if (IgnorePlatforms || LowestLimb.Position.Y < platform.Rect.Y) return -1; - break; - case Physics.CollisionWall: - break; - default: - return -1; + if (structure != null) closestStructure = structure; + } + onFloorTimer = 0.05f; + return closestFraction; } + , rayStart, rayEnd); - onGround = true; - if (fraction < closestFraction) + if (closestStructure != null && closestStructure.StairDirection != Direction.None) { - closestFraction = fraction; - - Structure structure = fixture.Body.UserData as Structure; - if (structure != null) closestStructure = structure; + stairs = closestStructure; + } + else + { + stairs = null; } - onFloorTimer = 0.05f; - return closestFraction; - } - , rayStart, rayEnd); - if (closestStructure != null && closestStructure.StairDirection != Direction.None) - { - stairs = closestStructure; - } - else - { - stairs = null; + if (closestFraction == 1) //raycast didn't hit anything + { + floorY = (currentHull == null) ? -1000.0f : ConvertUnits.ToSimUnits(currentHull.Rect.Y - currentHull.Rect.Height); + } + else + { + floorY = rayStart.Y + (rayEnd.Y - rayStart.Y) * closestFraction; + } } + //the ragdoll "stays on ground" for 50 millisecs after separation if (onFloorTimer <= 0.0f) { @@ -110,15 +121,6 @@ namespace Subsurface onFloorTimer -= deltaTime; } - if (closestFraction == 1) //raycast didn't hit anything - { - floorY = (currentHull == null) ? -1000.0f : ConvertUnits.ToSimUnits(currentHull.Rect.Y - currentHull.Rect.Height); - } - else - { - floorY = rayStart.Y + (rayEnd.Y - rayStart.Y) * closestFraction; - } - IgnorePlatforms = (TargetMovement.Y < 0.0f); @@ -131,11 +133,12 @@ namespace Subsurface if (stunTimer > 0) { - //UpdateStruggling(); stunTimer -= deltaTime; return; } + if (Anim != Animation.UsingConstruction) ResetPullJoints(); + if (TargetDir != dir) Flip(); if (SimplePhysicsEnabled) @@ -191,6 +194,10 @@ namespace Subsurface Limb leftLeg = GetLimb(LimbType.LeftLeg); Limb rightLeg = GetLimb(LimbType.RightLeg); + if (character.SelectedCharacter != null) DragCharacter(character.SelectedCharacter); + + + float getUpSpeed = 0.3f; float walkCycleSpeed = head.LinearVelocity.X * walkAnimSpeed; if (stairs != null) @@ -751,6 +758,27 @@ namespace Subsurface // } //} + public override void DragCharacter(Character target) + { + Limb leftHand = GetLimb(LimbType.LeftHand); + Limb rightHand = GetLimb(LimbType.RightHand); + + leftHand.Disabled = true; + rightHand.Disabled = true; + + Limb targetLimb = target.AnimController.GetLimb(LimbType.LeftHand); + + leftHand.pullJoint.Enabled = true; + leftHand.pullJoint.WorldAnchorB = targetLimb.SimPosition; + rightHand.pullJoint.Enabled = true; + rightHand.pullJoint.WorldAnchorB = targetLimb.SimPosition; + + targetLimb.pullJoint.Enabled = true; + targetLimb.pullJoint.WorldAnchorB = leftHand.SimPosition; + + target.AnimController.IgnorePlatforms = IgnorePlatforms; + } + public override void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle) { //calculate the handle positions diff --git a/Subsurface/Source/DebugConsole.cs b/Subsurface/Source/DebugConsole.cs index 796d37b65..5677314ff 100644 --- a/Subsurface/Source/DebugConsole.cs +++ b/Subsurface/Source/DebugConsole.cs @@ -141,7 +141,7 @@ namespace Subsurface public static void ExecuteCommand(string command, GameMain game) { #if !DEBUG - if (Game1.Client!=null) + if (GameMain.Client!=null) { ThrowError("Console commands are disabled in multiplayer mode"); return; diff --git a/Subsurface/Source/GameMain.cs b/Subsurface/Source/GameMain.cs index 3d27c205e..b2cad1462 100644 --- a/Subsurface/Source/GameMain.cs +++ b/Subsurface/Source/GameMain.cs @@ -128,7 +128,7 @@ namespace Subsurface World = new World(new Vector2(0, -9.82f)); FarseerPhysics.Settings.AllowSleep = true; FarseerPhysics.Settings.ContinuousPhysics = false; - FarseerPhysics.Settings.VelocityIterations = 2; + FarseerPhysics.Settings.VelocityIterations = 1; FarseerPhysics.Settings.PositionIterations = 1; } diff --git a/Subsurface/Source/Items/Components/ItemComponent.cs b/Subsurface/Source/Items/Components/ItemComponent.cs index 5b75efbb1..94d299c96 100644 --- a/Subsurface/Source/Items/Components/ItemComponent.cs +++ b/Subsurface/Source/Items/Components/ItemComponent.cs @@ -282,6 +282,12 @@ namespace Subsurface.Items.Components private int loopingSoundIndex; public void PlaySound(ActionType type, Vector2 position) { + if (loopingSound != null) + { + loopingSoundIndex = loopingSound.Sound.Loop(loopingSoundIndex, GetSoundVolume(loopingSound), position, loopingSound.Range); + return; + } + List matchingSounds = sounds.FindAll(x => x.Type == type); if (matchingSounds.Count == 0) return; @@ -292,24 +298,18 @@ namespace Subsurface.Items.Components itemSound = matchingSounds[index]; } + if (itemSound == null) return; - if (loopingSound!=null) + if (itemSound.Loop) { - loopingSoundIndex = loopingSound.Sound.Loop(loopingSoundIndex, GetSoundVolume(loopingSound), position, loopingSound.Range); + loopingSound = itemSound; } - else if (itemSound!=null) + else { - if (itemSound.Loop) - { - loopingSound = itemSound; - } - else - { - float volume = GetSoundVolume(itemSound); - if (volume == 0.0f) return; - itemSound.Sound.Play(volume, itemSound.Range, position); - } - } + float volume = GetSoundVolume(itemSound); + if (volume == 0.0f) return; + itemSound.Sound.Play(volume, itemSound.Range, position); + } } public void StopSounds(ActionType type) diff --git a/Subsurface/Source/Items/Components/Container.cs b/Subsurface/Source/Items/Components/ItemContainer.cs similarity index 91% rename from Subsurface/Source/Items/Components/Container.cs rename to Subsurface/Source/Items/Components/ItemContainer.cs index e1638b337..d795cca74 100644 --- a/Subsurface/Source/Items/Components/Container.cs +++ b/Subsurface/Source/Items/Components/ItemContainer.cs @@ -12,6 +12,8 @@ namespace Subsurface.Items.Components List containableItems; public ItemInventory inventory; + private bool hasStatusEffects; + //how many items can be contained [HasDefaultValue(5, false)] public int Capacity @@ -89,12 +91,6 @@ namespace Subsurface.Items.Components { inventory = new ItemInventory(this, capacity, hudPos, slotsPerRow); containableItems = new List(); - - //itemPos = ToolBox.GetAttributeVector2(element, "ItemPos", Vector2.Zero); - //itemPos = ConvertUnits.ToSimUnits(itemPos); - - //itemInterval = ToolBox.GetAttributeVector2(element, "ItemInterval", Vector2.Zero); - //itemInterval = ConvertUnits.ToSimUnits(itemInterval); foreach (XElement subElement in element.Elements()) { @@ -102,7 +98,15 @@ namespace Subsurface.Items.Components { case "containable": RelatedItem containable = RelatedItem.Load(subElement); - if (containable!=null) containableItems.Add(containable); + if (containable == null) continue; + + foreach (StatusEffect effect in containable.statusEffects) + { + if (effect.type == ActionType.OnContaining) hasStatusEffects = true; + } + + containableItems.Add(containable); + break; } } @@ -121,11 +125,12 @@ namespace Subsurface.Items.Components public override void Update(float deltaTime, Camera cam) { + if (!hasStatusEffects) return; + foreach (Item contained in inventory.items) { - if (contained == null || contained.Condition<=0.0f) continue; - - if (contained.body!=null) contained.body.Enabled = false; + if (contained == null || contained.Condition <= 0.0f) continue; + //if (contained.body != null) contained.body.Enabled = false; RelatedItem ri = containableItems.Find(x => x.MatchesItem(contained)); if (ri == null) continue; @@ -136,16 +141,15 @@ namespace Subsurface.Items.Components if (effect.Targets.HasFlag(StatusEffect.TargetType.Contained)) effect.Apply(ActionType.OnContaining, deltaTime, item, contained.AllPropertyObjects); } - contained.ApplyStatusEffects(ActionType.OnContained, deltaTime); + //contained.ApplyStatusEffects(ActionType.OnContained, deltaTime); } - } public override void Draw(SpriteBatch spriteBatch, bool editing) { base.Draw(spriteBatch); - if (hideItems || (item.body!=null && !item.body.Enabled)) return; + if (hideItems || (item.body != null && !item.body.Enabled)) return; Vector2 transformedItemPos = itemPos; Vector2 transformedItemInterval = itemInterval; diff --git a/Subsurface/Source/Items/Components/Signal/LightComponent.cs b/Subsurface/Source/Items/Components/Signal/LightComponent.cs index 29c0e5660..d9e790142 100644 --- a/Subsurface/Source/Items/Components/Signal/LightComponent.cs +++ b/Subsurface/Source/Items/Components/Signal/LightComponent.cs @@ -79,23 +79,22 @@ namespace Subsurface.Items.Components //lightColor = new Color(ToolBox.GetAttributeVector4(element, "color", Vector4.One)); } - + public override void Update(float deltaTime, Camera cam) { base.Update(deltaTime, cam); - - if (item.body != null) - { - light.Position = ConvertUnits.ToDisplayUnits(item.body.SimPosition); - } - - Pickable pickable = item.GetComponent(); - if (item.container!= null) + + if (item.container != null) { light.Color = Color.Transparent; return; } + if (item.body != null) + { + light.Position = ConvertUnits.ToDisplayUnits(item.body.SimPosition); + } + if (powerConsumption == 0.0f) { voltage = 1.0f; @@ -116,7 +115,6 @@ namespace Subsurface.Items.Components } light.Color = lightColor * lightBrightness * (1.0f-Rand.Range(0.0f,Flicker)); - light.Range = range * (float)Math.Sqrt(lightBrightness); voltage = 0.0f; diff --git a/Subsurface/Source/Items/Components/Signal/Wire.cs b/Subsurface/Source/Items/Components/Signal/Wire.cs index cdd8a64bd..f5e36e768 100644 --- a/Subsurface/Source/Items/Components/Signal/Wire.cs +++ b/Subsurface/Source/Items/Components/Signal/Wire.cs @@ -35,6 +35,8 @@ namespace Subsurface.Items.Components Nodes = new List(); connections = new Connection[2]; + + IsActive = false; } public override void Move(Vector2 amount) diff --git a/Subsurface/Source/Items/Inventory.cs b/Subsurface/Source/Items/Inventory.cs index e9d83d45b..9acced92c 100644 --- a/Subsurface/Source/Items/Inventory.cs +++ b/Subsurface/Source/Items/Inventory.cs @@ -116,7 +116,7 @@ namespace Subsurface items[i] = item; item.inventory = this; - if (item.body!=null) + if (item.body != null) { item.body.Enabled = false; } diff --git a/Subsurface/Source/Items/Item.cs b/Subsurface/Source/Items/Item.cs index f8a2fc131..d12a04d76 100644 --- a/Subsurface/Source/Items/Item.cs +++ b/Subsurface/Source/Items/Item.cs @@ -488,6 +488,8 @@ namespace Subsurface } ic.WasUsed = false; + if (container != null) ic.ApplyStatusEffects(ActionType.OnContained, deltaTime); + if (!ic.IsActive) continue; if (condition > 0.0f) @@ -495,7 +497,7 @@ namespace Subsurface ic.Update(deltaTime, cam); ic.PlaySound(ActionType.OnActive, Position); - ic.ApplyStatusEffects(ActionType.OnActive, deltaTime, null); + ic.ApplyStatusEffects(ActionType.OnActive, deltaTime, null); } else { @@ -505,7 +507,7 @@ namespace Subsurface if (body == null || !body.Enabled) return; - if (body.LinearVelocity.Length() > 0.001f) + if (Math.Abs(body.LinearVelocity.X) > 0.01f || Math.Abs(body.LinearVelocity.Y) > 0.01f) { FindHull(); @@ -808,7 +810,7 @@ namespace Subsurface if (body != null && body.UserData as Item != item) continue; dist = Vector2.Distance(pickPosition, item.SimPosition); - if ((closest == null || dist < closestDist)) + if (dist < item.prefab.PickDistance && (closest == null || dist < closestDist)) { closest = item; closestDist = dist; diff --git a/Subsurface/Source/Map/Hull.cs b/Subsurface/Source/Map/Hull.cs index 9ed1a8c4d..c2d9d0d58 100644 --- a/Subsurface/Source/Map/Hull.cs +++ b/Subsurface/Source/Map/Hull.cs @@ -50,6 +50,14 @@ namespace Subsurface float lastSentVolume; + public override string Name + { + get + { + return "Hull"; + } + } + public override bool IsLinkable { get { return true; } @@ -202,7 +210,7 @@ namespace Subsurface waveY[(int)(position.X - rect.X) / WaveWidth] = 100.0f; Volume = Volume + 1500.0f; } - else if (PlayerInput.GetMouseState.RightButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed) + else if (PlayerInput.RightButtonDown()) { Volume = Volume - 1500.0f; } @@ -210,12 +218,11 @@ namespace Subsurface } //update client hulls if the amount of water has changed by >10% - if (Math.Abs(lastSentVolume-volume)>FullVolume*0.1f) + if (Math.Abs(lastSentVolume - volume) > FullVolume * 0.1f) { new Networking.NetworkEvent(ID, false); lastSentVolume = volume; } - if (!update) return; float surfaceY = rect.Y - rect.Height + Volume / rect.Width; diff --git a/Subsurface/Source/Map/Levels/Level.cs b/Subsurface/Source/Map/Levels/Level.cs index 582852b28..36df15671 100644 --- a/Subsurface/Source/Map/Levels/Level.cs +++ b/Subsurface/Source/Map/Levels/Level.cs @@ -852,37 +852,6 @@ int currentTargetIndex = 1; Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f); - - //pos = startPosition; - //pos.X += Position.X; - //pos.Y = -pos.Y - Position.Y; - - //spriteBatch.Draw(shaftTexture, - // new Rectangle((int)(pos.X - shaftWidth/2), (int)pos.Y, shaftWidth, 512), - // new Rectangle(0, 0, shaftWidth, 256), - // Color.White, 0.0f, - // Vector2.Zero, - // SpriteEffects.None, 0.0f); - - //List edges = GetCellEdges(observerPosition, 1, false); - - //foreach (VoronoiCell cell in cells) - //{ - // for (int i = 0; i < cell.bodyVertices.Count - 1; i++) - // { - // Vector2 start = cell.bodyVertices[i]; - // start.X += Position.X; - // start.Y = -start.Y - Position.Y; - // start.X += Rand.Range(-10.0f, 10.0f); - - // Vector2 end = cell.bodyVertices[i + 1]; - // end.X += Position.X; - // end.Y = -end.Y - Position.Y; - // end.X += Rand.Range(-10.0f, 10.0f); - - // GUI.DrawLine(spriteBatch, start, end, (cell.body != null && cell.body.Enabled) ? Color.Red : Color.Red); - // } - //} } public List GetCells(Vector2 pos, int searchDepth = 2) diff --git a/Subsurface/Source/Map/Lights/ConvexHull.cs b/Subsurface/Source/Map/Lights/ConvexHull.cs index d069705a6..901f95490 100644 --- a/Subsurface/Source/Map/Lights/ConvexHull.cs +++ b/Subsurface/Source/Map/Lights/ConvexHull.cs @@ -5,11 +5,30 @@ using System.Linq; namespace Subsurface.Lights { + class CachedShadow + { + + public VertexPositionColor[] ShadowVertices; + public VertexPositionTexture[] PenumbraVertices; + + public Vector2 LightPos; + + public CachedShadow(VertexPositionColor[] shadowVertices, VertexPositionTexture[] penumbraVertices, Vector2 lightPos) + { + ShadowVertices = shadowVertices; + PenumbraVertices = penumbraVertices; + + LightPos = lightPos; + } + } + class ConvexHull { public static List list = new List(); static BasicEffect shadowEffect; static BasicEffect penumbraEffect; + + private Dictionary cachedShadows; private Vector2[] vertices; private int primitiveCount; @@ -47,19 +66,14 @@ namespace Subsurface.Lights penumbraEffect.LightingEnabled = false; penumbraEffect.Texture = TextureLoader.FromFile("Content/Lights/penumbra.png"); } + + cachedShadows = new Dictionary(); vertices = points; primitiveCount = vertices.Length; CalculateDimensions(); - //indices = new short[primitiveCount * 3]; - - //for (int i = 0; i < primitiveCount; i++) - //{ - // indices[3 * i] = (short)i; - // indices[3 * i + 1] = (short)((i + 1) % vertexCount); - // indices[3 * i + 2] = (short)vertexCount; - //} + backFacing = new bool[primitiveCount]; Enabled = true; @@ -90,6 +104,8 @@ namespace Subsurface.Lights public void Move(Vector2 amount) { + cachedShadows.Clear(); + for (int i = 0; i < vertices.Count(); i++) { vertices[i] += amount; @@ -100,6 +116,8 @@ namespace Subsurface.Lights public void SetVertices(Vector2[] points) { + cachedShadows.Clear(); + vertices = points; } @@ -222,25 +240,62 @@ namespace Subsurface.Lights } } + public void DrawShadows(GraphicsDevice graphicsDevice, Camera cam, LightSource light, Matrix transform, bool los = true) + { + if (!Enabled) return; + + CachedShadow cachedShadow = null; + if (cachedShadows.TryGetValue(light, out cachedShadow)) + { + if (light.Position == cachedShadow.LightPos || + Vector2.DistanceSquared(light.Position, cachedShadow.LightPos) < 1.0f) + { + shadowVertices = cachedShadow.ShadowVertices; + penumbraVertices = cachedShadow.PenumbraVertices; + + } + else + { + CalculateShadowVertices(light.Position, los); + cachedShadow.LightPos = light.Position; + cachedShadow.ShadowVertices = shadowVertices; + cachedShadow.PenumbraVertices = penumbraVertices; + + } + } + else + { + CalculateShadowVertices(light.Position, los); + cachedShadow = new CachedShadow(shadowVertices, penumbraVertices, light.Position); + cachedShadows.Add(light, cachedShadow); + } + + DrawShadows(graphicsDevice, cam, transform, los); + } + public void DrawShadows(GraphicsDevice graphicsDevice, Camera cam, Vector2 lightSourcePos, Matrix transform, bool los = true) { if (!Enabled) return; CalculateShadowVertices(lightSourcePos, los); - + DrawShadows(graphicsDevice, cam, transform, los); + } + + private void DrawShadows(GraphicsDevice graphicsDevice, Camera cam, Matrix transform, bool los = true) + { shadowEffect.World = transform; shadowEffect.CurrentTechnique.Passes[0].Apply(); - graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, shadowVertices, 0, shadowVertices.Length - 2); - + graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, shadowVertices, 0, shadowVertices.Length - 2); + if (los) { penumbraEffect.World = shadowEffect.World; penumbraEffect.CurrentTechnique.Passes[0].Apply(); #if WINDOWS - graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, penumbraVertices, 0, 2, VertexPositionTexture.VertexDeclaration); + graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, penumbraVertices, 0, 2, VertexPositionTexture.VertexDeclaration); #endif } } diff --git a/Subsurface/Source/Map/Lights/LightManager.cs b/Subsurface/Source/Map/Lights/LightManager.cs index 2f53ce7f5..b6d3d57e9 100644 --- a/Subsurface/Source/Map/Lights/LightManager.cs +++ b/Subsurface/Source/Map/Lights/LightManager.cs @@ -57,12 +57,13 @@ namespace Subsurface.Lights public void DrawLOS(GraphicsDevice graphics, Camera cam, Vector2 pos) { + if (!LosEnabled) return; + 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; - if (!LosEnabled) return; foreach (ConvexHull convexHull in ConvexHull.list) { if (!camView.Intersects(convexHull.BoundingBox)) continue; @@ -72,6 +73,14 @@ namespace Subsurface.Lights } + public void OnMapLoaded() + { + foreach (LightSource light in lights) + { + light.UpdateHullsInRange(); + } + } + public void DrawLightmap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam) { Matrix shadowTransform = cam.ShaderTransform @@ -81,28 +90,28 @@ namespace Subsurface.Lights Rectangle viewRect = cam.WorldView; viewRect.Y -= cam.WorldView.Height; - + //clear to some small ambient light graphics.Clear(AmbientLight); foreach (LightSource light in lights) { - if (light.Color.A < 0.01f || light.Range < 0.01f) continue; - //clear alpha to 1 - ClearAlphaToOne(graphics, spriteBatch); - + if (light.Color.A < 0.01f || light.Range < 0.01f || light.hullsInRange.Count == 0) continue; if (!MathUtils.CircleIntersectsRectangle(light.Position, light.Range, viewRect)) continue; - + + //clear alpha to 1 + ClearAlphaToOne(graphics, spriteBatch); + //draw all shadows //write only to the alpha channel, which sets alpha to 0 graphics.RasterizerState = RasterizerState.CullNone; graphics.BlendState = CustomBlendStates.WriteToAlpha; - foreach (ConvexHull ch in ConvexHull.list) + foreach (ConvexHull ch in light.hullsInRange) { - if (!MathUtils.CircleIntersectsRectangle(light.Position, light.Range, ch.BoundingBox)) continue; + //if (!MathUtils.CircleIntersectsRectangle(light.Position, light.Range, ch.BoundingBox)) continue; //draw shadow - ch.DrawShadows(graphics, cam, light.Position, shadowTransform, false); + ch.DrawShadows(graphics, cam, light, shadowTransform, false); } //draw the light shape @@ -111,6 +120,20 @@ namespace Subsurface.Lights light.Draw(spriteBatch); spriteBatch.End(); } + + //ClearAlphaToOne(graphics, spriteBatch); + //spriteBatch.Begin(SpriteSortMode.Immediate, CustomBlendStates.MultiplyWithAlpha, null, null, null, null, cam.Transform); + + //foreach (LightSource light in lights) + //{ + // if (light.Color.A < 0.01f || light.Range < 0.01f || light.hullsInRange.Count > 0) continue; + // if (!MathUtils.CircleIntersectsRectangle(light.Position, light.Range, viewRect)) continue; + + // light.Draw(spriteBatch); + //} + + //spriteBatch.End(); + //clear alpha, to avoid messing stuff up later ClearAlphaToOne(graphics, spriteBatch); graphics.SetRenderTarget(null); diff --git a/Subsurface/Source/Map/Lights/LightSource.cs b/Subsurface/Source/Map/Lights/LightSource.cs index 8798a6e0e..d96b532c9 100644 --- a/Subsurface/Source/Map/Lights/LightSource.cs +++ b/Subsurface/Source/Map/Lights/LightSource.cs @@ -11,13 +11,26 @@ namespace Subsurface.Lights { private static Texture2D lightTexture; + public List hullsInRange; + private Color color; private float range; private Texture2D texture; - public Vector2 Position; + private Vector2 position; + public Vector2 Position + { + get { return position; } + set + { + if (position == value) return; + + position = value; + UpdateHullsInRange(); + } + } public Color Color { @@ -30,13 +43,19 @@ namespace Subsurface.Lights get { return range; } set { - range = MathHelper.Clamp(value, 0.0f, 2048.0f); + float newRange = MathHelper.Clamp(value, 0.0f, 2048.0f); + if (range == newRange) return; + range = newRange; + + UpdateHullsInRange(); } } public LightSource(Vector2 position, float range, Color color) { - Position = position; + hullsInRange = new List(); + + this.position = position; this.range = range; this.color = color; @@ -50,10 +69,21 @@ namespace Subsurface.Lights GameMain.LightManager.AddLight(this); } + public void UpdateHullsInRange() + { + hullsInRange.Clear(); + if (range < 1.0f) return; + + foreach (ConvexHull ch in ConvexHull.list) + { + if (MathUtils.CircleIntersectsRectangle(position, range, ch.BoundingBox)) hullsInRange.Add(ch); + } + } + public void Draw(SpriteBatch spriteBatch) { Vector2 center = new Vector2(lightTexture.Width / 2, lightTexture.Height / 2); - float scale = range / ((float)lightTexture.Width / 2.0f); + float scale = range / (lightTexture.Width / 2.0f); spriteBatch.Draw(lightTexture, new Vector2(Position.X, -Position.Y), null, color, 0, center, scale, SpriteEffects.None, 1); } diff --git a/Subsurface/Source/Map/MapEntity.cs b/Subsurface/Source/Map/MapEntity.cs index bf86dc7f1..9c8fad1ba 100644 --- a/Subsurface/Source/Map/MapEntity.cs +++ b/Subsurface/Source/Map/MapEntity.cs @@ -192,6 +192,8 @@ namespace Subsurface } } + static Dictionary timeElapsed = new Dictionary(); + /// /// Call Update() on every object in Entity.list /// @@ -202,10 +204,46 @@ namespace Subsurface item.Updated = false; } - for (int i = 0; i < mapEntityList.Count; i++) + foreach (Hull hull in Hull.hullList) { - mapEntityList[i].Update(cam, deltaTime); + hull.Update(cam, deltaTime); } + + foreach (Gap gap in Gap.GapList) + { + gap.Update(cam, deltaTime); + } + + foreach (Item item in Item.itemList) + { + item.Update(cam, deltaTime); + } + + //Stopwatch sw = new Stopwatch(); + + //for (int i = 0; i < mapEntityList.Count; i++) + //{ + // sw.Restart(); + // mapEntityList[i].Update(cam, deltaTime); + // sw.Stop(); + + // if (timeElapsed.ContainsKey(mapEntityList[i].Name)) + // { + // float asd = 0.0f; + // timeElapsed.TryGetValue(mapEntityList[i].Name, out asd); + // asd += sw.ElapsedTicks; + + // timeElapsed.Remove(mapEntityList[i].Name); + // timeElapsed.Add(mapEntityList[i].Name, asd); + // } + // else + // { + // timeElapsed.Add(mapEntityList[i].Name, sw.ElapsedTicks); + // } + //} + + + } public virtual void Update(Camera cam, float deltaTime) { } diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index d766cb5f2..1b6da89a9 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -609,7 +609,7 @@ namespace Subsurface subBody = new SubmarineBody(this); MapEntity.OnMapLoaded(); - + foreach (Item item in Item.itemList) { foreach (ItemComponent ic in item.components) @@ -618,6 +618,8 @@ namespace Subsurface } } + GameMain.LightManager.OnMapLoaded(); + ID = int.MaxValue-10; loaded = this; diff --git a/Subsurface/Source/Map/WayPoint.cs b/Subsurface/Source/Map/WayPoint.cs index bcfca1136..416acebd8 100644 --- a/Subsurface/Source/Map/WayPoint.cs +++ b/Subsurface/Source/Map/WayPoint.cs @@ -29,6 +29,14 @@ namespace Subsurface set { spawnType = value; } } + public override string Name + { + get + { + return "WayPoint"; + } + } + public string[] IdCardTags { get { return idCardTags; } diff --git a/Subsurface/Source/PlayerInput.cs b/Subsurface/Source/PlayerInput.cs index 89cfad5a3..0eca9b249 100644 --- a/Subsurface/Source/PlayerInput.cs +++ b/Subsurface/Source/PlayerInput.cs @@ -127,7 +127,12 @@ namespace Subsurface && mouseState.LeftButton == ButtonState.Released); } - public static bool RightButtonClicked() + public static bool RightButtonDown() + { + return mouseState.RightButton == ButtonState.Pressed; + } + + public static bool RightButtonClicked() { return (oldMouseState.RightButton == ButtonState.Pressed && mouseState.RightButton == ButtonState.Released); diff --git a/Subsurface/Source/Screens/GameScreen.cs b/Subsurface/Source/Screens/GameScreen.cs index 972793247..113a25503 100644 --- a/Subsurface/Source/Screens/GameScreen.cs +++ b/Subsurface/Source/Screens/GameScreen.cs @@ -158,7 +158,7 @@ namespace Subsurface public void DrawMap(GraphicsDevice graphics, SpriteBatch spriteBatch) { - GameMain.LightManager.DrawLightmap(graphics, spriteBatch, cam); + if (GameMain.LightManager.LightingEnabled) GameMain.LightManager.DrawLightmap(graphics, spriteBatch, cam); //---------------------------------------------------------------------------------------- //1. draw the background, characters and the parts of the submarine that are behind them @@ -267,17 +267,7 @@ namespace Subsurface } Hull.renderer.Render(graphics, cam, renderTargetAir, Cam.ShaderTransform); - - spriteBatch.Begin(SpriteSortMode.BackToFront, - BlendState.AlphaBlend, SamplerState.LinearWrap, - null, null, null, - cam.Transform); - - Submarine.DrawFront(spriteBatch); - - spriteBatch.End(); - - + if (GameMain.GameSession != null && GameMain.GameSession.Level != null) { GameMain.GameSession.Level.Render(graphics, cam); @@ -303,6 +293,8 @@ namespace Subsurface foreach (Character c in Character.CharacterList) c.DrawFront(spriteBatch); + Submarine.DrawFront(spriteBatch); + if (GameMain.GameSession != null && GameMain.GameSession.Level != null) { GameMain.GameSession.Level.Draw(spriteBatch); diff --git a/Subsurface/Subsurface.csproj b/Subsurface/Subsurface.csproj index 6cfc53da0..0373a9e8e 100644 --- a/Subsurface/Subsurface.csproj +++ b/Subsurface/Subsurface.csproj @@ -148,7 +148,7 @@ - + diff --git a/Subsurface_Solution.sln b/Subsurface_Solution.sln index 441d727e0..d1bf602ec 100644 --- a/Subsurface_Solution.sln +++ b/Subsurface_Solution.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Subsurface", "Subsurface\Subsurface.csproj", "{008C0F83-E914-4966-9135-EA885059EDD8}" EndProject @@ -20,9 +20,6 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrashReporter", "CrashReporter\CrashReporter.csproj", "{6BE950CD-9A34-49C9-939A-786AC89C287E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D32A29D8-AC7B-4189-B734-8ED9EB4120D0}" - ProjectSection(SolutionItems) = preProject - Performance1.psess = Performance1.psess - EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -401,7 +398,4 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection EndGlobal