forked from: ocean
forked from ocean (diff: 1307)
ActionScript3 source code
/**
* Copyright Ludd ( http://wonderfl.net/user/Ludd )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/2N5u
*/
// forked from zonnbe's ocean
package {
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.TriangleCulling;
import flash.display.Graphics;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Vector3D;
import flash.geom.Point;
import flash.geom.PerspectiveProjection;
import flash.geom.Utils3D;
import flash.geom.Matrix3D;
import flash.geom.Matrix;
import flash.utils.getTimer;
import net.hires.debug.Stats;
[SWF(frameRate='60',width='465',height='465',backgroundColor='0xFFFFFF')]
public class oceanBeta extends Sprite
{
//world
private var gravity:Number = 9.81;
private var fftDir:int = 0;
private var oceanSizeX:Number = 32;
private var oceanSizeY:Number = 32;
private var oceanGridSize:Number = 1;
private var oceanWindScaleX:Number = 0.1;
private var oceanWindScaleY:Number = 0.1;
private var oceanLambda:Number = 1.2;
//map
private var oceanMapSizeX:int = oceanSizeX+0;
private var oceanMapSizeY:int = oceanSizeY+0;
private var heights:Vector.<Vector.<Complex>> = new Vector.<Vector.<Complex>>(); //Vector.<Complex> = new Vector.<Complex>();
private var horizontals:Vector.<Vector.<Vector.<Number>>> = new Vector.<Vector.<Vector.<Number>>>();
private var bmpd:BitmapData = new BitmapData(oceanSizeX, oceanSizeY, false, 0x0);
private var oreal:Vector.<Number> = new Vector.<Number>();
private var oimag:Vector.<Number> = new Vector.<Number>();
private var fft:FFT = new FFT(oceanSizeX);
// surgery
private var vertices:Vector.<Number> = new Vector.<Number>();
private var uvs:Vector.<Number> = new Vector.<Number>();
private var indices:Vector.<int> = new Vector.<int>();
private var normals:Vector.<Vector3D> = new Vector.<Vector3D>();
private var gridSizeX:Number = 25;
private var gridSizeY:Number = 25;
private var _vertexNormal:Vector.<Vector3D> = new Vector.<Vector3D>();
private var viewport:Sprite = new Sprite();
private var _projector:PerspectiveProjection;
private var _projectionMatrix:Matrix3D;
private var cp:Point = new Point();
private var _vertexOnWorld:Vector.<Number> = new Vector.<Number>();
private var _vout:Vector.<Number> = new Vector.<Number>();
public function oceanBeta()
{
cp.x = stage.stageWidth / 2;
cp.y = stage.stageHeight / 2;
viewport.x = cp.x;
viewport.y = cp.y;
_projector = new PerspectiveProjection();
_projectionMatrix = _projector.toMatrix3D();
var args1:Array = ["linear", [0, 0x043055], [1, 0], [0, 240]];
var args2:Array = ["linear", [0, 0x043055], [1, 1], [0, 255]];
with(addChild(new Bitmap(bmpd)))
{
scaleX = scaleY = 3; x = (stage.stageWidth - width) / 2; y = stage.stageHeight - height;
}
boot();
}
private function boot():void
{
var i:int, j:int, k:int;
for(j = 0; j < oceanMapSizeY; j++)
{
heights.push(new Vector.<Complex>());
horizontals.push(new Vector.<Vector.<Number>>());
for(i = 0; i < oceanMapSizeX; i++)
{
vertices.push(i*gridSizeX-(gridSizeX*oceanMapSizeX)/2, 0, j*gridSizeY-(gridSizeY*oceanMapSizeY)/2);
uvs.push(Number(0.0), Number(0.0), Number(0.0));
normals.push(new Vector3D());
heights[j].push(new Complex());
horizontals[j].push(new Vector.<Number>);
oreal.push(Number(0.0));
oimag.push(Number(0.0));
for (k = 0; k < 4; k++)
{
horizontals[j][i].push(Number(0.0));
}
}
}
init();
}
private function init():void
{
var invSqrt2:Number = 1/Math.sqrt(2);
var aGlobal:Number = 0.001;
var rootOfPhillips:Number = 0.0;
var horizontal:Vector.<Number> = new Vector.<Number>(2,true);
var gv:Vector.<Number> = new Vector.<Number>(2,true);
var winds:Vector.<Number> = new Vector.<Number>(2,true);
winds[0] = 100*oceanWindScaleX;
winds[1] = 100*oceanWindScaleY;
var i:int, j:int;
for (i = 0; i < oceanSizeY; i++)
{
for (j = 0; j < oceanSizeX; j++)
{
horizontal[0]=horizontals[i][j][0]=2.0*Math.PI*(i-0.5*(oceanSizeX))/((oceanSizeX)*2.0);
horizontal[1]=horizontals[i][j][1]=2.0*Math.PI*(j-0.5*(oceanSizeY))/((oceanSizeY)*2.0);
horizontals[i][j][3]=horizontals[i][j][0]*horizontals[i][j][0]+horizontals[i][j][1]*horizontals[i][j][1];
horizontals[i][j][2]=Math.sqrt(horizontals[i][j][3]);
gauss(gv);
rootOfPhillips=Math.sqrt(phillips(aGlobal,horizontal,winds));
heights[i][j].real=invSqrt2*gv[0]*rootOfPhillips;
heights[i][j].imag=invSqrt2*gv[1]*rootOfPhillips;
}
}
stage.addEventListener(Event.ENTER_FRAME, processing);
}
private function processing(e:Event):void
{
oceanSimulating(getTimer()/180*Math.PI/10);
bmpd.lock();
bmpd.fillRect(bmpd.rect, 0x0);
var i:int, j:int;
var h:int = 0;
var c:uint = 0;
for(j = 0; j < oceanMapSizeY; j++)
{
for(i = 0; i < oceanMapSizeX; i++)
{
vertices[(i + j * oceanMapSizeX) * 3 + 1] = oreal[i + j * oceanMapSizeX]*3;
h = (oreal[i + j * oceanMapSizeX]+10)/40 * 256;
if (h < 0) h = 0;
if (h > 255) h = 255;
c = h;
c += h << 8;
c += h << 16;
c += 0xFF000000;
bmpd.setPixel32(i,j,c);
}
}
bmpd.unlock();
}
private function gauss(work:Vector.<Number>):void
{
var x1:Number;
var x2:Number;
var w:Number;
do
{
x1 = 2.0 * Math.random() - 1.0;
x2 = 2.0 * Math.random() - 1.0;
w = x1 * x1 + x2 * x2;
} while ( w >= 1.0 );
w = Math.sqrt( (-2.0 * Math.log( w ) ) / w );
work[0] = x1 * w;
work[1] = x2 * w;
}
private function phillips(a:Number, k:Vector.<Number>, wind:Vector.<Number>):Number
{
var k2:Number;
var v2:Number;
var EL:Number;
var Phk:Number;
k2 = k[0]*k[0]+k[1]*k[1];
v2 = wind[0]*wind[0]+wind[1]*wind[1];
EL = v2 / gravity;
if (k2==0)
{
return 0;
}
else
{
Phk = a*(Math.exp(-1/(k2*(EL)*(EL)))/(k2*k2))*((k[0]*wind[0]+k[1]*wind[1])*(k[0]*wind[0]+k[1]*wind[1])/(k2*v2))*Math.exp(-Math.sqrt(k2)*1.0);
return Phk;
}
}
private function oceanSimulating(timeStep:Number):void
{
var i:int, j:int;
var kvector:Vector.<Number> = new Vector.<Number>(2,true);
var klength:Number = 0;
var wkt:Number = 0;
var yHalf:int = (oceanSizeY)/2 + 1;
var yLine:int = 0;
var yLineMirr:int = 0;
var kNegIndex:int = 0;
var ri:int = 0;
var rj:int = 0;
for (i = 0; i < yHalf; ++i)
{
yLine = i*(oceanSizeY);
yLineMirr = (((oceanSizeY)-i)% (oceanSizeY))*(oceanSizeY);
for (j = 0; j < (oceanSizeX); ++j)
{
ri = (oceanSizeX) - i - 1;
rj = (oceanSizeX) - j - 1;
kvector[0]=horizontals[i][j][0];
kvector[1]=horizontals[i][j][1];
klength=horizontals[i][j][2];
wkt = Math.sqrt(klength * gravity) * timeStep;
kNegIndex = yLineMirr*(oceanSizeY) + (((oceanSizeY)-j)% (oceanSizeY));
oreal[j+i*oceanSizeX]=
heights[i][j].real*Math.cos(wkt) + heights[i][j].imag*Math.sin(wkt)
+ heights[ri][rj].real*Math.cos(wkt)
- heights[ri][rj].imag*Math.sin(wkt);
oimag[j+i*oceanSizeX]=
heights[i][j].imag*Math.cos(wkt) + heights[i][j].real*Math.sin(wkt)
- heights[ri][rj].imag*Math.cos(wkt)
- heights[ri][rj].real*Math.sin(wkt);
if (i != yHalf-1)
{
oimag[rj+ri*oceanSizeX]=
heights[i][j].real*Math.cos(wkt) + heights[i][j].imag*Math.sin(wkt)
+ heights[ri][rj].real*Math.cos(wkt)
- heights[ri][rj].imag*Math.sin(wkt);
oreal[rj+ri*oceanSizeX]=
heights[i][j].imag*Math.cos(wkt) + heights[i][j].real*Math.sin(wkt)
- heights[ri][rj].imag*Math.cos(wkt)
- heights[ri][rj].real*Math.sin(wkt);
}
}
}
fft.fft2d(oreal,oimag);
for (j = 0; j < oceanSizeY; j++)
{
for (i = 0; i < oceanSizeX; i++)
{
oreal[i+j*oceanSizeX] *= Number(Math.pow(-1.0,i+j));
}
}
}
}
}
import flash.geom.Vector3D;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.geom.ColorTransform;
import flash.display.BitmapData;
import flash.display.BlendMode;
class Face
{
public var i0:int, i1:int, i2:int, z:Number, normal:Vector3D = new Vector3D();
public function Face(a:int = 0, b:int = 0, c:int = 0)
{
i0 = a; i1 = b; i2 = c;
}
}
class Complex
{
public var real:Number = 0;
public var imag:Number = 0;
public function Complex(r:Number = 0, i:Number = 0) { real = r; imag = i; }
}
class FFT{
private var n:int; // データ数
private var bitrev:Vector.<int>; // ビット反転テーブル
private var cstb:Vector.<Number>; // 三角関数テーブル
public static const HPF:String = "high";
public static const LPF:String = "low";
public static const BPF:String = "band"
public function FFT(n:int) {
if(n != 0 && (n & (n-1)) == 0) {
this.n = n;
this.cstb = new Vector.<Number>(n + (n>>2), true);
this.bitrev = new Vector.<int>(n, true);
makeCstb();
makeBitrev();
}
}
// 1D-FFT
public function fft(re:Vector.<Number>, im:Vector.<Number>, inv:Boolean=false):Boolean {
if(!inv) {
return fftCore(re, im, 1);
} else {
if(fftCore(re, im, -1)) {
for(var i:int=0; i<n; i++) {
re[i] /= n;
im[i] /= n;
}
}
}
return true;
}
// 2D-FFT
public function fft2d(re:Vector.<Number>, im:Vector.<Number>, inv:Boolean=false):Boolean {
var tre:Vector.<Number> = new Vector.<Number>(re.length, true);
var tim:Vector.<Number> = new Vector.<Number>(im.length, true);
var x:int, y:int;
if(inv) cvtSpectrum(re, im);
// x軸方向のFFT
for(y=0; y<n; y++) {
for(x=0; x<n; x++) {
tre[x] = re[x + y*n];
tim[x] = im[x + y*n];
}
if(!inv) fft(tre, tim);
else fft(tre, tim, true);
for(x=0; x<n; x++) {
re[x + y*n] = tre[x];
im[x + y*n] = tim[x];
}
}
// y軸方向のFFT
for(x=0; x<n; x++) {
for(y=0; y<n; y++) {
tre[y] = re[x + y*n];
tim[y] = im[x + y*n];
}
if(!inv) fft(tre, tim);
else fft(tre, tim, true);
for(y=0; y<n; y++) {
re[x + y*n] = tre[y];
im[x + y*n] = tim[y];
}
}
if(!inv) cvtSpectrum(re, im);
return true;
}
// 空間周波数フィルタ
public function applyFilter(re:Vector.<Number>, im:Vector.<Number>, rad:uint, type:String, bandWidth:uint = 0):void {
var r:int = 0; // 半径
var n2:int = n>>1;
for(var y:int=-n2; y<n2; y++) {
for(var x:int=-n2; x<n2; x++) {
r = Math.sqrt(x*x + y*y);
if((type == HPF && r<rad) || (type == LPF && r>rad) || (type == BPF && (r<rad || r>(rad + bandWidth)))) {
re[x + n2 + (y + n2)*n] = im[x + n2 + (y + n2)*n] = 0;
}
}
}
}
private function fftCore(re:Vector.<Number>, im:Vector.<Number>, sign:int):Boolean {
var h:int, d:int, wr:Number, wi:Number, ik:int, xr:Number, xi:Number, m:int, tmp:Number;
for(var l:int=0; l<n; l++) { // ビット反転
m = bitrev[l];
if(l<m) {
tmp = re[l];
re[l] = re[m];
re[m] = tmp;
tmp = im[l];
im[l] = im[m];
im[m] = tmp;
}
}
for(var k:int=1; k<n; k<<=1) { // バタフライ演算
h = 0;
d = n/(k<<1);
for(var j:int=0; j<k; j++) {
wr = cstb[h + (n>>2)];
wi = sign*cstb[h];
for(var i:int=j; i<n; i+=(k<<1)) {
ik = i+k;
xr = wr*re[ik] + wi*im[ik]
xi = wr*im[ik] - wi*re[ik];
re[ik] = re[i] - xr;
re[i] += xr;
im[ik] = im[i] - xi;
im[i] += xi;
}
h += d;
}
}
return true;
}
// スペクトル位置並び替え
private function cvtSpectrum(re:Vector.<Number>, im:Vector.<Number>):void {
var tmp:Number = 0.0, xn:int = 0, yn:int = 0;
for(var y:int=0; y<(n>>1); y++) {
for(var x:int=0; x<(n>>1); x++) {
xn = x + (n>>1);
yn = y + (n>>1);
tmp = re[x + y*n];
re[x + y*n] = re[xn + yn*n];
re[xn + yn*n] = tmp;
tmp = re[x + yn*n];
re[x + yn*n] = re[xn + y*n];
re[xn + y*n] = tmp;
tmp = im[x + y*n];
im[x + y*n] = im[xn + yn*n];
im[xn + yn*n] = tmp;
tmp = im[x + yn*n];
im[x + yn*n] = im[xn + y*n];
im[xn + y*n] = tmp;
}
}
}
// 三角関数テーブル作成
private function makeCstb():void {
var n2:int = n>>1, n4:int = n>>2, n8:int = n>>3;
var t:Number = Math.sin(Math.PI/n);
var dc:Number = 2*t*t;
var ds:Number = Math.sqrt(dc*(2 - dc));
var c:Number = cstb[n4] = 1;
var s:Number = cstb[0] = 0;
t = 2*dc;
for(var i:int=1; i<n8; i++) {
c -= dc;
dc += t*c;
s += ds;
ds -= t*s;
cstb[i] = s;
cstb[n4 - i] = c;
}
if(n8 != 0) cstb[n8] = Math.sqrt(0.5);
for(var j:int=0; j<n4; j++) cstb[n2 - j] = cstb[j];
for(var k:int=0; k<(n2 + n4); k++) cstb[k + n2] = -cstb[k];
}
// ビット反転テーブル作成
private function makeBitrev():void {
var i:int = 0, j:int = 0, k:int = 0;
bitrev[0] = 0;
while(++i<n) {
k= n >> 1;
while(k<=j) {
j -= k;
k >>= 1 ;
}
j += k;
bitrev[i] = j;
}
}
}