diff --git a/source/funkin/graphics/FunkinCamera.hx b/source/funkin/graphics/FunkinCamera.hx index 858e1f6b0..5cdb05d28 100644 --- a/source/funkin/graphics/FunkinCamera.hx +++ b/source/funkin/graphics/FunkinCamera.hx @@ -99,6 +99,14 @@ class FunkinCamera extends FlxCamera */ public var id:String; + /** + * If `true` the blend shader will try to blend with the camera underneath it. + * This is useful for, say, making a strumline note have a shader-only blend mode like `INVERT`. + * + * Defaults to `false` since this can impact performance. + */ + public var crossCameraBlending:Bool; + var _blendShader:RuntimeCustomBlendShader; var _backgroundFrame:FlxFrame; @@ -125,6 +133,8 @@ class FunkinCamera extends FlxCamera _cameraMatrix = new FlxMatrix(); _cameraTexture = FixedBitmapData.create(this.width, this.height); + + crossCameraBlending = false; } override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, @@ -136,7 +146,26 @@ class FunkinCamera extends FlxCamera // the specified blend mode requires the shader. if (shouldUseShader) { - _cameraTexture.drawCameraScreen(this); + if (crossCameraBlending) + { + var underneathCamera:FlxCamera = FlxG.cameras.list[FlxG.cameras.list.indexOf(this) - 1]; + if (underneathCamera != null) + { + _cameraTexture.drawCameraScreens([underneathCamera, this]); + + underneathCamera.clearDrawStack(); + underneathCamera.canvas.graphics.clear(); + } + else + { + _cameraTexture.drawCameraScreen(this); + } + } + else + { + _cameraTexture.drawCameraScreen(this); + } + _backgroundFrame.frame.set(0, 0, this.width, this.height); // Clear the camera's graphics diff --git a/source/funkin/graphics/framebuffer/BitmapDataUtil.hx b/source/funkin/graphics/framebuffer/BitmapDataUtil.hx index d83abf9f0..cc5e349e8 100644 --- a/source/funkin/graphics/framebuffer/BitmapDataUtil.hx +++ b/source/funkin/graphics/framebuffer/BitmapDataUtil.hx @@ -40,6 +40,33 @@ class BitmapDataUtil return _renderer; } + /** + * Draws the contents of multiple cameras onto a `BitmapData` object. + * + * @param bitmap The bitmap to draw onto. + * @param cameras The cameras to grab the screens from. + * + * @return The combined camera screens as a `BitmapData`. + */ + public static function drawCameraScreens(bitmap:BitmapData, cameras:Array):BitmapData + { + bitmap.__fillRect(bitmap.rect, 0, true); + + for (camera in cameras) + { + if (camera.filters != null && camera.filters.length > 0) + { + drawCameraScreen(bitmap, camera, false, true); + } + else + { + drawCameraScreen(bitmap, camera, false); + } + } + + return bitmap; + } + /** * Draws the contents of a camera onto a `BitmapData` object. * @@ -49,10 +76,12 @@ class BitmapDataUtil * * @param bitmap The bitmap to draw onto. * @param camera The camera to grab the screen from. + * @param clearBitmap Whether to clear the bitmap before drawing. + * @param drawFlashSprite Whether to draw the camera's flash sprite instead of the canvas. * * @return The camera screen as a `BitmapData`. */ - public static function drawCameraScreen(bitmap:BitmapData, camera:FlxCamera):BitmapData + public static function drawCameraScreen(bitmap:BitmapData, camera:FlxCamera, clearBitmap:Bool = true, drawFlashSprite:Bool = false):BitmapData { var matrix:FlxMatrix = new FlxMatrix(); var pivotX:Float = FlxG.scaleMode.scale.x; @@ -60,7 +89,7 @@ class BitmapDataUtil matrix.setTo(1 / pivotX, 0, 0, 1 / pivotY, camera.flashSprite.x / pivotX, camera.flashSprite.y / pivotY); - bitmap.__fillRect(bitmap.rect, 0, true); + if (clearBitmap) bitmap.__fillRect(bitmap.rect, 0, true); camera.render(); camera.flashSprite.__update(false, true); @@ -78,7 +107,14 @@ class BitmapDataUtil renderer.__worldColorTransform.__invert(); renderer.__setRenderTarget(bitmap); - bitmap.__drawGL(camera.canvas, renderer); + if (drawFlashSprite) + { + bitmap.__drawGL(camera.flashSprite, renderer); + } + else + { + bitmap.__drawGL(camera.canvas, renderer); + } return bitmap; }