forked from: beedama-korokoro QB2D (forked from: beedama-korokoro)

by bradsedito forked from beedama-korokoro QB2D (forked from: beedama-korokoro) (diff: 594)
beedama-korokoro QuickBox2D ver.
displacement map filterの練習用
玉の屈折などは完全に擬似的なもの。雰囲気だけお楽しみください
遊び方:中心からのマウスの位置でその方向に重力発生
玉をクリックすると、その玉を放り出す
玉が無いところをクリックすると、玉の追加
[Z]でランダムなサイズで玉を生成するモードに切り替え
[X]で玉追加
2010.4.3 コメントアウトしていたコードを除去
2010.4.3 複数サイズの玉を出したさいの衝突判定バグ修正
2010.4.3 [Z]でランダムなサイズで玉を生成するモードに切り替え
2010.4.4 QuickBox2D対応:http://wonderfl.net/code/6985cefc26f6fa12b2da2487ddaa708b5e52408f
http://blog.alumican.net/2009/06/28_021753
を参考にしました
2010.4.4. サイズが小さい玉の屈折具合を強くした

...
@author TMaeda
♥1 | Line 543 | Modified 2010-10-03 02:47:53 | MIT License
play

ActionScript3 source code

/**
 * Copyright bradsedito ( http://wonderfl.net/user/bradsedito )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/5Ccd
 */

// forked from zendenmushi's beedama-korokoro QB2D (forked from: beedama-korokoro)
// beedama-korokoro QuickBox2D ver.

// displacement map filterの練習用
// 玉の屈折などは完全に擬似的なもの。雰囲気だけお楽しみください

// 遊び方:中心からのマウスの位置でその方向に重力発生
// 玉をクリックすると、その玉を放り出す
// 玉が無いところをクリックすると、玉の追加

// [Z]でランダムなサイズで玉を生成するモードに切り替え
// [X]で玉追加

// 2010.4.3 コメントアウトしていたコードを除去
// 2010.4.3 複数サイズの玉を出したさいの衝突判定バグ修正
// 2010.4.3 [Z]でランダムなサイズで玉を生成するモードに切り替え
// 2010.4.4 QuickBox2D対応:http://wonderfl.net/code/6985cefc26f6fa12b2da2487ddaa708b5e52408f
//                     http://blog.alumican.net/2009/06/28_021753
//                     を参考にしました
// 2010.4.4. サイズが小さい玉の屈折具合を強くした
package  
{
    import com.actionsnippet.qbox.QuickBox2D;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BitmapDataChannel;
    import flash.display.BlendMode;
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.filters.DisplacementMapFilter;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import frocessing.core.F5BitmapData2D;
    /**
     * ...
     * @author TMaeda
     */
    [SWF(width=465,height=465,backgroundColor=0xcccccc,frameRate=60)]
    public class BeedamaQB2D extends Sprite
    {
        private var displacement : BitmapData;
        
        private var wood2 : BitmapData;
        private var back : F5BitmapData2D;
        private var zeroPoint : Point = new Point(0,0);
        private var temppos : Point = new Point();
        private var displaceFilter : DisplacementMapFilter;
        private var mouseIsDown : Boolean = false;
        private var mouseClicked : Boolean = false;
        private var lastPoint : Point = new Point();
        private var randomSizeMode : Boolean = false;
        
        private var qb2 : QuickBox2D;
        private var captureBall : Tama = null;
        
        // 
        private var tamas : Vector.<Tama> = new Vector.<Tama>;
        private var freep : int = -1;
        private const itemlimit : int = 5000;
        
        
        public function BeedamaQB2D() 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        private function init(e:Event=null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            addEventListener(Event.ENTER_FRAME, enterFrame);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
            stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);

            var qb2mc : MovieClip = new MovieClip();
            addChild(qb2mc);
            qb2 = new QuickBox2D(qb2mc,{ debug:false});
            qb2mc.visible = false;
        
            var wood : BitmapData = new BitmapData(stage.stageWidth*2, stage.stageHeight*2);
            wood2 = new BitmapData(stage.stageWidth, stage.stageHeight);
            wood.perlinNoise(stage.stageWidth * 2, stage.stageHeight / 2, 2, 0, true, false,7,true);
            
            back = new F5BitmapData2D(stage.stageWidth, stage.stageHeight, true, 0);

            displacement = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x808080);
            displaceFilter = new DisplacementMapFilter(displacement,null,BitmapDataChannel.GREEN, BitmapDataChannel.BLUE,back.width/2, back.height/2);
            
            addChild(new Bitmap(back.bitmapData));
            
            wood2.lock();
            for (var y : int = 0; y < wood2.height; y++) {
                for (var x : int = 0; x < wood2.width; x++) {
                    var sum : Number = 0;
                    for (var i : int = 0; i < 4; i++) {
                        var g : Number = ((wood.getPixel32(x*2 + (i & 1), y*2 + (i >> 1)) & 0xff) / 256.0) * 20;
                        sum += (g - (g >> 0))*255;
                    }
                    
                    var col : int = (sum / 4+10)*256/(256+10);
                    col = 0xff000000 | ((col*0.2) << 0) | ((col*0.6) << 8) | (col << 16);
                    
                    wood2.setPixel32(x, y, col );
                    
                }
            }
            wood2.unlock();
            wood.dispose();
            
            randomSizeMode = true;
            qb2.addBox( {x:-16/30, y:0, width:32/30, height:stage.stageHeight*2/30, density:0} );
            qb2.addBox( {x:0, y:-16/30, width:stage.stageWidth/15, height:32/30, density:0} );
            qb2.addBox( {x:(stage.stageWidth+16)/30, y:0, width:32/30, height:stage.stageHeight*2/30, density:0} );
            qb2.addBox( {x:0, y:(stage.stageHeight+16)/30, width:stage.stageWidth*2/30, height:32/30, density:0} );
            qb2.start();

            clear();
            generateBalls(10);
            
        }
        
        private function keyDown(e:KeyboardEvent):void 
        {
            if (e.charCode == 122) {
                for (var i : int = freep; i >= 0; i--) {
                    dropBall(tamas[i]);
                }
                randomSizeMode = !randomSizeMode;
                generateBalls(10);
            } else if (e.charCode == 120) {
                newBall(stage.mouseX, stage.mouseY);            
            }
        }
        
        public function generateBalls(count : int) : void
        {
            for (var ball : int = 0 ; ball < count; ball++) {
                var tama : Tama = newBall(Math.random() * (stage.stageWidth - 10) + 5, Math.random() * (stage.stageHeight - 10) + 5);
            }
        }
        private function newBall(x : Number, y : Number) : Tama
        {
            var r : int = randomSizeMode ? Math.random() * 50 + 16 : 32;
            var tama : Tama = newItem(x, y, 0, 0, r, back);
            if (tama) {
                tama.qb2Object = qb2.addCircle( { "x":x/30, "y":y/30, "radius":r/30, isBullet:false, density:r*30 } );
                tama.image.rl.r = Math.random();
                tama.image.rl.g = Math.random();
                tama.image.rl.b = Math.random();
                tama.image.tcol.r = Math.random();
                tama.image.tcol.g = Math.random();
                tama.image.tcol.b = Math.random();
                tama.image.render(r, r, true);
            }
            return tama;
        }
        private function newItem(x : Number, y : Number , dx : Number, dy : Number, r : int, back : F5BitmapData2D ) : Tama
        {
            var cnt : int = tamas.length;
            if (((itemlimit > 0) && cnt >= itemlimit) && (freep >= cnt-1)) return null;
            
            freep++;

            if (freep == cnt) {
                tamas[cnt] = new Tama(r*2,r*2, back.bitmapData);
            } else {
                tamas[freep].regenerate(r*2,r*2, back.bitmapData);
            }
            tamas[freep].index = freep;
            tamas[freep].visible = true;
            tamas[freep].x = x;
            tamas[freep].y = y;
            tamas[freep].dx = dx;
            tamas[freep].dy = dy;
            tamas[freep].r = r;
            tamas[freep].drop = false;
            tamas[freep].dropstate = 0;
        
            return tamas[freep];
        }
        private function remove(index : int) : void
        {
            var cnt : int = tamas.length;
            var temp : Tama = tamas[index];
            var lastp : int = freep;

            if (temp.qb2Object) {
                temp.qb2Object.destroy();
                temp.qb2Object = null;
            }
            temp.visible = false;
            if (lastp != index) {
                tamas[index] = tamas[lastp];
                tamas[index].index = index;
                tamas[lastp] = temp;
            }
            freep = lastp - 1;
            
        }
        private function dropBall(tama : Tama) : void
        {
            tama.drop = true;
            /*
            if (tama.qb2Object) {
                tama.qb2Object.destroy();
                tama.qb2Object = null;
            }
            */
            tama.dx = tama.x+(tama.x < stage.stageWidth / 2 ? -Math.random()*64 : Math.random()*64);
            tama.dy = -128;
        }
        
        private function clear() : void
        {
            for (var i : int = freep; i >= 0; i--) {
                var tama : Tama = tamas[i];
                remove(i);
            }
        }
        
        private function mouseUp(e:MouseEvent):void 
        {
            mouseClicked = false;
            if (Math.abs(lastPoint.x - stage.mouseX) + Math.abs(lastPoint.y - stage.mouseY) < 8) {
                mouseClicked = true;
            }
            captureBall = null;
            mouseIsDown = false;
        }
        
        private function mouseDown(e:MouseEvent):void 
        {
            lastPoint.x = stage.mouseX;
            lastPoint.y = stage.mouseY;
            
            mouseIsDown = true;
        }
        private function enterFrame(e:Event):void 
        {
            var i : int;
            var tama : Tama, tama2 : Tama;
            var gx : Number = (stage.mouseX - stage.stageWidth / 2)/4;
            var gy : Number = (stage.mouseY - stage.stageHeight / 2)/4;
            var l : Number = Math.sqrt(gx * gx + gy * gy);
            var addflg : Boolean = mouseClicked;
            
            if (l > 0) {
                if (l >20) {
                    gx = (gx/l)*20;
                    gy = (gy/l)*20;
                }
            } else {
                gx = 0;
                gy = 0;
            }
            if ((qb2.gravity.x != gx) || (qb2.gravity.y != gy)) {
                qb2.gravity.x = gx;
                qb2.gravity.y = gy;
                // オブジェクトが一瞬でも静止すると、重力方向を変えても移動しなくなってしまう。FlashDevelopの補間機能でWakeupがそれっぽい
                // ので、とりあえずsleepingなオブジェクトをWakeupすることで解決
                for (i = freep; i >= 0; i--) {
                    tama = tamas[i];
                    if ((tama.qb2Object) && (tama.qb2Object.body.IsSleeping())) {
                        tama.qb2Object.body.WakeUp();
                    }
                }
            }

            back.bitmapData.copyPixels(wood2, wood2.rect, zeroPoint);
            
            for (i = freep; i >= 0; i--) {
                tama = tamas[i];
                var ax : Number = gx;
                var ay : Number = gy;
                
                var len : Number = Math.sqrt( (tama.x - stage.mouseX) * (tama.x - stage.mouseX) + (tama.y- stage.mouseY) * (tama.y - stage.mouseY));
                if (!tama.drop) {
                    if (mouseClicked || mouseIsDown) {
                        if (len < tama.r) {
                            if (!mouseIsDown) {
                                captureBall = null;
                                dropBall(tama);
                            } else {
                                if (!captureBall) captureBall = tama;
                            }
                            addflg = false;
                        }             
                    }
                    
                } else {
                    tama.x += (tama.dx - tama.x) / 16;
                    tama.y += (tama.dy - tama.y) / 4;
                    tama.dropstate++;
                    if (tama.dropstate > 16) remove(tama.index);
                    
                }
                
            }
            
            if (captureBall) {
                captureBall.qb2Object.x = (stage.mouseX) / 30;
                captureBall.qb2Object.y = (stage.mouseY) / 30;
            }
            
            
            back.beginDraw();
            back.stroke(0xff, 0xff, 0xff);
            back.moveTo(stage.stageWidth / 2, stage.stageHeight / 2);
            back.lineTo(stage.mouseX, stage.mouseY);
            back.endDraw();
            
            for (i = freep; i >= 0; i--) {
                tama = tamas[i];
                if (tama.qb2Object) {
                    if (!tama.drop) {
                        tama.x = tama.qb2Object.x * 30;
                        tama.y = tama.qb2Object.y * 30;
                    } else {
                        tama.qb2Object.x = tama.x / 30;
                        tama.qb2Object.y = tama.y / 30;
                    }
                }
                temppos.x = tama.x - tama.r/2;
                temppos.y = tama.y - tama.r/2;
                back.bitmapData.copyPixels(tama.image.shadowBmp, back.bitmapData.rect, temppos, tama.image.shadowBmp, null, true);
            }
            displacement.fillRect(displacement.rect, 0xff008080);
            for (i = freep; i >= 0; i--) {
                tama = tamas[i];
                temppos.x = tama.x-tama.r ;
                temppos.y = tama.y-tama.r ;
                displacement.copyPixels(tama.image.refractionBmp, tama.image.refractionBmp.rect, temppos, null, null, true);
            }
            back.bitmapData.applyFilter(back.bitmapData, back.bitmapData.rect, zeroPoint, displaceFilter);

            for (i = freep; i >= 0; i--) {
                tama = tamas[i];
                temppos.x = tama.x-tama.r;
                temppos.y = tama.y-tama.r;
                back.bitmapData.copyPixels(tama.image.layerBmp, tama.image.layerBmp.rect, temppos, null, null, true);
            }

            if (addflg) {
                newBall(stage.mouseX, stage.mouseY);
            }

            mouseClicked = false;
        }
        
        private function dist(a : Tama, b : Tama): Number
        {
            return Math.sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
        }
        
        public function computeUnitVector(x0 : Number, y0 : Number, x1 : Number, y1 : Number, /*out*/ u : Point) : Boolean
        {
            var len : Number = Math.sqrt( (y0 - y1) * (y0 - y1) + (x0 - x1) * (x0 - x1) );
            if (len > 0) {
                u.x = (x0 - x1) / len;
                u.y = (y0 - y1) / len;
                return true;
            } else return false;
        }

        public function dotProduct(x0 : Number, y0 : Number, x1 : Number, y1 : Number) : Number
        {
            return x0 * x1 + y0 * y1;
        }
        
        public function crossProductZ(x0 : Number, y0 : Number, x1 : Number, y1 : Number) : Number
        {
            return x0 * y1 - y0 * x1;
        }

        
    }
    
}
import com.actionsnippet.qbox.QuickObject;
import flash.display.Bitmap;
import flash.display.BlendMode;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.filters.BlurFilter;
import frocessing.core.F5BitmapData2D;
class Tama
{
    public var qb2Object : QuickObject;
    public var x : Number;
    public var y : Number;
    public var r : Number;
    public var dx : Number;
    public var dy : Number;

    public var index : int;
    public var visible : Boolean = false;
    public var drop : Boolean;
    public var dropstate : int;
    
    public var image : SphereRenderImage;
    
    public function Tama(width : int, height : int, back : BitmapData) 
    {
        regenerate(width, height, back);
    }
    
    public function regenerate(width : int, height : int, back : BitmapData) : void
    {
        image = new SphereRenderImage(width, height, back);
    }
}
class Point3D
{
    public var x : Number;
    public var y : Number;
    public var z : Number;
}
class Rgb 
{
    public var a : Number;
    public var r : Number;
    public var g : Number;
    public var b : Number;
    
    public function color(col : uint) : Rgb
    {
        a = (col >> 24) / 255;
        r = ((col >> 16) & 0xff) / 255;
        g = ((col >> 8) & 0xff) / 255;
        b = ((col >> 0) & 0xff) / 255;
        
        return this;
    }
    
    public static function pack32(r : Number, g : Number, b : Number, a : Number) : uint
    {
        return (Math.min(255, a * 255) << 24) | (Math.min(255, r * 255) << 16) | (Math.min(255, g * 255) << 8) | Math.min(255, b * 255);
    }
    
    public function color32() : uint
    {
        return pack32(r, g, b, a);
    }
    
}

class SphereShadow
{
    private var blur : BlurFilter = new BlurFilter(4, 4, 1);
    public  var shadowBmpData : BitmapData;
    private var zeroPoint : Point = new Point(0, 0);
    private var shape : Shape;
    
    public function SphereShadow(width : int, height : int)
    {
        shadowBmpData = new BitmapData(width, height, true, 0);
    }    
    
    public function render(col : uint) : void
    {
        var sp1 : Sprite = new Sprite();
        var g : Graphics = sp1.graphics;
        // shadow
        g.beginFill(0x000000, .6);
        g.drawCircle(shadowBmpData.width / 2, shadowBmpData.height / 2, shadowBmpData.width / 2);
        g.endFill();
        // caustics
        g.beginFill(col, .4);
        g.drawCircle(shadowBmpData.width*6 / 10, shadowBmpData.height*6 / 10, shadowBmpData.width / 8);
        g.endFill();
        shadowBmpData.draw(sp1);
        
        shadowBmpData.applyFilter(shadowBmpData, shadowBmpData.rect, zeroPoint, blur);
    }
}

import flash.display.BitmapData;
import flash.filters.DisplacementMapFilter;
import flash.geom.Point;

class SphereRenderImage
{
    private const PI : Number = 3.141592;
    private var width : int;
    private var height : int;
    private var radius : int;
    
    //private var blur : BlurFilter = new BlurFilter(4, 4, 1);
    private var zeroPoint : Point = new Point(0, 0);
    public  var layerBmp : BitmapData;
    public  var refractionBmp : BitmapData;
    public  var shadowBmp : BitmapData;
    private var backgroundBmp : BitmapData;
    private var diffuseBmp : BitmapData = null; // not use yet
    
    private var temppos : Point3D = new Point3D();
    private var dcol : Rgb = new Rgb();
    private var shadow : SphereShadow;

    
    public  var refraction : Number = 1.0;
    public  var shininess : Number = 1.0;
    public  var tcol : Rgb = new Rgb(); 
    public  var spec : Rgb = new Rgb(); 
    public  var amb : Rgb = new Rgb(); 
    public  var rl : Rgb = new Rgb(); 
    public  var bk : Rgb = new Rgb(); 
    
    
    public function SphereRenderImage(width : int, height : int, background : BitmapData) : void
    {
        this.width = width;
        this.height = height;
        this.radius = Math.min(width, height) / 2;
        
        backgroundBmp = background;
        
        layerBmp = new BitmapData(width, height, true, 0);
        refractionBmp = new BitmapData(width, height, true, 0);
        shadow = new SphereShadow(width, height);
        shadowBmp = shadow.shadowBmpData;
        
        spec.a = 1.0;
        spec.r = 1.0;
        spec.g = 1.0;
        spec.b = 1.0;

        amb.a = .0;
        amb.r = .0;
        amb.g = .0;
        amb.b = .0;
    }
    
    private function norm(x : Number, y : Number, z : Number ,/*out*/ o : Point3D) : void
    {
        var len : Number = Math.sqrt( x*x + y*y + z*z );
        o.x = x / len;
        o.y = y / len;
        o.z = z / len;
    }

    
    public function render(posx : int, posy : int, use_displace : Boolean = false) : void
    {
        shadow.render(rl.color32());
        if (use_displace) refractionBmp.lock();
        layerBmp.lock();
        var cx : int = Math.min( width, height )/2;
        var cy : int = Math.min( width, height )/2;

        var rr : Number = radius;
        var tr : int = rr >> 0;

        var tr_xscale : Number =  4;// backgroundBmp.width / 32;// width;
        var tr_yscale : Number =  4;// backgroundBmp.height / 32;// height;
        
        for (var i : int = 0; i < tr * 2 ; i++) {
            
            var rad1 : Number = Math.acos( ((tr-i)/tr) );
            var spanr : Number = Math.sin( rad1 ) * rr - 1;
            var y : Number = (tr-i);

            for (var j : int = 0; j < tr * 4 -1; j++) {
                var rad2 : Number = (j / rr)*PI/4;
                var x : Number = Math.cos( rad2 ) * spanr;
                var z : Number = Math.sin( rad2 ) * spanr;

                norm(0 - x, 0 - y, rr*10 - z, temppos);
                var ex : Number = temppos.x;
                var ey : Number = temppos.y;
                var ez : Number = temppos.z;

                norm(rr*10 - x,rr*10 - y,rr*10 - z, temppos);
                var lx : Number = temppos.x;
                var ly : Number = temppos.y;
                var lz : Number = temppos.z;

                norm(ex+lx,ex+lx,ex+lx, temppos);
                var hx : Number = temppos.x;
                var hy : Number = temppos.y;
                var hz : Number = temppos.z;

                norm(x,y,z, temppos);
                var nx : Number = temppos.x;
                var ny : Number = temppos.y;
                var nz : Number = temppos.z;

                var dr : Number = 0, dg : Number = 0 , db : Number = 0;
                if (diffuseBmp) {
                    col = diffuseBmp.getPixel32( diffuseBmp.width * ((rad2 / PI / 1 )) , diffuseBmp.height * (rad1 / PI / 1 ));
                    dcol.color(col);
                    dcol.r = dcol.r * dr;
                    dcol.g = dcol.g * dg;
                    dcol.b = dcol.b * db;
                } else {
                    dcol.r = dr;
                    dcol.g = dg;
                    dcol.b = db;
                }

                var tx : int = x;
                var px : int = (cx - tr) + tr - tx;
                var py : int = (cy - tr + i);
                
                if ((tcol.r != 0.0) || (tcol.g != 0.0) || (tcol.b != 0.0)) {
                    var cosa : Number = nx * 0 + ny * 0 + nz * 1;
                    var tr_u : Number, tr_v : Number;
                    if (cosa != 0) tr_u = nx / cosa; else tr_u = 0;
                    if (cosa != 0) tr_v = ny / cosa; else tr_v = 0;

                    var tr_x : int = (backgroundBmp.width + ((cx+posx+tr_u*tr*refraction)*tr_xscale) >> 0) % backgroundBmp.width;
                    if (tr_x < 0) tr_x = 0;

                    var tr_y : int = (backgroundBmp.height + ((cy+posy+tr_v*tr*refraction)*tr_yscale) >> 0) % backgroundBmp.height;
                    if (tr_y < 0) tr_y = 0;

                    cosa = 1-cosa;
                    var reflection : Number = (1-0.2)*cosa;//0.0 + (1-0.0)*cosa*cosa*cosa*cosa*cosa; // fresnel

                    // pseudo refraction! not real! but look like
                    if (use_displace) {
                        var  tu : int = Math.max(Math.min(255, (tr_u*tr*refraction*tr_xscale/backgroundBmp.width)*128 + 128), 0);
                        var  tv : int = Math.max(Math.min(255, (tr_v*tr*refraction*tr_yscale/backgroundBmp.height)*128 + 128), 0);
                        refractionBmp.setPixel32(px, py, 0xff000000 | (tu << 8) | (tv));
                        dcol.r = (1-rl.r*reflection)*(dcol.r*(1-tcol.r)) + rl.r*reflection*1;
                        dcol.g = (1-rl.g*reflection)*(dcol.g*(1-tcol.g)) + rl.g*reflection*1;
                        dcol.b = (1-rl.b*reflection)*(dcol.b*(1-tcol.b)) + rl.b*reflection*1;
                    } else {
                        if (tr_y < backgroundBmp.height) {
                            col = backgroundBmp.getPixel32(tr_x, tr_y);
                            bk.color(col);
                            dcol.r = (1-rl.r*reflection)*(dcol.r*(1-tcol.r)+bk.r*tcol.r) + rl.r*reflection*1;
                            dcol.g = (1-rl.g*reflection)*(dcol.g*(1-tcol.g)+bk.g*tcol.g) + rl.g*reflection*1;
                            dcol.b = (1-rl.b*reflection)*(dcol.b*(1-tcol.b)+bk.b*tcol.b) + rl.b*reflection*1;
                        } else {
                            dcol.r = tcol.r;
                            dcol.g = tcol.g;
                            dcol.b = tcol.b;
                        }
                    }
                }
                
                var dot1 : Number;

                if ((tcol.r != 0.0) || (tcol.g != 0.0) || (tcol.b != 0.0)) {
                    dot1 = Math.max(1, Math.abs(lx*nx + ly*ny + lz*nz));
                } else {
                    dot1 = Math.max(0, lx*nx + ly*ny + lz*nz);
                }
                var kpow : Number = (shininess*128);
                var dot2 : Number = Math.pow(Math.max(0, hx*nx + hy*ny + hz*nz), kpow);

                var col : uint;
                
                if (use_displace) {
                    col = Rgb.pack32(dot2*spec.r + dot1 * dcol.r + amb.r, dot2*spec.g + dot1 * dcol.g + amb.g, dot2*spec.b + dot1 * dcol.b + amb.b, dot2*spec.a+dot1*Math.max(dcol.r, dcol.g, dcol.b) );
                } else {
                    col = Rgb.pack32(dot2 * spec.r + dot1 * dcol.r + amb.r,  dot2 * spec.g + dot1 * dcol.g + amb.g, dot2 * spec.b + dot1 * dcol.b + amb.b, 1 );
                }

                if ((px >= 0) && (px < width) && (py >= 0) && (py < height)) {
                    layerBmp.setPixel32(px, py, col);
                }
            }
        }
        layerBmp.unlock();
        if (use_displace) {
            //refractionBmp.applyFilter(refractionBmp, refractionBmp.rect, zeroPoint, blur);
            refractionBmp.unlock();
        }
    }
}