先人たちの知恵
この手のネタって,まだ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と同じ.