openfl / starling

Known as the "Cross-Platform Game Engine", Starling is a popular Stage3D framework for OpenFL and Haxe
Other
236 stars 68 forks source link

(Starling 2) painter.configureBackBuffer() not working correctly on HTML5 #77

Closed pol2095 closed 6 years ago

pol2095 commented 6 years ago

Hello,

I don’t have the same result on Flash (expected result)

GitHub Logo

and on HTML5

GitHub Logo my code

package;

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Rectangle;

import starling.core.Starling;
import starling.display.Canvas;
import starling.display.Image;
import starling.display.DisplayObject;
import starling.display.Sprite;
import starling.display.Stage;
import starling.textures.Texture;
import starling.rendering.Painter;
import starling.utils.Color;
import starling.utils.SystemUtil;

@:keep class Game extends Sprite
{
    public function new()
    {
        super();
    }

    public function start():Void
    {
        var bg:Canvas = new Canvas();
        bg.beginFill(0xCCCCCC);
        bg.drawRectangle(0, 0, stage.stageWidth, stage.stageHeight);
        bg.endFill();
        bg.alpha = 0.5;
        this.addChild(bg);

        var _width:Int = 400;
        var _height:Int = 200;
        var canvas: Canvas = new Canvas();
        canvas.x = canvas.y = 100;
        canvas.beginFill(0xFF0000);
        canvas.drawRectangle(0, 0, _width, _height);
        canvas.endFill();
        canvas.beginFill(0x00FF00);
        canvas.drawRectangle(_width, 0, _width, _height);
        canvas.endFill();
        canvas.beginFill(0x0000FF);
        canvas.drawRectangle(0, _height, _width, _height);
        canvas.endFill();
        canvas.beginFill(0x000000);
        canvas.drawRectangle(_width, _height, _width, _height);
        canvas.endFill();
        this.addChild(canvas);

        var bitmapData : BitmapData = takeScreenshot(stage.starling, canvas);
        this.removeChild(canvas);
        var image:Image = new Image( Texture.fromBitmap( new Bitmap( bitmapData ) ) );
        image.scale = 0.5;
        this.addChild( image );
    }

    private function takeScreenshot(starling : Starling, displayObject : DisplayObject, out:BitmapData=null, color:UInt=0x0, alpha:Float=0.0) : BitmapData
    {
        var painter:Painter = starling.painter;
        var viewPort:Rectangle = starling.viewPort;
        var stageWidth:Float = stage.stageWidth;
        var stageHeight:Float = stage.stageHeight;
        var viewPortRestore:Rectangle = (displayObject.width > stageWidth || displayObject.height > stageHeight) ? viewPort.clone() : null;
        var scaleX:Float = viewPort.width  / stageWidth;
        var scaleY:Float = viewPort.height / stageHeight;
        var backBufferScale:Float = painter.backBufferScaleFactor;
        var projectionX:Float, projectionY:Float;
        var bounds:Rectangle;
        if(viewPortRestore != null)
        {
            viewPort.width = displayObject.width;
            viewPort.height = displayObject.height;
            painter.configureBackBuffer( viewPort, starling.contentScaleFactor, starling.antiAliasing, SystemUtil.supportsDepthAndStencil );
        }

        if (Std.is(displayObject, Stage))
        {
            projectionX = viewPort.x < 0 ? -viewPort.x / scaleX : 0.0;
            projectionY = viewPort.y < 0 ? -viewPort.y / scaleY : 0.0;

            if (out == null) out = new BitmapData(Std.int(painter.backBufferWidth  * backBufferScale),
                                    Std.int(painter.backBufferHeight * backBufferScale));
        }
        else
        {
            bounds = displayObject.getBounds(displayObject.parent);
            projectionX = bounds.x;
            projectionY = bounds.y;

            if (out == null) out = new BitmapData(Math.ceil(bounds.width  * scaleX * backBufferScale),
                                    Math.ceil(bounds.height * scaleY * backBufferScale));
        }

        color = Color.multiply(color, alpha); // premultiply alpha

        painter.clear(color, alpha);
        painter.pushState();
        painter.setupContextDefaults();
        painter.state.renderTarget = null;
        painter.state.setModelviewMatricesToIdentity();
        painter.setStateTo(transformationMatrix);
        painter.state.setProjectionMatrix(projectionX, projectionY,
            painter.backBufferWidth / scaleX, painter.backBufferHeight / scaleY,
            stageWidth, stageHeight, stage.cameraPosition);

        render(painter);

        painter.finishMeshBatch();
        painter.context.drawToBitmapData(out);
        painter.popState();

        if(viewPortRestore != null)
        {
            viewPort.width = viewPortRestore.width;
            viewPort.height = viewPortRestore.height;
            painter.configureBackBuffer( viewPort, starling.contentScaleFactor, starling.antiAliasing, SystemUtil.supportsDepthAndStencil );
        }
        return out;
    }
}
<window width="500" height="400" orientation="portrait" background="0xffffff" />

Thanks

jgranick commented 6 years ago

It appears this is resolved by newer drawToBitmapData code (such as https://github.com/openfl/openfl/commit/61fb06ee83c3a3ccb09e1f461746c46cee71b741) :smile: :+1:

pol2095 commented 6 years ago

I try your fix but it doesn't solve the problem.

jgranick commented 6 years ago

I had the same aspect ratio on all platforms targeted using the development versions of Lime and OpenFL. However, there was a slight difference in behavior because stage.stageWidth reports as a different size initially on Flash Player, so in order for it to look exactly the same, I hard-coded a width/height (like 600x400) instead of using stageWidth/stageHeight

pol2095 commented 6 years ago

On html5, the result is smaller that the initial Sprite, the width is 800px in the initial Sprite, and 500px on html5 + 300px in white color. it's strange ???

varadig commented 6 years ago

Here is the same issue