package; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Matrix3D; import flash.geom.Vector3D; import flash.utils.ByteArray; import flash.utils.Endian; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import flash.display.StageAlign; import flash.display.StageScaleMode; class Main extends Sprite { // storage params private static inline var WIDTH : Int = 550; private static inline var HEIGHT : Int = 400; private static inline var PIXELS : Int = WIDTH*HEIGHT; private static inline var PIXEL_BYTES : Int = PIXELS*4; private static inline var PARTICLE_START : Int = PIXEL_BYTES; private static inline var PARTICLES : Int = 0x400 * 300; private static inline var PARTICLE_BYTES : Int = PARTICLES*12; private static inline var COLOR_START : Int = PARTICLE_START + PARTICLE_BYTES; private static inline var COLORS : UInt = PIXELS*3; private static inline var COLOR_BYTES : UInt = COLORS*4; private static inline var EULERS_START : UInt = COLOR_START + COLOR_BYTES; private static inline var EULERS_BYTES : UInt = 55416; private static inline var DATA_START : Int = EULERS_START + EULERS_BYTES; private static inline var _x : Int = DATA_START+4; private static inline var _y : Int = _x+4; private static inline var _z : Int = _y+4; private static inline var _mx : Int = _z+4; private static inline var _my : Int = _mx+4; private static inline var _mz : Int = _my+4; private static inline var _a : Int = _mz+4; private static inline var _f : Int = _a+4; private static inline var _b : Int = _f+4; private static inline var _d : Int = _b+4; private static inline var _g : Int = _d+4; private static inline var _o : Int = _g+4; private static inline var _ox : Int = _o+4; private static inline var _oy : Int = _ox+4; private static inline var _oz : Int = _oy+4; private static inline var _tx : Int = _oz+4; private static inline var _ty : Int = _tx+4; private static inline var p00: Int = _ty+4; private static inline var p01: Int = p00+4; private static inline var p02: Int = p01+4; private static inline var p10: Int = p02+4; private static inline var p11: Int = p10+4; private static inline var p12: Int = p11+4; private static inline var p20: Int = p12+4; private static inline var p21: Int = p20+4; private static inline var p22: Int = p21+4; private static inline var p32: Int = p22+4; private static inline var pz: Int = p32+4; private static inline var _w: Int = pz+4; private static inline var DATA_END : Int = _w + 4; private static inline var BYTES : Int = DATA_END; // class constants private static inline var SCALE : Int = 40; private static inline var FOCAL : Float = 433.0126953125; private static inline var CX : Int = Std.int(WIDTH/2); private static inline var CY : Int = Std.int(HEIGHT/2); private static inline var SHADE : Int = 0x030303; private static inline var MAXCOLOR : Int = 0xFFFFFF - SHADE; // instance properties private var bitmap : Bitmap; private var bitmapData : BitmapData; private var _matrix : Matrix3D; function init():Void { initBuffers(); generateVertices(); createEulersLookup(); layout(); addEventListener( Event.ENTER_FRAME, enterFrameHandler ); } function layout() : Void { var tf : TextFormat = new TextFormat(); tf.font = 'arial'; tf.size = 10; tf.color = 0xffffff; var textField: TextField = new TextField(); textField.autoSize = TextFieldAutoSize.LEFT; textField.defaultTextFormat = tf; textField.selectable = false; textField.text = 'nathan at webr3 dot org : Pushing ' + PARTICLES + ' full color particles - pure haXe.'; textField.y = 400 - textField.height; textField.opaqueBackground = 0x000000; addChild( textField ); } function initBuffers():Void { // create bitmap this.bitmapData = new BitmapData( WIDTH , HEIGHT , false , 0 ); this.bitmap = new Bitmap( this.bitmapData ); addChild( this.bitmap ); // create memory var storage : ByteArray = new ByteArray(); storage.endian = Endian.LITTLE_ENDIAN; storage.length = BYTES; flash.Memory.select( storage ); // starting positions flash.Memory.setFloat( _x, 1 ); flash.Memory.setFloat( _y, 1 ); flash.Memory.setFloat( _z, 1 ); flash.Memory.setFloat( _mx, 0 ); flash.Memory.setFloat( _my, 0 ); flash.Memory.setFloat( _mz, 0 ); // lorenz values flash.Memory.setFloat( _a , 1.111); flash.Memory.setFloat( _b , 1.479); flash.Memory.setFloat( _f , 4.494); flash.Memory.setFloat( _g , 0.44); flash.Memory.setFloat( _d , 0.135); flash.Memory.setFloat( _tx , 0); flash.Memory.setFloat( _ty , 0); // start matrix _matrix = new Matrix3D(); } function generateVertices():Void { var a : Int = 0; while( a < PARTICLES ) { flash.Memory.setFloat(_g , flash.Memory.getFloat(_g) + 0.000001 ); flash.Memory.setI32( _o , PARTICLE_START + (a*12) ); flash.Memory.setFloat( _mx , flash.Memory.getFloat(_x) + flash.Memory.getFloat(_d) * (-flash.Memory.getFloat(_a) * flash.Memory.getFloat(_x) - flash.Memory.getFloat(_y) * flash.Memory.getFloat(_y) - flash.Memory.getFloat(_z) * flash.Memory.getFloat(_z) + flash.Memory.getFloat(_a) * flash.Memory.getFloat(_f)) ); flash.Memory.setFloat( _my , flash.Memory.getFloat(_y) + flash.Memory.getFloat(_d) * (-flash.Memory.getFloat(_y) + flash.Memory.getFloat(_x) * flash.Memory.getFloat(_y) - flash.Memory.getFloat(_b) * flash.Memory.getFloat(_x) * flash.Memory.getFloat(_z) + flash.Memory.getFloat(_g)) ); flash.Memory.setFloat( _mz , flash.Memory.getFloat(_z) + flash.Memory.getFloat(_d) * (-flash.Memory.getFloat(_z) + flash.Memory.getFloat(_b) * flash.Memory.getFloat(_x) * flash.Memory.getFloat(_y) + flash.Memory.getFloat(_x) * flash.Memory.getFloat(_z)) ); flash.Memory.setFloat( _x , flash.Memory.getFloat(_mx) ); flash.Memory.setFloat( _y , flash.Memory.getFloat(_my) ); flash.Memory.setFloat( _z , flash.Memory.getFloat(_mz) ); flash.Memory.setI32( flash.Memory.getI32(_o) , Std.int( flash.Memory.getFloat(_x)*SCALE ) ); flash.Memory.setI32( flash.Memory.getI32(_o)+4 , Std.int( flash.Memory.getFloat(_y)*SCALE ) ); flash.Memory.setI32( flash.Memory.getI32(_o)+8 , Std.int( flash.Memory.getFloat(_z)*SCALE ) ); a++; } } static inline function updateMatrix( matrix : Matrix3D , mx : Float , my : Float ) : Void { flash.Memory.setFloat( _tx , flash.Memory.getFloat(_tx) + ((mx - flash.Memory.getFloat(_tx))/10) ); flash.Memory.setFloat( _ty , flash.Memory.getFloat(_ty) + ((my - flash.Memory.getFloat(_ty))/10) ); matrix.identity(); matrix.appendRotation( flash.Memory.getFloat(_tx), Vector3D.Y_AXIS ); matrix.appendRotation( flash.Memory.getFloat(_ty), Vector3D.X_AXIS ); matrix.appendTranslation( 0, 0, 10 ); flash.Memory.setFloat( p00 , matrix.rawData[ 0x0 ] ); flash.Memory.setFloat( p01 , matrix.rawData[ 0x1 ] ); flash.Memory.setFloat( p02 , matrix.rawData[ 0x2 ] ); flash.Memory.setFloat( p10 , matrix.rawData[ 0x4 ] ); flash.Memory.setFloat( p11 , matrix.rawData[ 0x5 ] ); flash.Memory.setFloat( p12 , matrix.rawData[ 0x6 ] ); flash.Memory.setFloat( p20 , matrix.rawData[ 0x8 ] ); flash.Memory.setFloat( p21 , matrix.rawData[ 0x9 ] ); flash.Memory.setFloat( p22 , matrix.rawData[ 0xa ] ); flash.Memory.setFloat( p32 , matrix.rawData[ 0xe ] ); } private function enterFrameHandler( event : Event ): Void { updateMatrix( _matrix , mouseX , mouseY ); var po : Int = 0; // clear all color data for( i in 0...COLOR_BYTES ) { flash.Memory.setFloat( COLOR_START + i , 0 ); } for( a in 0...PARTICLES ) { if( setPZ(PARTICLE_START + (a*12)) > 0 ) { setColors( calculatePositions() , a/PARTICLES ); } } for( i in 0...PIXELS ) { flash.Memory.setI32( i*4 , getColor( (i * 12) + COLOR_START ) ); } // update display flash.system.ApplicationDomain.currentDomain.domainMemory.position = 0; this.bitmapData.lock(); this.bitmapData.setPixels( this.bitmapData.rect , flash.system.ApplicationDomain.currentDomain.domainMemory ); this.bitmapData.unlock( this.bitmapData.rect ); } static inline function calculatePositions() : UInt { return pointToOffset( Std.int( flash.Memory.getFloat(_w) * ( flash.Memory.getI32( flash.Memory.getI32(_ox) ) * flash.Memory.getFloat( p00 ) + flash.Memory.getI32( flash.Memory.getI32(_oy) ) * flash.Memory.getFloat( p10 ) + flash.Memory.getI32( flash.Memory.getI32(_oz) ) * flash.Memory.getFloat( p20 ) ) + CX ), Std.int( flash.Memory.getFloat(_w) * ( flash.Memory.getI32( flash.Memory.getI32(_ox) ) * flash.Memory.getFloat( p01 ) + flash.Memory.getI32( flash.Memory.getI32(_oy) ) * flash.Memory.getFloat( p11 ) + flash.Memory.getI32( flash.Memory.getI32(_oz) ) * flash.Memory.getFloat( p21 ) ) + CY ), WIDTH ) + COLOR_START; } /** * Realtime rendering color function, uses the truncate values stored in eulers lookup chart * colors generated by this method can be as good as getRenderColor with real time processing * however the subtleness value in createEulersLookup needs decreased to circa 0.0085 * gives approx 10* speed increase over render calculation */ static inline function getColor( o : UInt ) : UInt { return color( shadeEulersLookup( flash.Memory.getFloat( o ) ) , shadeEulersLookup(flash.Memory.getFloat( o + 4 ) ) , shadeEulersLookup(flash.Memory.getFloat( o + 8 ) ) ); } /** * replaces shade() for realtime rendering * inline 48ms per 1920000 { @see createEulersLookup } */ static inline function shadeEulersLookup( s : Float ) : Int { return s < 0.1 ? 0 : s > 554.16 ? 254 : flash.Memory.getByte( EULERS_START + Std.int(s*100) ); } /** * truncated lookup chart for approximate color values, accurate to 100th or float r/g/b value */ static function createEulersLookup() { // replaces multiple calls to shade() for realtime rendering // lookup chart is a truncated int reference for all value up to 554.16 (0xFD) var x : Int; for( y in 0...55416 ) { x = EULERS_START + y; flash.Memory.setByte( x , Std.int( (1.0 - Math.exp( -0.03 * (y/55.416) )) * 0xFF ) & 0xFF ); } } static inline function getRenderColor( o : UInt ) : UInt { return color( shade( flash.Memory.getFloat( o ) ) , shade(flash.Memory.getFloat( o + 4 ) ) , shade(flash.Memory.getFloat( o + 8 ) ) ); } static inline function color( r : Int , g : Int , b : Int ) : UInt { return ((r << 16) + (g << 8) + b); } static inline function shade( s : Float ) : Int { return s < 0.1 ? 0 : Std.int( (1.0 - Math.exp( -0.036 * s )) * 0xFF ) & 0xFF; } static inline function setColors( o : UInt , h : Float ) : Void { if( (o < COLOR_START+COLOR_BYTES) && (COLOR_START < o) ) { switch( Std.int( h * 6 ) % 6 ) { case 0: flash.Memory.setFloat( o , flash.Memory.getFloat( o ) + 1.0); flash.Memory.setFloat( o+4 , flash.Memory.getFloat( o + 4 ) + h); case 1: flash.Memory.setFloat( o , flash.Memory.getFloat( o ) + (1.0 - h)); flash.Memory.setFloat( o+4 , flash.Memory.getFloat( o + 4 ) + 1.0); case 2: flash.Memory.setFloat( o+4 , flash.Memory.getFloat( o + 4 ) + 1.0); flash.Memory.setFloat( o+8 , flash.Memory.getFloat( o + 8 ) + h); case 3: flash.Memory.setFloat( o+4 , flash.Memory.getFloat( o + 4 ) + (1.0 - h)); flash.Memory.setFloat( o+8 , flash.Memory.getFloat( o + 8 ) + 1.0); case 4: flash.Memory.setFloat( o , flash.Memory.getFloat( o ) + h); flash.Memory.setFloat( o+8 , flash.Memory.getFloat( o + 8 ) + 1.0); case 5: flash.Memory.setFloat( o , flash.Memory.getFloat( o ) + 1.0); flash.Memory.setFloat( o+8 , flash.Memory.getFloat( o + 8 ) + (1.0 - h)); } } } static inline function setPZ( o : Int ) : Float { flash.Memory.setI32( _ox , o ); flash.Memory.setI32( _oy , o+4 ); flash.Memory.setI32( _oz , o+8 ); flash.Memory.setFloat( pz , FOCAL + flash.Memory.getI32( flash.Memory.getI32(_ox) ) * flash.Memory.getFloat( p02 ) + flash.Memory.getI32( flash.Memory.getI32(_oy) ) * flash.Memory.getFloat( p12 ) + flash.Memory.getI32( flash.Memory.getI32(_oz) ) * flash.Memory.getFloat( p22 ) + flash.Memory.getFloat( p32 ) ); flash.Memory.setFloat( _w , FOCAL / flash.Memory.getFloat(pz) ); return flash.Memory.getFloat(pz); } static inline function increaseColor( c : UInt ) : UInt { return c >= MAXCOLOR ? 0xFFFFFF : c + SHADE; } static inline function pointToOffset( vx : Int , vy : Int , vw : Int ) : UInt { return (( vy * vw ) + vx) * 12; } function new() { super(); init(); } static function main() { var mc:flash.display.MovieClip = flash.Lib.current; mc.stage.align = StageAlign.TOP_LEFT; mc.stage.scaleMode = StageScaleMode.NO_SCALE; var main:Main = new Main(); mc.addChild( main ); } }