Is it possible to improve the performance of this drawing technique?

試著忘記壹切 提交于 2019-12-23 03:00:36

问题


Am currently working on a tool created by a colleague of mine and would like to improve performance. Basically, it's a tool for drawing on screen and uses a combination of Sprites and the Graphics class to draw a line segment every time the mouse is moved when the mouse button is down. Here is the drawing bit:

// on MouseMove
protected function drawLine(e:MouseEvent):void {
        if (currentTool.thickness > 0){
            //pen
            var line:Sprite = new Sprite();

            line.graphics.lineStyle(currentTool.thickness, currentColour);
            line.graphics.moveTo(lastKnownPoint.x, lastKnownPoint.y);
            line.graphics.lineTo(e.localX, e.localY);
            inkLayer.addChild(line);
            lastKnownPoint.x = e.localX;
            lastKnownPoint.y = e.localY;
            e.updateAfterEvent();
        } else {
            //eraser
            var inkChildren:int = inkLayer.numChildren;
            for (var i:uint = inkChildren; i > 0; i--){
                if (toolCursor.hitTestObject(inkLayer.getChildAt(i - 1))){
                    inkLayer.removeChildAt(i - 1);
                }
            }
        }
    }

As you can see, it checks if the line 'thickness' property and draws if it is and erases if it isn't.

I did think of using a technique similar to blitting here where it'd draw to a bitmap but I'm not sure this'd give the performance boost I want or if, indeed, there would be any way to have an eraser function.

Any ideas on a better way to do this? The drawing itself works nicely - this isn't the problem, it's the performance of the subsequent 'drawn' sprites.


回答1:


I have solved similar problem recently and I could not think of efficient way to implement eraser with vectors. So I made a bitmap to erase drawings from. It works this way: when user selects colored pen, while he holds the left button, draw lines to sprite. When left button is released, sprite is flushed to BitmapData and board is redrawn using this bitmap. When user selects eraser, he draws thick black lines on sprite (they are invisible with alpha = 0). After each movement, affected part of sprite is flushed to BitmapData in erasing mode and this is reflected on board. To support scaling, I made bitmap big and hooked BlurFilter on it. It's not perfect, but works fast enough.

Edit: some code, not tested after cut, but should give the idea:

public class DrawingBoard extends Sprite {
    //...vars declaration
    public function DrawingBoard(width:int, height:int, bitmapWidth:int = 1000, bitmapHeight:int = 1000)
    {
        super();
        scrollRect = new Rectangle(0, 0, width, height);

        downMatrix = new Matrix();
        downMatrix.scale(bitmapWidth / width, bitmapHeight / height);

        upMatrix = new Matrix();
        upMatrix.scale(width / bitmapWidth, height / bitmapHeight);

        bitmap = new BitmapData(bitmapWidth, bitmapHeight, true, 0x00000000);

        //on canvas we draw vector pencils and eraser traces before flush
        canvas = new Sprite();
        addChild(canvas);

        filters = [new BlurFilter(3, 3)];
    }

        //external control api
    public function moveTo(point:Point):void {
        canvas.graphics.moveTo(point.x, point.y);
        var lineWidth:Number = 4 / parent.scaleX;
        canvas.graphics.lineStyle(lineWidth, currentColor, 0.8, false, LineScaleMode.NORMAL);
    }

    public function lineTo(point:Point):void {
        canvas.graphics.lineTo(point.x, point.y);
    }

    public function eraserLineTo(point:Point):void {
        canvas.graphics.lineStyle(eraserSize, 0, 1.0);
        canvas.graphics.lineTo(point.x, point.y);
        flush(BlendMode.ERASE);
        canvas.graphics.moveTo(point.x, point.y);
    }

    public function flush(blendMode:String = null):void {
                    //draw temporary vectors to bitmap
        bitmap.draw(canvas, downMatrix, null, blendMode, null, true);
                    //update board
        var bounds:Rectangle = canvas.getBounds(this);
        with (graphics) {
            beginBitmapFill(bitmap, upMatrix);
            drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
            endFill();
        }
                    //erase temporary vectors
        canvas.graphics.clear();
    }
}



回答2:


While drawing you will notice that curves are not sharp anymore.. and they will become composed from bigger and bigger lines. The workaround is not to create millions of small lines and add them as children, but to write in the same container using copyBitmapData.




回答3:


You could optimize this by checking at the start of the method whether lastKnownPoint.x and lastKnownPoint.y are the same value or within a certain distance (2 or 3 pixels, perhaps). If they are, you simply return without doing anything. Experiment and find the distance at which you strike a good balance between performance and smoothness of the line.



来源:https://stackoverflow.com/questions/3996984/is-it-possible-to-improve-the-performance-of-this-drawing-technique

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!