Archive for 2007

Drawing using controlpoints

Wednesday, July 18th, 2007

There is an old trick which comes down to drawing a fluid line through controlpoints, by using the average of the controlpoints as anchors.

Here is my quick and dirty go at it:

You can download the example here: ControlPointDrawing (74)

arguments.callee._name in ActionScript 2

Monday, July 16th, 2007

A question on the flashcoders list about an hour ago triggered me to put together a very simple example that I have been wanting to put together for ages now.

How do you get the name of a function?

With function we could refer to:

  • any function
  • a calling function
  • a function being called

My reflection package is at the core of my xflas2 logger. It provides much the same information MTASC can put into a trace statement WITHOUT MTASC (except for the linenumbers).

Anyway, the reflection package is perfectly capable of being used standalone without a logger of some kind. It provides two simple classes with an even simpler API: ClassFinder and FunctionFinder.

Imagine a function:

	private static function runExample3() {
		_print (
			"I am :"+
			FunctionFinder.getFunctionName(arguments.callee)+
			" and I am defined in "+
			ClassFinder.getClassName(
				FunctionFinder.getFunctionClass(arguments.callee)
			)+
			" and was called by "+
			FunctionFinder.getFunctionName(arguments.caller)
		);
	}

Note that it’s static, but it doesn’t have to be, I’m just being a lazy git.

This prints:


I am :runExample3 and I am defined in SampleClass and I was called by main

Now, for the small print : you HAVE to call ClassFinder.registerAll() once somewhere at the start of your program.

Download the sample here: GettingCalleeName (116)

MovieClipLoader won’t load in ActionScript 2

Friday, June 29th, 2007

Check the following example:


var mc:MovieClipLoader = new MovieClipLoader();
mc.addListener (this);
mc.loadClip(_viewUrl, _root);

Should work right?

Should but doesn’t. What’s the gotcha? It doesn’t work on _root.
Not that that is a bad thing since _root is evil anyway, but I was only writing a ‘quick’ test for something.
Flash turns it into a ‘quirck’ test instead.

Correct way is to load it into a subclip of some kind.

AsSetPropFlags Explained

Thursday, June 21st, 2007

You might stop reading here, everything you need to know is in the provided example.

So you have decided to read on. Yes, it’s 2007 & I’m still doing AS2. I know, it’s sad, and I’m never gonna get my band started (weird purple tentacle sucking noises). But believe or not, I still love it :) .
One of the things on my todo list was understanding the AsSetPropsFlags demon. As with all things, once you do understand them, you can’t understand why it took you so long.

AsSetPropFlags is simple. Really. Assuming you know your binary numbers, and I assume you do. But if you don’t check the example below and the utility classes provided.

So now I’m going to try and explain it to you :) . Note that I only have used it in Flash 7 and above, so don’t ask me about all the flash 5 and flash 6 weirdness involved.

Properties and their attributes

Before diving into _global.ASSetPropFlags let us discuss properties first. Properties are part of an object.

For example:

var lObj:Object = new Object();
lObj ["testProp"] = "testValue";

gives us an object with a single property ‘testProp’.

In flash these properties have certain attributes, just as files in your filesystem can have a read only attribute, so can a property of your object. Which attributes do you ask? These:

  • the hidden attribute: a property can be visible or hidden, meaning for … in loops will or will not enumerate over the property
  • the protected attribute: a property can be deletable or not, meaning delete obj.prop can throw away the object stored in obj.prop or not
  • the read only attribute: a property can be overwritable or read only, meaning you can assign store new values in the property or not

A property might have default values set. In the previous example where a new object was created, the default values are (visible, deletable, overwritable). Some other properties such as _global might have all their properties hidden.

I don’t want to go into the ‘why would you need this’ too much, since you probably already know or you wouldn’t be reading this, but sometimes it might be necessary to be able to enumerate over all hidden objects for example in order to implement something such as reflection.

Now we are almost getting to explaining _global.ASSetPropFlags.

Attribute representation and storage

A question to be answered first is HOW are these attributes stored. To be honest I don’t have a clue. Somewhere with the object. This is part of why it’s so confusing. These attributes are stored, they have a representation, and apparently can be altered through _global.ASSetPropFlags, but we cannot retrieve them directly to print them (except through a little trick, but we’ll get to that).

Let’s check the representation of these attributes first. Although we cannot directly retrieve them, some smart minds have figured them out by checking their findings with the documentation from Adobe (thanks John Grden :) ).

Basically: Each property has a bitflag, consisting of 3 bits, one bit for each attribute:
bit 1 – hidden (0 no, 1 yes)
bit 2 – protected (0 no, 1 yes)
bit 4 – read only (0 no, 1 yes)

As said, you cannot retrieve these directly, but you can test them. If I tell you anObject has a property aProperty, you can check if you encounter it while enumerating, check if you can delete it, and check if you can overwrite it. Based on your findings you know the bitflags. Luckily this code was already available on osflash.org, and I’ve included the snippet in the ObjectUtil.as contained in the download (check the getPropertyFlags method). (Note that the code is not completely the same, since the original modifies the flags while testing and mine doesn’t).

So… now we know about attributes, attribute representation in binary format, and retrieving the bitflags for a property. But that’s not the end of it, we might want to alter these attributes as well. That is where _global.ASSetPropFlags comes in.

You might *still* stop reading here, everything you need to know is in the provided example. All the _global.ASSetPropFlags calls and intricacies are neatly wrapped in that class.

_global.ASSetPropFlags in detail

The _global.ASSetPropFlags method has the following signature:

_global.ASSetPropFlags(pObj:Object , pProp:Object , pBitSet:Number , pBitClear:Number)

ASSetPropFlags takes four arguments (note the global to satisfy MTASC):

@param pObj
- the object whose properties you want to affect

@param pProp a specification of the properties whose flags you want to change
- null -> all properties,
- “propName” -> a single prop,
- “p1,p2″ -> multiple properties,
- ["p1", "p2"] -> multiple properties

@param pBitSet
- any bits that are 1 are set on the target property, zero bits are ignored (so whatever you specify here it will NEVER CLEAR any bits)

@param pBitClear
- any bits that are 1 are cleared on the target property, zero bits are ignored (so whatever you specify here it will NEVER SET any bits)

Confused about the pBitSet and pBitClear?
Remember that you would use the ASSetPropsFlags to alter specific attributes, eg you wish unhide all properties in _global. So you know which bit you want to change, but you don’t know the bits for all the other properties, so pBitSet let’s you specify only the bits you want to set. It does not let you specify which bits to ‘unset’ so:

Assume we have:

var lObj:Object = new Object();
lObj ["testProp"] = "testValue";
trace(ObjectUtil.getPropertyFlags(lObj, "testProp")); // traces 0
_global.ASSetPropFlags(lObj , "testProp", 1, 0); //sets bit 1
trace(ObjectUtil.getPropertyFlags(lObj, "testProp")); // traces 1
_global.ASSetPropFlags(lObj , "testProp", 2, 0); //sets bit 2, but does not unset bit 1
trace(ObjectUtil.getPropertyFlags(lObj, "testProp")); // traces 3

So you see the pBitSet only specifies the bits that are set, first we pass bit 1 and then bit 2, in binary 011, which is 3 in decimal. In other words:

001
010
---
011

So how do we clear bits then? Right through the bBitClear flag. It works exactly the same, however instead of setting bits, the specified bits are cleared. And they are cleared BEFORE the bits specified in pBitSet are applied.

Referring to the previous example again:

var lObj:Object = new Object();
lObj ["testProp"] = "testValue";
trace(ObjectUtil.getPropertyFlags(lObj, "testProp")); // traces 0
_global.ASSetPropFlags(lObj , "testProp", 1, 0); //sets bit 1
trace(ObjectUtil.getPropertyFlags(lObj, "testProp")); // traces 1
_global.ASSetPropFlags(lObj , "testProp", 2, 1); //clear bit 1, sets bit 2,
trace(ObjectUtil.getPropertyFlags(lObj, "testProp")); // traces 2

Ok, so you might say: what the.. ? How can I ever be sure what flags I end up with? Well thats very simple. If you want to be entirely sure and in control of the endresult you use:

_global.ASSetPropFlags(lObj , "testProp", newFlags, 7); //clear all bits, sets newFlags

You clear all bits and set whatever you want. However usually you want to flip certain bits so for enabling a certain bit you use:

_global.ASSetPropFlags(lObj , "testProp", bitToSet, 0); //clear nothing, set my bit

and to clear it:

_global.ASSetPropFlags(lObj , "testProp", 0, bitToClear); //clear my bit, set nothing.

If you’d rather see it in formula form:

The formula is:
oldBit ^(oldBit & clearBit) | setBit

where oldBit represents the property’s current flags. The oldBit and clearBit are AND-ed together first giving you only those bits from clearBit that are actually in oldBit. Then this value is XOR against oldBit, meaning the bits from clearBit that are in oldBit are flipped to 0. Last but not least we OR it against all bits in setBit.

You might have seen (oldBit ^ clearBit) ^ setBit, that formula is not correct:

var oldBit:Number = 1;
var clearBit:Number = 2;
var setBit:Number = 3;
trace (oldBit ^(oldBit & clearBit) | setBit); //--> RIGHT FORMULA traces 3
trace ((oldBit ^ clearBit) ^ setBit);  //--> WRONG FORMULA traces 0

Download example

If you’d rather see in in action, everything you need to know is in the provided example: AssetpropsflagsExample (88)

Credits

I would like to thank John Grden for his (code) groundwork and assistance in getting my head around the specifics. Other credits go to the people who created the osflash documentation on http://osflash.org/flashcoders/undocumented/assetpropflags especially Jerome Cordiez

If I forgot to give you due credit, or you would like to see it changed, drop me a line!

Image perspective effect in ActionScript 2

Saturday, June 2nd, 2007

Very rudimentary image perspective demo. Since it’s performance intensive in AS2 you’ll have to click the more link if it’s not already visible. Note that this is not a demo of how it should be done, it’s more a test of how far we can push displacementmaps.

You just got to read the original story by the way, it’s hilarious: http://www.b3ta.com/board/496182

You can download this example here (Flash IDE & FlashDevelop / MTASC compatible):ImagePerspectiveEffect (109)

ps check out some posts on distorted perspective planes for a much better way

Image flipping

Saturday, June 2nd, 2007

A post on the flashcoderlist (http://www.mail-archive.com/flashcoders@chattyfig.figleaf.com/msg34296.html) asking about an image turn around effect got me coding for 2 hours in a row until I finished it and realized my effect was not quite similar to what was required (http://www.ja-ik-doe-mee.be/).

Anyway I liked it nonetheless so posting it anyway.

You can download this example here (Flash IDE & FlashDevelop / MTASC compatible):ImageTurnEffect (68).

Calculating displacement maps based on reference maps

Friday, January 19th, 2007

I already blogged about this, but I saw that some items could use some more explanation. Please read “Getting the displacement you need” first for the basic idea.

In short the principle is:

  • you have a reference map, say A
  • you apply a distortion effect to the reference map created a distorted version of A say A’
  • you calculate the displacement map that could transform A into A’ by calculating the difference in pixel value between A and A’

Difference process

Some important points before we start:

Use a lossless image format (eg bmp). If you use lossy compression anywhere in the pipeline, you are throwing information away. This missing information results in artifacts in the displacement map. So, save all images as BMP for example. Import them into flash and set the properties to lossless.

We will now describe some steps in my previous post in some more detail.

Creating the reference map

Option 1 – Creating the reference map in photoshop
—————————————————————————————————-

  • create a new image 256 x 256
  • add another layer
  • linear gradient fill the bottom layer from left to right, black to red
    (while filling keep shift pressed to make sure the gradients are vertical/horizontal &
    zoom in a bit to make sure you fill the whole area)
  • linear gradient fill the top layer from top to bottom, black to green
  • set the top layer to difference, or screen, or lighten (doesn’t matter in this case)
  • verify the top left pixel has RGB value (0,0,0) and the bottom right has (255,255,0), if this is not the case, start over :)

Option 2 – Creating the reference map through code in Flash
—————————————————————————————————-

import flash.display.BitmapData;
var baseBitmap:BitmapData = new BitmapData (256,256, false, 0×000000);
for (var x:Number=0;x<256;x++) {
for (var y:Number=0;y<256;y++) {
baseBitmap.setPixel(x,y,x<<16|y<<8);
}
}
_root.attachBitmap(baseBitmap, 0);

Copy & paste in imaging programming and save.

Creating the transformed map/image

  • Open up your base reference map
  • Apply a distortion filter, eg Spherize
  • Save the image

Calculating / deducting the displacement map

  • import both the base reference map A and the transformed reference map A’ into Flash
  • set the properties to lossless
  • export them as base and transformed
  • run the difference calculation code below
import flash.display.BitmapData;
var baseBitmap:BitmapData = BitmapData.loadBitmap(“base”); //load base map
var refBitmap:BitmapData = BitmapData.loadBitmap(“transformed”);//load transformed map
var diffBitmap:BitmapData = new BitmapData (256,256, false, 0×000000);//store for difference result

//deduct each pixel and add middle value
//factor 0.5 prevents overflowing
var factor:Number = 0.5;
for (var x:Number=0;x<256;x++) {
for (var y:Number=0;y<256;y++) {
//middle the difference to prevent overflow
var dx:Number = ((refBitmap.getPixel(x,y) >> 16 & 0xff) – (baseBitmap.getPixel(x,y) >> 16 & 0xff))*factor+0×80;
var dy:Number = ((refBitmap.getPixel(x,y) >> 8 & 0xff) – (baseBitmap.getPixel(x,y) >> 8 & 0xff))*factor+0×80;
diffBitmap.setPixel(x, y,
(dx << 16)|(dy<<8)|0x80 //0x80 is not necessary, but using a visual grey as 'no displacement' is satisfying:)
);
}
}
_root.attachBitmap(diffBitmap, 0);

Scaling the displacement map / Preventing artifacts
To prevent confusing there are two ways of scaling, one is to scale the displacements, and two is to resize the displacement map itself. This technique applies to both types.
As you scale the displacement map, you might see artifacts appearing. How bad these artifacts are depends on how you are scaling the map and how much you are scaling it. Since the displacement map can only displace pixels from -128 to 128 without scaling, the feature has its limits.

What might help in preventing artifacts is maximizing the pixel difference, so that less scaling in the filter in needed. How far you can maximize it depends on the image itself. Below is an example of multiplying the difference until it breaks:

Difference process

The second image is useable, but the 3rd is not (unless you want some glass like special effect, then it is very nice).

Another thing that can help preventing artifacts is blurring. Basicly if you resize the displacement map, any lines that you see in the map, will be visible in the result as well. Blurring those lines will improve the result.

The image on the left shows artifacts due to displacement map scaling, the image on the right uses the same map, but blurred.

Difference process

The code for this post can be downloaded here: BitmapDifferenceExample (73).

Note that if you generate your displacement maps through code a lot of this information does not apply:). The next post will go deeper into the panoramic displacement mapping.

Panoramic projection using displacement mapping

Friday, January 19th, 2007

In this post we will be looking at the creation of a distorted panorama using a displacement map. The two examples below show the difference between a panorama without and with distortion (notice how in the distorted version the grid bends):

Panorama without distortion (NondistortedPanorama (78))

Panorama with distortion (DistortedSoftPanorama (103))

Some simple tricks to note up front:

  • detecting the mouse outside of the panorama is done through an empty movieclip with a stage-sized hitarea and an onpress=null
  • in order to displace the whole stage at once, you can set the displacement map on the root but you need to mask the stage through code (ie setMask)

We will be looking at a visual way to generate the required displacement maps using a 3D program and an imaging program. Ofcourse you can generate the required maps through code as well, but I like the visual way of doing stuff like this. It has its limitations of course. I have summed up the whole process in a slide show below. The different resources that are required can be downloaded below as well. Note that I’m still experimenting with this stuff:). Some of the slides refer back to previous posts.

The slides refer to some resources. The base map and difference calculation resources can be found elsewhere on this blog (search for displacement). The displacement maps can be retrieved from the downloaded source file, but now you know how to create them yourself as well. Let’s conclude with what happens if you tinker with the rendered image and force overflows etc:

That said, this is again an example of what you can do with displacementmaps, but not the way to go when you want to create a real cubic panorama.

Getting the displacement you need in ActionScript 2

Tuesday, January 9th, 2007

In my previous post I explained the basics of displacement mapping, and I promised to tell something about getting the filter to do what you want it to do. Well, in order to do so, let’s look at the picture I showed you again, written a little differently:

+ *? =

where ? is an unknown scale factor

It says that given a source image, if we apply a displacement map multiplied by some scaling factor, we will end up with a result image. If we look at the visual formula written like this:

ImgSource + DispMap*ScaleFactor = ImgResult,

we can see that with some basic math we get:

ImgResult – ImgSource = DispMap*ScaleFactor, in other words:

- = *?

This tells us that if we have the source image and the result, that we can in theory calculate the displacement map, but since the displacement map is related to the scalefactor, there is not a single result.

Would this simple idea gives us the one possible displacement map that caused the transformation of ImgSource into ImgResult?

No, unfortunately not. Why not?
Well, in displacement mapping, pixels are being displaced (Orly?), but pixels are being lost and duplicated as well. All in all, just by looking at the original image and the displacement, you cannot usually tell which pixel came from where. This is especially true of course if multiple pixels in the source image have the same value.

But then again, we only need one displacement map that matches the formula and we are good to go. In order to find a good displacementmap we need to start with a good image. So what is a good image to start with? One that has unique pixels in it AND relates the position of a pixel to its color. Here is an example of such an image:

basemap

The x,y coordinate of a pixel is reflected in the pixel value. This allows us to relate pixel values to these x,y coordinates.

In order to transform this image to get our displaced image (the result), we can use photoshop for example. Imagine we transform this image by performing a few sphererizes on it. Now, the magic step is to simply substract the pixel values in the source image from the result image and add the ‘no displacement’ value of 0×80 to each pixelchannel, and tadaa: we have our displacement map. In order to understand how this works, we have to realize that since pixel values were actually pixel locations, the distance in value between two pixels, is actually the distance in pixels. To explain this further, let’s look at a single pixel. For simplicities sake we are leaving the scale factor out of this discussion.

Example pixel displacement

  • a pixel at (16,128) has color value 0×108000
  • if after applying a transform this pixel has been moved to (32,96) the distance in pixels is (-16,32).
  • the pixel at (32,96) had the value 0×206000 before applying the transform.
  • the difference between 0×108000 and 0×206000 is -0×10 << 16 | 0x20 << 8, which is (-16,32)
  • adding 0×80 for each channel gives us: 0×70<<16|0xa0<<8 = 0x70a000
  • a value of 0×70a0 in the displacement map at position (32,96) will cause a lookup at (-16,32) which is (16,128)
  • the story applies to a pixel at (x,y) in general

Note that you cannot display the difference without adding the grey no-displacement map, since we cannot show negative values for a pixel channel. Select some different images below to play with this principle. You can use the code it contains to calculate your own displacement maps.

I haven’t experimented a lot with maps larger than 256×256, I will blog about that when I get to it. Ofcourse, again a picture says more than a thousand words, so here is something that shows this principle in practice:

Select an effect, and play with the slider! Note that this example has not been optimized for performance.

Here are the sources: DisplacementRefMapExample (92)

Well, I don’t know about you but I can just feel the air tingle with Harry Potter magic, Pixellatio!

  • for the actual process please refer to the source code. In fact: the formula is that half the distance between two pixels is added, since the maximum distance is +/- 256 while we need it to be +/- 128

Relative paths in ActionScript

Wednesday, January 3rd, 2007

The first post in this new year is something I see a lot of beginners run into. They create a flash movie which has to load some resources and they simply go like:

   obj.loadSomething("mycontent.swf");

Running the sample locally works fine of course since everything is where you expect it to be.
However, after deployment your swf might be loaded into another swf, or loaded from a html page at another location and your content suddenly breaks. Why? Since “mycontent.swf” was a relative location.

So how do you fix it? Well there are several solutions:

  1. use an absolute path
  2. use a resource file to define a content path
  3. use _url to determine where your swf actually is and thus where your content is

Option 1 isn’t very good, if your content is moved to another folder on the webserver, it breaks again. Option 2 does not actually solve the problem, since now you have to find the resource file :) . Let’s go with option 3.

Using _url you can determine where your calling swf is being loaded from. Based on where it is loaded from you can find your relative content again. Image the following function (wrap it in a class or not):

function getPath (parent:MovieClip, path:String):String {
	//if its a full path, do not alter it
	if (path.indexOf(":") != -1) return path;
	//take the parent url and normalize it
	//(some player versions return \\ for local paths)
	var parUrl:String = parent._url;
	parUrl = parUrl.split("\\\").join("/");
	//take our full path, and cut off filename
	//eg (http://url/main.swf, becomes http://url/
	var parArr:Array =	parUrl.split("/");
	parArr.pop();
	parUrl = parArr.join("/")+"/";
	//normalize the path we are looking for too
	var pathUrl:String = path.split("\\\").join("/");
	//combine full path and relative url
	return parUrl+pathUrl;
}

Note that this is not a complete working version, but it works fine except for the following:

  • it might not work locally on a mac when full paths are being used
  • relative paths with ./ or ../../ will not work
  • Of course the code can easily be extended to incorporate these features. We’ll leave this as an exercise for the reader.

    Using this function, we can now change our previous code to:

       obj.loadSomething(getPath(this,"mycontent.swf"));
    

    “this” should refer to a movieclip, for example _root. Using this indirection is a good thing in itself, since our path management is now localized, so if any problems occur, we only have to edit the getPath function instead of going through our code finding every loadSomething call. In a real project you might put the getPath function as a static method into a Utility class, add logging to it etc.