Use filters for Text in GPU mode AIR mobile

后端 未结 3 1135
深忆病人
深忆病人 2021-01-13 16:31

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.<

相关标签:
3条回答
  • 2021-01-13 16:58

    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;
    
    0 讨论(0)
  • 2021-01-13 17:03

    The basic idea is to apply the filters as normal and then draw the display object to a bitmapdata and add the bitmap to the stage. See http://forums.adobe.com/message/3934192 for an example.

    If the text that you are applying this to is static it should be easy enough to do, but if you want to apply this dynamic text (for example, a score counter that will change frequently, or text that is user-editable) I imagine it may start to get annoying, but I don't know of any other solution.

    0 讨论(0)
  • 2021-01-13 17:06

    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;
        }
    
    0 讨论(0)
提交回复
热议问题