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));
}
}
}
}
Excellent!
Also I appreciated your comparison / contrast with Alex Uhlmanns work. It helps me to understand the differences between the two.
Dw
Thank you for sharing!
I learn lots when I get to look at other people’s code…and I have *alot* to learn!
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
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…
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
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.
great
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
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;
Hi Derrick,
Thanks for the great example and your generosity in sharing your source code and thinking in building the project.
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 !
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
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.
Any chance this could be made to work with more than 6 viewstacks?
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.
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
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.
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.
I tried to port your example to Away3D and could not.
Suggestion?
(Away 3d has extruded text, PV does not).
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.
same problem with id 1046, download papervision 3d source and past in org path, but the error continuos … please help
Great… Thanks