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));
         }
      }
      
   }
}

22 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. 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. 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

  8. 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;

  9. Becky Wood

    Hi Derrick,

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

  10. 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 !

  11. angel

    hi its a goos example but doesn’t work ,i download the new api for papervision and all methods are missing and undefined, you need rebuild the aplication with new methods

  12. Steve

    Hi,

    Kudos for sharing this. I downloaded the project, but I seem to be missing the Plane component in CubeForm.as. There is no import statement, so I am not sure where to look for this class.

    Thanks again.

  13. Alan

    Any chance this could be made to work with more than 6 viewstacks?

  14. I’m sure you could do it with more than 6 views but a cube only has 6 six sides so it would be tricky to handle the extra views.

  15. Alfredo

    Hola, estoy tratando de hacer funcionar el ejemplo y me da el siguiente error

    Id

    1046: Type was not found or was not a compile-time constant: Plane. cubo/src/com/dgrigg/containers CubeForm.as line 205

    En que me estoy equivocando.

    Desde ya gracias

  16. So if you take a look at the source code you’ll see that I’ve created a BasePV3DContainer, which extends ViewStack and creates 3D planes for each child in the container. The idea here is that you can create an extension of this class and implement the layoutChildren() method and make up your own 3D container component.

  17. Nice! The cube component is a cool example. And you’re right, this is a good example of how the 3D APIs in Flex make it a bit more accessible. It would be cool to see Papervision3D wrapped in MXML tags. :)

  18. Vic Cekvenich

    I tried to port your example to Away3D and could not.

    Suggestion?

    (Away 3d has extruded text, PV does not).

  19. Question

    Id 1046: Type was not found or was not a compile-time constant: Plane.

    derrick_cuboid/src/com/dgrigg/containers

    CubeForm.as : line 205

    How to resolve this issue, i have whole code of papervision 3d as well in my app.

  20. julian

    same problem with id 1046, download papervision 3d source and past in org path, but the error continuos … please help

  21. Vaibhav

    Great… Thanks

Leave a comment

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>