In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Shadow casting test

shadow mapping test (warning: CPU killer)
Get Adobe Flash player
by makc3d 12 Mar 2009
package
{
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    import flash.geom.*;

    import sandy.core.*;
    import sandy.core.data.*;
    import sandy.core.scenegraph.*;
    import sandy.primitive.*;
    import sandy.materials.*;
    import sandy.materials.attributes.*;
    import sandy.view.*;

    // shadow mapping test (warning: CPU killer)

    [SWF (width=465, height=465, backgroundColor=0, frameRate=10)]
    public class Test extends BasicView
    {
        private const S:int = 150;
        private const Q:int = 10;
        private const Y:Number = 30;

        private var angle:Number = 0;
        private var texture:BitmapData;
        private var hmap:BitmapData, lmap:BitmapData, tmap:BitmapData;
        private var blur:BlurFilter = new BlurFilter (2, 2, 2);
        private var stmp:Shape = new Shape;

        public function Test()
        {
            super (); init (465, 465); render ();

            // planes suck - use hexagonal grid instead
            var p:Plane3D = addHorizontalPlane (S, S, Q,
                new Point3D (0, -0.6 * S, 0));
            texture = new BitmapData (S, S, false, 0);
            p.appearance = makeBitmapAppearance (texture);

            // engine light
            p.appearance.frontMaterial.attributes =
                new MaterialAttributes (new LightAttributes (false, 0.6));
            p.appearance.lightingEnable = true;

            // build random terrain
            // this is not really smooth terrain, but whatever
            var r:Number = 0;
            for each (var v:Vertex in p.geometry.aVertex) {
                //r = 0.5 * (r + Math.random ()); v.y = Y * r;
                if (Math.random () < 0.1) v.y = Y / 2;
            }

            // update face normals
            for each (var face:Polygon in p.aPolygons) face.updateNormal ();

            // render terrain heightmap
            renderHeightMap (p, graphics, S);
            hmap = new BitmapData (S, S, false, 0); hmap.draw (this);

            // noisy texture
            tmap = new BitmapData (S, S, false, 0);
            tmap.noise (123, 200, 255, 7, true);
            tmap.draw (tmap, null, new ColorTransform (1, 0xEF / 255.0, 0x7F / 255.0));

            // make light map
            lmap = new BitmapData (S, S, false, 0);
            var b:Bitmap = new Bitmap (lmap); b.x = S; addChild (b);

            // "sun"
            graphics.beginFill (0xFFEF7F); graphics.drawCircle (465 * 0.5, 465 * 0.5, 10);
        }

        override public function simpleRender(e:Event = null):void {
            // spin light (map coords)
            angle = mouseX / 100;
            var light:Point3D = new Point3D (Math.sin (angle), Math.cos (angle), 0.25); light.normalize ();

            // face light (real coords)
            camera.x = +2 * S * light.x;
            camera.y = +2 * S * light.z;
            camera.z = -2 * S * light.y;
            camera.lookAt (0, 0, 0);
            scene.light.setDirection (camera.x, -camera.y, camera.z);

            // re-build shadow map
            lmap.lock ();
            lmap.fillRect (lmap.rect, 0);
            var m:Number = 0; m1.identity (); 
            while (m < 255) { 
                m1.tx += light.x; m1.ty += light.y; m += 2; // TODO: m = f (light) 
                stmp.graphics.clear (); 
                stmp.graphics.beginBitmapFill (hmap, m1, true, true); 
                stmp.graphics.drawRect (0, 0, S, S); 
                stmp.graphics.endFill (); 
                lmap.draw (stmp, null, new ColorTransform (1, 1, 1, 1, -m, -m, -m), 
                    BlendMode.LIGHTEN, null, true); 
            } 
            lmap.draw (hmap, null, null, BlendMode.DIFFERENCE); 

            // transform into light map 
            lmap.draw (lmap, null, new ColorTransform ( -10, -10, -10, 1, 255, 255, 255)); 
            lmap.threshold (lmap, lmap.rect, lmap.rect.topLeft, "<", 0x808080, 0xFF404030, 0xFFFFFF); 
            lmap.threshold (lmap, lmap.rect, lmap.rect.topLeft, ">", 0x808080, 0xFFFFFFFF, 0xFFFFFF); 
            lmap.unlock ();

            lmap.applyFilter (lmap, lmap.rect, lmap.rect.topLeft, blur);
            texture.draw (tmap); texture.draw (lmap, null, null, BlendMode.MULTIPLY);

            super.simpleRender (e);
        }

        private function renderHeightMap (p:Plane3D, g:Graphics, s:int):void {
            for each (var t:Polygon in p.aPolygons)
                renderHeightMapElement (t, g, s);
        }

        private var m1:Matrix = new Matrix;
        private var m2:Matrix = new Matrix;
        private function renderHeightMapElement (t:Polygon, g:Graphics, s:int):void {
            var h0:Number = t.a.y / Y;
            var h1:Number = t.b.y / Y;
            var h2:Number = t.c.y / Y;

            var v0:Number = -100, v1:Number = 0, v2:Number = 100;
            var u0:Number = (h0 - 0.5) * (32768 * 0.05);
            var u1:Number = (h1 - 0.5) * (32768 * 0.05);
            var u2:Number = (h2 - 0.5) * (32768 * 0.05);

            var uv:UVCoord = UVCoord (t.aUVCoord [0]); m2.tx = uv.u * s; m2.ty = uv.v * s;

            if ( (int (u0 * 0.1) == int (u1 * 0.1)) && (int (u1 * 0.1) == int (u2 * 0.1)) ) {
                // solid color case
                g.beginFill ( 0x10101 * Math.round (0xFF * h0) );
            } else {
                // gradient case
                if ((u2 - u1) * (u1 - u0) > 0) {
                    var tmp:Number = v1; v1 = v2; v2 = tmp;
                }

                m1.a = u1 - u0; m1.b = v1 - v0;
                m1.c = u2 - u0; m1.d = v2 - v0;
                m1.tx = u0; m1.ty = v0;
                m1.invert ();

                uv = UVCoord (t.aUVCoord [1]);
                m2.a = uv.u * s - m2.tx; m2.b = uv.v * s - m2.ty;
                uv = UVCoord (t.aUVCoord [2]);
                m2.c = uv.u * s - m2.tx; m2.d = uv.v * s - m2.ty;
                m1.concat (m2);

                g.beginGradientFill ("linear", [0, 0xFFFFFF], [1, 1], [0, 255], m1);
            }
            g.moveTo (m2.tx, m2.ty); for each (uv in t.aUVCoord) g.lineTo (uv.u * s, uv.v * s);
            g.endFill ();
        }
    }
}