1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2024-08-20 07:25:59 +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()
{
camera = new FlxCamera();
camera.antialiasing = false;
camera.bgColor = FlxColor.TRANSPARENT;
camera.flashSprite.cacheAsBitmap = true;
@:privateAccess camera.flashSprite.stage = Lib.current.stage;
}
/**
* Creates a frame buffer with the given size.
* @param width the width
* @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();
final c3d = Lib.current.stage.context3D;
texture = c3d.createTexture(width, height, BGRA, true);
bitmap = BitmapData.fromTexture(texture);
camera.bgColor = bgColor;
}
/**
@ -45,7 +49,12 @@ class FrameBuffer
*/
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);
}
@ -58,17 +67,22 @@ class FrameBuffer
camera.clearDrawStack();
camera.canvas.graphics.clear();
camera.fill(camera.bgColor.to24Bit(), camera.useBgAlphaBlending, camera.bgColor.alphaFloat);
#if FLX_DEBUG
camera.debugLayer.graphics.clear();
#end
}
/**
* Renders all sprite copies.
*/
@:access(flixel.FlxCamera)
public function render():Void
{
for (spriteCopy in spriteCopies)
{
spriteCopy.render(camera);
}
camera.render();
}
/**

View file

@ -1,5 +1,6 @@
package funkin.graphics.framebuffer;
import flixel.util.FlxColor;
import openfl.display.BitmapData;
import flixel.FlxSprite;
import flixel.FlxCamera;
@ -21,33 +22,33 @@ class FrameBufferManager
/**
* Creates a new frame buffer with a 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))
{
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);
frameBufferMap[name] = fb;
}
final fb = new FrameBuffer();
fb.create(camera.width, camera.height, bgColor);
frameBufferMap[name] = fb;
return fb.bitmap;
}
/**
* Adds a copy of the sprite to the frame buffer.
* @param name the name of the frame buffer
* @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));
}
@ -58,27 +59,20 @@ class FrameBufferManager
{
for (_ => fb in frameBufferMap)
{
fb.follow(camera);
fb.lock();
}
}
/**
* Renders all the copies of the sprites. Make sure this is called between
* `lock` and `unlock`.
* Unlocks the frame buffers. This updates the bitmap data of each frame buffer.
*/
public function render():Void
public function unlock():Void
{
for (_ => fb in frameBufferMap)
{
fb.render();
}
}
/**
* After calling this you can use bitmap data of all frame buffers.
*/
public function unlock():Void
{
for (_ => fb in frameBufferMap)
{
fb.unlock();
@ -88,7 +82,7 @@ class FrameBufferManager
/**
* Returns the bitmap data 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
{
@ -96,7 +90,7 @@ class FrameBufferManager
}
/**
* Disposes all frame buffers.
* Disposes all frame buffers. The instance can be reused.
*/
public function dispose():Void
{

View file

@ -1,14 +1,15 @@
package funkin.graphics.framebuffer;
import flixel.util.FlxColor;
import flixel.FlxCamera;
import flixel.FlxSprite;
class SpriteCopy
{
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.color = color;
@ -21,30 +22,34 @@ class SpriteCopy
@:access(flixel.FlxSprite)
public function render(camera:FlxCamera):Void
{
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;
sprite._cameras = [camera];
if (color != -1)
if (color == null)
{
final red = color >> 16 & 0xFF;
final green = color >> 8 & 0xFF;
final blue = color & 0xFF;
sprite.setColorTransform(0, 0, 0, 1, red, green, blue, 0);
final tmpCameras = sprite._cameras;
sprite._cameras = [camera];
sprite.draw();
sprite._cameras = tmpCameras;
}
sprite.draw();
sprite._cameras = tmpCameras;
if (color != -1)
else
{
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);
}
}

View file

@ -15,7 +15,10 @@ import flixel.FlxObject;
import flixel.FlxSprite;
import flixel.FlxState;
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 funkin.play.components.ComboMilestone;
import flixel.math.FlxPoint;
@ -25,8 +28,6 @@ import flixel.math.FlxRect;
import flixel.text.FlxText;
import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import flixel.system.frontEnds.CameraFrontEnd;
import flixel.util.FlxColor;
import flixel.ui.FlxBar;
import flixel.util.FlxColor;
import funkin.api.newgrounds.NGio;
@ -37,21 +38,24 @@ import openfl.geom.Rectangle;
import funkin.audio.VoicesGroup;
import funkin.save.Save;
import funkin.Highscore.Tallies;
import funkin.NoteSplash;
import funkin.audio.VoicesGroup;
import funkin.data.notestyle.NoteStyleRegistry;
import funkin.input.PreciseInputManager;
import funkin.modding.events.ScriptEvent;
import funkin.ui.mainmenu.MainMenuState;
import funkin.modding.events.ScriptEventDispatcher;
import funkin.play.character.BaseCharacter;
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.VideoCutscene;
import funkin.data.event.SongEventData.SongEventParser;
import funkin.play.notes.NoteSprite;
import funkin.play.notes.NoteDirection;
import funkin.play.notes.NoteSprite;
import funkin.play.notes.Strumline;
import funkin.play.notes.SustainTrail;
import funkin.play.notes.notestyle.NoteStyle;
import funkin.play.scoring.Scoring;
import funkin.play.song.Song;
import funkin.data.song.SongRegistry;
@ -66,7 +70,6 @@ import funkin.ui.options.PreferencesMenu;
import funkin.ui.debug.stage.StageOffsetSubState;
import funkin.ui.story.StoryMenuState;
import funkin.util.SerializerUtil;
import funkin.util.SortUtil;
import lime.ui.Haptic;
#if discord_rpc
import Discord.DiscordClient;
@ -590,9 +593,6 @@ class PlayState extends MusicBeatSubState
}
initStrumlines();
// Initialize sprites for the buffer texture.
initMaskSprites();
// Initialize the judgements and combo meter.
comboPopUps = new PopUpStuff();
comboPopUps.cameras = [camHUD];
@ -980,28 +980,6 @@ class PlayState extends MusicBeatSubState
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
{
// ORDER: Module, Stage, Character, Song, Conversation, Note
@ -1275,11 +1253,6 @@ class PlayState extends MusicBeatSubState
performCleanup();
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.bgColor.alpha = 0; // Show the game scene behind the camera.
initBufferCameras();
FlxG.cameras.reset(camGame);
FlxG.cameras.add(camHUD, false);
FlxG.cameras.add(camCutscene, false);
@ -1329,24 +1300,6 @@ 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.
*/
@ -1397,24 +1350,6 @@ class PlayState extends MusicBeatSubState
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,
* and adds it to the state.
@ -1597,18 +1532,6 @@ 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.
*/

View file

@ -1,5 +1,8 @@
package funkin.play.stage;
import funkin.graphics.framebuffer.FrameBufferManager;
import flixel.util.FlxColor;
import funkin.graphics.framebuffer.SpriteCopy;
import flixel.FlxCamera;
import flixel.FlxSprite;
import flixel.group.FlxSpriteGroup;
@ -20,6 +23,26 @@ import funkin.util.assets.FlxAnimationUtil;
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.
*
@ -34,10 +57,9 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
public var camZoom:Float = 1.0;
/**
* The list of sprites that should be rendered for mask texture.
*/
public var maskSprites:Array<FlxSprite> = [];
var frameBufferMan:FrameBufferManager;
public final frameBufferSprites:Array<FrameBufferSprite> = [];
/**
* 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
{
if (frameBufferMan != null) frameBufferMan.dispose();
frameBufferMan = new FrameBufferManager(FlxG.camera);
onFrameBufferCreate();
buildStage();
this.refresh();
@ -691,6 +717,8 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
{
debugIconGroup = null;
}
frameBufferMan.dispose();
}
/**
@ -743,6 +771,19 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
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 onPause(event:PauseScriptEvent) {}