mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-23 08:07:54 -05:00
added GrabbableCamera
This commit is contained in:
parent
9fc3a46b48
commit
ab7ba485cb
9 changed files with 306 additions and 30 deletions
43
source/funkin/graphics/framebuffer/BitmapDataTools.hx
Normal file
43
source/funkin/graphics/framebuffer/BitmapDataTools.hx
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
package funkin.graphics.framebuffer;
|
||||||
|
|
||||||
|
import flixel.FlxG;
|
||||||
|
import openfl.display.Bitmap;
|
||||||
|
import openfl.display.BitmapData;
|
||||||
|
import openfl.display.Sprite;
|
||||||
|
import openfl.filters.BitmapFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides cool stuff for `BitmapData`s that have a hardware texture internally.
|
||||||
|
*/
|
||||||
|
class BitmapDataTools
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Applies a bitmap filter to a bitmap immediately. The bitmap filter may refer
|
||||||
|
* the bitmap itself as a shader input.
|
||||||
|
* @param bitmap the bitmap data
|
||||||
|
* @param filter the bitmap filter
|
||||||
|
*/
|
||||||
|
public static function applyFilter(bitmap:BitmapData, filter:BitmapFilter):Void
|
||||||
|
{
|
||||||
|
if (bitmap.readable)
|
||||||
|
{
|
||||||
|
FlxG.log.error('do not use `BitmapDataTools` for non-GPU bitmaps!');
|
||||||
|
}
|
||||||
|
// man, allow me to use anon structuers for local vars!
|
||||||
|
static var cache:{sprite:Sprite, bitmap:Bitmap} = null;
|
||||||
|
if (cache == null)
|
||||||
|
{
|
||||||
|
final sprite = new Sprite();
|
||||||
|
final bitmap = new Bitmap();
|
||||||
|
sprite.addChild(bitmap);
|
||||||
|
cache =
|
||||||
|
{
|
||||||
|
sprite: sprite,
|
||||||
|
bitmap: bitmap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cache.bitmap.bitmapData = bitmap;
|
||||||
|
cache.sprite.filters = [filter];
|
||||||
|
bitmap.draw(cache.sprite);
|
||||||
|
}
|
||||||
|
}
|
42
source/funkin/graphics/framebuffer/FixedBitmapData.hx
Normal file
42
source/funkin/graphics/framebuffer/FixedBitmapData.hx
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package funkin.graphics.framebuffer;
|
||||||
|
|
||||||
|
import openfl.display.BitmapData;
|
||||||
|
import openfl.display.DisplayObject;
|
||||||
|
import openfl.display.DisplayObjectContainer;
|
||||||
|
import openfl.display.IBitmapDrawable;
|
||||||
|
import openfl.display.OpenGLRenderer;
|
||||||
|
import openfl.display3D.textures.TextureBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `BitmapData` is kinda broken so I fixed it.
|
||||||
|
*/
|
||||||
|
@:access(openfl.display3D.textures.TextureBase)
|
||||||
|
@:access(openfl.display.OpenGLRenderer)
|
||||||
|
class FixedBitmapData extends BitmapData
|
||||||
|
{
|
||||||
|
override function __drawGL(source:IBitmapDrawable, renderer:OpenGLRenderer):Void
|
||||||
|
{
|
||||||
|
if (Std.isOfType(source, DisplayObject))
|
||||||
|
{
|
||||||
|
final object:DisplayObjectContainer = cast source;
|
||||||
|
renderer.__stage = object.stage;
|
||||||
|
}
|
||||||
|
super.__drawGL(source, renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Never use `BitmapData.fromTexture`, always use this.
|
||||||
|
* @param texture the texture
|
||||||
|
* @return the bitmap data
|
||||||
|
*/
|
||||||
|
public static function fromTexture(texture:TextureBase):FixedBitmapData
|
||||||
|
{
|
||||||
|
if (texture == null) return null;
|
||||||
|
final bitmapData = new FixedBitmapData(texture.__width, texture.__height, true, 0);
|
||||||
|
bitmapData.readable = false;
|
||||||
|
bitmapData.__texture = texture;
|
||||||
|
bitmapData.__textureContext = texture.__textureContext;
|
||||||
|
bitmapData.image = null;
|
||||||
|
return bitmapData;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
package funkin.graphics.framebuffer;
|
package funkin.graphics.framebuffer;
|
||||||
|
|
||||||
import openfl.geom.Rectangle;
|
|
||||||
import openfl.geom.Matrix;
|
|
||||||
import openfl.display.BitmapData;
|
|
||||||
import flixel.util.FlxColor;
|
|
||||||
import flixel.FlxCamera;
|
import flixel.FlxCamera;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
import openfl.Lib;
|
import openfl.Lib;
|
||||||
|
import openfl.display.BitmapData;
|
||||||
import openfl.display3D.textures.TextureBase;
|
import openfl.display3D.textures.TextureBase;
|
||||||
|
import openfl.geom.Matrix;
|
||||||
|
import openfl.geom.Rectangle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A single frame buffer. Used by `FrameBufferManager`.
|
* A single frame buffer. Used by `FrameBufferManager`.
|
||||||
|
@ -27,7 +27,6 @@ class FrameBuffer
|
||||||
camera = new FlxCamera();
|
camera = new FlxCamera();
|
||||||
camera.antialiasing = false;
|
camera.antialiasing = false;
|
||||||
camera.bgColor = FlxColor.TRANSPARENT;
|
camera.bgColor = FlxColor.TRANSPARENT;
|
||||||
camera.flashSprite.cacheAsBitmap = true;
|
|
||||||
@:privateAccess camera.flashSprite.stage = Lib.current.stage;
|
@:privateAccess camera.flashSprite.stage = Lib.current.stage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +40,7 @@ class FrameBuffer
|
||||||
{
|
{
|
||||||
dispose();
|
dispose();
|
||||||
texture = Lib.current.stage.context3D.createTexture(width, height, BGRA, true);
|
texture = Lib.current.stage.context3D.createTexture(width, height, BGRA, true);
|
||||||
bitmap = BitmapData.fromTexture(texture);
|
bitmap = FixedBitmapData.fromTexture(texture);
|
||||||
camera.bgColor = bgColor;
|
camera.bgColor = bgColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +107,7 @@ class FrameBuffer
|
||||||
bitmap.dispose();
|
bitmap.dispose();
|
||||||
bitmap = null;
|
bitmap = null;
|
||||||
}
|
}
|
||||||
spriteCopies.clear();
|
spriteCopies.resize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package funkin.graphics.framebuffer;
|
package funkin.graphics.framebuffer;
|
||||||
|
|
||||||
|
import flixel.FlxCamera;
|
||||||
|
import flixel.FlxG;
|
||||||
|
import flixel.FlxSprite;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import openfl.display.BitmapData;
|
import openfl.display.BitmapData;
|
||||||
import flixel.FlxSprite;
|
|
||||||
import flixel.FlxCamera;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages frame buffers and gives access to each frame buffer.
|
* Manages frame buffers and gives access to each frame buffer.
|
||||||
|
@ -56,7 +57,7 @@ class FrameBufferManager
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this before everything is drawn.
|
* Call this before drawing anything.
|
||||||
*/
|
*/
|
||||||
public function lock():Void
|
public function lock():Void
|
||||||
{
|
{
|
||||||
|
|
161
source/funkin/graphics/framebuffer/GrabbableCamera.hx
Normal file
161
source/funkin/graphics/framebuffer/GrabbableCamera.hx
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
package funkin.graphics.framebuffer;
|
||||||
|
|
||||||
|
import flixel.FlxCamera;
|
||||||
|
import flixel.FlxG;
|
||||||
|
import flixel.graphics.FlxGraphic;
|
||||||
|
import flixel.graphics.frames.FlxFrame;
|
||||||
|
import flixel.math.FlxMatrix;
|
||||||
|
import flixel.math.FlxRect;
|
||||||
|
import flixel.system.FlxAssets.FlxShader;
|
||||||
|
import openfl.Lib;
|
||||||
|
import openfl.display.BitmapData;
|
||||||
|
import openfl.display3D.textures.TextureBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A camera, but grabbable.
|
||||||
|
*/
|
||||||
|
@:access(openfl.display.DisplayObject)
|
||||||
|
@:access(openfl.display.BitmapData)
|
||||||
|
@:access(openfl.display3D.Context3D)
|
||||||
|
@:access(openfl.display3D.textures.TextureBase)
|
||||||
|
@:access(flixel.graphics.FlxGraphic)
|
||||||
|
@:access(flixel.graphics.frames.FlxFrame)
|
||||||
|
class GrabbableCamera extends FlxCamera
|
||||||
|
{
|
||||||
|
final grabbed:Array<BitmapData> = [];
|
||||||
|
final texturePool:Array<TextureBase> = [];
|
||||||
|
final defaultShader:FlxShader = new FlxShader();
|
||||||
|
|
||||||
|
final bgTexture:TextureBase;
|
||||||
|
final bgBitmap:BitmapData;
|
||||||
|
final bgFrame:FlxFrame;
|
||||||
|
|
||||||
|
public function new(x:Int = 0, y:Int = 0, width:Int = 0, height:Int = 0, zoom:Float = 0)
|
||||||
|
{
|
||||||
|
super(x, y, width, height, zoom);
|
||||||
|
bgTexture = pickTexture(width, height);
|
||||||
|
bgBitmap = FixedBitmapData.fromTexture(bgTexture);
|
||||||
|
bgFrame = new FlxFrame(new FlxGraphic('', null));
|
||||||
|
bgFrame.parent.bitmap = bgBitmap;
|
||||||
|
bgFrame.frame = new FlxRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grabs the camera screen and returns it as a `BitmapData`. The returned bitmap
|
||||||
|
* will not be referred by the camera, so changing it will not affect the scene.
|
||||||
|
* @param applyFilters if this is `true`, the camera's filters will be applied to the grabbed bitmap
|
||||||
|
* @return the grabbed bitmap data
|
||||||
|
*/
|
||||||
|
public function grabScreen(applyFilters:Bool):BitmapData
|
||||||
|
{
|
||||||
|
final texture = pickTexture(width, height);
|
||||||
|
final bitmap = FixedBitmapData.fromTexture(texture);
|
||||||
|
squashTo(bitmap, applyFilters);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
function squashTo(bitmap:BitmapData, applyFilters:Bool):Void
|
||||||
|
{
|
||||||
|
static final matrix = new FlxMatrix();
|
||||||
|
|
||||||
|
// resize the background bitmap if needed
|
||||||
|
if (bgTexture.__width != width || bgTexture.__height != height)
|
||||||
|
{
|
||||||
|
resizeTexture(bgTexture, width, height);
|
||||||
|
bgBitmap.__resize(width, height);
|
||||||
|
bgFrame.parent.bitmap = bgBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// grab the bitmap
|
||||||
|
render();
|
||||||
|
bitmap.fillRect(bitmap.rect, 0);
|
||||||
|
matrix.setTo(1, 0, 0, 1, flashSprite.x, flashSprite.y);
|
||||||
|
if (applyFilters)
|
||||||
|
{
|
||||||
|
bitmap.draw(flashSprite, matrix);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
final tmp = flashSprite.filters;
|
||||||
|
flashSprite.filters = null;
|
||||||
|
bitmap.draw(flashSprite, matrix);
|
||||||
|
flashSprite.filters = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// also copy to the background bitmap
|
||||||
|
bgBitmap.fillRect(bgBitmap.rect, 0);
|
||||||
|
bgBitmap.draw(bitmap);
|
||||||
|
|
||||||
|
// clear graphics data
|
||||||
|
super.clearDrawStack();
|
||||||
|
canvas.graphics.clear();
|
||||||
|
|
||||||
|
// render the background bitmap
|
||||||
|
bgFrame.frame.set(0, 0, width, height);
|
||||||
|
matrix.setTo(viewWidth / width, 0, 0, viewHeight / height, viewMarginLeft, viewMarginTop);
|
||||||
|
drawPixels(bgFrame, matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resizeTexture(texture:TextureBase, width:Int, height:Int):Void
|
||||||
|
{
|
||||||
|
texture.__width = width;
|
||||||
|
texture.__height = height;
|
||||||
|
final context = texture.__context;
|
||||||
|
final gl = context.gl;
|
||||||
|
context.__bindGLTexture2D(texture.__textureID);
|
||||||
|
gl.texImage2D(gl.TEXTURE_2D, 0, texture.__internalFormat, width, height, 0, texture.__format, gl.UNSIGNED_BYTE, null);
|
||||||
|
context.__bindGLTexture2D(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function destroy():Void
|
||||||
|
{
|
||||||
|
super.destroy();
|
||||||
|
disposeTextures();
|
||||||
|
}
|
||||||
|
|
||||||
|
override function clearDrawStack():Void
|
||||||
|
{
|
||||||
|
super.clearDrawStack();
|
||||||
|
// also clear grabbed bitmaps
|
||||||
|
for (bitmap in grabbed)
|
||||||
|
{
|
||||||
|
texturePool.push(@:privateAccess bitmap.__texture);
|
||||||
|
bitmap.dispose();
|
||||||
|
}
|
||||||
|
grabbed.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickTexture(width:Int, height:Int):TextureBase
|
||||||
|
{
|
||||||
|
// zero-sized textures will be problematic
|
||||||
|
width = width < 1 ? 1 : width;
|
||||||
|
height = height < 1 ? 1 : height;
|
||||||
|
if (texturePool.length > 0)
|
||||||
|
{
|
||||||
|
final res = texturePool.pop();
|
||||||
|
if (res.__width != width || res.__height != height)
|
||||||
|
{
|
||||||
|
resizeTexture(res, width, height);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return Lib.current.stage.context3D.createTexture(width, height, BGRA, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function disposeTextures():Void
|
||||||
|
{
|
||||||
|
trace('disposing textures');
|
||||||
|
for (bitmap in grabbed)
|
||||||
|
{
|
||||||
|
bitmap.dispose();
|
||||||
|
}
|
||||||
|
grabbed.clear();
|
||||||
|
for (texture in texturePool)
|
||||||
|
{
|
||||||
|
texture.dispose();
|
||||||
|
}
|
||||||
|
texturePool.resize(0);
|
||||||
|
bgTexture.dispose();
|
||||||
|
bgBitmap.dispose();
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,21 +61,12 @@ class RuntimeRainShader extends RuntimePostEffectShader
|
||||||
return puddleY = value;
|
return puddleY = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public var groundMap(default, set):BitmapData;
|
public var blurredScreen(default, set):BitmapData;
|
||||||
|
|
||||||
function set_groundMap(value:BitmapData):BitmapData
|
function set_blurredScreen(value:BitmapData):BitmapData
|
||||||
{
|
{
|
||||||
this.setBitmapData('uGroundMap', value);
|
this.setBitmapData('uBlurredScreen', value);
|
||||||
// this.setFloat2('uPuddleTextureSize', value.width, value.height);
|
return blurredScreen = value;
|
||||||
return groundMap = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public var lightMap(default, set):BitmapData;
|
|
||||||
|
|
||||||
function set_lightMap(value:BitmapData):BitmapData
|
|
||||||
{
|
|
||||||
this.setBitmapData('uLightMap', value);
|
|
||||||
return lightMap = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var mask(default, set):BitmapData;
|
public var mask(default, set):BitmapData;
|
||||||
|
|
|
@ -411,7 +411,7 @@ class PlayState extends MusicBeatSubState
|
||||||
/**
|
/**
|
||||||
* The camera which contains, and controls visibility of, the stage and characters.
|
* The camera which contains, and controls visibility of, the stage and characters.
|
||||||
*/
|
*/
|
||||||
public var camGame:FlxCamera;
|
public var camGame:SwagCamera;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The camera which contains, and controls visibility of, a video cutscene.
|
* The camera which contains, and controls visibility of, a video cutscene.
|
||||||
|
|
|
@ -3,6 +3,7 @@ package funkin.play.stage;
|
||||||
import funkin.graphics.framebuffer.FrameBufferManager;
|
import funkin.graphics.framebuffer.FrameBufferManager;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import funkin.graphics.framebuffer.SpriteCopy;
|
import funkin.graphics.framebuffer.SpriteCopy;
|
||||||
|
import funkin.graphics.framebuffer.GrabbableCamera;
|
||||||
import flixel.FlxCamera;
|
import flixel.FlxCamera;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.group.FlxSpriteGroup;
|
import flixel.group.FlxSpriteGroup;
|
||||||
|
@ -78,7 +79,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
||||||
{
|
{
|
||||||
if (frameBufferMan != null) frameBufferMan.dispose();
|
if (frameBufferMan != null) frameBufferMan.dispose();
|
||||||
frameBufferMan = new FrameBufferManager(FlxG.camera);
|
frameBufferMan = new FrameBufferManager(FlxG.camera);
|
||||||
onFrameBufferCreate();
|
setupFrameBuffers();
|
||||||
|
|
||||||
buildStage();
|
buildStage();
|
||||||
this.refresh();
|
this.refresh();
|
||||||
|
@ -696,8 +697,11 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
||||||
debugIconGroup = null;
|
debugIconGroup = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frameBufferMan != null)
|
||||||
|
{
|
||||||
frameBufferMan.dispose();
|
frameBufferMan.dispose();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function that gets called once per step in the song.
|
* A function that gets called once per step in the song.
|
||||||
|
@ -750,17 +754,51 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
||||||
}
|
}
|
||||||
|
|
||||||
override function draw():Void
|
override function draw():Void
|
||||||
|
{
|
||||||
|
if (frameBufferMan != null)
|
||||||
{
|
{
|
||||||
frameBufferMan.lock();
|
frameBufferMan.lock();
|
||||||
|
}
|
||||||
super.draw();
|
super.draw();
|
||||||
|
if (frameBufferMan != null)
|
||||||
|
{
|
||||||
frameBufferMan.unlock();
|
frameBufferMan.unlock();
|
||||||
}
|
}
|
||||||
|
frameBuffersUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the frame buffer manager is ready.
|
* Called when the frame buffer manager is ready.
|
||||||
* Create frame buffers inside this method.
|
* Create frame buffers inside this method.
|
||||||
*/
|
*/
|
||||||
public function onFrameBufferCreate():Void {}
|
function setupFrameBuffers():Void {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when all the frame buffers are updated. If you need any
|
||||||
|
* frame buffers before `grabScreen()`, make sure you
|
||||||
|
* grab the screen inside this method since it immediately uses the
|
||||||
|
* frame buffers.
|
||||||
|
*/
|
||||||
|
function frameBuffersUpdated():Void {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grabs the current screen and returns it as a bitmap data. You can sefely modify it.
|
||||||
|
* @param applyFilters if this is `true`, the filters set to the camera will be applied to the resulting bitmap
|
||||||
|
* @return the grabbed screen
|
||||||
|
*/
|
||||||
|
function grabScreen(applyFilters:Bool):BitmapData
|
||||||
|
{
|
||||||
|
if (Std.isOfType(FlxG.camera, GrabbableCamera))
|
||||||
|
{
|
||||||
|
final cam:GrabbableCamera = cast FlxG.camera;
|
||||||
|
return cam.grabScreen(applyFilters);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FlxG.log.error('cannot grab the screen: the main camera is not grabbable');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function onScriptEvent(event:ScriptEvent) {}
|
public function onScriptEvent(event:ScriptEvent) {}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package funkin.ui;
|
package funkin.ui;
|
||||||
|
|
||||||
|
import funkin.graphics.framebuffer.GrabbableCamera;
|
||||||
import flixel.FlxCamera;
|
import flixel.FlxCamera;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
import funkin.util.MathUtil;
|
import funkin.util.MathUtil;
|
||||||
|
|
||||||
class SwagCamera extends FlxCamera
|
class SwagCamera extends GrabbableCamera
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* properly follow framerate
|
* properly follow framerate
|
||||||
|
|
Loading…
Reference in a new issue