Archive for the ‘Flash+ActionScript’ Category

Write JAVA, publish SWF

Sunday, February 15th, 2009

Ted Patrick (Senior Manager Developer Communities at Adobe Systems) has posted an interesting article about the first milestone of the Eclipse E4 project.

It seems that the SWT project has added compilation support for SWF from JAVA. Write your app in JAVA and publish as SWF to Flash Player. The cool part is that you get full JAVA development in Eclipse with all debugging and tooling but you get a SWF file on publish. 

We’re using Flex Builder for our Flex/AS3 stuff, but this could become a very interesting option since the JAVA development in Eclipse is a lot more sophisticated than Flex Builder at the moment.

FITC Amsterdam 2009

Saturday, January 24th, 2009

FITC Amsterdam 2009

On February 22-24th the Flash In The Can event is back in town! Design, Technology. Cool shit. I will be just a visitor, but Tim is going to help Ralph with his workshop Papervision3D from the Core. If you want to meet up, give us a ping.

Papervision3D forum

Tuesday, January 20th, 2009

On request of many: Papervision3D now has a forum : http://forum.papervision3d.org/

Read more at the Papervision3D blog.

Papervision3D wins Innovation Of The Year award

Tuesday, December 9th, 2008

Papervision3D has won the INNOVATION OF THE YEAR in this year’s .net Awards!
Other nominees included Google Android and App Engine, Microsoft Telescope, Open Social and Silverlight 2. I’m very proud to be part of the Papervision3D team!

dotnet innovation award 2008

Read more on the Papervision3D blog.

Alchemy – first looks

Sunday, November 23rd, 2008

Adobe has recently released a preview version of Alchemy. From their site:

Welcome the preview release of codename “Alchemy.” Alchemy is a research project that allows users to compile C and C++ code that is targeted to run on the open source ActionScript Virtual Machine (AVM2). The purpose of this preview is to assess the level of community interest in reusing existing C and C++ libraries in Web applications that run on Adobe® Flash® Player and Adobe AIR®.

So, what does this mean? This means that we can use existing C/C++ code and compile that down to AS3. Initially I though that this implied a hefty increase in code execution speed, but as all is compiled down to AS3 this is not true in most cases. Code will only run faster if you ’stay’ on the C-side and only return to ‘AS3′ when your C code is done processing. The reason is that AS3 method-calls are sloooow (params need to be ‘unboxed’ etc.)! When in C this slowness doesn’t occur and hence execution speed will be faster (Adobe claims a potential speed increase by a factor 2 to 10 I beleive). Wow! That of course made me wonder whether Alchemy would be usefull for 3D engines like Papervision3D, more soon! :-)

Branden Hall did a nice writeup on Alchemy explaining above better then me.

I couldn’t resist myself and started off immediately with something I always wanted to code for our 3D engine: Polygon Triangulation with support for holes.

I installed the Alchemy Toolkit, got the Flex 3.2 SDK and got some C code from the Department of Computer Science, UNC Chapel Hill.

Setting up the toolkit was bit tricky, but with help from this page I finally succeeded to get my environment right (OSX). Then I hit ‘make’ and presto! Got my swc! Download the swc and sample code or view a live example.

Some notes on swc usage:
1] ‘outer’ polygons must be defined anti-clockwise
2] ‘inner’ polygons (holes) must be defined clock-wise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// import
import cmodule.triangulation.CLibInit;
 
// initialize
var loader:CLibInit = new CLibInit;
var lib:Object = loader.init();
 
// @vertices is an array of XY-pairs: [ [], [x0, y0], [x1, y1], ...]
//                NOTE: @vertices[0] should always be [] 
// @contours is an array containing the number of points of each polygon
//                => [4, 3, 3, 3] indicates 4 polygons with the first poly having 4 points, the second 3, etc.
// @ncontours is the number of polygons (in our example: 4)
//
// @return An array of indices into the vertices array in form: [ [p0, p1, p2], [p0, p1, p2], ...]
var indices : Array = lib.triangulate( vertices, contours, ncontours );

Here’s the relevant C code which was simply added to tri.c :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
static AS3_Val triangulate(void* self, AS3_Val args)
{
	int ncontours = 0;
	int ccount;
	int npoints, first, last, n, nmonpoly;
	register int i;
	int op[SEGSIZE][3], ntriangles;
	AS3_Val dataVal;
	AS3_Val contourVal;
	AS3_Val retVal;
	AS3_Val temp;
 
	/* initialze the AS3 values */
	dataVal = AS3_Undefined();
	contourVal = AS3_Undefined();
	retVal = AS3_Undefined();
	temp = AS3_Undefined();
 
	//parse the arguments.
	AS3_ArrayValue( args, "AS3ValType, AS3ValType, IntType", &dataVal, &contourVal, &ncontours );
 
	//if no argument is specified
	if(dataVal == NULL || contourVal == NULL || ncontours <= 0)
	{
		AS3_Trace( AS3_String("Invalid input data!") );
		return AS3_Null();
	}
 
	ccount = 0;
	i = 1;
 
	while (ccount < ncontours)
   	{
		int j;
		int k;
		//fscanf(infile, "%d", &npoints);
 
		npoints = AS3_IntValue( AS3_Get(contourVal, AS3_Int(ccount)) );
 
		first = i;
		last = first + npoints - 1;
		for (j = 0, k = 1; j < npoints; j++, i++, k += 2)
		{
			//fscanf(infile, "%lf%lf", &seg[i].v0.x, &seg[i].v0.y);
			temp = AS3_Get(dataVal, AS3_Int(i) );
 
			seg[i].v0.x = AS3_NumberValue( AS3_Get(temp, AS3_Int(0)) );
			seg[i].v0.y = AS3_NumberValue( AS3_Get(temp, AS3_Int(1)) );
 
			if (i == last)
			{
				seg[i].next = first;
				seg[i].prev = i-1;
				seg[i-1].v1 = seg[i].v0;
			}
			else if (i == first)
			{
				seg[i].next = i+1;
				seg[i].prev = last;
				seg[last].v1 = seg[i].v0;
			}
			else
			{
				seg[i].prev = i-1;
				seg[i].next = i+1;
				seg[i-1].v1 = seg[i].v0;
			}
 
			seg[i].is_inserted = FALSE;
		}
 
		ccount++;
	}
 
	n = i - 1;
	initialise(n);
	construct_trapezoids(n);
	nmonpoly = monotonate_trapezoids(n);
	ntriangles = triangulate_monotone_polygons(n, nmonpoly, op);
 
	retVal = AS3_Array("AS3ValType", NULL);
 
	for (i = 0; i < ntriangles; i++)
   	{
		AS3_Val data = AS3_Array("IntType, IntType, IntType", op[i][0], op[i][1], op[i][2] );
 
		AS3_Set(retVal, AS3_Int(i), data);
	}
 
	return retVal;
}
 
//entry point for code
int main()
{
	//define the methods exposed to ActionScript
	//typed as an ActionScript Function instance
	AS3_Val echoMethod = AS3_Function( NULL, echo );
	AS3_Val triMethod = AS3_Function( NULL, triangulate );
 
	// construct an object that holds references to the functions
	AS3_Val result = AS3_Object( "echo: AS3ValType", echoMethod );
	AS3_SetS(result, "triangulate", triMethod);
 
	// Release
	AS3_Release( echoMethod );
	AS3_Release( triMethod );
 
	// notify that we initialized -- THIS DOES NOT RETURN!
	AS3_LibInit( result );
 
	// should never get here!
	return 0;
}

Drag’n'drop from HTML to Flash

Thursday, November 6th, 2008

Last week we released a new Floorplanner account, the Enterprise account. With it, companies can have an online Floorplanner solution completely branded to their wishes. It includes the Roomplanner module and a custom library of their own furniture elements.  Steelcase and Maxon are the first to have an active Enterprise account.

The interesting part of this release, from a tech point of view, is the new drag-and-drop functionality. The Roomplanner is running in the Flash Player. However, the library of furniture elements is in HTML. We chose to build the furniture library in the HTML sidebar for a couple of reasons. It’s not in the Roomplanner, so there is more space left to design. It gives us more freedom in the page layout. All items on the page are indexed and things like sorting and tags we’re easier to build in Ruby on Rails than in Flash.

Now we only needed a way to get the furniture from the sidebar to the Roomplanner. That’s where the drag’n'drop comes in, drag from HTML and drop in Flash. To drag an image of a furniture element in HTML we used the fantastic JavaScript script.aculo.us framework. The next step was to swap the image to an element in the Roomplanner and to update the position of the element while moving the cursor on the Flash content. For this we used ExternalInterface to communicate between JavaScript and ActionScript. That’s all there is to it. The theory is actually quite simple, but in practice it was very (I repeat, VERY) difficult to get it working in all the main browsers. All those nitty gritty browser details…

At this moment everything seems to work just fine, so please take a look at Steelcase and/or Maxon and let me know what you think!

Printing & Big Bitmaps

Wednesday, October 22nd, 2008

Last week I started working on a new version of the print functionality in Floorplanner. The problem with the previous version was that it didn’t print shadows, it was impossible to rotate the plan to landscape and textures didn’t look very well. Overall it produced a very mediocre image compared to the visual quality of a plan on the screen. As can be seen below:

Old print output

Old print output

For printing we use the AS2 PrintJob class, which works really easy, with a small disadvantage: it doesn’t print Floorplans properly. I tried all kinds of settings for this class, with as input just a MovieClip with a drawing of the plan on it. I tried setting the printAsBitmap to true and false, both giving the exact same result. So although being stuck with it, the printAsBitmap boolean inspired me to investigate the Bitmap thing. We already had an image export utility, which produces images of a Floorplan with the same quality as it is shown in the FlashPlayer. The funny thing is that when I printed this exported image, the print quality was really good, at least a lot better than our own printing functionality. So for some reason, even if I used the printAsBitmap functionality, it still didn’t produce the same quality as using a real bitmap.
Of course we could have stopped here and just tell the users of Floorplanner to print the exported image. But since we are Floorplanner, we didn’t want to introduce another step requiring user action in the printing process, after all, we are the “easiest way” :-) .
So I decided to use the same BitmapData created for the image export as basis for the printing. The first results where rather disappointing, I attached the created BitmapData to a MovieClip which in turn was given to the PrintJob. The produced print was of really low quality, you could easily see pixels all over the place. I tried using more pixels but now I bumped into the pixel limit of BitmapData (2880×2880 pixels). To work around this I invented the BigBitmapData class, this is a wrapper class that mimics the functionality of the BitmapData class, but which doesn’t have an upper limit of the number of pixels which can be used. When an instance of BitBitmapData is created which is bigger than 2880 by 2880, it creates additional BitmapDatas to store the additional pixels needed. So in fact the BigBitmapData internally stores an two dimensional array of BitmapDatas to bypass the pixel limit.
So with this new class I was able to scale up the created image to unprecedented sizes. I did a lot of printing experiments with scaling of the input, I tried scaling settings from 2 times to more than 10 times! This huge bitmap was attached to a MovieClip which in turn had to be scaled to fit on one single page of the printer. These values did give a better result, but still not good enough. It turned out that I had to take the DPI of the printer into account. The optimal scale factor turned out to be (1 / 72) * 300. The 72 is the DPI of the screen, and the 300 is the DPI of the printer. Furthermore a ‘point’ (print unit of measurement) is 1/72 inch, while the size of a pixel (screen unit of measurement) is dependent on the resolution of the screen.
So what this method actually does is creating a big image (which is resized to the paper contents) with enough quality to be printable on a 300 DPI printer.

New print output

New print output

So as you can see in the second image above, the new print looks a lot better, and since the new print uses bitmaps it is really easy to rotate it to always produce a print that tries to fill the entire paper.

A disadvantage of this method is that it takes quite some computational power to compute all the pixels for the bitmap that is created in memory, so as a result the FlashPlayer and sometimes even the browser freezes for a moment. Although this isn’t very good, we thought this behavior is acceptable since the quality of the prints is much better than the previous ones and the freeze time is actually really short. If you are not convinced by the images (which is understandable since the quality difference can only be seen on paper), just check it out!

New cross domain findings

Friday, September 12th, 2008

Today I learned a couple of new things about the use (and trouble) of BitmapData in combination with loading content from other domains. I thought we solved it a while ago, but it in some situations it didn’t work… I definitely hope this is my last post about the subject!

When you load content from another domain and you want to use BitmapData, then you always have to load a policy file (crossdomain.xml) from that other domain. What I discovered today is that you have to do this for ALL the content you’re loading, otherwise the BitmapData just doesn’t work. Even if it’s content you don’t want to use for the BitmapData, you still need to load the policy file. It took me quite a while of debugging to figure this out.

This is our current setup. Every server has its own domain.

The other thing I learned today is a small trick to remove the Warning in your logs. Jeffry Houser explains it in his post Fixing your CrossDomain.xml File.

JSON parser for ActionScript2

Thursday, May 29th, 2008

It took us some time, but now we see the virtues of JSON. We’re moving from XML to JSON to communicate with the outside world. The Floorplanner 2D app is (still) AS2 and I’m very happy to see that 5etdemi created a nice JSON parser in AS2.

Saves me a lot of work, thanks!

BitmapData.draw(..) cross domains

Monday, May 26th, 2008

Since recently we create a thumbnail image of every Floorplanner plan that is saved. To create a 240×180px image we use the BitmapData class (AS2) to get the pixel info and we send it to our server to create the PNG/JPG.

It can happen that the content (images, swf’s) has to be loaded from a different server then the server that holds the HTML page with the Flash app. We noticed that the Flash Security Sandbox doesn’t like that (surprise!) by not allowing us to use the BitmapData.draw(..) method.

Abdul found a solution for AS3 and we ported it to AS2. We only needed a way to load the crossdomain.xml file from the domain of the HTML page. This sniplet uses Javascript to determine the domain and loads the policy file (crossdomain.xml) from it.

1
2
3
4
5
var url:String =  String( ExternalInterface.call(
    "function(){ return document.location.href.toString();}"
));
var split:Array = lCurrentUrl.split( "/" );
System.security.loadPolicyFile( "http://"+ split[2] +"/crossdomain.xml" );