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

Clear Water [Stage3D version]

Clear Water [FlashPlayer10 version] http://wonderfl.net/c/9R8a
Simple usage of fragment shader for dual textures.
blog; 技術概要説明:http://d.hatena.ne.jp/keim_at_Si/20110418/p1
webpage; http://soundimpulse.sakura.ne.jp/clear-water-with-refraction-rendering/
/**
 * Copyright keim_at_Si ( http://wonderfl.net/user/keim_at_Si )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/enj6
 */

// forked from keim_at_Si's Clear Water with refraction rendering forked from: 3D水面 / Water 3D
// forked from saharan's 3D水面 / Water 3D
package {
    import flash.system.LoaderContext;
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.text.*;
    import flash.net.*;
    import com.bit101.components.*;
    import net.hires.debug.*;
    
    import com.adobe.utils.*;
    import flash.display3D.*;
    import flash.display3D.textures.*;
    //import org.si.ptolemy.*;

    public class main extends Sprite {
        private const NUM_DETAILS:int = 48;
        private const INV_NUM_DETAILS:Number = 1 / NUM_DETAILS;
        private const MESH_SIZE:Number = 100;
        private const SURFACE_DETAILS:int = NUM_DETAILS-4;
        private const VCOUNT:int = SURFACE_DETAILS * SURFACE_DETAILS;
        private const VBUFFER_SIZE:int = 9;
        private var count:uint;
        private var bmd:BitmapData, bmd2:BitmapData;
        private var loader:Loader, loader2:Loader;
        private var vertices:Vector.<Number>;
        private var transformedVertices:Vector.<Number>;
        private var indices:Vector.<int>;
        private var uvt:Vector.<Number>, uvt2:Vector.<Number>;
        private var heights:Vector.<Number>;
        private var velocity:Vector.<Number>;
        
/*      // for local
        private var refractionTexture:String = "_env1.png";
        private var reflectionTexture:String = "_env2.png";
/*/     // for wonderfl
        private var refractionTexture:String = "http://assets.wonderfl.net/images/related_images/b/b2/b217/b2177f87d979a28b9bcbb6e0b89370e77ce22337";
        private var reflectionTexture:String = "http://assets.wonderfl.net/images/related_images/b/bb/bbf1/bbf12c60cf84e5ab43e059920783d036da25df48";
//*/
        private var container:Sprite;
        private var viewedAngleH:Number = 0;
        private var viewedAngleV:Number = -20 * 0.017453292519943295;
        private var rotH:Number = 0, rotV:Number = 0;
        private var cameraDistance:Number = MESH_SIZE;
        private var focalLength:Number = MESH_SIZE * 4;
        private var boxHeight:Number = MESH_SIZE*0.75;
        private var refractiveIndex:Number = 1.4;
        private var reflectionRatio:Number = 0.4;
        
        private var cameraPosition:Vector3D = new Vector3D();

        // molehill
        private var ptolemy:TinyPtolemy;
        private var projectionMatrix:PerspectiveMatrix3D = new PerspectiveMatrix3D();
        private var modelviewMatrix:Matrix3D = new Matrix3D();
        private var matrix3D:Matrix3D = new Matrix3D();
        
        private var vertexBuffer:VertexBuffer3D;
        private var normalBuffer:VertexBuffer3D;
        private var indexBuffer:IndexBuffer3D;
        private var program:Program3D;
        private var tex:Texture, tex2:Texture;
        private var asm:AGALMiniAssembler = new AGALMiniAssembler();
        

        
        
    //-------------------------------------------------- constructor
        function main() : void {
            Wonderfl.disable_capture();
            // create surface
            var i:int, j:int, idx:int;
            vertices = new Vector.<Number>(VCOUNT * VBUFFER_SIZE, true);
            transformedVertices = new Vector.<Number>(VCOUNT * 2, true);
            uvt = new Vector.<Number>(VCOUNT * 2, true);
            uvt2 = new Vector.<Number>(VCOUNT * 2, true);
            for (i = 0; i < VCOUNT; i++) {
                vertices[i*VBUFFER_SIZE]   = ((int(i/SURFACE_DETAILS)+2) * INV_NUM_DETAILS - 0.5) * MESH_SIZE;
                vertices[i*VBUFFER_SIZE+1] = ((int(i%SURFACE_DETAILS)+2) * INV_NUM_DETAILS - 0.5) * MESH_SIZE;
                vertices[i*VBUFFER_SIZE+2] = 0;
            }
            indices = new Vector.<int>();
            for (i=1; i<SURFACE_DETAILS; i++) for (j=1; j<SURFACE_DETAILS; j++) {
                idx = j * SURFACE_DETAILS + i;
                indices.push(idx-SURFACE_DETAILS-1, idx-SURFACE_DETAILS, idx, 
                             idx-SURFACE_DETAILS-1, idx, idx-1);
            }
            
            // create field
            heights = new Vector.<Number>(NUM_DETAILS * NUM_DETAILS, true);
            velocity = new Vector.<Number>(NUM_DETAILS * NUM_DETAILS, true);
            for (i = 0; i < NUM_DETAILS * NUM_DETAILS; i++) velocity[i] = heights[i] = 0;
            
            addEventListener(Event.ADDED_TO_STAGE, setup);
        }

        private function setup(e:Event) : void {
            e.target.removeEventListener(e.type, arguments.callee);
            // load resource
            ptolemy = new TinyPtolemy(this, 8, 8, 450, 450);
            ptolemy.addEventListener(Event.CONTEXT3D_CREATE, loaded);
            loader = new Loader();
            loader.load(new URLRequest(refractionTexture), new LoaderContext(true));
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
            loader2 = new Loader();
            loader2.load(new URLRequest(reflectionTexture), new LoaderContext(true));
            loader2.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
        }
        
        private function loaded(e:Event) : void {
            e.target.removeEventListener(e.type, arguments.callee);
            if (loader.content && loader2.content && ptolemy.context3D) {
                bmd  = Bitmap(loader.content).bitmapData;
                bmd2 = Bitmap(loader2.content).bitmapData;
                
                // setup buffers
                var uindices:Vector.<uint> = new Vector.<uint>(indices.length, true);
                for (var i:int=0; i<uindices.length; i++) uindices[i] = indices[i];
                vertexBuffer = ptolemy.context3D.createVertexBuffer(VCOUNT, VBUFFER_SIZE);
                indexBuffer = ptolemy.context3D.createIndexBuffer(uindices.length);
                indexBuffer.uploadFromVector(uindices, 0, uindices.length);
                program = ptolemy.context3D.createProgram();
                program.upload(asm.assemble("vertex", vs), asm.assemble("fragment", fs));
                
                // setup textures
                tex = ptolemy.context3D.createTexture(512, 512, "bgra", false);
                tex.uploadFromBitmapData(bmd);

                tex2 = ptolemy.context3D.createTexture(512, 512, "bgra", false);
                tex2.uploadFromBitmapData(bmd2);

                
                projectionMatrix.perspectiveFieldOfViewLH(60/180*3.141592653589793, 1, 1, 200);
                
                addChild(container = new Sprite());
                container.x = container.y = 8;
                container.graphics.beginFill(0);
                container.graphics.drawRect(0,0,180,78);
                container.graphics.endFill();
                new HUISlider(container, 0,  0, "Angle", function(e:Event):void { viewedAngleV = -e.target.value*0.017453292519943295;}).setSliderParams(0, 80, 20);
                new HUISlider(container, 0, 20, "Rotation", function(e:Event):void { viewedAngleH = -e.target.value*0.017453292519943295;}).setSliderParams(-180, 180, 0);
                new HUISlider(container, 0, 40, "Refraction", function(e:Event):void { refractiveIndex = e.target.value;}).setSliderParams(1, 3, 1.4);
                new HUISlider(container, 0, 60, "Reflection", function(e:Event):void { reflectionRatio = e.target.value;}).setSliderParams(0, 1, 0.4);
                var driverInfo:TextField = new TextField();
                driverInfo.textColor = 0xffffff;
                driverInfo.width = 450;
                driverInfo.y = 435;
                driverInfo.text = ptolemy.context3D.driverInfo;
                container.addChild(driverInfo);
                addAllEventListeners();
            }
        }
        
        private function addAllEventListeners() : void {
            // add all listeners     
            stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
            addEventListener(Event.ENTER_FRAME, frame);
            count = 0;
        }
        
    //-------------------------------------------------- events
        private function mouseDown(e:MouseEvent) : void {
            stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseDrag);
            ripple((232.5 - mouseY) / 465, (mouseX -232.5) / 465, 20);
        }
        
        private function mouseUp(e:MouseEvent) : void {
            stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUp);
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseDrag);
        }
        
        private function mouseDrag(e:MouseEvent) : void {
            ripple((232.5 - mouseY) / 465, (mouseX -232.5) / 465, 3);
        }
        
        private function ripple(mx:Number, my:Number, intensity:Number) : void {
            var i:int, j:int, idx:int, dx:Number, dy:Number, acc:Number, imin:int, jmin:int, imax:int, jmax:int,
                sin:Number = Math.sin(viewedAngleH), cos:Number = Math.cos(viewedAngleH);
            dx =  mx * cos + my * sin;
            dy = -mx * sin + my * cos;
            mx = (dx + 0.5) * NUM_DETAILS;
            my = (dy + 0.5) * NUM_DETAILS;
            imin = (mx > 5) ? int(mx - 3) : 2;
            jmin = (my > 5) ? int(my - 3) : 2;
            imax = (mx < NUM_DETAILS-5) ? int(mx + 4) : (NUM_DETAILS - 1);
            jmax = (my < NUM_DETAILS-5) ? int(my + 4) : (NUM_DETAILS - 1);
            for (i=imin; i<imax; i++) for (j=jmin; j<jmax; j++) {
                dx = mx - i;
                dy = my - j;
                acc = 3 - Math.sqrt(dx * dx + dy * dy);
                if (acc > 0) velocity[j*NUM_DETAILS+i] += acc*intensity;
            }
        }
        
    //-------------------------------------------------- on each frame
        private function frame(e:Event = null):void {
            count++;
            move();
            setMesh();
            molehill_draw();
        }

        private function move():void {
            // ---Water simulation---
            var i:int, j:int, idx:int, v:Number, imax:int, jmax:int;
            imax = jmax = NUM_DETAILS - 1;
            for (i=1; i<imax; i++) for (j=1; j<jmax; j++) {
                idx = j * NUM_DETAILS + i;
                heights[idx] += velocity[idx];
                if (heights[idx] > 100) heights[idx] = 100;
                else if (heights[idx] < -100) heights[idx] = -100;
            }
            for (i=1; i<imax; i++) for (j=1; j<jmax; j++) {
                idx = j * NUM_DETAILS + i;
                v = -heights[idx] * 4; idx-=NUM_DETAILS;
                v += heights[idx];     idx+=NUM_DETAILS-1;
                v += heights[idx];     idx+=2;
                v += heights[idx];     idx+=NUM_DETAILS-1;
                v += heights[idx];     idx-=NUM_DETAILS;
                velocity[idx] = (velocity[idx] + v * 0.5) * 0.9;
            }
            
            // change view
            /*
            var targetAngleH:Number = (mouseX -232.5) / 465 * 40 * 0.017453292519943295,
                targetAngleV:Number = -((mouseY -232.5) / 465 * 40 + 40) * 0.017453292519943295;
            rotH += (targetAngleH - viewedAngleH) * 0.01;
            rotV += (targetAngleV - viewedAngleV) * 0.01;
            viewedAngleH += (rotH *= 0.9);
            viewedAngleV += (rotV *= 0.9);
            */
            modelviewMatrix.identity();
            modelviewMatrix.prependTranslation(0, 0, cameraDistance);
            modelviewMatrix.prependRotation(-viewedAngleV*57.29577951308232, Vector3D.X_AXIS);
            modelviewMatrix.prependRotation(-viewedAngleH*57.29577951308232, Vector3D.Z_AXIS);
            _invmat.copyFrom(modelviewMatrix);
            _invmat.invert();
            _invmat.copyColumnTo(3, cameraPosition);
        }
        private var _invmat:Matrix3D = new Matrix3D();

        private function setMesh():void {
            var i:int, j:int, index:int, len:Number, u:Number, v:Number,
                t:Number, s:Number, r:Number, hitz:Number, sign:Number,
                vx:Number, vy:Number, vz:Number, 
                nx:Number, ny:Number, nz:Number, 
                dx:Number, dy:Number, dz:Number, 
                rimo:Number = refractiveIndex - 1,
                xymax:Number = MESH_SIZE * 0.45, //MESH_SIZE * 0.5,
                ixymax:Number = 1 / xymax;
            
            for (i = 0; i < SURFACE_DETAILS; i++) {
                for (j = 0; j < SURFACE_DETAILS; j++) {
                    index = (j * SURFACE_DETAILS + i) * VBUFFER_SIZE;
                    len = heights[(j+2)*NUM_DETAILS+i+2];
                    vx = vertices[index]; index++;
                    vy = vertices[index]; index++;
                    vz = vertices[index] = len * 0.25; index++;
                    
                    // Sphere map
                    nx = (len - heights[(j+2)*NUM_DETAILS+i+1]) * 0.25;
                    ny = (len - heights[(j+1)*NUM_DETAILS+i+2]) * 0.25;
                    nz = 1 / Math.sqrt(nx * nx + ny * ny + 1);
                    nx *= nz;
                    ny *= nz;
                    
                    // Refraction map
                    // incident vector (you can calculate them in the setup if you want faster)
                    dx = vx - cameraPosition.x;
                    dy = vy - cameraPosition.y;
                    dz = vz - cameraPosition.z;
                    len = 1 / Math.sqrt(dx * dx + dy * dy + dz * dz);
                    dx *= len;
                    dy *= len;
                    dz *= len;
                    // output vector
                    t = (dx * nx + dy * ny + dz) * rimo;
                    dx += nx * t;
                    dy += ny * t;
                    dz += nz * t;
                    // uv coordinate
                    if (dx == 0) {
                        if (dy == 0) {
                            u = v = 0.5;
                            sign = 0;
                        } else sign = (dy < 0) ? -1 : 1;
                    } else {
                        sign = (dx < 0) ? -1 : 1;
                        t = (sign * xymax - vx) / dx;
                        s = t * dy + vy;
                        if (-xymax < s && s < xymax) {
                            hitz = t * dz + vz;
                            if (hitz > boxHeight) {
                                r = (boxHeight-vz) / dz;
                                u = (dx * r + vx) * ixymax * 0.25 + 0.5;
                                v = (dy * r + vy) * ixymax * 0.25 + 0.5;
                            } else {
                                r = boxHeight / (hitz + boxHeight);
                                u = sign       * r * 0.5 + 0.5;
                                v = s * ixymax * r * 0.5 + 0.5;
                            }
                            sign = 0;
                        } else sign = (dy < 0) ? -1 : 1;
                    }
                    if (sign != 0) {
                        t = (sign * xymax - vy) / dy;
                        s = t * dx + vx;
                        hitz = t * dz + vz;
                        if (hitz > boxHeight) {
                            r = (boxHeight-vz) / dz;
                            u = (dx * r + vx) * ixymax * 0.25 + 0.5;
                            v = (dy * r + vy) * ixymax * 0.25 + 0.5;
                        } else {
                            r = boxHeight / (hitz + boxHeight);
                            u = s * ixymax * r * 0.5 + 0.5;
                            v = sign       * r * 0.5 + 0.5;
                        }
                    }
                    // set vertices
                    vertices[index] = nx * 0.5 + 0.5 + ((i - NUM_DETAILS * 0.5) * INV_NUM_DETAILS * 0.25); index++;
                    vertices[index] = ny * 0.5 + 0.5 + ((NUM_DETAILS * 0.5 - j) * INV_NUM_DETAILS * 0.25); index++;
                    vertices[index] = u; index++;
                    vertices[index] = v;
                }
            }
        }
        
        
        private function molehill_draw() : void {
            var context3D:Context3D = ptolemy.context3D;
            context3D.clear(0.2, 0.2, 0.2, 1);
            matrix3D.copyFrom(projectionMatrix);
            matrix3D.prepend(modelviewMatrix);
            
            vertexBuffer.uploadFromVector(vertices, 0, VCOUNT);
            context3D.setDepthTest(true, "less");
            context3D.setProgram(program);
            context3D.setTextureAt(0, tex);
            context3D.setTextureAt(1, tex2);
            context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
            context3D.setVertexBufferAt(1, vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_2);
            context3D.setVertexBufferAt(2, vertexBuffer, 5, Context3DVertexBufferFormat.FLOAT_2);
            context3D.setProgramConstantsFromMatrix("vertex", 0, matrix3D, true);
            context3D.setProgramConstantsFromVector("vertex", 9, Vector.<Number>([0,0.5,1,2]));
            context3D.setProgramConstantsFromVector("fragment", 0, Vector.<Number>([reflectionRatio,1-reflectionRatio,0,1]));
            context3D.drawTriangles(indexBuffer, 0, indices.length/3);
            
            context3D.present();
        }
    }
}

var vs:String = <agalCode><![CDATA[
mov vt0.xyz, va0.xyz
mov vt0.w, vc9.z
m44 op, vt0, vc0
mov v0, va1
mov v1, va2
]]></agalCode>;

var fs:String = <agalCode><![CDATA[
tex ft0, v0.xy, fs0 <2d,clamp,nearest>
tex ft1, v1.xy, fs1 <2d,clamp,nearest>
mul ft0, ft0, fc0.x
mul ft1, ft1, fc0.y
add oc, ft0, ft1
]]></agalCode>;




import flash.events.*;
import flash.display.*;
import flash.display3D.*;

class TinyPtolemy extends EventDispatcher {
    public var context3D:Context3D;
    
    function TinyPtolemy(parent:DisplayObjectContainer, xpos:Number, ypos:Number ,width:int, height:int) : void {
        var stage:Stage = parent.stage, stage3D:Stage3D = stage.stage3Ds[0];
        stage.scaleMode = StageScaleMode.NO_SCALE;
        stage.align = StageAlign.TOP_LEFT;
        stage.quality = StageQuality.LOW;
        stage3D.x = xpos;
        stage3D.y = ypos;
        stage3D.addEventListener(Event.CONTEXT3D_CREATE, function(e:Event):void{
            context3D = e.target.context3D;
            if (context3D) {
                context3D.enableErrorChecking = false;                  // check internal error
                context3D.configureBackBuffer(width, height, 0, true);  // disable AA/ enable depth/stencil
                context3D.setRenderToBackBuffer();
                context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);
                context3D.setCulling(Context3DTriangleFace.BACK);         // culling back face
                dispatchEvent(e.clone());
            } else {
                dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, "Context3D not found"));
            }
        });
        stage3D.requestContext3D();
    }
}