Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copying a FlxCamera's pixels to a FlxSprite doesn't keep zoom, scroll, etc. of the camera #2145

Open
grayhaze opened this issue Apr 28, 2018 · 7 comments

Comments

@grayhaze
Copy link
Contributor

grayhaze commented Apr 28, 2018

  • Haxe version: 3.4.7
  • Flixel version: git
  • OpenFL version: git
  • Lime version: git
  • Affected targets: cpp

Code snippet reproducing the issue:

package;

using flixel.util.FlxSpriteUtil;

import flash.geom.Point;
import flixel.FlxCamera;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.FlxState;

class PlayState extends FlxState
{
	var cameraOriginal:FlxCamera;
	var circleSprite:FlxSprite;
	var cameraCopy:FlxCamera;
	var cameraCopySprite:FlxSprite;

	override public function create():Void
	{
		super.create();
		cameraOriginal = new FlxCamera(0, 0, Std.int(FlxG.width / 2), Std.int(FlxG.height));
		FlxG.cameras.add(cameraOriginal);
		cameraOriginal.zoom = 3;
		circleSprite = new FlxSprite((FlxG.width / 4) - 32, (FlxG.height / 2) - 32);
		circleSprite.makeGraphic(64, 64, 0, true);
		circleSprite.drawCircle(32, 32, 32, 0xffff0000);
		circleSprite.updateHitbox();
		circleSprite.cameras = [cameraOriginal];
		add(circleSprite);
		cameraCopy = new FlxCamera(Std.int(FlxG.width / 2), 0, Std.int(FlxG.width / 2), Std.int(FlxG.height));
		FlxG.cameras.add(cameraCopy);
		cameraCopySprite = new FlxSprite(0, 0);
		cameraCopySprite.makeGraphic(Std.int(FlxG.width / 2), Std.int(FlxG.height), 0, true);
		cameraCopySprite.cameras = [cameraCopy];
		add(cameraCopySprite);
	}

	override public function update(elapsed:Float):Void
	{
		super.update(elapsed);
		cameraCopySprite.fill(0);
		if (FlxG.renderBlit) {
			cameraCopySprite.pixels.copyPixels(cameraOriginal.buffer, cameraOriginal.buffer.rect, new Point());
		} else {
			cameraCopySprite.pixels.draw(cameraOriginal.canvas);
		}
	}
}

Observed behavior:

I'm trying to copy the contents of a camera to a sprite so that I can apply effects to that sprite, such as applying an alpha mask by using copyChannel() on the resulting BitmapData (e.g. https://stackoverflow.com/questions/48075991/is-there-a-way-to-apply-an-alpha-mask-to-a-flxcamera?rq=1). Before getting to the point of applying effects however, I'm having difficulty getting the camera pixels to copy over 1:1 while observing camera zoom, scroll, etc. The above example creates a single sprite containing a red circle, which is placed in the source camera. That camera's zoom is then set to 3, resulting in the circle being rendered at 300% of its original size. When I copy the pixels from this camera to a new sprite, which is displayed in a second camera, it seems that the current zoom of the source camera is not observed and this results in the circle displaying at its original size in the target sprite.

2018-04-28 10_30_54-flxproject

Expected behavior:

I would expect the target sprite to be a 1:1 copy of the source camera's current view, including zoom, scroll, etc.

@Gama11
Copy link
Member

Gama11 commented Apr 28, 2018

Does it work with Lime 2.9.1 + OpenFL 3.6.1?

@grayhaze
Copy link
Contributor Author

No, I get the exact same result with 2.9.1 and 3.6.1.

@grayhaze
Copy link
Contributor Author

I assume that a FlxCamera's pixels represent the state of the camera's view before any transforms are applied for camera zoom, etc. Do I perhaps need to apply a matrix to the copyPixels() or draw() calls to apply these transforms manually? Is there a way of accessing the relevant matrix from the FlxCamera, as the internal matrices seem to be private?

@JoeCreates
Copy link
Member

JoeCreates commented Apr 28, 2018 via email

@grayhaze
Copy link
Contributor Author

grayhaze commented Apr 28, 2018

As an aside, compiling the above code to Flash produces the following output:

2018-04-28 13_43_31-adobe flash player 29

I don't actually use the Flash target in my main project, but it appears that the behaviour in this target is to copy the camera viewport correctly, but still at the default zoom.

@grayhaze
Copy link
Contributor Author

So I've got this sort of working on cpp targets, using a transform matrix built using public properties of the camera:

	override public function update(elapsed:Float):Void
	{
		super.update(elapsed);
		cameraCopySprite.fill(0);
		var transformMatrix = new Matrix();
		transformMatrix.translate(-(0.5 * cameraOriginal.width * (cameraOriginal.scaleX - cameraOriginal.initialZoom) / cameraOriginal.scaleX), -(0.5 * cameraOriginal.height * (cameraOriginal.scaleY - cameraOriginal.initialZoom) / cameraOriginal.scaleY));
		transformMatrix.scale(cameraOriginal.scaleX * 0.997, cameraOriginal.scaleY * 0.997);
		cameraCopySprite.pixels.draw(cameraOriginal.canvas, transformMatrix);
	}

The translation calculation is based on those done in FlxCamera to calculate offsets, and that part works. The scale calculation requires multiplying the camera's scale by some seemingly arbitrary value. If that multiplication isn't done, or the value by which I'm multiplying passes a certain threshold (which varies depending on the zoom), the resulting image is empty. If it weren't for this I'd be happy just performing these transforms whenever I need to copy the camera.

2018-04-28 15_14_02-flxproject

@grayhaze
Copy link
Contributor Author

grayhaze commented Apr 28, 2018

So this works. I have no idea why though. 😁

	override public function update(elapsed:Float):Void
	{
		super.update(elapsed);
		cameraCopySprite.fill(0);
		cameraCopySprite.pixels.draw(cameraOriginal.canvas);
		cameraCopySprite.fill(0);
		var transformMatrix = new Matrix();
		transformMatrix.translate(-(0.5 * cameraOriginal.width * (cameraOriginal.scaleX - cameraOriginal.initialZoom) / cameraOriginal.scaleX), -(0.5 * cameraOriginal.height * (cameraOriginal.scaleY - cameraOriginal.initialZoom) / cameraOriginal.scaleY));
		transformMatrix.scale(cameraOriginal.scaleX, cameraOriginal.scaleY);
		cameraCopySprite.pixels.draw(cameraOriginal.canvas, transformMatrix);
	}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants