package away3d.materials
{
import away3d.containers.*;
import away3d.arcane;
import away3d.core.base.*;
import away3d.core.draw.*;
import away3d.core.utils.*;
import away3d.events.*;
import flash.display.*;
import flash.geom.*;
import flash.utils.*;
use namespace arcane;
/**
* Container for caching multiple bitmapmaterial objects.
* Renders each material by caching a bitmapData surface object for each face.
* For continually updating materials, use CompositeMaterial.
*
* @see away3d.materials.CompositeMaterial
*/
public class BitmapMaterialContainer extends BitmapMaterial implements ITriangleMaterial, ILayerMaterial
{
private var _width:Number;
private var _height:Number;
private var _containerDictionary:Dictionary = new Dictionary(true);
private var _cacheDictionary:Dictionary = new Dictionary(true);
private var _containerVO:FaceVO;
private var _faceWidth:int;
private var _faceHeight:int;
private var _forceRender:Boolean;
private var _face:Face;
private var _material:ILayerMaterial;
private var _viewDictionary:Dictionary = new Dictionary(true);
private function onMaterialUpdate(event:MaterialEvent):void
{
_faceDirty = true;
dispatchEvent(event);
}
/**
* An array of bitmapmaterial objects to be overlayed sequentially.
*/
protected var materials:Array;
/**
* @inheritDoc
*/
protected override function updateRenderBitmap():void
{
_bitmapDirty = false;
_faceDirty = true;
}
/**
* @inheritDoc
*/
protected override function getMapping(tri:DrawTriangle):Matrix
{
_face = tri.face;
_faceVO = getFaceVO(tri.face, tri.source, tri.view);
if (_faceVO.invalidated || !_faceVO.texturemapping) {
_faceVO.invalidated = false;
//_faceVO.backface = tri.backface;
//check to see if face drawtriangle needs updating
if (!_faceVO.texturemapping) {
//update face bitmapRect
_face.bitmapRect = new Rectangle(int(_width*_face.minU), int(_height*(1 - _face.maxV)), int(_width*(_face.maxU-_face.minU)+2), int(_height*(_face.maxV-_face.minV)+2));
_faceWidth = _face.bitmapRect.width;
_faceHeight = _face.bitmapRect.height;
//update texturemapping
_faceVO.invtexturemapping = tri.transformUV(this).clone();
_faceVO.texturemapping = _faceVO.invtexturemapping.clone();
_faceVO.texturemapping.invert();
//resize bitmapData for container
_faceVO.resize(_faceWidth, _faceHeight, transparent);
}
//call renderFace on each material
for each (_material in materials)
_faceVO = _material.renderBitmapLayer(tri, _bitmapRect, _faceVO);
_cacheDictionary[_face] = _faceVO;
_renderBitmap = _faceVO.bitmap;
_faceVO.updated = false;
} else {
_renderBitmap = _cacheDictionary[_face].bitmap;
}
//check to see if tri texturemapping need updating
if (!_faceVO.texturemapping) {
//update texturemapping
_faceVO.invtexturemapping = tri.transformUV(this).clone();
_faceVO.texturemapping = _faceVO.invtexturemapping.clone();
_faceVO.texturemapping.invert();
}
return _faceVO.texturemapping;
}
/**
* Defines whether the caching bitmapData objects are transparent
*/
public var transparent:Boolean;
/**
* Creates a new BitmapMaterialContainer object.
*
* @param width The containing width of the texture, applied to all child materials.
* @param height The containing height of the texture, applied to all child materials.
* @param init [optional] An initialisation object for specifying default instance properties.
*/
public function BitmapMaterialContainer(width:int, height:int, init:Object = null)
{
super(new BitmapData(width, height, true, 0x00FFFFFF), init);
materials = ini.getArray("materials");
_width = width;
_height = height;
_bitmapRect = new Rectangle(0, 0, _width, _height);
for each (_material in materials)
_material.addOnMaterialUpdate(onMaterialUpdate);
transparent = ini.getBoolean("transparent", true);
}
public function addMaterial(material:ILayerMaterial):void
{
material.addOnMaterialUpdate(onMaterialUpdate);
materials.push(material);
_faceDirty = true;
}
public function removeMaterial(material:ILayerMaterial):void
{
var index:int = materials.indexOf(material);
if (index == -1)
return;
material.removeOnMaterialUpdate(onMaterialUpdate);
materials.splice(index, 1);
_faceDirty = true;
}
public function clearMaterials():void
{
var i:int = materials.length;
while (i--)
removeMaterial(materials[i]);
}
/**
* Creates a new BitmapMaterialContainer object.
*
* @param width The containing width of the texture, applied to all child materials.
* @param height The containing height of the texture, applied to all child materials.
* @param init [optional] An initialisation object for specifying default instance properties.
*/
public override function updateMaterial(source:Object3D, view:View3D):void
{
if (_colorTransformDirty)
updateColorTransform();
if (_bitmapDirty)
updateRenderBitmap();
if (_faceDirty || _blendModeDirty)
clearFaceDictionary();
for each (_material in materials)
_material.updateMaterial(source, view);
_blendModeDirty = false;
}
public override function getFaceVO(face:Face, source:Object3D, view:View3D = null):FaceVO
{
if ((_faceDictionary = _viewDictionary[view])) {
if ((_faceVO = _faceDictionary[face]))
return _faceVO;
} else {
_faceDictionary = _viewDictionary[view] = new Dictionary(true);
}
return _faceDictionary[face] = new FaceVO();
}
public override function removeFaceDictionary():void
{
_viewDictionary = new Dictionary(true);
}
/**
* @private
*/
public override function renderLayer(tri:DrawTriangle, layer:Sprite, level:int):void
{
throw new Error("Not implemented");
}
/**
* @inheritDoc
*/
public override function renderBitmapLayer(tri:DrawTriangle, containerRect:Rectangle, parentFaceVO:FaceVO):FaceVO
{
_faceVO = getFaceVO(tri.face, tri.source, tri.view);
//get width and height values
_faceWidth = tri.face.bitmapRect.width;
_faceHeight = tri.face.bitmapRect.height;
//check to see if bitmapContainer exists
if (!(_containerVO = _containerDictionary[tri]))
_containerVO = _containerDictionary[tri] = new FaceVO();
//resize container
if (parentFaceVO.resized) {
parentFaceVO.resized = false;
_containerVO.resize(_faceWidth, _faceHeight, transparent);
}
//call renderFace on each material
for each (_material in materials)
_containerVO = _material.renderBitmapLayer(tri, containerRect, _containerVO);
//check to see if face update can be skipped
if (parentFaceVO.updated || _containerVO.updated) {
parentFaceVO.updated = false;
_containerVO.updated = false;
//reset booleans
_faceVO.invalidated = false;
_faceVO.cleared = false;
_faceVO.updated = true;
//store a clone
_faceVO.bitmap = parentFaceVO.bitmap.clone();
_faceVO.bitmap.lock();
_sourceVO = _faceVO;
//draw into faceBitmap
if (_blendMode == BlendMode.NORMAL && !_colorTransform)
_faceVO.bitmap.copyPixels(_containerVO.bitmap, _containerVO.bitmap.rect, _zeroPoint, null, null, true);
else
_faceVO.bitmap.draw(_containerVO.bitmap, null, _colorTransform, _blendMode);
}
_containerVO.updated = false;
return _faceVO;
}
}
}