diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs index 21e09f991c..93e8257913 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs @@ -1,12 +1,78 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using JetBrains.Annotations; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Catch.Mods { - public class CatchModFlashlight : ModFlashlight + public class CatchModFlashlight : ModFlashlight { public override double ScoreMultiplier => 1.12; + + private const float default_flashlight_size = 350; + + public override Flashlight CreateFlashlight() => new CatchFlashlight(playfield); + + private CatchPlayfield playfield; + + public override void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + { + playfield = (CatchPlayfield)rulesetContainer.Playfield; + base.ApplyToRulesetContainer(rulesetContainer); + } + + private class CatchFlashlight : Flashlight + { + private readonly CatchPlayfield playfield; + + public CatchFlashlight(CatchPlayfield playfield) + { + this.playfield = playfield; + MousePosWrapper.CircularFlashlightSize = getSizeFor(0); + MousePosWrapper.Rectangular = false; + } + + protected override void Update() + { + base.Update(); + + MousePosWrapper.FlashlightPosition = (playfield.CatcherArea.MovableCatcher.ScreenSpaceDrawQuad.TopLeft + playfield.CatcherArea.MovableCatcher.ScreenSpaceDrawQuad.TopRight) / 2; + MousePosWrapper.FlashlightPositionChanged = true; + } + + [UsedImplicitly] + private float flashlightSize + { + set + { + if (MousePosWrapper.CircularFlashlightSize == value) return; + + MousePosWrapper.CircularFlashlightSize = value; + MousePosWrapper.CircularFlashlightSizeChanged = true; + } + + get => MousePosWrapper.CircularFlashlightSize; + } + + private float getSizeFor(int combo) + { + if (combo > 200) + return default_flashlight_size * 0.8f; + else if (combo > 100) + return default_flashlight_size * 0.9f; + else + return default_flashlight_size; + } + + protected override void OnComboChange(int newCombo) + { + this.TransformTo(nameof(flashlightSize), getSizeFor(newCombo), FLASHLIGHT_FADE_DURATION); + } + } } } diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 925e7aaac9..b121d6814b 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.UI { public const float BASE_WIDTH = 512; - private readonly CatcherArea catcherArea; + internal readonly CatcherArea CatcherArea; protected override bool UserScrollSpeedAdjustment => false; @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Catch.UI { RelativeSizeAxes = Axes.Both, }, - catcherArea = new CatcherArea(difficulty) + CatcherArea = new CatcherArea(difficulty) { GetVisualRepresentation = getVisualRepresentation, ExplodingFruitTarget = explodingFruitContainer, @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Catch.UI VisibleTimeRange.Value = BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450); } - public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.AttemptCatch(obj); + public bool CheckIfWeCanCatch(CatchHitObject obj) => CatcherArea.AttemptCatch(obj); public override void Add(DrawableHitObject h) { @@ -72,6 +72,6 @@ namespace osu.Game.Rulesets.Catch.UI } private void onNewResult(DrawableHitObject judgedObject, JudgementResult result) - => catcherArea.OnResult((DrawableCatchHitObject)judgedObject, result); + => CatcherArea.OnResult((DrawableCatchHitObject)judgedObject, result); } } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 06453ac32d..8661a3c162 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.UI { public const float CATCHER_SIZE = 100; - protected readonly Catcher MovableCatcher; + protected internal readonly Catcher MovableCatcher; public Func> GetVisualRepresentation; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs index 08815ede09..73942cbb53 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs @@ -3,6 +3,7 @@ using System; using osu.Game.Graphics; +using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Mania.Mods @@ -16,6 +17,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override string Description => @"Keys appear out of nowhere!"; public override double ScoreMultiplier => 1; public override bool Ranked => true; - public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) }; + public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) }; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs index d7a1bc4fbe..be45bb7296 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs @@ -2,13 +2,59 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; +using OpenTK; namespace osu.Game.Rulesets.Mania.Mods { - public class ManiaModFlashlight : ModFlashlight + public class ManiaModFlashlight : ModFlashlight { public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(ModHidden) }; + + private const float default_flashlight_size = 180; + + public override Flashlight CreateFlashlight() => new ManiaFlashlight(); + + private class ManiaFlashlight : Flashlight + { + public ManiaFlashlight() + { + MousePosWrapper.Rectangular = true; + MousePosWrapper.RectangularFlashlightSize = new Vector2(0, default_flashlight_size); + } + + public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) + { + if ((invalidation & Invalidation.DrawSize) > 0) + { + Schedule(() => + { + MousePosWrapper.RectangularFlashlightSize.X = DrawWidth; + MousePosWrapper.RectangularFlashlightSizeChanged = true; + + MousePosWrapper.FlashlightPosition = ScreenSpaceDrawQuad.Centre; + MousePosWrapper.FlashlightPositionChanged = true; + }); + } + + return base.Invalidate(invalidation, source, shallPropagate); + } + + protected override void OnComboChange(int newCombo) + { + } + + protected override void LoadComplete() + { + MousePosWrapper.RectangularFlashlightSize.X = DrawWidth; + MousePosWrapper.RectangularFlashlightSizeChanged = true; + + MousePosWrapper.FlashlightPosition = ScreenSpaceDrawQuad.Centre; + MousePosWrapper.FlashlightPositionChanged = true; + } + } } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index 2ef68a35fa..9bc2502a8f 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Mania.Mods @@ -10,6 +11,6 @@ namespace osu.Game.Rulesets.Mania.Mods { public override string Description => @"Keys fade out before you hit them!"; public override double ScoreMultiplier => 1; - public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) }; + public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) }; } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index c6b6d67ce6..a5f803f726 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs @@ -1,95 +1,65 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; -using osu.Framework.Allocation; +using JetBrains.Annotations; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Vertices; -using osu.Framework.Graphics.Primitives; -using osu.Framework.Graphics.Shaders; -using osu.Framework.Graphics.Textures; using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.UI; -using OpenTK; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModFlashlight : ModFlashlight, IApplicableToRulesetContainer + public class OsuModFlashlight : ModFlashlight { public override double ScoreMultiplier => 1.12; - public void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + private const float default_flashlight_size = 180; + + public override Flashlight CreateFlashlight() => new OsuFlashlight(); + + private class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition { - rulesetContainer.KeyBindingInputManager.Add(new Flashlight + public OsuFlashlight() { - RelativeSizeAxes = Axes.Both, - }); - } - - private class Flashlight : Drawable, IRequireHighFrequencyMousePosition - { - private Shader shader; - private readonly MousePositionWrapper mousePosWrapper = new MousePositionWrapper - { - FlashlightSize = 300f - }; - - protected override DrawNode CreateDrawNode() => new FlashlightDrawNode(); - - protected override void ApplyDrawNode(DrawNode node) - { - base.ApplyDrawNode(node); - - var flashNode = (FlashlightDrawNode)node; - - flashNode.Shader = shader; - flashNode.ScreenSpaceDrawQuad = ScreenSpaceDrawQuad; - flashNode.MousePosWrapper = mousePosWrapper; - } - - [BackgroundDependencyLoader] - private void load(ShaderManager shaderManager) - { - shader = shaderManager.Load(VertexShaderDescriptor.POSITION, "Flashlight"); + MousePosWrapper.CircularFlashlightSize = getSizeFor(0); + MousePosWrapper.Rectangular = false; } protected override bool OnMouseMove(MouseMoveEvent e) { - mousePosWrapper.MousePosition = e.ScreenSpaceMousePosition; + MousePosWrapper.FlashlightPosition = e.ScreenSpaceMousePosition; + MousePosWrapper.FlashlightPositionChanged = true; return base.OnMouseMove(e); } - } - private class MousePositionWrapper - { - public Vector2 MousePosition; - public float FlashlightSize; - public bool FlashlightUniformUpdated; - } - - private class FlashlightDrawNode : DrawNode - { - public Shader Shader; - public Quad ScreenSpaceDrawQuad; - public MousePositionWrapper MousePosWrapper; - - public override void Draw(Action vertexAction) + [UsedImplicitly] + private float flashlightSize { - base.Draw(vertexAction); + set + { + if (MousePosWrapper.CircularFlashlightSize == value) return; - Shader.Bind(); - // ReSharper disable once AssignmentInConditionalExpression - if(MousePosWrapper.FlashlightUniformUpdated = !MousePosWrapper.FlashlightUniformUpdated) - Shader.GetUniform("flashlightSize").UpdateValue(ref MousePosWrapper.FlashlightSize); + MousePosWrapper.CircularFlashlightSize = value; + MousePosWrapper.CircularFlashlightSizeChanged = true; + } - Shader.GetUniform("mousePos").UpdateValue(ref MousePosWrapper.MousePosition); + get => MousePosWrapper.CircularFlashlightSize; + } - Texture.WhitePixel.DrawQuad(ScreenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction); + private float getSizeFor(int combo) + { + if (combo > 200) + return default_flashlight_size * 0.8f; + else if (combo > 100) + return default_flashlight_size * 0.9f; + else + return default_flashlight_size; + } - Shader.Unbind(); + protected override void OnComboChange(int newCombo) + { + this.TransformTo(nameof(flashlightSize), getSizeFor(newCombo), FLASHLIGHT_FADE_DURATION); } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index f530b6725c..86dd37b476 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -8,6 +8,8 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Mods; +using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty { @@ -82,7 +84,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (mods.Any(m => m is ModHidden)) strainValue *= 1.025; - if (mods.Any(m => m is ModFlashlight)) + if (mods.Any(m => m is ModFlashlight)) // Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps. strainValue *= 1.05 * lengthBonus; diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index 49f7786f59..8e14f24bb3 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -1,12 +1,93 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using JetBrains.Annotations; +using osu.Framework.Graphics; +using osu.Framework.Input; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.UI; +using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Taiko.Mods { - public class TaikoModFlashlight : ModFlashlight + public class TaikoModFlashlight : ModFlashlight { public override double ScoreMultiplier => 1.12; + + private const float default_flashlight_size = 250; + + public override Flashlight CreateFlashlight() => new TaikoFlashlight(playfield); + + private TaikoPlayfield playfield; + + public override void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + { + playfield = (TaikoPlayfield)rulesetContainer.Playfield; + base.ApplyToRulesetContainer(rulesetContainer); + } + + private class TaikoFlashlight : Flashlight + { + private readonly TaikoPlayfield taikoPlayfield; + + public TaikoFlashlight(TaikoPlayfield taikoPlayfield) + { + this.taikoPlayfield = taikoPlayfield; + MousePosWrapper.CircularFlashlightSize = getSizeFor(0); + MousePosWrapper.Rectangular = false; + } + + [UsedImplicitly] + private float flashlightSize + { + set + { + if (MousePosWrapper.CircularFlashlightSize == value) return; + + MousePosWrapper.CircularFlashlightSize = value; + MousePosWrapper.CircularFlashlightSizeChanged = true; + } + + get => MousePosWrapper.CircularFlashlightSize; + } + + private float getSizeFor(int combo) + { + if (combo > 200) + return default_flashlight_size * 0.8f; + else if (combo > 100) + return default_flashlight_size * 0.9f; + else + return default_flashlight_size; + } + + protected override void OnComboChange(int newCombo) + { + this.TransformTo(nameof(flashlightSize), getSizeFor(newCombo), FLASHLIGHT_FADE_DURATION); + } + + public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) + { + if ((invalidation & Invalidation.DrawSize) > 0) + { + Schedule(() => + { + MousePosWrapper.FlashlightPosition = taikoPlayfield.HitExplosionContainer.ScreenSpaceDrawQuad.Centre; + MousePosWrapper.FlashlightPositionChanged = true; + }); + } + + return base.Invalidate(invalidation, source, shallPropagate); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + MousePosWrapper.FlashlightPosition = taikoPlayfield.HitExplosionContainer.ScreenSpaceDrawQuad.Centre; + MousePosWrapper.FlashlightPositionChanged = true; + } + } } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 40ed659bd6..5e1593638c 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Taiko.UI protected override SpeedChangeVisualisationMethod VisualisationMethod => SpeedChangeVisualisationMethod.Overlapping; - private readonly Container hitExplosionContainer; + internal readonly Container HitExplosionContainer; private readonly Container kiaiExplosionContainer; private readonly JudgementContainer judgementContainer; @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Taiko.UI Masking = true, Children = new Drawable[] { - hitExplosionContainer = new Container + HitExplosionContainer = new Container { RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, @@ -243,7 +243,7 @@ namespace osu.Game.Rulesets.Taiko.UI { case TaikoStrongJudgement _: if (result.IsHit) - hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).MainObject)?.VisualiseSecondHit(); + HitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).MainObject)?.VisualiseSecondHit(); break; default: judgementContainer.Add(new DrawableTaikoJudgement(result, judgedObject) @@ -259,7 +259,7 @@ namespace osu.Game.Rulesets.Taiko.UI bool isRim = judgedObject.HitObject is RimHit; - hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim)); + HitExplosionContainer.Add(new HitExplosion(judgedObject, isRim)); if (judgedObject.HitObject.Kiai) kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject, isRim)); diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 223263195c..a99f4e81fb 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -1,11 +1,27 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.OpenGL.Vertices; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Shaders; +using osu.Framework.Graphics.Textures; +using osu.Game.Beatmaps.Timing; using osu.Game.Graphics; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; +using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Rulesets.Mods { - public abstract class ModFlashlight : Mod + public abstract class ModFlashlight : Mod, IApplicableToRulesetContainer, IApplicableToScoreProcessor + where T : HitObject { public override string Name => "Flashlight"; public override string ShortenedName => "FL"; @@ -13,5 +29,130 @@ namespace osu.Game.Rulesets.Mods public override ModType Type => ModType.DifficultyIncrease; public override string Description => "Restricted view area."; public override bool Ranked => true; + + public const double FLASHLIGHT_FADE_DURATION = 800; + protected readonly BindableInt Combo = new BindableInt(); + + public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + { + Combo.BindTo(scoreProcessor.Combo); + } + + public virtual void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + { + var flashlight = CreateFlashlight(); + flashlight.Combo = Combo; + flashlight.RelativeSizeAxes = Axes.Both; + flashlight.Colour = Color4.Black; + rulesetContainer.KeyBindingInputManager.Add(flashlight); + + flashlight.Breaks = rulesetContainer.Beatmap.Breaks; + } + + public abstract Flashlight CreateFlashlight(); + + public abstract class Flashlight : Drawable + { + internal BindableInt Combo; + private Shader shader; + protected readonly FlashlightUniformWrapper MousePosWrapper = new FlashlightUniformWrapper(); + + protected override DrawNode CreateDrawNode() => new FlashlightDrawNode(); + + public override bool RemoveCompletedTransforms => false; + + public List Breaks; + + protected override void ApplyDrawNode(DrawNode node) + { + base.ApplyDrawNode(node); + + var flashNode = (FlashlightDrawNode)node; + + flashNode.Shader = shader; + flashNode.ScreenSpaceDrawQuad = ScreenSpaceDrawQuad; + flashNode.MousePosWrapper = MousePosWrapper; + } + + [BackgroundDependencyLoader] + private void load(ShaderManager shaderManager) + { + shader = shaderManager.Load("PositionAndColour", "Flashlight"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Combo.ValueChanged += OnComboChange; + + this.FadeInFromZero(FLASHLIGHT_FADE_DURATION); + + foreach (var breakPeriod in Breaks) + { + this.Delay(breakPeriod.StartTime + FLASHLIGHT_FADE_DURATION).FadeOutFromOne(FLASHLIGHT_FADE_DURATION); + this.Delay(breakPeriod.EndTime - FLASHLIGHT_FADE_DURATION).FadeInFromZero(FLASHLIGHT_FADE_DURATION); + } + } + + protected abstract void OnComboChange(int newCombo); + } + + public class FlashlightUniformWrapper + { + public bool Rectangular; + public bool RectangularChanged = true; + + public Vector2 FlashlightPosition; + public bool FlashlightPositionChanged = true; + + public float CircularFlashlightSize; + public bool CircularFlashlightSizeChanged = true; + + public Vector2 RectangularFlashlightSize; + public bool RectangularFlashlightSizeChanged = true; + } + + private class FlashlightDrawNode : DrawNode + { + public Shader Shader; + public Quad ScreenSpaceDrawQuad; + public FlashlightUniformWrapper MousePosWrapper; + + public override void Draw(Action vertexAction) + { + base.Draw(vertexAction); + + Shader.Bind(); + + if (MousePosWrapper.RectangularChanged) + { + Shader.GetUniform("rectangular").UpdateValue(ref MousePosWrapper.Rectangular); + MousePosWrapper.RectangularChanged = false; + } + + if (MousePosWrapper.FlashlightPositionChanged) + { + Shader.GetUniform("flashlightPos").UpdateValue(ref MousePosWrapper.FlashlightPosition); + MousePosWrapper.FlashlightPositionChanged = false; + } + + if (MousePosWrapper.CircularFlashlightSizeChanged) + { + Shader.GetUniform("circularFlashlightSize").UpdateValue(ref MousePosWrapper.CircularFlashlightSize); + MousePosWrapper.CircularFlashlightSizeChanged = false; + } + + if (MousePosWrapper.RectangularFlashlightSizeChanged) + { + Shader.GetUniform("rectangularFlashlightSize").UpdateValue(ref MousePosWrapper.RectangularFlashlightSize); + MousePosWrapper.RectangularFlashlightSizeChanged = false; + } + + Texture.WhitePixel.DrawQuad(ScreenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction); + + Shader.Unbind(); + } + } } }