Sunday, November 20, 2011

我應該記住,我的家並不溫暖!

美好的大學生活,如盛放的煙花:一放即逝!但它真的真的很美好。由萬劫深淵所得到的救贖;由谷底所抓到的一絲瞬間,不懂為我多添加了一絲絲的精彩,也由痛苦的家中得到解放。和媽子有和好的關係原來是好溫暖的。孩時溫暖的回憶也續漸閃回腦中!

美好的,真的要那麼短暫麼?半年可算短麼?

我應該記住,我的家並不溫暖!可能沒有我的家才好吧!所以,我想我是時候要再一次離開她了! 但今次應該不會再回去了吧...... 縱使不是不再見,但我真我受傷了,心總是淌著血,可不能為自已再做點甚麼吧?! 我還得想去完成,實現難以得到夢吧!

夢真的不可不追吧!但女呢? 我真的還要嗎?

我還是先去追去吧......

By
ErikYang

Tuesday, August 30, 2011

感言 - BB79十週年


BB79, 一個既熟識而又陌生的名字! 它不但留給我與一眾的導師及隊友許許多多的珍貴回憶, 也讓我們發熱發亮,燃燒有限的青春。 轉眼十年的光陰就此過去了, 此些熱勝勝的回憶一直留在心中! 希望新加入的你可以跟我一樣, 盡量敞開心扉、信任你們的導師及隊友, 創造美好的回憶, 一起燃燒青春吧!
楊頌豪@1st BB79

Monday, August 29, 2011

Beginner’s Guide to Powerflasher’s FDT 4 | Activetuts+

Beginner’s Guide to Powerflasher’s FDT 4 | Activetuts+


Flash Professional isn’t the only tool you can use for making Flash apps and games. Earlier in the year we looked at FlashDevelop; now, we’ll take a look at FDT 4, a powerful IDE designed specifically for ActionScript, MXML and haXe development. Read on to find out what it can offer you!

FDT’s Great Timesaving Features

The difference between FDT and the Flash Professional code editor or other tools is that it offers tons of timesaving features that let you concentrate on the logic of your code, so you don’t have to bother with syntax problems like a missing closing bracket or a misspelled function call. Like a spell checker, FDT gives you instant feedback about your code and identifies problems before you even compile the project. Before we install and start working with FDT I’d like to give you a taste of some of its most exciting features.

Code Completion

The most important feature of FDT, that you will probably use most often, is code completion, also called auto completion. You will never have to type in the whole name of a variable or function again. Simply start writing and hit CTRL + Space to bring up the list of proposals. You can change the auto completion behavior to be triggered on every keystroke (like FlashDevelop does) by going to Preferences > FDT > Editor > Code Assist and turning on “Every Key”.

Thursday, August 4, 2011

Ken Shirriff's blog: A Multi-Protocol Infrared Remote Library for the Arduino

Ken Shirriff's blog: A Multi-Protocol Infrared Remote Library for the Arduino


A Multi-Protocol Infrared Remote Library for the Arduino

Do you want to control your Arduino with an IR remote? Do you want to use your Arduino to control your stereo or other devices? This IR remote library lets you both send and receive IR remote codes in multiple protocols. It supports NEC, Sony SIRC, Philips RC5, Philips RC6, and raw protocols. If you want additional protocols, they are straightforward to add. The library can even be used to record codes from your remote and re-transmit them, as a minimal universal remote.
Arduino IR remote
To use the library, download the IRremote.zip and unpack to arduino/hardware/libraries. I have tested the library with Arduino version 0017.

How to send

This infrared remote library consists of two parts: IRsend transmits IR remote packets, while IRrecv receives and decodes an IR message. IRsend uses an infrared LED connected to output pin 3. To send a message, call the send method for the desired protocol with the data to send and the number of bits to send. The examples/IRsendDemo sketch provides a simple example of how to send codes:
#include  IRsend irsend;  void setup() {   Serial.begin(9600); }  void loop() {   if (Serial.read() != -1) {     for (int i = 0; i < 3; i++) {       irsend.sendSony(0xa90, 12); // Sony TV power code       delay(100);     }   } }  
This sketch sends a Sony TV power on/off code whenever a character is sent to the serial port, allowing the Arduino to turn the TV on or off. (Note that Sony codes must be sent 3 times according to the protocol.)

How to receive

IRrecv uses an infrared detector connected to any digital input pin.
The examples/IRrecvDemo sketch provides a simple example of how to receive codes:
#include   int RECV_PIN = 11; IRrecv irrecv(RECV_PIN); decode_results results;  void setup() {   Serial.begin(9600);   irrecv.enableIRIn(); // Start the receiver }  void loop() {   if (irrecv.decode(&results)) {     Serial.println(results.value, HEX);     irrecv.resume(); // Receive the next value   } } 
The IRrecv class performs the decoding, and is initialized with enableIRIn(). Thedecode() method is called to see if a code has been received; if so, it returns a nonzero value and puts the results into the decode_results structure. (For details of this structure, see theexamples/IRrecvDump sketch.) Once a code has been decoded, the resume() method must be called to resume receiving codes. Note that decode() does not block; the sketch can perform other operations while waiting for a code because the codes are received by an interrupt routine.

Hardware setup

The library can use any of the digital input signals to receive the input from a 38KHz IR receiver module. It has been tested with the Radio Shack 276-640 IR receiver and the Panasonic PNA4602. Simply wire power to pin 1, ground to pin 2, and the pin 3 output to an Arduino digital input pin, e.g. 11. These receivers provide a filtered and demodulated inverted logic level output; you can't just use a photodiode or phototransistor. I have found these detectors have pretty good range and easily work across a room.
IR wiring
For output, connect an IR LED and appropriate resistor to PWM output pin 3. Make sure the polarity of the LED is correct, or it won't illuminate - the long lead is positive. I used a NTE 3027 LED (because that's what was handy) and 100 ohm resistor; the range is about 15 feet. For additional range, you can amplify the output with a transistor.

Some background on IR codes

An IR remote works by turning the LED on and off in a particular pattern. However, to prevent inteference from IR sources such as sunlight or lights, the LED is not turned on steadily, but is turned on and off at a modulation frequency (typically 36, 38, or 40KHz). The time when a modulated signal is being sent will be called a mark, and when the LED is off will be called a space.
Each key on the remote has a particular code (typically 12 to 32 bits) associated with it, and broadcasts this code when the key is pressed. If the key is held down, the remote usually repeatedly broadcasts the key code. For an NEC remote, a special repeat code is sent as the key is held down, rather than repeatedly sending the code. For Philips RC5 or RC6 remotes, a bit in the code is toggled each time a key is pressed; the receiver uses this toggle bit to determine when a key is pressed down a second time.
On the receiving end, the IR detector demodulates this signal, and outputs a logic-level signal indicating if it is receiving a signal or not. The IR detector will work best when its frequency matches the sender's frequency, but in practice it doesn't matter a whole lot.
The best source I've found for details on the various types of IR codes is SB IR knowledge base.

Handling raw codes

The library provides support for sending and receiving raw durations. This is intended mainly for debugging, but can also be used for protocols the library doesn't implement, or to provide universal remote functionality.
The raw data for received IR measures the duration of successive spaces and marks in 50us ticks. The first measurement is the gap, the space before the transmission starts. The last measurement is the final mark.
The raw data for sending IR holds the duration of successive marks and spaces in microseconds. The first value is the first mark, and the last value is the last mark.
There are two differences between the raw buffers for sending and for receiving. The send buffer values are in microseconds, while the receive buffer values are in 50 microsecond ticks. The send buffer starts with the duration of the first mark, while the receive buffer starts with the duration of the gap space before the first mark. The formats are different because I considered it useful for the library to measure gaps between transmissions, but not useful for the library to provide these gaps when transmitting. For receiving, 50us granularity is sufficient for decoding and avoids overflow of the gaps, while for transmitting, 50us granularity is more than 10% error so 1us granularity seemed better.

Obtaining codes for your remote

The easiest way to obtain codes to work with your device is to use this library to decode and print the codes from your existing remote.
Various libraries of codes are available online, often in proprietary formats. The Linux Infrared Remote Control project (LIRC), however, has an open format for describing codes for many remotes. Note that even if you can't find codes for your exact device model, a particular manufacturer will usually use the same codes for multiple products.
Beware that other sources may be inconsistent in how they handle these protocols, for instance reversing the order, flipping 1 and 0 bits, making start bits explicit, dropping leading or trailing bits, etc. In other words, if the IRremote library yields different codes than you find listed elsewhere, these inconsistencies are probably why.

Details of the receiving library

The IRrecv library consists of two parts. An interrupt routine is called every 50 microseconds, measures the length of the marks and spaces, and saves the durations in a buffer. The user calls a decoding routine to decode the buffered measurements into the code value that was sent (typically 11 to 32 bits).
The decode library tries decoding different protocols in succession, stopping if one succeeds. It returns a structure that contains the raw data, the decoded data, the number of bits in the decoded data, and the protocol used to decode the data.
For decoding, the MATCH macro determine if the measured mark or space time is approximately equal to the expected time.
The RC5/6 decoding is a bit different from the others because RC5/6 encode bits with mark + space or space + mark, rather than by durations of marks and spaces. The getRClevel helper method splits up the durations and gets the mark/space level of a single time interval.
For repeated transmissions (button held down), the decoding code will return the same decoded value over and over. The exception is NEC, which sends a special repeat code instead of repeating the transmission of the value. In this case, the decode routine returns a special REPEAT value.
In more detail, the receiver's interrupt code is called every time the TIMER1 overflows, which is set to happen after 50 microseconds. At each interrupt, the input status is checked and the timer counter is incremented. The interrupt routine times the durations of marks (receiving a modulated signal) and spaces (no signal received), and records the durations in a buffer. The first duration is the length of the gap before the transmission starts. This is followed by alternating mark and space measurements. All measurements are in "ticks" of 50 microseconds.
The interrupt routine is implemented as a state machine. It starts in STATE_IDLE, which waits for the gap to end. When a mark is received, it moves to STATE_MARK which times the duration of the mark. It then alternates between STATE_MARK and STATE_SPACE to time marks and spaces. When a space of sufficiently long duration is received, the state moves to STATE_STOP, indicating a full transmission is received. The interrupt routine continues to time the gap, but blocks in this state.
The STATE_STOP is used a a flag to indicate to the decode routine that a full transmission is available. When processing is done, the resume() method sets the state to STATE_IDLE so the interrupt routine can start recording the next transmission. There are a few things to note here. Gap timing continues during STATE_STOP and STATE_IDLE so an accurate measurement of the time between transmissions can be obtained. If resume() is not called before the next transmission starts, the partial transmission will be discarded. The motivation behind the stop/resume is to ensure the receive buffer is not overwritten while it is still being processed; debugging becomes very difficult if the buffer is constantly changing.

Details of the sending library

The transmission code is straightforward. To ensure accurate output frequencies and duty cycles, I use the PWM timer, rather than delay loops to modulate the output LED at the appropriate frequency. (See my Arduino PWM Secrets article for more details on the PWM timers.) At the low level, enableIROut sets up the timer for PWM output on pin 3 at the proper frequency. The mark() method sends a mark by enabling PWM output and delaying the specified time. The space() method sends a space by disabling PWM output and delaying the specified time.
The IRremote library treats the different protocols as follows:
NEC: 32 bits are transmitted, most-significant bit first. (protocol details)
Sony: 12 or more bits are transmitted, most-significant bit first. Typically 12 or 20 bits are used. Note that the official protocol is least-significant bit first. (protocol details) For more details, I've written an article that describes the Sony protocol in much more detail: Understanding Sony IR remote codes.
RC5: 12 or more bits are transmitted most-significant bit first. The message starts with the two start bits, which are not part of the code values. (protocol details)
RC6: 20 (typically) bits are transmitted, most-significant bit first. The message starts with a leader pulse, and a start bit, which is not part of the code values. The fourth bit is transmitted double-wide, since it is the trailer bit. (protocol details)
For Sony and RC5/6, each transmission must be repeated 3 times as specified in the protocol. The transmission code does not implement the RC5/6 toggle bit; that is up to the caller.

Adding new protocols

Manufacturers have implemented many more protocols than this library supports. Adding new protocols should be straightforward if you look at the existing library code. A few tips: It will be easier to work with a description of the protocol rather than trying to entirely reverse-engineer the protocol. The durations you receive are likely to be longer for marks and shorter for spaces than the protocol suggests. It's easy to be off-by-one with the last bit; the last space may be implicit.

Troubleshooting

To make it easier to debug problems with IR communication, I have optional debugging code in the library. Add #define DEBUG to the beginning of your code to enable debugging output on the serial console. You will need to delete the .o files and/or restart the IDE to force recompilation.

Problems with Transmission

If sending isn't working, first make sure your IR LED is actually transmitting. IR will usually show up on a video camera or cell phone camera, so this is a simple way to check. Try putting the LED right up to the receiver; don't expect a lot of range unless you amplify the output.
The next potential problem is if the receiver doesn't understand the transmitter, for instance if you are sending the wrong data or using the wrong protocol. If you have a remote, use this library to check what data it is sending and what protocol it is using.
An oscilloscope will provide a good view of what the Arduino or a remote is transmitting. You can use an IR photodiode to see what is getting transmitted; connect it directly to the oscilloscope and hold the transmitter right up to the photodiode. If you have an oscilloscope, just connect the oscilloscope to the photodiode. If you don't have an oscilloscope, you can use a sound card oscilloscope program such as xoscope.
The Sony and RC5/6 protocols specify that messages must be sent three times. I have found that receivers will ignore the message if only sent once, but will work if it is sent twice. For RC5/6, the toggle bit must be flipped by the calling code in successive transmissions, or else the receiver may only respond to a code once.
Finally, there may be bugs in this library. In particular, I don't have anything that receives RC5/RC6, so they are untested.

Problems with Receiving

If receiving isn't working, first make sure the Arduino is at least receiving raw codes. The LED on pin 13 of the Arduino will blink when IR is being received. If not, then there's probably a hardware issue.
If the codes are getting received but cannot be decoded, make sure the codes are in one of the supported protocols. If codes should be getting decoded, but are not, some of the measured times are probably not within the 20% tolerance of the expected times. You can print out the minimum and maximum expected values and compare with the raw measured values.
The examples/IRrecvDump sketch will dump out details of the received data. The dump method dumps out these durations but converts them to microseconds, and uses the convention of prefixing a space measurement with a minus sign. This makes it easier to keep the mark and space measurements straight.
IR sensors typically cause the mark to be measured as longer than expected and the space to be shorter than expected. The code extends marks by 100us to account for this (the value MARK_EXCESS). You may need to tweak the expected values or tolerances in this case.
The library does not support simultaneous sending and receiving of codes; transmitting will disable receiving.

Applications

I've used this library for several applications:

Other projects that use this library

Other Arduino IR projects

I was inspired by Building a Universal Remote with an Arduino; this doesn't live up to being a universal remote, but has a lot of information. The NECIRrcv library provided the interrupt handling code I use.

Drum Master - Drum Master

Drum Master - Drum Master


Drum Master

Introduction to Drum Master

For some time, I have been wanting to create my own electric drum set from scratch. While I do have some electronics experience, most of my skills are with software. A few years ago, a failed attempt with using a PIC processor as the brain for a MIDI drum controller finally prompted me to give up and purchase a second hand Yamaha DTXpress set.
Fast forward a couple of years. I have now finished school, have a bit more time, and am in search of a new project to entertain me. One day I find a reference to the Arduino project - basically a simple development board built around an Atmel microprocessor. It includes a number of analog and digital inputs, and can interface with all major operating systems via a virtual Serial-over-USB port. Best of all, it is open source and relatively cheap (about $30 for the official board; down to about $10 for a kit to build your own).
After looking at the specs for this board, I decided to use it to make my own drum controller. Since I am a software guy, I want to keep as much of the processing (notably the actual playback of the samples) in software as possible, to keep the hardware as simple as possible. At the same time, I wanted this to be powerful (definitely an improvement over my current Yamaha kit), and if possible, I wanted it to rival the high end electric kits selling for multiple thousands of dollars. From this design goal was born the Drum Master system.

Overview

The Drum Master system is actually comprised of two parts. The hardware brain module (containing the Arduino microcontroller and a collection of circuits to assist in obtaining the sensor information) is called the Drum Master. This is connected via USB (technically, a virtual serial port over USB) to a computer, which is running the Drum Slave software, written in Java (inital version was in Python). When a sensor is hit, the Drum Master converts the signal to a digital value, and sends this value (and the port on which the sensor was detected) over the serial port. The Drum Slave program listens for this, and plays the corresponding audio sample.
For more information on how this system works, and how to build one yourself, read on!

Saturday, July 30, 2011

有點愛玩Flash: [AS3] flash.filter.ColorMatrixFilter(matrix) - RGB到灰階

有點愛玩Flash: [AS3] flash.filter.ColorMatrixFilter(matrix) - RGB到灰階

Understanding AS3 ColorMatrixFilter class - Emanuele Feronato

Understanding AS3 ColorMatrixFilter class - Emanuele Feronato

Filter.as - as3-classes - my collection of useful as3 classes - Google Project Hosting

Filter.as - as3-classes - my collection of useful as3 classes - Google Project Hosting


package org.lzyy.util {
import flash.display.*;
import flash.geom.*;
import flash.filters.*;

/**
* as.Filter
*
* as3.Filter class includes methods generate variety of filters for image processing.
*/
public class Filter
{
/**
* Generate the DisplacementMapFilter for twirling effect.
*
* You can apply the filter is as follows:
*
* var bmd:BitmapData = new BitmapData(width, height, false);
* var filter:DisplacementMapFilter = Filter.twirlFilter(bmd);
* bmd.draw(video);
* bmd.applyFilter(bmd, bmd.rect, new Point(0, 0), filter);
*
* You can also apply the filter specified region:
*
* var region:Rectangle = new Rectangle(100, 100, 100, 100);
* var filter:DisplacementMapFilter = Filter.twirlFilter(bmd, rect);
*
* @params source BitmapData The input bitmap data to apply the twirling effect.
* @params region Rectangle The region to apply the twirling effect.
* @params rotation Number The max amount to rotate, in radius.
* Default is Math.PI / 2.
*
* @return DisplacementMapFilter Filter to apply twirl effect
*/
static public function twirlFilter(source:BitmapData, region:Rectangle=null,
rotation:Number=0):DisplacementMapFilter
{
var width:int = source.width;
var height:int = source.height;
region ||= new Rectangle(0, 0, width, height);
rotation ||= Math.PI / 2;
var dbmd:BitmapData = new BitmapData(width, height, false, 0x8080);
var radius:Number = Math.min(region.width, region.height) / 2;
var centerX:int = region.x + region.width / 2;
var centerY:int = region.y + region.height / 2;
for(var y:int=0;y<height;++y) {
var ycoord:int = y - centerY;
for(var x:int=0;x<width;++x) {
var xcoord:int = x - centerX;
var dr:Number = radius - Math.sqrt(xcoord * xcoord + ycoord * ycoord);
if(dr > 0) {
var angle:Number = dr / radius * rotation;
var dx:Number = xcoord * Math.cos(angle) - ycoord * Math.sin(angle) - xcoord;
var dy:Number = xcoord * Math.sin(angle) + ycoord * Math.cos(angle) - ycoord;
var blue:int = 0x80 + Math.round(dx / width * 0xff);
var green:int = 0x80 + Math.round(dy / height * 0xff);
dbmd.setPixel(x, y, green << 8 | blue);
}
}
}
return new DisplacementMapFilter(dbmd,
new Point(0, 0),
BitmapDataChannel.BLUE,
BitmapDataChannel.GREEN,
width,
height,
DisplacementMapFilterMode.IGNORE);
}

/**
* Generate the BitmapData which applied mirror effect.
*
* You can create the mirrored BitmapData is as follows:
*
* var bmd = new BitmapData(video.width, video.height, false);
* bmd.draw(video);
* var mirroredBmd = Filter.mirror(bmd);
*
* @params source BitmapData The input bitmap data to apply the mirror effect.
* @params region Rectangle The region to apply the twirling effect. Default is entire region.
* @return BitmapData BitmapData which applied the mirror effect
*/
static public function mirror(source:BitmapData):BitmapData
{
var bmd:BitmapData = new BitmapData(source.width, source.height, false);
var halfWidth:int = Math.round(source.width / 2);
source.lock();
bmd.copyPixels(source, new Rectangle(0, 0, halfWidth, source.height), new Point(0,0));
for(var i:int=0;i<source.height;++i) {
for(var j:int=0;j<halfWidth;++j) {
bmd.setPixel32(halfWidth + j, i, source.getPixel32(halfWidth - j, i));
}
}
source.unlock();
return bmd;
}

/**
* Generate the DisplacementMapFilterMode for pinch effect.
*
* You can apply the filter is as follows:
*
* var bmd:BitmapData = new BitmapData(width, height, false);
* var filter:DisplacementMapFilter = Filter.pinchFilter(bmd);
* bmd.draw(video);
* bmd.applyFilter(bmd, bmd.rect, new Point(0, 0), filter);
*
* You can also apply the filter specified region:
*
* var region:Rectangle = new Rectangle(100, 100, 100, 100);
* var amount:Number = 0.5;
* var filter:DisplacementMapFilter = Filter.pinchFilter(bmd, rect, amount);
*
* @params source BitmapData The input bitmap data to apply the twirling effect.
* @params region Rectangle The region to apply the twirling effect.
* @params amount Number Amount of pinch. (-1 <= x <= 1)
* Default is 0.35.
*/
static public function pinchFilter(source:BitmapData, region:Rectangle=null,
amount:Number=0.35):DisplacementMapFilter
{
var width:int = source.width;
var height:int = source.height;
region ||= new Rectangle(0, 0, width, height);
var radius:Number = Math.min(region.width, region.height) / 2;
var centerX:int = region.x + region.width / 2;
var centerY:int = region.y + region.height / 2;
var dbmd:BitmapData = new BitmapData(width, height, false, 0x8080);
for(var y:int=0;y<height;++y) {
var ycoord:int = y - centerY;
for(var x:int=0;x<width;++x) {
var xcoord:int = x - centerX;
var d:Number = Math.sqrt(xcoord * xcoord + ycoord * ycoord);
if(d < radius) {
var t:Number = d == 0 ? 0 : Math.pow(Math.sin(Math.PI / 2 * d / radius), -amount);
var dx:Number = xcoord * (t - 1) / width;
var dy:Number = ycoord * (t - 1) / height;
var blue:int = 0x80 + dx * 0xff;
var green:int = 0x80 + dy * 0xff;
dbmd.setPixel(x, y, green << 8 | blue);
}
}
}
return new DisplacementMapFilter(dbmd,
new Point(0, 0),
BitmapDataChannel.BLUE,
BitmapDataChannel.GREEN,
width,
height,
DisplacementMapFilterMode.CLAMP);
}

/**
* Generate the DisplacementMapFilter for photic tunnel effect.
* Photic tunnel effect is as same as effect of Photo Booth application in Mac OS.
*
* You can apply the filter is as follows:
*
* var bmd:BitmapData = new BitmapData(width, height, false);
* var filter:DisplacementMapFilter = Filter.pinchFilter(bmd);
* bmd.draw(video);
* bmd.applyFilter(bmd, bmd.rect, new Point(0, 0), filter);
*
* @params source BitmapData The input bitmap data to apply the twirling effect.
* @params region Rectangle The region to apply the twirling effect.
* @return DisplacementMapFilter Filter to apply photic tunnel effect.
*/
static public function photicTunnelFilter(source:BitmapData, region:Rectangle=null):DisplacementMapFilter
{
var width:int = source.width;
var height:int = source.height;
region ||= new Rectangle(0, 0, width, height);
var centerX:int = region.x + region.width / 2;
var centerY:int = region.y + region.height / 2;
var dbmd:BitmapData = new BitmapData(width, height, false, 0x8080);
var radius:Number = Math.min(region.width, region.height) / 2;
for(var y:int=0;y<height;++y) {
var ycoord:int = y - centerY;
for(var x:int=0;x<width;++x) {
var xcoord:int = x - centerX;
var d:Number = Math.sqrt(xcoord * xcoord + ycoord * ycoord);
if(radius < d) {
var angle:Number = Math.atan2(Math.abs(ycoord), Math.abs(xcoord));
var dx:Number = (xcoord > 0? -1 : 1) * (d - radius) * Math.cos(angle) / width;
var dy:Number = (ycoord > 0? -1 : 1) * (d - radius) * Math.sin(angle) / height;
var blue:int = 0x80 + dx * 0xff;
var green:int = 0x80 + dy * 0xff;
dbmd.setPixel(x, y, green << 8 | blue);
}
}
}
return new DisplacementMapFilter(dbmd,
new Point(0, 0),
BitmapDataChannel.BLUE,
BitmapDataChannel.GREEN,
width,
height,
DisplacementMapFilterMode.CLAMP);
}

/**
* Generate the DisplacementMapFilter for bulge effect.
* Bulge effect is wrapper of pinchFilter method.
*
* @params source BitmapData The input bitmap data to apply the effect.
* @params region Rectangle The region to apply the bulge effect.
* @params amount Number Amount of bulge. (0 <= x <= 1)
* @return DisplacementMapFilter The filter to apply bulge effect.
*/
static public function bulgeFilter(source:BitmapData, region:Rectangle=null,
amount:Number=0.5):DisplacementMapFilter
{
// wrapper method of pinchFilter
return pinchFilter(source, region, Math.min(-amount, -1));
}
/**
* Generate the DisplacementMapFilter for squeeze effect.
* Dent effect is wrapper of pinchFilter method.
*
* @params source BitmapData The input bitmap data to apply the effect.
* @params region Rectangle The region to apply the bulge effect
* @params amount Number Amount of squeeze. (0 <= x <= 1)
*/
static public function squeezeFilter(source:BitmapData, region:Rectangle=null,
amount:Number=0.5):DisplacementMapFilter
{
// wrapper method of bulge filter
return pinchFilter(source, region, amount);
}

/**
* Generate the DisplacementMapFilter for fisheye effect.
*
* @params source BitmapData The input bitmap data to apply the twirling effect.
* @params amount Number Amount of fisheye (0 <= x <= 1)
* @return DisplacementMapFilter The filter to apply the fisheye effect.
*/
static public function fisheyeFilter(source:BitmapData, amount:Number=0.8):DisplacementMapFilter
{
var width:int = source.width;
var height:int = source.height;
var dbmd:BitmapData = new BitmapData(width, height, false, 0x8080);
var centerX:int = width / 2;
var centerY:int = height / 2;
var radius:Number = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
for(var y:int=0;y<height;++y) {
var ycoord:int = y - centerY;
for(var x:int=0;x<width;++x) {
var xcoord:int = x - centerX;
var d:Number = Math.sqrt(xcoord * xcoord + ycoord * ycoord);
if(d < radius) {
var t:Number = d == 0 ? 0 : Math.pow(Math.sin(Math.PI / 2 * d / radius), amount);
var dx:Number = xcoord * (t - 1) / width;
var dy:Number = ycoord * (t - 1) / height;
var blue:int = 0x80 + dx * 0xff;
var green:int = 0x80 + dy * 0xff;
dbmd.setPixel(x, y, green << 8 | blue);
}
}
}
return new DisplacementMapFilter(dbmd,
new Point(0, 0),
BitmapDataChannel.BLUE,
BitmapDataChannel.GREEN,
width,
height,
DisplacementMapFilterMode.CLAMP);
}

/**
* Generate the DisplacementMapFilter for strech effect.
*
* @params source BitmapData The input bitmap data to apply the twirling effect.
* @params amount Number Amount of strech (0 <= x <= 1), default is 0.6;
* @return DisplacementMapFilter The filter to apply the strech effect.
*/
static public function strechFilter(source:BitmapData, amount:Number=0.6):DisplacementMapFilter
{
var width:int = source.width;
var height:int = source.height;
var dbmd:BitmapData = new BitmapData(width, height, false, 0x8080);
var centerX:int = width / 2;
var centerY:int = height / 2;
var vregion:Rectangle = new Rectangle(0, 0 , width / 3, height);
var hregion:Rectangle = new Rectangle(0, 0, width, height / 3);
var blue:int;
var green:int;
for(var y:int=0;y<height;++y) {
var ycoord:int = y - centerY;
for(var x:int=0;x<width;++x) {
var xcoord:int = x - centerX;
var dx:int = (Math.abs(xcoord) < vregion.width)?
xcoord * (Math.pow(Math.abs(xcoord) / vregion.width, amount) - 1) : 0x0;
var dy:int = (Math.abs(ycoord) < hregion.height)?
ycoord * (Math.pow(Math.abs(ycoord) / hregion.height, amount) - 1) : 0x0;
blue = 0x80 + 0xff * dx / width;
green = 0x80 + 0xff * dy / height;
dbmd.setPixel(x, y, green << 8 | blue);
}
}
return new DisplacementMapFilter(dbmd,
new Point(0, 0),
BitmapDataChannel.BLUE,
BitmapDataChannel.GREEN,
width,
height,
DisplacementMapFilterMode.CLAMP);
}
}
}