/* todo: - bitmapfilematerial in case of loading... problem with applying mat to submesh + wireframematerial - mouseevents + uvs - shadedmaterials */ package { import away3d.containers.ObjectContainer3D; import away3d.core.base.Geometry; import away3d.core.base.SubGeometry; import away3d.core.base.SubMesh; import away3d.entities.Mesh; import away3d.loading.parsers.data.DefaultBitmapData; import away3d.materials.AnimatedBitmapMaterial; import away3d.materials.BitmapMaterial; import away3d.materials.ColorMaterial; import away3d.materials.MaterialBase; import away3d.materials.VideoMaterial; import away3d.materials.WireframeMaterial; import away3d.materials.utils.WireframeMapGenerator; import away3d.tools.MeshHelper; import com.adobe.utils.DictionaryUtil; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.MovieClip; import flash.display.Sprite; import flash.events.Event; import flash.geom.Matrix; import flash.geom.Matrix3D; import flash.utils.Dictionary; import mx.core.mx_internal; import org.papervision3d.Papervision3D; import org.papervision3d.core.geom.renderables.Triangle3D; import org.papervision3d.core.geom.renderables.Vertex3D; import org.papervision3d.core.math.Matrix3D; import org.papervision3d.core.math.NumberUV; import org.papervision3d.core.proto.MaterialObject3D; import org.papervision3d.events.FileLoadEvent; import org.papervision3d.materials.BitmapFileMaterial; import org.papervision3d.materials.BitmapMaterial; import org.papervision3d.materials.ColorMaterial; import org.papervision3d.materials.MovieMaterial; import org.papervision3d.materials.VideoStreamMaterial; import org.papervision3d.materials.WireframeMaterial; import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.objects.DisplayObject3D; import teleranek.util.Util; public class PaperAway { /* in this case, we must create new vertex for every face, 'cause num of uv is bigger than num of verts probably too much verts, could be less */ public static var dirtyUV:Boolean = false; public static var lastMeshes:Array; public static var bmpNum:uint = 0; public static function fromDo3D( do3d:DisplayObject3D , recreateMaterials:Boolean = true ):Mesh{ var material:MaterialBase; var container:ObjectContainer3D; var child:DisplayObject3D; var ret:Mesh;//ObjectContainer3D; var msh:Mesh; var geom : Geometry; var subgeoms:Dictionary; var sg:SubGeometry; //var ret:Mesh = new Mesh( fromDo3DMaterial( do3d.material ) , geom ); var mat:MaterialObject3D; var obj:Object; var groups:Dictionary; // traverse do3d var stack:Vector. = new Vector.(); var item:PaperStackItem; stack.push( new PaperStackItem(do3d , null , do3d.transform) ); while( stack.length ){ item = stack.shift(); // create geometry if( item.do3d.geometry && item.do3d.geometry.faces && item.do3d.geometry.faces.length ){ subgeoms = null; if( recreateMaterials ) gatherMaterials( item.do3d ); if( item.do3d.materials && item.do3d.materials.numMaterials > 1 ){ container = new Mesh( null /* is it ok? */ , new Geometry() ); subgeoms = new Dictionary(); for each( mat in item.do3d.materials.materialsByName ){ subgeoms[ mat ] = { mesh:new Mesh( fromDo3DMaterial( mat ) , new Geometry()) , material:mat }; } }else{ if( item.do3d.materials ){ for each( mat in item.do3d.materials.materialsByName ){ container = new Mesh( fromDo3DMaterial( mat ) , new Geometry() ); break } }else{ container = new Mesh( fromDo3DMaterial( item.do3d.material ) , new Geometry() ); } } if( subgeoms ){ groups = extractGroups( item.do3d ); if( item.parent ) item.parent.addChild( container ); else ret = Mesh( container ); for each( obj in subgeoms ){ mat = obj.material; geom = Mesh(obj.mesh).geometry; sg = createSubGeometry( groups[mat].vertices , groups[mat].faces ); geom.addSubGeometry( sg ); container.addChild( Mesh(obj.mesh) ); updateSubgeometries( Mesh(obj.mesh) , sg ); } }else{ sg = createSubGeometry( item.do3d.geometry.vertices , item.do3d.geometry.faces ); Mesh(container).geometry.addSubGeometry( sg ); if( item.parent ){ item.parent.addChild( container ); // prabably the parents should have this subgeometry updateSubgeometries( Mesh(container) , sg ) }else ret = Mesh(container); } container.transform = fromDo3DTransform( item.do3d.transform ); }else{ container = new Mesh( fromDo3DMaterial( item.do3d.material ) , new Geometry() ); if( item.parent ) item.parent.addChild( container ); else ret = Mesh(container); } if( item.do3d.children ){ for each( child in item.do3d.children ){ stack.push( new PaperStackItem( child , container , org.papervision3d.core.math.Matrix3D.multiply( item.world , child.transform ) ) ); } } } applyWireframe( ret ); if( !lastMeshes ) lastMeshes = new Array(); lastMeshes.push( ret ); return ret; } public static function gatherMaterials( do3d:DisplayObject3D ):void{ if( !(do3d.geometry && do3d.geometry.faces && do3d.geometry.faces.length) ) return; var matDict:Dictionary = new Dictionary(); var tri:Triangle3D; var matNum:uint = 0; var mat:MaterialObject3D; for each( tri in do3d.geometry.faces ){ if( !matDict[ tri.material ] ){ matDict[ tri.material ] = tri.material; matNum++; } } if( matNum > 1 ){ do3d.materials = new MaterialsList(); for each( mat in matDict ){ do3d.materials.addMaterial( mat ); } }else if( matNum == 1 ){ for each( mat in matDict ){ do3d.material = mat; } } } public static function extractGroups(do3d:DisplayObject3D):Dictionary{ var groups:Dictionary = new Dictionary(); if( !(do3d.geometry && do3d.geometry.faces && do3d.geometry.faces.length) ) return new Dictionary(); var vertsDict:Dictionary = new Dictionary(); var gi:GroupItem; var tri:Triangle3D; for each( tri in do3d.geometry.faces ){ if( !(gi=groups[ tri.material ]) ){ groups[ tri.material ] = gi = new GroupItem(); vertsDict[ tri.material ] = new Dictionary(); } gi.faces.push( tri ); if( !vertsDict[tri.material][ tri.v0 ] ){ gi.vertices.push( tri.v0 ); vertsDict[tri.material][ tri.v0 ] = true; } if( !vertsDict[ tri.material ][ tri.v1 ] ){ gi.vertices.push( tri.v1 ); vertsDict[ tri.material ][ tri.v1 ] = true; } if( !vertsDict[ tri.material ][ tri.v2 ] ){ gi.vertices.push( tri.v2 ); vertsDict[ tri.material ][ tri.v2 ] = true; } } return groups; } public static function createSubGeometry( do3dVertices:Array , do3dFaces:Array ):SubGeometry{ var sg:SubGeometry = new SubGeometry( ); var vertices : Vector.; var normals : Vector.; var indices : Vector.; var uvs : Vector.; var vertexMap:Dictionary; var uvMap:Dictionary; var vertexNum:int; var do3dTri:Triangle3D; var do3dVert:Vertex3D; vertices = new Vector.(); indices = new Vector.(); normals = new Vector.( ); uvs = new Vector.( do3dFaces.length*6 ); vertexMap = new Dictionary(); uvMap = new Dictionary(); var i0:int, i1:int,i2:int,i:int,j:int,uv:NumberUV,uvv:NumberUV,found:int; var uvVec:Vector.; var indVec:Vector.; vertexNum = 0; if( Papervision3D.useRIGHTHANDED ){ for each( do3dTri in do3dFaces ){ if( !dirtyUV ){ for(i=0; i < 3; i++ ){ found = -1; do3dVert = do3dTri.vertices[ i ]; uv = NumberUV(do3dTri.uv[i]); // check from vertexMap, if uv differs - create new... if( (indVec = vertexMap[do3dVert]) ){ // <- vertexmap contains an array of indices uvVec = uvMap[ do3dVert ]; // <- uvmap contains an array of uv's to compare... for( j = 0; j < uvVec.length; j++ ){ uvv = uvVec[ j ]; if( (uv.u == uvv.u ) && (uv.v == uvv.v) ){ found = indVec[ j ]; break; } } } if( found < 0 ){ uvs[ 2*vertexNum ] = 1.0 - uv.u; uvs[ 2*vertexNum+1 ] = 1.0 - uv.v; if( !indVec ){ indVec = vertexMap[ do3dVert ] = new Vector.(); uvVec = uvMap[ do3dVert ] = new Vector.(); } uvVec.push( uv ); indVec.push( vertexNum ); if( !do3dVert.normal ) do3dVert.calculateNormal(); normals.push( do3dVert.normal.x , do3dVert.normal.y , do3dVert.normal.z ); vertices.push( do3dVert.x , do3dVert.y , do3dVert.z ); indices.push( vertexNum++ ); }else{ uvs[ 2*found ] = 1.0 - uv.u; uvs[ 2*found+1 ] = 1.0 - uv.v; indices.push( found ); } } }else{ for(i=0; i < 3; i++ ){ do3dVert = do3dTri.vertices[ i ]; uvs[ 2*indices.length ] = 1.0-NumberUV( do3dTri.uv[ i ] ).u; uvs[ 2*indices.length+1 ] = 1.0-NumberUV( do3dTri.uv[ i ] ).v; /* this should work, but doesn't ... if( (i0 = vertexMap[ do3dVert ]) ){ indices.push( i0 ); }else{ */ vertices.push( do3dVert.x , do3dVert.y , do3dVert.z ); if( !do3dVert.normal ) do3dVert.calculateNormal(); normals.push( do3dVert.normal.x , do3dVert.normal.y , do3dVert.normal.z ); //vertexMap[ do3dVert ] = vertexNum; indices.push( vertexNum++ ); } } } }else{ for each( do3dTri in do3dFaces ){ if( !dirtyUV ){ for(i=2; i >= 0; i-- ){ found = -1; do3dVert = do3dTri.vertices[ i ]; uv = NumberUV(do3dTri.uv[i]); // check from vertexMap, if uv differs - create new... if( (indVec = vertexMap[do3dVert]) ){ // <- vertexmap contains an array of indices uvVec = uvMap[ do3dVert ]; // <- uvmap contains an array of uv's to compare... for( j = 0; j < uvVec.length; j++ ){ uvv = uvVec[ j ]; if( (uv.u == uvv.u ) && (uv.v == uvv.v) ){ found = indVec[ j ]; break; } } } if( found < 0 ){ uvs[ 2*vertexNum ] = uv.u; uvs[ 2*vertexNum+1 ] = 1.0 - uv.v; if( !indVec ){ indVec = vertexMap[ do3dVert ] = new Vector.(); uvVec = uvMap[ do3dVert ] = new Vector.(); } uvVec.push( uv ); indVec.push( vertexNum ); if( !do3dVert.normal ) do3dVert.calculateNormal(); normals.push( do3dVert.normal.x , do3dVert.normal.y , do3dVert.normal.z ); vertices.push( do3dVert.x , do3dVert.y , do3dVert.z ); indices.push( vertexNum++ ); }else{ uvs[ 2*found ] = uv.u; uvs[ 2*found+1 ] = 1.0 - uv.v; indices.push( found ); } } }else{ for(i=2; i >= 0; i-- ){ do3dVert = do3dTri.vertices[ i ]; vertices.push( do3dVert.x , do3dVert.y , do3dVert.z ); if( !do3dVert.normal ) do3dVert.calculateNormal(); normals.push( do3dVert.normal.x , do3dVert.normal.y , do3dVert.normal.z ); uvs[ 2*vertexNum ] = NumberUV( do3dTri.uv[ i ] ).u; uvs[ 2*vertexNum+1 ] = 1.0-NumberUV( do3dTri.uv[ i ] ).v; indices.push( vertexNum++ ); } } } } sg.updateIndexData( indices ); sg.updateVertexData( vertices ); sg.updateVertexNormalData( normals ); sg.updateUVData( uvs ); return sg; } public static function updateSubgeometries( container:Mesh , sg:SubGeometry ):void{ var currentParent:ObjectContainer3D = container.parent; while( currentParent ){ if( currentParent is Mesh ) Mesh( currentParent ).geometry.addSubGeometry( sg ); currentParent = currentParent.parent; } } public static function fromDo3DTransform( transform:org.papervision3d.core.math.Matrix3D ):flash.geom.Matrix3D{ var trans:flash.geom.Matrix3D = new flash.geom.Matrix3D( ); trans.rawData[ 0 ] = transform.n11; trans.rawData[ 1 ] = transform.n12; trans.rawData[ 2 ] = transform.n13; trans.rawData[ 3 ] = transform.n14; trans.rawData[ 4 ] = transform.n21; trans.rawData[ 5 ] = transform.n22; trans.rawData[ 6 ] = transform.n23; trans.rawData[ 7 ] = transform.n24; trans.rawData[ 8 ] = transform.n31; trans.rawData[ 9 ] = transform.n32; trans.rawData[ 10 ] = transform.n33; trans.rawData[ 11 ] = transform.n34; trans.rawData[ 12 ] = transform.n41; trans.rawData[ 13 ] = transform.n42; trans.rawData[ 14 ] = transform.n43; trans.rawData[ 15 ] = transform.n44; return trans; } // todo: ShadedMaterial public static function fromDo3DMaterial( mat:MaterialObject3D ):MaterialBase{ if( !mat ) return null; var ret:MaterialBase; // seems that wireframe is not finished yet, everything's commented out in away if( mat is org.papervision3d.materials.WireframeMaterial ){ // WireframeMaterial doesnt work: stream 1 sth // instead we must do some strange shit ret = new away3d.materials.BitmapMaterial( DefaultBitmapData.bitmapData ); ret.extra = { action:"wire" }; /* ret = new away3d.materials.BitmapMaterial(WireframeMapGenerator.generateSolidMap( mdl, 0xffffff, 2, 0, 0, 512, 512)); ret.bothSides = true; mmm.alpha = .7; ret.transparent = true; ret.mipmap = false; */ // ret = new away3d.materials.ColorMaterial( 0xff0000 , 0.5 ); }else if( mat is org.papervision3d.materials.ColorMaterial ){ ret = new away3d.materials.ColorMaterial( org.papervision3d.materials.ColorMaterial(mat).fillColor , org.papervision3d.materials.ColorMaterial(mat).fillAlpha ); // }else if( mat is VideoStreamMaterial ){ // ret = new VideoMaterial( VideoStreamMaterial(mat).stream. ); }else if( mat is MovieMaterial ){ var mm:MovieMaterial = MovieMaterial(mat); if( mm.movie is MovieClip ) ret = new AnimatedBitmapMaterial(MovieClip(mm.movie),true,mm.animated,0,adaptBitmap(mm.bitmap)); // can't render sprites with GPU ... else ret = new away3d.materials.BitmapMaterial( adaptBitmap(mm.bitmap) ); } else if( mat is org.papervision3d.materials.BitmapFileMaterial && (!org.papervision3d.materials.BitmapFileMaterial(mat).loaded)){ //ret = new away3d.materials.BitmapFileMaterial( ); var bmpf:org.papervision3d.materials.BitmapFileMaterial = org.papervision3d.materials.BitmapFileMaterial(mat); ret = new away3d.materials.BitmapMaterial( DefaultBitmapData.bitmapData ); ret.extra = { action:"loadBmp" , bmp:bmpf }; bmpf.addEventListener(FileLoadEvent.LOAD_COMPLETE , replaceBmp ); bmpNum++; } else if( mat is org.papervision3d.materials.BitmapMaterial ){ ret = new away3d.materials.BitmapMaterial( adaptBitmap(mat.bitmap) ); //ret.lights = [televiewer.light]; } // videostream /* stream(NetStream) , video (Video) */ // moviemat /* movie==texture==bitmap(obj), movie transparent(bool) */ // bmpfilemat /* url, loaded, callback , texture ( == url ) */ // matob3d /* this.bitmap = material.bitmap; * this.smooth = material.smooth; this.lineColor = material.lineColor; this.lineAlpha = material.lineAlpha; this.fillColor = material.fillColor; this.fillAlpha = material.fillAlpha; * this.oneSide = material.oneSide; this.opposite = material.opposite; this.invisible = material.invisible; * this.name = material.name; this.maxU = material.maxU; this.maxV = material.maxV; */ ret.name = mat.name; ret.smooth = mat.smooth; ret.bothSides = !mat.oneSide; return ret; } private static function replaceBmp( e:FileLoadEvent ):void{ var mesh:Mesh, child:Mesh; var i:int; var stack:Array; bmpNum--; if( bmpNum == 0 ){ // iterate through submeshes or meshes? // apparently submeshes are not assigned with materials (???) so must iterate through meshes while( lastMeshes.length ){ mesh = lastMeshes.shift(); if( mesh.material && mesh.material.extra && (mesh.material.extra.action == "loadBmp") ){ mesh.material = new away3d.materials.BitmapMaterial( org.papervision3d.materials.BitmapFileMaterial( mesh.material.extra.bmp ).bitmap ); } for( i = 0; i < mesh.numChildren; i++ ){ lastMeshes.push( mesh.getChildAt( i ) ); } } } } private static function applyWireframe( obj:Mesh ):void{ // for each( var submesh:SubMesh in obj.subMeshes ){ // ... // } var mesh:Mesh , child:Mesh; var i:int; var mat:away3d.materials.BitmapMaterial; var stack:Array = new Array(); stack.push( obj ); while( stack.length ){ mesh = stack.shift(); if( mesh.material && mesh.material.extra && (mesh.material.extra.action == "wire") ){ mat = new away3d.materials.BitmapMaterial( WireframeMapGenerator.generateSolidMap( mesh, 0xffffff, 2, 0, 0, 512, 512)); mat.bothSides = true; mat.alpha = .7; mat.transparent = true; mat.mipmap = false; mesh.material = mat; } for( i = 0; i < mesh.numChildren; i++ ){ stack.push( mesh.getChildAt( i ) ); } } } public static function adaptBitmap( bmp:BitmapData ):BitmapData{ var newsize:uint = 2; var maxsize:uint = Math.min( Math.max( bmp.width , bmp.height ) , 2048 ); var sx:Number = 1.; var sy:Number = 1.; while( newsize < maxsize ){ newsize *= 2; } sx = newsize/bmp.width; sy = newsize/bmp.height; if( (sx == 1)&&(sy==1) ) return bmp.clone(); var newbitmap:BitmapData = new BitmapData( newsize , newsize , false , 0 ); var mtx:Matrix = new Matrix(); mtx.scale( sx , sy ); newbitmap.draw( bmp , mtx , null , null , null , true ); return newbitmap; } } } import away3d.containers.ObjectContainer3D; import org.papervision3d.core.math.Matrix3D; import org.papervision3d.objects.DisplayObject3D; internal class PaperStackItem{ public var do3d:DisplayObject3D; public var world:Matrix3D; public var parent:ObjectContainer3D; public function PaperStackItem( do3d:DisplayObject3D , parent:ObjectContainer3D , world:Matrix3D ){ this.do3d = do3d; this.world = world; this.parent = parent; //this.container = container; } } internal class GroupItem{ public var faces:Array; // must be an array cause do3d has arrays of faces/verts public var vertices:Array; public function GroupItem(){ faces = new Array(); vertices = new Array(); } }