|
-
Qwaizang:syntax_entity_
[F8] [Disc] 2D Effects Rendering
In the process of figuring out my game engine, I've decided to create an open discussion about the methods I've found to achieve certain visual effects so that others can learn from my experiments and I can learn from others' responses.
Before I get into anything, I want to point out that my engine utilizes a document stack of container movieclips. By that I mean I have a seperate container for all interactive objects, a seperate container for players, a seperate container for background graphics, a seperate container for buildings, etc. Each container serves as a layer that is composited into the final frame at render time. With that in mind, let's continue.
1. Residual Frames
A specific goal I had from the beginning was the ability to render residual frames. This is an effect that is typically used in fighting or action games during special moves or power ups. Although a bit of work can make this staple of eye candy look original, it generally tends to look like this:

My first approach to this effect was the assumption that I could simply use a seperate BitmapData surface to copy the position of affected objects and composite that surface into each rendered frame like everything else, however, this would not address two particular issues. First, it would retain all frames rendered until the effect was turned off, rather than only retaining a specified number of frames. Second, in a multiplayer situation, the residual frames would render relative to the visible region of the screen, not world coordinates of the game level itself, so not every one would see the same thing at render time. I devised the following method to address these issues, which holds up well at 60 fps on my mashed up machine:
Code:
// New Document: frame 1, main timeline
import flash.display.BitmapData
import flash.geom.ColorTransform
import flash.geom.Point
import flash.geom.Rectangle
var myRoot:MovieClip = this;
var playerMC:MovieClip = myRoot.createEmptyMovieClip("playerMC", myRoot.getNextHighestDepth());
var renderMC:MovieClip = myRoot.createEmptyMovieClip("renderMC", myRoot.getNextHighestDepth());
var renderPoint:Point = new Point(0, 0);
var startP:Point = new Point(-1, -1);
var endP:Point;
var renderW:Number = Stage.width;
var renderH:Number = Stage.height;
var residualBuffer:Number = 8; // legal values are 1 thru 255
var residualFade:ColorTransform = new ColorTransform(1, 1, 1, 1, 0, 0, 0, -Math.round(256 / (residualBuffer + 1)));
var residualSurface:BitmapData = new BitmapData(renderW, renderH, true, 0x00000000);
var renderSize:Rectangle = new Rectangle(0, 0, renderW, renderH);
function testResidual() {
// reduce render quality to improve framerate
if(myRoot._quality != "LOW") myRoot._quality = "LOW";
// remove our player from video memory
if(playerMC._visible) playerMC._visible = false;
// erase previous line
playerMC.clear();
// start drawing new line
playerMC.lineStyle(10, 0xffffff, 100);
if((startP.x < 0) && (startP.y < 0)) {
startP.x = Math.round(Math.random() * renderW);
startP.y = Math.round(Math.random() * renderH);
} else {
startP.x = endP.x;
startP.y = endP.y;
}
endP = new Point(Math.round(Math.random() * renderW), Math.round(Math.random() * renderH));
playerMC.moveTo(startP.x, startP.y);
playerMC.lineTo(endP.x, endP.y);
// finished drawing new line
// fade residual frames
residualSurface.colorTransform(renderSize, residualFade);
// append a current frame
residualSurface.draw(playerMC);
// clean up before rendering
renderMC.clear();
// start rendering current frame
renderMC.lineStyle(0, 0x000000, 0);
renderMC.moveTo(0, 0);
renderMC.beginBitmapFill(residualSurface);
renderMC.lineTo(renderW, 0);
renderMC.lineTo(renderW, renderH);
renderMC.lineTo(0, renderH);
renderMC.lineTo(0, 0);
renderMC.endFill();
// finished rendering current frame
}
// render once per frame
myRoot.onEnterFrame = testResidual;
The way this works is pretty straight forward. Each frame of animation is drawn to residualSurface, then the entire contents of the BitmapData are manipulated using a ColorTransform so that their alpha channel is reduced. Older frames appear more transparent and eventually disappear because the effect is cumulative. By controlling the rate of dissipation, the number of visible residual frames can be accurately constrained.
This demo is a basic primer on the technique, but it doesn't give any real indication of its limitations or practical use. A bit of rewriting and additional logic is required to properly test this effect. Below is a beefed up version, complete with full commentation:
Code:
// New Document: frame 1, main timeline
// import the classes we need
import flash.display.BitmapData
import flash.geom.ColorTransform
import flash.geom.Matrix
import flash.geom.Point
import flash.geom.Rectangle
// allow or disallow residual frame rendering
var ALLOW_RESIDUAL:Boolean = true;
// numerics
var worldW:Number = Stage.width;
var worldH:Number = Stage.height;
var charW:Number = 64;
var charH:Number = 96;
var residualBuffer:Number = 8;
// the behavior of our character
var behavior:Object = {maxSpeed : 10, moveX : 0, moveY : 0};
// clean reference to _root
var myRoot:MovieClip = this;
// a container for all elements of our world
var world_mc:MovieClip = myRoot.createEmptyMovieClip("world_mc", myRoot.getNextHighestDepth());
// a surface to render our frames on
var render_mc:MovieClip = myRoot.createEmptyMovieClip("render_mc", myRoot.getNextHighestDepth());
// a container for all elements of our character
var char_mc:MovieClip = world_mc.createEmptyMovieClip("char_mc", world_mc.getNextHighestDepth());
// a surface to render our character's residual frames on
var residual_mc:MovieClip = char_mc.createEmptyMovieClip("residual_mc", char_mc.getNextHighestDepth());
// a surface to render our character's current frame on
var graphics_mc:MovieClip = char_mc.createEmptyMovieClip("frame_mc", char_mc.getNextHighestDepth());
// objects used in rendering residual frames
var residualFader:ColorTransform = new ColorTransform(1, 1, 1, 1, 0, 0, 0, -Math.round(256 / (residualBuffer + 1)));
var residualMatrix:Matrix; // to be initialized later
var residualRegion:Rectangle; // ...
var residualSurface:BitmapData; // ...
var renderSurface:BitmapData = new BitmapData(worldW, worldH, false, 0xff000000);
// the events of our demo
myRoot.onLoad = init;
myRoot.onEnterFrame = drawFrame;
// initilization code
function init() {
initRender();
initRegion();
initSurface();
initChar();
};
// optimize rendering
function initRender() {
// reduce render quality to improve framerate
myRoot._quality = "LOW";
// free up video memory by hiding the contents of our world
world_mc._visible = false;
};
// calculate surface area needed for residual frames
function initRegion() {
residualRegion = new Rectangle(0,
0,
charW + (2 * (residualBuffer * behavior.maxSpeed)),
charH + (2 * (residualBuffer * behavior.maxSpeed)));
};
// allocate memory for surface area of residualRegion
function initSurface() {
residualSurface = new BitmapData(residualRegion.width, residualRegion.height, true, 0x00000000);
};
// draw the content of our character
function initChar() {
graphics_mc.clear();
graphics_mc.lineStyle(0, 0xc0c0c0, 100);
graphics_mc.moveTo(0, 0);
graphics_mc.beginFill(0xc0c0c0, 100);
graphics_mc.lineTo(charW, 0);
graphics_mc.lineTo(charW, charH);
graphics_mc.lineTo(0, charH);
graphics_mc.lineTo(0, 0);
graphics_mc.endFill();
residual_mc._x = -(residualBuffer * behavior.maxSpeed);
residual_mc._y = -(residualBuffer * behavior.maxSpeed);
};
// process keypresses independent of Key.addListener() event handlers
function getInput() {
// assume no key is pressed
behavior.moveX = 0;
behavior.moveY = 0;
if(Key.isDown(Key.LEFT)) {
if(char_mc._x - behavior.maxSpeed >= 0) {
// enable left movement
behavior.moveX = -1;
}
}
if(Key.isDown(Key.RIGHT)) {
if(worldW - (char_mc._x + charW + behavior.maxSpeed) >= 0) {
// enable up movement
behavior.moveX = 1;
}
}
if(Key.isDown(Key.UP)) {
if(char_mc._y - behavior.maxSpeed >= 0) {
// enable right movement
behavior.moveY = -1;
}
}
if(Key.isDown(Key.DOWN)) {
if(worldH - (char_mc._y + charH + behavior.maxSpeed) >= 0) {
// enable down movement
behavior.moveY = 1;
}
}
// toggle rendering of residual frames
ALLOW_RESIDUAL = !Key.isToggled(Key.CAPSLOCK);
};
// process the movement flags and update character position on screen
function moveChar() {
char_mc._x += behavior.moveX * behavior.maxSpeed;
char_mc._y += behavior.moveY * behavior.maxSpeed;
};
function drawFrame() {
// build translation matrix
residualMatrix = new Matrix(1, 0, 0, 1, residualBuffer * behavior.maxSpeed, residualBuffer * behavior.maxSpeed);
// once-per-frame code
getInput();
moveChar();
// translate the residual frames rendered up until this point
residualSurface.scroll(-behavior.moveX * behavior.maxSpeed, -behavior.moveY * behavior.maxSpeed);
// apply fade to residual frames rendered up until this point
residualSurface.colorTransform(residualRegion, residualFader);
// conditionally allow current frame to be added to residual frames
(ALLOW_RESIDUAL) ? residualSurface.draw(graphics_mc, residualMatrix) : null;
// clean up before compositing
residual_mc.clear();
// composite the residual frames into the final frame
residual_mc.lineStyle(0, 0x000000, 0);
residual_mc.moveTo(0, 0);
residual_mc.beginBitmapFill(residualSurface);
residual_mc.lineTo(residualRegion.width, 0);
residual_mc.lineTo(residualRegion.width, residualRegion.height);
residual_mc.lineTo(0, residualRegion.height);
residual_mc.lineTo(0, 0);
residual_mc.endFill();
// clean up before capturing
renderSurface.fillRect(new Rectangle(0, 0, worldW, worldH), 0xff000000);
// capture the current composite
renderSurface.draw(world_mc);
// clean up before rendering
render_mc.clear();
// render the current final frame
render_mc.lineStyle(0, 0x000000, 0);
render_mc.moveTo(0, 0);
render_mc.beginBitmapFill(renderSurface);
render_mc.lineTo(worldW, 0);
render_mc.lineTo(worldW, worldH);
render_mc.lineTo(0, worldH);
render_mc.lineTo(0, 0);
render_mc.endFill();
// end of once-per-frame code
};
It is important to note that while the first demonstration can be run using 255 residual frames with no perceptible bogging, this second demonstration begins to bog very noticably with a residual frame count of only 32 (on my junky machine, at least). While a strict rectangle is far from being anything remotely like a fully animated character, you get the idea.
The first demo can be used to generate fog-like effects by setting the alpha value of playerMC.lineStyle() to 1 and changing the alpha channel transformation in residualFade to return a positive value instead of a negative one. Unfortunately, this takes time to generate anything very interesting, but perhaps using a for() loop might be handy in churning out a randomized haze layer in no time.
More soon.
Qwai•zang \kwî-'zan\ n [origin unknown] 1 : abstract designer, esp. of complex real-time experiments, c. 21st century
-
Please, Call Me Bob
hows this for a residual effect?
http://trogdorffe.tripod.com/junk.htm
note, it actualy looks kindof cooler on low quality (which makes it somewhat pixelated)
EDIT: advertisements appear to have some effect on the thing...
-
Please, Call Me Bob
...and if you combine that with a ColorMatrixFilter, you can make a lava-lampish effect.
http://trogdorffe.tripod.com/junk2.htm
note that the ColorMatrix filter stays, allowing the whiteness to "overtake" the darkness, unlike in the other version
so i made it draw the opposite color of getPixel(1,1) instead of just white
-
Qwaizang:syntax_entity_
Sorry Trog, either the file's been removed or Player 9 won't run it. Nonetheless, I want to begin working with ColorMatrixFilter to see what it can do. It sounds powerful.
For the time being, I'm a bit stumped as to why my second demo is bogging when my first one isn't. I think it's related to the dimensions of the BitmapData, but even when I reduce maxSpeed to 1 it runs at about half the expected framerate. Not that I would ever need more than 8 residual frames, I just don't understand where the bottleneck is. Ah well, if it isn't a problem, I guess I won't dwell on it.
Qwai•zang \kwî-'zan\ n [origin unknown] 1 : abstract designer, esp. of complex real-time experiments, c. 21st century
-
M.D.
why are you using beginBitmapFill when you're not actually repeating anything, it looks like an unnecessary step. Just attach residual Surface to render_mc
render_mc.attachBitmap(residualSurface, 0) //do once
-
Senior Member
heh, I like the second one, thats a fun effect.
-
Qwaizang:syntax_entity_
Dynamic Lo-fi Lighting
One thing I wanted to incorporate into my engine was simulated light sources. I managed to come up with a fairly versatile solution that can achieve some fairly decent results even though it's considerably lo-fi. A rudimentary example follows. As usual, "copy, paste, run"; replace "YOUR_URL_HERE" in the script with an url to a source image, use keys 1 thru 6 to enable different blend modes, and use the mouse to translate the position of your source image:
Code:
// new document: frame 1, main timeline
// set document dimensions to: 640 x 480
// set document framerate to: 30 or 60
// import the classes we need
import flash.display.BitmapData
import flash.geom.ColorTransform
import flash.geom.Matrix
import flash.geom.Rectangle
// clean reference to root
var myRoot:MovieClip = this;
// the container of our world
var world:MovieClip = myRoot.createEmptyMovieClip("world", myRoot.getNextHighestDepth());
// the surface where our frames are rendered
var render:MovieClip = myRoot.createEmptyMovieClip("render", myRoot.getNextHighestDepth());
// the surface that contains the terrain
var terrain:MovieClip = world.createEmptyMovieClip("terrain", world.getNextHighestDepth());
// the surface where lights are drawn
var lighting:MovieClip = world.createEmptyMovieClip("lighting", world.getNextHighestDepth());
// the discreet layers of the lighting data
var lightSurface_0:MovieClip = lighting.createEmptyMovieClip("lightSurface_0", lighting.getNextHighestDepth());
var lightSurface_1:MovieClip = lighting.createEmptyMovieClip("lightSurface_1", lighting.getNextHighestDepth());
var lightSurface_2:MovieClip = lighting.createEmptyMovieClip("lightSurface_2", lighting.getNextHighestDepth());
var lightSurface_3:MovieClip = lighting.createEmptyMovieClip("lightSurface_3", lighting.getNextHighestDepth());
var lightSurface_4:MovieClip = lighting.createEmptyMovieClip("lightSurface_4", lighting.getNextHighestDepth());
var lightSurface_5:MovieClip = lighting.createEmptyMovieClip("lightSurface_5", lighting.getNextHighestDepth());
var lightSurface_6:MovieClip = lighting.createEmptyMovieClip("lightSurface_6", lighting.getNextHighestDepth());
var lightSurface_7:MovieClip = lighting.createEmptyMovieClip("lightSurface_7", lighting.getNextHighestDepth());
var lightSurface_8:MovieClip = lighting.createEmptyMovieClip("lightSurface_8", lighting.getNextHighestDepth());
// the object responsible for downloading our terrain
var terrainLoader:MovieClipLoader = new MovieClipLoader();
// the url of our terrain
var terrainSource:String = "YOUR_URL_HERE";
// the surface where our frames are compositted
var frontBufferData:BitmapData = new BitmapData(Stage.width, Stage.height, false, 0xff000000);
// the array of light source objects
var lightSources:Array = new Array();
// this enables different blend modes
var renderFlag:Number = 0;
// establish our events
myRoot.onLoad = init;
myRoot.onEnterFrame = renderScene;
// initialixation code
function init() {
// reduce quality to improve framerate
myRoot._quality = "LOW";
// free up video memory by hiding our world
world._visible = false;
// prevent our lighting from obscuring our terrain
lighting._visible = false;
// create our light source objects
lightSources.push({x : 300, y : 230, r : 200});
lightSources.push({x : 420, y : 250, r : 80});
lightSources.push({x : 550, y : 190, r : 40});
lightSources.push({x : 40, y : 300, r : 300});
// establish rendering surface
render.attachBitmap(frontBufferData, 0);
// establish event handling
Key.addListener(myRoot);
terrainLoader.addListener(myRoot);
// begin transfer of terrain
terrainLoader.loadClip(terrainSource, terrain);
};
// event handlers
function onKeyDown() {
// enable different blendmodes
if(Key.isDown(49)) {
renderFlag = 0;
return;
} else if(Key.isDown(50)) {
renderFlag = 1;
return;
} else if(Key.isDown(51)) {
renderFlag = 2;
return;
} else if(Key.isDown(52)) {
renderFlag = 3;
return;
} else if(Key.isDown(53)) {
renderFlag = 4;
return;
} else if(Key.isDown(54)) {
renderFlag = 5;
}
};
// more event handlers
function onLoadInit() {
// go through all of the discreet layers of the lighting data
for(var lCount:Number = 0; lCount < 9; lCount++) {
// dynamically get the scope of the current discreet layer
with(lighting["lightSurface_" + lCount]) {
if(lCount < 1) {
// if this is the backdrop layer...
// apply a fill whose value is the darkest value in the lighting data
lineStyle(0, 0x000000, 100);
beginFill(0x000000, 100);
moveTo(0, 0);
lineTo(Stage.width, 0);
lineTo(Stage.width, Stage.height);
lineTo(0, Stage.height);
lineTo(0, 0);
endFill();
} else {
// otherwise...
// create a placeholder for our lighting value
var fillColor:Number;
// calculate the percentage of the radius for any given light source object
var m:Number = 1 - ((lCount - 1) / 8);
// the first layer is darkest, the last layer is lightest, so...
// assign the proper lighting values to our placeholder
if(lCount == 1) {
fillColor = 0x1f1f1f;
} else if(lCount == 2) {
fillColor = 0x3f3f3f;
} else if(lCount == 3) {
fillColor = 0x5f5f5f;
} else if(lCount == 4) {
fillColor = 0x7f7f7f;
} else if(lCount == 5) {
fillColor = 0x9f9f9f;
} else if(lCount == 6) {
fillColor = 0xbfbfbf;
} else if(lCount == 7) {
fillColor = 0xdfdfdf;
} else if(lCount == 8) {
fillColor = 0xffffff;
}
// establish lineStyle for this discreet layer
lineStyle(1, fillColor, 100);
// go through every light source object
for(sCount:Number = 0; sCount < lightSources.length; sCount++) {
// begin rendering the fill of this value for this light source object
beginFill(fillColor, 100);
// start drawing a lo-fi, 8-point circle
moveTo(lightSources[sCount].x + m * lightSources[sCount].r, lightSources[sCount].y);
// draw the remaining points
for(var t:Number = 0; t < Math.PI * (8 / 4); t += Math.PI * (1 / 4)) {
lineTo( lightSources[sCount].x + Math.cos(t) * m * lightSources[sCount].r,
lightSources[sCount].y - Math.sin(t) * m * lightSources[sCount].r);
}
// draw the final point
lineTo(lightSources[sCount].x + m * lightSources[sCount].r, lightSources[sCount].y);
// complete rendering the fill of this value for this light source object
endFill();
}
}
}
}
};
function renderScene() {
// update position of terrain
terrain._x = (myRoot._xmouse) - (terrain._width / 2);
terrain._y = (myRoot._ymouse) - (terrain._height / 2);
// clean up the front buffer before capturing
// < comment out the clean up for some interesting residual imaging effects >
frontBufferData.fillRect(new Rectangle(0, 0, Stage.width, Stage.height), 0xff000000);
// apply blend modes...
switch(renderFlag) {
case 0:
// multiply, single pass lighting
frontBufferData.draw(world);
frontBufferData.draw(lighting, new Matrix(), new ColorTransform(), "multiply");
break;
case 1:
// render only the lighting data
frontBufferData.draw(lighting);
break;
case 2:
// render only the world
frontBufferData.draw(world);
break;
case 3:
// multiply, overlay, dual pass lighting
frontBufferData.draw(world);
frontBufferData.draw(lighting, new Matrix(), new ColorTransform(), "multiply");
frontBufferData.draw(lighting, new Matrix(), new ColorTransform(), "overlay");
break;
case 4:
// overlay, single pass lighting
frontBufferData.draw(world);
frontBufferData.draw(lighting, new Matrix(), new ColorTransform(), "overlay");
break;
case 5:
// hardlight, single pass lighting
frontBufferData.draw(world);
frontBufferData.draw(lighting, new Matrix(), new ColorTransform(), "hardlight");
break;
}
};
The foremost thing to notice in this demo is that the lightsources simulate blending when their gradient fills overlap. That is to say, values that are alike in adjacent gradients merge so that no gradient fills are superimposed on top of other gradient fills (darkest values in one covering up lightest values in another, etc.)
The principles of this demo are in the process of being converted over to a self-contained class and will not be so chunky in its final form.
The strange thing about this approach is that when Flash Player is rendering using high quality, artifacts start showing up in the final frame. I won't be using high quality, so this isn't an issue for me. All the same, does anybody know why those artifacts are happening?
Last edited by Q__Hybrid; 04-24-2007 at 02:45 AM.
Qwai•zang \kwî-'zan\ n [origin unknown] 1 : abstract designer, esp. of complex real-time experiments, c. 21st century
-
Pumpkin Carving 2008
Is there no way to gradiently blend each ring from the lightest value in the first ring, to the lightests color in the second? The concept is really cool, but the rings look slightly foolish. As I said, if you were able to blend each ring into the one larger than it, it would be really something...
The 'Boose':
ASUS Sabertooth P67 TUF
Intel Core i7-2600K Quad-Core Sandy Bridge 3.4GHz Overclocked to 4.2GHz
8GB G.Skill Ripjaws 1600 DDR3
ASUS ENGTX550 TI DC/DI/1GD5 GeForce GTX 550 Ti (Fermi) 1GB 1GDDR5 (Overclocked to 1.1GHz)
New addition: OCZ Vertex 240GB SATA III SSD
WEI Score: 7.6
-
M.D.
it nice, but very ugly looking, hows the performance with a higher poly count?
-
Please, Call Me Bob
oh thats right, i replaced my lava lamp with this bizarre thing:
http://trogdorffe.tripod.com/junk3.htm
-
Pumpkin Carving 2008
You're movie doesn't load, trog. And yes, I do have flash player 9.
The 'Boose':
ASUS Sabertooth P67 TUF
Intel Core i7-2600K Quad-Core Sandy Bridge 3.4GHz Overclocked to 4.2GHz
8GB G.Skill Ripjaws 1600 DDR3
ASUS ENGTX550 TI DC/DI/1GD5 GeForce GTX 550 Ti (Fermi) 1GB 1GDDR5 (Overclocked to 1.1GHz)
New addition: OCZ Vertex 240GB SATA III SSD
WEI Score: 7.6
-
Qwaizang:syntax_entity_
IP: I'm a little bit confused as to exactly what you're asking. Do you mean a blending of contour to create more of a "blob" pattern, or do you mean some sort of blending of colors that is different than the one I'm using?
This would require a bit more math and would slow down the framerate somewhat. However, I've already figured out most of the logic behind it in my head and I should really figure out just how much slower it actually runs, right? 
Malee: You're right that it does look choppy, but when it's blended into the final frame I really don't notice it that much. Using a series of curveTo() calls would help reduce the chunky look of it. When I get the "blob" version written the poly count will be 32 points per circle, not 8.
Qwai•zang \kwî-'zan\ n [origin unknown] 1 : abstract designer, esp. of complex real-time experiments, c. 21st century
-
Pumpkin Carving 2008
Use a gradient on the mask of the inner circle to meet the color of the next circle so that you have one continuous gradient instead of rings.
The 'Boose':
ASUS Sabertooth P67 TUF
Intel Core i7-2600K Quad-Core Sandy Bridge 3.4GHz Overclocked to 4.2GHz
8GB G.Skill Ripjaws 1600 DDR3
ASUS ENGTX550 TI DC/DI/1GD5 GeForce GTX 550 Ti (Fermi) 1GB 1GDDR5 (Overclocked to 1.1GHz)
New addition: OCZ Vertex 240GB SATA III SSD
WEI Score: 7.6
-
Qwaizang:syntax_entity_
IP: again you've lost me. Maybe a picture would help explain?
Back to code...
Qwai•zang \kwî-'zan\ n [origin unknown] 1 : abstract designer, esp. of complex real-time experiments, c. 21st century
-
Can't load the movie here either. If I load it in Safari it says that the swf is not found.
-
Zombie Coder
This is a good thread. Anybody else have some unusual techniques to get cool special effects on their movieclips?
-
Please, Call Me Bob
wont load? does this include the blob effect? ill just post the code then:
import flash.display.BitmapData;
import flash.filters.ColorMatrixFilter;
import flash.filters.BlurFilter;
import flash.geom.Point;
removeMovieClip(drawer);
if(bitmap==undefined){
var bitmap:BitmapData=new BitmapData(200,200,true,0xFF000000);
this.createEmptyMovieClip("bitmappy",this.getNextH ighestDepth());
bitmappy.attachBitmap(bitmap,this.getNextHighestDe pth(),"auto",true);
}
this.createEmptyMovieClip("drawer",-500);
drawer.lineStyle(19.5,0xFFFFFF-bitmap.getPixel(1,1));
drawer.beginFill(0,0);
drawer.moveTo(oldx,oldy);
drawer.lineTo(_root._xmouse,_root._ymouse);
drawer.endFill();
bitmap.draw(drawer);
var matrix:Array = new Array(2,0,0,0,-128,0,2,0,0,-128,0,0,2,0,-128,0,0,0,1.1,0);
var filter:BlurFilter= new BlurFilter(6,6,3);
var filter2:ColorMatrixFilter= new ColorMatrixFilter(matrix);
bitmap.applyFilter(bitmap,bitmap.rectangle,new Point(0,0),filter);
bitmap.applyFilter(bitmap,bitmap.rectangle,new Point(0,0),filter2);
var oldx:Number=_root._xmouse;
var oldy:Number=_root._ymouse;
its a two framer
EDIT: something wrong with this forum adds an extra space here and there, delete the one in getNextHighestDepth
Last edited by trogdor458; 04-26-2007 at 05:12 PM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|