package
{
import flash.display.Sprite;
import flash.display.Graphics;
import flash.display.LoaderInfo;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.events.TimerEvent;
import flash.events.Event;
import flash.utils.Timer;
import flash.utils.ByteArray;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.materials.BitmapFileMaterial;
import org.papervision3d.materials.MovieMaterial;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.materials.WireframeMaterial;
import org.papervision3d.core.proto.MaterialObject3D;
import org.papervision3d.objects.parsers.DAE;
import org.papervision3d.events.FileLoadEvent;
import org.papervision3d.objects.primitives.*;
import com.tadSrc.tadsClasses.LoadSomeXML;
import com.tadSrc.tadsClasses.DOMEx;
import com.tadSrc.tadsClasses.Checker;
/**
*
* Requiers Paversion3D - www.papervision3D.org
* 3D Object Creation via simple XML with JavaScript DOM support.
* Build - Version 1 Feb 2010
* Author - Tad D. Green
*
* License - Free for any use so long as this notice remains intact.
*
* Warranty - None. Your use of this software is at your own risk.
*
* Credits - www.Papervision3D.org, www.actiontad.com
*
*/
public class ThreeDObjectMaker extends Sprite
{
private var theScene:Scene3D;
private var viewPort:Viewport3D;
private var camera:Camera3D;
private var Brenderer:BasicRenderEngine;
private var myLoop:Timer;
private var toRotate:Number;
private var toYaw:Number;
private var toRoll:Number;
private var toPitch:Number;
private var objectMade:Boolean;
private var jcommunique:DOMEx;
private var theSWFsID:*;
public var threeDObject:*;
private var myW:Number = 0;
private var myH:Number = 0;
private var useDOM:Boolean = false;
/* can be commented out */
[Embed(source="defaultCube.xml", mimeType="application/octet-stream")]
private var dCube:Class;
private var fRate:int;
private var flashvarser:Object;
public function ThreeDObjectMaker(frameRate:int = 30, fvars:Object = null, wrapperEnable:Boolean = true)
{
fRate = frameRate;
flashvarser = fvars;
useDOM = wrapperEnable;
if (!objectMade) {objectMade = false;}
if (!flashvarser) {
try {
flashvarser = loaderInfo.parameters;
}
catch(e:Error) {
if (useDOM) DOMEx.alert(e.message+"");
}
}
var theFrameRate:Number = (flashvarser && flashvarser["framerate"]) ? flashvarser["framerate"] : fRate;
myLoop = new Timer(Math.round(1/ theFrameRate * 1000), 0);
toPitch = 0;toRoll = 0;toYaw = 0;toRotate = 0;
try {
if (flashvarser && flashvarser.hasOwnProperty("threedobjectxml")) {
loadExternalObjectSpecs(flashvarser["threedobjectxml"].toString());
}else {
if (flashvarser && flashvarser.hasOwnProperty("threedobjectdirect")) {
var obarrOne:Array = flashvarser["threedobjectdirect"].toString().split(",");
var arrObj:Object = new Object();
for (var aio:int = 0; aio < obarrOne.length; aio+=2)
{ arrObj[obarrOne[aio]] = obarrOne[aio+1]; }
var obarr:Array = [ arrObj ];
obarr.unshift(null);obarr.unshift("thesespecs");
loadDirectObjectSpecs.apply(null, obarr);
}
}
}catch (e:Error) { if(useDOM) {DOMEx.alert(e.message+"");} }
var communicationWord:String = "invokeTDOMGetter";
var creationWord:String = "createObject";
if (flashvarser && flashvarser.hasOwnProperty("creationfunctionname"))
{creationWord = flashvarser["creationfunctionname"].toString()}
if (flashvarser && flashvarser.hasOwnProperty("jsfunctionname"))
{communicationWord = flashvarser["jsfunctionname"].toString()}
if (useDOM == true) {
if (!flashvarser || !flashvarser.hasOwnProperty("swfsid")) {
theSWFsID = DOMEx.idGet();
(theSWFsID != undefined && theSWFsID != "") ?
theSWFsID = theSWFsID : theSWFsID = "ThreeDObjectMaker";
}else {theSWFsID = flashvarser["swfsid"];}
jcommunique = new DOMEx(this);
if (DOMEx.addCall("passage"+theSWFsID+"", jcommunique.invokeViaJavaScript))
{DOMEx.makeMasterTalk(communicationWord, "passage"+theSWFsID+"", theSWFsID);}
if (DOMEx.addCall("doLoad"+theSWFsID+"", loadDirectObjectSpecs))
{DOMEx.makeMasterTalk(creationWord, "doLoad"+theSWFsID+"", theSWFsID);}
}
}
/* End constructor */
public function get TDOMWidth():Number { return myW; }
public function get TDOMHeight():Number{ return myH; }
public function get constructed():Boolean { return objectMade; }
public function get toggleRender():Function
{
var tR:Function = function(kill:Boolean = false):void {
if (kill == false) { if (myLoop) {(myLoop.running) ? myLoop.stop() : myLoop.start();} }
else
{if (myLoop) {myLoop.stop();myLoop.removeEventListener(TimerEvent.TIMER, reRender);myLoop = null;} }
};
return tR;
}
public function get allRotationSpecs():Function
{
var changeAllRotationSpecs:Function = function(arg1:Number,arg2:Number,arg3:Number,arg4:Number):void {
try
{toRotate = arg1;toYaw = arg2;toRoll = arg3;toPitch = arg4;}
catch (e:Error) {
throw new Error("Four numbers, separated by commas, must be passed to allRotationSpecs.");
}
};
return changeAllRotationSpecs;
}
public function set rotationDirection(angle:Number):void { toRotate = angle; }
public function get rotationDirection():Number { return toRotate; }
public function set rotationYaw(y:Number):void { toYaw = y; }
public function get rotationYaw():Number { return toYaw; }
public function set rotationRoll(r:Number):void { toRoll = r; }
public function get rotationRoll():Number { return toRoll; }
public function set rotationPitch(p:Number):void { toPitch = p; }
public function get rotationPitch():Number { return toPitch; }
public function get allRotations():Array { return new Array(toRotate, toYaw, toRoll, toPitch); }
public function get zoom():Number
{
var zoomer:Number = 0;
if (camera && camera as Camera3D != null)
{
zoomer = camera.z;
}
return zoomer;
}
public function get loadExternalObjectSpecs():Function
{
var externalLoadCreaIniFunc:Function = function(XMLDataURL:String):void {
if (objectMade == false) {loadSignify();
LoadSomeXML.freshXMLFile(XMLDataURL, ExternalXMLLoaded, LoadError);
}
};
return externalLoadCreaIniFunc;
}
public function get loadDirectObjectSpecs():Function
{
var DirecCreaFunc:Function = function(plainXML:* = null,
arrayOfBytes:ByteArray = null,
specs:Object = null):void {
if (objectMade == false) {
loadSignify();
var theX:XML;
if (plainXML != null && plainXML as XML == null) {
if (plainXML.toString().match(/thesespecs/i)) {
try {
var cuber:ByteArray = new dCube();
theX = new XML(cuber.readUTFBytes(cuber.length));
if (specs) {
for (var argi:String in specs)
{ theX[argi] = specs[argi]; }
}
}catch(e:Error) {
throw new Error("defaultCube.xml was not embeded, use full xml not a partial object.");
}
}
}
if (plainXML != null && plainXML as XML != null)
{
theX = plainXML;
}
if (plainXML == null && arrayOfBytes != null && arrayOfBytes as ByteArray != null) {
var xmlBytes:ByteArray = arrayOfBytes;
theX = new XML(xmlBytes.readUTFBytes(xmlBytes.length));
}
makeObject(theX);
}
};
return DirecCreaFunc;
}
public function get loadSignify():Function { return loadProgress; }
/* End getters */
private function loadProgress(thisText:String = "."):void
{
var loadField:TextField = new TextField();
if (thisText != ".") {loadField.text = thisText;}
else {loadField.text = "Loading...";}
loadField.autoSize = TextFieldAutoSize.LEFT;
if (this.numChildren == 0) {
this.addChild(loadField);
}
else {
if (thisText != ".") TextField(this.getChildAt(0)).text = thisText;
}
}
protected function makeObject(xd:XML):void
{
var theXML:XML = xd;
var check:Checker = new Checker(theXML);
var threeDObjectRadius:Number = check.property("objectRadius", 100, "justNumbers");
theScene = new Scene3D();
camera = new Camera3D();
var vW:Number = check.property("viewWidth", 100, "justNumbers");
var vH:Number = check.property("viewHeight", 100, "justNumbers");
myW = vW;myH = vH;
viewPort = new Viewport3D(vW, vH, false);
Brenderer = new BasicRenderEngine();
toRotate = Number(check.property("toRotate", 0, "justNumbers"));
toYaw = Number(check.property("toYaw", 0, "justNumbers"));
toRoll = Number(check.property("toRoll", 0, "justNumbers"));
toPitch = Number(check.property("toPitch", 0, "justNumbers"));
/* This is not really the zoom of the camera but the z position.
It can be thought of as the distance from the camera to the object, and therefore zoom.
Camera3D objects also have a zoom property, it sets the scale at which 3D objects are rendered.
Uping the true scale will lead to long uploading times and slow processing of colladas.
The z property is used instead to move the camera back and forth from the object in 3D space.
For ease of mind we just signify it as zoom in the xml and when getting it. */
camera.z = check.property("zoom", -1000);
var threeDObjectRed:String = check.property("RedColorValue", "00");
var threeDObjectGreen:String = check.property("GreenColorValue", "ff");
var threeDObjectBlue:String = check.property("BlueColorValue", "00");
var colorIs:Number = Number("0x"+threeDObjectRed+threeDObjectGreen+threeDObjectBlue);
var threeDObjectAlpha:Number = check.property("wireAlpha", 1, "justNumbers");
var segW:int = int(check.property("segW", 1, "justNumbers"));
var segH:int = int(check.property("segH", 1, "justNumbers"));
var myMaterial:MaterialObject3D;
var materialChoice:String = check.property("materialType", "wireframe", "justAlphas");
var objectChoice:String = check.property("objectType", "Cube", "justAlphas");
switch(materialChoice) {
case "wireframe":
myMaterial = new WireframeMaterial(colorIs, threeDObjectAlpha);
break;
case "bitmapFile":
myMaterial = new BitmapFileMaterial(check.property("bitmap", "default.png")+"", false);
break;
case "plainColor":
var sp:Sprite = new Sprite();
sp.graphics.beginFill(uint("0x"+check.property("plainColor", "ff0000", "6DigitColor")));
sp.graphics.drawRect(0,0,threeDObjectRadius,threeDObjectRadius);
myMaterial = new MovieMaterial(sp, true, false, true);
break;
default:
myMaterial = new WireframeMaterial(colorIs, threeDObjectAlpha);
break;
}
switch(objectChoice) {
case "Arrow":
threeDObject = new Arrow(myMaterial);
break;
case "Cone":
threeDObject = new Cone(myMaterial, threeDObjectRadius, threeDObjectRadius, segW, segH);
break;
case "Cube":
var insideF:int = check.property("insideFaces", 0, "justNumbers");
var excludeF:int = check.property("excludeFaces", 0, "justNumbers");
var mLc:MaterialsList = new MaterialsList( {all: myMaterial} );
threeDObject =
new Cube(mLc,threeDObjectRadius,threeDObjectRadius,threeDObjectRadius,1,1,1,insideF,excludeF);
break;
case "Rectangle":
var insideFr:int = check.property("insideFaces", 0, "justNumbers");
var excludeFr:int = check.property("excludeFaces", 0, "justNumbers");
var mLcr:MaterialsList = new MaterialsList( {all: myMaterial} );
var rw:Number = check.property("rectangleWidth", 200);
var rh:Number = check.property("rectangleHeight", 100);
threeDObject =
new Cube(mLcr,threeDObjectRadius+rw,threeDObjectRadius,threeDObjectRadius+rh,1,1,1,insideFr,excludeFr);
break;
case "Cylinder":
var topR:Number = check.property("topRadius", -1);
var topF:Boolean = Boolean(check.property("cylinderTopFace", true));
var bottF:Boolean = Boolean(check.property("bottomFace", true));
threeDObject =
new Cylinder(myMaterial, threeDObjectRadius, threeDObjectRadius, segW, segH, topR, topF, bottF);
break;
case "PaperPlane":
var pPlaneScale:Number = check.property("paperPlaneScale", 0, "justNumbers");
threeDObject = new PaperPlane(myMaterial, pPlaneScale);
break;
case "Plane":
threeDObject = new Plane(myMaterial, threeDObjectRadius, threeDObjectRadius, segW, segH);
case "Sphere":
threeDObject = new Sphere(myMaterial, threeDObjectRadius, segW, segH);
break;
case "Collada":
var mL:MaterialsList = new MaterialsList();mL.addMaterial(myMaterial, theXML.materialName);
threeDObject = new DAE();
threeDObject.scale = Number(check.property("daeScale", 1));threeDObject.forceCoordSet = 1;
threeDObject.useOwnContainer = false;threeDObject.autoCalcScreenCoords = true;
threeDObject.addEventListener(FileLoadEvent.LOAD_COMPLETE, removeLoadSay, false, 0, true);
try {threeDObject.load(""+check.property("dae", "default.dae")+"", mL);} catch (e:Error) {}
break;
default:
var insideFD:int = check.property("insideFaces", 0, "justNumbers");
var excludeFD:int = check.property("excludeFaces", 0, "justNumbers");
var mLcD:MaterialsList = new MaterialsList( {all: myMaterial} );
threeDObject =
new Cube(mLcD,threeDObjectRadius,threeDObjectRadius,threeDObjectRadius,1,1,1,insideFD,excludeFD);
break;
}
if (objectChoice != "Collada") {showThings();}
}
private function removeLoadSay(e:Event):void
{
showThings();
}
private function showThings():void
{
if (this.getChildAt(0) as TextField != null) this.removeChild(this.getChildAt(0));
this.addChild(viewPort);
if (objectMade == false) {
objectMade = true;
theScene.addChild(threeDObject);
var fRateToBe:int = (fRate) ? fRate : 30;
if (!myLoop) {myLoop = new Timer(Math.round(1/ fRateToBe * 1000), 0);}
myLoop.addEventListener(TimerEvent.TIMER, reRender, false, 0, true);
myLoop.start();
}
}
private function reRender(e:TimerEvent):void
{
threeDObject.yaw(toRotate * toYaw);
threeDObject.roll(toRotate * toRoll);
threeDObject.pitch(toRotate * toPitch);
Brenderer.renderScene(theScene, camera, viewPort);
}
private function ExternalXMLLoaded(e:Event):void
{
var loadedXML:XML = new XML(e.target.data);
makeObject(loadedXML);
}
private function LoadError(e:Event):void
{
if (useDOM) DOMEx.alert("Error loading xml");
}
}
}