Friday, April 28, 2006

Colour Space Conversion Class

Download:Here

Notes:

The colour space conversion isn't 100% automated in this class. In order to convert from RGB to LAB you need to convert from RGB to XYZ then to LAB. Eventually I will create a wrapper class that will allow you to convert from anything to anything. Without messy calls like:

var rgbColour:Object = {r:100, g:231, b:16}; //Super sweet colour
var labColour:Object = ColourSpace.XYZtoLAB(ColourSpace.RGBtoXYZ(rgbColour));

However, for now you'll have to make due.

Return Format:
All the methods return objects that contain the respecitve prop names of what they're converted to in lower case. I did this so all the output is somewhat uniform ex. {l:val, a:val, b:val} and {x:val, y:val, z:val}.

HSV and HSL Notes:
The hue in HSV and HSL are returned in degrees not percentiles.

Thursday, April 27, 2006

Finding The Closest Value To X In An Array

For a project I'm working on I needed to find the value in a lookup table that was closest to whatever value I put in. I wrote a simple little prototype that does the job nice and easy, it even returns both the closest value and the index of the element containing that value.


Array.prototype.findNearest = function(compare:Number):Object{
var c:Object = {value:null, index:null};
var d:Number = Infinity; //difference between this[i] and find
var t:Number;

for(var i:Number = 0; i < this.length; i++){

t = Math.abs(this[i]-compare);

if(t < d){

d = t;
c.value = this[i];
c.index = i;
}
}

return c;
}


To call it all you need to do is this.


var myArray:Array = [10, -55, 28, 32, -11, 63, 3];
var find:Number = 5;
var result:Object = myArray.findNearest(5);

for(var i in result){
trace(i+" "+result[i]);
}


Simple and effective.

Stripping The Alpha Channel From An ARGB Value

I ran into this problem when I was working on a project where I was holding one large set of ARGB data within flash. For those of you who don't know flash's non-base 10 number support is half-hearted at best. I kept wracking my mind on how to remove the alpha channel. I could break up the ARGB number into it's components: alpha, red, green, and blue. Once that's done simply take the red, green, and blue and make a RGB value out of them.

This worked great, however, it was extremely slow with many values in real time.
I knew that I was using bitwise operators to convert from hex to decimal so that got me thinking.
There must be a bitwise operator to do this easily and quickly.

After a little investigation I came uppon the bitwise AND operator. With this you can easily "mask" out the alpha channel using one simple line.

var alphaColour:Number = myBitmap.getPixel32( scope._xmouse, scope._ymouse );
var nonAlpha:Number = alphaColour & 0x00FFFFFF;


By using 0x00FFFFFF as the "mask" the bitwise AND operator only returns the red, green, and blue values from the ARGB value that was grabbed from the bitmap.

Wednesday, April 26, 2006

FlashDevelop Code Injection

Download:SWF Mill Ready Template

Place in /../FlashDevelop/Templates

Create a new project using the "Mill Ready Project".

Basic Directory Structure


classes
---Contains all of the base classes.

library
---For external library data (See note below!)

swfmill
---Contains the source to build the application.swf from in simple SWFML.
---Also contains the compiled classes.swf that is injected into application.swf on compile.

-----------------------


Note:
There are two ways to add library items to this project. You can bundle them with classes.swf by adding them to the library within flash develop and selecting add to library from the right click menu, or you can import them into the library of the swf created by swfmill like so. Code:

<!-- Within the library tags -->
<clip id="myLibraryItem" import="../externalData/myImage.png" />

Both of these methods function in the same way, it's just a matter of taste.


Pressing F8 will have mtasc compile classes.swf into ./swfmill and then compile swfMillSource.xml into application.swf in the root project directory.

Tuesday, April 25, 2006

Using Delegate.create to maintain scope

 For those using mtasc:

If you're using mtasc you're going to need to use this special mtasc friendly Delegate class. It's also a good alternative to the built in macromedia delegate class becuase it allows for arguments.



/**
* Delegate class
* - MTASC friendly
* - allows additional parameters when creating the Delegate
*/
class Delegate
{
/**
* Create a delegate function
* @param target Objet context
* @param handler Method to call
*/
public static function create(target:Object, handler:Function):Function
{
var func = function()
{
var context:Function = arguments.callee;
var args:Array = arguments.concat(context.initArgs);
return context.handler.apply(context.target, args);
}

// Don't use local references to avoid "Persistent activation object" bug
// See: http://timotheegroleau.com/Flash/articles/scope_chain.htm
func.target = target;
func.handler = handler;
func.initArgs = arguments.slice(2);
return func;
}



What Delegate Does



Delegate is an extremely powerful tool for all OOP actionscriptors out there. If you haven't noticed already AS's scope handling blows, and oh boy it blows hard. For example:


class ScopeTest extends MovieClip{


public var myListener:Object;
public var myTest:String;

public function(Void){

myTest = "ScopeTest!";
myListener.onResize = traceSize;
Stage.addListener(myListener);
}

public function traceSize(Void):Void{
trace(Stage.width);
trace(Stage.height);

trace(myTest);
}
}



As you can see the last trace returns undefined. Wait a second, isn't traceSize a method of my instance of the object and should have the scope of the instance?

This is where Delegate comes in handy. We can force the scope of the method we're calling to be anything we want, even _root (although I wouldn't advise that, it'd be best to pass a timeline param to your class). To fix our previous scope issue we need to use Delegate.create. The syntax for Delegate.create is very simple.


Delegate.create(scope:Object, callback:Function, arg1:Type... argN:Type);


Simple right? In order to fix the event in the previous class all that needs to change is the assignment of a callback for that event.
From

myListener.onResize = Delegate.create( this, traceSize);


The final trace should now work.


Delegate is a very powerful tool, use it wisely.