package control
{
	import com.adobe.serialization.json.JSON;

	import dragonBones.objects.DataParser;
	import dragonBones.utils.ConstValues;

	import flash.display.BitmapData;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.FileReference;
	import flash.utils.ByteArray;

	import message.Message;
	import message.MessageDispatcher;

	import model.ImportDataProxy;
	import model.JSFLProxy;
	import model.XMLDataProxy;

	import utils.BitmapDataUtil;
	import utils.GlobalConstValues;
	import utils.PNGEncoder;
	import utils.xmlToObject;

	import zero.zip.Zip;

	public class ExportDataCommand
	{
		public static const instance:ExportDataCommand = new ExportDataCommand();

		private var _fileREF:FileReference;
		private var _isExporting:Boolean;
		private var _scale:Number;
		private var _exportType:uint;
		private var _backgroundColor:uint;

		private var _importDataProxy:ImportDataProxy;

		private var _xmlDataProxy:XMLDataProxy;
		private var _bitmapData:BitmapData;

		public function ExportDataCommand()
		{
			_fileREF = new FileReference();

			_importDataProxy = ImportDataProxy.getInstance();
		}

		public function export(exportType:uint, scale:Number, backgroundColor:uint = 0):void
		{
			if(_isExporting)
			{
				return;
			}
			_isExporting = true;

			_exportType = exportType;
			_scale = scale;

			switch(_exportType)
			{
				case 0:
				case 2:
				case 5:
					_scale = 1;
					break;
			}

			_backgroundColor = backgroundColor;

			exportStart();
		}

		private function exportStart():void
		{
			var dataBytes:ByteArray;
			var zip:Zip;
			var date:Date;

			_xmlDataProxy = _importDataProxy.xmlDataProxy;
			_bitmapData = _importDataProxy.textureAtlas.bitmapData;

			if(_scale != 1)
			{
				_xmlDataProxy = _xmlDataProxy.clone();
				var subBitmapDataDic:Object;
				var movieClip:MovieClip = _importDataProxy.textureAtlas.movieClip;
				if(movieClip && movieClip.totalFrames >= 3)
				{
					subBitmapDataDic = {};
					for each (var displayName:String in _xmlDataProxy.getSubTextureListFromDisplayList())
					{
						movieClip.gotoAndStop(movieClip.totalFrames);
						movieClip.gotoAndStop(displayName);
						subBitmapDataDic[displayName] = movieClip.getChildAt(0);
					}
				}
				else
				{
					subBitmapDataDic = BitmapDataUtil.getSubBitmapDataDic(
						_bitmapData,
						_xmlDataProxy.getSubTextureRectMap()
					);
				}

				_xmlDataProxy.scaleData(_scale);

				_bitmapData = BitmapDataUtil.getMergeBitmapData(
					subBitmapDataDic,
					_xmlDataProxy.getSubTextureRectMap(),
					_xmlDataProxy.textureAtlasWidth,
					_xmlDataProxy.textureAtlasHeight,
					_scale
				);
			}

			var isSWF:Boolean = _exportType == 0 || _exportType == 2 || _exportType == 5;
			var isXML:Boolean = _exportType == 2 || _exportType == 3 || _exportType == 4;

			switch(_exportType)
			{
				case 0:
					try
					{
						dataBytes = getSWFBytes();
						if(dataBytes)
						{
							exportSave(
								DataParser.compressData(
									xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES),
									xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES),
									dataBytes
								),
								_importDataProxy.data.name + GlobalConstValues.SWF_SUFFIX
							);
							return;
						}
						break;
					}
					catch(_e:Error)
					{
						break;
					}
				case 1:
					try
					{
						dataBytes = getPNGBytes(_backgroundColor);
						if(dataBytes)
						{
							exportSave(
								DataParser.compressData(
									xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES),
									xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES),
									dataBytes
								),
								_importDataProxy.data.name + GlobalConstValues.PNG_SUFFIX
							);
							return;
						}
						break;
					}
					catch(_e:Error)
					{
						break;
					}
				case 2:
				case 3:
				case 5:
				case 6:
					try
					{
						if(isSWF)
						{
							dataBytes = getSWFBytes();
						}
						else
						{
							dataBytes = getPNGBytes(_backgroundColor);
						}

						if(dataBytes)
						{
							date = new Date();
							zip = new Zip();
							zip.add(
								dataBytes,
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + (isSWF?GlobalConstValues.SWF_SUFFIX:GlobalConstValues.PNG_SUFFIX),
								date
							);
							_xmlDataProxy.setImagePath(GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.PNG_SUFFIX);

							if(isXML)
							{
								zip.add(
									_xmlDataProxy.xml.toXMLString(),
									GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.XML_SUFFIX,
									date
								);
								zip.add(
									_xmlDataProxy.textureAtlasXML.toXMLString(),
									GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.XML_SUFFIX,
									date
								);
							}
							else
							{
								zip.add(
									com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES)),
									GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
									date
								);
								zip.add(
									com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES)),
									GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
									date
								);
							}
							exportSave(
								zip.encode(),
								_importDataProxy.data.name + GlobalConstValues.ZIP_SUFFIX
							);
							zip.clear();
							return;
						}
						break;
					}
					catch(_e:Error)
					{
						break;
					}
				case 4:
				case 7:
					try
					{
						date = new Date();
						zip = new Zip();

						if(_xmlDataProxy == _importDataProxy.xmlDataProxy)
						{
							_xmlDataProxy = _xmlDataProxy.clone();
						}
						_xmlDataProxy.changePath();

						subBitmapDataDic = BitmapDataUtil.getSubBitmapDataDic(
							_bitmapData,
							_xmlDataProxy.getSubTextureRectMap()
						);
						for(var subTextureName:String in subBitmapDataDic)
						{
							var subBitmapData:BitmapData = subBitmapDataDic[subTextureName];
							zip.add(
								PNGEncoder.encode(subBitmapData),
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + "/" + subTextureName + GlobalConstValues.PNG_SUFFIX,
								date
							);
							subBitmapData.dispose();
						}
						if(isXML)
						{
							zip.add(
								_xmlDataProxy.xml.toXMLString(),
								GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.XML_SUFFIX,
								date
							);
							zip.add(
								_xmlDataProxy.textureAtlasXML.toXMLString(),
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.XML_SUFFIX,
								date
							);
						}
						else
						{
							zip.add(
								com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES)),
								GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
								date
							);
							zip.add(
								com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES)),
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
								date
							);
						}

						exportSave(
							zip.encode(),
							_importDataProxy.data.name + GlobalConstValues.ZIP_SUFFIX
						);
						zip.clear();
						return;
					}
					catch(_e:Error)
					{
						break;
					}
				default:
					break;
			}
			_isExporting = false;
			MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_ERROR);
		}

		private function getSWFBytes():ByteArray
		{
			if(_importDataProxy.textureAtlas.movieClip)
			{
				return _importDataProxy.textureBytes;
			}
			return null;
		}

		private function getPNGBytes(color:uint = 0):ByteArray
		{
			if(color)
			{
				var bitmapData:BitmapData = new BitmapData(_bitmapData.width, _bitmapData.height, true, color);
				bitmapData.draw(_bitmapData);

				var byteArray:ByteArray = PNGEncoder.encode(bitmapData);
				bitmapData.dispose();

				return byteArray;
			}
			else if(_importDataProxy.textureAtlas.movieClip)
			{
				return PNGEncoder.encode(_bitmapData);
			}
			else
			{
				if(_bitmapData && _bitmapData != _importDataProxy.textureAtlas.bitmapData)
				{
					return PNGEncoder.encode(_bitmapData);
				}
				return _importDataProxy.textureBytes;
			}
			return null;
		}

		private function exportSave(fileData:ByteArray, fileName:String):void
		{
			MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT, fileName);
			_fileREF.addEventListener(Event.CANCEL, onFileSaveHandler);
			_fileREF.addEventListener(Event.COMPLETE, onFileSaveHandler);
			_fileREF.addEventListener(IOErrorEvent.IO_ERROR, onFileSaveHandler);
			_fileREF.save(fileData, fileName);
		}

		private function onFileSaveHandler(e:Event):void
		{
			_fileREF.removeEventListener(Event.CANCEL, onFileSaveHandler);
			_fileREF.removeEventListener(Event.COMPLETE, onFileSaveHandler);
			_fileREF.removeEventListener(IOErrorEvent.IO_ERROR, onFileSaveHandler);
			_isExporting = false;
			switch(e.type)
			{
				case Event.CANCEL:
					MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_CANCEL);
					break;
				case IOErrorEvent.IO_ERROR:
					MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_ERROR);
					break;
				case Event.COMPLETE:
					if(_bitmapData && _bitmapData != _importDataProxy.textureAtlas.bitmapData)
					{
						_bitmapData.dispose();
						_bitmapData = null;
					}
					MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_COMPLETE);
					break;
			}
		}
	}
}

package control
{
	import com.adobe.serialization.json.JSON;

	import dragonBones.objects.DataParser;
	import dragonBones.utils.ConstValues;

	import flash.display.BitmapData;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.FileReference;
	import flash.utils.ByteArray;

	import message.Message;
	import message.MessageDispatcher;

	import model.ImportDataProxy;
	import model.JSFLProxy;
	import model.XMLDataProxy;

	import utils.BitmapDataUtil;
	import utils.GlobalConstValues;
	import utils.PNGEncoder;
	import utils.xmlToObject;

	import zero.zip.Zip;

	public class ExportDataCommand
	{
		public static const instance:ExportDataCommand = new ExportDataCommand();

		private var _fileREF:FileReference;
		private var _isExporting:Boolean;
		private var _scale:Number;
		private var _exportType:uint;
		private var _backgroundColor:uint;

		private var _importDataProxy:ImportDataProxy;

		private var _xmlDataProxy:XMLDataProxy;
		private var _bitmapData:BitmapData;

		public function ExportDataCommand()
		{
			_fileREF = new FileReference();

			_importDataProxy = ImportDataProxy.getInstance();
		}

		public function export(exportType:uint, scale:Number, backgroundColor:uint = 0):void
		{
			if(_isExporting)
			{
				return;
			}
			_isExporting = true;

			_exportType = exportType;
			_scale = scale;

			switch(_exportType)
			{
				case 0:
				case 2:
				case 5:
					_scale = 1;
					break;
			}

			_backgroundColor = backgroundColor;

			exportStart();
		}

		private function exportStart():void
		{
			var dataBytes:ByteArray;
			var zip:Zip;
			var date:Date;

			_xmlDataProxy = _importDataProxy.xmlDataProxy;
			_bitmapData = _importDataProxy.textureAtlas.bitmapData;

			if(_scale != 1)
			{
				_xmlDataProxy = _xmlDataProxy.clone();
				var subBitmapDataDic:Object;
				var movieClip:MovieClip = _importDataProxy.textureAtlas.movieClip;
				if(movieClip && movieClip.totalFrames >= 3)
				{
					subBitmapDataDic = {};
					for each (var displayName:String in _xmlDataProxy.getSubTextureListFromDisplayList())
					{
						movieClip.gotoAndStop(movieClip.totalFrames);
						movieClip.gotoAndStop(displayName);
						subBitmapDataDic[displayName] = movieClip.getChildAt(0);
					}
				}
				else
				{
					subBitmapDataDic = BitmapDataUtil.getSubBitmapDataDic(
						_bitmapData,
						_xmlDataProxy.getSubTextureRectMap()
					);
				}

				_xmlDataProxy.scaleData(_scale);

				_bitmapData = BitmapDataUtil.getMergeBitmapData(
					subBitmapDataDic,
					_xmlDataProxy.getSubTextureRectMap(),
					_xmlDataProxy.textureAtlasWidth,
					_xmlDataProxy.textureAtlasHeight,
					_scale
				);
			}

			var isSWF:Boolean = _exportType == 0 || _exportType == 2 || _exportType == 5;
			var isXML:Boolean = _exportType == 2 || _exportType == 3 || _exportType == 4;

			switch(_exportType)
			{
				case 0:
					try
					{
						dataBytes = getSWFBytes();
						if(dataBytes)
						{
							exportSave(
								DataParser.compressData(
									xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES),
									xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES),
									dataBytes
								),
								_importDataProxy.data.name + GlobalConstValues.SWF_SUFFIX
							);
							return;
						}
						break;
					}
					catch(_e:Error)
					{
						break;
					}
				case 1:
					try
					{
						dataBytes = getPNGBytes(_backgroundColor);
						if(dataBytes)
						{
							exportSave(
								DataParser.compressData(
									xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES),
									xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES),
									dataBytes
								),
								_importDataProxy.data.name + GlobalConstValues.PNG_SUFFIX
							);
							return;
						}
						break;
					}
					catch(_e:Error)
					{
						break;
					}
				case 2:
				case 3:
				case 5:
				case 6:
					try
					{
						if(isSWF)
						{
							dataBytes = getSWFBytes();
						}
						else
						{
							dataBytes = getPNGBytes(_backgroundColor);
						}

						if(dataBytes)
						{
							date = new Date();
							zip = new Zip();
							zip.add(
								dataBytes,
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + (isSWF?GlobalConstValues.SWF_SUFFIX:GlobalConstValues.PNG_SUFFIX),
								date
							);
							_xmlDataProxy.setImagePath(GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.PNG_SUFFIX);

							if(isXML)
							{
								zip.add(
									_xmlDataProxy.xml.toXMLString(),
									GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.XML_SUFFIX,
									date
								);
								zip.add(
									_xmlDataProxy.textureAtlasXML.toXMLString(),
									GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.XML_SUFFIX,
									date
								);
							}
							else
							{
								zip.add(
									com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES)),
									GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
									date
								);
								zip.add(
									com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES)),
									GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
									date
								);
							}
							exportSave(
								zip.encode(),
								_importDataProxy.data.name + GlobalConstValues.ZIP_SUFFIX
							);
							zip.clear();
							return;
						}
						break;
					}
					catch(_e:Error)
					{
						break;
					}
				case 4:
				case 7:
					try
					{
						date = new Date();
						zip = new Zip();

						if(_xmlDataProxy == _importDataProxy.xmlDataProxy)
						{
							_xmlDataProxy = _xmlDataProxy.clone();
						}

						//do not need to change changePath for TexturePacker
						//_xmlDataProxy.changePath();

						subBitmapDataDic = BitmapDataUtil.getSubBitmapDataDic(
							_bitmapData,
							_xmlDataProxy.getSubTextureRectMap()
						);
						for(var subTextureName:String in subBitmapDataDic)
						{
							var subBitmapData:BitmapData = subBitmapDataDic[subTextureName];
							zip.add(
								PNGEncoder.encode(subBitmapData),
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + "/" + subTextureName + GlobalConstValues.PNG_SUFFIX,
								date
							);
							subBitmapData.dispose();
						}
						if(isXML)
						{
							zip.add(
								_xmlDataProxy.xml.toXMLString(),
								GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.XML_SUFFIX,
								date
							);
							zip.add(
								_xmlDataProxy.textureAtlasXML.toXMLString(),
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.XML_SUFFIX,
								date
							);
						}
						else
						{
							zip.add(
								com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.xml, GlobalConstValues.XML_LIST_NAMES)),
								GlobalConstValues.DRAGON_BONES_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
								date
							);
							zip.add(
								com.adobe.serialization.json.JSON.encode(xmlToObject(_xmlDataProxy.textureAtlasXML, GlobalConstValues.XML_LIST_NAMES)),
								GlobalConstValues.TEXTURE_ATLAS_DATA_NAME + GlobalConstValues.JSON_SUFFIX,
								date
							);
						}

						exportSave(
							zip.encode(),
							_importDataProxy.data.name + GlobalConstValues.ZIP_SUFFIX
						);
						zip.clear();
						return;
					}
					catch(_e:Error)
					{
						break;
					}
				default:
					break;
			}
			_isExporting = false;
			MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_ERROR);
		}

		private function getSWFBytes():ByteArray
		{
			if(_importDataProxy.textureAtlas.movieClip)
			{
				return _importDataProxy.textureBytes;
			}
			return null;
		}

		private function getPNGBytes(color:uint = 0):ByteArray
		{
			if(color)
			{
				var bitmapData:BitmapData = new BitmapData(_bitmapData.width, _bitmapData.height, true, color);
				bitmapData.draw(_bitmapData);

				var byteArray:ByteArray = PNGEncoder.encode(bitmapData);
				bitmapData.dispose();

				return byteArray;
			}
			else if(_importDataProxy.textureAtlas.movieClip)
			{
				return PNGEncoder.encode(_bitmapData);
			}
			else
			{
				if(_bitmapData && _bitmapData != _importDataProxy.textureAtlas.bitmapData)
				{
					return PNGEncoder.encode(_bitmapData);
				}
				return _importDataProxy.textureBytes;
			}
			return null;
		}

		private function exportSave(fileData:ByteArray, fileName:String):void
		{
			MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT, fileName);
			_fileREF.addEventListener(Event.CANCEL, onFileSaveHandler);
			_fileREF.addEventListener(Event.COMPLETE, onFileSaveHandler);
			_fileREF.addEventListener(IOErrorEvent.IO_ERROR, onFileSaveHandler);
			_fileREF.save(fileData, fileName);
		}

		private function onFileSaveHandler(e:Event):void
		{
			_fileREF.removeEventListener(Event.CANCEL, onFileSaveHandler);
			_fileREF.removeEventListener(Event.COMPLETE, onFileSaveHandler);
			_fileREF.removeEventListener(IOErrorEvent.IO_ERROR, onFileSaveHandler);
			_isExporting = false;
			switch(e.type)
			{
				case Event.CANCEL:
					MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_CANCEL);
					break;
				case IOErrorEvent.IO_ERROR:
					MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_ERROR);
					break;
				case Event.COMPLETE:
					if(_bitmapData && _bitmapData != _importDataProxy.textureAtlas.bitmapData)
					{
						_bitmapData.dispose();
						_bitmapData = null;
					}
					MessageDispatcher.dispatchEvent(MessageDispatcher.EXPORT_COMPLETE);
					break;
			}
		}
	}
}

remove _xmlDataProxy.changePath

remove _xmlDataProxy.changePath


//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2010 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.miso.client {

import flash.utils.getTimer;

import flash.display.DisplayObject;
import flash.display.Sprite;

import flash.events.Event;

import flash.geom.Point;
import flash.geom.Rectangle;

import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;

import flash.events.MouseEvent;

import mx.core.ClassFactory;

import as3isolib.display.primitive.IsoBox;
import as3isolib.display.renderers.SimpleSceneLayoutRenderer;
import as3isolib.geom.Pt;
import as3isolib.geom.IsoMath;
import as3isolib.display.scene.IsoGrid;
import as3isolib.display.scene.IsoScene;
import as3isolib.display.IsoView;

import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.util.DelayUtil;
import com.threerings.util.Log;
import com.threerings.media.tile.Colorizer;
import com.threerings.media.tile.NoSuchTileSetError;
import com.threerings.media.tile.TileSet;
import com.threerings.media.tile.TileUtil;
import com.threerings.miso.client.MisoMetricsTransformation;
import com.threerings.miso.client.PrioritizedSceneLayoutRenderer;
import com.threerings.miso.data.MisoSceneModel;
import com.threerings.miso.data.ObjectInfo;
import com.threerings.miso.util.MisoContext;
import com.threerings.miso.util.ObjectSet;
import com.threerings.miso.util.MisoSceneMetrics;

public class MisoScenePanel extends Sprite
    implements PlaceView
{
    private var log :Log = Log.getLog(MisoScenePanel);

    public function MisoScenePanel (ctx :MisoContext, metrics :MisoSceneMetrics)
    {
        _ctx = ctx;
        // Excitingly, we get to override this globally for as3isolib...
        IsoMath.transformationObject = new MisoMetricsTransformation(metrics,
            metrics.tilehei * 3 / 4);

        _metrics = metrics;

        _isoView = new IsoView();
        _isoView.setSize(DEF_WIDTH, DEF_HEIGHT);

        _isoView.addEventListener(MouseEvent.CLICK, onClick);

        addChild(_loading = createLoadingPanel());
    }

    /**
     * Creates whatever we want to show while we're waiting to load our exciting scene tile data.
     */
    protected function createLoadingPanel () :DisplayObject
    {
        // By default we just stick up a basic label for this...
        var loadingText :TextField = new TextField();
        loadingText.textColor = 0xFFFFFF;
        var loadingFmt :TextFormat = new TextFormat();
        loadingFmt.size = 24;
        loadingText.defaultTextFormat = loadingFmt;
        loadingText.autoSize = TextFieldAutoSize.LEFT;

        _loadingProgressFunc = function (progress :Number) :void {
            loadingText.text = "Loading... " + int(progress*100) + "%";
        };
        _loadingProgressFunc(0.0);
        return loadingText;
    }

    protected function loadingProgress (progress :Number) :void
    {
        if (_loadingProgressFunc != null) {
            _loadingProgressFunc(progress);
        }
    }

    public function onClick (event :MouseEvent) :void
    {
        var viewPt :Point = _isoView.globalToLocal(new Point(event.stageX, event.stageY));
        _isoView.centerOnPt(new Pt(viewPt.x - _isoView.width / 2 + _isoView.currentX,
            viewPt.y - _isoView.height / 2 + _isoView.currentY), false);
    }

    public function setSceneModel (model :MisoSceneModel) :void
    {
        _model = model;
        _ctx.getTileManager().ensureLoaded(_model.getAllTilesets(), function() :void {
                DelayUtil.delayFrame(function() :void {
                    refreshScene();
                    removeChild(_loading);
                    addChild(_isoView);
                });
            }, loadingProgress);
    }

    public function willEnterPlace (plobj :PlaceObject) :void
    {
    }

    public function didLeavePlace (plobj :PlaceObject) :void
    {
    }

    protected function refreshScene () :void
    {
        // Clear it out...
        _isoView.removeAllScenes();

        var scene :IsoScene = new IsoScene();
        scene.layoutRenderer = new ClassFactory(PrioritizedSceneLayoutRenderer);
        var time :int = getTimer();
        var baseArr :Array = [];

        for (var si :int = -2; si < 4; si++) {
            for (var sj :int = -1; sj < 3; sj++) {
                var baseScene :IsoScene = new IsoScene();
                baseScene.layoutRenderer = new ClassFactory(SimpleSceneLayoutRenderer);
                for (var ii :int = 10*si; ii < 10*si + 10; ii++) {
                    for (var jj :int = 10*sj; jj < 10*sj + 10; jj++) {
                        var tileId :int = _model.getBaseTileId(ii, jj);
                        if (tileId <= 0) {
                            var defSet :TileSet;
                            try {
                                var setId :int = _model.getDefaultBaseTileSet();
                                defSet = _ctx.getTileManager().getTileSet(setId);
                                tileId = TileUtil.getFQTileId(setId,
                                    TileUtil.getTileHash(ii, jj) % defSet.getTileCount());
                            } catch (err :NoSuchTileSetError) {
                                // Someone else already complained...
                                continue;
                            }
                        }

                        var tileSet :TileSet;
                        try {
                            tileSet =
                                _ctx.getTileManager().getTileSet(TileUtil.getTileSetId(tileId));
                        } catch (err :NoSuchTileSetError) {
                            // Someone else already complained...
                            continue;
                        }

                        if (tileSet == null) {
                            log.warning("TileManager returned null tilset: " +
                                TileUtil.getTileSetId(tileId));
                            continue;
                        }

                        baseScene.addChild(
                            new BaseTileIsoSprite(ii, jj, tileId,
                                tileSet.getTile(TileUtil.getTileIndex(tileId)), _metrics));
                    }
                }
                baseScene.render();
                _isoView.addScene(baseScene);
            }
        }

        var set :ObjectSet = new ObjectSet();
        _model.getObjects(new Rectangle(-100, -100, 200, 200), set);
        time = getTimer();
        for (ii = 0; ii < set.size(); ii++) {
            var objInfo :ObjectInfo = set.get(ii);
            var objTileId :int = objInfo.tileId;
            var objTileSet :TileSet;
            try {
                objTileSet =
                    _ctx.getTileManager().getTileSet(TileUtil.getTileSetId(objTileId));
            } catch (err :NoSuchTileSetError) {
                // Someone else already complained...
                continue;
            }

            if (objTileSet == null) {
                log.warning("TileManager returned null TileSet: " +
                    TileUtil.getTileSetId(objTileId));
                continue;
            }

            scene.addChild(
                new ObjectTileIsoSprite(objInfo.x, objInfo.y, objTileId,
                    objTileSet.getTile(TileUtil.getTileIndex(objTileId), getColorizer(objInfo)),
                    objInfo.priority, _metrics));
        }

        time = getTimer();
        scene.render();

        _isoView.addScene(scene);
    }

    /**
     * Derived classes can override this method and provide a colorizer that will be used to
     * colorize the supplied scene object when rendering.
     */
    protected function getColorizer (oinfo :ObjectInfo) :Colorizer
    {
        return null;
    }

    protected var _model :MisoSceneModel;

    protected var _isoView :IsoView;

    protected var _ctx :MisoContext;

    protected var _metrics :MisoSceneMetrics;

    /** What we display while we're loading up our tilesets. */
    protected var _loading :DisplayObject;

    /** If we should do something when we hear about progress updates, this is it. */
    protected var _loadingProgressFunc :Function;

    protected const DEF_WIDTH :int = 985;
    protected const DEF_HEIGHT :int = 560;
}
}

//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2010 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.miso.client {

import flash.utils.getTimer;

import flash.display.DisplayObject;
import flash.display.Sprite;

import flash.events.Event;

import flash.geom.Point;
import flash.geom.Rectangle;

import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;

import flash.events.MouseEvent;

import mx.core.ClassFactory;

import as3isolib.display.primitive.IsoBox;
// import as3isolib.display.renderers.SimpleSceneLayoutRenderer;
import as3isolib.geom.Pt;
import as3isolib.geom.IsoMath;
import as3isolib.display.scene.IsoGrid;
import as3isolib.display.scene.IsoScene;
import as3isolib.display.IsoView;

import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.util.DelayUtil;
import com.threerings.util.Log;
import com.threerings.media.tile.Colorizer;
import com.threerings.media.tile.NoSuchTileSetError;
import com.threerings.media.tile.TileSet;
import com.threerings.media.tile.TileUtil;
import com.threerings.miso.client.MisoMetricsTransformation;
import com.threerings.miso.client.PrioritizedSceneLayoutRenderer;
import com.threerings.miso.data.MisoSceneModel;
import com.threerings.miso.data.ObjectInfo;
import com.threerings.miso.util.MisoContext;
import com.threerings.miso.util.ObjectSet;
import com.threerings.miso.util.MisoSceneMetrics;

public class MisoScenePanel extends Sprite
    implements PlaceView
{
    private var log :Log = Log.getLog(MisoScenePanel);

    public function MisoScenePanel (ctx :MisoContext, metrics :MisoSceneMetrics)
    {
        _ctx = ctx;
        // Excitingly, we get to override this globally for as3isolib...
        IsoMath.transformationObject = new MisoMetricsTransformation(metrics,
            metrics.tilehei * 3 / 4);

        _metrics = metrics;

        _isoView = new IsoView();
        _isoView.setSize(DEF_WIDTH, DEF_HEIGHT);

        _isoView.addEventListener(MouseEvent.CLICK, onClick);

        addChild(_loading = createLoadingPanel());
    }

    /**
     * Creates whatever we want to show while we're waiting to load our exciting scene tile data.
     */
    protected function createLoadingPanel () :DisplayObject
    {
        // By default we just stick up a basic label for this...
        var loadingText :TextField = new TextField();
        loadingText.textColor = 0xFFFFFF;
        var loadingFmt :TextFormat = new TextFormat();
        loadingFmt.size = 24;
        loadingText.defaultTextFormat = loadingFmt;
        loadingText.autoSize = TextFieldAutoSize.LEFT;

        _loadingProgressFunc = function (progress :Number) :void {
            loadingText.text = "Loading... " + int(progress*100) + "%";
        };
        _loadingProgressFunc(0.0);
        return loadingText;
    }

    protected function loadingProgress (progress :Number) :void
    {
        if (_loadingProgressFunc != null) {
            _loadingProgressFunc(progress);
        }
    }

    public function onClick (event :MouseEvent) :void
    {
        var viewPt :Point = _isoView.globalToLocal(new Point(event.stageX, event.stageY));
        _isoView.centerOnPt(new Pt(viewPt.x - _isoView.width / 2 + _isoView.currentX,
            viewPt.y - _isoView.height / 2 + _isoView.currentY), false);
    }

    public function setSceneModel (model :MisoSceneModel) :void
    {
        _model = model;
        _ctx.getTileManager().ensureLoaded(_model.getAllTilesets(), function() :void {
                DelayUtil.delayFrame(function() :void {
                    refreshScene();
                    removeChild(_loading);
                    addChild(_isoView);
                });
            }, loadingProgress);
    }

    public function willEnterPlace (plobj :PlaceObject) :void
    {
    }

    public function didLeavePlace (plobj :PlaceObject) :void
    {
    }

    protected function refreshScene () :void
    {
        // Clear it out...
        _isoView.removeAllScenes();

        var scene :IsoScene = new IsoScene();
        scene.layoutRenderer = new ClassFactory(PrioritizedSceneLayoutRenderer);
        var time :int = getTimer();
        var baseArr :Array = [];

        for (var si :int = -2; si < 4; si++) {
            for (var sj :int = -1; sj < 3; sj++) {
                var baseScene :IsoScene = new IsoScene();
//                baseScene.layoutRenderer = new ClassFactory(SimpleSceneLayoutRenderer);
                for (var ii :int = 10*si; ii < 10*si + 10; ii++) {
                    for (var jj :int = 10*sj; jj < 10*sj + 10; jj++) {
                        var tileId :int = _model.getBaseTileId(ii, jj);
                        if (tileId <= 0) {
                            var defSet :TileSet;
                            try {
                                var setId :int = _model.getDefaultBaseTileSet();
                                defSet = _ctx.getTileManager().getTileSet(setId);
                                tileId = TileUtil.getFQTileId(setId,
                                    TileUtil.getTileHash(ii, jj) % defSet.getTileCount());
                            } catch (err :NoSuchTileSetError) {
                                // Someone else already complained...
                                continue;
                            }
                        }

                        var tileSet :TileSet;
                        try {
                            tileSet =
                                _ctx.getTileManager().getTileSet(TileUtil.getTileSetId(tileId));
                        } catch (err :NoSuchTileSetError) {
                            // Someone else already complained...
                            continue;
                        }

                        if (tileSet == null) {
                            log.warning("TileManager returned null tilset: " +
                                TileUtil.getTileSetId(tileId));
                            continue;
                        }

                        baseScene.addChild(
                            new BaseTileIsoSprite(ii, jj, tileId,
                                tileSet.getTile(TileUtil.getTileIndex(tileId)), _metrics));
                    }
                }
                baseScene.render();
                _isoView.addScene(baseScene);
            }
        }

        var set :ObjectSet = new ObjectSet();
        _model.getObjects(new Rectangle(-100, -100, 200, 200), set);
        time = getTimer();
        for (ii = 0; ii < set.size(); ii++) {
            var objInfo :ObjectInfo = set.get(ii);
            var objTileId :int = objInfo.tileId;
            var objTileSet :TileSet;
            try {
                objTileSet =
                    _ctx.getTileManager().getTileSet(TileUtil.getTileSetId(objTileId));
            } catch (err :NoSuchTileSetError) {
                // Someone else already complained...
                continue;
            }

            if (objTileSet == null) {
                log.warning("TileManager returned null TileSet: " +
                    TileUtil.getTileSetId(objTileId));
                continue;
            }

            scene.addChild(
                new ObjectTileIsoSprite(objInfo.x, objInfo.y, objTileId,
                    objTileSet.getTile(TileUtil.getTileIndex(objTileId), getColorizer(objInfo)),
                    objInfo.priority, _metrics));
        }

        time = getTimer();
        scene.render();

        _isoView.addScene(scene);
    }

    /**
     * Derived classes can override this method and provide a colorizer that will be used to
     * colorize the supplied scene object when rendering.
     */
    protected function getColorizer (oinfo :ObjectInfo) :Colorizer
    {
        return null;
    }

    protected var _model :MisoSceneModel;

    protected var _isoView :IsoView;

    protected var _ctx :MisoContext;

    protected var _metrics :MisoSceneMetrics;

    /** What we display while we're loading up our tilesets. */
    protected var _loading :DisplayObject;

    /** If we should do something when we hear about progress updates, this is it. */
    protected var _loadingProgressFunc :Function;

    protected const DEF_WIDTH :int = 985;
    protected const DEF_HEIGHT :int = 560;
}
}

Fix the Shared Libraries build.  It looks like the version of as3isolib in
extlibs needs to be updated.

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


package
{
	import com.*;
	import com.errors.RuntimeError;
	import com.events.*;
	import com.utils.BlobPile;

	import flash.display.LoaderInfo;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.ProgressEvent;
	import flash.external.ExternalInterface;
	import flash.system.ApplicationDomain;
	import flash.system.Security;
	import flash.utils.*;

	import mxi.Extend;
	import mxi.Utils;
	import mxi.events.ODataEvent;
	import mxi.events.OProgressEvent;

	[SWF(width='500', height='500')]
	public class Moxie extends Sprite
	{
		public static var uid:String;

		public static var comps:ComponentFactory;

		public static var blobPile:BlobPile;

		public static var stageOccupied:Boolean = false; // whether a display facility is already occupied

		/**
		 * Main constructor for the Plupload class.
		 */
		public function Moxie()
		{
			if (stage) {
				_init();
			} else {
				addEventListener(Event.ADDED_TO_STAGE, init);
			}
		}

		/**
		 * Initialization event handler.
		 *
		 * @param e Event object.
		 */
		private function _init(e:Event = null):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, _init);

			// Allow scripting on swf loaded from another domain
			// Security.allowDomain("*");

			// Align and scale stage
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.EXACT_FIT;

			// Setup id
			Moxie.uid = Utils.sanitize(stage.loaderInfo.parameters["uid"]);

			//ExternalInterface.marshallExceptions = true; // propagate AS exceptions to JS and vice-versa
			ExternalInterface.addCallback('exec', exec);
			ExternalInterface.addCallback('isOccupied', isOccupied);

			// initialize component factory
			Moxie.comps = new ComponentFactory;

			// blob registry
			Moxie.blobPile = new BlobPile;

			_fireEvent(Moxie.uid + "::Init");
		}

		public function exec(uid:String, compName:String, action:String, args:* = null) : *
		{
			// Moxie.log([uid, compName, action, args]);

			uid = Utils.sanitize(uid); // make it safe

			var result:*, comp:* = Moxie.comps.get(uid, compName);

			// Moxie.log([compName, action]);

			try {
				// initialize corresponding com
				if (!comp) {
					comp = Moxie.comps.create(this, uid, compName);
				}

				// execute the action if available
				if (comp.hasOwnProperty(action)) {
					return comp[action].apply(comp, args as Array);
				} else {
					_fireEvent(uid + "::Exception", { name: "RuntimeError", code: RuntimeError.NOT_SUPPORTED_ERR });
				}

			} catch(err:*) { // re-route exceptions thrown by components (TODO: check marshallExceptions feature)
				_fireEvent(uid + "::Exception", { name: getQualifiedClassName(err).replace(/^[^:*]::/, ''), code: err.errorID });
			}
		}

		public function isOccupied() : Boolean {
			return Moxie.stageOccupied;
		}

		/**
		 * Intercept component events and do some operations if required
		 *
		 * @param uid String unique identifier of the component throwing the event
		 * @param e mixed Event object
		 * @param exType String event type in mOxie format
		 */
		public function onComponentEvent(uid:String, e:*, exType:String) : void
		{
			var evt:Object = {};

			switch (e.type)
			{
				case ProgressEvent.PROGRESS:
				case OProgressEvent.PROGRESS:
					evt.loaded = e.bytesLoaded;
					evt.total = e.bytesTotal;
					break;
			}

			evt.type = [uid, exType].join('::');
			evt.async = true;

			_fireEvent(evt, e.hasOwnProperty('data') ? e.data : null);
		}

		/**
		 * Fires an event from the flash movie out to the page level JS.
		 *
		 * @param uid String unique identifier of the component throwing the event
		 * @param type Name of event to fire.
		 * @param obj Object with optional data.
		 */
		private function _fireEvent(evt:*, obj:Object = null):void {
			try {
				ExternalInterface.call("mOxie.EventTarget.instance.dispatchEvent", evt, obj);
			} catch(err:*) {
				//_fireEvent("Exception", { name: 'RuntimeError', message: 4 });

				// throwing an exception would be better here
			}
		}

		public static function log(obj:*) : void {
			ExternalInterface.call('console.info', obj);
		}

	}
}

package
{
	import com.*;
	import com.errors.RuntimeError;
	import com.events.*;
	import com.utils.BlobPile;

	import flash.display.LoaderInfo;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.ProgressEvent;
	import flash.external.ExternalInterface;
	import flash.system.ApplicationDomain;
	import flash.system.Security;
	import flash.utils.*;

	import mxi.Extend;
	import mxi.Utils;
	import mxi.events.ODataEvent;
	import mxi.events.OProgressEvent;

	[SWF(width='500', height='500')]
	public class Moxie extends Sprite
	{
		public static var uid:String;

		public static var comps:ComponentFactory;

		public static var blobPile:BlobPile;

		public static var stageOccupied:Boolean = false; // whether a display facility is already occupied

		/**
		 * Main constructor for the Plupload class.
		 */
		public function Moxie()
		{
			if (stage) {
				_init();
			} else {
				addEventListener(Event.ADDED_TO_STAGE, init);
			}
		}

		/**
		 * Initialization event handler.
		 *
		 * @param e Event object.
		 */
		private function _init(e:Event = null):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, _init);

			// Allow scripting on swf loaded from another domain
			// Security.allowDomain("*");

			// Align and scale stage
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.EXACT_FIT;

			// Setup id
			Moxie.uid = Utils.sanitize(stage.loaderInfo.parameters["uid"]);

			//ExternalInterface.marshallExceptions = true; // propagate AS exceptions to JS and vice-versa
			ExternalInterface.addCallback('exec', exec);
			ExternalInterface.addCallback('isOccupied', isOccupied);

			// initialize component factory
			Moxie.comps = new ComponentFactory;

			// blob registry
			Moxie.blobPile = new BlobPile;

			_fireEvent(Moxie.uid + "::Init");
		}

		public function exec(uid:String, compName:String, action:String, args:* = null) : *
		{
			// Moxie.log([uid, compName, action, args]);

			uid = Utils.sanitize(uid); // make it safe

			var result:*, comp:* = Moxie.comps.get(uid, compName);

			// Moxie.log([compName, action]);

			try {
				// initialize corresponding com
				if (!comp) {
					comp = Moxie.comps.create(this, uid, compName);
				}

				// execute the action if available
				if (comp.hasOwnProperty(action)) {
					return comp[action].apply(comp, args as Array);
				} else {
					_fireEvent(uid + "::Exception", { name: "RuntimeError", code: RuntimeError.NOT_SUPPORTED_ERR });
				}

			} catch(err:*) { // re-route exceptions thrown by components (TODO: check marshallExceptions feature)
				_fireEvent(uid + "::Exception", { name: getQualifiedClassName(err).replace(/^[^:*]::/, ''), code: err.errorID });
			}
		}

		public function isOccupied() : Boolean {
			return Moxie.stageOccupied;
		}

		/**
		 * Intercept component events and do some operations if required
		 *
		 * @param uid String unique identifier of the component throwing the event
		 * @param e mixed Event object
		 * @param exType String event type in mOxie format
		 */
		public function onComponentEvent(uid:String, e:*, exType:String) : void
		{
			var evt:Object = {};

			switch (e.type)
			{
				case ProgressEvent.PROGRESS:
				case OProgressEvent.PROGRESS:
					evt.loaded = e.bytesLoaded;
					evt.total = e.bytesTotal;
					break;
			}

			evt.type = [uid, exType].join('::');
			evt.async = true;

			_fireEvent(evt, e.hasOwnProperty('data') ? e.data : null);
		}

		/**
		 * Fires an event from the flash movie out to the page level JS.
		 *
		 * @param uid String unique identifier of the component throwing the event
		 * @param type Name of event to fire.
		 * @param obj Object with optional data.
		 */
		private function _fireEvent(evt:*, obj:Object = null):void {
			try {
				ExternalInterface.call("moxie.core.EventTarget.instance.dispatchEvent", evt, obj);
			} catch(err:*) {
				//_fireEvent("Exception", { name: 'RuntimeError', message: 4 });

				// throwing an exception would be better here
			}
		}

		public static function log(obj:*) : void {
			ExternalInterface.call('console.info', obj);
		}

	}
}

Flash: Change event target to moxie.core.EventTarget.instance (more future-proof).


package aerys.minko.scene.controller
{
    import aerys.minko.ns.minko_math;
    import aerys.minko.render.Viewport;
    import aerys.minko.scene.node.Group;
    import aerys.minko.scene.node.ISceneNode;
    import aerys.minko.scene.node.Scene;
    import aerys.minko.type.math.Matrix4x4;

    import flash.display.BitmapData;
    import flash.utils.Dictionary;

    import mx.olap.aggregators.MaxAggregator;

    use namespace minko_math;

    /**
     * The TransformController handles the batched update of all the local to world matrices
     * of a sub-scene. As such, it will only be active on the root node of a sub-scene and will
     * automatically disable itself on other nodes.
     *
     * @author Jean-Marc Le Roux
     *
     */
    public final class TransformController extends AbstractController
    {
        private static const INIT_NONE                  : uint  = 0;
        private static const INIT_LOCAL_TO_WORLD        : uint  = 1;
        private static const INIT_WORLD_TO_LOCAL        : uint  = 2;

        private var _target								: ISceneNode;

        private var _invalidList						: Boolean;

        private var _nodeToId							: Dictionary;
        private var _idToNode							: Vector.<ISceneNode>
        private var _transforms							: Vector.<Matrix4x4>;
        private var _initialized	                    : Vector.<uint>;
        private var _localToWorldTransforms 			: Vector.<Matrix4x4>;
        private var _worldToLocalTransforms 			: Vector.<Matrix4x4>;
        private var _numChildren						: Vector.<uint>;
        private var _firstChildId						: Vector.<uint>;
        private var _parentId							: Vector.<int>;

        public function TransformController()
        {
            super();

            targetAdded.add(targetAddedHandler);
            targetRemoved.add(targetRemovedHandler);
        }

        private function renderingBeginHandler(scene			: Scene,
                                               viewport		: Viewport,
                                               destination	: BitmapData,
                                               time			: Number) : void
        {
            if (_invalidList)
                updateTransformsList();

            if (_transforms.length)
                updateLocalToWorld();
        }

        private function updateLocalToWorld(nodeId : uint = 0, subtreeOnly : Boolean = false) : void
        {
            var numNodes 			: uint 			= _transforms.length;
            var childrenOffset		: uint			= 1;
            var rootLocalToWorld	: Matrix4x4		= _localToWorldTransforms[nodeId];
            var rootTransform		: Matrix4x4		= _transforms[nodeId];
            var root				: ISceneNode	= _idToNode[nodeId];
            var subtreeMax          : uint          = nodeId;

            if (rootTransform._hasChanged || _initialized[nodeId] == INIT_NONE)
            {
                rootLocalToWorld.copyFrom(rootTransform);

                if (nodeId != 0)
                    rootLocalToWorld.append(_localToWorldTransforms[_parentId[nodeId]]);

                rootTransform._hasChanged = false;
                _initialized[nodeId] = INIT_LOCAL_TO_WORLD;
                root.localToWorldTransformChanged.execute(root, rootLocalToWorld);
            }

            if (lastChildId > subtreeMax)
                subtreeMax = lastChildId;

            while (nodeId < numNodes)
            {
                var localToWorld 	: Matrix4x4	= _localToWorldTransforms[nodeId];
                var numChildren		: uint		= _numChildren[nodeId];
                var firstChildId	: uint		= _firstChildId[nodeId];
                var lastChildId		: uint		= firstChildId + numChildren;
                var isDirty			: Boolean	= localToWorld._hasChanged;

                localToWorld._hasChanged = false;

                for (var childId : uint = firstChildId; childId < lastChildId; ++childId)
                {
                    var childTransform		: Matrix4x4		= _transforms[childId];
                    var childLocalToWorld	: Matrix4x4		= _localToWorldTransforms[childId];
                    var childIsDirty		: Boolean		= isDirty || childTransform._hasChanged
                        || !_initialized[childId];

                    if (childIsDirty)
                    {
                        var child	: ISceneNode	= _idToNode[childId];

                        childLocalToWorld
                            .copyFrom(childTransform)
                            .append(localToWorld);

                        childTransform._hasChanged = false;
                        _initialized[childId] = INIT_LOCAL_TO_WORLD;
                        child.localToWorldTransformChanged.execute(child, childLocalToWorld);
                    }
                }

                if (subtreeOnly && nodeId && nodeId >= subtreeMax)
                {
                    // jump to the first brother who has children
                    var parentId : uint = _parentId[nodeId];

                    nodeId = _firstChildId[parentId];
                    while (!_numChildren[nodeId] && nodeId < subtreeMax)
                        ++nodeId;

                    if (nodeId >= subtreeMax)
                        return ;

                    nodeId = _firstChildId[nodeId];
                }
                else
                    ++nodeId;
            }
        }

        private function updateAncestorsAndSelfLocalToWorld(nodeId : int) : void
        {
            var dirtyRoot : int = -1;

            while (nodeId >= 0)
            {
                if ((_transforms[nodeId] as Matrix4x4)._hasChanged || !_initialized[nodeId])
                    dirtyRoot = nodeId;

                nodeId = _parentId[nodeId];
            }

            if (dirtyRoot >= 0)
                updateLocalToWorld(dirtyRoot, true);
        }

        private function targetAddedHandler(ctrl	: TransformController,
                                            target	: ISceneNode) : void
        {
            if (_target)
                throw new Error('The TransformController cannot have more than one target.');

            _target = target;
            _invalidList = true;

            if (target is Scene)
            {
                (target as Scene).renderingBegin.add(renderingBeginHandler);
                return;
            }

            if (target is Group)
            {
                var targetGroup : Group = target as Group;

                targetGroup.descendantAdded.add(descendantAddedHandler);
                targetGroup.descendantRemoved.add(descendantRemovedHandler);
            }

            target.added.add(addedHandler);
        }

        private function targetRemovedHandler(ctrl		: TransformController,
                                              target	: ISceneNode) : void
        {
            target.added.remove(addedHandler);

            if (target is Group)
            {
                var targetGroup : Group = target as Group;

                targetGroup.descendantAdded.remove(descendantAddedHandler);
                targetGroup.descendantRemoved.remove(descendantRemovedHandler);
            }

            _invalidList = false;
            _target = null;

            _nodeToId = null;
            _transforms = null;
            _initialized = null;
            _localToWorldTransforms = null;
            _worldToLocalTransforms = null;
            _numChildren = null;
            _idToNode = null;
            _parentId = null;
        }

        private function addedHandler(target : ISceneNode, ancestor : Group) : void
        {
            // the controller will remove itself from the node when it's not its own root anymore
            // but it will watch for the 'removed' signal to add itself back if the node becomes
            // its own root again
            _target.removed.add(removedHandler);
            _target.removeController(this);
        }

        private function removedHandler(target : ISceneNode, ancestor : Group) : void
        {
            if (target.root == target)
            {
                target.removed.remove(removedHandler);
                target.addController(this);
            }
        }

        private function descendantAddedHandler(root		: Group,
                                                descendant	: ISceneNode) : void
        {
            _invalidList = true;
        }

        private function descendantRemovedHandler(root			: Group,
                                                  descendant	: ISceneNode) : void
        {
            _invalidList = true;
        }

        private function updateTransformsList() : void
        {
            var root    	                : ISceneNode 			= _target.root;
            var nodes   	                : Vector.<ISceneNode> 	= new <ISceneNode>[root];
            var nodeId  	                : uint 					= 0;
            var oldNodeToId                 : Dictionary            = _nodeToId;
            var oldInitialized              : Vector.<uint>         = _initialized;
            var oldLocalToWorldTransforms   : Vector.<Matrix4x4>    = _localToWorldTransforms;
            var oldWorldToLocalTransform    : Vector.<Matrix4x4>    = _worldToLocalTransforms;

            _nodeToId = new Dictionary(true);
            _transforms = new <Matrix4x4>[];
            _initialized = new <uint>[];
            _localToWorldTransforms = new <Matrix4x4>[];
            _worldToLocalTransforms = new <Matrix4x4>[];
            _numChildren = new <uint>[];
            _firstChildId = new <uint>[];
            _idToNode = new <ISceneNode>[];
            _parentId = new <int>[-1];

            while (nodes.length)
            {
                var node 	: ISceneNode 	= nodes.shift();
                var group   : Group 		= node as Group;

                _nodeToId[node] = nodeId;
                _idToNode[nodeId] = node;
                _transforms[nodeId] = node.transform;

                if (oldNodeToId && node in oldNodeToId)
                {
                    var oldNodeId   : uint  = oldNodeToId[node];

                    _localToWorldTransforms[nodeId] = oldLocalToWorldTransforms[oldNodeId];
                    _worldToLocalTransforms[nodeId] = oldWorldToLocalTransform[oldNodeId];
                    _initialized[nodeId] = oldInitialized[oldNodeId];
                }
                else
                {
                    _localToWorldTransforms[nodeId] = new Matrix4x4().lock();
                    _worldToLocalTransforms[nodeId] = null;
                    _initialized[nodeId] = INIT_NONE;
                }

                if (group)
                {
                    var numChildren 	: uint = group.numChildren;
                    var firstChildId 	: uint = nodeId + nodes.length + 1;

                    _numChildren[nodeId] = numChildren;
                    _firstChildId[nodeId] = firstChildId;
                    for (var childId : uint = 0; childId < numChildren; ++childId)
                    {
                        _parentId[uint(firstChildId + childId)] = nodeId;
                        nodes.push(group.getChildAt(childId));
                    }
                }
                else
                {
                    _numChildren[nodeId] = 0;
                    _firstChildId[nodeId] = 0;
                }

                ++nodeId;
            }

            _worldToLocalTransforms.length = _localToWorldTransforms.length;
            _invalidList = false;
        }

        public function getLocalToWorldTransform(node 			: ISceneNode,
                                                 forceUpdate 	: Boolean = false) : Matrix4x4
        {
            if (_invalidList || _nodeToId[node] == undefined)
                updateTransformsList();

            var nodeId : uint = _nodeToId[node];

            if (forceUpdate)
                updateAncestorsAndSelfLocalToWorld(nodeId);

            return _localToWorldTransforms[nodeId];
        }

        public function getWorldToLocalTransform(node           : ISceneNode,
                                                 forceUpdate    : Boolean   = false) : Matrix4x4
        {
            if (_invalidList || _nodeToId[node] == undefined)
                updateTransformsList();

            var nodeId                  : uint      = _nodeToId[node];
            var worldToLocalTransform   : Matrix4x4 = _worldToLocalTransforms[nodeId];

            if (!worldToLocalTransform)
            {
                _worldToLocalTransforms[nodeId] = worldToLocalTransform = new Matrix4x4();
                if (!forceUpdate)
                {
                    worldToLocalTransform.copyFrom(_localToWorldTransforms[nodeId]).invert();
                    _initialized[nodeId] |= INIT_WORLD_TO_LOCAL;
                }
            }

            if (forceUpdate)
                updateAncestorsAndSelfLocalToWorld(nodeId);

            if (!(_initialized[nodeId] & INIT_WORLD_TO_LOCAL))
            {
                _initialized[nodeId] |= INIT_WORLD_TO_LOCAL;

                worldToLocalTransform
                    .copyFrom(_localToWorldTransforms[nodeId])
                    .invert();
            }

            return worldToLocalTransform;
        }
    }
}

package aerys.minko.scene.controller
{
    import aerys.minko.ns.minko_math;
    import aerys.minko.render.Viewport;
    import aerys.minko.scene.node.Group;
    import aerys.minko.scene.node.ISceneNode;
    import aerys.minko.scene.node.Scene;
    import aerys.minko.type.math.Matrix4x4;

    import flash.display.BitmapData;
    import flash.utils.Dictionary;

    import mx.olap.aggregators.MaxAggregator;

    use namespace minko_math;

    /**
     * The TransformController handles the batched update of all the local to world matrices
     * of a sub-scene. As such, it will only be active on the root node of a sub-scene and will
     * automatically disable itself on other nodes.
     *
     * @author Jean-Marc Le Roux
     *
     */
    public final class TransformController extends AbstractController
    {

        private static const FLAG_NONE                      : uint  = 0;
        private static const FLAG_INIT_LOCAL_TO_WORLD       : uint  = 1;
        private static const FLAG_INIT_WORLD_TO_LOCAL       : uint  = 2;
        private static const FLAG_SYNCHRONIZE_TRANSFORMS    : uint  = 4;
        private static const FLAG_LOCK_TRANSFORMS           : uint  = 8;

        private var _target					: ISceneNode;

        private var _invalidList			: Boolean;

        private var _nodeToId				: Dictionary;
        private var _idToNode				: Vector.<ISceneNode>
        private var _transforms				: Vector.<Matrix4x4>;
        private var _flags	                : Vector.<uint>;
        private var _localToWorldTransforms : Vector.<Matrix4x4>;
        private var _worldToLocalTransforms : Vector.<Matrix4x4>;
        private var _numChildren			: Vector.<uint>;
        private var _firstChildId			: Vector.<uint>;
        private var _parentId				: Vector.<int>;

        public function TransformController()
        {
            super();

            targetAdded.add(targetAddedHandler);
            targetRemoved.add(targetRemovedHandler);
        }

        private function renderingBeginHandler(scene			: Scene,
                                               viewport		: Viewport,
                                               destination	: BitmapData,
                                               time			: Number) : void
        {
            if (_invalidList)
                updateTransformsList();

            if (_transforms.length)
                updateLocalToWorld();
        }

        private function updateRootLocalToWorld(nodeId : uint = 0) : void
        {
            var rootLocalToWorld	: Matrix4x4		= _localToWorldTransforms[nodeId];
            var rootTransform		: Matrix4x4		= _transforms[nodeId];
            var root				: ISceneNode	= _idToNode[nodeId];
            var rootFlags           : uint          = _flags[nodeId];

            if (rootTransform._hasChanged || !(rootFlags & FLAG_INIT_LOCAL_TO_WORLD))
            {
                if (rootFlags & FLAG_LOCK_TRANSFORMS)
                    rootLocalToWorld.lock();

                rootLocalToWorld.copyFrom(rootTransform);

                if (nodeId != 0)
                    rootLocalToWorld.append(_localToWorldTransforms[_parentId[nodeId]]);

                if (rootFlags & FLAG_LOCK_TRANSFORMS)
                    rootLocalToWorld.unlock();

                rootTransform._hasChanged = false;
                _flags[nodeId] |= FLAG_INIT_LOCAL_TO_WORLD;
                root.localToWorldTransformChanged.execute(root, rootLocalToWorld);

                if (rootFlags & FLAG_SYNCHRONIZE_TRANSFORMS)
                {
                    var rootWorldToLocal : Matrix4x4 = _worldToLocalTransforms[nodeId]
                        || (_worldToLocalTransforms[nodeId] = new Matrix4x4());

                    if (rootFlags & FLAG_LOCK_TRANSFORMS)
                        rootWorldToLocal.lock();

                    rootWorldToLocal.copyFrom(rootLocalToWorld).invert();

                    if (rootFlags & FLAG_LOCK_TRANSFORMS)
                        rootWorldToLocal.unlock();
                }
            }
        }

        private function updateLocalToWorld(nodeId : uint = 0, subtreeOnly : Boolean = false) : void
        {
            var numNodes 			: uint 			= _transforms.length;
            var subtreeMax          : uint          = nodeId;

            updateRootLocalToWorld(nodeId);

            while (nodeId < numNodes)
            {
                var localToWorld 	: Matrix4x4	= _localToWorldTransforms[nodeId];
                var numChildren		: uint		= _numChildren[nodeId];
                var firstChildId	: uint		= _firstChildId[nodeId];
                var lastChildId		: uint		= firstChildId + numChildren;
                var isDirty			: Boolean	= localToWorld._hasChanged;

                localToWorld._hasChanged = false;

                if (lastChildId > subtreeMax)
                    subtreeMax = lastChildId;

                for (var childId : uint = firstChildId; childId < lastChildId; ++childId)
                {
                    var childTransform		: Matrix4x4		= _transforms[childId];
                    var childLocalToWorld	: Matrix4x4		= _localToWorldTransforms[childId];
                    var childFlags          : uint          = _flags[childId];
                    var childIsDirty		: Boolean		= isDirty || childTransform._hasChanged
                        || !(childFlags & FLAG_INIT_LOCAL_TO_WORLD);

                    if (childIsDirty)
                    {
                        var child	: ISceneNode	= _idToNode[childId];

                        if (childFlags & FLAG_LOCK_TRANSFORMS)
                            childLocalToWorld.lock();

                        childLocalToWorld
                            .copyFrom(childTransform)
                            .append(localToWorld);

                        if (childFlags & FLAG_LOCK_TRANSFORMS)
                            childLocalToWorld.unlock();

                        childTransform._hasChanged = false;
                        _flags[childId] |= FLAG_INIT_LOCAL_TO_WORLD;
                        child.localToWorldTransformChanged.execute(child, childLocalToWorld);

                        if (childFlags & FLAG_SYNCHRONIZE_TRANSFORMS)
                        {
                            var childWorldToLocal : Matrix4x4 = _worldToLocalTransforms[childId]
                                || (_worldToLocalTransforms[childId] = new Matrix4x4());

                            if (childFlags & FLAG_LOCK_TRANSFORMS)
                                childWorldToLocal.lock();

                            childWorldToLocal.copyFrom(childLocalToWorld).invert();

                            if (childFlags & FLAG_LOCK_TRANSFORMS)
                                childWorldToLocal.unlock();
                        }
                    }
                }

                if (subtreeOnly && nodeId && nodeId >= subtreeMax)
                {
                    // jump to the first brother who has children
                    var parentId : uint = _parentId[nodeId];

                    nodeId = _firstChildId[parentId];
                    while (!_numChildren[nodeId] && nodeId < subtreeMax)
                        ++nodeId;

                    if (nodeId >= subtreeMax)
                        return ;

                    nodeId = _firstChildId[nodeId];
                }
                else
                    ++nodeId;
            }
        }

        private function updateAncestorsAndSelfLocalToWorld(nodeId : int) : void
        {
            var dirtyRoot : int = -1;

            while (nodeId >= 0)
            {
                if ((_transforms[nodeId] as Matrix4x4)._hasChanged || !_flags[nodeId])
                    dirtyRoot = nodeId;

                nodeId = _parentId[nodeId];
            }

            if (dirtyRoot >= 0)
                updateLocalToWorld(dirtyRoot, true);
        }

        private function targetAddedHandler(ctrl	: TransformController,
                                            target	: ISceneNode) : void
        {
            if (_target)
                throw new Error('The TransformController cannot have more than one target.');

            _target = target;
            _invalidList = true;

            if (target is Scene)
            {
                (target as Scene).renderingBegin.add(renderingBeginHandler);
                return;
            }

            if (target is Group)
            {
                var targetGroup : Group = target as Group;

                targetGroup.descendantAdded.add(descendantAddedHandler);
                targetGroup.descendantRemoved.add(descendantRemovedHandler);
            }

            target.added.add(addedHandler);
        }

        private function targetRemovedHandler(ctrl		: TransformController,
                                              target	: ISceneNode) : void
        {
            target.added.remove(addedHandler);

            if (target is Group)
            {
                var targetGroup : Group = target as Group;

                targetGroup.descendantAdded.remove(descendantAddedHandler);
                targetGroup.descendantRemoved.remove(descendantRemovedHandler);
            }

            _invalidList = false;
            _target = null;

            _nodeToId = null;
            _transforms = null;
            _flags = null;
            _localToWorldTransforms = null;
            _worldToLocalTransforms = null;
            _numChildren = null;
            _idToNode = null;
            _parentId = null;
        }

        private function addedHandler(target : ISceneNode, ancestor : Group) : void
        {
            // the controller will remove itself from the node when it's not its own root anymore
            // but it will watch for the 'removed' signal to add itself back if the node becomes
            // its own root again
            _target.removed.add(removedHandler);
            _target.removeController(this);
        }

        private function removedHandler(target : ISceneNode, ancestor : Group) : void
        {
            if (target.root == target)
            {
                target.removed.remove(removedHandler);
                target.addController(this);
            }
        }

        private function descendantAddedHandler(root		: Group,
                                                descendant	: ISceneNode) : void
        {
            _invalidList = true;
        }

        private function descendantRemovedHandler(root			: Group,
                                                  descendant	: ISceneNode) : void
        {
            _invalidList = true;
        }

        private function getNodeId(node : ISceneNode) : uint
        {
            if (_invalidList || !(node in _nodeToId))
                updateTransformsList();

            return _nodeToId[node];
        }

        private function updateTransformsList() : void
        {
            var root    	                : ISceneNode 			= _target.root;
            var nodes   	                : Vector.<ISceneNode> 	= new <ISceneNode>[root];
            var nodeId  	                : uint 					= 0;
            var oldNodeToId                 : Dictionary            = _nodeToId;
            var oldInitialized              : Vector.<uint>         = _flags;
            var oldLocalToWorldTransforms   : Vector.<Matrix4x4>    = _localToWorldTransforms;
            var oldWorldToLocalTransform    : Vector.<Matrix4x4>    = _worldToLocalTransforms;

            _nodeToId = new Dictionary(true);
            _transforms = new <Matrix4x4>[];
            _flags = new <uint>[];
            _localToWorldTransforms = new <Matrix4x4>[];
            _worldToLocalTransforms = new <Matrix4x4>[];
            _numChildren = new <uint>[];
            _firstChildId = new <uint>[];
            _idToNode = new <ISceneNode>[];
            _parentId = new <int>[-1];

            while (nodes.length)
            {
                var node 	: ISceneNode 	= nodes.shift();
                var group   : Group 		= node as Group;

                _nodeToId[node] = nodeId;
                _idToNode[nodeId] = node;
                _transforms[nodeId] = node.transform;

                if (oldNodeToId && node in oldNodeToId)
                {
                    var oldNodeId   : uint  = oldNodeToId[node];

                    _localToWorldTransforms[nodeId] = oldLocalToWorldTransforms[oldNodeId];
                    _worldToLocalTransforms[nodeId] = oldWorldToLocalTransform[oldNodeId];
                    _flags[nodeId] = oldInitialized[oldNodeId];
                }
                else
                {
                    _localToWorldTransforms[nodeId] = new Matrix4x4().lock();
                    _worldToLocalTransforms[nodeId] = null;
                    _flags[nodeId] = FLAG_NONE;
                }

                if (group)
                {
                    var numChildren 	: uint = group.numChildren;
                    var firstChildId 	: uint = nodeId + nodes.length + 1;

                    _numChildren[nodeId] = numChildren;
                    _firstChildId[nodeId] = firstChildId;
                    for (var childId : uint = 0; childId < numChildren; ++childId)
                    {
                        _parentId[uint(firstChildId + childId)] = nodeId;
                        nodes.push(group.getChildAt(childId));
                    }
                }
                else
                {
                    _numChildren[nodeId] = 0;
                    _firstChildId[nodeId] = 0;
                }

                ++nodeId;
            }

            _worldToLocalTransforms.length = _localToWorldTransforms.length;
            _invalidList = false;
        }

        public function getLocalToWorldTransform(node 			: ISceneNode,
                                                 forceUpdate 	: Boolean = false) : Matrix4x4
        {
            var nodeId : uint = getNodeId(node);

            if (forceUpdate)
                updateAncestorsAndSelfLocalToWorld(nodeId);

            return _localToWorldTransforms[nodeId];
        }

        public function getWorldToLocalTransform(node           : ISceneNode,
                                                 forceUpdate    : Boolean   = false) : Matrix4x4
        {
            var nodeId                  : uint      = getNodeId(node);
            var worldToLocalTransform   : Matrix4x4 = _worldToLocalTransforms[nodeId];

            if (!worldToLocalTransform)
            {
                _worldToLocalTransforms[nodeId] = worldToLocalTransform = new Matrix4x4();
                if (!forceUpdate)
                {
                    worldToLocalTransform.copyFrom(_localToWorldTransforms[nodeId]).invert();
                    _flags[nodeId] |= FLAG_INIT_WORLD_TO_LOCAL;
                }
            }

            if (forceUpdate)
                updateAncestorsAndSelfLocalToWorld(nodeId);

            var flags : uint = _flags[nodeId];

            if (!(flags & FLAG_INIT_WORLD_TO_LOCAL))
            {
                _flags[nodeId] |= FLAG_INIT_WORLD_TO_LOCAL;

                if (flags & FLAG_LOCK_TRANSFORMS)
                    worldToLocalTransform.lock();

                worldToLocalTransform
                    .copyFrom(_localToWorldTransforms[nodeId])
                    .invert();

                if (flags & FLAG_LOCK_TRANSFORMS)
                    worldToLocalTransform.unlock();
            }

            return worldToLocalTransform;
        }

        public function setSharedLocalToWorldTransformReference(node      : ISceneNode,
                                                                matrix    : Matrix4x4) : void
        {
            var nodeId : uint = getNodeId(node);

            if (_flags[nodeId] & FLAG_INIT_LOCAL_TO_WORLD)
                matrix.copyFrom(_localToWorldTransforms[nodeId]);
            _localToWorldTransforms[nodeId] = matrix;
        }

        public function setSharedWorldToLocalTransformReference(node      : ISceneNode,
                                                                matrix    : Matrix4x4) : void
        {
            var nodeId : uint = getNodeId(node);

            if (_flags[nodeId] & FLAG_INIT_WORLD_TO_LOCAL)
                matrix.copyFrom(_worldToLocalTransforms[nodeId]);
            _worldToLocalTransforms[nodeId] = matrix;
        }

        public function synchronizeTransforms(node : ISceneNode, enabled : Boolean) : void
        {
            var nodeId : uint = getNodeId(node);

            _flags[nodeId] = enabled
                ? _flags[nodeId] | FLAG_SYNCHRONIZE_TRANSFORMS
                : _flags[nodeId] & ~FLAG_SYNCHRONIZE_TRANSFORMS;
        }

        public function lockTransformsBeforeUpdate(node : ISceneNode, enabled : Boolean) : void
        {
            var nodeId : uint = getNodeId(node);

            _flags[nodeId] = enabled
                ? _flags[nodeId] | FLAG_LOCK_TRANSFORMS
                : _flags[nodeId] & ~FLAG_LOCK_TRANSFORMS;
        }
    }
}

add TransformController.setSharedLocalToWorldTransformReference() and TransformController.setSharedWorldToLocalTransformReference() to share Matrix4x4 references and avoid copies


package dolly.utils {

import dolly.core.dolly_internal;

import mx.collections.ArrayCollection;
import mx.collections.ArrayList;

use namespace dolly_internal;

public class PropertyUtil {

	dolly_internal static function copyArray(sourceObj:*, targetObj:*, propertyName:String):void {
		targetObj[propertyName] = sourceObj[propertyName].slice();
	}

	dolly_internal static function copyArrayList(targetObj:*, propertyName:String, arrayList:ArrayList):void {
		targetObj[propertyName] = arrayList.source ? new ArrayList(arrayList.source) : new ArrayList();
	}

	dolly_internal static function copyArrayCollection(targetObj:*, propertyName:String, sourceProperty:*):void {
		const arrayCollection:ArrayCollection = (sourceProperty as ArrayCollection);
		targetObj[propertyName] = arrayCollection.source ?
				new ArrayCollection(arrayCollection.source.slice()) :
				new ArrayCollection();
	}

	private static function copyObject(targetObj:*, propertyName:String, sourceProperty:*):void {
		targetObj[propertyName] = sourceProperty;
	}

	public static function copyProperty(sourceObj:*, targetObj:*, propertyName:String):void {
		const sourceProperty:* = sourceObj[propertyName];

		if (sourceProperty is Array) {
			copyArray(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayList) {
			copyArrayList(targetObj, propertyName, sourceObj);
			return;
		}

		if (sourceProperty is ArrayCollection) {
			copyArrayCollection(targetObj, propertyName, sourceProperty);
			return;
		}

		copyObject(targetObj, propertyName, sourceProperty);
	}

	public static function cloneProperty(sourceObj:*, targetObj:*, propertyName:String):void {
		const sourceProperty:* = sourceObj[propertyName];

		if (sourceProperty is Array) {
			copyArray(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayList) {
			copyArrayList(targetObj, propertyName, sourceProperty);
			return;
		}

		if (sourceProperty is ArrayCollection) {
			copyArrayCollection(targetObj, propertyName, sourceProperty);
			return;
		}

		copyObject(targetObj, propertyName, sourceProperty);
	}
}
}

package dolly.utils {

import dolly.core.dolly_internal;

import mx.collections.ArrayCollection;
import mx.collections.ArrayList;

use namespace dolly_internal;

public class PropertyUtil {

	dolly_internal static function copyArray(sourceObj:*, targetObj:*, propertyName:String):void {
		targetObj[propertyName] = sourceObj[propertyName].slice();
	}

	dolly_internal static function copyArrayList(sourceObj:*, targetObj:*, propertyName:String):void {
		targetObj[propertyName] = sourceObj[propertyName] ?
				new ArrayList(sourceObj[propertyName].source) :
				new ArrayList();
	}

	dolly_internal static function copyArrayCollection(targetObj:*, propertyName:String, sourceProperty:*):void {
		const arrayCollection:ArrayCollection = (sourceProperty as ArrayCollection);
		targetObj[propertyName] = arrayCollection.source ?
				new ArrayCollection(arrayCollection.source.slice()) :
				new ArrayCollection();
	}

	private static function copyObject(targetObj:*, propertyName:String, sourceProperty:*):void {
		targetObj[propertyName] = sourceProperty;
	}

	public static function copyProperty(sourceObj:*, targetObj:*, propertyName:String):void {
		const sourceProperty:* = sourceObj[propertyName];

		if (sourceProperty is Array) {
			copyArray(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayList) {
			copyArrayList(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayCollection) {
			copyArrayCollection(targetObj, propertyName, sourceProperty);
			return;
		}

		copyObject(targetObj, propertyName, sourceProperty);
	}

	public static function cloneProperty(sourceObj:*, targetObj:*, propertyName:String):void {
		const sourceProperty:* = sourceObj[propertyName];

		if (sourceProperty is Array) {
			copyArray(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayList) {
			copyArrayList(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayCollection) {
			copyArrayCollection(targetObj, propertyName, sourceProperty);
			return;
		}

		copyObject(targetObj, propertyName, sourceProperty);
	}
}
}

Change signature of PropertyUtil.copyArrayList() method.


						-*- shell-script -*-
m4_pattern_allow([^URBI_SERVER_FLAGS$])
URBI_INIT()[

## --------------------- ##
## Auxiliary functions.  ##
## --------------------- ##

]URBI_GET_OPTIONS(
[  (-h|--help)    usage;;
   (-t|--to)      shift; dir=$1;;
   (-w|--wrapper) shift; process_wrapper "$1";;
   (*)            add_directory "$1";;
])[

# Print usage
usage ()
{
  cat <<EOF
Usage: $0 [OPTIONS] [DIR]...

Return a string which is to be used to define the environment.  I.e.,
typically returns (on stdout) something like

    WINEPREFIX=/SOME/PATH

Arguments can also be passed via the envvar
\`WINE_LD_LIBRARY_PATH_ARGS'.  The DIRs are added to the pseudo
LD_LIBRARY_PATH that Windows supports.

Options:
  -h, --help           display this message and exit
  -t, --to=DIR         install the \`wine' directory inside DIR
                       [$where]
  -w, --wrapper=FILE   also add the DIRs required to load the libraries
                       used by the Libtool wrapper FILE
                       multiple invocations accumulate
EOF
    exit 0
}

# add_directory DIR
# -----------------
# Add DIR to the output path.
add_directory ()
{
  local dir=$1
  if test -d "$dir"; then
    dir=$(winepath -w "$dir")
    windirs="$windirs;$dir"
  fi
}

# process_wrapper WRAPPER
# -----------------------
# Get the PATH spec from the libtool WRAPPER, and put its components
# in the output path.
process_wrapper ()
{
  local wrapper=$1
  require_file "$wrapper"
  local path
  path=$(sed -ne 's/^ *PATH=//p' "$wrapper")
  local save_IFS=$IFS
  IFS=:
  for p in $path
  do
    IFS=$save_IFS
    add_directory "$p"
  done
}

create_wine_directory ()
{
  verbose "creating $WINEPREFIX"
  rm -rf "$WINEPREFIX"
  mkdir -p "$WINEPREFIX"
  cp -a ~/.wine/dosdevices ~/.wine/*.reg ~/.wine/config "$WINEPREFIX"
  # Symlink everything from the .wine directory just in case.
  for f in ~/.wine/*
  do
    bf=$(basename $f)
    if ! test -a "$WINEPREFIX/$bf"; then
      ln -s $f "$WINEPREFIX/$bf"
    fi
  done
  # Add all the added path to the Path variable in user.reg config
  # file.  That idiotic file may have multiple "Path=".  Only one
  # will have ';'.

  # A safe means to pass information to Perl: envvars.
  export windirs
  perl -pi                                                              \
    -e 'BEGIN { $dirs=$ENV{windirs}; $dirs =~ s/\\/\\\\/g; }'           \
    -e 's/"Path"="(.*;.*)"/"Path"="\1$dirs"/' "$WINEPREFIX/user.reg"
}

# By default, installed this here.
where=$(pwd)
# List of directories to add to the Path.
windirs=
# If we need wine, setup it.
host=@host@

get_options $WINE_LD_LIBRARY_PATH_ARGS "$@"
verbose "host: $host"

# We used to check that we are not running Cygwin underneath.  Does
# not seem to make any sense here, and MN does not remember why he
# checked that.  So this check is removed.
case ${WINEPREFIX+set}:$host in
    (set:*) # Don't override the user's choice.
      ;;
    (*:*pw32*|*:*mingw32*)
      export WINEPREFIX=$where/wine
      test -d "$WINEPREFIX" ||
        create_wine_directory
      verbose "WINEPREFIX='$WINEPREFIX'"
      echo "WINEPREFIX='$WINEPREFIX'"
      ;;
esac

exit 0
]

						-*- shell-script -*-
m4_pattern_allow([^URBI_SERVER_FLAGS$])
URBI_INIT()[

## --------------------- ##
## Auxiliary functions.  ##
## --------------------- ##

]URBI_GET_OPTIONS(
[  (-h|--help)    usage;;
   (-t|--to)      shift; where=$1;;
   (-w|--wrapper) shift; process_wrapper "$1";;
   (*)            add_directory "$1";;
])[

# Print usage
usage ()
{
  cat <<EOF
Usage: $0 [OPTIONS] [DIR]...

Return a string which is to be used to define the environment.  I.e.,
typically returns (on stdout) something like

    WINEPREFIX=/SOME/PATH

Arguments can also be passed via the envvar
\`WINE_LD_LIBRARY_PATH_ARGS'.  The DIRs are added to the pseudo
LD_LIBRARY_PATH that Windows supports.

Options:
  -h, --help           display this message and exit
  -t, --to=DIR         install the \`wine' directory inside DIR
                       in other words, make WINEPREFIX=DIR/wine
                       [$where]
  -w, --wrapper=FILE   also add the DIRs required to load the libraries
                       used by the Libtool wrapper FILE
                       multiple invocations accumulate
EOF
    exit 0
}

# add_directory DIR
# -----------------
# Add DIR to the output path.
add_directory ()
{
  local dir=$1
  if test -d "$dir"; then
    dir=$(winepath -w "$dir")
    windirs="$windirs;$dir"
  fi
}

# process_wrapper WRAPPER
# -----------------------
# Get the PATH spec from the libtool WRAPPER, and put its components
# in the output path.
process_wrapper ()
{
  local wrapper=$1
  require_file "$wrapper"
  local path
  path=$(sed -ne 's/^ *PATH=//p' "$wrapper")
  local save_IFS=$IFS
  IFS=:
  for p in $path
  do
    IFS=$save_IFS
    add_directory "$p"
  done
}

create_wine_directory ()
{
  verbose "creating $WINEPREFIX"
  rm -rf "$WINEPREFIX"
  mkdir -p "$WINEPREFIX"
  cp -a ~/.wine/dosdevices ~/.wine/*.reg ~/.wine/config "$WINEPREFIX"
  # Symlink everything from the .wine directory just in case.
  for f in ~/.wine/*
  do
    bf=$(basename $f)
    if ! test -a "$WINEPREFIX/$bf"; then
      ln -s $f "$WINEPREFIX/$bf"
    fi
  done
  # Add all the added path to the Path variable in user.reg config
  # file.  That idiotic file may have multiple "Path=".  Only one
  # will have ';'.

  # A safe means to pass information to Perl: envvars.
  export windirs
  perl -pi                                                              \
    -e 'BEGIN { $dirs=$ENV{windirs}; $dirs =~ s/\\/\\\\/g; }'           \
    -e 's/"Path"="(.*;.*)"/"Path"="\1$dirs"/' "$WINEPREFIX/user.reg"
}

# By default, installed this here.
where=$(pwd)
# List of directories to add to the Path.
windirs=
# If we need wine, setup it.
host=@host@

get_options $WINE_LD_LIBRARY_PATH_ARGS "$@"
verbose "host: $host"

# We used to check that we are not running Cygwin underneath.  Does
# not seem to make any sense here, and MN does not remember why he
# checked that.  So this check is removed.
case $host in
  (*pw32*|*mingw32*)
    export WINEPREFIX=$where/wine
    test -d "$WINEPREFIX" ||
      create_wine_directory
    verbose "WINEPREFIX='$WINEPREFIX'"
    echo "WINEPREFIX='$WINEPREFIX'"
    ;;
esac

exit 0
]

Fix wine-ld-library-path --to.

Fix wine-ld-library-path --to.

	* build-aux/wine-ld-library-path.as: Fix var name.
	Override WINEPREFIX if defined.


///////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011 Esri. All Rights Reserved.
//
// Licensed 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 widgets.Geoprocessing.parameters
{

import com.esri.ags.tasks.supportClasses.RasterData;

public class RasterDataLayerParam extends BaseParameter
{
    //--------------------------------------------------------------------------
    //
    //  Overridden properties
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    //  defaultValue
    //----------------------------------

    private var _defaultValue:RasterData;

    override public function get defaultValue():Object
    {
        return _defaultValue;
    }

    override public function set defaultValue(value:Object):void
    {
        _defaultValue = new RasterData(value.url, value.format);
    }

    //----------------------------------
    //  type
    //----------------------------------

    override public function get type():String
    {
        return GPParameterTypes.RASTER_DATA_LAYER;
    }

    //--------------------------------------------------------------------------
    //
    //  Overridden methods
    //
    //--------------------------------------------------------------------------

    public override function defaultValueFromString(text:String):void
    {
        //NOT SUPPORTED - OUTPUT PARAM ONLY
    }
}

}

///////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011 Esri. All Rights Reserved.
//
// Licensed 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 widgets.Geoprocessing.parameters
{

import com.esri.ags.tasks.supportClasses.RasterData;

public class RasterDataLayerParam extends BaseParameter
{
    //--------------------------------------------------------------------------
    //
    //  Constants
    //
    //--------------------------------------------------------------------------

    private static const URL_DELIMITER:String = "url:";
    private static const FORMAT_DELIMITER:String = "format:";
    private static const ITEM_ID_DELIMITER:String = "itemID:";

    private static const VALID_URL_REGEX:RegExp = /^(ht|f)tps?:\/\/[^\s\.]+(\.[^\s\.]+)*((\/|\.)[^\s\.]+)+\/?$/;

    //--------------------------------------------------------------------------
    //
    //  Overridden properties
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    //  defaultValue
    //----------------------------------

    private var _defaultValue:RasterData;

    override public function get defaultValue():Object
    {
        return _defaultValue;
    }

    override public function set defaultValue(value:Object):void
    {
        _defaultValue = new RasterData(value.url, value.format);
    }

    //----------------------------------
    //  type
    //----------------------------------

    override public function get type():String
    {
        return GPParameterTypes.RASTER_DATA_LAYER;
    }

    //--------------------------------------------------------------------------
    //
    //  Overridden methods
    //
    //--------------------------------------------------------------------------

    public override function defaultValueFromString(description:String):void
    {
        var dataFile:RasterData = new RasterData();

        if (description.indexOf(URL_DELIMITER) == 0
            || description.indexOf(FORMAT_DELIMITER) == 0)
        {
            var tokens:Array = description.split(",");
            for each (var token:String in tokens)
            {
                if (token.indexOf(URL_DELIMITER) == 0)
                {
                    dataFile.url = token.substr(URL_DELIMITER.length);
                }
                else if (token.indexOf(FORMAT_DELIMITER) == 0)
                {
                    dataFile.format = token.substr(FORMAT_DELIMITER.length);
                }
            }
        }
        else if (description.indexOf(ITEM_ID_DELIMITER) == 0)
        {
            dataFile.itemID = description.substr(ITEM_ID_DELIMITER.length);
        }

        _defaultValue = dataFile;
    }

    override public function hasValidValue():Boolean
    {
        if (_defaultValue.itemID)
        {
            return true;
        }
        else if (_defaultValue.url)
        {
            return VALID_URL_REGEX.test(_defaultValue.url);
        }
        else
        {
            return false;
        }
    }
}

}

Support RasterDataLayerParam parsing & validating its default value.