1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2024-11-05 06:14:36 +00:00

made it a library

This commit is contained in:
shr 2023-09-17 20:45:10 +09:00 committed by Cameron Taylor
parent 6d0a8cc535
commit 26818e6d99
6 changed files with 117 additions and 204 deletions

View file

@ -1,64 +0,0 @@
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);
}
}

View file

@ -22,21 +22,25 @@ class FrameBuffer
public function new() public function new()
{ {
camera = new FlxCamera(); camera = new FlxCamera();
camera.antialiasing = false;
camera.bgColor = FlxColor.TRANSPARENT; camera.bgColor = FlxColor.TRANSPARENT;
camera.flashSprite.cacheAsBitmap = true; camera.flashSprite.cacheAsBitmap = true;
@:privateAccess camera.flashSprite.stage = Lib.current.stage;
} }
/** /**
* Creates a frame buffer with the given size. * Creates a frame buffer with the given size.
* @param width the width * @param width the width
* @param height the height * @param height the height
* @param bgColor the background color
*/ */
public function create(width:Int, height:Int):Void public function create(width:Int, height:Int, bgColor:FlxColor):Void
{ {
dispose(); dispose();
final c3d = Lib.current.stage.context3D; final c3d = Lib.current.stage.context3D;
texture = c3d.createTexture(width, height, BGRA, true); texture = c3d.createTexture(width, height, BGRA, true);
bitmap = BitmapData.fromTexture(texture); bitmap = BitmapData.fromTexture(texture);
camera.bgColor = bgColor;
} }
/** /**
@ -45,7 +49,12 @@ class FrameBuffer
*/ */
public function follow(target:FlxCamera):Void public function follow(target:FlxCamera):Void
{ {
camera.scroll.copyFrom(target.scroll); camera.x = target.x;
camera.y = target.y;
camera.width = target.width;
camera.height = target.height;
camera.scroll.x = target.scroll.x;
camera.scroll.y = target.scroll.y;
camera.setScale(target.scaleX, target.scaleY); camera.setScale(target.scaleX, target.scaleY);
} }
@ -58,17 +67,22 @@ class FrameBuffer
camera.clearDrawStack(); camera.clearDrawStack();
camera.canvas.graphics.clear(); camera.canvas.graphics.clear();
camera.fill(camera.bgColor.to24Bit(), camera.useBgAlphaBlending, camera.bgColor.alphaFloat); camera.fill(camera.bgColor.to24Bit(), camera.useBgAlphaBlending, camera.bgColor.alphaFloat);
#if FLX_DEBUG
camera.debugLayer.graphics.clear();
#end
} }
/** /**
* Renders all sprite copies. * Renders all sprite copies.
*/ */
@:access(flixel.FlxCamera)
public function render():Void public function render():Void
{ {
for (spriteCopy in spriteCopies) for (spriteCopy in spriteCopies)
{ {
spriteCopy.render(camera); spriteCopy.render(camera);
} }
camera.render();
} }
/** /**

View file

@ -1,5 +1,6 @@
package funkin.graphics.framebuffer; package funkin.graphics.framebuffer;
import flixel.util.FlxColor;
import openfl.display.BitmapData; import openfl.display.BitmapData;
import flixel.FlxSprite; import flixel.FlxSprite;
import flixel.FlxCamera; import flixel.FlxCamera;
@ -21,33 +22,33 @@ class FrameBufferManager
/** /**
* Creates a new frame buffer with a name. * Creates a new frame buffer with a name.
* @param name the name * @param name the name
* @param bgColor the background color
* @return the bitmap data of the frame buffer. the bitmap data instance
* will not be changed through frame buffer updates.
*/ */
public function createFrameBuffer(name:String):Void public function createFrameBuffer(name:String, bgColor:FlxColor):BitmapData
{ {
if (frameBufferMap.exists(name)) if (frameBufferMap.exists(name))
{ {
FlxG.log.warn('frame buffer "$name" already exists'); FlxG.log.warn('frame buffer "$name" already exists');
frameBufferMap[name].dispose();
frameBufferMap.remove(name);
} }
else final fb = new FrameBuffer();
{ fb.create(camera.width, camera.height, bgColor);
final fb = new FrameBuffer(); frameBufferMap[name] = fb;
fb.create(camera.width, camera.height); return fb.bitmap;
frameBufferMap[name] = fb;
}
} }
/** /**
* Adds a copy of the sprite to the frame buffer. * Adds a copy of the sprite to the frame buffer.
* @param name the name of the frame buffer * @param name the name of the frame buffer
* @param sprite the sprite * @param sprite the sprite
* @param color if this is not `-1`, the sprite will have the color while keeping its shape * @param color if this is not `null`, the sprite will be filled with the color.
* if this is `null`, the sprite will keep its original color.
*/ */
public function addSpriteTo(name:String, sprite:FlxSprite, color:Int = -1):Void public function addSpriteCopyTo(name:String, sprite:FlxSprite, color:Null<FlxColor> = null):Void
{ {
if (!frameBufferMap.exists(name))
{
createFrameBuffer(name);
}
frameBufferMap[name].addSpriteCopy(new SpriteCopy(sprite, color)); frameBufferMap[name].addSpriteCopy(new SpriteCopy(sprite, color));
} }
@ -58,27 +59,20 @@ class FrameBufferManager
{ {
for (_ => fb in frameBufferMap) for (_ => fb in frameBufferMap)
{ {
fb.follow(camera);
fb.lock(); fb.lock();
} }
} }
/** /**
* Renders all the copies of the sprites. Make sure this is called between * Unlocks the frame buffers. This updates the bitmap data of each frame buffer.
* `lock` and `unlock`.
*/ */
public function render():Void public function unlock():Void
{ {
for (_ => fb in frameBufferMap) for (_ => fb in frameBufferMap)
{ {
fb.render(); fb.render();
} }
}
/**
* After calling this you can use bitmap data of all frame buffers.
*/
public function unlock():Void
{
for (_ => fb in frameBufferMap) for (_ => fb in frameBufferMap)
{ {
fb.unlock(); fb.unlock();
@ -88,7 +82,7 @@ class FrameBufferManager
/** /**
* Returns the bitmap data of the frame buffer * Returns the bitmap data of the frame buffer
* @param name the name of the frame buffer * @param name the name of the frame buffer
* @return the ready-to-use bitmap data * @return the bitmap data
*/ */
public function getFrameBuffer(name:String):BitmapData public function getFrameBuffer(name:String):BitmapData
{ {
@ -96,7 +90,7 @@ class FrameBufferManager
} }
/** /**
* Disposes all frame buffers. * Disposes all frame buffers. The instance can be reused.
*/ */
public function dispose():Void public function dispose():Void
{ {

View file

@ -1,14 +1,15 @@
package funkin.graphics.framebuffer; package funkin.graphics.framebuffer;
import flixel.util.FlxColor;
import flixel.FlxCamera; import flixel.FlxCamera;
import flixel.FlxSprite; import flixel.FlxSprite;
class SpriteCopy class SpriteCopy
{ {
final sprite:FlxSprite; final sprite:FlxSprite;
var color:Int; var color:Null<FlxColor>;
public function new(sprite:FlxSprite, color:Int = -1) public function new(sprite:FlxSprite, color:Null<FlxColor>)
{ {
this.sprite = sprite; this.sprite = sprite;
this.color = color; this.color = color;
@ -21,30 +22,34 @@ class SpriteCopy
@:access(flixel.FlxSprite) @:access(flixel.FlxSprite)
public function render(camera:FlxCamera):Void public function render(camera:FlxCamera):Void
{ {
final rMult = sprite.colorTransform.redMultiplier; if (color == null)
final gMult = sprite.colorTransform.greenMultiplier;
final bMult = sprite.colorTransform.blueMultiplier;
final aMult = sprite.colorTransform.alphaMultiplier;
final rOff = Std.int(sprite.colorTransform.redOffset);
final gOff = Std.int(sprite.colorTransform.greenOffset);
final bOff = Std.int(sprite.colorTransform.blueOffset);
final aOff = Std.int(sprite.colorTransform.alphaOffset);
final tmpCameras = sprite._cameras;
sprite._cameras = [camera];
if (color != -1)
{ {
final red = color >> 16 & 0xFF; final tmpCameras = sprite._cameras;
final green = color >> 8 & 0xFF; sprite._cameras = [camera];
final blue = color & 0xFF; sprite.draw();
sprite.setColorTransform(0, 0, 0, 1, red, green, blue, 0); sprite._cameras = tmpCameras;
} }
sprite.draw(); else
sprite._cameras = tmpCameras;
if (color != -1)
{ {
final rMult = sprite.colorTransform.redMultiplier;
final gMult = sprite.colorTransform.greenMultiplier;
final bMult = sprite.colorTransform.blueMultiplier;
final aMult = sprite.colorTransform.alphaMultiplier;
final rOff = Std.int(sprite.colorTransform.redOffset);
final gOff = Std.int(sprite.colorTransform.greenOffset);
final bOff = Std.int(sprite.colorTransform.blueOffset);
final aOff = Std.int(sprite.colorTransform.alphaOffset);
final tmpCameras = sprite._cameras;
final tmpShader = sprite.shader;
sprite._cameras = [camera];
sprite.shader = null;
sprite.setColorTransform(0, 0, 0, 1, color.red, color.green, color.blue, 0);
sprite.draw();
sprite._cameras = tmpCameras;
sprite.shader = tmpShader;
sprite.setColorTransform(rMult, gMult, bMult, aMult, rOff, gOff, bOff, aOff); sprite.setColorTransform(rMult, gMult, bMult, aMult, rOff, gOff, bOff, aOff);
} }
} }

View file

@ -15,7 +15,10 @@ import flixel.FlxObject;
import flixel.FlxSprite; import flixel.FlxSprite;
import flixel.FlxState; import flixel.FlxState;
import flixel.FlxSubState; import flixel.FlxSubState;
import flixel.input.keyboard.FlxKey; import flixel.addons.display.FlxPieDial;
import flixel.addons.transition.FlxTransitionableState;
import flixel.addons.transition.FlxTransitionableSubState;
import flixel.addons.transition.Transition;
import flixel.math.FlxMath; import flixel.math.FlxMath;
import funkin.play.components.ComboMilestone; import funkin.play.components.ComboMilestone;
import flixel.math.FlxPoint; import flixel.math.FlxPoint;
@ -25,8 +28,6 @@ import flixel.math.FlxRect;
import flixel.text.FlxText; import flixel.text.FlxText;
import flixel.tweens.FlxEase; import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween; import flixel.tweens.FlxTween;
import flixel.system.frontEnds.CameraFrontEnd;
import flixel.util.FlxColor;
import flixel.ui.FlxBar; import flixel.ui.FlxBar;
import flixel.util.FlxColor; import flixel.util.FlxColor;
import funkin.api.newgrounds.NGio; import funkin.api.newgrounds.NGio;
@ -37,21 +38,24 @@ import openfl.geom.Rectangle;
import funkin.audio.VoicesGroup; import funkin.audio.VoicesGroup;
import funkin.save.Save; import funkin.save.Save;
import funkin.Highscore.Tallies; import funkin.Highscore.Tallies;
import funkin.NoteSplash;
import funkin.audio.VoicesGroup;
import funkin.data.notestyle.NoteStyleRegistry;
import funkin.input.PreciseInputManager; import funkin.input.PreciseInputManager;
import funkin.modding.events.ScriptEvent; import funkin.modding.events.ScriptEvent;
import funkin.ui.mainmenu.MainMenuState; import funkin.ui.mainmenu.MainMenuState;
import funkin.modding.events.ScriptEventDispatcher; import funkin.modding.events.ScriptEventDispatcher;
import funkin.play.character.BaseCharacter; import funkin.play.character.BaseCharacter;
import funkin.play.character.CharacterData.CharacterDataParser; import funkin.play.character.CharacterData.CharacterDataParser;
import funkin.play.cutscene.dialogue.Conversation;
import funkin.play.cutscene.dialogue.ConversationDataParser;
import funkin.play.cutscene.VanillaCutscenes; import funkin.play.cutscene.VanillaCutscenes;
import funkin.play.cutscene.VideoCutscene; import funkin.play.cutscene.VideoCutscene;
import funkin.data.event.SongEventData.SongEventParser; import funkin.data.event.SongEventData.SongEventParser;
import funkin.play.notes.NoteSprite; import funkin.play.notes.NoteSprite;
import funkin.play.notes.NoteDirection; import funkin.play.notes.NoteDirection;
import funkin.play.notes.NoteSprite;
import funkin.play.notes.Strumline; import funkin.play.notes.Strumline;
import funkin.play.notes.SustainTrail; import funkin.play.notes.SustainTrail;
import funkin.play.notes.notestyle.NoteStyle;
import funkin.play.scoring.Scoring; import funkin.play.scoring.Scoring;
import funkin.play.song.Song; import funkin.play.song.Song;
import funkin.data.song.SongRegistry; import funkin.data.song.SongRegistry;
@ -66,7 +70,6 @@ import funkin.ui.options.PreferencesMenu;
import funkin.ui.debug.stage.StageOffsetSubState; import funkin.ui.debug.stage.StageOffsetSubState;
import funkin.ui.story.StoryMenuState; import funkin.ui.story.StoryMenuState;
import funkin.util.SerializerUtil; import funkin.util.SerializerUtil;
import funkin.util.SortUtil;
import lime.ui.Haptic; import lime.ui.Haptic;
#if discord_rpc #if discord_rpc
import Discord.DiscordClient; import Discord.DiscordClient;
@ -590,9 +593,6 @@ class PlayState extends MusicBeatSubState
} }
initStrumlines(); initStrumlines();
// Initialize sprites for the buffer texture.
initMaskSprites();
// Initialize the judgements and combo meter. // Initialize the judgements and combo meter.
comboPopUps = new PopUpStuff(); comboPopUps = new PopUpStuff();
comboPopUps.cameras = [camHUD]; comboPopUps.cameras = [camHUD];
@ -980,28 +980,6 @@ class PlayState extends MusicBeatSubState
processNotes(elapsed); processNotes(elapsed);
} }
@:access(flixel.FlxCamera)
@:access(flixel.system.frontEnds.CameraFrontEnd)
override function draw():Void
{
// Clears the draw stacks buffer cameras.
bufferCameraFrontEnd.lock();
// Collects draw stacks to render stuff, for ALL cameras including
// the main ones and buffer ones. But at this point each camera's
// canvas.graphics is still empty.
super.draw();
// Actually render (using canvas.graphics) stuff ONLY for the buffer cameras.
// For the main cameras, it will be done by FlxGame LATER.
bufferCameraFrontEnd.render();
// Possibly applies some FXs to the buffer cameras.
bufferCameraFrontEnd.unlock();
// Update the buffer texture using `flashSprite`.
// This is IMMEDIATELY done while the main cameras are not rendered yet,
// so any shaders in the main part that refer the texture can see the updated texture!
maskTexture.fillRect(new Rectangle(0, 0, FlxG.width, FlxG.height), 0);
maskTexture.draw(camMask.flashSprite, new openfl.geom.Matrix(1, 0, 0, 1, camMask.flashSprite.x, camMask.flashSprite.y));
}
public override function dispatchEvent(event:ScriptEvent):Void public override function dispatchEvent(event:ScriptEvent):Void
{ {
// ORDER: Module, Stage, Character, Song, Conversation, Note // ORDER: Module, Stage, Character, Song, Conversation, Note
@ -1275,11 +1253,6 @@ class PlayState extends MusicBeatSubState
performCleanup(); performCleanup();
super.destroy(); super.destroy();
// It's manually obtained, don't forget to release it!
maskTextureBase.dispose();
FlxG.signals.postUpdate.remove(syncBufferCameras);
bufferCameraFrontEnd.remove(camMask);
} }
/** /**
@ -1314,8 +1287,6 @@ class PlayState extends MusicBeatSubState
camCutscene = new FlxCamera(); camCutscene = new FlxCamera();
camCutscene.bgColor.alpha = 0; // Show the game scene behind the camera. camCutscene.bgColor.alpha = 0; // Show the game scene behind the camera.
initBufferCameras();
FlxG.cameras.reset(camGame); FlxG.cameras.reset(camGame);
FlxG.cameras.add(camHUD, false); FlxG.cameras.add(camHUD, false);
FlxG.cameras.add(camCutscene, false); FlxG.cameras.add(camCutscene, false);
@ -1329,24 +1300,6 @@ class PlayState extends MusicBeatSubState
add(cameraFollowPoint); 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. * Initializes the health bar on the HUD.
*/ */
@ -1397,24 +1350,6 @@ class PlayState extends MusicBeatSubState
add(menuBG); add(menuBG);
} }
/**
* Syncs cameras for buffers; basically just copies how the main camera is doing
*/
function syncBufferCameras():Void
{
final tr = @:privateAccess FlxG.log._standardTraceFunction;
// tr("zoom: " + camGame.zoom);
for (cam in bufferCameraFrontEnd.list)
{
cam.x = camGame.x;
cam.y = camGame.y;
cam.scroll.x = camGame.scroll.x;
cam.scroll.y = camGame.scroll.y;
cam.zoom = camGame.zoom;
@:privateAccess cam.updateFlashSpritePosition();
}
}
/** /**
* Loads stage data from cache, assembles the props, * Loads stage data from cache, assembles the props,
* and adds it to the state. * and adds it to the state.
@ -1597,18 +1532,6 @@ class PlayState extends MusicBeatSubState
this.refresh(); 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. * Initializes the Discord Rich Presence.
*/ */

View file

@ -1,5 +1,8 @@
package funkin.play.stage; package funkin.play.stage;
import funkin.graphics.framebuffer.FrameBufferManager;
import flixel.util.FlxColor;
import funkin.graphics.framebuffer.SpriteCopy;
import flixel.FlxCamera; import flixel.FlxCamera;
import flixel.FlxSprite; import flixel.FlxSprite;
import flixel.group.FlxSpriteGroup; import flixel.group.FlxSpriteGroup;
@ -20,6 +23,26 @@ import funkin.util.assets.FlxAnimationUtil;
typedef StagePropGroup = FlxTypedSpriteGroup<StageProp>; typedef StagePropGroup = FlxTypedSpriteGroup<StageProp>;
typedef FrameBufferSprite =
{
/**
* The name of the target frame buffer.
*/
var name:String;
/**
* The sprite to be rendered.
*/
var sprite:FlxSprite;
/**
* The RGB color of the sprite. The alpha component will be ignored.
* If this is `null`, the sprite keeps its original color.
*/
@:optional
var color:Null<FlxColor>;
}
/** /**
* A Stage is a group of objects rendered in the PlayState. * A Stage is a group of objects rendered in the PlayState.
* *
@ -34,10 +57,9 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
public var camZoom:Float = 1.0; public var camZoom:Float = 1.0;
/** var frameBufferMan:FrameBufferManager;
* The list of sprites that should be rendered for mask texture.
*/ public final frameBufferSprites:Array<FrameBufferSprite> = [];
public var maskSprites:Array<FlxSprite> = [];
/** /**
* The texture that has the mask information. Used for shader effects. * The texture that has the mask information. Used for shader effects.
@ -76,6 +98,10 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
*/ */
public function onCreate(event:ScriptEvent):Void public function onCreate(event:ScriptEvent):Void
{ {
if (frameBufferMan != null) frameBufferMan.dispose();
frameBufferMan = new FrameBufferManager(FlxG.camera);
onFrameBufferCreate();
buildStage(); buildStage();
this.refresh(); this.refresh();
@ -691,6 +717,8 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
{ {
debugIconGroup = null; debugIconGroup = null;
} }
frameBufferMan.dispose();
} }
/** /**
@ -743,6 +771,19 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
return Sprite; return Sprite;
} }
override function draw():Void
{
frameBufferMan.lock();
super.draw();
frameBufferMan.unlock();
}
/**
* Called when the frame buffer manager is ready.
* Create frame buffers inside this method.
*/
public function onFrameBufferCreate():Void {}
public function onScriptEvent(event:ScriptEvent) {} public function onScriptEvent(event:ScriptEvent) {}
public function onPause(event:PauseScriptEvent) {} public function onPause(event:PauseScriptEvent) {}