Tube Experiment

After I finished my previous experiment with the Web Audio API I was looking for something else to do with sound. I had this idea of using London Underground’s data and playing a note every time a train left a station. I could assign a different note for each line and the live feed would create random music all day long. So I started checking TfL Developers’ Area and it didn’t take long to realize that my idea wouldn’t be possible. The data does show predicted arrival times for each station, but these are rounded to 30 seconds. If the experiment were to use the data literally, it would stay silent for 30s, then play a bunch of notes at the same time, then go back to silence for another 30s. A friend even suggested randomizing some values in between those 30s, but that wouldn’t be any different from just listening to some random notes chosen by the computer, without any connection to the tube.

OK, that idea was gone, but the data was quite interesting. With the rounded times I could tween the position of the trains between stations. It would be cool to see the trains moving in ‘almost’ real time on the screen, wouldn’t it? Oh wait, someone did it already: Live map of London Underground, by Matthew Somerville. And it is nice, but not really what I had in mind. I wanted more of a cool visualization based on the tube data, rather than an informative/useful map. How could I do something new with this data? Add a third dimension maybe? Three.js was on my list of things to experiment with for a long time and this seemed like the right opportunity. Oh wait, has someone done it already? The only thing I could find was this and it is definitely not what I had in mind. So yeah, green light!

Tube Experiment

To do a 3D map of the tube I would need x,y,z values. It is amazing what we can find on the internet, it’s all there. Depth of tube lines and London Underground Station Locations.

I had everything I needed: train times, latitude, longitude and depth of the stations. Those were coming from many different files, so I stretched my regex skills and created a simple tool with Adobe AIR to parse everything and output a consolidated .json for me. With that I could finally plot some points in space using the Mercator projection. The next step was to create tubes connecting these points and again I was really lucky to find exactly what I needed online. Three.js is an amazing library not only because of what it does, but also because of how it is made. Together with the classes I needed (TubeGeometry and SplineCurve3), I also found the conversation between the authors while they were developing these classes.

One of the biggest challenges was to make the trains follow the spline and sometimes change splines depending on the train’s destination. I feel that my algorithm could be more solid here, but it is working well. The last touches were to add the labels for each station and add some ambient sound recorded at the tube.

Tube Experiment

That’s it. I hope people find it interesting and play with it.

Launch the experiment.


If you ever need to export a file from Flash IDE using MinimalComps and/or WCK, you might run into the same issues I did today. Took me quite some time to find a solution, so hopefully this can be a time saver for someone.

MinimalComps in Flash CS5
- get MinimalComps
- Flash IDE > Publish > Profile > ActionScript Settings > Library Path > Add New Path
- browse to MinimalComps_[version].swc

Now in the first frame, type something like:

import com.bit101.components.PushButton;
var pushButton:PushButton = new PushButton(this, 10, 10, "PUSH ME");

When you compile, you should get these errors:

VerifyError: Error #1014: Class mx.core::FontAsset could not be found.
ReferenceError: Error #1065: Variable Component_Ronda is not defined.

A good hint to fix this can be found on the comments of minimalcomps Issue 141, where Keith Peters says flex.swc must be added to the library as well. Unfortunately it didn’t work for me, probably due to different SDK versions. So if you’re using Flex SDK 4.1 or Flex 4.5, what you need to add is framework.swc.

[path to sdk]\frameworks\libs\framework.swc

 

WCK in Flash CS5 – new World()
- get WCK
- Flash IDE > Publish > Profile > ActionScript Settings > Library Path > Add New Path
- browse to Box2D.swc

On the first frame, type:

import wck.World;
var world:World = new World();

When you compile, you should get this error:

1136: Incorrect number of arguments. Expected 2.

If you open World.as you’ll notice that there is no constructor, so it can’t be missing 2 arguments. Even if you delete the wck.World import line, the error message is the same. Where is this World class coming from? I’ll let Fumio Nonaka from JActionScripters answer:

According to […] the blog article “Flash CS5 Built-in Physics Discovered“, the class World is a part of physics engine in the inverse Inverse Kinematics framework. And once the API was planned to release with the “Physics” panel but was abandoned by Adobe.

This abandoned Physics library is in the PffLib.swc file which is referenced by default in your .fla: $(AppConfig)/ActionScript 3.0/libs. Just add flash.swc to the end of that line.

$(AppConfig)/ActionScript 3.0/libs/flash.swc

That’s it.


In my previous post I talked about my attempts on Processing + Typography, but I didn’t post any interactive example. Not because I didn’t want to, but because my sketch is using the OPENGL renderer and it is tricky to publish applets with it. Last night I received a notification about a reply to a post at the processing forum with some instructions to do just that. Now the applet is published.

Works fine for me. I asked a few friends to test it and it didn’t work for everyone. If it will work for you or not depends on platform and JRE version – and probably the lunar phase and many other things. Please give it try. Source code is also available.

Launch the sketch.


Variations made with the ‘visual’ sketch.


When I first got my hands on the Form + Code book what impressed me the most was the artwork with typography on the titles and opening pages. It reminded me how much I like typography and how focusing on the shape of letters and text can produce beautiful visuals. Then of course it got me trying to reproduce those visuals using Processing. There is no code in the book to help with that. All we get are some short descriptions at the bottom of each title page, like this one:

Form+Code page 9

That is a good hint. I knew I had to start with Python, which didn’t take long to lead me to TTX. It is a great piece of software that describes TrueType and OpenType fonts in an XML-based format. XML is much easier to read than bytecode and I guess the authors of Form+Code used TTX at some point. But having the fonts described in a text format is not enough, it is necessary to write Processing software to parse all that and create the points and curves and shapes. TTX to Processing: that would be an interesting library. Before I started to write one myself (like it would be easy), I went on a search for other contributed libraries to handle typography.

Which lead me to Geomerative. A fantastic library to work with TrueType fonts and SVG shapes in Processing. I was very happy when I found it. It was not Python or Postscript, but it would let me achieve similar visuals in a much quicker way.

Form+Code page 26
similar visuals made with geomerative

 
Form+Code page 42
similar visuals made with geomerative

 
Form+Code page 92
similar visuals made with geomerative

 
Why it doesn’t look the same
I’ve put some effort to copy the exact look of the titles in the book, but it still looks different. Why?
It all comes down to the differences between TrueType and Postscript.

The external contours are drawn in opposite directions, counter-clockwise on Postscript and clockwise on TrueType. This also affects the starting points of each glyph: Postscript starts where TrueType ends and vice-versa. This difference becomes evident on the “Computers” example.

Postscript vs TrueType: start point and direction

There is also a big difference in the way curves are drawn in the two formats. Postscript use cubic Bézier splines while TrueType uses quadratic Bézier splines. Which means TrueType needs more anchor points than Postscript to draw similar curves. The difference becomes evident on the “Working” example.

Postscript vs TrueType: curves

 
Geomerative and OpenType
The OpenType file format can describe both TrueType and Postscript outlines. Is it possible to use OpenType fonts (Postscript flavored) with Geomerative? No. At least not with the current version (rev 34). Geomerative uses a Java library called Batik to parse the TrueType format and convert it to SVG instructions. The Batik library (release 1.7) ignores the CFF table used to describe Postscript outlines. I searched for updates to the Batik library to see if there are plans to support CFF, but it doesn’t look like that is going to happen.

One interesting thing I found was that the Adobe Flex SDK also uses Batik to handle TrueType fonts. Actually, there are four font managers: Batik and JRE to manage TrueType and AFE and CFF to manage TrueType and OpenType.

This post is coming to an end but there aren’t many conclusions to make. Except that, as I read somewhere, OpenType file format is a hard nut to crack. The next steps could be: find a parser for the CFF table and adapt it to Geomerative; or write a parser for the TTX format as I mentioned at the beginning; or accept the formats differences and focus on the visuals of the other titles in Form+Code book. For now, I’ll probably go for the latest option. I’m enjoying the ride and I hope I can post some updates here soon.


My first PlayBook app is now available for free on BlackBerry App World.

flag.in – A quiz about flags, countries and capitals

The idea to make it started when I became addicted to a flag quiz game on my Android phone. It was quite fun to play, but it was too ugly and I thought it was missing some features. So why not build one myself? I went on with the concept, a few sketches and I got myself an Android development book. The progress was very slow because I was learning the language while building it.

Then I attended to Flash Camp Brasil 2011. RIM was there showcasing their new tablet and people got pretty excited about it. Since it is possible to build native apps for the PlayBook using AIR, why not put my ‘flags quiz’ project on track and build it with ActionScript? I started the development as soon as I got back home.

I had a good time working on it. The only differences from a desktop AIR project are the setup (downloading the SDK, installing the simulator, etc) and working with the QNX components. I have already talked about these two topics here.

flag.in screensflag.in game types: country » capital and flag » country

For future updates I think about adding sound, a horizontal layout, statistics, etc. But I am more interested in what people have to say about it. So go get flag.in and make sure you leave your review and comments. Cheers!

Big Thank You:
- to my beautiful girlfriend Pri, for helping me with the countries info;
- to my friend Toninho, for design tips and early logo designs;
- and to Cássio, for testing the app on a real device.


The native set of components for the BlackBerry PlayBook look very nice, but there are times when a custom design is needed. It is possible to skin the UI components and there is a good source of information and code at the BlackBerry site: Skinning your UI components. However, it only covers a few scenarios. There are many needs one might find while trying to apply a custom skin without finding clear instructions for them. I ran into a few when I was building my first application and I would like to share a few tricks and workarounds here.

TextInput
Problem: Font sizes bigger than 20 get cut.

package 
{
	import flash.display.Sprite;
	import flash.text.TextFormat;
	import qnx.ui.text.TextInput;
 
	public class Main extends Sprite 
	{
		public function Main():void 
		{
			var textInput:TextInput;
 
			textInput = new TextInput();
			textInput.setPosition(100, 100);
			textInput.setSize(280, 60);
			textInput.format = new TextFormat("Arial", 30, 0x666666, true);
			addChild(textInput);
		}
	}
}

Fix:

  1. Create a class that extends TextInput
  2. Override protected method getTextRect()
  3. Set rect.height = text input height


package  
{
	import flash.geom.Rectangle;
	import qnx.ui.text.TextInput;
 
	public class MyTextInput extends TextInput 
	{
		public function MyTextInput() 
		{
 
		}
 
		override protected function getTextRect():Rectangle
		{
			var rect:Rectangle;
			rect = super.getTextRect();
			rect.height = height;
			return rect;
		}
	}
}

LabelButton
Problem: There is no access to the label’s TextField. Using the public API you can set the text format and you can set the label. That’s it. If you want to change any other properties of the textField (ie. access textField.y to move it up a bit) you need a workaround.

Fix:

  1. Create a class that extends LabelButton
  2. Override protected method init()
  3. Loop between all children until a TextField is found and store it


package  
{
	import flash.text.TextField;
	import qnx.ui.buttons.LabelButton;
 
	public class MyLabelButton extends LabelButton 
	{
		private var _textField:TextField;
 
		public function MyLabelButton() 
		{
 
		}
 
		override protected function init():void
		{
			super.init();
 
			for (var i:int = 0; i < numChildren; i++) 
			{
				if (getChildAt(i) is TextField)
				{
					_textField = getChildAt(i) as TextField;
					break;
				}
			}
		}
 
		override protected function drawLabel():void
		{
			super.drawLabel();
 
			// move textField up
			if (_textField) _textField.y -= 3;
		}
	}
}

TextInputClearIcon
Problem: There is no direct access to the “x” clear icon in the TextInput component. If you want to change any of its properties (ie. move it 10 pixels to the left) you need to…

Fix:

  1. Create a class that extends SkinAssets_TextInputClearIcon
  2. Change the properties you need in the constructor of the new class
  3. Set SkinAssets.TextInputClearIcon = MyTextInputClearIcon; (your new class)
    This can be set anywhere in your code. My choice was to put it right at the beginning of my Main class, before UI components are created.


package  
{
	import qnx.ui.skins.SkinAssets_TextInputClearIcon;
 
	public class MyTextInputClearIcon extends SkinAssets_TextInputClearIcon 
	{
		public function MyTextInputClearIcon() 
		{
			move(-10, 1);
		}
 
	}
}

ScaleBitmap
Problem: Bitmap skins don’t scale nicely.

Fix:

  1. Use ScaleBitmap by ByteArray.org

package  
{
	import flash.display.DisplayObject;
	import flash.geom.Rectangle;
	import org.bytearray.display.ScaleBitmap;
	import qnx.ui.skins.SkinStates;
	import qnx.ui.skins.UISkin;
 
	public class MyTextInputSkin extends UISkin 
	{
		private var _up:DisplayObject;
		private var _gridRect:Rectangle;
 
		public function MyTextInputSkin() 
		{
 
		}
 
		override protected function initializeStates():void
		{
			_gridRect = new Rectangle(10, 10, 30, 30);
 
			_up = new ScaleBitmap(new SomeBitmapSkinInMyLibrary());
			_up.scale9Grid = _gridRect;
			setSkinState(SkinStates.UP, _up);
 
			showSkin(_up);
		}
	}
}

 

LINKS
Example Files

 


I have just started developing for the BlackBerry PlayBook tablet using AIR and I’ve already found something that I think is useful to share. First thing I had to do was to setup FlashDevelop to compile, package and install the app in the PlayBook Simulator. Why FlashDevelop? Because it is awesome. If you’re using Flash Builder, there is is plenty of information about compiling and testing an application on this page BlackBerry – Getting Started Guide. But if you’re using FlashDevelop or a different editor, there is not much info out there. So here we go.

To start developing for the PlayBook, we’ll need to download some files:

  1. Download AIR SDK (2.5 or bigger)
  2. Download BlackBerry Tablet OS SDK for AIR for Windows (1.0.1)
  3. Download VMware (required to run the BlackBerry PlayBook Simulator)

The PlayBook Simulator is packaged with the SDK, but you want to download it separately for some reason, here is the link: Download the BlackBerry PlayBook Simulator for Windows.

 

It does take a while to download and install all these, but it is all quite straightforward.
Below I’ll comment on some key steps:

 

- When you launch BlackBerryTabletSDK-Air-Installer just select No on the Flash Builder Integration step.

 

- After you install the VMware Player, click Open a Virtual Machine.

 

- Browse to the blackberry-tablet-sdk folder, then to BlackBerryPlayBookSimulator folder and select BlackBerryPlayBookSimulator.vmx

 

- Double click BlackBerry PlayBook Simulator on the left, wait for it to load, type in the password (playbook) and you should see something like this:

 

- Click on the little man icon on at the top, make sure Development Mode is ON and remember the IP Address to target this device later.

 

Great. Now let’s go to FlashDevelop.

- Create a new project. Project > New Project…
- Select AIR AS3 Projector.
- Name it PlayBook and hit OK.

 

- Click Project > Properties…
- Select the Compiler Options tab.
- Select Custom Path to Flex SDK and browse to the blackberry-tablet-sdk folder.

 

- In this example, we are going to use one of the PlayBook UI components, so it is necessary to add a SWC library to our project before we start coding. Browse to the blackberry-tablet-sdk folder then go to frameworks\libs\qnx-screen. Copy qnx-screen.swc and paste it into the project’s lib folder. Right-click and Add To Library.

 

- This is the code for the Main.as:

package 
{
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import qnx.ui.buttons.LabelButton;
 
	[SWF(width="1024", height="600", backgroundColor="#cccccc", frameRate="30")]
	public class Main extends Sprite 
	{
 
		public function Main():void 
		{
			var helloButton:LabelButton = new LabelButton();
			helloButton.label = "Hello World!";
			helloButton.x = (stage.stageWidth - helloButton.width)/2;
			helloButton.y = (stage.stageHeight - helloButton.height) / 2;
			helloButton.addEventListener(MouseEvent.CLICK, closeWindow);
			addChild(helloButton);
 
			stage.nativeWindow.visible = true;
		}
 
		private function closeWindow(event:MouseEvent):void{
			stage.nativeWindow.close();
		}
	}
}

 

If you compile and run the project, you should see an AIR window with a nice “Hello World!” button in the center. Now it is time to see it running inside the PlayBook Simulator. Flash Builder has a graphic interface for this step, but in FlashDevelop we have to use the command line.

- Click Project > Properties…
- Select the Build tab.
- In the Post-Build Command Line box, click Builder…
- Inside the Command Line Builder, according to the instructions on this page Package and deploy your application using the command line we should type in:

blackberry-airpackager -package output_bar_file_name -installApp
-launchApp project_name-app.xml project_name.swf any_other_project_files -device IP_address -password password

Adapted for this example it should look like this:

$(CompilerPath)\bin\blackberry-airpackager.bat -package PlayBook.bar -installApp -launchApp $(ProjectDir)\application.xml $(OutputDir)\PlayBook.swf -device 192.168.47.128 -password playbook

 

- If you try to run that, you’ll probably see the following error message in the output window:

Error: Cannot find node: versionNumber

The AIR AS3 Project template is a bit outdated, so we need to edit the application.xml
In the <application> node at the top, the xmlns attribute needs to end with 2.5:

<application xmlns="http://ns.adobe.com/air/application/2.5">

And the <version> node needs to be updated to <versionNumber>:

<versionNumber>1.0.0</versionNumber>

 

Now you’re good to go. Open the PlayBook Simulator in the VMPlayer, then hit F8 or Ctrl+Enter to compile the project, wait for it to finish and check the simulator window. You should be able to see a new PlayBook application with the default icon there. Now try to open it. Crashed instantly? Yes, happened to me. And took me a while to understand what was wrong.

The problem is that the project’s files are not all in one folder. The AIR AS3 Project template puts the application.xml in the root folder and the .swf in the bin folder and the blackberry-airpackager doesn’t like that. We need to put all files in the same folder.

If you choose to put all the files in the project’s root folder, go back to the Command Line Builder and type this:

$(CompilerPath)\bin\blackberry-airpackager.bat -package PlayBook.bar -installApp -launchApp application.xml PlayBook.swf -device 192.168.47.128 -password playbook

If you prefer to keep your files in the bin folder we need to add the $(OutputDir) paths AND add the packager option -C :

$(CompilerPath)\bin\blackberry-airpackager.bat -package $(OutputDir)\PlayBook.bar -C $(OutputDir) -installApp -launchApp $(OutputDir)\application.xml $(OutputDir)\PlayBook.swf -device 192.168.47.128 -password playbook

 

Compile the project and you should see it running nicely in the PlayBook Simulator.

 

And that’s it. Have fun developing for the BlackBerry PlayBook!

 

UPDATE: ANT
Ok, it doesn’t take long to realize you don’t want to deploy for the Simulator on every build. A good option is to create an ANT build file so you can decide which task to run. I have added the following files to the Example Files below:
build.xml (ANT build)
build.properties (user settings and project variables)
config.xml (project specific values)

Please make sure you edit both build.properties and config.xml to match your project.

If you’re new to ANT, it is very easy to get it running on FlashDevelop.
There is nice ANT panel plug-in called fd-ant-plugin

- Donwload AntPlugin-r9.zip.
- Extract the content to [ FlashDevelop path ]/Plugins/
- Restart FlashDevelop.
- A new tab called Ant should be available besides Outline | Bookmarks | Files | Project.
- From the Project tab, drag build.xml and drop it in the Ant tab.
- Double click any of the ANT tasks to run them.

 

LINKS
Example Files

ADITIONAL NOTE: GESTURES
Some useful gestures when testing with the PlayBook Simulator:

Minimize an application: drag up from the border at the bottom
Open settings: drag down from the border at the top
Close an application: when minimized, click the app thumb and drag up
Rotate the simulator: drag from the bottom-right corner to the center

 


In one my projects last year, I had to build something like this:

Forum Intro

It seems fairly simple, just a bunch of cubes, right? I just need to draw their outlines, some showing their back faces and some not. So I started with Papervision3D.

The thing is there is nothing like an ‘OutlineMaterial’ in Papervision. WireframeMaterial is pretty close, but I couldn’t find a way to draw just the face borders instead of drawing all the triangles. MovieMaterial with an outlined square shape could be an option, but the result doesn’t look any good:

In the Papervision3D documentation I found the class Line3D. This would probably give me a good looking result for the outlines. However I wouldn’t be building primitives anymore, as each line would have to be a separate object. Rotating the cubes and hiding their back faces could become a nightmare. So, Papervision3D is great, but it couldn’t help me in this particular need. Besides, it is quite a heavy library to add to a project for such a simple effect.

With Away3DLite I could only get the same wireframe triangles result. I thought Sandy3D could help me when I found their Outlines Demo, but the result is more like a ‘glow’ around the whole object instead of outlines for each face like I needed.

Then I tried Flash Player 10 native 3D. It is not as easy to create a cube as with the other 3D engines, but luckily Keith Peters taught me how to do it in his book AdvancED ActionScript 3.0 Animation. I just had to pass an outlined shape to all of the cube faces. The result is actually quite good:

Good, but not good enough. Depending on the angle of rotation, the outlines look a bit jerky. They vary according to their distance to the camera. What I wanted rotating and moving in three dimensions while keeping the outlines as sharp as they would look in a two dimension screen – like the ones we get when we use graphics.lineTo(x, y). So I needed to find the vertices 3D coordinates (x, y, z) and project them onto 2D coordinates (x, y). Hmm, this looks familiar. I am sure this can be done with 3D engines, but it can also be done without any engine.
The good and old scale = fl / (z + fl) can give just the right result in a lighter, faster and more fun way. This is the result:

 

To do that, I created a class called CubeOldSchool and this is what happens inside it:

  1. Create vertices.
  2. Create faces.
  3. Create rotation getters/setters.
  4. Render.
    • a. Append rotation to vertices.
    • b. Convert 3D vertices into 2D points.
    • c. Perform back face culling. [optional]
    • d. Draw lines.

 

1. Create vertices
A cube has eight vertices. If we say our cube will have width, height and depth of 100px, then our vertices should look like this:

var _vertex:Vector.<Vector3D> = new Vector.<Vector3D>(8, true);
 
_vertex[0] = (new Vector3D(-50, -50, -50));
_vertex[1] = (new Vector3D(50, -50, -50));
_vertex[2] = (new Vector3D(50, 50, -50));
_vertex[3] = (new Vector3D(-50, 50, -50));
_vertex[4] = (new Vector3D(-50, -50, 50));
_vertex[5] = (new Vector3D(50, -50, 50));
_vertex[6] = (new Vector3D(50, 50, 50));
_vertex[7] = (new Vector3D(-50, 50, 50));

If the project is targeting Flash Player 10, we can use Vector3D to represent a point in a three dimensional space. If project needs to run in an earlier Flash Player, then it is just a matter of creating a simple class with public x, y and z properties.

 

2. Create faces.
A cube has six faces. We need to define which vertices belong to each face and also in which order they should be drawn.

Cube vertices and faces

In the image above, every number is an index in the _vertex Vector. And every face is a collection of four indexes. To organize that in a readable way, let’s create a simple Face class:

class Face 
{
	public var index:Vector.<int> = new Vector.<int>(4, true);
 
	public function Face(i0:int, i1:int, i2:int, i3:int) 
	{
		index[0] = i0;
		index[1] = i1;
		index[2] = i2;
		index[3] = i3;
	}
}

Then create the six faces:

var _faces:Vector.<Face> = new Vector.<Face>();
 
_faces.push(new Face(1, 2, 6, 5));
_faces.push(new Face(2, 3, 7, 6));
_faces.push(new Face(3, 0, 4, 7));
_faces.push(new Face(0, 1, 5, 4));
_faces.push(new Face(0, 3, 2, 1));
_faces.push(new Face(5, 6, 7, 4));

The order of the indexes in all faces is important to perform the back face culling. In this example all faces are drawn counter-clockwise, although clockwise would work just the same. The important thing is to make sure all faces are drawn in the same direction.

 

3. Create rotation getters/setters.
When we say _cube.rotationX = 10; we want to rotate our vertices, not the whole Sprite. So we need to override the rotation properties and store their values.

override public function get rotationX():Number { return _rotationX; }
 
override public function set rotationX(value:Number):void
{
	_rotationX = value;
}
 
override public function get rotationY():Number { return _rotationY; }
 
override public function set rotationY(value:Number):void 
{
	_rotationY = value;
}
 
override public function get rotationZ():Number { return _rotationZ; }
 
override public function set rotationZ(value:Number):void 
{
	_rotationZ = value;
}

 

4. Render.
This is where we transform the coordinates and draw the outline. Render should be called on enter frame.

a. Append rotation to vertices.
All vertices need to be transformed according to the cube’s rotations on all three axes. To do this we need a 3D transformation matrix. Luckily Flash Player 10 has Matrix3D to make our lives easier. The code below resets the matrix3D, applies all rotations and stores all transformed vertices in a new vector.

var _matrix3D:Matrix3D = new Matrix3D();
var _points3D:Vector.<Vector3D> = new Vector.<Vector3D>();
 
_matrix3D.identity();
_matrix3D.appendRotation(_rotationY, Vector3D.Y_AXIS);
_matrix3D.appendRotation(_rotationX, Vector3D.X_AXIS);
_matrix3D.appendRotation(_rotationZ, Vector3D.Z_AXIS);
_points3D = new Vector.<Vector3D>();
 
for each (var vertex:Vector3D in _vertex) 
{
	_points3D.push(_matrix3D.transformVector(vertex));
}

If you need to target an earlier Flash Player or if you want to understand what happens in these matrix transformations, my friend André Anaya has a very detailed post about this in his blog.

 

b. Convert 3D vertices into 2D points.
Here is where the famous perspective formula scale = fl / (z + fl) kicks in. It needs to be applied to each vertex in each face and the result is a new Vector, this time storing 2D Point objects.

var vectors:Vector.<Vector3D> = new Vector.<Vector3D>();
var points:Vector.<Point> = new Vector.<Point>();
var scale:Number;
 
for each (var face:Face in _faces)
{
	for (i = 0; i < 4; i++) 
	{
		vectors[i] = _points3D[face.index[i]];
		scale = 500 / (vectors[i].z + 500);
		points[i] = new Point();
		points[i].x = vectors[i].x * scale; 
		points[i].y = vectors[i].y * scale; 
	}
}

 

c. Perform back face culling. [optional]
First time I read about how to do back face culling I was amazed about how smart and simple it is. Well, at least in this situation where we have a fixed camera. All we need to do is take the cross product of three points in each face. The result is the magnitude of the vector in the z-axis. If magnitude is positive we can tell the face is not facing the camera and skip drawing it. This works only if the orientation of the points in the faces is kept consistent (in this case, counter-clockwise).

Back face culling

if (( points[2].x - points[1].x ) * ( points[0].y - points[1].y ) -
    ( points[2].y - points[1].y ) * ( points[0].x - points[1].x ) > 0) continue;

 

d. Draw lines.
Finally, draw the outlines!

for (i = 0; i < 4; i++) 
{
	j = (i < 3) ? i + 1 : 0;
	graphics.moveTo(points[i].x, points[i].y);
	graphics.lineTo(points[j].x, points[j].y);
}

 

Now that we can control vertices and faces, why not try some crazy 3D objects like this one:

 

LINKS
Example Files
Forum (project using 3D outlines)

 


First time I saw the map() function was in the Processing language reference. So simple and so useful. And what does it do? From the Processing page:

– Re-maps a number from one range to another.

Best way to understand is with an example (always):

map(num, min1, max1, min2, max2)
 
map(20, 0, 100, 0, 400) // outputs 80

In other words, it gets a number (20), finds its percentage within the first range (0 – 100) which results to 0.2 and maps it to the second range (0 – 400) which results to 80. In this example it is the same as finding 20% of 400, which is easy enough, we don’t need a function for it.

Now another example:

map(1152, 1000, 1440, 130, 230) // outputs 164.54

That’s a bit harder to calculate. The percentage of 1152 within the range 1000 – 1440 is 0.3454… And that mapped to the range 130 – 230 results in 164.5454…
I’ve came to hundreds of situations where I need to map a value from one range to another. The most frequent one is to position or scale objects according to the stage size.

Let’s take a look at the previous example again:

map(1152, 1000, 1440, 130, 230)
 
num  = 1152 // current stageWidth
min1 = 1000 // minimum supported stage width
max1 = 1440 // maximum supported stage width
min2 = 130  // x position of an object in the minimum width layout
max2 = 230  // x position of an object in the maximum width layout

If the user is viewing your Flash in a small screen resolution and the stageWidth is 1000, object is positioned at x 130. If your user has a big screen and the stageWidth is 1440, object is repositioned to x 230. And every screen size in between will make object.x change proportionally.

Click the image below for an example of resize / reposition:

Resize Example

 

I guess the best place to put a map() function is in a MathUtils static class. That’s what I did. I have also added round, constrainMin and constrainMax parameters that are also very useful.

public static function map(num:Number, min1:Number, max1:Number, min2:Number, max2:Number, round:Boolean = false, constrainMin:Boolean = true, constrainMax:Boolean = true):Number
{
	if (constrainMin && num < min1) return min2;
	if (constrainMax && num > max1) return max2;
 
	var num1:Number = (num - min1) / (max1 - min1);
	var num2:Number = (num1 * (max2 - min2)) + min2;
	if (round) return Math.round(num2);
	return num2;
}

 

LINKS
Example
MathUtils.as

 


Say you need to flip an image. You don’t want a boring rotationY flip, you’d rather see it bending a little so it looks more like a paper flip. Something like this (click to flip):

 

 

How do you do that?

It is easy, thanks to AS3Dmod (created by Bartek Drodz) and its nice modifiers like Bend and Twist. Those modifiers work on 3D meshes, so you need to choose a 3D library to create your “paper” before you can twist it. AS3Dmod comes with proxies to work with 4 known 3D libraries: Papervision, Away3D, Sandy and Alternativa. I can’t say much about the last two, but Papervision and Away3D would add around 200k to your file, which might be a big cost for this simple effect. It is a better choice to use Away3DLite (if you can use Flash Player 10).

The thing is AS3Dmod does not come with a proxy to work with Away3DLite, but thanks to the nice structure of the library, we can easily write a new proxy. Here is what I came up with:

 

LibraryAway3dLite

public function LibraryAway3dLite() 
{
	var m:MeshProxy = new Away3dLiteMesh();
	var v:VertexProxy = new Away3dLiteVertex();
}

Away3dLiteVertex

private var vx:Vector3D;
 
override public function setVertex(vertex:*):void 
{
	vx = vertex as Vector3D;
	ox = vx.x;
	oy = vx.y;
	oz = vx.z;
}

Away3dLiteMesh

override public function setMesh(mesh:*):void 
{
	awm = mesh as Mesh;
 
	var lookUp : Dictionary = new Dictionary(true);
	var vs:Vector.<Number> = awm.vertices;
	var vc:int = vs.length;
	var ts:Vector.<Face> = awm.faces;
	var tc:int = ts.length;
 
	for (var i:int = 0; i < vc; i+=3) {
		var nv:Away3dLiteVertex = new Away3dLiteVertex();
		var vector:Vector3D = new Vector3D(vs[i], vs[i + 1], vs[i + 2]);
		nv.setVertex(vector);
		vertices.push(nv);
		lookUp[vector] = nv;
	}
 
	(...)
}
 
override public function postApply():void 
{
	var vs:Vector.<Number> = awm.vertices;
	var vc:int = vs.length;
 
	for (var i:int = 0; i < vc; i+=3) 
	{
		var vertex:Away3dLiteVertex = vertices[i / 3];
		vs[i] = vertex.x;
		vs[i + 1] = vertex.y;
		vs[i + 2] = vertex.z;
	}
}

Those are just the main parts of the code. You can download all the classes with the example files below. I’d like to make clear that I kept the package com.as3dmod.plugins because it seemed more logical and organized, but it is not originally a part of AS3Dmod, so you might want to add it to com.something-else.modifiers.plugins if you want to keep it pure.

I wrote an email to Bartek about this proxy, so maybe he’ll consider adding this to AS3Dmod.
That would be awesome! :-)

 

Ok, so your file lost some extra weight, but you still have to bend that image. You might want to start by creating 2 planes, 2 bitmap materials, 2 modifiers, 2 stacks, etc. I find it easier to create a cube and flatten it. I can ignore top, bottom, left and right faces and use it like a plane with some material in the front and another material in the back. I have tried both ways (planes and cube) and I couldn’t tell any difference between them, so it is up to you.

If you choose the cube version, there is one more thing to consider: Away3DLite doesn’t have a primitive called Cube. Instead, it has a simpler object called Cube6. You can only set one material for the cube, which means that if you set a bitmap material, you’ll see it wrapping around the whole cube.

 

 

Away3DLite maps your image in six equally sized areas and set each of them to one face of the cube. Once I found which one was the front and the back, it was done.

 

Away3DLite Cube6 map

 

To create the paper flip, you don’t need all those faces. So you can create an empty BitmapData 3 times wider and 2 times higher than the front face. This will be your cube material. Now you just need to draw the front and back faces in the correct position. Matrix tx and ty properties will handle that:

var faces:BitmapData;
var front:BitmapData;
var back:BitmapData;
var bmpMaterial:BitmapMaterial;
var matrix:Matrix;
 
bmpFront = new FrontFace(0, 0); // bitmap asset from the library
bmpBack = new BackFace(0, 0);  // bitmap asset from the library
 
faces= new BitmapData(front.width * 3, front.height * 2, false, 0xFFFFFFFF);
matrix = new Matrix(1, 0, 0, 1, 0, front.height);
faces.draw(front, matrix);
matrix = new Matrix(1, 0, 0, 1, back.width, 0);
faces.draw(back, matrix);
 
bmpMaterial	 = new BitmapMaterial(faces);

 

Now it’s all set for the flipping and bending effect. I first started with the Bend modifier, but it looks much better with Twist. The effect is a combination of rotationY and twist tweens. I am using GreenSock’s TweenLite.

TweenLite.to(_twist, .6, { angle:.6, ease:Quart.easeIn, onComplete:function():void
{
	TweenLite.to(_twist, .5, { angle:0, overwrite:0, ease:Quart.easeOut } );
} } );
TweenLite.to(_cube, 1.2, { rotationY:endRotationY, ease:Expo.easeInOut } );

 

You’ve seen the effect at the beginning of the post, but since I am dealing with a cube, why not add some depth? It looks nice too (click to flip):

 

FILES
Example and classes