示例#1
0
        public void UpdateLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, RenderTarget2D backgroundObstructor = null)
        {
            if (!LightingEnabled)
            {
                return;
            }

            if (Math.Abs(currLightMapScale - GameMain.Config.LightMapScale) > 0.01f)
            {
                //lightmap scale has changed -> recreate render targets
                CreateRenderTargets(graphics);
            }

            Matrix spriteBatchTransform = cam.Transform * Matrix.CreateScale(new Vector3(GameMain.Config.LightMapScale, GameMain.Config.LightMapScale, 1.0f));
            Matrix transform            = cam.ShaderTransform
                                          * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f;

            bool highlightsVisible = UpdateHighlights(graphics, spriteBatch, spriteBatchTransform, cam);

            Rectangle viewRect = cam.WorldView;

            viewRect.Y -= cam.WorldView.Height;
            //check which lights need to be drawn
            activeLights.Clear();
            foreach (LightSource light in lights)
            {
                if (!light.Enabled)
                {
                    continue;
                }
                if ((light.Color.A < 1 || light.Range < 1.0f) && !light.LightSourceParams.OverrideLightSpriteAlpha.HasValue)
                {
                    continue;
                }
                if (light.ParentBody != null)
                {
                    light.Position = light.ParentBody.DrawPosition;
                    if (light.ParentSub != null)
                    {
                        light.Position -= light.ParentSub.DrawPosition;
                    }
                }

                float range = light.LightSourceParams.TextureRange;
                if (light.LightSprite != null)
                {
                    float spriteRange = Math.Max(
                        light.LightSprite.size.X * light.SpriteScale.X * (0.5f + Math.Abs(light.LightSprite.RelativeOrigin.X - 0.5f)),
                        light.LightSprite.size.Y * light.SpriteScale.Y * (0.5f + Math.Abs(light.LightSprite.RelativeOrigin.Y - 0.5f)));
                    range = Math.Max(spriteRange, range);
                }
                if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, range, viewRect))
                {
                    continue;
                }
                activeLights.Add(light);
            }

            //draw light sprites attached to characters
            //render into a separate rendertarget using alpha blending (instead of on top of everything else with alpha blending)
            //to prevent the lights from showing through other characters or other light sprites attached to the same character
            //---------------------------------------------------------------------------------------------------
            graphics.SetRenderTarget(LimbLightMap);
            graphics.Clear(Color.Black);
            graphics.BlendState = BlendState.NonPremultiplied;
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
            foreach (LightSource light in activeLights)
            {
                if (light.IsBackground)
                {
                    continue;
                }
                //draw limb lights at this point, because they were skipped over previously to prevent them from being obstructed
                if (light.ParentBody?.UserData is Limb)
                {
                    light.DrawSprite(spriteBatch, cam);
                }
            }
            spriteBatch.End();

            //draw background lights
            //---------------------------------------------------------------------------------------------------
            graphics.SetRenderTarget(LightMap);
            graphics.Clear(AmbientLight);
            graphics.BlendState = BlendState.Additive;
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
            foreach (LightSource light in activeLights)
            {
                if (!light.IsBackground)
                {
                    continue;
                }
                light.DrawSprite(spriteBatch, cam);
                light.DrawLightVolume(spriteBatch, lightEffect, transform);
            }
            GameMain.ParticleManager.Draw(spriteBatch, true, null, Particles.ParticleBlendState.Additive);
            spriteBatch.End();

            //draw a black rectangle on hulls to hide background lights behind subs
            //---------------------------------------------------------------------------------------------------

            if (backgroundObstructor != null)
            {
                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
                spriteBatch.Draw(backgroundObstructor, new Rectangle(0, 0,
                                                                     (int)(GameMain.GraphicsWidth * currLightMapScale), (int)(GameMain.GraphicsHeight * currLightMapScale)), Color.Black);
                spriteBatch.End();
            }

            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, transformMatrix: spriteBatchTransform);
            Dictionary <Hull, Rectangle> visibleHulls = GetVisibleHulls(cam);

            foreach (KeyValuePair <Hull, Rectangle> hull in visibleHulls)
            {
                GUI.DrawRectangle(spriteBatch,
                                  new Vector2(hull.Value.X, -hull.Value.Y),
                                  new Vector2(hull.Value.Width, hull.Value.Height),
                                  hull.Key.AmbientLight == Color.TransparentBlack ? Color.Black : hull.Key.AmbientLight.Multiply(hull.Key.AmbientLight.A / 255.0f), true);
            }
            spriteBatch.End();

            SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColor"];
            SolidColorEffect.Parameters["color"].SetValue(AmbientLight.ToVector4());
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform, effect: SolidColorEffect);
            Submarine.DrawDamageable(spriteBatch, null);
            spriteBatch.End();

            graphics.BlendState = BlendState.Additive;


            //draw the focused item and character to highlight them,
            //and light sprites (done before drawing the actual light volumes so we can make characters obstruct the highlights and sprites)
            //---------------------------------------------------------------------------------------------------
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
            foreach (LightSource light in activeLights)
            {
                //don't draw limb lights at this point, they need to be drawn after lights have been obstructed by characters
                if (light.IsBackground || light.ParentBody?.UserData is Limb)
                {
                    continue;
                }
                light.DrawSprite(spriteBatch, cam);
            }
            spriteBatch.End();

            if (highlightsVisible)
            {
                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
                spriteBatch.Draw(HighlightMap, Vector2.Zero, Color.White);
                spriteBatch.End();
            }

            //draw characters to obstruct the highlighted items/characters and light sprites
            //---------------------------------------------------------------------------------------------------

            SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidVertexColor"];
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
            foreach (Character character in Character.CharacterList)
            {
                if (character.CurrentHull == null || !character.Enabled || !character.IsVisible)
                {
                    continue;
                }
                if (Character.Controlled?.FocusedCharacter == character)
                {
                    continue;
                }
                Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
                                   Color.Black :
                                   character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
                foreach (Limb limb in character.AnimController.Limbs)
                {
                    if (limb.DeformSprite != null)
                    {
                        continue;
                    }
                    limb.Draw(spriteBatch, cam, lightColor);
                }
            }
            spriteBatch.End();

            DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShaderSolidVertexColor"];
            DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
            foreach (Character character in Character.CharacterList)
            {
                if (character.CurrentHull == null || !character.Enabled || !character.IsVisible)
                {
                    continue;
                }
                if (Character.Controlled?.FocusedCharacter == character)
                {
                    continue;
                }
                Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
                                   Color.Black :
                                   character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
                foreach (Limb limb in character.AnimController.Limbs)
                {
                    if (limb.DeformSprite == null)
                    {
                        continue;
                    }
                    limb.Draw(spriteBatch, cam, lightColor);
                }
            }
            spriteBatch.End();
            DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShader"];
            graphics.BlendState = BlendState.Additive;

            //draw the actual light volumes, additive particles, hull ambient lights and the halo around the player
            //---------------------------------------------------------------------------------------------------
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);

            spriteBatch.Draw(LimbLightMap, new Rectangle(cam.WorldView.X, -cam.WorldView.Y, cam.WorldView.Width, cam.WorldView.Height), Color.White);

            foreach (ElectricalDischarger discharger in ElectricalDischarger.List)
            {
                discharger.DrawElectricity(spriteBatch);
            }

            foreach (LightSource light in activeLights)
            {
                if (light.IsBackground)
                {
                    continue;
                }
                light.DrawLightVolume(spriteBatch, lightEffect, transform);
            }

            lightEffect.World = transform;

            GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.Additive);

            if (Character.Controlled != null)
            {
                DrawHalo(Character.Controlled);
            }
            else
            {
                foreach (Character character in Character.CharacterList)
                {
                    if (character.Submarine == null || character.IsDead || !character.IsHuman)
                    {
                        continue;
                    }
                    DrawHalo(character);
                }
            }

            void DrawHalo(Character character)
            {
                Vector2 haloDrawPos = character.DrawPosition;

                haloDrawPos.Y = -haloDrawPos.Y;

                //ambient light decreases the brightness of the halo (no need for a bright halo if the ambient light is bright enough)
                float ambientBrightness = (AmbientLight.R + AmbientLight.B + AmbientLight.G) / 255.0f / 3.0f;
                Color haloColor         = Color.White.Multiply(0.3f - ambientBrightness);

                if (haloColor.A > 0)
                {
                    float scale = 512.0f / LightSource.LightTexture.Width;
                    spriteBatch.Draw(
                        LightSource.LightTexture, haloDrawPos, null, haloColor, 0.0f,
                        new Vector2(LightSource.LightTexture.Width, LightSource.LightTexture.Height) / 2, scale, SpriteEffects.None, 0.0f);
                }
            }

            spriteBatch.End();

            //draw the actual light volumes, additive particles, hull ambient lights and the halo around the player
            //---------------------------------------------------------------------------------------------------

            graphics.SetRenderTarget(null);
            graphics.BlendState = BlendState.NonPremultiplied;
        }