
Adobe Flash Tutorial: XML Papervision
May 6, 2009Good day, people.
This is my first tutorial, so don’t kill me if i’ll get it optimized.
What was the idea?
I’m a big fan of Papervision. I try to stay in touch with the entire community, at least read what’s new, what the guys show us and how i can use them in different (and , for the most part, more lame) ways.Also I haven’t seen many tutorials done that involve papervision and xml. So i thought i could start there. Little did i know what headache i’d get by making the demo to work. Ok, so let’s get to it.
UPDATE I realized how to greatly simply the init3d function. Will update it in aproximately 12 hours.
Idea: I tried to replicate a menu from a site did by Carlos Ulloa, where you have 4 cubes (they’re not exactly cubes, i think they are collada imported objects which have a plane on a side, my wild guess) ….which do stuff
.
IDE: I used Flash CS3. Yes, i know, it’s like shooting yourself in the foot when trying to open the tv.
Steps:
Step 1.
Make a new as3 fla, choose at what fps your movie will run ( i prefer 31 fps or more, however, the PC will disagree with me on this, that lazy bastard) and add the classpaths to the papervision classes( or you could copy the folder where you saved your fla).
I made a very small xml which looks like this ( i put it in a folder called “data”):
?xml version=”1.0″ encoding=”utf-8″?
root
menupics test=”pics/mybrainquit-128.jpg”
pics test=”pics/mybrainquit-128.jpg”
pics test=”pics/mybrainquit-128.jpg”
pics test=”pics/mybrainquit-128.jpg”
menu
root
..and i created another folder for the pic which was called, you guessed it , “pics”.
Step 2:
I had to think (tough task) on how i’d structure the code. So, of course, xml first, viewport and scene second and lastly, a @#$@@!^%$ cube. Yes, a cube. Why am i ripping my hair out of my head because i chose a cube? Because the cube class doesn’t accept the normal and traditional BitmapFileMaterial, that FFFFFFFFF bastard. And therefore you have to cast somehow the String you receive from the xml into something that Cube will like…except ColorMaterial, that doesn’t do you much good. Cube accepts MaterialsList, which, in turn, accept MaterialObject3D.And MaterialObject3D accepts only LineMaterial, ParticleMaterial, TriangleMaterial and VectorShapeMaterial. BitmapMaterial is our weapon of choice for this demo. Of course i had to learn this the hard way, looking into the classes and looking at what material is simple enough to implement and doesn’t require too much thinking from me.
Step 3:
Code. Smoke.Smoke some more. Become extremelly frustrated when you realise you forgot to initialize a number for a command. Smoke to calm yourself. Etc….
Step 4:
Rejoice.
So, without further ado, here’s the entire code.
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.view.Viewport3D;
import org.papervision3d.objects.primitives.Cube;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.materials.ColorMaterial;import flash.events.*;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.filters.GlowFilter;
import flash.display.Bitmap;
import flash.display.Loader;var mycube:Cube;
var myscube:Cube;
var mytcube:Cube;
var myfcube:Cube;
var mycamera:Camera3D;
var myscene:Scene3D;
var myview:Viewport3D;
var myrender:BasicRenderEngine;
var mymaterialslist:MaterialsList;
var mymaterialslists:MaterialsList;
var mymaterialslista:MaterialsList;
var mymaterialslistj:MaterialsList;
var mylist:XMLList;
var myxml:XML = new XML();
var mybit:BitmapMaterial;
var myloader:Loader;
var mybitmap:Bitmap;var nrofCubes:Number = 4;
var isOrbiting = true;
var myglow:GlowFilter = new GlowFilter(0×000000,1,6,6,1,3);
var urlloader:URLLoader = new URLLoader();
var myarray:Array = new Array();
urlloader.addEventListener(Event.COMPLETE, doDistribution);function doDistribution(e:Event):void
{myxml = XML(e.target.data);
mylist = myxml.menu;
for (var i:Number = 0; i<mylist.pics.length();i++)
{
myarray.push(mylist.pics[i].@test);
}
myloader = new Loader();
myloader.load(new URLRequest(String(myarray[0])));
myloader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadPic);}
function loadPic(e:Event):void
{
mybitmap = new Bitmap();
mybitmap = Bitmap(e.target.content);
initPapervision();
init3d();
addEventListener(Event.ENTER_FRAME, doRender);
}urlloader.load(new URLRequest(“data/data.xml”));
function initPapervision():void
{
myview = new Viewport3D(550,550,true,true);
myview.filters = [myglow];
addChild(myview);
mycamera = new Camera3D();
myscene = new Scene3D();
myrender = new BasicRenderEngine();
stage.addEventListener(MouseEvent.MOUSE_DOWN, doFalse);
stage.addEventListener(MouseEvent.MOUSE_UP, doTrue);
}function init3d():void
{for (var t:Number = 0; t<nrofCubes;t++)
{
switch(t)
{
case 0:mymaterialslist = new MaterialsList();
mymaterialslist.addMaterial(createCorrectMaterial(),”left”);
mymaterialslist.addMaterial( createCorrectMaterial(),”back”);
mymaterialslist.addMaterial(createCorrectMaterial(),”front”);
mymaterialslist.addMaterial(createCorrectMaterial(),”right”);
mymaterialslist.addMaterial(createCorrectMaterial(),”top”);
mymaterialslist.addMaterial(createCorrectMaterial(),”bottom”);
mycube = new Cube(mymaterialslist,128,128,128,1,1,1);
myscene.addChild(mycube);
break;case 1:
mymaterialslists = new MaterialsList();
mymaterialslists.addMaterial(createCorrectMaterial(),”left”);
mymaterialslists.addMaterial( createCorrectMaterial(),”back”);
mymaterialslists.addMaterial(createCorrectMaterial(),”front”);
mymaterialslists.addMaterial(createCorrectMaterial(),”right”);
mymaterialslists.addMaterial(createCorrectMaterial(),”top”);
mymaterialslists.addMaterial(createCorrectMaterial(),”bottom”);
myscube = new Cube(mymaterialslists,128,128,128,1,1,1);
myscene.addChild(myscube);
myscube.z -= 256;
myscube.x -= 256;
break;case 2:
mymaterialslista = new MaterialsList();
mymaterialslista.addMaterial(createCorrectMaterial(),”left”);
mymaterialslista.addMaterial( createCorrectMaterial(),”back”);
mymaterialslista.addMaterial(createCorrectMaterial(),”front”);
mymaterialslista.addMaterial(createCorrectMaterial(),”right”);
mymaterialslista.addMaterial(createCorrectMaterial(),”top”);
mymaterialslista.addMaterial(createCorrectMaterial(),”bottom”);
mytcube = new Cube(mymaterialslista,128,128,128,1,1,1);
myscene.addChild(mytcube);
mytcube.z -= 256;
mytcube.x += 256;
break;case 3:
mymaterialslistj = new MaterialsList();
mymaterialslistj.addMaterial(createCorrectMaterial(),”left”);
mymaterialslistj.addMaterial( createCorrectMaterial(),”back”);
mymaterialslistj.addMaterial(createCorrectMaterial(),”front”);
mymaterialslistj.addMaterial(createCorrectMaterial(),”right”);
mymaterialslistj.addMaterial(createCorrectMaterial(),”top”);
mymaterialslistj.addMaterial(createCorrectMaterial(),”bottom”);
myfcube = new Cube(mymaterialslistj,128,128,128,1,1,1);
myscene.addChild(myfcube);
myfcube.z -= (256*2);
break;
}
}
}function createCorrectMaterial():BitmapMaterial
{
mybit = new BitmapMaterial(mybitmap.bitmapData,true);
return mybit;
}var myx:Number = 0;
var myprev:Number = 0;
var myy:Number = 0;
var myprevy:Number = 0;
function doRender(e:Event):void
{
myrender.renderScene(myscene, mycamera, myview);
if (!isOrbiting)
{
myx = stage.mouseX – myprev;
myy = stage.mouseX – myprevy;
myx += myprev;
myy += myprevy;
myx %= 360;
myy %= 360;
mycamera.orbit(myy,myx,true,mycamera.target);
}
myprev = stage.mouseX;
myprevy = stage.mouseY;
}function doFalse(e:Event):void
{
isOrbiting = false;
}function doTrue(e:Event):void
{
isOrbiting = true;
}
Ok, so, let’s explain, from the first function.
function doDistribution(e:Event):void
{myxml = XML(e.target.data);
mylist = myxml.menu;
for (var i:Number = 0; i<mylist.pics.length();i++)
{
myarray.push(mylist.pics[i].@test);
}
myloader = new Loader();
myloader.load(new URLRequest(String(myarray[0])));
myloader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadPic);}
Quite simple, i parse the xml, and put the pic paths in an array. I wanted to store them so i could use them everywhere and anywhere. Next, my favourite part (NOT) , i used a loader to push the pics into a bitmap. I’ll explain more on the second function on why i did this here.
function loadPic(e:Event):void
{
mybitmap = new Bitmap();
mybitmap = Bitmap(e.target.content);
initPapervision();
init3d();
addEventListener(Event.ENTER_FRAME, doRender);
}
Ok, here comes the explanatory part. You cannot upload a picture into a bitmap (not that i know off, i’d be very happy to be proven wrong) without using a loader. Why did i need a bitmap? Because BitmapMaterial, the material needed for the cube, accepts Bitmaps, not Strings (dammit). That’s also part of the reason why i initialized the other functions here. I tested my functions, which one initializes first and the EventListener always will start first. So if later on you’ll need the “mybitmap” variable and you didn’t instantiate it here, it would throw a very nice (I HATE YOU!!!) error that the object and/or reference is null.
function initPapervision():void
{
myview = new Viewport3D(550,550,true,true);
myview.filters = [myglow];
addChild(myview);
mycamera = new Camera3D();
myscene = new Scene3D();
myrender = new BasicRenderEngine();
stage.addEventListener(MouseEvent.MOUSE_DOWN, doFalse);
stage.addEventListener(MouseEvent.MOUSE_UP, doTrue);
}
Pretty self – explanatory. I initialized the viewport, the scene, almost everything papervisiony. Also, i added some listeners for a cool mouse effect that i’ll tell you more about in the last function. And a glow filter because it looks nice and i like to glow in the dark.
function init3d():void
{for (var t:Number = 0; t<nrofCubes;t++)
{
switch(t)
{
case 0:mymaterialslist = new MaterialsList();
mymaterialslist.addMaterial(createCorrectMaterial(),”left”);
mymaterialslist.addMaterial( createCorrectMaterial(),”back”);
mymaterialslist.addMaterial(createCorrectMaterial(),”front”);
mymaterialslist.addMaterial(createCorrectMaterial(),”right”);
mymaterialslist.addMaterial(createCorrectMaterial(),”top”);
mymaterialslist.addMaterial(createCorrectMaterial(),”bottom”);
mycube = new Cube(mymaterialslist,128,128,128,1,1,1);
myscene.addChild(mycube);
break;case 1:
mymaterialslists = new MaterialsList();
mymaterialslists.addMaterial(createCorrectMaterial(),”left”);
mymaterialslists.addMaterial( createCorrectMaterial(),”back”);
mymaterialslists.addMaterial(createCorrectMaterial(),”front”);
mymaterialslists.addMaterial(createCorrectMaterial(),”right”);
mymaterialslists.addMaterial(createCorrectMaterial(),”top”);
mymaterialslists.addMaterial(createCorrectMaterial(),”bottom”);
myscube = new Cube(mymaterialslists,128,128,128,1,1,1);
myscene.addChild(myscube);
myscube.z -= 256;
myscube.x -= 256;
break;case 2:
mymaterialslista = new MaterialsList();
mymaterialslista.addMaterial(createCorrectMaterial(),”left”);
mymaterialslista.addMaterial( createCorrectMaterial(),”back”);
mymaterialslista.addMaterial(createCorrectMaterial(),”front”);
mymaterialslista.addMaterial(createCorrectMaterial(),”right”);
mymaterialslista.addMaterial(createCorrectMaterial(),”top”);
mymaterialslista.addMaterial(createCorrectMaterial(),”bottom”);
mytcube = new Cube(mymaterialslista,128,128,128,1,1,1);
myscene.addChild(mytcube);
mytcube.z -= 256;
mytcube.x += 256;
break;case 3:
mymaterialslistj = new MaterialsList();
mymaterialslistj.addMaterial(createCorrectMaterial(),”left”);
mymaterialslistj.addMaterial( createCorrectMaterial(),”back”);
mymaterialslistj.addMaterial(createCorrectMaterial(),”front”);
mymaterialslistj.addMaterial(createCorrectMaterial(),”right”);
mymaterialslistj.addMaterial(createCorrectMaterial(),”top”);
mymaterialslistj.addMaterial(createCorrectMaterial(),”bottom”);
myfcube = new Cube(mymaterialslistj,128,128,128,1,1,1);
myscene.addChild(myfcube);
myfcube.z -= (256*2);
break;
}
}
}
I added 4 cubes to the stage. You’re probably wondering why i used a switch to add them. Well, i wanted only a side of the cubes to have a photo attached, the rest i would have used a ColorMaterial (basically, i’m saying i would have used the color white on 5 sides out of 6). But when everything else was finished and i wanted to start splitting the sides, i realised i’m too lazy and i want to go to sleep, so i’ll leave it to you to finish this task, if you want to, of course
.
function createCorrectMaterial():BitmapMaterial
{
mybit = new BitmapMaterial(mybitmap.bitmapData,true);
return mybit;
}
Here’s where the xml magic happens. I’m taking the bitmap that i created earlier and putting it to good use. BitmapMaterial accepts bitmaps, i’m giving it the data, i’m saying it’s precise and returning it to the cube to be used as a texture for its sides. Hooray for OOP.
var myx:Number = 0;
var myprev:Number = 0;
var myy:Number = 0;
var myprevy:Number = 0;
function doRender(e:Event):void
{
myrender.renderScene(myscene, mycamera, myview);
if (!isOrbiting)
{
myx = stage.mouseX – myprev;
myy = stage.mouseX – myprevy;
myx += myprev;
myy += myprevy;
myx %= 360;
myy %= 360;
mycamera.orbit(myy,myx,true,mycamera.target);
}
myprev = stage.mouseX;
myprevy = stage.mouseY;
}
I render the scene and add it a cool mouse effect. What is this mouse effect? Well, when you hold down the mouse button and move around with your mouse, the camera will orbit around the entire scene while you hold the mouse down, looking at its target. If the target isn’t set, it will look at the first object added to the scene. Here i could have done a little more, i could have added an invisible plane/cube/sphere/whatever, put it in the middle of the cubes and told the camera to look at it. This effect i learned from the tutorials provided by John Lindquist. You can see some pretty amazing stuff there.
And there you have it. My first tutorial. I hope i have been explanatory to some degree. If i haven’t, ask me what you didn’t understand and i’ll respond pronto. Also, if you think my code isn’t optimized, don’t just think it, give me some feedback, please. I’m gonna try to upload the swf on a server these days and , i hope, it will be up by Monday, to show you how it looks like.
Hope you enjoyed it, good night.
UPDATE: LINK link
mersi mult sfinx, chiar aveam nevoie k nu stiam cum sa fac ceva