diff --git a/source/game/StageGroup.hx b/source/game/StageGroup.hx index 40c3572cfc..df7ecdb8b4 100644 --- a/source/game/StageGroup.hx +++ b/source/game/StageGroup.hx @@ -1,5 +1,6 @@ package game; +import shaders.ColorSwapHSV; import modding.scripts.languages.HScript; #if polymod import polymod.backends.PolymodAssets; @@ -76,6 +77,8 @@ class StageGroup extends FlxGroup { public var stageScript:ModchartUtilities = null; #end + public var colorSwap:ColorSwapHSV; + public function updateStage(?newStage:String) { if (newStage != null) stage = newStage; @@ -282,6 +285,8 @@ class StageGroup extends FlxGroup { for (Object in stage_Data.objects) { var Sprite = new FlxSprite(Object.position[0], Object.position[1]); + Sprite.shader = colorSwap.shader; + if (Object.color != null && Object.color != []) Sprite.color = FlxColor.fromRGB(Object.color[0], Object.color[1], Object.color[2]); @@ -439,7 +444,7 @@ class StageGroup extends FlxGroup { override public function new(?stageName:String) { super(); - + colorSwap = new ColorSwapHSV(); stage = stageName; updateStage(); } diff --git a/source/modding/ModchartUtilities.hx b/source/modding/ModchartUtilities.hx index d96e6cd9fc..cf6f6b7917 100644 --- a/source/modding/ModchartUtilities.hx +++ b/source/modding/ModchartUtilities.hx @@ -2631,6 +2631,35 @@ class ModchartUtilities { return id; }); + setLuaFunction("tweenStageColorSwap", function(prop:String, value:Dynamic, time:Float, easeStr:String = "linear") { + @:privateAccess + var actor = PlayState.instance.stage.colorSwap; + var ease = easeFromString(easeStr); + + if(actor != null) + { + var startVal = Reflect.getProperty(actor, prop); + + PlayState.instance.tweenManager.num(startVal, value, time, {onUpdate: function(tween:FlxTween){ + var ting = FlxMath.lerp(startVal,value, ease(tween.percent)); + Reflect.setProperty(actor, prop, ting); + }, ease: ease, onComplete: function(tween:FlxTween) { + Reflect.setProperty(actor, prop, value); + }}); + } + }); + + + setLuaFunction("setStageColorSwap", function(prop:String, value:Dynamic) { + @:privateAccess + var actor = PlayState.instance.stage.colorSwap; + + if(actor != null) + { + Reflect.setProperty(actor, prop, value); + } + }); + setLuaFunction("getStrumTimeFromStep", function(step:Float) { var beat = step*0.25; var totalTime:Float = 0; @@ -2853,6 +2882,8 @@ class ModchartUtilities { }); setLuaFunction("setShaderProperty", function(id:String, property:String, value:Dynamic) { + if (!Options.getData("shaders")) + return; var funnyCustomShader:CustomShader = lua_Custom_Shaders.get(id); if(Std.isOfType(value, Float)){ funnyCustomShader.setFloat(property, Std.parseFloat(value)); @@ -2866,6 +2897,8 @@ class ModchartUtilities { }); setLuaFunction("tweenShaderProperty", function(id:String, property:String, value:Float, duration:Float, ?ease:String = "linear", ?startDelay:Float = 0.0, ?onComplete:Dynamic) { + if (!Options.getData("shaders")) + return; var shader:CustomShader = lua_Custom_Shaders.get(id); if (shader != null) { shader.tween(property, value, duration, easeFromString(ease), startDelay, onComplete); diff --git a/source/shaders/ColorSwapHSV.hx b/source/shaders/ColorSwapHSV.hx new file mode 100644 index 0000000000..d6c97eb10f --- /dev/null +++ b/source/shaders/ColorSwapHSV.hx @@ -0,0 +1,219 @@ +package shaders; + +import flixel.system.FlxAssets.FlxShader; + +/** + * Cool Shader by ShadowMario that changes RGB based on HSV. + */ +class ColorSwapHSV { + public var shader(default, null):ColorSwapHSVShader = new ColorSwapHSVShader(); + public var hue(default, set):Float = 0; + public var saturation(default, set):Float = 0; + public var brightness(default, set):Float = 0; + + private function set_hue(value:Float) { + hue = value; + shader.uTime.value[0] = hue; + return hue; + } + + private function set_saturation(value:Float) { + saturation = value; + shader.uTime.value[1] = saturation; + return saturation; + } + + private function set_brightness(value:Float) { + brightness = value; + shader.uTime.value[2] = brightness; + return brightness; + } + + public function new() + { + shader.uTime.value = [0, 0, 0]; + shader.awesomeOutline.value = [false]; + } +} + +class ColorSwapHSVShader extends FlxShader { + @:glFragmentSource(' + varying float openfl_Alphav; + varying vec4 openfl_ColorMultiplierv; + varying vec4 openfl_ColorOffsetv; + varying vec2 openfl_TextureCoordv; + + uniform bool openfl_HasColorTransform; + uniform vec2 openfl_TextureSize; + uniform sampler2D bitmap; + + uniform bool hasTransform; + uniform bool hasColorTransform; + + vec4 flixel_texture2D(sampler2D bitmap, vec2 coord) + { + vec4 color = texture2D(bitmap, coord); + if (!hasTransform) + { + return color; + } + + if (color.a == 0.0) + { + return vec4(0.0, 0.0, 0.0, 0.0); + } + + if (!hasColorTransform) + { + return color * openfl_Alphav; + } + + color = vec4(color.rgb / color.a, color.a); + + mat4 colorMultiplier = mat4(0); + colorMultiplier[0][0] = openfl_ColorMultiplierv.x; + colorMultiplier[1][1] = openfl_ColorMultiplierv.y; + colorMultiplier[2][2] = openfl_ColorMultiplierv.z; + colorMultiplier[3][3] = openfl_ColorMultiplierv.w; + + color = clamp(openfl_ColorOffsetv + (color * colorMultiplier), 0.0, 1.0); + + if (color.a > 0.0) + { + return vec4(color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav); + } + return vec4(0.0, 0.0, 0.0, 0.0); + } + + uniform vec3 uTime; + uniform bool awesomeOutline; + + const float offset = 1.0 / 128.0; + vec3 normalizeColor(vec3 color) + { + return vec3( + color[0] / 255.0, + color[1] / 255.0, + color[2] / 255.0 + ); + } + + vec3 rgb2hsv(vec3 c) + { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); + } + + vec3 hsv2rgb(vec3 c) + { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); + } + + void main() + { + vec4 color = flixel_texture2D(bitmap, openfl_TextureCoordv); + + vec4 swagColor = vec4(rgb2hsv(vec3(color[0], color[1], color[2])), color[3]); + + // [0] is the hue??? + swagColor[0] = swagColor[0] + uTime[0]; + swagColor[1] = swagColor[1] + uTime[1]; + swagColor[2] = swagColor[2] * (1.0 + uTime[2]); + + if(swagColor[1] < 0.0) + { + swagColor[1] = 0.0; + } + else if(swagColor[1] > 1.0) + { + swagColor[1] = 1.0; + } + + color = vec4(hsv2rgb(vec3(swagColor[0], swagColor[1], swagColor[2])), swagColor[3]); + + if (awesomeOutline) + { + // Outline bullshit? + vec2 size = vec2(3, 3); + + if (color.a <= 0.5) { + float w = size.x / openfl_TextureSize.x; + float h = size.y / openfl_TextureSize.y; + + if (flixel_texture2D(bitmap, vec2(openfl_TextureCoordv.x + w, openfl_TextureCoordv.y)).a != 0. + || flixel_texture2D(bitmap, vec2(openfl_TextureCoordv.x - w, openfl_TextureCoordv.y)).a != 0. + || flixel_texture2D(bitmap, vec2(openfl_TextureCoordv.x, openfl_TextureCoordv.y + h)).a != 0. + || flixel_texture2D(bitmap, vec2(openfl_TextureCoordv.x, openfl_TextureCoordv.y - h)).a != 0.) + color = vec4(1.0, 1.0, 1.0, 1.0); + } + } + gl_FragColor = color; + + /* + if (color.a > 0.5) + gl_FragColor = color; + else + { + float a = flixel_texture2D(bitmap, vec2(openfl_TextureCoordv + offset, openfl_TextureCoordv.y)).a + + flixel_texture2D(bitmap, vec2(openfl_TextureCoordv, openfl_TextureCoordv.y - offset)).a + + flixel_texture2D(bitmap, vec2(openfl_TextureCoordv - offset, openfl_TextureCoordv.y)).a + + flixel_texture2D(bitmap, vec2(openfl_TextureCoordv, openfl_TextureCoordv.y + offset)).a; + if (color.a < 1.0 && a > 0.0) + gl_FragColor = vec4(0.0, 0.0, 0.0, 0.8); + else + gl_FragColor = color; + } */ + }') + @:glVertexSource(' + attribute float openfl_Alpha; + attribute vec4 openfl_ColorMultiplier; + attribute vec4 openfl_ColorOffset; + attribute vec4 openfl_Position; + attribute vec2 openfl_TextureCoord; + + varying float openfl_Alphav; + varying vec4 openfl_ColorMultiplierv; + varying vec4 openfl_ColorOffsetv; + varying vec2 openfl_TextureCoordv; + + uniform mat4 openfl_Matrix; + uniform bool openfl_HasColorTransform; + uniform vec2 openfl_TextureSize; + + attribute float alpha; + attribute vec4 colorMultiplier; + attribute vec4 colorOffset; + uniform bool hasColorTransform; + + void main(void) + { + openfl_Alphav = openfl_Alpha; + openfl_TextureCoordv = openfl_TextureCoord; + + if (openfl_HasColorTransform) { + openfl_ColorMultiplierv = openfl_ColorMultiplier; + openfl_ColorOffsetv = openfl_ColorOffset / 255.0; + } + + gl_Position = openfl_Matrix * openfl_Position; + + openfl_Alphav = openfl_Alpha * alpha; + if (hasColorTransform) + { + openfl_ColorOffsetv = colorOffset / 255.0; + openfl_ColorMultiplierv = colorMultiplier; + } + }') + + public function new() + { + super(); + } +} \ No newline at end of file diff --git a/source/shaders/custom/CustomShader.hx b/source/shaders/custom/CustomShader.hx index d8673bdfad..fe499cfc31 100644 --- a/source/shaders/custom/CustomShader.hx +++ b/source/shaders/custom/CustomShader.hx @@ -1,5 +1,7 @@ package shaders.custom; +import flixel.math.FlxMath; +import states.PlayState; import flixel.addons.display.FlxRuntimeShader; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; @@ -21,7 +23,11 @@ class CustomShader extends FlxRuntimeShader { * @param onComplete When to do when the tween is done */ public function tween(property:String, to:Float, duration:Float = 1, ease:EaseFunction, ?startDelay:Float = 0.0, ?onComplete:Dynamic){ - FlxTween.num(getFloat(property), to, duration, {ease: ease, onComplete: function(twn) { + PlayState.instance.tweenManager.num(getFloat(property), to, duration, {onUpdate: function(tween:FlxTween){ + var ting = FlxMath.lerp(getFloat(property),to, ease(tween.percent)); + setFloat(property, ting); + },ease: ease, onComplete: function(twn) { + setFloat(property, to); //make sure if (onComplete != null) onComplete(); },startDelay: startDelay,}, (value)->{setFloat(property, value);}); diff --git a/source/states/PlayState.hx b/source/states/PlayState.hx index 5166d37595..c981742818 100644 --- a/source/states/PlayState.hx +++ b/source/states/PlayState.hx @@ -2860,7 +2860,7 @@ class PlayState extends MusicBeatState { } } - if (Conductor.songPosition - Conductor.safeZoneOffset > daNote.strumTime && !Options.getData("botplay")) { + if (Conductor.songPosition - Conductor.safeZoneOffset > daNote.strumTime) { if (daNote.checkPlayerMustPress() && daNote.playMissOnMiss && !(daNote.isSustainNote && daNote.animation.curAnim.name == "holdend") @@ -3097,6 +3097,8 @@ class PlayState extends MusicBeatState { } function endSong():Void { + allScriptCall("endSong"); + executeALuaState("endSong", []); canPause = false; FlxG.sound.music.volume = 0; vocals.volume = 0;