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

MetaBowl 2.5D

<< Metaお椀 2.5D - MetaBowl2.5D >> 
駄洒落。
Play with waterdrop から 2.5Dメタボール処理部分のみを抽出
2次元メタボールにちょっとした奥行き感を付加。3次元にはなりきれてないので2.5D
濃度閾値は0.1に固定。色も固定。擬似的にエッジ部分にAAをかけているけど、うまくいっていない。良いアイデアがあったら教えてください
Play with waterdropを作っているときに思いついた派生物をもう一つ用意中。脱線がとまらない
20100520 マウスからはずれたときの動きが気に入らないので微調整。ほとんどかわらないけど
/**
 * Copyright zendenmushi ( http://wonderfl.net/user/zendenmushi )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/2042
 */

// forked from zendenmushi's Play with Waterdrop (激重 注意!)
// << Metaお椀 2.5D - MetaBowl2.5D >> 
//
//  駄洒落。
//
// Play with waterdrop から 2.5Dメタボール処理部分のみを抽出
// 2次元メタボールにちょっとした奥行き感を付加。3次元にはなりきれてないので2.5D
//
// 濃度閾値は0.1に固定。色も固定。擬似的にエッジ部分にAAをかけているけど、うまくいっていない。良いアイデアがあったら教えてください
//
// Play with waterdropを作っているときに思いついた派生物をもう一つ用意中。脱線がとまらない
//
// 20100520 マウスからはずれたときの動きが気に入らないので微調整。ほとんどかわらないけど
package  
{
	import com.bit101.components.CheckBox;
	import flash.display.Bitmap;
	import flash.display.BlendMode;
	import flash.display.Loader;
	import flash.display.ShaderInput;
	import flash.display.ShaderParameter;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.display.StageDisplayState;
	import flash.events.Event;
	import flash.display.BitmapData;
	import flash.events.FullScreenEvent;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.filters.BlurFilter;
	import flash.filters.DropShadowFilter;
	import flash.filters.ShaderFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.geom.Vector3D;
	import flash.net.FileReference;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	import flash.utils.ByteArray;
	import frocessing.core.F5BitmapData2D;
	import mx.graphics.ImageSnapshot;
	import net.hires.debug.Stats;
	/**
	 * ...
	 * @author TM
	 */
    [SWF(width=465,height=465,backgroundColor=0x0,frameRate=60)]
	public class MetaBowl25D extends Sprite
	{
		private var canvas : BitmapData;
		private var canvasBmp : Bitmap;
		private var sceneImage : BitmapData;
		private var gradiant : BitmapData;
		private var back : BitmapData;
		private var backBmp : Bitmap;
		private var track : BitmapData;

		private var zeroPoint : Point = new Point(0, 0);
		private var dropimages : Vector.<MetaCircle> = new Vector.<MetaCircle>;
		private var uiBar : Sprite = new Sprite();
		
		private var tempPos : Point = new Point();
		private var tempRect : Rectangle = new Rectangle();
		
		private var shader : MetaBowlShader = new MetaBowlShader();
		private var filter : ShaderFilter = new ShaderFilter(shader);
		private var metaNV : MetaNVShader = new MetaNVShader();
		private var metaNVfilter : ShaderFilter = new ShaderFilter(metaNV);
		private var dropShadow : DropShadowFilter = new DropShadowFilter(2, 2, 0, 0.5);
		
		private var light : Vector3D;
		private var eye : Vector3D;
		private var halfv : Vector3D;

		private var debugMode : Boolean = false;

		private var shiftKeyIsDown : Boolean = false;
		private var mouseIsDown : Boolean = false;
		private var downPoint : Point = new Point();
		private var captureDrop : DropWater = null;

		private var fullscreenCheckbox : CheckBox;
		private var backscreenCheckbox : CheckBox;
		private var autoCheckbox : CheckBox;
		
		
		private var drops : Vector.<DropWater> = new Vector.<DropWater>;
		private var freep : int = -1;
		private const itemlimit : int = 10;

		public function MetaBowl25D() 
		{
			Wonderfl.capture_delay( 30 );
			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.CLICK, mouseClick);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
			stage.addEventListener(MouseEvent.DOUBLE_CLICK, doubleClick);
			stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
			stage.addEventListener(KeyboardEvent.KEY_UP, keyUp);
			stage.addEventListener(FullScreenEvent.FULL_SCREEN, changeFullscreen);
			
			stage.doubleClickEnabled = true;

			var back : Sprite = new Sprite();
			back.graphics.clear();
			back.graphics.beginFill(0x8080c0, 1.0);
			back.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
			back.graphics.endFill();
			addChild(back);
			
			track = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x000000);
			
			canvas = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0xff000000);
			canvasBmp = new Bitmap(canvas);
			addChild(canvasBmp);
			
			addChild(uiBar);
			uiBar.graphics.clear();
			uiBar.graphics.beginFill(0, 0.7);
			uiBar.graphics.drawRect(0, 0, stage.stageWidth, 16);
			uiBar.graphics.endFill();
			uiBar.y = stage.stageHeight - 16;
			fullscreenCheckbox = new CheckBox( uiBar, 2, 2, "FULL SCREEN", fullscreenChecked);
			
			//addChild(new Stats());

			light = new Vector3D( -0.2, 0.5, 0.8 );
			light.normalize();
			eye = new Vector3D( 0.0, 0.2, 1.0 ); // 少し斜めから見ている体にする
			eye.normalize();
			halfv = light.add(eye);
			halfv.normalize();
			shader.data.light.value = [ light.x, light.y, light.z];
	//		shader.data.eye.value = [ eye.x, eye.y, eye.z ];
			shader.data.halfv.value = [ halfv.x, halfv.y, halfv.z ];
			dropShadow.angle = Math.atan2( light.y, light.x ) * 180 / Math.PI;
			canvasBmp.filters = [ dropShadow ];
			
			
			for (var r : Number = 0; r <= MAX_RADIUS; r++) {
				dropimages[r] = new MetaCircle(r + 1, r > 10 ? 1.0 : r / 20 +0.5 );
			}
			DropWater.metaImages = dropimages;

			for (var i : int = 0; i < itemlimit; i++) {
				newItem( Math.random() * stage.stageWidth, Math.random() * stage.stageHeight, Math.random() * 50 + 50);
			}

		}
		private function changeFullscreen(e:Event):void 
		{
			if (stage.displayState == StageDisplayState.FULL_SCREEN) {
				fullscreenCheckbox.selected = true;
			} else {
				fullscreenCheckbox.selected = false;
			}
		}
		
		private function fullscreenChecked(e:Event) : void
		{
			if (!fullscreenCheckbox.selected) {
				stage.fullScreenSourceRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
				stage.displayState = StageDisplayState.NORMAL;
			} else {
				stage.fullScreenSourceRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
				stage.displayState = StageDisplayState.FULL_SCREEN;
			}
		}
		
		private function backscreenChecked(e:Event) : void
		{
			if (!backscreenCheckbox.selected) {
				back.copyPixels(sceneImage, sceneImage.rect, zeroPoint);
				shader.data.src2.input = sceneImage;
			} else {
				back.copyPixels(gradiant, gradiant.rect, zeroPoint);
				shader.data.src2.input = gradiant;
			}
		}

			
		private function autoChecked(e:Event) : void
		{
			
			
		}

		private function doubleClick(e:MouseEvent):void 
		{
		}
		
		private function mouseClick(e:MouseEvent):void 
		{
			/* // pixelBender ToolKit用ソース画像取り込み
			var pFile :FileReference = new FileReference();
			var imageSnap:ImageSnapshot = ImageSnapshot.captureImage(canvasBmp);
//			var imageSnap:ImageSnapshot = ImageSnapshot.captureImage(new Bitmap(dropimages[99].densityImage));
			var imageByteArray:ByteArray = imageSnap.data as ByteArray;
			pFile.save(imageByteArray, "image.png");			
			*/
		}
		
		private function mouseUp(e:MouseEvent):void 
		{
			mouseIsDown = false;
			captureDrop = null;
		}
		
		private function mouseDown(e:MouseEvent):void 
		{
			mouseIsDown = true;
			downPoint.x = e.stageX;
			downPoint.y = e.stageY;
		}
		
		private function keyDown(e:KeyboardEvent):void 
		{
			if (e.charCode == 122) { // "Z"
				debugMode = !debugMode;
			} else if (e.charCode == 120) { // "X"
			} 
			shiftKeyIsDown = e.shiftKey;
		}
		private function keyUp(e:KeyboardEvent):void 
		{
			shiftKeyIsDown = e.shiftKey;
		}
		
		private function newItem( x : Number, y : Number, r : Number) : DropWater
		{
			var cnt : int = drops.length;
			if (((itemlimit > 0) && cnt >= itemlimit) && (freep >= cnt-1)) return null;
			
			freep++;
			
			if (r > MAX_RADIUS) r = MAX_RADIUS;

			if (freep == cnt) {
				drops[cnt] = new DropWater(x, y, r);
			} else {
				drops[freep].regenerate(x, y, r);
			}
			drops[freep].index = freep;
			drops[freep].visible = true;

			
			return drops[freep];
		}
		private function remove(index : int) : void
		{
			var cnt : int = drops.length;
			var temp : DropWater = drops[index];
			var lastp : int = freep;

			temp.visible = false;
			//removeChild(temp);
			if (lastp != index) {
				drops[index] = drops[lastp];
				drops[index].index = index;
				drops[lastp] = temp;
			}
			freep = lastp - 1;
			
		}
		
		private function enterFrame(e:Event):void 
		{
			var i : int, j : int, drop : DropWater;
			

			if (shiftKeyIsDown) {
				light.x = (stage.stageWidth / 2.0 - stage.mouseX)/(stage.stageWidth / 2.0);
				light.y = (stage.stageHeight / 2.0 - stage.mouseY)/(stage.stageHeight / 2.0);
				light.z = 1.0;
				light.normalize();
				halfv = light.add(eye);
				halfv.normalize();
				shader.data.light.value = [ light.x, light.y, light.z];
				shader.data.halfv.value = [ halfv.x, halfv.y, halfv.z ];
				dropShadow.angle = Math.atan2( light.y, light.x ) * 180 / Math.PI;
				canvasBmp.filters = [ dropShadow ];
			}
			for (i = freep; i >= 0; i--) {
				var dropA : DropWater = drops[i];
				
				// マウスと引き合う or クリックで掴む
				if (mouseIsDown && captureDrop == dropA) {
					dropA.x = stage.mouseX;
					dropA.y = stage.mouseY;
				} else {
					if ((Math.abs(dropA.x - stage.mouseX) < dropA.radius) && (Math.abs(dropA.y - stage.mouseY) < dropA.radius)) {
						dropA.dx = (stage.mouseX - dropA.x) ;
						dropA.dy = (stage.mouseY - dropA.y) ;
						if (mouseIsDown && !captureDrop) {
							captureDrop = dropA;
						}
					} else {
						var dx : Number = (dropA.x - dropA.befpos.x)*dropA.radius;
						var dy : Number = (dropA.y - dropA.befpos.y)*dropA.radius;
						if (Math.abs(dx) > Math.abs(dropA.dx)) dropA.dx = dx;
						if (Math.abs(dy) > Math.abs(dropA.dy)) dropA.dy = dy;
					}
				}
				
			}
			
			canvas.fillRect(canvas.rect, 0x000000);
			//canvas.copyPixels(track, track.rect, zeroPoint);
			
			for (i = freep; i >= 0; i--) {
				drop = drops[i];
				drop.x += drop.dx*0.4;
				drop.y += drop.dy * 0.4;
				if (drop.x < 0) drop.dx = -drop.x;
				if (drop.x > stage.stageWidth) drop.dx = stage.stageWidth-drop.x;
				if (drop.y < 0) drop.dy = -drop.y;
				if (drop.y > stage.stageHeight) drop.dy = stage.stageHeight-drop.y;
				
				drop.dx = drop.dx*0.8;
				drop.dy = drop.dy*0.8;
				
				var befdx : Number = drop.x - drop.befpos.x;
				var befdy : Number = drop.y - drop.befpos.y;
				var movdist : Number = Math.sqrt(befdx * befdx + befdy * befdy);
				drop.befpos.x = drop.x;
				drop.befpos.y = drop.y;

				// render!
				var	rr : int = drop.radius;
				var xx : int = (drop.x  - rr) >> 0;
				var yy : int = (drop.y  - rr) >> 0;
				
				tempPos.x = xx;
				tempPos.y = yy;
				tempRect.x = tempPos.x;
				tempRect.y = tempPos.y;
				tempRect.width = drop.width;
				tempRect.height = drop.height;
				
				dropimages[rr].workImage.copyPixels( canvas, tempRect, zeroPoint );
				
				metaNV.data.fore.input = dropimages[rr].densityImage;
				metaNV.data.level.value = [ rr/MAX_RADIUS ];// 小さいボウルが大きいボウルに影響を与えないようにしたいけど、あまり上手く機能していない。既に描画済みのボウルのサイズがわからないため
				dropimages[rr].workImage.applyFilter( dropimages[rr].workImage, dropimages[rr].workImage.rect, zeroPoint, metaNVfilter);
				canvas.copyPixels(dropimages[rr].workImage, dropimages[rr].workImage.rect, tempPos);

			}
			
			
			if (!debugMode) canvas.applyFilter(canvas, canvas.rect, zeroPoint, filter);
		}
		
	}

}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Shader;
import flash.geom.Point;
import flash.utils.ByteArray;
import mx.utils.Base64Decoder;

const MAX_RADIUS : Number = 100;

class DropWater extends Bitmap
{
	public static var metaImages : Vector.<MetaCircle>;
	
	public var index : int;
	//public var visible : Boolean;
	private var _radius : int;
	//public var x : Number;
	//public var y : Number;
	public var dx : Number;
	public var dy : Number;
	public var befpos : Point = new Point();
	
	//public var width : Number;
	//public var height : Number;
	
	public function DropWater(x : Number, y : Number, r : Number)
	{
		regenerate(x, y, r);
	}
	
	public function regenerate(x : Number, y : Number, r : Number) : void
	{
		this.x = x;
		this.y = y;
		befpos.x = x;
		befpos.y = y;
		this.dx = 0;
		this.dy = 0;
		radius = r;
		visible = true;
	}
	
	public function get radius():int { return _radius; }
	
	public function set radius(value:int):void 
	{
		_radius = value < MAX_RADIUS ? value : MAX_RADIUS;
		bitmapData = metaImages[_radius >> 0].densityImage;
	}
}

class MetaCircle
{
	private var radius : Number = 0;
	private var maxdensity : Number = 1;
	private var visibleRatio : Number = 0.8;
	public  var densityImage : BitmapData;
	public  var workImage : BitmapData;
	private var pos : Point =  new Point();
	
	public function MetaCircle(r : Number, density : Number )
	{
		radius = r;
		maxdensity = density;
		densityImage = new BitmapData(r * 2+1, r * 2+1, true, 0);
		workImage = densityImage.clone();
		
		render();
	}
	
	public function density(r : Number) : Number
	{
		if (r < radius) {
			var t : Number = (r / radius);
			return maxdensity * (1 - t) * (1 - t);
		} else {
			return 0.0;
		}
	}
	
	private function render() : void
	{
		var h : int = densityImage.height;
		var w : int = densityImage.width;
		var h2 : int = h / 2;
		var w2 : int = w / 2;
		densityImage.lock();
		for (var y : int = 0; y < h; y++ ) {
			var rad1 : Number = Math.acos( ((h2-y)/h2) );
			var spanr : Number = Math.sin( rad1 ) * h2;
			
			for (var x : int = 0; x < w; x++) {
				var r : Number = Math.sqrt( (w2 - x) * (w2 - x) + (h2 - y) * (h2 - y) );
				var a : uint = density(r) * 127;
				if (a > 0) {
					var rad2 : Number = Math.acos(( (w2 - x) / w2));
					// 右手座標系 +X=左  +Y=上  +Z=手前
					var ny : Number = (h2 - y);
					var nx : Number = (Math.cos( rad2 ) * spanr);
					var nz : Number = Math.sin( rad2 ) * spanr;
					var l : Number = Math.sqrt( nx * nx + ny * ny +nz * nz );
					var nv : int = (Math.max(0,Math.min(255, nx / l * 128 + 128)) << 16) | (Math.min(255, ny / l * 128 + 128) << 8) | a;// (Math.min(255, nz / l * 128 + 128));
					
					if (a > 0) {
						// 本当はAチャンネルで濃度をあらわしたいが、Aの値を変えるとPixelBenderで参照しているRGBも変わってしまうのでしかたなくBに濃度を格納
						densityImage.setPixel32(x, y, (255 << 24) | nv );
					}
				}
			}
		}
		densityImage.unlock();
	}
	
	public function drawTo(target : BitmapData, x : Number, y : Number) : void
	{
		pos.x = x-radius;
		pos.y = y-radius;
		target.copyPixels(densityImage, densityImage.rect, pos, null, null, true);
	}
}

class MetaBowlShader extends Shader
{
	//[Embed(source = 'MetaBowl.pbj', mimeType = 'application/octet-stream')]
	//private var pbj : Class;
	private var bcode : String =
"pQEAAACkCABNZXRhQm93bKAMbmFtZXNwYWNlAGpwLmxpbWFjb24AoAx2ZW5kb3IARVNWAKAIdmVy"+
"c2lvbgABAKAMZGVzY3JpcHRpb24ATWV0YUJvd2wAoQECAAAMX091dENvb3JkAKEBAwEADmxpZ2h0"+
"AKEBAwIADmhhbGZ2AKMABHNyYwChAgQDAA9kc3QAMgAAID+AAAAyAAAQP4AAAB0EAMEAALAAMgAA"+
"IAAAAAACAAAgAgAAAB0FAIAAAIAAMgAAIAAAAAACAAAgAgBAAB0FAEAAAIAAHQUAIAIAgAAdBgDi"+
"BQAYADAFAPEAABAAHQcA8wUAGwAyAAAgPbhR7CoAACAHAIAAHQGAgACAAAA0AAAAAYAAADIAACA/"+
"AAAAHQQAMQcAEAACBAAxAACgADIAACBAAAAAHQUAwQQAsAADBQDBAACgAB0IAMEFABAAMgAAID+A"+
"AAAdAAAQCAAAAAMAABAIAAAAHQEAEAAAgAACAQAQAADAAB0AACAIAEAAAwAAIAgAQAAdAAAQAQDA"+
"AAIAABAAAIAAFgAAIAAAwAAdCAAgAACAAB0FAOICABgAJgUA4ggAGAAyAAAgQwAAAB0AABAFAAAA"+
"BwAAEAAAgAAdAAAgAADAAB0FAOIBABgAJgUA4ggAGAAdAAAQBQAAADIFAIA/gAAAMgUAQD8AAAAy"+
"BQAgPwAAADIFABA/AAAAHQkA4gUAGAADCQDiAAD8AB0KAOIAAKgAAQoA4gkAGAAdAwDiCgAYADIB"+
"ABA9zMzNKgEAEAcAgAAdAYBAAIAAADQAAAABgEAAMgMAED+AAAA1AAAAAAAAADIBABA9uFHsKgEA"+
"EAcAgAAdAYAgAIAAADQAAAABgIAAMgEAED24UewdAgAQBwCAAAICABABAMAAMgEAEELIAAAdBAAg"+
"AgDAAAMEACABAMAAHQMAEAQAgAA2AAAAAAAAADYAAAAAAAAANQAAAAAAAAAyAwAQAAAAADYAAAAA"+
"AAAA"

	public function MetaBowlShader()
	{
		/*
		var code : ByteArray = (new pbj()) as ByteArray;
		super( code );
		*/
		var dec : Base64Decoder = new Base64Decoder();
		dec.decode( bcode );
		super(dec.toByteArray());
		
	}
}

class MetaNVShader extends Shader
{
	//[Embed(source = 'metaNV.pbj', mimeType = 'application/octet-stream')]
	//private var pbj : Class;
	private var bcode : String = 
"pQEAAACkCQBEcm9wV2F0ZXKgDG5hbWVzcGFjZQBqcC5saW1hY29uAKAMdmVuZG9yAEVTVgCgCHZl"+
"cnNpb24AAgCgDGRlc2NyaXB0aW9uAG1ldGFOVgChAQIAAAxfT3V0Q29vcmQAoQEBAAACbGV2ZWwA"+
"owAEYmFjawCjAQRmb3JlAKECBAEAD2Rlc3QAHQIAwQAAEAAwAwDxAgAQAR0EAPMDABsAMAMA8QIA"+
"EAAdBQDzAwAbAB0AABAEAIAAHQIAIAUAgAAdAgAQAADAAAECABACAIAAHQMAgAIAwAAdAgAQBADA"+
"AAECABAFAMAAHQEAEAIAwAAyAgAQAAAAACoCABAEAMAAHQGAgACAAAA0AAAAAYAAADICABA/AAAA"+
"HQMAYQQAEAACAwBhAgDwADICABBAAAAAHQYAwQMAYAADBgDBAgDwAB0EAMEGABAAMgIAED+AAAAd"+
"AwBABAAAAAMDAEAEAAAAHQMAIAIAwAACAwAgAwBAAB0CABAEAEAAAwIAEAQAQAAdAwBAAwCAAAID"+
"AEACAMAAFgIAEAMAQAAdBAAgAgDAADICABAAAAAAKgIAEAUAwAAdAYBAAIAAADQAAAABgEAAMgIA"+
"ED8AAAAdAwBhBQAQAAIDAGECAPAAMgIAEEAAAAAdBgDBAwBgAAMGAMECAPAAHQUAwQYAEAAyAgAQ"+
"P4AAAB0DAEAFAAAAAwMAQAUAAAAdAwAgAgDAAAIDACADAEAAHQIAEAUAQAADAgAQBQBAAB0DAEAD"+
"AIAAAgMAQAIAwAAWAgAQAwBAAB0FACACAMAANQAAAAAAAAAyBQCAAAAAADIFAEAAAAAAMgUAID+A"+
"AAA2AAAAAAAAAB0DAHIEABgAAwMAcgAA/AAdBgDiAwBsAAMGAOIAAKgAHQMAcgUAGAADAwByAgCo"+
"AB0HAOIGABgAAQcA4gMAbAAdAwByBwAYACQCABIDAGwAHQYAgAIAwAAEBgByBgAAAAMGAHIDAGwA"+
"HQMAcgYAbAAyAgAQQAAAAAQGAHICAPwAAwYAcgMAbAAyAgAQPwAAAB0HAOIGAGwAAQcA4gIA/AAd"+
"AwByBwAYAB0GAEADAEAAHQYAIAMAgAAdBgAQAwAAAB0BAOIGAGwANQAAAAAAAAAdAQDiBQAYADYA"+
"AAAAAAAA";

	public function MetaNVShader()
	{
		/*
		var code : ByteArray = (new pbj()) as ByteArray;
		super( code );
		*/
		var dec : Base64Decoder = new Base64Decoder();
		dec.decode( bcode );
		super(dec.toByteArray());

		
	}
}
/*
<languageVersion : 1.0;>

kernel MetaBowl
<   namespace : "jp.limacon";
    vendor : "ESV";
    version : 1;
    description : "MetaBowl"; >
{

#if AIF_FLASH_TARGET
   parameter float3 eye;
   parameter float3 light;
   parameter float3 halfv;
#else
   parameter float3 eye
   <
        defaultValue : float3(0,0.2,1.0);
   >;
   parameter float3 light
   <
        defaultValue : float3(-0.2, 0.5, 0.8);
   >;
#endif
   input image4 src;
   
   output pixel4 dst;
   
   
   void evaluatePixel()
   {
#if !AIF_FLASH_TARGET
        float3 halfv = normalize(eye+light);
#endif
        float2 singlePixel = pixelSize(src);
        float3 invlight = float3(-halfv.x, -halfv.y, halfv.z);
        
        float4 pix = sampleNearest(src, outCoord());
        if (pix.z > 0.09) {
            
            float3 nv;
            nv.xy = (pix.xy-0.5)*2.0;
            nv.z = sqrt( 1.0 - nv.x*nv.x - nv.y*nv.y );

            float dotspec = pow(dot(halfv.xyz, nv.xyz),128.0);
            float dotdi = dot( light, nv ) ;

            float4 color = float4(1.0, 0.5, 0.5, 0.5);
            
            dst.rgb = dotspec + color.rgb*dotdi;//+(0.9-dotdi);
            
            if (pix.z > 0.1){
                dst.a = 1.0;
            } else if (pix.z > 0.09) { // pseoud AA
                dst.a = (pix.z-0.09)*100.0;
            }
        } else {
          dst.a = 0.0;
        }
    }
}
<languageVersion : 1.0;>

kernel MetaNV
<   namespace : "jp.limacon";
    vendor : "ESV";
    version : 2;
    description : "metaNV"; >
{
   parameter float level;
   input image4 back;
   input image4 fore;
   
   output pixel4 dest;
   
   
   void evaluatePixel()
   {
        float2 curPos = outCoord();
        pixel4 f0 = sampleNearest(fore, curPos);
        pixel4 b0 = sampleNearest(back, curPos);
        
        float  fd = f0.z;
        float  bd = b0.z;
        
        // .a=height
        // .r=norm.x
        // .g=norm.y
        // .b=density
        
        float density = fd + bd;
        
        dest.a = f0.a+b0.a;
        if (f0.a > 0.0) {
            f0.xy = (f0.xy-0.5)*2.0;
            f0.z = sqrt( 1.0 - f0.x*f0.x - f0.y*f0.y);

            if (b0.a > 0.0) {
                b0.xy = (b0.xy-0.5)*2.0;
                b0.z = sqrt( 1.0 - b0.x*b0.x - b0.y*b0.y);
            } else {
                b0.xyz = float3(0.0, 0.0, 1.0);               
            }
        
            float3 v = f0.xyz*fd*level + b0.xyz*bd;//(f0.xyz-0.5)*2.0 + (b0.xyz-0.5)*2.0;//(f0.xyz*2.0-1.0) + (b0.xyz*2.0-1.0);
            float l = length( v );
            v = v/l;
            v = v/2.0+0.5;

            dest.rgb = float3(v.x, v.y, density);//float3(density,density,density);// density);
        } else {
            dest.rgb = b0.rgb;
        }
        
   }
}

*/