Source code for 3d flex form

As promised here is the source code for the 3d flex form component I created using the Papervision engine. You can download the entire project sample code here. I should have some feature updates to this in the near future. Enjoy.

/**************************************************************
   CubeForm.as
   
   Created by:   Derrick Grigg
   derrick@dgrigg.com
   http://www.dgrigg.com
   
   Created on: April 18, 2007
   
   Version: 1.0.0
   
   This is released under a Creative Commons license. More information can be found here:
    http://creativecommons.org/licenses/by/2.5/

***************************************************************/
package com.dgrigg.containers
{
   import flash.display.Sprite;
   import flash.display.Stage;
   import flash.display.StageQuality;
   import flash.display.BitmapData;
   import flash.display.Bitmap;
   import flash.utils.clearInterval;
   import flash.utils.setInterval;
   import flash.geom.Point;
   import flash.events.Event;
   
   import mx.core.UIComponent;
   import mx.containers.ViewStack;
   import mx.core.Container;
   
   import org.papervision3d.cameras.Camera3D;
   import org.papervision3d.scenes.Scene3D;
   import org.papervision3d.objects.Plane;
   import org.papervision3d.objects.DisplayObject3D;
   import org.papervision3d.materials.BitmapMaterial;
   
   /**
    * Dispatched after cube rotates to selected side.
    */
   [Event(name="change",type="flash.events.Event")]
      
   /**
    * Renders a view stack as a 3d cube using the PaperVision engine. 
    * The cube can rotate to the 6 different sides to display a view
    * from the view stack and allow the user to interact with it.
    */
   public class CubeForm extends UIComponent
   {
      /**
       * Papervision camerea.
       */
      protected var camera:Camera3D;
      
      /**
       * Papervision scene.
       */
      protected var scene:Scene3D;
      
      /**
       * Sprite that form is rendered in.
       */
      protected var sprite:Sprite;
      
      /**
       * Value to store a reference to the rotation interval.
       */
      protected var intRotate:int;
      
      /**
       * @private 
       */
      protected var _selectedIndex: int = 0;
      
      /**
       * Array of the six planes that make up the cube. 
       * Each item in the array consists of a <code>plane</code> which is the Papervision Plane
       * and a <code>view</code> which is a reference to the child in the view stack.
       */
      protected var planes:Array;
      
      /**
       * The view stack the form is bound to.
       */
      protected var _viewStack:ViewStack;
      
      /**
       * Root display object for the cube form.
       */
      protected var rootNode:DisplayObject3D;
      
      /**
       * Number of steps used to rotate the cube;
       * 
       * @default 10
       */
      public var rotationSteps:int = 10;
      
      /**
       * @param canvas The sprite to generate the cube form in.
       */
      public function CubeForm(canvas:Sprite)
      {
         sprite = canvas;
         init();
      }

      private function init():void
      {
         var s:Stage = sprite.stage;
         s.quality = StageQuality.BEST;
         setupScene();
      }

      private function setupScene():void
      {
         scene = new Scene3D(sprite);


         camera = new Camera3D();
         camera.zoom = 10;
         camera.focus = 100;

         rootNode = scene.addChild(new DisplayObject3D(), 'rootNode');
         
         scene.renderCamera(camera);
      }
      
      /**
       * The view stack that is bound to the cube form. 
       * <ul>
       * <li>The view stack must have atleast six children, otherwise an error will be thrown.</li>
       * <li>The view stack must have it's <code>creationPolicy</code> property set to <code>all</code>.</li>
       * <li>Each view in the view stack must have it's width and height explicity set, 
       * otherwise the view does not get rendered properly during initialization.</li>
       * </ul>
       * 
       */

      public function set viewStack (vs:ViewStack):void
      {
         var plane: Plane;
         var view:Container;
         
         planes = new Array();
         _viewStack = vs;
         
         //check to see if there are 6 views in the view stack
         //if no throw an error
         var children:Array = _viewStack.getChildren();
         if (children.length > 5)
         {
            view = children[0] as Container;
            plane = createPlane(view, 0 , 0 ,-(_viewStack.width/2));
            rootNode.addChild(plane, 'plane0');
            planes.push({plane:plane, view:view});   
            
            view = children[1] as Container;
            plane = createPlane(view, (_viewStack.width/2), 0, 0, 0, 270, 0);
            rootNode.addChild(plane, 'plane1');
            planes.push({plane:plane, view:view});   
            
            view = children[2] as Container;
            plane =createPlane(view, 0, 0, (_viewStack.width/2), 0, 180, 0);
            rootNode.addChild(plane, 'plane2');
            planes.push({plane:plane, view:view});   
            
            view = children[3] as Container;
            plane =createPlane(view, -(_viewStack.width/2), 0, 0, 0, 90, 0);
            rootNode.addChild(plane, 'plane3');
            planes.push({plane:plane, view:view});   
            
            view = children[4] as Container;
            plane =createPlane(view, 0, (_viewStack.width/2), 0, 270, 0, 0);
            rootNode.addChild(plane, 'plane4');
            planes.push({plane:plane, view:view});   
            
            view = children[5] as Container;
            plane =createPlane(view, 0, -(_viewStack.width/2), 0, 90, 0, 0);
            rootNode.addChild(plane, 'plane5');
            planes.push({plane:plane, view:view});   
            
            //render the scene to get determine the rendered dimensions
            scene.renderCamera( camera );
            
            //position the view stack directly over the cube form
            var p:Point = sprite.localToGlobal(new Point(0,0));
            _viewStack.x = p.x - _viewStack.width/2;
            _viewStack.y = p.y - _viewStack.height/2;         
            
            //adjust the camera zoom to compensate for any scaling that has occurred,
            //in order to keep the cube at the exact scale of the view stack
            camera.zoom = (_viewStack.width/sprite.width)*10;
            scene.renderCamera(camera);
         } else {
            var error:Error = new Error('Error: the viewStack must contain at least six children');
            throw(error);
         }

      }
      
      /**
       * @private
       */
      protected function createPlane(panel:UIComponent, pX:int=0, pY:int=0, pZ:int=0, pRotationX:int=0, pRotationY:int=0, pRotationZ:int=0):Plane
      {
         var bmp:BitmapData = new BitmapData(_viewStack.width, _viewStack.height);
         bmp.draw(panel);
         var material:BitmapMaterial = new BitmapMaterial(bmp);
         material.smooth = true;
         var initObj:Object = {x:pX, y:pY, z:pZ, rotationX:pRotationX, rotationY: pRotationY, rotationZ:pRotationZ};
         var plane:Plane = new Plane(material, bmp.width, bmp.height, 4, 4, initObj);
         return plane;
      }
      
      /**
       * Index of selected plane on the cube form.
       * 
       * @default 0
       */
      public function get selectedIndex():int
      {
         return _selectedIndex;
      }
      
      public function set selectedIndex(val:int):void
      {
         //get the selected plane and re-render that side in order 
         //to reflect the current data on the view
         var obj:Object = planes[_selectedIndex];
         var plane:Plane = obj.plane as Plane;
         var bmp:BitmapData = new BitmapData(obj.view.width, obj.view.height);
         bmp.draw(obj.view);
         var material:BitmapMaterial = new BitmapMaterial(bmp);
         plane.material = material;
         this.scene.renderCamera( camera );
         obj.view.visible = false;
         
         //get the current cube's rotation values
         _selectedIndex = val;
         var curRotation:Object = {x:rootNode.rotationX, y:rootNode.rotationY, z:rootNode.rotationZ};
         var destRotation:Object;
         
         switch (_selectedIndex)
         {
            case 0:
               destRotation = {x: 0, y:0, z:0};
               break;
            case 1:
               destRotation = {x: 0, y:90, z:0};
               break;
            case 2:
               destRotation = {x: 0, y:180, z:0};
               break;
            case 3:
               destRotation = {x: 0, y:270, z:0};
               break;
            case 4:
               destRotation = {x: 90, y:0, z:0};
               break;
            case 5:
               destRotation = {x: 270, y:0, z:0};
               break;
         }
         
         var steps: Object = new Object();
         steps.x = Math.floor((destRotation.x - curRotation.x)/rotationSteps);
         steps.y = Math.floor((destRotation.y - curRotation.y)/rotationSteps);
         steps.z = Math.floor((destRotation.z - curRotation.z)/rotationSteps);
         
         intRotate = setInterval(rotateCube, 50, steps, destRotation);
      }
      
      private function rotateCube(steps:Object, dest:Object):void
      {
         if (Math.abs(rootNode.rotationX) != dest.x) rootNode.rotationX += steps.x;
         if (Math.abs(rootNode.rotationY) != dest.y) rootNode.rotationY += steps.y;
         if (Math.abs(rootNode.rotationX) != dest.z) rootNode.rotationZ += steps.z;
         
         scene.renderCamera( camera );
         
         if (Math.abs(rootNode.rotationX) == dest.x && Math.abs(rootNode.rotationY) == dest.y && Math.abs(rootNode.rotationZ) == dest.z)
         {
            //reset the rotation values back to a value <= 360
            if (Math.abs(rootNode.rotationX) >= 360) rootNode.rotationX = Math.abs(rootNode.rotationX) - 360;
            if (Math.abs(rootNode.rotationY) >= 360) rootNode.rotationY = Math.abs(rootNode.rotationY) - 360;
            if (Math.abs(rootNode.rotationZ) >= 360) rootNode.rotationZ = Math.abs(rootNode.rotationZ) - 360;
            
            clearInterval(intRotate);
            _viewStack.selectedIndex = _selectedIndex;
            dispatchEvent(new Event(Event.CHANGE));
         }
      }
      
   }
}

11 Comments:

  1. Dan Wilson

    Excellent!

    Also I appreciated your comparison / contrast with Alex Uhlmanns work. It helps me to understand the differences between the two.



    Dw

  2. David Harris

    Thank you for sharing!

    I learn lots when I get to look at other people's code...and I have *alot* to learn!

  3. anna



    Hi


    I have an mxml page which have 4 tabs each with a form which need to be submitted to 4 different tables.(backend php)

    I am able to submit the data to the table but when i submit form4.. i will get 4 entries of form1 in table1.

    How can I get some identifier to my php page on which form or which button is clicked.

    Thanks

  4. fadzril

    when i tried to run this app. from my Flex Builder 2, it show error on:
    1046: Type was not found or was not a compile-time constant: Plane.
    which i believed it sit on Cube.as.

    Can you assist me. Thanks in advance. Sorry for my bad english. Learning...

  5. Derrick

    Fadzril, do you have the PaperVision 3d source files/lib accessible to your project? You'll need those to be able to compile and run the code I provided.

    Derrick

  6. Clayton Gulick

    For those who need transparency in the forms:

    If you replace the BitmapMaterial with a MovieMaterial (which arguably should be used anyway) in both the CreatePlane function and the selectedIndex function you can get transparency support (for see-through themes, etc...).

    If anyone needs this let me know and I'll post the modified code.

    Awesome job Derrick, thanks.

  7. rahul

    great

  8. Natasha

    Thank you for sharing!

    I have found interesting sources ( http://filesfinds.com & http://fileshunt.com ) and would like to give the benefit of my experience to you

  9. dean

    Awesome effect

    Clayton Gulick can you post your code for transparency alter

    I add to alter the following to get the view stack on top of the 3d canvas, other wise was bottom left of the window
    //position the view stack directly over the cube form
    var p:Point = sprite.localToGlobal(new Point(0,0));
    _viewStack.x = p.x - _viewStack.width/2;
    _viewStack.y = p.y - _viewStack.height/2;

    //position the view stack directly over the cube form
    var p:Point = sprite.localToGlobal(new Point(0,0));
    _viewStack.x = 0;
    _viewStack.y = 0;

  10. Becky Wood

    Hi Derrick,

    Thanks for the great example and your generosity in sharing your source code and thinking in building the project.

  11. Julius

    Hi,

    Your example is very great !!!

    I just have a problem to dowload the PaperVision 3d source library.

    Could you give me a link to download this library ?

    Thanks !


Leave a comment

Name: (required)

Email: (required)

URL:

Captcha test: (required)
Comments: (required)