先人たちの知恵


この手のネタって,まだCPUが全然遅かった時代に,創意と工夫で,
かなりのことをやってきてたと思う.
自分はプログラム歴がかなり短いので,そういうのをあんまり知らないんだけど,
メガデモとかをやってた人ってそこら辺の知識が半端無いんじゃないかなと思う.
そういう時代の技術を色々知りたいなって,AS3やってて思った.


以下ソースコード
ライセンスはPublicDomain
id:keim_at_si:20071005辺りの高速化はこれにも使えるんだけど,
見通しが悪くなるので,やってないです.

//----------------------------------------
// 2D metaball + fire rendering
//  written by keim +Si+
//  licence: PD
//----------------------------------------
package {
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.filters.*;
    import flash.text.*;
    
    [SWF(width="240", height="240", backgroundColor="#406080", frameRate=30)]
    public class main_fire extends Sprite
    {
        static private const COOLING_MAP_SPEED:int = 7;
        static private const FIRE_MAP_SPEED:int = 4;
        
        static public  var base:BitmapData;     // base image
        static private var temp:BitmapData;     // tempolaly
        static private var fire_map:BitmapData;         // fire_map
        static private var cooling_map:BitmapData;      // cooling_map
        static private var cooling_elem:BitmapData;     // cooler
        static private var pixels:BitmapData;   // displaying image
        static private var screen:Bitmap;       // displaying image
        static private var balls:Array;         // meta-balls array
        
        static private var mat:Matrix = new Matrix();       // multipurpose
        static private var rct:Rectangle;                   // multipurpose

        static private var ptBallsCenter:Point = new Point();   // balls center position
        static private var matFace:Matrix = new Matrix();       // face matrix

        static private var cnvb:ConvolutionFilter;  // convolution filter for fire spreading
        static private var fireR:Array;     // fire coloring
        static private var fireG:Array;     // fire coloring
        static private var fireB:Array;     // fire coloring
        
        static private var face:BitmapData;     // face image 
        
        public function main_fire()
        {
            var i:int;
            
            var shp:Shape = new Shape();

            // bitmaps
            base   = new BitmapData(240, 240, false);
            temp   = new BitmapData(240, 240, false);
            pixels = new BitmapData(240, 240, false);
            screen = new Bitmap(pixels);
            
            // create filter instance
            cnvb = new ConvolutionFilter(3, 3, [0,1,0,1,0,1,0,1,0], 4, 0);
            
            // maps
            fire_map  = new BitmapData(240, 240, false, 0);
            cooling_map = new BitmapData(240, 320, false, 0xffffff);
            cooling_elem = new BitmapData(64, 64, false);
            mat.createGradientBox(64,64,0,0,0);
            shp.graphics.clear();
            shp.graphics.beginGradientFill(GradientType.RADIAL, [0x000000,0xffffff], [1,1], [0,255], mat);
            shp.graphics.drawRect(0,0,64,64);
            shp.graphics.endFill();
            cooling_elem.draw(shp);
            var colt:ColorTransform = new ColorTransform();
            for (i=0; i<240; i+=4) {
                mat.identity();
                mat.translate(Math.random()*240, i);
                var cooling:Number = Math.random() * 0.3;
                colt.redMultiplier = colt.greenMultiplier = colt.blueMultiplier = cooling;
                colt.redOffset = colt.greenOffset = colt.blueOffset = (1-cooling)*255;
                cooling_map.draw(cooling_elem, mat, colt, BlendMode.MULTIPLY);
            }
            rct = new Rectangle(0,316,240,4);
            
            // fire coloring
            var fire_grad:BitmapData = new BitmapData(256,1,false);
            mat.createGradientBox(256,1,0,0,0);
            shp.graphics.clear();
            shp.graphics.beginGradientFill(GradientType.LINEAR, [0x000000,0x800000,0xf0c040,0xffffff], [1,1,1,1], [0,160,224,255], mat);
            shp.graphics.drawRect(0,0,256,1);
            shp.graphics.endFill();
            fire_grad.draw(shp);
            fireR = new Array(256);
            fireG = new Array(256);
            fireB = new Array(256);
            for (i=0; i<256; i++) {
                var col:uint = fire_grad.getPixel(i,0);
                fireR[i] = col & 0xff0000;
                fireG[i] = col & 0x00ff00;
                fireB[i] = col & 0x0000ff;
            }
            fire_grad.dispose();
            
            // draw meta-ball gradation
            ball.pat = new BitmapData(ball.R*2,ball.R*2,false,0);
            mat.createGradientBox(ball.R*2,ball.R*2,0,0,0);
            shp.graphics.clear();
            shp.graphics.beginGradientFill(GradientType.RADIAL, [0x808080,0x000000], [1,1], [0,255], mat);
            shp.graphics.drawRect(0,0,ball.R*2,ball.R*2);
            shp.graphics.endFill();
            base.draw(shp);
            base.draw(shp, null, null, BlendMode.MULTIPLY);
            var blr:BlurFilter = new BlurFilter(16, 16);
            ball.pat.applyFilter(base, ball.pat.rect, ball.pat.rect.topLeft, blr);

            // draw face
            face = new BitmapData(48, 16, true, 0x00000000);
            var tf:TextField = new TextField();
            tf.width = 48;
            tf.height = 16;
            tf.defaultTextFormat = new TextFormat("MS Gothic", 12, 0x000000, null, null, null, null, null, TextFormatAlign.CENTER);
            tf.text = "o゚ω゚o";
            face.draw(tf);
            
            // create ball instance
            balls = new Array(16);
            for (i=0; i<balls.length; i++) { balls[i] = new ball(); }

            // set sprite/event
            addChild(screen);
            stage.quality   = StageQuality.HIGH;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align     = StageAlign.TOP_LEFT;
            stage.doubleClickEnabled = true;
            stage.addEventListener(Event.ENTER_FRAME, _onEnterFrame);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, _onMouseDown);
            stage.addEventListener(MouseEvent.MOUSE_UP,   _onMouseUp);
            stage.addEventListener(MouseEvent.DOUBLE_CLICK, _onDoubleClick);
        }

        
        private function _onEnterFrame(event:Event) : void
        {
            var i:int, j:int;
            
            // execute
            ball.mouseX = mouseX;
            ball.mouseY = mouseY;
            for (i=0; i<balls.length; i++) { ball(balls[i]).gravity(); }
            for (i=0; i<balls.length-1; i++) for (j=i+1; j<balls.length; j++) { ball(balls[i]).interact(ball(balls[j])); }
            for (i=0; i<balls.length; i++) { ball(balls[i]).run(); }
            calcBallCenter();
            
            // draw
            base.fillRect(pixels.rect,0x000000);
            for (i=0; i<balls.length; i++) { ball(balls[i]).draw(base); }

            // cooling map
            var cooling:Number = Math.random() * 0.3;
            var offset:Number = (1-cooling)*255;
            var colt:ColorTransform = new ColorTransform(cooling,cooling,cooling,1,offset,offset,offset,0);
            mat.identity();
            mat.translate(Math.random()*240, 240);
            cooling_map.draw(cooling_elem, mat, colt, BlendMode.MULTIPLY);
            cooling_map.scroll(0,-COOLING_MAP_SPEED);
            cooling_map.fillRect(rct, 0xffffff);

            // fire_map
            temp.copyPixels(fire_map, fire_map.rect, fire_map.rect.topLeft);
            temp.scroll(0,-FIRE_MAP_SPEED);
            fire_map.applyFilter(temp, temp.rect, temp.rect.topLeft, cnvb);
            fire_map.draw(base, null, null, BlendMode.ADD);
            fire_map.draw(cooling_map, null, null, BlendMode.MULTIPLY);

            pixels.paletteMap(fire_map, fire_map.rect, fire_map.rect.topLeft, fireR, fireG, fireB);
            drawFace();
        }
...以下略
}


後は,id:keim_at_Si:20070928と同じ.