Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use filters for Text in GPU mode AIR mobile

Unfortunately the filters do not work (drop shadow, glow) in GPU mode. I'm looking for an opportunity to use these effects to text in this mode. I will welcome any advice.

like image 644
Astraport Avatar asked Feb 19 '23 04:02

Astraport


2 Answers

As Astraport mentions, you'll need to draw the textfield out to a bitmapData every time you update the text using bitmapData.draw().

If you use textField.getBounds to determine the size of the bitmapData you need, the resulting bounds rectangle will not include the extra size due to the filter (e.g. a DropShadowFilter sticks out the side of the textbox by certain pixels depending on the 'distance' and 'blur'). To ensure that you include the filters when you draw the bitmap, you'll also need to use bitmapData.generateFilterRect() to get the correct size rect.

Code snippet (untested, but general idea):

// Remember the transform matrix of the text field
var offset : Matrix = myTextField.transform.matrix.clone();
// Get the bounds of just the textfield (does not include filters)
var tfBounds : Rectangle = myTextField.getBounds( myTextField.parent );     
// Create a bitmapData that is used just to calculate the size of the filters
var tempBD : BitmpaData = new BitmapData( Math.ceil(tfBounds.width), Math.ceil(tfBounds.height) );
// Make a copy of the textField bounds. We'll adjust this with the filters
var finalBounds : rectangle = tfBounds.clone();
// Step through each filter in the textField and adjust our bounds to include them all
var filterBounds : rectangle;
for each (var filter : BitmapFilter in myTextField.filters) {
    filterBounds = tempBD.generateFilterRect( tfBounds, filter );
    finalBounds.left = Math.min( finalBounds.left, filterBounds.left );
    finalBounds.right = Math.max( finalBounds.right, filterBounds.right );
    finalBounds.top = Math.min( finalBounds.top, filterBounds.top );
    finalBounds.bottom = Math.max( finalBounds.bottom, filterBounds.bottom );
}

// Now draw the textfield to a new bitmpaData
var textFieldBD : BitmpaData = new BitmapData( Math.ceil(finalBounds.width), math.ceil(finalBounds.height) );
offset.tx = -finalBounds.x;
offset.ty = -finalBounds.y;
textFieldBD.draw( myTextField.parent, offset, myTextField.transform.colorTransform );

// Create a bitmap and add the bitmap data. Note: normally you would create a
// bitmap once and just update the bitmpaData
var bitmap : Bitmap = new Bitmap();
myTextField.parent.addChild( bitmap );

// Position the bitmap in same place as textField
bitmap.bitmapData = textFieldBD;
bitmap.x = myTextField.x - finalBounds.x;
bitmap.y = myTextField.y - finalBounds.y;
myTextField.visible = false;
like image 175
Pixelthis Avatar answered Mar 02 '23 22:03

Pixelthis


Here is how to convert ANY DisplayObject to a Bitmap - useful for "restoring" filter effects in AIR GPU mobile rendermode. This is Pixelthis's solution, fixed, optimized and tested:

    // => 'bitmap' must belong to the same parent as 'obj'. 'obj' should be invisible.
    static public function Update(obj:DisplayObject, bitmap:Bitmap):void {
        //trace("CacheToBmp",obj.name);

        // Remember the transform matrix of the text field
        var offset:Matrix = obj.transform.matrix.clone();
        // Get the bounds of just the textfield (does not include filters)
        var bounds:Rectangle = obj.getBounds(obj);
        // Create a bitmapData that is used just to calculate the size of the filters
        var tempBD:BitmapData = new BitmapData( Math.ceil(bounds.width), Math.ceil(bounds.height), false );
        bounds.width = obj.width;
        bounds.height = obj.height;
        // Make a copy of the textField bounds. We'll adjust this with the filters
        var finalBounds:Rectangle = new Rectangle(0,0,bounds.width,bounds.height);

        // Step through each filter in the textField and adjust our bounds to include them all
        var filterBounds:Rectangle;
        for each (var filter:BitmapFilter in obj.filters) {
            filterBounds = tempBD.generateFilterRect( tempBD.rect, filter );
            finalBounds = finalBounds.union(filterBounds);
        }
        finalBounds.offset(bounds.x,bounds.y);
        finalBounds.x = Math.floor(finalBounds.x);
        finalBounds.y = Math.floor(finalBounds.y);
        finalBounds.width = Math.ceil(finalBounds.width);
        finalBounds.height = Math.ceil(finalBounds.height);

        // Now draw the textfield to a new bitmpaData
        var data:BitmapData = new BitmapData( finalBounds.width, finalBounds.height, false, 0 );
        offset.tx = -finalBounds.x;
        offset.ty = -finalBounds.y;
        data.drawWithQuality( obj, offset, obj.transform.colorTransform, obj.blendMode, null, true, StageQuality.HIGH );
        bitmap.bitmapData = data;

        // Position the bitmap in same place as 'obj'
        bitmap.x = obj.transform.matrix.tx + finalBounds.x;
        bitmap.y = obj.transform.matrix.ty + finalBounds.y;
    }
like image 29
Bill Kotsias Avatar answered Mar 02 '23 22:03

Bill Kotsias