package away3d.extrusions { import flash.display.BitmapData; import flash.geom.Point; import away3d.core.math.Number3D; import away3d.core.base.*; import away3d.arcane; use namespace arcane; public class NormalUVModifier { private var _mesh:Mesh; private var _geom:Array; private var _sourceBmd:BitmapData; private var _maxLevel:Number = 255; private function updateVertex(orivertex:Vertex, vertex:Vertex, pt:Point, normal:Number3D, channel:String, factor:Number):void { var color:uint = ( channel == "a")? _sourceBmd.getPixel32(pt.x, pt.y) : _sourceBmd.getPixel(pt.x, pt.y); var cha:Number; switch(channel){ case "a": cha = color >> 24 & 0xFF; break; case "r": cha = color >> 16 & 0xFF; break; case "g": cha = color >> 8 & 0xFF; break; case "b": cha = color & 0xFF; break; case "av": cha = ((color >> 16 & 0xFF)*0.212671) + ((color >> 8 & 0xFF)*0.715160) + ((color >> 8 & 0xFF)*0.072169); } if(cha <= _maxLevel){ var multi:Number = (cha*factor); vertex.x = orivertex.x+(normal.x * multi); vertex.y = orivertex.y+(normal.y * multi); vertex.z = orivertex.z+(normal.z * multi); } } private function setVertices():void { var basevertices:Array = []; _geom = []; var j:int; for(var i:int = 0;i<_mesh.vertices.length;++i){ basevertices[i] = _mesh.vertices[i]; } var n0:Number3D; var n1:Number3D; var n2:Number3D; var v0:Vertex; var v1:Vertex; var v2:Vertex; var p0:Point; var p1:Point; var p2:Point; var m0:Boolean; var m1:Boolean; var m2:Boolean; if(_sourceBmd != null){ var w:int = _sourceBmd.width-1; var h:int = _sourceBmd.height-1; } var face:Face; for(i = 0;i<_mesh.faces.length;++i){ m0 = false; m1 = false; m2 = false; face = _mesh.faces[i]; for(j = 0;j * * @param mesh Object3D. The mesh Object3D to be updated. * @param sourcebmd [optional] BitmapData. The bitmapdata used as source for the influence. */ public function NormalUVModifier(mesh:Mesh, sourcebmd:BitmapData = null, maxlevel:Number = 255) { if((mesh as Mesh).vertices != null){ maxLevel = maxlevel; _mesh = mesh as Mesh; _sourceBmd = sourcebmd; setVertices(); } else{ throw new Error("Unvalid Mesh, no vertices array found"); } } /** * Updates the vertexes with the color value found at the uv's coordinates multiplied by a factor along the normal vector. * * @param factor Number. The multiplier. (multiplier * 0/255). * @param channel [optional] The channel of the source bitmapdata. Possible values, red channel:"r", green channel:"g", blue channel:"b", average:"av". Default is "r". */ public function update(factor:Number, channel:String = "r"):void { channel = channel.toLowerCase(); var w:Number = _sourceBmd.width; var h:Number = _sourceBmd.height; for(var i:int = 0;i<_geom.length;++i){ if(_geom[i].v0 != null){ updateVertex(_geom[i].v0o, _geom[i].v0, _geom[i].p0, _geom[i].n0, channel, factor); } if(_geom[i].v1 != null){ updateVertex(_geom[i].v1o, _geom[i].v1, _geom[i].p1, _geom[i].n1, channel, factor); } if(_geom[i].v2 != null){ updateVertex(_geom[i].v2o, _geom[i].v2, _geom[i].p2, _geom[i].n2, channel, factor); } } } /** * Updates the vertexes alog the normal vectors according to a multiplier. * The influence is applied on top of the original vertex values. * @param factor Number. The multiplier. */ public function multiply(factor:Number):void { for(var i:int = 0;i<_geom.length;++i){ if(_geom[i].v0 != null){ _geom[i].v0.x = _geom[i].v0o.x+(_geom[i].n0.x * factor); _geom[i].v0.y = _geom[i].v0o.y+(_geom[i].n0.y * factor); _geom[i].v0.z = _geom[i].v0o.z+(_geom[i].n0.z * factor); } if(_geom[i].v1 != null){ _geom[i].v1.x = _geom[i].v1o.x+( _geom[i].n1.x * factor); _geom[i].v1.y = _geom[i].v1o.y+(_geom[i].n1.y * factor); _geom[i].v1.z = _geom[i].v1o.z+(_geom[i].n1.z * factor); } if(_geom[i].v2 != null){ _geom[i].v2.x = _geom[i].v2o.x+( _geom[i].n2.x * factor); _geom[i].v2.y = _geom[i].v2o.y+(_geom[i].n2.y * factor); _geom[i].v2.z = _geom[i].v2o.z+(_geom[i].n2.z * factor); } } } /** * Resets the vertexes to their original values */ public function resetVertices():void { for(var i:int = 0;i<_geom.length;++i){ if(_geom[i].v0 != null){ _geom[i].v0.x = _geom[i].v0o.x; _geom[i].v0.y = _geom[i].v0o.y; _geom[i].v0.z = _geom[i].v0o.z; } if(_geom[i].v1 != null){ _geom[i].v1.x = _geom[i].v1o.x; _geom[i].v1.y = _geom[i].v1o.y; _geom[i].v1.z = _geom[i].v1o.z; } if(_geom[i].v2 != null){ _geom[i].v2.x = _geom[i].v2o.x; _geom[i].v2.y = _geom[i].v2o.y; _geom[i].v2.z = _geom[i].v2o.z; } } } /** * Set a new source bitmapdata for the class */ public function set source(nSource:BitmapData):void { var nw:int = nSource.width; var nh:int = nSource.height; if(_sourceBmd != null){ var w:int = _sourceBmd.width; var h:int = _sourceBmd.height; } _sourceBmd = nSource; for(var i:int = 0;i<_geom.length;++i){ if(_geom[i].p0 != null){ _geom[i].p0.x = (_sourceBmd != null)? (_geom[i].p0.x/w)*nw : _geom[i].p0.x = _geom[i].p0.x * nw; _geom[i].p0.y = (_sourceBmd != null)? (_geom[i].p0.y/h)*nh : _geom[i].p0.y = _geom[i].p0.y * nh; } if(_geom[i].p1 != null){ _geom[i].p1.x = (_sourceBmd != null)? (_geom[i].p1.x/w)*nw : _geom[i].p1.x = _geom[i].p1.x * nw; _geom[i].p1.y = (_sourceBmd != null)? (_geom[i].p1.y/h)*nh : _geom[i].p1.y = _geom[i].p1.y * nh; } if(_geom[i].p2 != null){ _geom[i].p2.x = (_sourceBmd != null)? (_geom[i].p2.x/w)*nw : _geom[i].p2.x = _geom[i].p2.x * nw; _geom[i].p2.y = (_sourceBmd != null)? (_geom[i].p2.y/h)*nh : _geom[i].p2.y = _geom[i].p2.y * nh; } } } /** * Defines a maximum level of influence. Values required are 0 to 1. If above or equal that level the influence is not applyed. */ public function set maxLevel(val:Number):void { val = (val<0)? 0 : ((val>1)? 1 : val); _maxLevel = 255*val; } public function get maxLevel():Number { return 1/_maxLevel; } } }