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));
}
}
}
}
Apr 19, 2007 at 11:11 AM
Excellent!
Also I appreciated your comparison / contrast with Alex Uhlmanns work. It helps me to understand the differences between the two.
Dw
Apr 28, 2007 at 4:33 AM
Thank you for sharing!
I learn lots when I get to look at other people's code...and I have *alot* to learn!
Jul 23, 2007 at 6:12 AM
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
Dec 21, 2007 at 12:08 AM
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...
Dec 21, 2007 at 9:24 AM
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
Feb 26, 2008 at 1:39 PM
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.
Apr 11, 2008 at 6:08 AM
great
Apr 28, 2008 at 8:22 AM
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
May 16, 2008 at 4:41 PM
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;
Jun 10, 2008 at 11:43 AM
Hi Derrick,
Thanks for the great example and your generosity in sharing your source code and thinking in building the project.
Jul 21, 2008 at 4:18 AM
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 !