Drawing a bitmap based on a transformed movieclip - actionscript-3

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)

Related

Flash/AS3 - MovieClip into Bitmap

I need to turn a MovieClip that I have on the stage into a Bitmap. The function I have made for this halfway works; it does make a Bitmap from the MovieClip with the correct image, but it does not rotate it.
Here is the function
function makeBitmapData(mov):BitmapData
{
var bmpData:BitmapData = new BitmapData(mov.width, mov.height, true, 0);
bmpData.draw(mov);
this.addChild(new Bitmap(bmpData)); //Shows the bitmap on screen purely for example
return bmpData;
}
Here is the output
How should I rotate the bitmap or just purely copy all the pixels in that bitmap, rotated and all?
Have you checked rotate() function and fl.motion.MatrixTransformer class? Also this question looks helpful.
In the function that implements your code.
var b:Bitmap = new Bitmap ( makeBitmapData(mov) );
addChild(b);
b.rotation = mov.rotation;
One way to accomplish this, is to draw from the items parent instead, that way any transformation/filters will be reflected in the bitmap data captured. So something like this:
function makeBitmapData(mov:DisplayObject):BitmapData
{
var rect:Rectangle = mov.getBounds(mov.parent); //get the bounds of the item relative to it's parent
var bmpData:BitmapData = new BitmapData(rect.width, rect.height, false, 0xFF0000);
//you have to pass a matrix so you only draw the part of the parent that contains the child.
bmpData.draw(mov.parent, new Matrix(1,0,0,1,-rect.x,-rect.y));
addChild(new Bitmap(bmpData)); //Shows the bitmap on screen purely for example
return bmpData;
}

Converting a Shape to a Bitmap

I have created a subclass of Shape that contains paired GraphicsPath and GraphicsStroke objects. The class has a public method for retrieving the shape as a bitmap for passage to a Pixelbender kernel - the method is as follows:
public function GetBitmap():Bitmap{
var bmpData:BitmapData = new BitmapData(this.width, this.height, true, 0x00FFFFFF);
bmpData.draw(this);
return new Bitmap(bmpData);
}
To test these, I have the following code:
var v:Vector.<Number> = new <Number>[10,10,50,10,50,50]; //defines GraphicsPath.data to be used
var wave:CustomWave = new CustomWave(v,0xff0000); //constructor for the subclass
wave.Refresh(); //clears the Shape and redraws the GraphicsPath
//adds as shape
addChild(wave);
//adds as bitmap
var bmp:Bitmap = wave.GetBitmap()
addChild(bmp);
The visual output from both:
Any idea what could be causing the difference?
It's a long story, how to work with width and height, if you don't want any problems, draw your path from (0,0) or you can modify your function:
public function GetBitmap():Bitmap {
var bounds: Rectangle = getBounds(this);
var bmpData:BitmapData = new BitmapData(bounds.width, bounds.height, true, 0);
bmpData.draw(this, new Matrix(1, 0, 0, 1, -bounds.x, -bounds.y));
return new Bitmap(bmpData);
}
It may have something to do with the registration point of the Shape you're drawing into the Bitmap. Any chance you draw stuff above or to the left of the 0,0 coordinates? Then you'd have to add some params (perhaps a transformation Matrix) to the draw call, to get the right offset and such.

Actionscript 3 - How To Check A Random Pixel Of A Sprite

I have a sprite that is drawn in random and complicated way. Pixels would be either transparent or not. And now I need to check if pixel new Point(10, -5) is transparent or not.
How can I do that ?
This is not for collision detection.
I also draw in the negative area of the sprite graphics. It is not centered.
Solution:
The main problem was the drawing in negative area. I figured it out myself:
var bitmapData: BitmapData = new BitmapData(sprite.width, sprite.height, true, 0x0);
var rect: Rectangle = sprite.getBounds(sprite);
var mat: Matrix = new Matrix();
mat.translate(-rect.left, -rect.top);
bitmapData.draw(sprite, mat);
bitmapData.getPixel32(xCoordToTest - rect.left, yCoordToTest - rect.top);
// etc
Create new BitmapData object and draw your sprite onto it. Then check desired BitmapData pixel.
var bitmapData:BitmapData = new BitmapData(mySprite.width,mySprite.height,true,0x00000000);
bitmapData.draw(mySprite);
bitmapData.getPixel32(10,5);
Just like SzRaPnEL says, draw your sprite into a BitmapData object with the 3rd parameter set to true (enabling transparency).
Then...
var pixelValue:uint = bitmapData.getPixel32(xCoordToTest, yCoordToTest);
var alphaValue:uint = pixelValue >> 24 & 0xFF;
According to the BitmapData online docs, that should work...
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#getPixel32()

As3 performance for Sprite beginFillBitmap vs addChild(bitmap)

Just a quick question:
which of the following method of create a sprite have quick rendering and less memory usage?
Add bitmap to the sprite
var sprite:Sprite = new Sprite();
var bitmap:Bitmap = new Bitmap();
sprite.addChild(bitmap);
vs
Draw rectangle and fill with bitmapData
var bitmapData:Bitmapdata = new BitmapData(100, 100);
var sprite:Sprite = new Sprite();
sprite.graphic.drawRec(0, 0, 100, 100);
sprite.graphic.beginFillBitmap(bitmapData:Bitmapdata);
sprite.graphic.endFill();
Thanks for any idea.
The first one is faster because vector rendering mathematics are required to fill your shape in the latter.
If you want noticeable (and I mean very noticeable) performance gains, you should have one Bitmap on the stage. What you do from there is store references to BitmapData to represent graphics, and sample those onto your one Bitmap via .copyPixels().
Example:
// This is the only actual DisplayObject that will hit the Stage.
var canvas:Bitmap = new Bitmap();
canvas.bitmapData = new BitmapData(500, 400);
addChild(canvas);
// Create some BitmapData and draw it to the canvas.
var rect:BitmapData = new BitmapData(40, 40, false, 0xFF0000);
canvas.bitmapData.copyPixels(rect, rect.rect, new Point(20, 20));

Blending objects with eachother but not with background 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.