Blending objects with eachother but not with background actionscript 3 - actionscript-3

I have a number of objects (represented as DisplayObjects) that i wish to blend with eachother.
However behind these objects there is a background that i do not want to involve in the blending.
So basically i want to blend these objects with eachother and afterwards use the result of this blending as a new DisplayObject (for example to put it on top of a randomly colored background).
So what i have is:
var obj1:DisplayObject = getFirstObj();
var obj2:DisplayObject = getSecObj();
var background:DisplayObject = getBackground();
obj1.blendMode = BlendMode.ADD;
obj2.blendMode = BlendMode.ADD;
A first attempt i tried was putting these objects into a common DisplayObjectContainer hoping that blending mode would only be relative to all objects contained by the same DisplayObjectContainer, but this does not seem to be the case.
var objectsPool:Sprite = new Sprite();
objectsPool.addChild( obj1 );
objectsPool.addChild( obj2 );
addChild( background );
addchild( objectsPool );
So that diddent get me anywhere.
Any help is appreciated.
EDIT: changed DisplayObjectContainer to Sprite in the last code snippet

If you put the objects into a container, and remove it from the stage, you can then draw it with the BitmapData class and create a new Bitmap object representing the combination. This will have a transparent background, and it's blendMode will be normal, allowing you to use it on the background.
var obj1:DisplayObject = getFirstObj();
var obj2:DisplayObject = getSecObj();
var background:DisplayObject = getBackground();
obj1.blendMode = BlendMode.ADD;
obj2.blendMode = BlendMode.ADD;
var objectsPool:DisplayObjectContainer = new DisplayObjectContainer();
objectsPool.addChild( obj1 );
objectsPool.addChild( obj2 );
var bmd:BitmapData = new BitmapData(objectsPool.width,objectsPool.height,true,0);
bmd.draw(objectsPool);
var drawnObject:Bitmap = new Bitmap(bmd);
addChild( background );
addchild( drawnObject );
(untested code, good luck)

Rather going to the effort of drawing a Bitmap yourself, there are options that cause Flash to rasterize a layer and it's children automatically. Try:
container.cacheAsBitmap = true;
or try:
container.blendMode = "layer";
or try:
container.filters = [new GlowFilter(0,0,0,0)];
Any of those options should cause the children to render into a Bitmap under the hood, invalidating their individual blend modes/effects on the background.

Related

How to combine 2 bitmaps via color mask?

I want to use 3 bitmaps to create 1 resulting bitmap. The first will be the background. The second shall be drawn on top of the first with the help of a mask.
The images are loaded into Bitmap/BitmapData objects.
Example:
(red-green image is the mask, red is the visible part)
back mask source result
So how can I do that? What drawing function do I use in ActionScript-3?
Thanks for any help!
Edit:
(my first working solution, works only with pure red, green or blue)
var back: BitmapData = // load the back image
var mask: BitmapData = // load the mask image
var source:BitmapData = // load the source image (32-bit)
var result:BitmapData = back.clone();
// clone source because it will be modified in next step
var source2: BitmapData = source.clone();
// red of the mask becomes the alpha channel of source2
source2.copyChannel(mask, new Rectangle(0, 0, mask.width, mask.height), new Point(0, 0), BitmapDataChannel.RED, BitmapDataChannel.ALPHA);
// draw source2 to result
result.draw(source2);
(Is there a more efficient way? In this solution I have to clone source in order to keep original source bitmap intact.)
I don't know if it's the best way (performance and logic), but you can try:
var background:BitmapData = new Background();
var bmd1:BitmapData = new Mask();
var bmd2:BitmapData = new SourceImage();
var bmDiff:Bitmap = new Bitmap(mergeMaskAndBackground(bmd2, background, bmd1));
addChild(bmDiff);
function mergeMaskAndBackground(src:BitmapData, background:BitmapData, msk:BitmapData):BitmapData
{
var diffBmpData:BitmapData = BitmapData(src.compare(msk));
diffBmpData.floodFill(0, 0, BitmapDataChannel.RED);
diffBmpData.draw(background, new Matrix(), new ColorTransform(), BlendMode.OVERLAY, background.rect, true);
return diffBmpData;
}

change the color of flash cs6 createjs exported lib object

i've testing some code in using createjs + box2dweb, i exported a vector ball in blue color drawn by flash cs 6, here is part of the code.
var birds = (function() {
var spawn = function() {
//circle = new lib.ball1();
//var birdBMP = new createjs.Bitmap("images/bird.png");
var birdBMP = new lib.ball1();
birdBMP.x = Math.round(Math.random()*500);
birdBMP.y = -30;
birdBMP.regX = 60.75; // important to set origin point to center of your bitmap
birdBMP.regY = 60.75;
birdBMP.snapToPixel = true;
birdBMP.mouseEnabled = false;
stage.addChild(birdBMP);
box2d.createBird(birdBMP);
}
return {
spawn: spawn
}
})();
here i want to do change the color of the blue ball, how can i do that?
******updated*******
inclucde js
change code
birdBMP.cache(0, 0, 121.5, 121.5);
colorRan1 = Math.round(Math.random()*255);
colorRan2 = Math.round(Math.random()*255);
colorRan3 = Math.round(Math.random()*255);
birdBMP.filters = [
new createjs.ColorFilter(0,0,0,1, colorRan1,colorRan2,colorRan3,0)
];
birdBMP.updateCache();
I don't know too much about the createjs Flash Extension, but I highly suspect, that from the Flash Export there is also no way to simply "change" a color - you have probably three options:
1) ColorMatrixFilter - this involves caching ect. and I wouldn't recommend this for your purpose.
2) Draw another ball in the desired color and change the Bitmap to that other (differently colored) ball.
3) Or if it is a simple shape you can use the exported lib.ball1() method and extend it with a color-parameter. - In that case you would also have to change the references bitmap/shape, if you want to change the color post-creation.

How do you add stroke to text in a GPU rendered Mobile app? [duplicate]

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

Drawing a bitmap based on a transformed movieclip

I'm drawing bitmaps of movieclips which I then feed into my hittest function to test for collisions. However, I'm not quite sure how i would add to the code below to take into account and draw bitmaps for movieclips which have been scaled and/or rotated. The below code obviously only works for non-transformed movieclips. I've included in comments code which i've already tried but to no success.
When adding the drawn bitmap to the stage, no matter whether the movieclip in question is transformed or not, the drawn bitmap is "cut off" and incorrectly drawn - it appears to only draw a section of it. However, this does not particularly affect the collision testing for the non-transformed movieclips, but has an adverse effect on transformed movieclips.
All of the movieclips I want to be drawn have been created through the graphics property.
//for example:
var mymc:MovieClip = new MovieClip();
var g:Graphics = mymc.graphics;
g.moveTo(0,0);
g.lineTo(17.5,0);
g.lineTo(8.75,17.5);
g.lineTo(-8.75,17.5);
g.lineTo(0,0);
main code:
for each(var mc:MovieClip in impassable) {
//var bMatrix:Matrix = new Matrix();
//bMatrix.scale(mc.scaleX, mc.scaleY);
//bMatrix.rotate(mc.rotation * (Math.PI/180));
var bData:BitmapData = new BitmapData(mc.width, mc.height, true, 0);
//bData.draw(mc, bMatrix);
bData.draw(mc);
var bitmap:Bitmap = new Bitmap(bData);
bitmap.x = mc.x;
bitmap.y = mc.y;
var HitTest:Number = newCollision(bitmap, centerX, centerY, 13.7);
Any thoughts? thanks
This function will create a BitmapData clone of a DisplayObject, taking into account its transform matrix, though it doesn't take into account bitmap filters. (Based on this answer.)
function createBitmapClone(target:DisplayObject):BitmapData {
var targetTransform:Matrix = target.transform.concatenatedMatrix;
var targetGlobalBounds:Rectangle = target.getBounds(target.stage);
var targetGlobalPos:Point = target.localToGlobal(new Point());
// Calculate difference between target origin and top left.
var targetOriginOffset:Point = new Point(targetGlobalPos.x - targetGlobalBounds.left, targetGlobalPos.y - targetGlobalBounds.top);
// Move transform matrix so that top left of target will be at (0, 0).
targetTransform.tx = targetOriginOffset.x;
targetTransform.ty = targetOriginOffset.y;
var cloneData:BitmapData = new BitmapData(targetGlobalBounds.width, targetGlobalBounds.height, true, 0x00000000);
cloneData.draw(target, targetTransform);
return cloneData;
}
When you call successive transforms on a Matrix, the ordering is very important and can really mess things up.
Luckily there is a helper method that allows you to specify translation, rotation and scaling in one go and avoid those issues - createBox
For your case, something like this:
var matrix:Matrix = new Matrix();
matrix.createBox(mc.scaleX, mc.scaleY, mc.rotation*Math.PI/180, 0, 0);
(the two zeros are for x and y translation)

How to import picture in flash with transaprent background

How do I make transparent background to imported image in flash, because now i imported it and image has white box around it.
code for adding images to stage
var imageBD = (Math.floor(Math.random()*2))? new Trees() : new Rocks;
var bitmap:Bitmap = new Bitmap();
var BD:BitmapData = new BitmapData(imageBD.width, imageBD.height);
BD.draw(imageBD);
bitmap.bitmapData = BD;
bitmap.width = mRadius * 2 * mToPx;
bitmap.height = mRadius * 2 * mToPx;
bitmap.x = pxStartX;
bitmap.y = pxStartY;
this.addChild(bitmap);
obstacleImages.push(bitmap)
Since i'm mew i cannot post images so i'm giving you a link to image:http://prntscr.com/pugdl
You need to specifically tell the BitmapData (docs) object to be transparent.
In your case, replace this line:
var BD:BitmapData = new BitmapData(imageBD.width, imageBD.height);
...with this:
var BD:BitmapData = new BitmapData(imageBD.width, imageBD.height, true, 0x00000000);
Make sure the image itself has transparency. General file types for these kinds of images are PNG or GIF.
You shouldn't have to do anything for Flash to find the transparency.