From 883ef13e6539a179de5c562e7316a306248f2579 Mon Sep 17 00:00:00 2001 From: shr Date: Sun, 17 Sep 2023 00:32:45 +0900 Subject: [PATCH] finally did it --- source/funkin/SolidColorSprite.hx | 64 +++++++++++++++++++++++++++++++ source/funkin/play/PlayState.hx | 50 +++++++++++++++++------- 2 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 source/funkin/SolidColorSprite.hx diff --git a/source/funkin/SolidColorSprite.hx b/source/funkin/SolidColorSprite.hx new file mode 100644 index 000000000..b385ea1ae --- /dev/null +++ b/source/funkin/SolidColorSprite.hx @@ -0,0 +1,64 @@ +package funkin; + +import flixel.FlxSprite; + +/** + * Provides a clone of a sprite that is filled with a single color while keeping its alpha. + */ +class SolidColorSprite extends FlxSprite +{ + /** + * The FlxSprite that this sprite referes to. + */ + public var reference:FlxSprite; + + /** + * The red color strength, from 0.0 to 1.0. + */ + public var red:Float; + + /** + * The green color strength, from 0.0 to 1.0. + */ + public var green:Float; + + /** + * The blue color strength, from 0.0 to 1.0. + */ + public var blue:Float; + + function new(reference:FlxSprite, red:Float = 1.0, green:Float = 1.0, blue:Float = 1.0) + { + super(); + this.reference = reference; + this.red = red; + this.green = green; + this.blue = blue; + } + + override function draw():Void + { + super.draw(); + + final rMult = reference.colorTransform.redMultiplier; + final gMult = reference.colorTransform.greenMultiplier; + final bMult = reference.colorTransform.blueMultiplier; + final aMult = reference.colorTransform.alphaMultiplier; + final rOff = Std.int(reference.colorTransform.redOffset); + final gOff = Std.int(reference.colorTransform.greenOffset); + final bOff = Std.int(reference.colorTransform.blueOffset); + final aOff = Std.int(reference.colorTransform.alphaOffset); + final tmpCameras = reference._cameras; + final tmpShader = reference.shader; + + reference._cameras = _cameras; + + reference.shader = shader; + reference.setColorTransform(0, 0, 0, 1, Std.int(red * 255 + 0.5), Std.int(green * 255 + 0.5), Std.int(blue * 255 + 0.5), 0); + reference.draw(); + + reference._cameras = tmpCameras; + reference.shader = tmpShader; + reference.setColorTransform(rMult, gMult, bMult, aMult, rOff, gOff, bOff, aOff); + } +} diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 2a8be1c5e..0dab2c52e 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -31,6 +31,7 @@ import flixel.ui.FlxBar; import flixel.util.FlxColor; import funkin.api.newgrounds.NGio; import flixel.util.FlxTimer; +import openfl.Lib; import openfl.display.BitmapData; import openfl.geom.Rectangle; import funkin.audio.VoicesGroup; @@ -589,6 +590,9 @@ class PlayState extends MusicBeatSubState } initStrumlines(); + // Initialize sprites for the buffer texture. + initMaskSprites(); + // Initialize the judgements and combo meter. comboPopUps = new PopUpStuff(); comboPopUps.cameras = [camHUD]; @@ -1272,6 +1276,8 @@ class PlayState extends MusicBeatSubState super.destroy(); + // It's manually obtained, don't forget to release it! + maskTextureBase.dispose(); FlxG.signals.postUpdate.remove(syncBufferCameras); bufferCameraFrontEnd.remove(camMask); } @@ -1308,11 +1314,7 @@ class PlayState extends MusicBeatSubState camCutscene = new FlxCamera(); camCutscene.bgColor.alpha = 0; // Show the game scene behind the camera. - // Init cameras and stuff for buffers. - camMask = new FlxCamera(); - maskTexture = new BitmapData(FlxG.width, FlxG.height, true, FlxColor.TRANSPARENT); - bufferCameraFrontEnd.reset(camMask); - FlxG.signals.postUpdate.add(syncBufferCameras); + initBufferCameras(); FlxG.cameras.reset(camGame); FlxG.cameras.add(camHUD, false); @@ -1327,6 +1329,24 @@ class PlayState extends MusicBeatSubState add(cameraFollowPoint); } + function initBufferCameras():Void + { + // Init cameras and stuff for buffers. + camMask = new FlxCamera(); + // note: removing this line will cause NullReferenceError inside OpenGLRenderer lol + camMask.flashSprite.cacheAsBitmap = true; + // Prevent potential memory leak. + if (maskTextureBase != null) maskTextureBase.dispose(); + // We need to directly create texture using Context3D, otherwise cannot render Sprite + // using OpenGLRenderer, which disables any shader applied to it. + maskTextureBase = Lib.current.stage.context3D.createTexture(FlxG.width, FlxG.height, Context3DTextureFormat.BGRA, true); + maskTexture = BitmapData.fromTexture(maskTextureBase); + // This must be done BEFORE `FlxG.cameras.reset`. + bufferCameraFrontEnd.reset(camMask); + // Sync buffer cameras after every update. + FlxG.signals.postUpdate.add(syncBufferCameras); + } + /** * Initializes the health bar on the HUD. */ @@ -1419,14 +1439,6 @@ class PlayState extends MusicBeatSubState #if debug FlxG.console.registerObject('stage', currentStage); #end - - // Add mask sprites to the mask camera. - for (sprite in currentStage.maskSprites) - { - sprite.cameras = [camMask]; - } - // Set buffer textures. - currentStage.maskTexture = maskTexture; } else { @@ -1585,6 +1597,18 @@ class PlayState extends MusicBeatSubState this.refresh(); } + function initMaskSprites():Void + { + // Add mask sprites to the mask camera. + for (sprite in currentStage.maskSprites) + { + this.add(sprite); + sprite.cameras = [camMask]; + } + // Set buffer textures to the current stage. + currentStage.maskTexture = maskTexture; + } + /** * Initializes the Discord Rich Presence. */