Gamua / Starling-Framework

The Cross Platform Game Engine
http://www.starling-framework.org
Other
2.85k stars 819 forks source link

DisplacementMapFilter Issue #882

Closed Vabavia closed 8 years ago

Vabavia commented 8 years ago

Hi once again, as promised, I wrote small standalone example that reproduces my problem: When masked field moved DisplacementMapFilter acts unexpected. It moves when hold enabled (but must stay in position), and stays at top left corner when field cropped and field must be cropped to.

package {

    import flash.display.BitmapData;
    import flash.display.BitmapDataChannel;
    import flash.display.BlendMode;
    import flash.display.GradientType;
    import flash.display.Shape;
    import flash.display.SpreadMethod;
    import flash.display.Sprite;
    import flash.geom.Matrix;
    import flash.geom.Rectangle;
    import flash.system.Capabilities;

    import starling.core.Starling;
    import starling.display.Image;
    import starling.display.Quad;
    import starling.display.Sprite;
    import starling.events.Event;
    import starling.events.KeyboardEvent;
    import starling.filters.DisplacementMapFilter;
    import starling.text.TextField;
    import starling.textures.Texture;

    [SWF(width="640", height="360", frameRate="30", backgroundColor="#000000")]
    public class TestDisplacementMap extends flash.display.Sprite {
        private var board:Image;
        private var position:TextField;
        private var holdPosition:Boolean;

        public function TestDisplacementMap() {
            var starling:Starling = new Starling(starling.display.Sprite, stage, new Rectangle(0, 0, 640, 360));
            starling.stage.stageWidth = 640;
            starling.stage.stageHeight = 360;
            starling.enableErrorChecking = Capabilities.isDebugger;
            starling.skipUnchangedFrames = true;
            starling.addEventListener(Event.ROOT_CREATED, onRootCreated);
            starling.start();
        }

        private function update():void {
            position.text = 'x=' + board.x + ', y=' + board.y + '\nHold: ' + holdPosition;
            if (holdPosition) {
                DisplacementMapFilter(board.filter).mapX = -board.x;
                DisplacementMapFilter(board.filter).mapY = -board.y;
            }
        }

        private static function createWarpTexture(w:Number, h:Number, size:Number):Texture {
            var warpBD:BitmapData = new BitmapData(w, h, false, 0x7f7f7f);
            var warpShape:Shape = new Shape();
            var matrix:Matrix = new Matrix();
            matrix.createGradientBox(size, size, 0, 0, 0);
            warpShape.graphics.beginGradientFill(
                GradientType.RADIAL,
                [0x000000, 0x7F7F7F, 0x000000],
                [1, 1, 1],
                [0x00, 0x7F, 0xFF],
                matrix,
                SpreadMethod.PAD
            );
            warpShape.graphics.drawRect(0, 0, size, size);
            warpBD.draw(warpShape, null, null, BlendMode.ADD);
            var warpTexture:Texture = Texture.fromBitmapData(warpBD);
            return warpTexture;
        }

        private static function createBoardTexture(w:int, h:int, cellSize:int):Texture {
            var boardBD:BitmapData = new BitmapData(w, h, false, 0xf0f0f0);
            var rect:Rectangle = new Rectangle();
            for (var i:int = 0; i < w / cellSize; i++) {
                for (var j:int = 0; j < h / cellSize; j++) {
                    if ((i + j) % 2) {
                        rect.setTo(i * cellSize, j * cellSize, cellSize, cellSize);
                        boardBD.fillRect(rect, 0x0f0f0f);
                    }
                }
            }
            var boardTexture:Texture = Texture.fromBitmapData(boardBD);
            return boardTexture;
        }

        private function onRootCreated(event:Event):void {
            var root:starling.display.Sprite = event.data as starling.display.Sprite;
            var boardTexture:Texture = createBoardTexture(800, 600, 10);
            board = new Image(boardTexture);

            var mask:Quad = new Quad(320, 320);
            board.mask = mask;
            root.addChild(mask);

            root.addChild(board);

            var warpTexture:Texture = createWarpTexture(320, 320, 60);
            var warp:Image = new Image(warpTexture);
            warp.x = 320;
            root.addChild(warp);

            var filter:DisplacementMapFilter = new DisplacementMapFilter(
                warpTexture,
                BitmapDataChannel.RED,
                BitmapDataChannel.GREEN,
                40,
                40
            );
            board.filter = filter;

            position = new TextField(320, 40);
            position.format.color = 0x00ff00;
            position.y = 320;
            root.addChild(position);

            var help:TextField = new TextField(
                320, 40,
                'Use Arrows To Move Board,\nPress "H" For Filter Hold Position'
            );
            help.format.color = 0x00ff00;
            help.x = 320;
            help.y = 320;
            root.addChild(help);

            Starling.current.stage.addEventListener(KeyboardEvent.KEY_DOWN, onDebugKeyInput);
            update();
        }

        private function onDebugKeyInput(event:KeyboardEvent):void {
            switch (event.keyCode) {
                case 37:
                    board.x -= 15;
                    break;
                case 38:
                    board.y -= 15;
                    break;
                case 39:
                    board.x += 15;
                    break;
                case 40:
                    board.y += 15;
                    break;
                case 72:
                    holdPosition = !holdPosition;
                    break;
            }
            update();
        }
    }
}
PrimaryFeather commented 8 years ago

Thanks a lot for creating the sample! I'll look into it as soon as time permits.

PrimaryFeather commented 8 years ago

I just had a look at it, and can reproduce it. Thanks again for taking the time to create the sample!

Just one question: even without a mask, the filter acts wrongly, right? When moved out of the screen, the map texture should first be cropped and then move out, too. That't the main issue here — right?

PrimaryFeather commented 8 years ago

Oh, and one more thing: a quick fix is to call "filter.cache()". Then it will act as expected (until the filtered object changes, then you have to make that call again.

(Still, I'd like this to work consistently even without that workaround.)

PrimaryFeather commented 8 years ago

I think that should do it! Please try it out and let me know if that works for you. In any case, thanks a lot for pointing me at this problem!

Vabavia commented 8 years ago

Thank you! Fix work perfect, problem solved!

PrimaryFeather commented 8 years ago

I'm glad to hear that! :smile: All the best for the rest of your project!