package net.flashpunk.graphics
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import net.flashpunk.*;
/**
* Performance-optimized non-animated image. Can be drawn to the screen with transformations.
*/
public class Image extends Graphic
{
/**
* Rotation of the image, in degrees.
*/
public var angle:Number = 0;
/**
* Scale of the image, effects both x and y scale.
*/
public var scale:Number = 1;
/**
* X scale of the image.
*/
public var scaleX:Number = 1;
/**
* Y scale of the image.
*/
public var scaleY:Number = 1;
/**
* X origin of the image, determines transformation point.
*/
public var originX:int;
/**
* Y origin of the image, determines transformation point.
*/
public var originY:int;
/**
* Optional blend mode to use when drawing this image.
* Use constants from the flash.display.BlendMode class.
*/
public var blend:String;
/**
* If the image should be drawn transformed with pixel smoothing.
* This will affect drawing performance, but look less pixelly.
*/
public var smooth:Boolean;
/**
* Constructor.
* @param source Source image.
* @param clipRect Optional rectangle defining area of the source image to draw.
*/
public function Image(source:* = null, clipRect:Rectangle = null)
{
if (source is Class)
{
_source = FP.getBitmap(source);
_class = String(source);
}
else if (source is BitmapData) _source = source;
if (!_source) throw new Error("Invalid source image.");
_sourceRect = _source.rect;
if (clipRect)
{
if (!clipRect.width) clipRect.width = _sourceRect.width;
if (!clipRect.height) clipRect.height = _sourceRect.height;
_sourceRect = clipRect;
}
createBuffer();
updateBuffer();
}
/** @private Creates the buffer. */
protected function createBuffer():void
{
_buffer = new BitmapData(_sourceRect.width, _sourceRect.height, true, 0);
_bufferRect = _buffer.rect;
_bitmap.bitmapData = _buffer;
}
/** @private Renders the image. */
override public function render(target:BitmapData, point:Point, camera:Point):void
{
if (!_buffer) return;
_point.x = point.x + x - camera.x * scrollX;
_point.y = point.y + y - camera.y * scrollY;
if (angle == 0 && scaleX * scale == 1 && scaleY * scale == 1 && !blend)
{
target.copyPixels(_buffer, _bufferRect, _point, null, null, true);
return;
}
_matrix.b = _matrix.c = 0;
_matrix.a = scaleX * scale;
_matrix.d = scaleY * scale;
_matrix.tx = -originX * _matrix.a;
_matrix.ty = -originY * _matrix.d;
if (angle != 0) _matrix.rotate(angle * FP.RAD);
_matrix.tx += originX + _point.x;
_matrix.ty += originY + _point.y;
target.draw(_bitmap, _matrix, null, blend, null, smooth);
}
/**
* Creates a new rectangle Image.
* @param width Width of the rectangle.
* @param height Height of the rectangle.
* @param color Color of the rectangle.
* @return A new Image object.
*/
public static function createRect(width:uint, height:uint, color:uint = 0xFFFFFF):Image
{
var source:BitmapData = new BitmapData(width, height, true, 0xFF000000 | color);
return new Image(source);
}
/**
* Creates a new circle Image.
* @param radius Radius of the circle.
* @param color Color of the circle.
* @return A new Circle object.
*/
public static function createCircle(radius:uint, color:uint = 0xFFFFFF):Image
{
FP.sprite.graphics.clear();
FP.sprite.graphics.beginFill(color);
FP.sprite.graphics.drawCircle(radius, radius, radius);
var data:BitmapData = new BitmapData(radius * 2, radius * 2, true, 0);
data.draw(FP.sprite);
return new Image(data);
}
/**
* Updates the image buffer.
*/
public function updateBuffer(clearBefore:Boolean = false):void
{
if (!_source) return;
if (clearBefore) _buffer.fillRect(_bufferRect, 0);
_buffer.copyPixels(_source, _sourceRect, FP.zero);
if (_tint) _buffer.colorTransform(_bufferRect, _tint);
}
/**
* Clears the image buffer.
*/
public function clear():void
{
_buffer.fillRect(_bufferRect, 0);
}
/**
* Change the opacity of the Image, a value from 0 to 1.
*/
public function get alpha():Number { return _alpha; }
public function set alpha(value:Number):void
{
value = value < 0 ? 0 : (value > 1 ? 1 : value);
if (_alpha == value) return;
_alpha = value;
if (_alpha == 1 && _color == 0xFFFFFF)
{
_tint = null;
return updateBuffer();
}
_tint = _colorTransform;
_tint.redMultiplier = (_color >> 16 & 0xFF) / 255;
_tint.greenMultiplier = (_color >> 8 & 0xFF) / 255;
_tint.blueMultiplier = (_color & 0xFF) / 255;
_tint.alphaMultiplier = _alpha;
updateBuffer();
}
/**
* The tinted color of the Image. Use 0xFFFFFF to draw the Image normally.
*/
public function get color():uint { return _color; }
public function set color(value:uint):void
{
value &= 0xFFFFFF;
if (_color == value) return;
_color = value;
if (_alpha == 1 && _color == 0xFFFFFF)
{
_tint = null;
return updateBuffer();
}
_tint = _colorTransform;
_tint.redMultiplier = (_color >> 16 & 0xFF) / 255;
_tint.greenMultiplier = (_color >> 8 & 0xFF) / 255;
_tint.blueMultiplier = (_color & 0xFF) / 255;
_tint.alphaMultiplier = _alpha;
updateBuffer();
}
/**
* If you want to draw the Image horizontally flipped. This is
* faster than setting scaleX to -1 if your image isn't transformed.
*/
public function get flipped():Boolean { return _flipped; }
public function set flipped(value:Boolean):void
{
if (_flipped == value || !_class) return;
_flipped = value;
var temp:BitmapData = _source;
if (!value || _flip)
{
_source = _flip;
_flip = temp;
return updateBuffer();
}
if (_flips[_class])
{
_source = _flips[_class];
_flip = temp;
return updateBuffer();
}
_source = _flips[_class] = new BitmapData(_source.width, _source.height, true, 0);
_flip = temp;
FP.matrix.identity();
FP.matrix.a = -1;
FP.matrix.tx = _source.width;
_source.draw(temp, FP.matrix);
updateBuffer();
}
/**
* Centers the Image's originX/Y to its center.
*/
public function centerOrigin():void
{
originX = _bufferRect.width / 2;
originY = _bufferRect.height / 2;
}
/**
* Centers the Image's originX/Y to its center, and negates the offset by the same amount.
*/
public function centerOO():void
{
x += originX;
y += originY;
centerOrigin();
x -= originX;
y -= originY;
}
/**
* Width of the image.
*/
public function get width():uint { return _bufferRect.width; }
/**
* Height of the image.
*/
public function get height():uint { return _bufferRect.height; }
/**
* The scaled width of the image.
*/
public function get scaledWidth():uint { return _bufferRect.width * scaleX * scale; }
/**
* The scaled height of the image.
*/
public function get scaledHeight():uint { return _bufferRect.height * scaleY * scale; }
/**
* Clipping rectangle for the image.
*/
public function get clipRect():Rectangle { return _sourceRect; }
/** @private Source BitmapData image. */
protected function get source():BitmapData { return _source; }
/** @private */ protected var _source:BitmapData;
/** @private */ protected var _sourceRect:Rectangle;
/** @private */ protected var _buffer:BitmapData;
/** @private */ protected var _bufferRect:Rectangle;
/** @private */ protected var _bitmap:Bitmap = new Bitmap;
/** @private */ private var _alpha:Number = 1;
/** @private */ private var _color:uint = 0x00FFFFFF;
/** @private */ protected var _tint:ColorTransform;
/** @private */ private var _colorTransform:ColorTransform = new ColorTransform;
/** @private */ private var _matrix:Matrix = FP.matrix;
/** @private */ private var _class:String;
/** @private */ protected var _flipped:Boolean;
/** @private */ private var _flip:BitmapData;
/** @private */ private static var _flips:Object = { };
}
}