package sk.yoz.ycanvas.demo.simple
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.IBitmapDrawable;
    import flash.display.Loader;
    import flash.display.LoaderInfo;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.geom.Matrix;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;

    import sk.yoz.ycanvas.interfaces.ILayer;
    import sk.yoz.ycanvas.stage3D.interfaces.IPartitionStage3D;

    import starling.display.DisplayObject;
    import starling.display.Image;
    import starling.textures.Texture;

    public class Partition implements IPartitionStage3D
    {
        private var _x:int;
        private var _y:int;
        private var _content:starling.display.DisplayObject;
        private var _layer:ILayer;

        private var bitmapData:BitmapData;
        private var error:Boolean;
        private var loader:Loader;

        public function Partition(layer:ILayer, x:int, y:int)
        {
            _layer = layer;
            _x = x;
            _y = y;

            _content = new Image(Texture.fromBitmapData(new BitmapData(256, 256, true, 0x0)));
            content.x = x;
            content.y = y;
        }

        public function get content():starling.display.DisplayObject
        {
            return _content;
        }

        public function get x():int
        {
            return _x;
        }

        public function get y():int
        {
            return _y;
        }

        public function get expectedWidth():uint
        {
            return 256;
        }

        public function get expectedHeight():uint
        {
            return 256;
        }

        public function get concatenatedMatrix():Matrix
        {
            return content.getTransformationMatrix(content.stage);;
        }

        public function get loading():Boolean
        {
            return loader != null;
        }

        public function get loaded():Boolean
        {
            return bitmapData || error;
        }

        private function get layer():ILayer
        {
            return _layer;
        }

        private function get url():String
        {
            var level:uint = 18 - getPow(layer.level);
            var x:int = this.x / expectedWidth / layer.level;
            var y:int = this.y / expectedHeight / layer.level;
            var server:String = getServer(Math.abs(x + y) % 3);
            var result:String = "http://" + server + ".tile.openstreetmap.org/"
                + level + "/" + x + "/" + y + ".png";
            return result;
        }

        public function load():void
        {
            loader = new Loader;
            var request:URLRequest = new URLRequest(url);
            var context:LoaderContext = new LoaderContext(true);
            loader.load(request, context);

            var loaderInfo:LoaderInfo = loader.contentLoaderInfo;
            loaderInfo.addEventListener(Event.COMPLETE, onComplete);
            loaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onError);
        }

        public function stopLoading():void
        {
            if(!loading)
                return;

            try
            {
                loader.close();
            }
            catch(error:Error){}

            try
            {
                loader.unload();
            }
            catch(error:Error){}

            var loaderInfo:LoaderInfo = loader.loaderInfo;
            if(loaderInfo)
            {
                loaderInfo.removeEventListener(Event.COMPLETE, onComplete);
                loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onError);
            }
            loader = null;
        }

        public function applyIBitmapDrawable(source:IBitmapDrawable,
            matrix:Matrix):void
        {
        }

        public function toString():String
        {
            return "Partition: [x:" + x + ", y:" + y + "]";
        }

        public function dispose():void
        {
            stopLoading();
            bitmapData && bitmapData.dispose();
            bitmapData = null;
            if(content)
            {
                Image(content).texture.base.dispose();
                Image(content).texture.dispose();
                content.dispose();
            }
        }

        private function getPow(value:uint):uint
        {
            var i:uint = 0;
            while(value > 1)
            {
                value /= 2;
                i++;
            }
            return i;
        }

        private function getServer(value:uint):String
        {
            if(value == 1)
                return "a";
            if(value == 2)
                return "b";
            return "c";
        }

        private function onComplete(event:Event):void
        {
            var loaderInfo:LoaderInfo = LoaderInfo(event.target);
            bitmapData = Bitmap(loaderInfo.content).bitmapData;
            Image(content).texture = Texture.fromBitmapData(bitmapData);
            stopLoading();
        }

        private function onError(event:Event):void
        {
            error = true;
            stopLoading();
        }
    }
}

package sk.yoz.ycanvas.demo.simple
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.IBitmapDrawable;
    import flash.display.Loader;
    import flash.display.LoaderInfo;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.geom.Matrix;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;

    import sk.yoz.ycanvas.interfaces.ILayer;
    import sk.yoz.ycanvas.stage3D.interfaces.IPartitionStage3D;

    import starling.display.DisplayObject;
    import starling.display.Image;
    import starling.textures.Texture;

    public class Partition implements IPartitionStage3D
    {
        private var _x:int;
        private var _y:int;
        private var _content:starling.display.DisplayObject;
        private var _layer:ILayer;

        private var bitmapData:BitmapData;
        private var error:Boolean;
        private var loader:Loader;

        public function Partition(layer:ILayer, x:int, y:int)
        {
            _layer = layer;
            _x = x;
            _y = y;

            _content = new Image(Texture.fromBitmapData(new BitmapData(256, 256, true, 0x0)));
            content.x = x;
            content.y = y;
        }

        public function get content():starling.display.DisplayObject
        {
            return _content;
        }

        public function get x():int
        {
            return _x;
        }

        public function get y():int
        {
            return _y;
        }

        public function get expectedWidth():uint
        {
            return 256;
        }

        public function get expectedHeight():uint
        {
            return 256;
        }

        public function get concatenatedMatrix():Matrix
        {
            return content.getTransformationMatrix(content.stage);;
        }

        public function get loading():Boolean
        {
            return loader != null;
        }

        public function get loaded():Boolean
        {
            return bitmapData || error;
        }

        private function get layer():ILayer
        {
            return _layer;
        }

        private function get url():String
        {
            var level:uint = 18 - getPow(layer.level);
            var x:int = this.x / expectedWidth / layer.level;
            var y:int = this.y / expectedHeight / layer.level;
            var server:String = getServer(Math.abs(x + y) % 3);
            var result:String = "http://" + server + ".tile.openstreetmap.org/"
                + level + "/" + x + "/" + y + ".png";
            return result;
        }

        public function load():void
        {
            loader = new Loader;
            var request:URLRequest = new URLRequest(url);
            var context:LoaderContext = new LoaderContext(true);
            loader.load(request, context);

            var loaderInfo:LoaderInfo = loader.contentLoaderInfo;
            loaderInfo.addEventListener(Event.COMPLETE, onComplete);
            loaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onError);
        }

        public function stopLoading():void
        {
            if(!loading)
                return;

            try
            {
                loader.close();
            }
            catch(error:Error){}

            try
            {
                loader.unload();
            }
            catch(error:Error){}

            var loaderInfo:LoaderInfo = loader.loaderInfo;
            if(loaderInfo)
            {
                loaderInfo.removeEventListener(Event.COMPLETE, onComplete);
                loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onError);
            }
            loader = null;
        }

        public function applyIBitmapDrawable(source:IBitmapDrawable,
            matrix:Matrix):void
        {
        }

        public function toString():String
        {
            return "Partition: [x:" + x + ", y:" + y + "]";
        }

        public function dispose():void
        {
            stopLoading();
            bitmapData && bitmapData.dispose();
            bitmapData = null;
            if(content)
            {
                Image(content).texture.base.dispose();
                Image(content).texture.dispose();
                content.dispose();
            }
        }

        private function getPow(value:uint):uint
        {
            var i:uint = 0;
            while(value > 1)
            {
                value /= 2;
                i++;
            }
            return i;
        }

        private function getServer(value:uint):String
        {
            if(value == 1)
                return "a";
            if(value == 2)
                return "b";
            return "c";
        }

        private function onComplete(event:Event):void
        {
            var loaderInfo:LoaderInfo = LoaderInfo(event.target);
            bitmapData = Bitmap(loaderInfo.content).bitmapData;
			(content as Image).texture.base.dispose();
			(content as Image).texture.dispose();
    		(content as Image).texture = Texture.fromBitmapData(bitmapData);
            stopLoading();
        }

        private function onError(event:Event):void
        {
            error = true;
            stopLoading();
        }
    }
}

Update ApplicationDemo/src/main/flex/sk/yoz/ycanvas/demo/simple/Partition.as

Memory leak eliminated in case of several map creations and destructions .


/*
   SoundManager 2: Javascript Sound for the Web
   ----------------------------------------------
   http://schillmania.com/projects/soundmanager2/

   Copyright (c) 2007, Scott Schiller. All rights reserved.
   Code licensed under the BSD License:
   http://www.schillmania.com/projects/soundmanager2/license.txt

   Flash 9 / ActionScript 3 version
*/

package {

  import flash.external.*;
  import flash.events.*;
  import flash.display.Sprite;
  import flash.display.StageDisplayState;
  import flash.display.StageScaleMode;
  import flash.display.StageAlign;
  import flash.geom.Rectangle;
  import flash.media.Sound;
  import flash.media.SoundChannel;
  import flash.media.SoundLoaderContext;
  import flash.media.SoundTransform;
  import flash.media.SoundMixer;
  import flash.media.Video;
  import flash.net.URLRequest;
  import flash.utils.ByteArray;
  import flash.net.NetConnection;
  import flash.net.NetStream;

  public class SoundManager2_SMSound_AS3 extends Sound {

    public var sm: SoundManager2_AS3 = null;
    // externalInterface references (for Javascript callbacks)
    public var baseJSController: String = "soundManager";
    public var baseJSObject: String = baseJSController + ".sounds";
    public var soundChannel: SoundChannel = new SoundChannel();
    public var urlRequest: URLRequest;
    public var soundLoaderContext: SoundLoaderContext;
    public var waveformData: ByteArray = new ByteArray();
    public var waveformDataArray: Array = [];
    public var eqData: ByteArray = new ByteArray();
    public var eqDataArray: Array = [];
    public var usePeakData: Boolean = false;
    public var useWaveformData: Boolean = false;
    public var useEQData: Boolean = false;
    public var sID: String;
    public var sURL: String;
    public var justBeforeFinishOffset: int;
    public var didJustBeforeFinish: Boolean;
    public var didFinish: Boolean;
    public var loaded: Boolean;
    public var connected: Boolean;
    public var failed: Boolean;
    public var paused: Boolean;
    public var duration: Number;
    public var totalBytes: Number;
    public var handledDataError: Boolean = false;
    public var ignoreDataError: Boolean = false;

    public var lastValues: Object = {
      bytes: 0,
      position: 0,
      volume: 100,
      pan: 0,
      nLoops: 1,
      leftPeak: 0,
      rightPeak: 0,
      waveformDataArray: null,
      eqDataArray: null,
      isBuffering: null
    };
    public var didLoad: Boolean = false;
    public var sound: Sound = new Sound();

    public var cc: Object;
    public var nc: NetConnection;
    public var ns: NetStream;
    public var st: SoundTransform;
    public var useNetstream: Boolean;
    public var useVideo: Boolean = false;
    public var bufferTime: Number = -1;
    public var lastNetStatus: String = null;
    public var serverUrl: String = null;

    public var oVideo: Video = null;
    public var videoWidth: Number = 0;
    public var videoHeight: Number = 0;

    public function SoundManager2_SMSound_AS3(oSoundManager: SoundManager2_AS3, sIDArg: String = null, sURLArg: String = null, usePeakData: Boolean = false, useWaveformData: Boolean = false, useEQData: Boolean = false, useNetstreamArg: Boolean = false, useVideo: Boolean = false, netStreamBufferTime: Number = -1, serverUrl: String = null, duration: Number = 0, totalBytes: Number = 0) {
      this.sm = oSoundManager;
      this.sID = sIDArg;
      this.sURL = sURLArg;
      this.usePeakData = usePeakData;
      this.useWaveformData = useWaveformData;
      this.useEQData = useEQData;
      this.urlRequest = new URLRequest(sURLArg);
      this.justBeforeFinishOffset = 0;
      this.didJustBeforeFinish = false;
      this.didFinish = false; // non-MP3 formats only
      this.loaded = false;
      this.connected = false;
      this.failed = false;
      this.soundChannel = null;
      this.lastNetStatus = null;
      this.useNetstream = useNetstreamArg;
      this.serverUrl = serverUrl;
      this.duration = duration;
      this.totalBytes = totalBytes;
      this.useVideo = useVideo;
      this.bufferTime = netStreamBufferTime;
      writeDebug('in SoundManager2_SMSound_AS3, got duration '+duration+' and totalBytes '+totalBytes);

      if (this.useNetstream) {
        this.cc = new Object();
        this.nc = new NetConnection();

        // Handle FMS bandwidth check callback.
        // @see onBWDone
        // @see http://www.adobe.com/devnet/flashmediaserver/articles/dynamic_stream_switching_04.html
        // @see http://www.johncblandii.com/index.php/2007/12/fms-a-quick-fix-for-missing-onbwdone-onfcsubscribe-etc.html
        this.nc.client = this;

        // TODO: security/IO error handling
        // this.nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, doSecurityError);
        // this.nc.addEventListener(IOErrorEvent.IO_ERROR, doIOError);
        nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);

        writeDebug('Got server URL: '+ this.serverUrl);
        if (this.serverUrl != null) {
          writeDebug('NetConnection: connecting to server ' + this.serverUrl + '...');
        }
        this.nc.connect(serverUrl);
      } else {
        this.connected = true;
      }
    }

    private function netStatusHandler(event:NetStatusEvent):void {
      switch (event.info.code) {
        case "NetConnection.Connect.Success":

          writeDebug('NetConnection: connected');
          try {
            this.ns = new NetStream(this.nc);
            this.ns.checkPolicyFile = true;
            // bufferTime reference: http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/net/NetStream.html#bufferTime
            if (this.bufferTime != -1) {
              this.ns.bufferTime = this.bufferTime; // set to 0.1 or higher. 0 is reported to cause playback issues with static files.
            }
            this.st = new SoundTransform();
            this.cc.onMetaData = this.metaDataHandler;
            this.ns.client = this.cc;
            this.ns.receiveAudio(true);
            if (this.useVideo) {
              this.oVideo = new Video();
              this.ns.receiveVideo(true);
              this.sm.stage.addEventListener(Event.RESIZE, this.resizeHandler);
              this.oVideo.smoothing = true; // http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/media/Video.html#smoothing
              this.oVideo.visible = false; // hide until metadata received
              this.sm.addChild(this.oVideo);
              this.oVideo.attachNetStream(this.ns);
              writeDebug('setting video w/h to stage: ' + this.sm.stage.stageWidth + 'x' + this.sm.stage.stageHeight);
              this.oVideo.width = this.sm.stage.stageWidth;
              this.oVideo.height = this.sm.stage.stageHeight;
            }
            this.connected = true;
            ExternalInterface.call(this.sm.baseJSObject + "['" + this.sID + "']._onconnect", 1);
          } catch(e: Error) {
            this.failed = true;
            writeDebug('netStream error: ' + e.toString());
          }
          break;

        case "NetStream.Play.StreamNotFound":
          this.failed = true;
          writeDebug("NetConnection: Stream not found!");
          break;

        case "NetConnection.Connect.Closed":
          this.failed = true;
          writeDebug("NetConnection: Connection closed!");
          break;

        default:
          this.failed = true;
          writeDebug("NetConnection: got unhandled code '" + event.info.code + "'!");
          ExternalInterface.call(this.sm.baseJSObject + "['" + this.sID + "']._onconnect", 0);
          break;
      }
    }

    public function resizeHandler(e: Event) : void {
      // scale video to stage dimensions
      // probably less performant than using native flash scaling, but that doesn't quite seem to work. I'm probably missing something simple.
      this.oVideo.width = this.sm.stage.stageWidth;
      this.oVideo.height = this.sm.stage.stageHeight;
    }

    public function writeDebug(s: String, bTimestamp: Boolean = false) : Boolean {
      return this.sm.writeDebug(s, bTimestamp); // defined in main SM object
    }

    public function doNetStatus(e: NetStatusEvent) : void {
      writeDebug('netStatusEvent: ' + e.info.code);
    }

    public function metaDataHandler(infoObject: Object) : void {
      /*
    var data:String = new String();
    for (var prop:* in infoObject) {
    data += prop+': '+infoObject[prop]+' ';
    }
    ExternalInterface.call('soundManager._writeDebug','Metadata: '+data);
    */
      if (this.oVideo) {
        // set dimensions accordingly
        if (!infoObject.width && !infoObject.height) {
          writeDebug('No width/height specified');
          infoObject.width = 0;
          infoObject.height = 0;
        }
        writeDebug('video dimensions: ' + infoObject.width + 'x' + infoObject.height + ' (w/h)');
        this.videoWidth = infoObject.width;
        this.videoHeight = infoObject.height;
        // implement a subset of metadata to pass over EI bridge
        // some formats have extra stuff, eg. "aacaot", "avcprofile"
        // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000267.html
        var oMeta: Object = new Object();
        var item: Object = null;
        for (item in infoObject) {
          // exclude seekpoints for now, presumed not useful and overly large.
          if (item != 'seekpoints') {
            oMeta[item] = infoObject[item];
          }
        }
        ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onmetadata", oMeta);
        writeDebug('showing video for ' + this.sID);
        this.oVideo.visible = true; // show ze video!
      }
      if (!this.loaded) {
        ExternalInterface.call(baseJSObject + "['" + this.sID + "']._whileloading", this.bytesLoaded, (this.bytesTotal || this.totalBytes), (infoObject.duration || this.duration));
      }
      this.duration = infoObject.duration * 1000;
      // null this out for the duration of this object's existence.
      // it may be called multiple times.
      this.cc.onMetaData = function (infoObject: Object) : void {}

    }

    public function getWaveformData() : void {
      // http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/media/SoundMixer.html#computeSpectrum()
      SoundMixer.computeSpectrum(this.waveformData, false, 0); // sample wave data at 44.1 KHz
      this.waveformDataArray = [];
      for (var i: int = 0, j: int = this.waveformData.length / 4; i < j; i++) { // get all 512 values (256 per channel)
        this.waveformDataArray.push(int(this.waveformData.readFloat() * 1000) / 1000);
      }
    }

    public function getEQData() : void {
      // http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/media/SoundMixer.html#computeSpectrum()
      SoundMixer.computeSpectrum(this.eqData, true, 0); // sample EQ data at 44.1 KHz
      this.eqDataArray = [];
      for (var i: int = 0, j: int = this.eqData.length / 4; i < j; i++) { // get all 512 values (256 per channel)
        this.eqDataArray.push(int(this.eqData.readFloat() * 1000) / 1000);
      }
    }

    public function start(nMsecOffset: int, nLoops: int) : void {
      writeDebug("Called start nMsecOffset "+ nMsecOffset+ ' nLoops '+nLoops);
      this.sm.currentObject = this; // reference for video, full-screen
      if (this.useNetstream) {
        writeDebug('start: seeking to ' + nMsecOffset);
        this.cc.onMetaData = this.metaDataHandler;
        this.ns.seek(nMsecOffset);
        if (this.paused) {
          this.ns.resume(); // get the sound going again
          if (!this.didLoad) this.didLoad = true;
        } else if (!this.didLoad) {
          this.ns.play(this.sURL);
          this.didLoad = true;
        }
        // this.ns.addEventListener(Event.SOUND_COMPLETE, _onfinish);
        this.applyTransform();
      } else {
        this.soundChannel = this.play(nMsecOffset, nLoops);
        this.addEventListener(Event.SOUND_COMPLETE, _onfinish);
        this.applyTransform();
      }
    }

    private function _onfinish() : void {
      this.removeEventListener(Event.SOUND_COMPLETE, _onfinish);
    }

    public function loadSound(sURL: String, bStream: Boolean) : void {
      if (this.useNetstream) {
        if (this.didLoad != true) {
          ExternalInterface.call('loadSound(): loading ' + this.sURL);
          this.ns.play(this.sURL);
          this.didLoad = true;
        }
        // this.addEventListener(Event.SOUND_COMPLETE, _onfinish);
        this.applyTransform();
      } else {
        try {
          this.didLoad = true;
          this.urlRequest = new URLRequest(sURL);
          this.soundLoaderContext = new SoundLoaderContext(1000, true); // check for policy (crossdomain.xml) file on remote domains - http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/media/SoundLoaderContext.html
          this.load(this.urlRequest, this.soundLoaderContext);
        } catch(e: Error) {
          writeDebug('error during loadSound(): ' + e.toString());
        }
      }
    }

    public function setVolume(nVolume: Number) : void {
      this.lastValues.volume = nVolume / 100;
      this.applyTransform();
    }

    public function setPan(nPan: Number) : void {
      this.lastValues.pan = nPan / 100;
      this.applyTransform();
    }

    public function applyTransform() : void {
      var st: SoundTransform = new SoundTransform(this.lastValues.volume, this.lastValues.pan);
      if (this.useNetstream) {
        this.ns.soundTransform = st;
      } else if (this.soundChannel) {
        this.soundChannel.soundTransform = st; // new SoundTransform(this.lastValues.volume, this.lastValues.pan);
      }
    }

    // Handle FMS bandwidth check callback.
    // @see http://www.adobe.com/devnet/flashmediaserver/articles/dynamic_stream_switching_04.html
    // @see http://www.johncblandii.com/index.php/2007/12/fms-a-quick-fix-for-missing-onbwdone-onfcsubscribe-etc.html
    public function onBWDone():void{
      writeDebug('onBWDone: called and ignored');
    }
  }

}

/*
   SoundManager 2: Javascript Sound for the Web
   ----------------------------------------------
   http://schillmania.com/projects/soundmanager2/

   Copyright (c) 2007, Scott Schiller. All rights reserved.
   Code licensed under the BSD License:
   http://www.schillmania.com/projects/soundmanager2/license.txt

   Flash 9 / ActionScript 3 version
*/

package {

  import flash.external.*;
  import flash.events.*;
  import flash.display.Sprite;
  import flash.display.StageDisplayState;
  import flash.display.StageScaleMode;
  import flash.display.StageAlign;
  import flash.geom.Rectangle;
  import flash.media.Sound;
  import flash.media.SoundChannel;
  import flash.media.SoundLoaderContext;
  import flash.media.SoundTransform;
  import flash.media.SoundMixer;
  import flash.media.Video;
  import flash.net.URLRequest;
  import flash.utils.ByteArray;
  import flash.net.NetConnection;
  import flash.net.NetStream;

  public class SoundManager2_SMSound_AS3 extends Sound {

    public var sm: SoundManager2_AS3 = null;
    // externalInterface references (for Javascript callbacks)
    public var baseJSController: String = "soundManager";
    public var baseJSObject: String = baseJSController + ".sounds";
    public var soundChannel: SoundChannel = new SoundChannel();
    public var urlRequest: URLRequest;
    public var soundLoaderContext: SoundLoaderContext;
    public var waveformData: ByteArray = new ByteArray();
    public var waveformDataArray: Array = [];
    public var eqData: ByteArray = new ByteArray();
    public var eqDataArray: Array = [];
    public var usePeakData: Boolean = false;
    public var useWaveformData: Boolean = false;
    public var useEQData: Boolean = false;
    public var sID: String;
    public var sURL: String;
    public var justBeforeFinishOffset: int;
    public var didJustBeforeFinish: Boolean;
    public var didFinish: Boolean;
    public var loaded: Boolean;
    public var connected: Boolean;
    public var failed: Boolean;
    public var paused: Boolean;
    public var duration: Number;
    public var totalBytes: Number;
    public var handledDataError: Boolean = false;
    public var ignoreDataError: Boolean = false;

    public var lastValues: Object = {
      bytes: 0,
      position: 0,
      volume: 100,
      pan: 0,
      nLoops: 1,
      leftPeak: 0,
      rightPeak: 0,
      waveformDataArray: null,
      eqDataArray: null,
      isBuffering: null
    };
    public var didLoad: Boolean = false;
    public var sound: Sound = new Sound();

    public var cc: Object;
    public var nc: NetConnection;
    public var ns: NetStream;
    public var st: SoundTransform;
    public var useNetstream: Boolean;
    public var useVideo: Boolean = false;
    public var bufferTime: Number = -1;
    public var lastNetStatus: String = null;
    public var serverUrl: String = null;

    public var oVideo: Video = null;
    public var videoWidth: Number = 0;
    public var videoHeight: Number = 0;

    public function SoundManager2_SMSound_AS3(oSoundManager: SoundManager2_AS3, sIDArg: String = null, sURLArg: String = null, usePeakData: Boolean = false, useWaveformData: Boolean = false, useEQData: Boolean = false, useNetstreamArg: Boolean = false, useVideo: Boolean = false, netStreamBufferTime: Number = -1, serverUrl: String = null, duration: Number = 0, totalBytes: Number = 0) {
      this.sm = oSoundManager;
      this.sID = sIDArg;
      this.sURL = sURLArg;
      this.usePeakData = usePeakData;
      this.useWaveformData = useWaveformData;
      this.useEQData = useEQData;
      this.urlRequest = new URLRequest(sURLArg);
      this.justBeforeFinishOffset = 0;
      this.didJustBeforeFinish = false;
      this.didFinish = false; // non-MP3 formats only
      this.loaded = false;
      this.connected = false;
      this.failed = false;
      this.soundChannel = null;
      this.lastNetStatus = null;
      this.useNetstream = useNetstreamArg;
      this.serverUrl = serverUrl;
      this.duration = duration;
      this.totalBytes = totalBytes;
      this.useVideo = useVideo;
      this.bufferTime = netStreamBufferTime;
      writeDebug('in SoundManager2_SMSound_AS3, got duration '+duration+' and totalBytes '+totalBytes);

      if (this.useNetstream) {
        this.cc = new Object();
        this.nc = new NetConnection();

        // Handle FMS bandwidth check callback.
        // @see onBWDone
        // @see http://www.adobe.com/devnet/flashmediaserver/articles/dynamic_stream_switching_04.html
        // @see http://www.johncblandii.com/index.php/2007/12/fms-a-quick-fix-for-missing-onbwdone-onfcsubscribe-etc.html
        this.nc.client = this;

        // TODO: security/IO error handling
        // this.nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, doSecurityError);
        // this.nc.addEventListener(IOErrorEvent.IO_ERROR, doIOError);
        nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);

        writeDebug('Got server URL: '+ this.serverUrl);
        if (this.serverUrl != null) {
          writeDebug('NetConnection: connecting to server ' + this.serverUrl + '...');
        }
        this.nc.connect(serverUrl);
      } else {
        this.connected = true;
      }
    }

    private function netStatusHandler(event:NetStatusEvent):void {
      switch (event.info.code) {
        case "NetConnection.Connect.Success":

          writeDebug('NetConnection: connected');
          try {
            this.ns = new NetStream(this.nc);
            this.ns.checkPolicyFile = true;
            // bufferTime reference: http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/net/NetStream.html#bufferTime
            if (this.bufferTime != -1) {
              this.ns.bufferTime = this.bufferTime; // set to 0.1 or higher. 0 is reported to cause playback issues with static files.
            }
            this.st = new SoundTransform();
            this.cc.onMetaData = this.metaDataHandler;
            this.ns.client = this.cc;
            this.ns.receiveAudio(true);
            if (this.useVideo) {
              this.oVideo = new Video();
              this.ns.receiveVideo(true);
              this.sm.stage.addEventListener(Event.RESIZE, this.resizeHandler);
              this.oVideo.smoothing = true; // http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/media/Video.html#smoothing
              this.oVideo.visible = false; // hide until metadata received
              this.sm.addChild(this.oVideo);
              this.oVideo.attachNetStream(this.ns);
              writeDebug('setting video w/h to stage: ' + this.sm.stage.stageWidth + 'x' + this.sm.stage.stageHeight);
              this.oVideo.width = this.sm.stage.stageWidth;
              this.oVideo.height = this.sm.stage.stageHeight;
            }
            this.connected = true;
            ExternalInterface.call(this.sm.baseJSObject + "['" + this.sID + "']._onconnect", 1);
          } catch(e: Error) {
            this.failed = true;
            writeDebug('netStream error: ' + e.toString());
          }
          break;

        case "NetStream.Play.StreamNotFound":
          this.failed = true;
          writeDebug("NetConnection: Stream not found!");
          break;

        case "NetConnection.Connect.Closed":
          this.failed = true;
          writeDebug("NetConnection: Connection closed!");
          break;

        default:
          this.failed = true;
          writeDebug("NetConnection: got unhandled code '" + event.info.code + "'!");
          ExternalInterface.call(this.sm.baseJSObject + "['" + this.sID + "']._onconnect", 0);
          break;
      }
    }

    public function resizeHandler(e: Event) : void {
      // scale video to stage dimensions
      // probably less performant than using native flash scaling, but that doesn't quite seem to work. I'm probably missing something simple.
      this.oVideo.width = this.sm.stage.stageWidth;
      this.oVideo.height = this.sm.stage.stageHeight;
    }

    public function writeDebug(s: String, bTimestamp: Boolean = false) : Boolean {
      return this.sm.writeDebug(s, bTimestamp); // defined in main SM object
    }

    public function doNetStatus(e: NetStatusEvent) : void {
      writeDebug('netStatusEvent: ' + e.info.code);
    }

    public function metaDataHandler(infoObject: Object) : void {
      /*
    var data:String = new String();
    for (var prop:* in infoObject) {
    data += prop+': '+infoObject[prop]+' ';
    }
    ExternalInterface.call('soundManager._writeDebug','Metadata: '+data);
    */
      if (this.oVideo) {
        // set dimensions accordingly
        if (!infoObject.width && !infoObject.height) {
          writeDebug('No width/height specified');
          infoObject.width = 0;
          infoObject.height = 0;
        }
        writeDebug('video dimensions: ' + infoObject.width + 'x' + infoObject.height + ' (w/h)');
        this.videoWidth = infoObject.width;
        this.videoHeight = infoObject.height;
        // implement a subset of metadata to pass over EI bridge
        // some formats have extra stuff, eg. "aacaot", "avcprofile"
        // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000267.html
        var oMeta: Object = new Object();
        var item: Object = null;
        for (item in infoObject) {
          // exclude seekpoints for now, presumed not useful and overly large.
          if (item != 'seekpoints') {
            oMeta[item] = infoObject[item];
          }
        }
        ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onmetadata", oMeta);
        writeDebug('showing video for ' + this.sID);
        this.oVideo.visible = true; // show ze video!
      }
      if (!this.loaded) {
        ExternalInterface.call(baseJSObject + "['" + this.sID + "']._whileloading", this.bytesLoaded, (this.bytesTotal || this.totalBytes), (infoObject.duration || this.duration));
      }
      this.duration = infoObject.duration * 1000;
      // null this out for the duration of this object's existence.
      // it may be called multiple times.
      this.cc.onMetaData = function (infoObject: Object) : void {}

    }

    public function getWaveformData() : void {
      // http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/media/SoundMixer.html#computeSpectrum()
      SoundMixer.computeSpectrum(this.waveformData, false, 0); // sample wave data at 44.1 KHz
      this.waveformDataArray = [];
      for (var i: int = 0, j: int = this.waveformData.length / 4; i < j; i++) { // get all 512 values (256 per channel)
        this.waveformDataArray.push(int(this.waveformData.readFloat() * 1000) / 1000);
      }
    }

    public function getEQData() : void {
      // http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/media/SoundMixer.html#computeSpectrum()
      SoundMixer.computeSpectrum(this.eqData, true, 0); // sample EQ data at 44.1 KHz
      this.eqDataArray = [];
      for (var i: int = 0, j: int = this.eqData.length / 4; i < j; i++) { // get all 512 values (256 per channel)
        this.eqDataArray.push(int(this.eqData.readFloat() * 1000) / 1000);
      }
    }

    public function start(nMsecOffset: int, nLoops: int) : void {
      writeDebug("Called start nMsecOffset "+ nMsecOffset+ ' nLoops '+nLoops);
      this.sm.currentObject = this; // reference for video, full-screen
      if (this.useNetstream) {
        writeDebug('start: seeking to ' + nMsecOffset);
        this.cc.onMetaData = this.metaDataHandler;
        this.ns.seek(nMsecOffset);
        if (this.paused) {
          this.ns.resume(); // get the sound going again
          if (!this.didLoad) this.didLoad = true;
        } else if (!this.didLoad) {
          this.ns.play(this.sURL);
          this.didLoad = true;
        }
        // this.ns.addEventListener(Event.SOUND_COMPLETE, _onfinish);
        this.applyTransform();
      } else {
        this.soundChannel = this.play(nMsecOffset, nLoops);
        this.addEventListener(Event.SOUND_COMPLETE, _onfinish);
        this.applyTransform();
      }
    }

    private function _onfinish() : void {
      this.removeEventListener(Event.SOUND_COMPLETE, _onfinish);
    }

    public function loadSound(sURL: String, bStream: Boolean) : void {
      if (this.useNetstream) {
        if (this.didLoad != true) {
          ExternalInterface.call('loadSound(): loading ' + this.sURL);
          this.ns.play(this.sURL);
          this.didLoad = true;
        }
        // this.addEventListener(Event.SOUND_COMPLETE, _onfinish);
        this.applyTransform();
      } else {
        try {
          this.didLoad = true;
          this.urlRequest = new URLRequest(sURL);
          this.soundLoaderContext = new SoundLoaderContext(1000, true); // check for policy (crossdomain.xml) file on remote domains - http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/media/SoundLoaderContext.html
          this.load(this.urlRequest, this.soundLoaderContext);
        } catch(e: Error) {
          writeDebug('error during loadSound(): ' + e.toString());
        }
      }
    }

    public function setVolume(nVolume: Number) : void {
      this.lastValues.volume = nVolume / 100;
      this.applyTransform();
    }

    public function setPan(nPan: Number) : void {
      this.lastValues.pan = nPan / 100;
      this.applyTransform();
    }

    public function applyTransform() : void {
      var st: SoundTransform = new SoundTransform(this.lastValues.volume, this.lastValues.pan);
      if (this.useNetstream) {
        this.ns.soundTransform = st;
      } else if (this.soundChannel) {
        this.soundChannel.soundTransform = st; // new SoundTransform(this.lastValues.volume, this.lastValues.pan);
      }
    }

    // Handle FMS bandwidth check callback.
    // @see http://www.adobe.com/devnet/flashmediaserver/articles/dynamic_stream_switching_04.html
    // @see http://www.johncblandii.com/index.php/2007/12/fms-a-quick-fix-for-missing-onbwdone-onfcsubscribe-etc.html
    public function onBWDone():void{
      writeDebug('onBWDone: called and ignored');
    }

    // NetStream client callback.  Invoked when the song is complete
    public function onPlayStatus(info:Object):void {
      writeDebug('onPlayStatus called with '+info);
      switch(info.code) {
        case "NetStream.Play.Complete":
          writeDebug('Song has finished!');
          break;
      }
    }
  }
}

Add an onPlayStatus method to capture the callback...but it's never called.


//
// Flump - Copyright 2013 Flump Authors

package flump.xfl {

import aspire.util.XmlUtil;

import flump.mold.KeyframeMold;
import flump.mold.LayerMold;

public class XflLayer
{
    public static const NAME :String = "name";
    public static const TYPE :String = "layerType";

    public static const TYPE_GUIDE :String = "guide";
    public static const TYPE_FOLDER :String = "folder";
	public static const TYPE_MASK :String = "mask";

    use namespace xflns;

    public static function parse (lib :XflLibrary, baseLocation :String, xml :XML, flipbook :Boolean,mask:String=null) :LayerMold {
        const layer :LayerMold = new LayerMold();
        layer.name = XmlUtil.getStringAttr(xml, NAME);
        layer.flipbook = flipbook;
		// mask
		if (mask!=null) layer.mask = mask;
        const location :String = baseLocation + ":" + layer.name;
        var frameXmlList :XMLList = xml.frames.DOMFrame;
        for each (var frameXml :XML in frameXmlList) {
            layer.keyframes.push(XflKeyframe.parse(lib, location, frameXml, flipbook));
        }
        if (layer.keyframes.length == 0) lib.addError(location, ParseError.INFO, "No keyframes on layer");

        var ii :int;
        var kf :KeyframeMold;
        var nextKf :KeyframeMold;

        // normalize skews, so that we always skew the shortest distance between
        // two angles (we don't want to skew more than Math.PI)
        for (ii = 0; ii < layer.keyframes.length - 1; ++ii) {
            kf = layer.keyframes[ii];
            nextKf = layer.keyframes[ii+1];
            frameXml = frameXmlList[ii];

            if (kf.skewX + Math.PI < nextKf.skewX) {
                nextKf.skewX += -Math.PI * 2;
            } else if (kf.skewX - Math.PI > nextKf.skewX) {
                nextKf.skewX += Math.PI * 2;
            }
            if (kf.skewY + Math.PI < nextKf.skewY) {
                nextKf.skewY += -Math.PI * 2;
            } else if (kf.skewY - Math.PI > nextKf.skewY) {
                nextKf.skewY += Math.PI * 2;
            }
        }

        // apply additional rotations
        var additionalRotation :Number = 0;
        for (ii = 0; ii < layer.keyframes.length - 1; ++ii) {
            kf = layer.keyframes[ii];
            nextKf = layer.keyframes[ii+1];
            frameXml = frameXmlList[ii];

            var motionTweenRotate :String = XmlUtil.getStringAttr(frameXml,
                XflKeyframe.MOTION_TWEEN_ROTATE, XflKeyframe.MOTION_TWEEN_ROTATE_NONE);

            // If a direction is specified, take it into account
            if (motionTweenRotate != XflKeyframe.MOTION_TWEEN_ROTATE_NONE) {
                var direction :Number = (motionTweenRotate == XflKeyframe.MOTION_TWEEN_ROTATE_CLOCKWISE ? 1 : -1);
                // negative scales affect rotation direction
                direction *= sign(nextKf.scaleX) * sign(nextKf.scaleY);

                while (direction < 0 && kf.skewX < nextKf.skewX) {
                    nextKf.skewX -= Math.PI * 2;
                }
                while (direction > 0 && kf.skewX > nextKf.skewX) {
                    nextKf.skewX += Math.PI * 2;
                }
                while (direction < 0 && kf.skewY < nextKf.skewY) {
                    nextKf.skewY -= Math.PI * 2;
                }
                while (direction > 0 && kf.skewY > nextKf.skewY) {
                    nextKf.skewY += Math.PI * 2;
                }

                // additional rotations specified?
                var motionTweenRotateTimes :Number =
                    XmlUtil.getNumberAttr(frameXml, XflKeyframe.MOTION_TWEEN_ROTATE_TIMES, 0);
                var thisRotation :Number = motionTweenRotateTimes * Math.PI * 2 * direction;
                additionalRotation += thisRotation;
            }

            nextKf.rotate(additionalRotation);
        }

        return layer;
    }

    protected static function sign (n :Number) :Number {
        return (n > 0 ? 1 : (n < 0 ? -1 : 0));
    }
}
}

//
// Flump - Copyright 2013 Flump Authors

package flump.xfl {

import aspire.util.XmlUtil;

import flump.mold.KeyframeMold;
import flump.mold.LayerMold;

public class XflLayer
{
    public static const NAME :String = "name";
    public static const TYPE :String = "layerType";

    public static const TYPE_GUIDE :String = "guide";
    public static const TYPE_FOLDER :String = "folder";
	public static const TYPE_MASK :String = "mask";

    use namespace xflns;

    public static function parse (lib :XflLibrary, baseLocation :String, xml :XML, flipbook :Boolean) :LayerMold {
        const layer :LayerMold = new LayerMold();
        layer.name = XmlUtil.getStringAttr(xml, NAME);
        layer.flipbook = flipbook;
		// mask
		if (mask!=null) layer.mask = mask;
        const location :String = baseLocation + ":" + layer.name;
        var frameXmlList :XMLList = xml.frames.DOMFrame;
        for each (var frameXml :XML in frameXmlList) {
            layer.keyframes.push(XflKeyframe.parse(lib, location, frameXml, flipbook));
        }
        if (layer.keyframes.length == 0) lib.addError(location, ParseError.INFO, "No keyframes on layer");

        var ii :int;
        var kf :KeyframeMold;
        var nextKf :KeyframeMold;

        // normalize skews, so that we always skew the shortest distance between
        // two angles (we don't want to skew more than Math.PI)
        for (ii = 0; ii < layer.keyframes.length - 1; ++ii) {
            kf = layer.keyframes[ii];
            nextKf = layer.keyframes[ii+1];
            frameXml = frameXmlList[ii];

            if (kf.skewX + Math.PI < nextKf.skewX) {
                nextKf.skewX += -Math.PI * 2;
            } else if (kf.skewX - Math.PI > nextKf.skewX) {
                nextKf.skewX += Math.PI * 2;
            }
            if (kf.skewY + Math.PI < nextKf.skewY) {
                nextKf.skewY += -Math.PI * 2;
            } else if (kf.skewY - Math.PI > nextKf.skewY) {
                nextKf.skewY += Math.PI * 2;
            }
        }

        // apply additional rotations
        var additionalRotation :Number = 0;
        for (ii = 0; ii < layer.keyframes.length - 1; ++ii) {
            kf = layer.keyframes[ii];
            nextKf = layer.keyframes[ii+1];
            frameXml = frameXmlList[ii];

            var motionTweenRotate :String = XmlUtil.getStringAttr(frameXml,
                XflKeyframe.MOTION_TWEEN_ROTATE, XflKeyframe.MOTION_TWEEN_ROTATE_NONE);

            // If a direction is specified, take it into account
            if (motionTweenRotate != XflKeyframe.MOTION_TWEEN_ROTATE_NONE) {
                var direction :Number = (motionTweenRotate == XflKeyframe.MOTION_TWEEN_ROTATE_CLOCKWISE ? 1 : -1);
                // negative scales affect rotation direction
                direction *= sign(nextKf.scaleX) * sign(nextKf.scaleY);

                while (direction < 0 && kf.skewX < nextKf.skewX) {
                    nextKf.skewX -= Math.PI * 2;
                }
                while (direction > 0 && kf.skewX > nextKf.skewX) {
                    nextKf.skewX += Math.PI * 2;
                }
                while (direction < 0 && kf.skewY < nextKf.skewY) {
                    nextKf.skewY -= Math.PI * 2;
                }
                while (direction > 0 && kf.skewY > nextKf.skewY) {
                    nextKf.skewY += Math.PI * 2;
                }

                // additional rotations specified?
                var motionTweenRotateTimes :Number =
                    XmlUtil.getNumberAttr(frameXml, XflKeyframe.MOTION_TWEEN_ROTATE_TIMES, 0);
                var thisRotation :Number = motionTweenRotateTimes * Math.PI * 2 * direction;
                additionalRotation += thisRotation;
            }

            nextKf.rotate(additionalRotation);
        }

        return layer;
    }

    protected static function sign (n :Number) :Number {
        return (n > 0 ? 1 : (n < 0 ? -1 : 0));
    }
}
}

Revert "fix XflLayer parse signature"

Revert "fix XflLayer parse signature"

This reverts commit 47388cac329edc12b6a57798a59f27b37b2923b1.


package nt.lib.util
{
	import flash.system.Capabilities;

	[Inline]
	public function assert(b:Boolean, m:String = "", errorClass:Class = null):void
	{
		if (Capabilities.isDebugger)
		{
			if (!b)
			{
				throw new (errorClass ||= Error)(m);
			}
		}
	}
}

package nt.lib.util
{
	import flash.system.Capabilities;
/**
 *debug异常抛出类
 *@param b 值为flase则抛出异常
 *@param m 如果错误类为空则抛出该错误信息
 *@param errorClass 错误类
 */
	[Inline]
	public function assert(b:Boolean, m:String = "", errorClass:Class = null):void
	{
		if (Capabilities.isDebugger)
		{
			if (!b)
			{
				throw new (errorClass ||= Error)(m);
			}
		}
	}
}

add annotate

add annotate


package aerys.minko.render
{
	import aerys.minko.ns.minko_render;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.render.geometry.stream.IVertexStream;
	import aerys.minko.render.geometry.stream.StreamUsage;
	import aerys.minko.render.geometry.stream.VertexStream;
	import aerys.minko.render.geometry.stream.format.VertexComponent;
	import aerys.minko.render.geometry.stream.format.VertexFormat;
	import aerys.minko.render.resource.Context3DResource;
	import aerys.minko.render.resource.IndexBuffer3DResource;
	import aerys.minko.render.resource.Program3DResource;
	import aerys.minko.render.resource.VertexBuffer3DResource;
	import aerys.minko.render.resource.texture.ITextureResource;
	import aerys.minko.render.shader.binding.IBinder;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.enum.Blending;
	import aerys.minko.type.enum.ColorMask;
	import aerys.minko.type.enum.TriangleCulling;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	import flash.display3D.Context3DProgramType;
	import flash.utils.Dictionary;

	/**
	 * DrawCall objects contain all the shader constants and buffer settings required
	 * to perform drawing operations using the Stage3D API.
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class DrawCall
	{
		use namespace minko_render;

		private static const PROGRAM_TYPE_VERTEX	: String			= Context3DProgramType.VERTEX;
		private static const PROGRAM_TYPE_FRAGMENT	: String			= Context3DProgramType.FRAGMENT;
		private static const NUM_TEXTURES			: uint				= 8;
		private static const NUM_VERTEX_BUFFERS		: uint				= 8;

		private static const TMP_VECTOR4			: Vector4			= new Vector4();
		private static const TMP_NUMBERS			: Vector.<Number>	= new Vector.<Number>(0xffff, true);
		private static const TMP_INTS				: Vector.<int>		= new Vector.<int>(0xffff, true);

		private var _bindings			: Object							= null;

		private var _vsInputComponents	: Vector.<VertexComponent>			= null;
		private var _vsInputIndices		: Vector.<uint>						= null;
		private var _cpuConstants		: Dictionary						= null;
		private var _vsConstants		: Vector.<Number>					= null;
		private var _fsConstants		: Vector.<Number>					= null;
		private var _fsTextures			: Vector.<ITextureResource>			= new Vector.<ITextureResource>(NUM_TEXTURES, true);

		// states
		private var _indexBuffer		: IndexBuffer3DResource				= null;
		private var _firstIndex			: int								= 0;
		private var _numTriangles		: int								= -1;

		private var _vertexBuffers		: Vector.<VertexBuffer3DResource>	= new Vector.<VertexBuffer3DResource>(NUM_VERTEX_BUFFERS, true);
		private var _numVertexComponents: uint								= 0;
		private var _offsets			: Vector.<int>						= new Vector.<int>(8, true);
		private var _formats			: Vector.<String>					= new Vector.<String>(8, true);

		private var _blending			: uint								= 0;
		private var _blendingSource		: String							= null;
		private var _blendingDest		: String							= null;

		private var _triangleCulling	: uint								= 0;
		private var _triangleCullingStr	: String							= null;

		private var _colorMask			: uint								= 0;
		private var _colorMaskR			: Boolean							= true;
		private var _colorMaskG			: Boolean							= true;
		private var _colorMaskB			: Boolean							= true;
		private var _colorMaskA			: Boolean							= true;

		private var _enabled			: Boolean							= true;

		private var _depth				: Number							= 0.;
        private var _center				: Vector4							= null;
		private var _invalidDepth		: Boolean							= false;
		private var _localToWorld		: Matrix4x4							= null;
		private var _worldToScreen		: Matrix4x4							= null;

		private var _bindingsConsumer	: DrawCallBindingsConsumer;

		public function get vertexComponents() : Vector.<VertexComponent>
		{
			return _vsInputComponents;
		}

		public function get blending() : uint
		{
			return _blending;
		}
		public function set blending(value : uint) : void
		{
			_blending = value;
			_blendingSource = Blending.STRINGS[int(value & 0xffff)];
			_blendingDest	= Blending.STRINGS[int(value >>> 16)]
		}

		public function get triangleCulling() : uint
		{
			return _triangleCulling;
		}
		public function set triangleCulling(value : uint) : void
		{
			_triangleCulling = value;
			_triangleCullingStr = TriangleCulling.STRINGS[value];
		}

		public function get colorMask() : uint
		{
			return _colorMask;
		}
		public function set colorMask(value : uint) : void
		{
			_colorMask = value;
			_colorMaskR = (value & ColorMask.RED) != 0;
			_colorMaskG = (value & ColorMask.GREEN) != 0;
			_colorMaskB = (value & ColorMask.BLUE) != 0;
			_colorMaskA = (value & ColorMask.ALPHA) != 0;
		}

		public function get enabled() : Boolean
		{
			return _enabled;
		}
		public function set enabled(value : Boolean) : void
		{
			_enabled = value;
			if (_bindingsConsumer)
				_bindingsConsumer.enabled = value;
		}

		public function get depth() : Number
		{
			if (_invalidDepth && _enabled)
			{
				_invalidDepth = false;

				if (_localToWorld != null && _worldToScreen != null)
				{
					var worldSpacePosition 	: Vector4	= _localToWorld.transformVector(
						_center, TMP_VECTOR4
					);
					var screenSpacePosition : Vector4 	= _worldToScreen.transformVector(
						worldSpacePosition, TMP_VECTOR4
					);

					_depth = screenSpacePosition.z / screenSpacePosition.w;
				}
			}

			return _depth;
		}

		public function configure(program		: Program3DResource,
								  geometry		: Geometry,
								  meshBindings	: DataBindings,
								  sceneBindings	: DataBindings,
								  computeDepth	: Boolean) : void
		{
			_invalidDepth = computeDepth;

			setProgram(program);
			setGeometry(geometry);
			setBindings(meshBindings, sceneBindings, computeDepth);
		}

		public function unsetBindings(meshBindings	: DataBindings,
									  sceneBindings	: DataBindings) : void
		{
			if (_bindingsConsumer != null)
			{
				meshBindings.removeConsumer(_bindingsConsumer);
				sceneBindings.removeConsumer(_bindingsConsumer);
			}

			if (sceneBindings.hasCallback('worldToScreen', transformChangedHandler))
				sceneBindings.removeCallback('worldToScreen', transformChangedHandler);

			if (meshBindings.hasCallback('localToWorld', transformChangedHandler))
				meshBindings.removeCallback('localToWorld', transformChangedHandler);
		}

		private function setProgram(program : Program3DResource) : void
		{
			_cpuConstants		= new Dictionary();
			_vsConstants		= program._vsConstants.slice();
			_fsConstants		= program._fsConstants.slice();
			_fsTextures			= program._fsTextures.slice();
			_vsInputComponents	= program._vertexInputComponents;
			_vsInputIndices		= program._vertexInputIndices;
			_bindings			= program._bindings;

			_bindingsConsumer	= new DrawCallBindingsConsumer(
				_bindings,
				_cpuConstants,
				_vsConstants,
				_fsConstants,
				_fsTextures
			);
			_bindingsConsumer.enabled = _enabled;

			triangleCulling		= TriangleCulling.FRONT;
			blending			= Blending.NORMAL;
			colorMask			= ColorMask.RGBA;
		}

		 /**
		  * Ask geometry to compute additional vertex data if needed for this drawcall.
		  */
		public function updateGeometry(geometry : Geometry) : void
		{
			var vertexFormat    : VertexFormat	= geometry.format;
            var hasNormals      : Boolean       = vertexFormat.hasComponent(VertexComponent.NORMAL);

			if (_vsInputComponents.indexOf(VertexComponent.TANGENT) >= 0
				&& !vertexFormat.hasComponent(VertexComponent.TANGENT))
			{
				geometry.computeTangentSpace(!hasNormals);
			}
			else if (_vsInputComponents.indexOf(VertexComponent.NORMAL) >= 0 && !hasNormals)
			{
				geometry.computeNormals();
			}
		}

		/**
		 * Obtain a reference to each buffer and offset that apply() may possibly need.
		 *
		 */
		public function setGeometry(geometry : Geometry, frame : uint = 0) : void
		{
			if (!_vsInputComponents)
				return ;

			updateGeometry(geometry);

			_center = geometry.boundingSphere
				? geometry.boundingSphere.center
				: Vector4.ZERO;

			_numVertexComponents = _vsInputComponents.length;
			_indexBuffer		 = geometry.indexStream.resource;
			_firstIndex			 = geometry.firstIndex;
			_numTriangles		 = geometry.numTriangles;

			for (var i : uint = 0; i < _numVertexComponents; ++i)
			{
				var component : VertexComponent	= _vsInputComponents[i];
				var index	  : uint			= _vsInputIndices[i];

				if (component)
				{
					var vertexStream	: IVertexStream = geometry.getVertexStream(index + frame);
					var stream	 		: VertexStream	= vertexStream.getStreamByComponent(component);

					if (stream == null)
					{
						throw new Error(
							'Missing vertex component: \'' + component.toString() + '\'.'
						);
					}

					_vertexBuffers[i]	= stream.resource;
					_formats[i]			= component.nativeFormatString;
					_offsets[i]			= stream.format.getOffsetForComponent(component);
				}
			}
		}

		/**
		 * @fixme There is a bug here
		 * @fixme We splitted properties between scene and mesh
		 * @fixme it should be done on the compiler also to avoid this ugly hack
		 */
		private function setBindings(meshBindings	: DataBindings,
									 sceneBindings	: DataBindings,
									 computeDepth	: Boolean) : void
		{
			meshBindings.addConsumer(_bindingsConsumer);
			sceneBindings.addConsumer(_bindingsConsumer);

			if (computeDepth)
			{
				_worldToScreen = sceneBindings.getProperty('worldToScreen') as Matrix4x4;
				_localToWorld = meshBindings.getProperty('localToWorld') as Matrix4x4;

				sceneBindings.addCallback('worldToScreen', transformChangedHandler);
				meshBindings.addCallback('localToWorld', transformChangedHandler);

				_invalidDepth = true;
			}
		}

		public function apply(context : Context3DResource, previous : DrawCall) : uint
		{
			if (!_enabled)
				return 0;

			context.setColorMask(_colorMaskR, _colorMaskG, _colorMaskB, _colorMaskA)
				   .setProgramConstantsFromVector(PROGRAM_TYPE_VERTEX, 0, _vsConstants)
				   .setProgramConstantsFromVector(PROGRAM_TYPE_FRAGMENT, 0, _fsConstants);

			var numTextures	: uint	= _fsTextures.length;
			var maxTextures	: uint	= previous ? previous._fsTextures.length : NUM_TEXTURES;
			var maxBuffers	: uint	= previous ? previous._numVertexComponents : NUM_VERTEX_BUFFERS;
			var i 			: uint 	= 0;

			// setup textures
			for (i = 0; i < numTextures; ++i)
			{
				context.setTextureAt(
					i,
					(_fsTextures[i] as ITextureResource).getTexture(context)
				);
			}

			while (i < maxTextures)
				context.setTextureAt(i++, null);

			// setup buffers
			for (i = 0; i < _numVertexComponents; ++i)
			{
				context.setVertexBufferAt(
					i,
					(_vertexBuffers[i] as VertexBuffer3DResource).getVertexBuffer3D(context),
					_offsets[i],
					_formats[i]
				);
			}

			while (i < maxBuffers)
				context.setVertexBufferAt(i++, null);

			// draw triangles
			context.drawTriangles(
				_indexBuffer.getIndexBuffer3D(context),
				_firstIndex,
				_numTriangles
			);

			return _numTriangles == -1 ? _indexBuffer.numIndices / 3 : _numTriangles;
		}

		public function setParameter(name : String, value : Object) : void
		{
			_bindingsConsumer.setProperty(name, value);
		}

		private function transformChangedHandler(bindings 	: DataBindings,
												 property 	: String,
												 oldValue	: Matrix4x4,
												 newValue	: Matrix4x4) : void
		{
			if (property == 'worldToScreen')
				_worldToScreen = newValue;
			else if (property == 'localToWorld')
				_localToWorld = newValue;

			_invalidDepth = true;
		}
	}
}

package aerys.minko.render
{
	import aerys.minko.ns.minko_render;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.render.geometry.stream.IVertexStream;
	import aerys.minko.render.geometry.stream.StreamUsage;
	import aerys.minko.render.geometry.stream.VertexStream;
	import aerys.minko.render.geometry.stream.format.VertexComponent;
	import aerys.minko.render.geometry.stream.format.VertexFormat;
	import aerys.minko.render.resource.Context3DResource;
	import aerys.minko.render.resource.IndexBuffer3DResource;
	import aerys.minko.render.resource.Program3DResource;
	import aerys.minko.render.resource.VertexBuffer3DResource;
	import aerys.minko.render.resource.texture.ITextureResource;
	import aerys.minko.render.shader.binding.IBinder;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.enum.Blending;
	import aerys.minko.type.enum.ColorMask;
	import aerys.minko.type.enum.TriangleCulling;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	import flash.display3D.Context3DProgramType;
	import flash.utils.Dictionary;

	/**
	 * DrawCall objects contain all the shader constants and buffer settings required
	 * to perform drawing operations using the Stage3D API.
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class DrawCall
	{
		use namespace minko_render;

		private static const PROGRAM_TYPE_VERTEX	: String			= Context3DProgramType.VERTEX;
		private static const PROGRAM_TYPE_FRAGMENT	: String			= Context3DProgramType.FRAGMENT;
		private static const NUM_TEXTURES			: uint				= 8;
		private static const NUM_VERTEX_BUFFERS		: uint				= 8;

		private static const TMP_VECTOR4			: Vector4			= new Vector4();
		private static const TMP_NUMBERS			: Vector.<Number>	= new Vector.<Number>(0xffff, true);
		private static const TMP_INTS				: Vector.<int>		= new Vector.<int>(0xffff, true);

		private var _bindings			: Object							= null;

		private var _vsInputComponents	: Vector.<VertexComponent>			= null;
		private var _vsInputIndices		: Vector.<uint>						= null;
		private var _cpuConstants		: Dictionary						= null;
		private var _vsConstants		: Vector.<Number>					= null;
		private var _fsConstants		: Vector.<Number>					= null;
		private var _fsTextures			: Vector.<ITextureResource>			= new Vector.<ITextureResource>(NUM_TEXTURES, true);

		// states
		private var _indexBuffer		: IndexBuffer3DResource				= null;
		private var _firstIndex			: int								= 0;
		private var _numTriangles		: int								= -1;

		private var _vertexBuffers		: Vector.<VertexBuffer3DResource>	= new Vector.<VertexBuffer3DResource>(NUM_VERTEX_BUFFERS, true);
		private var _numVertexComponents: uint								= 0;
		private var _offsets			: Vector.<int>						= new Vector.<int>(8, true);
		private var _formats			: Vector.<String>					= new Vector.<String>(8, true);

		private var _blending			: uint								= 0;
		private var _blendingSource		: String							= null;
		private var _blendingDest		: String							= null;

		private var _triangleCulling	: uint								= 0;
		private var _triangleCullingStr	: String							= null;

		private var _colorMask			: uint								= 0;
		private var _colorMaskR			: Boolean							= true;
		private var _colorMaskG			: Boolean							= true;
		private var _colorMaskB			: Boolean							= true;
		private var _colorMaskA			: Boolean							= true;

		private var _enabled			: Boolean							= true;

		private var _depth				: Number							= 0.;
        private var _center				: Vector4							= null;
		private var _invalidDepth		: Boolean							= false;
		private var _localToWorld		: Matrix4x4							= null;
		private var _worldToScreen		: Matrix4x4							= null;

		private var _bindingsConsumer	: DrawCallBindingsConsumer;

		public function get vertexComponents() : Vector.<VertexComponent>
		{
			return _vsInputComponents;
		}

		public function get blending() : uint
		{
			return _blending;
		}
		public function set blending(value : uint) : void
		{
			_blending = value;
			_blendingSource = Blending.STRINGS[int(value & 0xffff)];
			_blendingDest	= Blending.STRINGS[int(value >>> 16)]
		}

		public function get triangleCulling() : uint
		{
			return _triangleCulling;
		}
		public function set triangleCulling(value : uint) : void
		{
			_triangleCulling = value;
			_triangleCullingStr = TriangleCulling.STRINGS[value];
		}

		public function get colorMask() : uint
		{
			return _colorMask;
		}
		public function set colorMask(value : uint) : void
		{
			_colorMask = value;
			_colorMaskR = (value & ColorMask.RED) != 0;
			_colorMaskG = (value & ColorMask.GREEN) != 0;
			_colorMaskB = (value & ColorMask.BLUE) != 0;
			_colorMaskA = (value & ColorMask.ALPHA) != 0;
		}

		public function get enabled() : Boolean
		{
			return _enabled;
		}
		public function set enabled(value : Boolean) : void
		{
			_enabled = value;
			if (_bindingsConsumer)
				_bindingsConsumer.enabled = value;
		}

		public function get depth() : Number
		{
			if (_invalidDepth && _enabled)
			{
				_invalidDepth = false;

				if (_localToWorld != null && _worldToScreen != null)
				{
					var worldSpacePosition 	: Vector4	= _localToWorld.transformVector(
						_center, TMP_VECTOR4
					);
					var screenSpacePosition : Vector4 	= _worldToScreen.transformVector(
						worldSpacePosition, TMP_VECTOR4
					);

					_depth = screenSpacePosition.z / screenSpacePosition.w;
				}
			}

			return _depth;
		}

		public function configure(program		: Program3DResource,
								  geometry		: Geometry,
								  meshBindings	: DataBindings,
								  sceneBindings	: DataBindings,
								  computeDepth	: Boolean) : void
		{
			_invalidDepth = computeDepth;

			setProgram(program);
			setGeometry(geometry);
			setBindings(meshBindings, sceneBindings, computeDepth);
		}

		public function unsetBindings(meshBindings	: DataBindings,
									  sceneBindings	: DataBindings) : void
		{
			if (_bindingsConsumer != null)
			{
				meshBindings.removeConsumer(_bindingsConsumer);
				sceneBindings.removeConsumer(_bindingsConsumer);
			}

			if (sceneBindings.hasCallback('worldToScreen', transformChangedHandler))
				sceneBindings.removeCallback('worldToScreen', transformChangedHandler);

			if (meshBindings.hasCallback('localToWorld', transformChangedHandler))
				meshBindings.removeCallback('localToWorld', transformChangedHandler);

            _bindingsConsumer = null;
		}

		private function setProgram(program : Program3DResource) : void
		{
			_cpuConstants		= new Dictionary();
			_vsConstants		= program._vsConstants.slice();
			_fsConstants		= program._fsConstants.slice();
			_fsTextures			= program._fsTextures.slice();
			_vsInputComponents	= program._vertexInputComponents;
			_vsInputIndices		= program._vertexInputIndices;
			_bindings			= program._bindings;

			_bindingsConsumer	= new DrawCallBindingsConsumer(
				_bindings,
				_cpuConstants,
				_vsConstants,
				_fsConstants,
				_fsTextures
			);
			_bindingsConsumer.enabled = _enabled;

			triangleCulling		= TriangleCulling.FRONT;
			blending			= Blending.NORMAL;
			colorMask			= ColorMask.RGBA;
		}

		 /**
		  * Ask geometry to compute additional vertex data if needed for this drawcall.
		  */
		public function updateGeometry(geometry : Geometry) : void
		{
			var vertexFormat    : VertexFormat	= geometry.format;
            var hasNormals      : Boolean       = vertexFormat.hasComponent(VertexComponent.NORMAL);

			if (_vsInputComponents.indexOf(VertexComponent.TANGENT) >= 0
				&& !vertexFormat.hasComponent(VertexComponent.TANGENT))
			{
				geometry.computeTangentSpace(!hasNormals);
			}
			else if (_vsInputComponents.indexOf(VertexComponent.NORMAL) >= 0 && !hasNormals)
			{
				geometry.computeNormals();
			}
		}

		/**
		 * Obtain a reference to each buffer and offset that apply() may possibly need.
		 *
		 */
		public function setGeometry(geometry : Geometry, frame : uint = 0) : void
		{
			if (!_vsInputComponents)
				return ;

			updateGeometry(geometry);

			_center = geometry.boundingSphere
				? geometry.boundingSphere.center
				: Vector4.ZERO;

			_numVertexComponents = _vsInputComponents.length;
			_indexBuffer		 = geometry.indexStream.resource;
			_firstIndex			 = geometry.firstIndex;
			_numTriangles		 = geometry.numTriangles;

			for (var i : uint = 0; i < _numVertexComponents; ++i)
			{
				var component : VertexComponent	= _vsInputComponents[i];
				var index	  : uint			= _vsInputIndices[i];

				if (component)
				{
					var vertexStream	: IVertexStream = geometry.getVertexStream(index + frame);
					var stream	 		: VertexStream	= vertexStream.getStreamByComponent(component);

					if (stream == null)
					{
						throw new Error(
							'Missing vertex component: \'' + component.toString() + '\'.'
						);
					}

					_vertexBuffers[i]	= stream.resource;
					_formats[i]			= component.nativeFormatString;
					_offsets[i]			= stream.format.getOffsetForComponent(component);
				}
			}
		}

		/**
		 * @fixme There is a bug here
		 * @fixme We splitted properties between scene and mesh
		 * @fixme it should be done on the compiler also to avoid this ugly hack
		 */
		private function setBindings(meshBindings	: DataBindings,
									 sceneBindings	: DataBindings,
									 computeDepth	: Boolean) : void
		{
			meshBindings.addConsumer(_bindingsConsumer);
			sceneBindings.addConsumer(_bindingsConsumer);

			if (computeDepth)
			{
				_worldToScreen = sceneBindings.getProperty('worldToScreen') as Matrix4x4;
				_localToWorld = meshBindings.getProperty('localToWorld') as Matrix4x4;

				sceneBindings.addCallback('worldToScreen', transformChangedHandler);
				meshBindings.addCallback('localToWorld', transformChangedHandler);

				_invalidDepth = true;
			}
		}

		public function apply(context : Context3DResource, previous : DrawCall) : uint
		{
			if (!_enabled)
				return 0;

			context.setColorMask(_colorMaskR, _colorMaskG, _colorMaskB, _colorMaskA)
				   .setProgramConstantsFromVector(PROGRAM_TYPE_VERTEX, 0, _vsConstants)
				   .setProgramConstantsFromVector(PROGRAM_TYPE_FRAGMENT, 0, _fsConstants);

			var numTextures	: uint	= _fsTextures.length;
			var maxTextures	: uint	= previous ? previous._fsTextures.length : NUM_TEXTURES;
			var maxBuffers	: uint	= previous ? previous._numVertexComponents : NUM_VERTEX_BUFFERS;
			var i 			: uint 	= 0;

			// setup textures
			for (i = 0; i < numTextures; ++i)
			{
				context.setTextureAt(
					i,
					(_fsTextures[i] as ITextureResource).getTexture(context)
				);
			}

			while (i < maxTextures)
				context.setTextureAt(i++, null);

			// setup buffers
			for (i = 0; i < _numVertexComponents; ++i)
			{
				context.setVertexBufferAt(
					i,
					(_vertexBuffers[i] as VertexBuffer3DResource).getVertexBuffer3D(context),
					_offsets[i],
					_formats[i]
				);
			}

			while (i < maxBuffers)
				context.setVertexBufferAt(i++, null);

			// draw triangles
			context.drawTriangles(
				_indexBuffer.getIndexBuffer3D(context),
				_firstIndex,
				_numTriangles
			);

			return _numTriangles == -1 ? _indexBuffer.numIndices / 3 : _numTriangles;
		}

		public function setParameter(name : String, value : Object) : void
		{
			_bindingsConsumer.setProperty(name, value);
		}

		private function transformChangedHandler(bindings 	: DataBindings,
												 property 	: String,
												 oldValue	: Matrix4x4,
												 newValue	: Matrix4x4) : void
		{
			if (property == 'worldToScreen')
				_worldToScreen = newValue;
			else if (property == 'localToWorld')
				_localToWorld = newValue;

			_invalidDepth = true;
		}
	}
}

set _bindingConsumer to null when the bindings are unset


////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package spark.utils
{
import mx.core.DPIClassification;

/**
 *  This class provides a list of bitmaps for various runtime densities.  It is supplied
 *  as the source to BitmapImage or Image and as the icon of a Button.  The components
 *  will use the Application.runtimeDPI to choose which image to display.
 *
 *  @langversion 3.0
 *  @playerversion Flash 10.2
 *  @playerversion AIR 2.6
 *  @productversion Flex 4.5
 */
public class MultiDPIBitmapSource
{
    include "../core/Version.as";

	/**
	 *  The source to use if the Application.runtimeDPI
	 *  is DPIClassification.DPI_120.
	 *
	 *  @langversion 3.0
	 *  @playerversion Flash 10.2
	 *  @playerversion AIR 2.6
	 *  @productversion ApacheFlex 4.11
	 */
	public var source120dpi:Object;

    /**
     *  The source to use if the Application.runtimeDPI
     *  is DPIClassification.DPI_160.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion Flex 4.5
     */
    public var source160dpi:Object;

    /**
     *  The source to use if the Application.runtimeDPI
     *  is DPIClassification.DPI_240.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion Flex 4.5
     */
    public var source240dpi:Object;

	/**
	 *  The source to use if the Application.runtimeDPI
	 *  is DPIClassification.DPI_320.
	 *
	 *  @langversion 3.0
	 *  @playerversion Flash 10.2
	 *  @playerversion AIR 2.6
	 *  @productversion Flex 4.5
	 */
	public var source320dpi:Object;

	/**
	 *  The source to use if the Application.runtimeDPI
	 *  is DPIClassification.DPI_480.
	 *
	 *  @langversion 3.0
	 *  @playerversion Flash 10.2
	 *  @playerversion AIR 2.6
	 *  @productversion ApacheFlex 4.10
	 */
	public var source640dpi:Object;

	/**
	 *  The source to use if the Application.runtimeDPI
	 *  is DPIClassification.DPI_640.
	 *
	 *  @langversion 3.0
	 *  @playerversion Flash 10.2
	 *  @playerversion AIR 2.6
	 *  @productversion ApacheFlex 4.11
	 */
	public var source640dpi:Object;

    /**
     *  Select one of the sourceXXXdpi properties based on the given DPI.  This
     *  function handles the fallback to different sourceXXXdpi properties
     *  if the given one is null.
     *  The strategy is to try to choose the next highest
     *  property if it is not null, then return a lower property if not null, then
     *  just return null.
     *
     *  @param The desired DPI.
     *
     *  @return One of the sourceXXXdpi properties based on the desired DPI.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion Flex 4.5
     */
    public function getSource(desiredDPI:Number):Object
    {
        var source:Object = source160dpi;
        switch (desiredDPI)
        {
			case DPIClassification.DPI_640:
				source = source640dpi;
				if (!source || source == "")
					source = source480dpi;
				if (!source || source == "")
					source = source320dpi;
				if (!source || source == "")
					source = source240dpi;
				if (!source || source == "")
					source = source160dpi;
				if (!source || source == "")
					source = source120dpi;
				break;
			case DPIClassification.DPI_480:
				source = source480dpi;
				if (!source || source == "")
					source = source640dpi;
				if (!source || source == "")
					source = source320dpi;
				if (!source || source == "")
					source = source240dpi;
				if (!source || source == "")
					source = source160dpi;
				if (!source || source == "")
					source = source120dpi;
				break;
            case DPIClassification.DPI_320:
                source = source320dpi;
				if (!source || source == "")
					source = source480dpi;
				if (!source || source == "")
					source = source640dpi;
                if (!source || source == "")
                    source = source240dpi;
                if (!source || source == "")
                    source = source160dpi;
				if (!source || source == "")
					source = source120dpi;
                break;
			case DPIClassification.DPI_240:
				source = source240dpi;
				if (!source || source == "")
					source = source320dpi;
				if (!source || source == "")
					source = source480dpi;
				if (!source || source == "")
					source = source640dpi;
				if (!source || source == "")
					source = source160dpi;
				if (!source || source == "")
					source = source120dpi;
				break;
			case DPIClassification.DPI_160:
				source = source160dpi;
				if (!source || source == "")
					source = source240dpi;
				if (!source || source == "")
					source = source320dpi;
				if (!source || source == "")
					source = source480dpi;
				if (!source || source == "")
					source = source640dpi;
				if (!source || source == "")
					source = source120dpi;
				break;
			case DPIClassification.DPI_120:
				source = source120dpi;
				if (!source || source == "")
					source = source160dpi;
				if (!source || source == "")
					source = source240dpi;
				if (!source || source == "")
					source = source320dpi;
				if (!source || source == "")
					source = source480dpi;
				if (!source || source == "")
					source = source640dpi;
				break;
        }
        return source;

    }

}
}

////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package spark.utils
{
import mx.core.DPIClassification;

/**
 *  This class provides a list of bitmaps for various runtime densities.  It is supplied
 *  as the source to BitmapImage or Image and as the icon of a Button.  The components
 *  will use the Application.runtimeDPI to choose which image to display.
 *
 *  @langversion 3.0
 *  @playerversion Flash 10.2
 *  @playerversion AIR 2.6
 *  @productversion Flex 4.5
 */
public class MultiDPIBitmapSource
{
    include "../core/Version.as";

	/**
	 *  The source to use if the Application.runtimeDPI
	 *  is DPIClassification.DPI_120.
	 *
	 *  @langversion 3.0
	 *  @playerversion Flash 10.2
	 *  @playerversion AIR 2.6
	 *  @productversion ApacheFlex 4.11
	 */
	public var source120dpi:Object;

    /**
     *  The source to use if the Application.runtimeDPI
     *  is DPIClassification.DPI_160.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion Flex 4.5
     */
    public var source160dpi:Object;

    /**
     *  The source to use if the Application.runtimeDPI
     *  is DPIClassification.DPI_240.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion Flex 4.5
     */
    public var source240dpi:Object;

	/**
	 *  The source to use if the Application.runtimeDPI
	 *  is DPIClassification.DPI_320.
	 *
	 *  @langversion 3.0
	 *  @playerversion Flash 10.2
	 *  @playerversion AIR 2.6
	 *  @productversion Flex 4.5
	 */
	public var source320dpi:Object;

	/**
	 *  The source to use if the Application.runtimeDPI
	 *  is DPIClassification.DPI_480.
	 *
	 *  @langversion 3.0
	 *  @playerversion Flash 10.2
	 *  @playerversion AIR 2.6
	 *  @productversion ApacheFlex 4.10
	 */
	public var source480dpi:Object;

	/**
	 *  The source to use if the Application.runtimeDPI
	 *  is DPIClassification.DPI_640.
	 *
	 *  @langversion 3.0
	 *  @playerversion Flash 10.2
	 *  @playerversion AIR 2.6
	 *  @productversion ApacheFlex 4.11
	 */
	public var source640dpi:Object;

    /**
     *  Select one of the sourceXXXdpi properties based on the given DPI.  This
     *  function handles the fallback to different sourceXXXdpi properties
     *  if the given one is null.
     *  The strategy is to try to choose the next highest
     *  property if it is not null, then return a lower property if not null, then
     *  just return null.
     *
     *  @param The desired DPI.
     *
     *  @return One of the sourceXXXdpi properties based on the desired DPI.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion Flex 4.5
     */
    public function getSource(desiredDPI:Number):Object
    {
        var source:Object = source160dpi;
        switch (desiredDPI)
        {
			case DPIClassification.DPI_640:
				source = source640dpi;
				if (!source || source == "")
					source = source480dpi;
				if (!source || source == "")
					source = source320dpi;
				if (!source || source == "")
					source = source240dpi;
				if (!source || source == "")
					source = source160dpi;
				if (!source || source == "")
					source = source120dpi;
				break;
			case DPIClassification.DPI_480:
				source = source480dpi;
				if (!source || source == "")
					source = source640dpi;
				if (!source || source == "")
					source = source320dpi;
				if (!source || source == "")
					source = source240dpi;
				if (!source || source == "")
					source = source160dpi;
				if (!source || source == "")
					source = source120dpi;
				break;
            case DPIClassification.DPI_320:
                source = source320dpi;
				if (!source || source == "")
					source = source480dpi;
				if (!source || source == "")
					source = source640dpi;
                if (!source || source == "")
                    source = source240dpi;
                if (!source || source == "")
                    source = source160dpi;
				if (!source || source == "")
					source = source120dpi;
                break;
			case DPIClassification.DPI_240:
				source = source240dpi;
				if (!source || source == "")
					source = source320dpi;
				if (!source || source == "")
					source = source480dpi;
				if (!source || source == "")
					source = source640dpi;
				if (!source || source == "")
					source = source160dpi;
				if (!source || source == "")
					source = source120dpi;
				break;
			case DPIClassification.DPI_160:
				source = source160dpi;
				if (!source || source == "")
					source = source240dpi;
				if (!source || source == "")
					source = source320dpi;
				if (!source || source == "")
					source = source480dpi;
				if (!source || source == "")
					source = source640dpi;
				if (!source || source == "")
					source = source120dpi;
				break;
			case DPIClassification.DPI_120:
				source = source120dpi;
				if (!source || source == "")
					source = source160dpi;
				if (!source || source == "")
					source = source240dpi;
				if (!source || source == "")
					source = source320dpi;
				if (!source || source == "")
					source = source480dpi;
				if (!source || source == "")
					source = source640dpi;
				break;
        }
        return source;

    }

}
}

fix 480 dpi bitmap source

fix 480 dpi bitmap source


//
// $Id$
//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/nenya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.threerings.flex {

import flash.events.Event;

import mx.controls.ComboBox;
import mx.events.ListEvent;

import com.threerings.util.CommandEvent;
import com.threerings.util.Util;

/**
 * A combo box that dispatches a command (or calls a callback) when an item is selected.
 * The argument will be the 'data' value of the selected item.
 * NOTE: Unlike the other Command* controls, CommandComboBox allows a null cmd/callback
 * to be specified.
 */
public class CommandComboBox extends ComboBox
{
    /** The field of the selectedItem object used as the 'data'. If this property is null,
     * then the item is the data. */
    public var dataField :String = "data";

    /**
     * Create a command combobox.
     *
     * @param cmdOrFn either a String, which will be the CommandEvent command to dispatch,
     *        or a function, which will be called when changed.
     */
    public function CommandComboBox (cmdOrFn :* = null)
    {
        CommandButton.validateCmd(cmdOrFn);
        _cmdOrFn = cmdOrFn;

        addEventListener(ListEvent.CHANGE, handleChange, false, int.MIN_VALUE);
    }

    /**
     * Set the command and argument to be issued when this button is pressed.
     */
    public function setCommand (cmd :String) :void
    {
        _cmdOrFn = cmd;
    }

    /**
     * Set a callback function to call when the button is pressed.
     */
    public function setCallback (fn :Function) :void
    {
        _cmdOrFn = fn;
    }

    /**
     * Set the selectedItem based on the data field.
     */
    public function set selectedData (data :Object) :void
    {
        for (var ii :int = 0; ii < dataProvider.length; ++ii) {
            if (Util.equals(data, itemToData(dataProvider[ii]))) {
                this.selectedIndex = ii;
                return;
            }
        }

        // not found, clear the selection
        this.selectedIndex = -1;
    }

    /**
     * The value that will be passed to the command or function based on dataField and the
     * current selected item.
     */
    public function get selectedData () :Object
    {
        return itemToData(this.selectedItem);
    }

    /**
     * Extract the data from the specified item. This can be expanded in the future
     * if we provide a 'dataFunction'.
     */
    protected function itemToData (item :Object) :Object
    {
        return (item == null || dataField == null) ? item : item[dataField];
    }

    protected function handleChange (event :ListEvent) :void
    {
        if (_cmdOrFn != null && this.selectedIndex != -1) {
            CommandEvent.dispatch(this, _cmdOrFn, selectedData);
        }
    }

    /** The command (String) to submit, or the function (Function) to call
     * when changed,  */
    protected var _cmdOrFn :Object;
}
}

//
// $Id$
//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/nenya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.threerings.flex {

import flash.events.Event;

import mx.controls.ComboBox;
import mx.events.ListEvent;

import com.threerings.util.CommandEvent;
import com.threerings.util.Util;

/**
 * A combo box that dispatches a command (or calls a callback) when an item is selected.
 * The argument will be the 'data' value of the selected item.
 * NOTE: Unlike the other Command* controls, CommandComboBox allows a null cmd/callback
 * to be specified.
 */
public class CommandComboBox extends ComboBox
{
    /** The field of the selectedItem object used as the 'data'. If this property is null,
     * then the item is the data. */
    public var dataField :String = "data";

    /**
     * Create a command combobox.
     *
     * @param cmdOrFn either a String, which will be the CommandEvent command to dispatch,
     *        or a function, which will be called when changed.
     */
    public function CommandComboBox (cmdOrFn :* = null)
    {
        CommandButton.validateCmd(cmdOrFn);
        _cmdOrFn = cmdOrFn;

        addEventListener(ListEvent.CHANGE, handleChange, false, int.MIN_VALUE);
    }

    /**
     * Set the command and argument to be issued when this button is pressed.
     */
    public function setCommand (cmd :String) :void
    {
        _cmdOrFn = cmd;
    }

    /**
     * Set a callback function to call when the button is pressed.
     */
    public function setCallback (fn :Function) :void
    {
        _cmdOrFn = fn;
    }

    /**
     * Set the selectedItem based on the data field.
     */
    public function set selectedData (data :Object) :void
    {
        for (var ii :int = 0; ii < dataProvider.length; ++ii) {
            if (Util.equals(data, itemToData(dataProvider[ii]))) {
                this.selectedIndex = ii;
                return;
            }
        }

        // not found, clear the selection
        this.selectedIndex = -1;
    }

    /**
     * The value that will be passed to the command or function based on dataField and the
     * current selected item.
     */
    public function get selectedData () :Object
    {
        return itemToData(this.selectedItem);
    }

    /**
     * Extract the data from the specified item. This can be expanded in the future
     * if we provide a 'dataFunction'.
     */
    protected function itemToData (item :Object) :Object
    {
        if (item != null && dataField != null) {
            try {
                return item[dataField];
            } catch (re :ReferenceError) {
                // fallback to just returning the item
            }
        }
        return item;
    }

    protected function handleChange (event :ListEvent) :void
    {
        if (_cmdOrFn != null && this.selectedIndex != -1) {
            CommandEvent.dispatch(this, _cmdOrFn, selectedData);
        }
    }

    /** The command (String) to submit, or the function (Function) to call
     * when changed,  */
    protected var _cmdOrFn :Object;
}
}

Fix for when the items don't have a 'data' property.

git-svn-id: b675b909355d5cf946977f44a8ec5a6ceb3782e4@756 ed5b42cb-e716-0410-a449-f6a68f950b19


package server {
	dynamic public class FMSClient extends Object {
		public function FMSClient() {
			super();
		}

		public function onRegisterUser(user:String, result:Object):void {
			trace('FMSClient.onRegisterUser:', user, result);
		}

		public function onStartGame(user:String):void {
			trace('FMSClient.onStartGame:', user);
		}

		public function onChangePlayer(user:String, player:uint):void {
			trace('FMSClient.onChangePlayer:', user, player);
		}

		public function onDisconnect(user:String):void {
			trace('FMSClient.onDisconnect:', user);
		}
	}
}

package server {
	dynamic public class FMSClient extends Object {
		public function FMSClient() {
			super();
		}

		public function onRegisterUser(user:String, result:Object):void {
			trace('FMSClient.onRegisterUser:', user, result);
		}

		public function onSigninUser(user:String, result:Object):void {
			trace('FMSClient.onSigninUser:', user, result);
		}

		public function onStartGame(user:String):void {
			trace('FMSClient.onStartGame:', user);
		}

		public function onChangePlayer(user:String, player:uint):void {
			trace('FMSClient.onChangePlayer:', user, player);
		}

		public function onDisconnect(user:String):void {
			trace('FMSClient.onDisconnect:', user);
		}
	}
}

Update FMSClient.as

Update FMSClient.as