Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaClient/Source/Screens/GameScreen.cs
Joonas Rikkonen 63eb4d64e5 f8b0295...0671290
2019-03-18 23:30:58 +02:00

385 lines
19 KiB
C#

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System;
using FarseerPhysics;
using System.Diagnostics;
using System.Linq;
namespace Barotrauma
{
partial class GameScreen : Screen
{
private RenderTarget2D renderTargetBackground;
private RenderTarget2D renderTarget;
private RenderTarget2D renderTargetWater;
private RenderTarget2D renderTargetFinal;
private Effect damageEffect;
private Effect postProcessEffect;
private Texture2D damageStencil;
private Texture2D distortTexture;
public Effect PostProcessEffect
{
get { return postProcessEffect; }
}
public GameScreen(GraphicsDevice graphics, ContentManager content)
{
cam = new Camera();
cam.Translate(new Vector2(-10.0f, 50.0f));
CreateRenderTargets(graphics);
GameMain.Instance.OnResolutionChanged += () =>
{
CreateRenderTargets(graphics);
};
#if LINUX || OSX
//var blurEffect = content.Load<Effect>("Effects/blurshader_opengl");
damageEffect = content.Load<Effect>("Effects/damageshader_opengl");
postProcessEffect = content.Load<Effect>("Effects/postprocess_opengl");
#else
//var blurEffect = content.Load<Effect>("Effects/blurshader");
damageEffect = content.Load<Effect>("Effects/damageshader");
postProcessEffect = content.Load<Effect>("Effects/postprocess");
#endif
damageStencil = TextureLoader.FromFile("Content/Map/walldamage.png");
damageEffect.Parameters["xStencil"].SetValue(damageStencil);
damageEffect.Parameters["aMultiplier"].SetValue(50.0f);
damageEffect.Parameters["cMultiplier"].SetValue(200.0f);
distortTexture = TextureLoader.FromFile("Content/Effects/distortnormals.png");
postProcessEffect.Parameters["xDistortTexture"].SetValue(distortTexture);
}
private void CreateRenderTargets(GraphicsDevice graphics)
{
renderTarget?.Dispose();
renderTargetBackground?.Dispose();
renderTargetWater?.Dispose();
renderTargetFinal?.Dispose();
renderTarget = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight, false, SurfaceFormat.Color, DepthFormat.None, 0, RenderTargetUsage.PreserveContents);
renderTargetBackground = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
renderTargetWater = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
renderTargetFinal = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight, false, SurfaceFormat.Color, DepthFormat.None);
}
public override void AddToGUIUpdateList()
{
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != null && Character.Controlled.CanInteractWith(Character.Controlled.SelectedConstruction))
{
Character.Controlled.SelectedConstruction.AddToGUIUpdateList();
}
if (GameMain.GameSession != null) GameMain.GameSession.AddToGUIUpdateList();
Character.AddAllToGUIUpdateList();
}
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
{
cam.UpdateTransform(true);
Submarine.CullEntities(cam);
Stopwatch sw = new Stopwatch();
sw.Start();
DrawMap(graphics, spriteBatch, deltaTime);
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("DrawMap", sw.ElapsedTicks);
sw.Restart();
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, GameMain.ScissorTestEnable);
if (Character.Controlled != null && cam != null) Character.Controlled.DrawHUD(spriteBatch, cam);
if (GameMain.GameSession != null) GameMain.GameSession.Draw(spriteBatch);
if (Character.Controlled == null && !GUI.DisableHUD)
{
for (int i = 0; i < Submarine.MainSubs.Length; i++)
{
if (Submarine.MainSubs[i] == null) continue;
if (Level.Loaded != null && Submarine.MainSubs[i].WorldPosition.Y < Level.MaxEntityDepth) continue;
Color indicatorColor = i == 0 ? Color.LightBlue * 0.5f : Color.Red * 0.5f;
GUI.DrawIndicator(
spriteBatch, Submarine.MainSubs[i].WorldPosition, cam,
Math.Max(Submarine.MainSub.Borders.Width, Submarine.MainSub.Borders.Height),
GUI.SubmarineIcon, indicatorColor);
}
}
GUI.Draw(cam, spriteBatch);
spriteBatch.End();
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("DrawHUD", sw.ElapsedTicks);
sw.Restart();
}
public void DrawMap(GraphicsDevice graphics, SpriteBatch spriteBatch, double deltaTime)
{
foreach (Submarine sub in Submarine.Loaded)
{
sub.UpdateTransform();
}
GameMain.ParticleManager.UpdateTransforms();
GameMain.LightManager.ObstructVision = Character.Controlled != null && Character.Controlled.ObstructVision;
if (Character.Controlled != null)
{
GameMain.LightManager.UpdateObstructVision(graphics, spriteBatch, cam, Character.Controlled.CursorWorldPosition);
}
//------------------------------------------------------------------------
graphics.SetRenderTarget(renderTarget);
graphics.Clear(Color.Transparent);
//Draw resizeable background structures (= background walls) and wall background sprites
//(= the background texture that's revealed when a wall is destroyed) into the background render target
//These will be visible through the LOS effect.
//Could be drawn with one Submarine.DrawBack call, but we can avoid sorting by depth by doing it like this.
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, DepthStencilState.None, null, null, cam.Transform);
Submarine.DrawBack(spriteBatch, false, s => s is Structure && s.ResizeVertical && s.ResizeHorizontal);
Submarine.DrawBack(spriteBatch, false, s => s is Structure && !(s.ResizeVertical && s.ResizeHorizontal) && ((Structure)s).Prefab.BackgroundSprite != null);
spriteBatch.End();
graphics.SetRenderTarget(null);
GameMain.LightManager.UpdateLightMap(graphics, spriteBatch, cam, renderTarget);
//------------------------------------------------------------------------
graphics.SetRenderTarget(renderTargetBackground);
if (Level.Loaded == null)
{
graphics.Clear(new Color(11, 18, 26, 255));
}
else
{
//graphics.Clear(new Color(255, 255, 255, 255));
Level.Loaded.DrawBack(graphics, spriteBatch, cam);
}
//draw alpha blended particles that are in water and behind subs
#if LINUX || OSX
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
#else
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, DepthStencilState.None, null, null, cam.Transform);
#endif
GameMain.ParticleManager.Draw(spriteBatch, true, false, Particles.ParticleBlendState.AlphaBlend);
spriteBatch.End();
//draw additive particles that are in water and behind subs
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.None, null, null, cam.Transform);
GameMain.ParticleManager.Draw(spriteBatch, true, false, Particles.ParticleBlendState.Additive);
spriteBatch.End();
//Draw resizeable background structures (= background walls) and wall background sprites
//(= the background texture that's revealed when a wall is destroyed) into the background render target
//These will be visible through the LOS effect.
//Could be drawn with one Submarine.DrawBack call, but we can avoid sorting by depth by doing it like this.
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, DepthStencilState.None);
spriteBatch.Draw(renderTarget, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
spriteBatch.End();
//----------------------------------------------------------------------------
//Start drawing to the normal render target (stuff that can't be seen through the LOS effect)
graphics.SetRenderTarget(renderTarget);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, DepthStencilState.None, null, null, null);
spriteBatch.Draw(renderTargetBackground, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
spriteBatch.End();
//Draw the rest of the structures, characters and front structures
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, DepthStencilState.None, null, null, cam.Transform);
Submarine.DrawBack(spriteBatch, false, s => !(s is Structure) || !(s.ResizeVertical && s.ResizeHorizontal));
foreach (Character c in Character.CharacterList)
{
if (c.AnimController.Limbs.Any(l => l.DeformSprite != null)) continue;
c.Draw(spriteBatch, Cam);
}
Submarine.DrawFront(spriteBatch, false, null);
spriteBatch.End();
//draw characters with deformable limbs last, because they can't be batched into SpriteBatch
//pretty hacky way of preventing draw order issues between normal and deformable sprites
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, DepthStencilState.None, null, null, cam.Transform);
foreach (Character c in Character.CharacterList)
{
if (c.AnimController.Limbs.All(l => l.DeformSprite == null)) continue;
c.Draw(spriteBatch, Cam);
}
spriteBatch.End();
//draw the rendertarget and particles that are only supposed to be drawn in water into renderTargetWater
graphics.SetRenderTarget(renderTargetWater);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque);
spriteBatch.Draw(renderTarget, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);// waterColor);
spriteBatch.End();
//draw alpha blended particles that are inside a sub
#if LINUX || OSX
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.DepthRead, null, null, cam.Transform);
#else
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, DepthStencilState.DepthRead, null, null, cam.Transform);
#endif
GameMain.ParticleManager.Draw(spriteBatch, true, true, Particles.ParticleBlendState.AlphaBlend);
spriteBatch.End();
graphics.SetRenderTarget(renderTarget);
//draw alpha blended particles that are not in water
#if LINUX || OSX
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.DepthRead, null, null, cam.Transform);
#else
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, DepthStencilState.DepthRead, null, null, cam.Transform);
#endif
GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.AlphaBlend);
spriteBatch.End();
//draw additive particles that are not in water
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.None, null, null, cam.Transform);
GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.Additive);
spriteBatch.End();
graphics.DepthStencilState = DepthStencilState.DepthRead;
graphics.SetRenderTarget(renderTargetFinal);
WaterRenderer.Instance.ResetBuffers();
Hull.UpdateVertices(graphics, cam, WaterRenderer.Instance);
WaterRenderer.Instance.RenderWater(spriteBatch, renderTargetWater, cam);
WaterRenderer.Instance.RenderAir(graphics, cam, renderTarget, Cam.ShaderTransform);
graphics.DepthStencilState = DepthStencilState.None;
spriteBatch.Begin(SpriteSortMode.Immediate,
BlendState.NonPremultiplied, SamplerState.LinearWrap,
null, null,
damageEffect,
cam.Transform);
Submarine.DrawDamageable(spriteBatch, damageEffect, false);
spriteBatch.End();
//draw additive particles that are inside a sub
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.Default, null, null, cam.Transform);
GameMain.ParticleManager.Draw(spriteBatch, true, true, Particles.ParticleBlendState.Additive);
foreach (var discharger in Items.Components.ElectricalDischarger.List)
{
discharger.DrawElectricity(spriteBatch);
}
spriteBatch.End();
if (GameMain.LightManager.LightingEnabled)
{
spriteBatch.Begin(SpriteSortMode.Deferred, Lights.CustomBlendStates.Multiplicative, null, DepthStencilState.None, null, null, null);
spriteBatch.Draw(GameMain.LightManager.LightMap, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
spriteBatch.End();
}
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearWrap, DepthStencilState.None, null, null, cam.Transform);
foreach (Character c in Character.CharacterList) c.DrawFront(spriteBatch, cam);
if (Level.Loaded != null) Level.Loaded.DrawFront(spriteBatch, cam);
if (GameMain.DebugDraw && GameMain.GameSession?.EventManager != null)
{
GameMain.GameSession.EventManager.DebugDraw(spriteBatch);
}
spriteBatch.End();
if (GameMain.LightManager.LosEnabled && GameMain.LightManager.LosMode != LosMode.None && Character.Controlled != null)
{
GameMain.LightManager.LosEffect.CurrentTechnique = GameMain.LightManager.LosEffect.Techniques["LosShader"];
GameMain.LightManager.LosEffect.Parameters["xTexture"].SetValue(renderTargetBackground);
GameMain.LightManager.LosEffect.Parameters["xLosTexture"].SetValue(GameMain.LightManager.LosTexture);
Color losColor;
if (GameMain.LightManager.LosMode == LosMode.Transparent)
{
//convert the los color to HLS and make sure the luminance of the color is always the same
//as the luminance of the ambient light color
float r = Character.Controlled?.CharacterHealth == null ?
0.0f : Math.Min(Character.Controlled.CharacterHealth.DamageOverlayTimer * 0.5f, 0.5f);
Vector3 ambientLightHls = GameMain.LightManager.AmbientLight.RgbToHLS();
Vector3 losColorHls = Color.Lerp(GameMain.LightManager.AmbientLight, Color.Red, r).RgbToHLS();
losColorHls.Y = ambientLightHls.Y;
losColor = ToolBox.HLSToRGB(losColorHls);
}
else
{
losColor = Color.Black;
}
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null, GameMain.LightManager.LosEffect, null);
spriteBatch.Draw(renderTargetBackground, new Rectangle(0, 0, spriteBatch.GraphicsDevice.Viewport.Width, spriteBatch.GraphicsDevice.Viewport.Height), losColor);
spriteBatch.End();
}
graphics.SetRenderTarget(null);
float BlurStrength = 0.0f;
float DistortStrength = 0.0f;
Vector3 chromaticAberrationStrength = GameMain.Config.ChromaticAberrationEnabled ?
new Vector3(-0.02f, -0.01f, 0.0f) : Vector3.Zero;
if (Character.Controlled != null)
{
BlurStrength = Character.Controlled.BlurStrength * 0.005f;
DistortStrength = Character.Controlled.DistortStrength;
chromaticAberrationStrength -= Vector3.One * Character.Controlled.RadialDistortStrength;
chromaticAberrationStrength += new Vector3(-0.03f, -0.015f, 0.0f) * Character.Controlled.ChromaticAberrationStrength;
}
else
{
BlurStrength = 0.0f;
DistortStrength = 0.0f;
}
string postProcessTechnique = "";
if (BlurStrength > 0.0f)
{
postProcessTechnique += "Blur";
postProcessEffect.Parameters["blurDistance"].SetValue(BlurStrength);
}
if (chromaticAberrationStrength != Vector3.Zero)
{
postProcessTechnique += "ChromaticAberration";
postProcessEffect.Parameters["chromaticAberrationStrength"].SetValue(chromaticAberrationStrength);
}
if (DistortStrength > 0.0f)
{
postProcessTechnique += "Distort";
postProcessEffect.Parameters["distortScale"].SetValue(Vector2.One * DistortStrength);
postProcessEffect.Parameters["distortUvOffset"].SetValue(WaterRenderer.Instance.WavePos * 0.001f);
#if LINUX || OSX
postProcessEffect.Parameters["xTexture"].SetValue(distortTexture);
#else
postProcessEffect.Parameters["xTexture"].SetValue(renderTargetFinal);
#endif
}
if (string.IsNullOrEmpty(postProcessTechnique))
{
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None);
}
else
{
postProcessEffect.CurrentTechnique = postProcessEffect.Techniques[postProcessTechnique];
postProcessEffect.CurrentTechnique.Passes[0].Apply();
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, effect: postProcessEffect);
}
#if LINUX || OSX
spriteBatch.Draw(renderTargetFinal, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
#else
spriteBatch.Draw(DistortStrength > 0.0f ? distortTexture : renderTargetFinal, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
#endif
spriteBatch.End();
}
}
}