Techblog

Tech Blog

Our latest geek adventures!

Archive for the ‘Flash+ActionScript’ Category

5 September Build ActionScript3 projects with TextMate in 5 easy steps

The text editor of choice of our Rails team is TextMate. Our Flash team is a bit divided between Eclipse+FDT and FlexBuilder. I wanted to see if TextMate is a good alternative for building Flash/ActionScript projects.

There are a couple of good sources on using TexMate for ActionScript projects, but it’s a little fragmented and sometimes outdated. I found pixelate’s blog post and Simon’s blog very useful.

1. TextMate

First of all, you need have MacroMates’ TexMate of course. If you don’t already own a copy, you can download a 30-day-trial.

2. ActionScript3 bundle

Simon Gregory did some fine work by creating a TextMate bundle for ActionScript3. The most important things that the bundle handles are auto-completion and auto-import. You can download it directly from his blog, or fetch it with Git or SVN.

To install via Subversion:

export LC_CTYPE=en_US.UTF-8
cd ~/"Library/Application Support/TextMate/Bundles/"
svn co http://svn.textmate.org/trunk/Review/Bundles/ActionScript\ 3.tmbundle
osascript -e 'tell app "TextMate" to reload bundles'

To install via Git:

cd ~/"Library/Application Support/TextMate/Bundles/"
git clone git://github.com/simongregory/actionscript3-tmbundle.git "ActionScript 3.tmbundle"
osascript -e 'tell app "TextMate" to reload bundles'

3. Flex SDK

The actual building of your project is done by the free Flex 3 SDK. Download it and move the extracted folder into your /Developer/SDKs/ folder. The SDK has to be accessible throughout your whole system. You can do this by adding it to the PATH variable in the /etc/profile file. Open terminal and type:

sudo mate /etc/profile

Then add the folder “/Developers/SDKs/flex_sdk_3/bin” to the file and save it. It should look something like this:

PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/mysql/bin:/Developer/SDKs/flex_sdk_3/bin"

4. TextMate settings

Before we can start the ActionScript fun we have to setup a few things in TextMate. Open TextMate and select File→New Project. Click on the info button located in the bottom of the Project Drawer. Add two shell variables so that the ActionScript Bundle knows where to look for your files:

TM_FLEX_FILE_SPECS    src/Main.as
TM_FLEX_OUTPUT        bin/Main.swf

We also need to let TextMate know where the Flex SDK is located. Go to TextMate→Preferences→Advanced→Shell Variables and add a new global variable:

TM_FLEX_PATH    Developer/SDKs/flex_sdk_3

5. Hello World

With all that out of the way, we can finally start working on a ActionScript project: Hello World. Create a folder on your system that will hold this project. Drag this folder to TextMate’s Project Drawer. Create two new folders named bin and src in your project folder. Then create a new file in the src folder and name it Main.as. It should look something like this:

package {        
    import flash.display.Sprite;
    import flash.text.TextField;
 
    [SWF( backgroundColor='0xFFFFFF', frameRate='30', width='200', height='200')]
 
    public class Main extends Sprite {
        private var textField: TextField;
 
        public function Main() {
            textField = new TextField();
            textField.text = "Hello World.";
 
            addChild(textField);
        }        
    }
}

Choose Bundles→ActionScript 3→Build to build your project. A terminal window pops up which runs the Flex SDK to build your project. You can find the resulting Main.swf file in your bin folder. Yay!

Notes

If you want to build Flash Player 10 specific stuff (like me) you have to let the Flex SDK know. Open /Developer/SDKs/flex_sdk_3/frameworks/flex-config.xml and set the target-player tag to 10.0.0

<target-player>10.0.0</target-player>

The easiest way to work with libraries, the so called SWC files, in this setup is to drop them directly into /Developer/SDKs/flex_sdk_3/frameworks/libs folder. That way the Flex SDK has no problem finding them.

2 Comments - Tags:

26 May Papervision3D 2.1 – alpha

Just committed rev. 911 to the Papervision3D SVN trunk. Rev. 911 and upwards will become Papervision3D 2.1 because the changes made are quite big.
Major changes where made to the DAE, MD2 and animation classes.

NOTE:
This revision is considerably different then previous revisions. Use with care!
At this point its not advised to use rev. 911 for production.

This revision fixes several issues regarding the DAE class:

  1. vertex-animation
  2. nested animations
  3. Cinema4D support
  4. morph-weight animation
  5. splines
  6. cloning
  7. play(), play(”clipName”), stop(), pause(), resume()
  8. more…

The whole org.papervision3d.core.animation.* package has been revamped completely to allow for the changes in the DAE class.

DAE Example:

var autoPlay : Boolean = false; // don't play animations automatically
 
var dae : DAE = new DAE( autoPlay, "myCollada" );
 
dae.addEventListener(FileLoadEvent.LOAD_COMPLETE, onDaeComplete);
dae.addEventListener(FileLoadEvent.LOAD_PROGRESS, onDaeLoadProgress);
 
// optionally pass materials to DAE
// NOTE: here's a change with previous revs :
// 1. lookup the <material> elements in the COLLADA file (inside <library_materials>).
// 2. write down / remember the @id attribute of the <material> element.
// 3. materials.addMaterial( myMaterial, materialElementID ).
// ==> this will probably change in future revs
var materials : MaterialsList = new MaterialsList();
 
// If textures fail to load optionally add some search-paths 
// (relative to the swf):
dae.addFileSearchPath( "images" );
dae.addFileSearchPath( "textures" );
 
// set to true if you get a script-timeout error
var asyncParsing : Boolean = false;
 
// load it!
dae.load( "/path/to/dae", materials, asyncParsing );
 
/**
 * The DAE has loaded completely
 */
private function onDaeComplete(event : FileLoadEvent) : void
{
     var dae : DAE = event.target as DAE;
 
     // add to scene
     scene.addChild( dae );
 
     // start playing animation (if any available)
     // other animation controls include :
     // 1. play( "clipName ")
     // 2. stop()
     // 3. pause()
     // 4. resume()
     // 5. playing (getter: bool indicating if playing)
     dae.play();
 
     // lets create a clone
     // NOTE: DAE#clone() is somewhat bugged still, 
     // but seems to work in most cases
     var clone : DAE = dae.clone() as DAE;
 
     // add clone to scene
     scene.addChild( clone );
 
     // move it a bit
     clone.x = 200;
}
 
private function onDaeLoadProgress(event : FileLoadEvent) : void
{
 
}

MD2 Example:

var md2 : MD2 = new MD2();
 
var material : MaterialObject3D = new WireframeMaterial();
 
md2.addEventListener(FileLoadEvent.LOAD_COMPLETE, onMD2Complete);
 
md2.load("/path/to/md2", material);
 
scene.addChild(md2);
 
private function onMD2Complete(event : FileLoadEvent) : void
{
       var md2 : MD2 = event.target as MD2;
 
       md2.play();
       // or play some clip :
       // md2.play( "run" )
}

Animation:

Click the image below to show an example of the new animation controls.
Animation Test
Download the source of this example here.

The DAE and MD2 class implement IAnimatable, IAnimationProvider and IControllerProvider, which can be found in the org.papervision3d.core.animation.* package.

As so much has changed I’m sure some bugs are introduced. Please let me know!

PS: I’ll be on vacation until june 8th, so its unlikely I’ll be able to fix any bugs before that time.
PS2: Many people have helped by submitting code-snips, reporting bugs etc. I’ll credit you all when I’m back :-)

38 Comments -

4 May Load, modify and save local images with Flash Player 10

One of the cool new things about Flash Player 10 is that you now have access to the local file system. This means that you can load, modify and save files directly on the client side without any server interaction. Mike Chambers wrote a post about reading and writing text files and I was wondering if it was possible to do this with image files too.
thumbr here

Publish Flash Player 10 content

To test this, I first needed a way to make my Flex Builder compile Flash Player 10 content. I found a rather old post by Andrei Ionescu about building Flash Player 10 applications that told me exactly what I was looking for. I downloaded the latest Flex SDK (3.3) from Adobe’s Flex Download page, followed the tutorial and I was ready to go.

Load image from local file system

Reading a local file was no biggie, just copied and pasted the code from Mike’s sample. What I needed now was a way to convert the loaded data into an image. As usual Tim helped me out by sending me a snippet:

var data:ByteArray = fileRef['data'];
var loader:Loader = new Loader();
loader.loadBytes(data);
addChild(loader);

Modify image

Now that I could load the image, I wanted to modify it before having it rendered. I extended the snippet to use BitmapData and a Matrix to resize the image to a thumb image (240×180px).

var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onDataLoadComplete);
loader.loadBytes(loadFileRef.data);
 
private function onDataLoadComplete(e:Event):void {
  var bitmapData:BitmapData = Bitmap(e.target.content).bitmapData;
  var matrix:Matrix = new Matrix();
  matrix.scale(THUMB_WIDTH/bitmapData.width, THUMB_HEIGHT/bitmapData.height);
 
  imageView.graphics.clear();
  imageView.graphics.beginBitmapFill(bitmapData, matrix, false);
  imageView.graphics.drawRect(0, 0, THUMB_WIDTH, THUMB_HEIGHT);
  imageView.graphics.endFill();
}

Save image to local file system

Now that it’s possible to load and modify an image, saving it is the last step. To save an image, it has to be encoded to a ByteArray. I used the open source as3corelib to help me out. Saving the ByteArray to a file is rather straight forward.

Update 1: You don’t need to use the as3corelib anymore, Flex 3.3 has it own JPEGEncoder.

var encoder:JPEGEncoder = new JPEGEncoder();
var rawBytes:ByteArray = encoder.encode(bitmapData);
 
var saveFileRef:FileReference = new FileReference();
saveFileRef.save(rawBytes);

Update 2: Thibault Imbert figured out a way to speed up JPEG encoding using the new FP10 Vector class. Good stuff!

Update 3: You can now also use Alchemy for the encoding. It’s much, much faster then the other options! See this post from Jens Krause: Speed up JPEG encoding using Alchemy

This sample shows that it’s not only possible to load, modify and save images directly from the local file system, but that it’s actually very simple to do so. Add some PixelBender image processing power to the game and you almost have a Photoshop killer running completly client side!

Code sample

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundGradientColors="[0xFFFFFF,0xFFFFFF]" backgroundColor="0xFFFFFF">
 
	<mx:Script>
		<![CDATA[
			import mx.graphics.codec.JPEGEncoder;
			import mx.binding.utils.BindingUtils;
			import mx.core.UIComponent;
 
			import flash.net.FileReference;
			import flash.net.FileFilter;
			import flash.events.IOErrorEvent;
			import flash.events.Event;
			import flash.utils.ByteArray;
 
			private var loadFileRef:FileReference;
 
			private static const FILE_TYPES:Array = [new FileFilter("Image Files", "*.jpg;*.jpeg;*.gif;*.png;*.JPG;*.JPEG;*.GIF;*.PNG")];
			private static const THUMB_WIDTH:uint = 240;
			private static const THUMB_HEIGHT:uint = 180;
 
			private function loadFile():void {
				loadFileRef = new FileReference();
				loadFileRef.addEventListener(Event.SELECT, onFileSelect);
				loadFileRef.browse();
			}
 
			private function saveFile():void {		
				var bitmapData:BitmapData = new BitmapData(THUMB_WIDTH, THUMB_HEIGHT);
				bitmapData.draw(imageView);
 
				var encoder:JPEGEncoder = new JPEGEncoder();
				var rawBytes:ByteArray = encoder.encode(bitmapData);
 
 				var saveFileRef:FileReference = new FileReference();
				saveFileRef.save(rawBytes);
			}
 
			private function onFileSelect(e:Event):void {
				loadFileRef.addEventListener(Event.COMPLETE, onFileLoadComplete);
				loadFileRef.load();
			}
 
			private function onFileLoadComplete(e:Event):void {
			   	var loader:Loader = new Loader();
			   	loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onDataLoadComplete);
			   	loader.loadBytes(loadFileRef.data);
 
				loadFileRef = null;
			}
 
			private function onDataLoadComplete(e:Event):void {
				var bitmapData:BitmapData = Bitmap(e.target.content).bitmapData;
 
                var matrix:Matrix = new Matrix();
                matrix.scale(THUMB_WIDTH/bitmapData.width, THUMB_HEIGHT/bitmapData.height);
 
				imageView.graphics.clear();
				imageView.graphics.beginBitmapFill(bitmapData, matrix, false); 
				imageView.graphics.drawRect(0, 0, THUMB_WIDTH, THUMB_HEIGHT);
				imageView.graphics.endFill(); 
 
				saveButton.enabled = true;
			}
 
		]]>
	</mx:Script>
	<mx:Panel title="Create thumb image" paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5">
		<mx:VBox>
			<mx:Canvas id="imageView" width="240" height="180" borderThickness="1" borderColor="#CCCCCC" borderStyle="solid"/>
			<mx:HBox paddingTop="5" borderThickness="1">
				<mx:Button label="Load image" click="loadFile()"/>
				<mx:Button label="Save image" click="saveFile()" id="saveButton" enabled="false"/>
			</mx:HBox>
		</mx:VBox>
	</mx:Panel>
</mx:Application>

11 Comments - Tags: , , , , , , ,

29 April Unproject with useProjectionMatrix = true

I just updated Papervision3D to allow the CameraObject3D#unproject method to work when CameraObject3D#useProjectionMatrix = true.

Papervision3D has two methods of ‘projecting’ vectors onto the screen:

  1. useProjectionMatrix = false, this is the default ‘fast’ method
  2. useProjectionMatrix = true, this is the method where projection is done by a matrix

Note that Papervision3D switches to method #2 in ‘ortho mode’.

So what is the difference exactly between these two kinds of projection? First we need to define what projection is. Projection is what adds ‘perspective’ to a scene and makes sure your scene fits to the viewport. Its the last step in the so-called ‘render pipeline’.

We can derive the ‘fore shortening’ effect of perspective in several ways. Method #1 is simple, effective and fast. It uses the camera’s focus and zoom values. Method #2 uses a more classic way of projection : it uses a dedicated matrix. Tech buffs: very much like OpenGL’s gluPerspective.

Andy Zupko has a great post on unproject using method #1.

We will discuss unproject using method #2, which works slightly different.

The difference is that when #useProjectionMatrix is set to true, then CameraObject3D#unproject returns a point in world-space, rather then a ray. Let me explain with some code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// we want to use a projection matrix
camera.useProjectionMatrix = true;
 
// '0' indicates we want a point on the near plane
var pointOnNearPlane : Number3D = camera.unproject( screenX, screenY, 0 );
 
// '1' indicates we want a point on the far plane
var pointOnFarPlane : Number3D = camera.unproject( screenX, screenY, 1 );
 
// Construct the ray's direction
var dir : Number3D = Number3D.sub( pointOnFarPlane, pointOnNearPlane );
 
// Normalize
dir.normalize();
 
// So, now you have a ray with its origin at 'pointOnNearPlane',
// and direction 'dir'

Optimization: could save some cycles by doing (*not* in ortho mode!, see below):

1
2
3
4
5
6
7
var camPosition : Number3D = new Number3D( camera.x, camera.y, camera.z );
// Construct the ray's direction
var dir : Number3D = Number3D.sub( pointOnFarPlane, camPosition );
// Normalize
dir.normalize();
// So, now you have a ray with its origin at the camera's position
// and direction 'dir'

Why can’t we use above optimization in ortho mode?
In perspective mode all ‘rays’ originate from the camera’s position: the ‘view cone’ has shape of a pyramid. Hence we can assume ‘pointOnNearPlane’ to coincide with the camera’s position.
In ortho mode however the ‘view cone’ has the shape of a cube, all rays are parallel. Hence we need to unproject *two* points to construct our ray.

Now simply follow Andy Zupko ’s post to drag objects around.
Or perform ‘picking’, or…

Update:
Created a little demo to visualize what I’m ranting about, check it out here

3 Comments - Tags: , , ,

25 February Creating a REST API for a Flash application

We have been working hard to implement an XML-based REST-style API for Floorplanner and some of our partners are using it already to access their users and plans. We now have started to use this API ourselves.

The Floorplanner Flash application communicates with our servers to load and save projects and designs. The backend for this functionality used to be written in PHP. Eliminating this PHP application simplifies our server setup, eases development and reduces our maintenance burden. To rewrite this functionality in Rails, we decided to eat our own dogfood and use the REST API to load and save designs. Why reinvent the wheel?

However, while implementing the changes it the Flash application, we found that it did not work out of the box, because of some limitations in ActionScript. Note that we still use ActionScript 2, so some of these issues may not be relevant for ActionScript 3. In this post, we will detail what these issues are and how we overcame them.

Using a separate format

Our REST API uses the XML format supplied by Rails. Because we had to make some changes to make it work from ActionScript, we decided to add a distinct format that we could implement differently without altering the behavior of the default XML API. Adding a new format, called “flash” can be done in Rails by adding a MIME alias to your environment:

Mime::Type.register_alias "application/xml", :flash

Now we can send different responses based on this format:

respond_to do |format|
  format.xml   { ... } # default API behavior
  format.flash { ... } # do something different
end

HTTP status codes

REST APIs use HTTP status codes to return whether a call succeeded, and if not, why. Flash however uses the browser to perform HTTP requests. The browser only returns something to Flash if the request was successful. So, if an error code is used if a request failed together with some error messages, these error messages will not be delivered to Flash and cannot be displayed to the user. We resolved this by always sending the HTTP OK status.

respond_to do |format|
  format.xml   { render :xml => @project.errors, :status => 422 }
  format.flash { render :xml => XML.failure(@project.errors, 422) }
end

Our XML.failure method will return something like:

<failure status="422">
  <error on="name">A project should have a name!</error>
</failure>

Note that other HTTP success statuses than 200 work in Safari and Firefox, but not in Internet Explorer. So, never return a 201 (:created), because Internet Explorer will not send the result to Flash!

PUT and DELETE requests

REST-style APIs use HTTP PUT requests to alter objects and DELETE requests to destroy objects. Most browsers do not support these request type. It is not supported by ActionScript either, because Flash uses the browser to send the request.

To overcome this problem, these types of requests can be simulated in Rails by sending a _method parameter along with a POST request. Unfortunately, this does not work when calling the REST API. The POST request body cannot be used to send additional variables, because it is used for the XML payload.

We solved this issue by creating additional routes for POST requests to the update and destroy actions of our resource controllers. Our routes.rb file now looks like this:

  map.resources :projects, :member => { :update => :post, :destroy => :post }

These routes route to exactly the same methods as the default REST actions (ProjectsController#update and ProjectsController#destroy), so no additional code is needed. The following calls are now equivalent:

PUT    /projects/123.xml
POST   /projects/123/update.xml
POST   /projects/123/update.flash

DELETE /projects/123.xml
POST   /projects/123/destroy.xml
POST   /projects/123/destroy.flash

The result

It requires some stretching of the pure REST principles, but doing so is worth it: we can now reuse the code we use for our API to handle Flash application calls and we can eliminate the PHP backend.

3 Comments - Tags: , , , , , , , ,

15 February Write JAVA, publish SWF

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.

No Comments - Tags: , , , ,

24 January FITC Amsterdam 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.

2 Comments - Tags: , ,

20 January Papervision3D forum

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

Read more at the Papervision3D blog.

No Comments - Tags: ,

9 December Papervision3D wins Innovation Of The Year award

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.

2 Comments - Tags: ,

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: