package { /** * ... * @author nicoptere */ import flash.display.Bitmap; import flash.events.Event; import flash.events.MouseEvent; import flash.display.Sprite; import net.nicoptere.marchingcubes.Dataset; import org.papervision3d.core.math.Number3D; import org.papervision3d.lights.PointLight3D; import org.papervision3d.core.proto.MaterialObject3D; import org.papervision3d.materials.ColorMaterial; import org.papervision3d.materials.WireframeMaterial; import org.papervision3d.materials.special.CompositeMaterial; import org.papervision3d.materials.shadematerials.FlatShadeMaterial; import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.cameras.Camera3D; import org.papervision3d.core.geom.renderables.Triangle3D; import org.papervision3d.core.geom.TriangleMesh3D; import org.papervision3d.core.geom.renderables.Vertex3D; import org.papervision3d.objects.primitives.Cube; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.render.BasicRenderEngine; import org.papervision3d.scenes.Scene3D; import org.papervision3d.view.Viewport3D; //marching cube classes import net.nicoptere.marchingcubes.Triangle; import net.nicoptere.marchingcubes.Vector3D; import net.nicoptere.marchingcubes.MarchingCubes; public class PaperObject extends Sprite { private var viewport:Viewport3D; private var scene:Scene3D; private var camera:Camera3D; private var renderer:BasicRenderEngine; private var cube:Cube; public var group:DisplayObject3D; private var mesh : TriangleMesh3D; private var cubeMaterial:WireframeMaterial; private var shapeMaterial:FlatShadeMaterial; //marching cubes utils private var marchingCubes:MarchingCubes; private var _data:Dataset = null; private var _scale:Number = 50; static private var _instance:PaperObject; //to manipualte the mesh private var mouseDown:Boolean = false; //display the boundingbox private var _boundingBox:Boolean; //display the boundingbox private var _doubleSided:Boolean; //renders the object when drag/rotating private var _liveRender:Boolean = false; //swaps the face normal private var normal:Boolean = true; public function PaperObject( mc:MarchingCubes = null, scale:Number = 30, boundingBox:Boolean = false ) { if ( mc == null ) return; marchingCubes = mc; _data = mc.dataset; _scale = scale; _boundingBox = boundingBox; //for static calls _instance = this; init(); } private function init():void { initPapervision(); initMaterials(); initObjects(); initListeners(); } private function initPapervision():void { viewport = new Viewport3D( 500, 500, false, true ); addChild( viewport ); scene = new Scene3D(); camera = new Camera3D(); camera.z = -300; renderer = new BasicRenderEngine(); //active zone var sp:Sprite = new Sprite (); sp.graphics.beginFill( 0, 0 ); sp.graphics.drawRect( 0, 0, 500, 500 ); addChild( sp ); hitArea = sp; buttonMode = true; } private function initMaterials():void { cubeMaterial = new WireframeMaterial( 0x2F2F2F, 100, 2); cubeMaterial.doubleSided = true; shapeMaterial = new FlatShadeMaterial(new PointLight3D(), 0x41260f, 0xFFCC00); } private function initObjects():void { group = new DisplayObject3D(); scene.addChild( group ); //bounding box cube = new Cube(new MaterialsList( { all: cubeMaterial } ), 1, 1, 1 ); group.addChild( cube ); if ( !_boundingBox ) { cube.visible = false; } } public function build():void { //builsds or refreshes the mesh if ( mesh != null) reset(); mesh = new TriangleMesh3D( shapeMaterial, [], []); group.addChild( mesh ); //processes the dataset through the MarchingCubes instance var tris:Array = marchingCubes.compute(); /* // alternative (static) way of computing the triangles //var tris:Array = MarchingCubes.compute(); */ // builds up the volume after the new ly created triangles var i:int = 0; for ( i = 0; i < tris.length; i++ ) { var t :Triangle = tris[ i ]; var v0:Vertex3D = new Vertex3D( t.p0.x * _scale, t.p0.y * _scale, t.p0.z * _scale); var v1:Vertex3D = new Vertex3D( t.p1.x * _scale, t.p1.y * _scale, t.p1.z * _scale); var v2:Vertex3D = new Vertex3D( t.p2.x * _scale, t.p2.y * _scale, t.p2.z * _scale); if ( normal ) { mesh.geometry.vertices.push( v2, v1, v0 ); mesh.geometry.faces.push( new Triangle3D( mesh, [ v2, v1, v0], shapeMaterial, [] ) ); }else { mesh.geometry.vertices.push( v0, v1, v2 ); mesh.geometry.faces.push( new Triangle3D( mesh, [ v0, v1, v2], shapeMaterial, [] ) ); } } //centers the model mesh.position = new Number3D( -( _data.x * _scale ) / 2 , -( _data.y * _scale ) / 2, -( _data.z * _scale ) / 2 ); //and eventually rescales the boundingbox if ( _boundingBox ) { cube.scaleX = _data.x * _scale; cube.scaleY = _data.y * _scale; cube.scaleZ = _data.z * _scale; } render(); } static public function build():void { _instance.build(); } private function initListeners():void { addEventListener( MouseEvent.MOUSE_DOWN, mouseHandler ); addEventListener( MouseEvent.MOUSE_UP, mouseHandler ); } public function mouseHandler( e:Event ):void { switch( e.type ) { case 'mouseDown': mouseDown = true; //displays only the bounding box when moving to spare resources if ( !_liveRender ) { cube.scaleX = _data.x * _scale; cube.scaleY = _data.y * _scale; cube.scaleZ = _data.z * _scale; cube.visible = true; mesh.visible = false; } addEventListener( Event.ENTER_FRAME, onEnterFrame ); break; case 'mouseUp': mouseDown = false; removeEventListener( Event.ENTER_FRAME, onEnterFrame ); //shows the mesh again cube.visible = _boundingBox; mesh.visible = true; render(); break; } } private function resetHandler (e:Event = null):void { reset(); } private function reset ():void { mesh.geometry.vertices = []; mesh.geometry.faces = []; mesh = null; } private function onEnterFrame( e:Event ):void { if ( mouseDown ) { var offx:Number = ( ( stage.stageHeight / 2 - mouseY ) / stage.stageHeight ) * 5; var offy:Number = ( ( stage.stageWidth / 2 - mouseX ) / stage.stageWidth ) * 5; group.rotationX += offx; group.rotationY += offy; } render(); } private function render():void { renderer.renderScene( scene, camera, viewport ); } /** * bounding box visibility */ public function set boundingBox( boolean:Boolean ):void { cube.visible = _boundingBox = boolean; } /** * bounding box visibility */ public function get boundingBox( ):Boolean { return _boundingBox; } /** * renders the mesh when dragging */ public function set liveRender( boolean:Boolean ):void { _liveRender = boolean; } /** * renders the mesh when dragging */ public function get liveRender( ):Boolean { return _liveRender; } /** * sets the model scale */ public function set modelScale( scale:Number ):void { _scale = scale; } /** * returns the model scale */ public function get modelScale():Number { return _scale; } /** * is the mesh material double sided */ public function set doubleSided( boolean:Boolean ):void { shapeMaterial.doubleSided = _doubleSided = boolean; } /** * is the mesh material double sided */ public function get doubleSided( ):Boolean { return _doubleSided; } /** * changes the color [ shadow, diffuse ] */ public function set colors( colors:Array ):void { if ( colors == null ) colors = [0x41260f, 0xFFCC00]; shapeMaterial = new FlatShadeMaterial(new PointLight3D(), colors[0], colors[1]); shapeMaterial.doubleSided = _doubleSided; } } }