Techblog

Tech Blog

Our latest geek adventures!

Posts Tagged ‘alchemy flash as3 swc triangulation’

23 November Alchemy – first looks

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;
}

14 Comments - Tags: