package aerys.minko.type.binding
{
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.type.Signal;
	import aerys.minko.type.enum.DataProviderUsage;

	import flash.utils.Dictionary;

	public final class DataBindings
	{
		private var _owner							: ISceneNode				= null;

		private var _providers						: Vector.<IDataProvider> 	= new <IDataProvider>[];
		private var _bindingNames					: Vector.<String>			= new Vector.<String>();

		private var _bindingNameToValue				: Object					= {};
		private var _bindingNameToChangedSignal		: Object					= {};

		private var _bindingNameToProvider			: Object					= {};
		private var _providerToBindingNames			: Dictionary				= new Dictionary(); // dic[Vector.<String>[]]

		public function get owner() : ISceneNode
		{
			return _owner;
		}

		public function get numProviders() : uint
		{
			return _providers.length;
		}

		public function get numProperties() : uint
		{
			return _bindingNames.length;
		}

		public function DataBindings(owner : ISceneNode)
		{
			_owner = owner;
		}

		public function contains(dataProvider : IDataProvider) : Boolean
		{
			return _providers.indexOf(dataProvider) != -1;
		}

		public function addProvider(provider : IDataProvider) : void
		{
			if (_providerToBindingNames[provider])
				throw new Error('This provider is already bound.');

			var providerBindingNames	: Vector.<String>	= new <String>[];
			var dataDescriptor			: Object			= provider.dataDescriptor;

			provider.changed.add(providerChangedHandler);

			_providerToBindingNames[provider] = providerBindingNames;
			_providers.push(provider);

			for (var attrName : String in dataDescriptor)
			{
				// if this provider attribute is also a dataprovider, let's also bind it
				var bindingName	: String	= dataDescriptor[attrName];
				var attribute	: Object	= provider[attrName];

				if (_bindingNames.indexOf(bindingName) != -1)
					throw new Error(
						'Another data provider is already declaring the \'' + bindingName + '\' property.'
					);

				_bindingNameToProvider[bindingName] = provider;
				_bindingNameToValue[bindingName] = attribute;

				providerBindingNames.push(bindingName);
				_bindingNames.push(bindingName);

				if (_bindingNameToChangedSignal[bindingName])
					_bindingNameToChangedSignal[bindingName].execute(this, bindingName, null, attribute);
			}
		}

		public function removeProvider(provider : IDataProvider) : void
		{
			var providerBindingsNames 	: Vector.<String> 	= _providerToBindingNames[provider];
			var tmpValues				: Object			= {};

			if (providerBindingsNames == null)
				throw new ArgumentError('Unkown provider.');

			var numBindings : uint = _bindingNames.length;
			for (var indexRead : uint = 0, indexWrite : uint = 0; indexRead < numBindings; ++indexRead)
			{
				var bindingName : String = _bindingNames[indexRead];

				if (providerBindingsNames.indexOf(bindingName) != -1)
				{
					tmpValues[bindingName] = _bindingNameToValue[bindingName];

					delete _bindingNameToValue[bindingName];
					delete _bindingNameToProvider[bindingName];
				}
				else
					_bindingNames[indexWrite++] = _bindingNames[indexRead];
			}
			_bindingNames.length = indexWrite;

			provider.changed.remove(providerChangedHandler);

			_providers.splice(_providers.indexOf(provider), 1);

			delete _providerToBindingNames[provider];

			for each (bindingName in providerBindingsNames)
			{
				var changedSignal : Signal = _bindingNameToChangedSignal[bindingName] as Signal;

				if (changedSignal != null)
				{
					changedSignal.execute(
						this, bindingName, tmpValues[bindingName], null
					);
				}
			}
		}

		public function removeAllProviders() : void
		{
			var numProviders : uint = this.numProviders;

			for (var providerId : int = numProviders - 1; providerId >= 0; --providerId)
				removeProvider(getProviderAt(providerId));
		}

		public function hasCallback(bindingName	: String,
									callback	: Function) : Boolean
		{
			var signal : Signal = _bindingNameToChangedSignal[bindingName];

			return signal != null && signal.hasCallback(callback);
		}

		public function addCallback(bindingName : String,
									callback	: Function) : void
		{
			_bindingNameToChangedSignal[bindingName] ||= new Signal(
				'DataBindings.changed[' + bindingName + ']'
			);

			Signal(_bindingNameToChangedSignal[bindingName]).add(callback);
		}

		public function removeCallback(bindingName	: String,
									   callback		: Function) : void
		{
			var signal : Signal = _bindingNameToChangedSignal[bindingName];
			if (!signal)
				throw new ArgumentError('Unkown property \'' + bindingName + '\'.');

			signal.remove(callback);

			if (signal.numCallbacks == 0)
				delete _bindingNameToChangedSignal[bindingName];
		}

		public function getProviderAt(index : uint) : IDataProvider
		{
			return _providers[index];
		}

		public function getProviderByBindingName(bindingName : String) : IDataProvider
		{
			if (_bindingNameToProvider[bindingName] == null)
				throw new ArgumentError('Unkown property \'' + bindingName + '\'.');

			return _bindingNameToProvider[bindingName];
		}

		public function propertyExists(bindingName : String) : Boolean
		{
			return _bindingNameToValue.hasOwnProperty(bindingName);
		}

		public function getProperty(bindingName : String) : *
		{
			if (_bindingNames.indexOf(bindingName) < 0)
				throw new Error('The property \'' + bindingName + '\' does not exist.');

			return _bindingNameToValue[bindingName];
		}

		public function getPropertyName(bindingIndex : uint) : String
		{
			if (bindingIndex > numProperties)
				throw new ArgumentError('No such binding');

			return _bindingNames[bindingIndex];
		}

		public function copySharedProvidersFrom(source : DataBindings) : void
		{
			var numProviders : uint = source._providers.length;

			for (var providerId : uint = 0; providerId < numProviders; ++providerId)
			{
				var provider : IDataProvider = source._providers[providerId];

				if (provider.usage == DataProviderUsage.SHARED)
					addProvider(provider);
			}
		}

		private function providerChangedHandler(source : IDataProvider, attributeName : String) : void
		{
			if (attributeName == null)
			{
				throw new Error('DataProviders must change one property at a time.');
			}
			else if (attributeName == 'dataDescriptor')
			{
				removeProvider(source);
				addProvider(source);
			}
			else
			{
				var bindingName : String		= source.dataDescriptor[attributeName];
				var oldValue	: Object		= _bindingNameToValue[bindingName];
				var newValue	: Object		= source[attributeName];

				_bindingNameToValue[bindingName] = newValue;

				if (_bindingNameToChangedSignal[bindingName])
					_bindingNameToChangedSignal[bindingName].execute(this, bindingName, oldValue, newValue);
			}
		}
	}
}

package aerys.minko.type.binding
{
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.type.Signal;
	import aerys.minko.type.enum.DataProviderUsage;

	import flash.utils.Dictionary;

	public final class DataBindings
	{
		private var _owner							: ISceneNode				= null;

		private var _providers						: Vector.<IDataProvider> 	= new <IDataProvider>[];
		private var _bindingNames					: Vector.<String>			= new Vector.<String>();

		private var _bindingNameToValue				: Object					= {};
		private var _bindingNameToChangedSignal		: Object					= {};

		private var _bindingNameToProvider			: Object					= {};
		private var _providerToBindingNames			: Dictionary				= new Dictionary(); // dic[Vector.<String>[]]

		public function get owner() : ISceneNode
		{
			return _owner;
		}

		public function get numProviders() : uint
		{
			return _providers.length;
		}

		public function get numProperties() : uint
		{
			return _bindingNames.length;
		}

		public function DataBindings(owner : ISceneNode)
		{
			_owner = owner;
		}

		public function contains(dataProvider : IDataProvider) : Boolean
		{
			return _providers.indexOf(dataProvider) != -1;
		}

		public function addProvider(provider : IDataProvider) : void
		{
			if (_providerToBindingNames[provider])
				throw new Error('This provider is already bound.');

			var providerBindingNames	: Vector.<String>	= new <String>[];
			var dataDescriptor			: Object			= provider.dataDescriptor;

			provider.changed.add(providerChangedHandler);

			_providerToBindingNames[provider] = providerBindingNames;
			_providers.push(provider);

			for (var attrName : String in dataDescriptor)
			{
				// if this provider attribute is also a dataprovider, let's also bind it
				var bindingName	: String	= dataDescriptor[attrName];
				var attribute	: Object	= provider[attrName];

				if (_bindingNames.indexOf(bindingName) != -1)
					throw new Error(
						'Another data provider is already declaring the \'' + bindingName
                        + '\' property.'
					);

				_bindingNameToProvider[bindingName] = provider;
				_bindingNameToValue[bindingName] = attribute;

				providerBindingNames.push(bindingName);
				_bindingNames.push(bindingName);

				if (_bindingNameToChangedSignal[bindingName])
					_bindingNameToChangedSignal[bindingName].execute(this, bindingName, null, attribute);
			}
		}

		public function removeProvider(provider : IDataProvider) : void
		{
			var providerBindingsNames 	: Vector.<String> 	= _providerToBindingNames[provider];
			var tmpValues				: Object			= {};

			if (providerBindingsNames == null)
				throw new ArgumentError('Unknown provider.');

			var numBindings : uint = _bindingNames.length;
			for (var indexRead : uint = 0, indexWrite : uint = 0; indexRead < numBindings; ++indexRead)
			{
				var bindingName : String = _bindingNames[indexRead];

				if (providerBindingsNames.indexOf(bindingName) != -1)
				{
					tmpValues[bindingName] = _bindingNameToValue[bindingName];

					delete _bindingNameToValue[bindingName];
					delete _bindingNameToProvider[bindingName];
				}
				else
					_bindingNames[indexWrite++] = _bindingNames[indexRead];
			}
			_bindingNames.length = indexWrite;

			provider.changed.remove(providerChangedHandler);

			_providers.splice(_providers.indexOf(provider), 1);

			delete _providerToBindingNames[provider];

			for each (bindingName in providerBindingsNames)
			{
				var changedSignal : Signal = _bindingNameToChangedSignal[bindingName] as Signal;

				if (changedSignal != null)
				{
					changedSignal.execute(
						this, bindingName, tmpValues[bindingName], null
					);
				}
			}
		}

		public function removeAllProviders() : void
		{
			var numProviders : uint = this.numProviders;

			for (var providerId : int = numProviders - 1; providerId >= 0; --providerId)
				removeProvider(getProviderAt(providerId));
		}

		public function hasCallback(bindingName	: String,
									callback	: Function) : Boolean
		{
			var signal : Signal = _bindingNameToChangedSignal[bindingName];

			return signal != null && signal.hasCallback(callback);
		}

		public function addCallback(bindingName : String,
									callback	: Function) : void
		{
			_bindingNameToChangedSignal[bindingName] ||= new Signal(
				'DataBindings.changed[' + bindingName + ']'
			);

			Signal(_bindingNameToChangedSignal[bindingName]).add(callback);
		}

		public function removeCallback(bindingName	: String,
									   callback		: Function) : void
		{
			var signal : Signal = _bindingNameToChangedSignal[bindingName];
			if (!signal)
				throw new ArgumentError('Unkown property \'' + bindingName + '\'.');

			signal.remove(callback);

			if (signal.numCallbacks == 0)
				delete _bindingNameToChangedSignal[bindingName];
		}

		public function getProviderAt(index : uint) : IDataProvider
		{
			return _providers[index];
		}

		public function getProviderByBindingName(bindingName : String) : IDataProvider
		{
			if (_bindingNameToProvider[bindingName] == null)
				throw new ArgumentError('Unkown property \'' + bindingName + '\'.');

			return _bindingNameToProvider[bindingName];
		}

		public function propertyExists(bindingName : String) : Boolean
		{
			return _bindingNameToValue.hasOwnProperty(bindingName);
		}

		public function getProperty(bindingName : String) : *
		{
			if (_bindingNames.indexOf(bindingName) < 0)
				throw new Error('The property \'' + bindingName + '\' does not exist.');

			return _bindingNameToValue[bindingName];
		}

		public function getPropertyName(bindingIndex : uint) : String
		{
			if (bindingIndex > numProperties)
				throw new ArgumentError('No such binding');

			return _bindingNames[bindingIndex];
		}

		public function copySharedProvidersFrom(source : DataBindings) : void
		{
			var numProviders : uint = source._providers.length;

			for (var providerId : uint = 0; providerId < numProviders; ++providerId)
			{
				var provider : IDataProvider = source._providers[providerId];

				if (provider.usage == DataProviderUsage.SHARED)
					addProvider(provider);
			}
		}

		private function providerChangedHandler(source : IDataProvider, attributeName : String) : void
		{
			if (attributeName == null)
			{
				throw new Error('DataProviders must change one property at a time.');
			}
			else if (attributeName == 'dataDescriptor')
			{
				removeProvider(source);
				addProvider(source);
			}
			else
			{
				var bindingName : String		= source.dataDescriptor[attributeName];
				var oldValue	: Object		= _bindingNameToValue[bindingName];
				var newValue	: Object		= source[attributeName];

				_bindingNameToValue[bindingName] = newValue;

				if (_bindingNameToChangedSignal[bindingName])
					_bindingNameToChangedSignal[bindingName].execute(this, bindingName, oldValue, newValue);
			}
		}
	}
}

fix coding style and typo

fix coding style and typo


// Urho3D spawn editor

LineEdit@ randomRotationX;
LineEdit@ randomRotationY;
LineEdit@ randomRotationZ;
LineEdit@ randomScaleMinEdit;
LineEdit@ randomScaleMaxEdit;
LineEdit@ NumberSpawnedObjectsEdit;
LineEdit@ spawnRadiusEdit;
LineEdit@ spawnCountEdit;

Window@ spawnWindow;
Vector3 randomRotation=Vector3(0.f,0.f,0.f);
float randomScaleMin=1;
float randomScaleMax=1;
float spawnCount=1;
float spawnRadius=0;
bool useNormal=true;

int numberSpawnedObjects=1;
Array<String> spawnedObjectsNames;

void CreateSpawnEditor()
{
    if (spawnWindow !is null)
        return;

    spawnWindow = ui.LoadLayout(cache.GetResource("XMLFile", "UI/EditorSpawnWindow.xml"));
    ui.root.AddChild(spawnWindow);
    spawnWindow.opacity = uiMaxOpacity;

    int height = Min(ui.root.height - 60, 500);
    spawnWindow.SetSize(300, height);
    CenterDialog(spawnWindow);

    HideSpawnEditor();
    SubscribeToEvent(spawnWindow.GetChild("CloseButton", true), "Released", "HideSpawnEditor");
    randomRotationX=spawnWindow.GetChild("RandomRotation.x", true);
    randomRotationY=spawnWindow.GetChild("RandomRotation.y", true);
    randomRotationZ=spawnWindow.GetChild("RandomRotation.z", true);
    randomRotationX.text=String(randomRotation.x);
    randomRotationY.text=String(randomRotation.y);
    randomRotationZ.text=String(randomRotation.z);

    randomScaleMinEdit=spawnWindow.GetChild("RandomScaleMin", true);
    randomScaleMaxEdit=spawnWindow.GetChild("RandomScaleMax", true);
    randomScaleMinEdit.text=String(randomScaleMin);
    randomScaleMaxEdit.text=String(randomScaleMax);
    CheckBox@ useNormalToggle = spawnWindow.GetChild("UseNormal", true);
    useNormalToggle.checked = useNormal;

    NumberSpawnedObjectsEdit=spawnWindow.GetChild("NumberSpawnedObjects", true);
    NumberSpawnedObjectsEdit.text=String(numberSpawnedObjects);

    spawnRadiusEdit=spawnWindow.GetChild("SpawnRadius", true);
    spawnCountEdit=spawnWindow.GetChild("SpawnCount", true);
    spawnRadiusEdit.text=String(spawnRadius);
    spawnCountEdit.text=String(spawnCount);

    SubscribeToEvent(randomRotationX, "TextChanged", "EditRandomRotation");
    SubscribeToEvent(randomRotationY, "TextChanged", "EditRandomRotation");
    SubscribeToEvent(randomRotationZ, "TextChanged", "EditRandomRotation");
    SubscribeToEvent(randomScaleMinEdit, "TextChanged", "EditRandomScale");
    SubscribeToEvent(randomScaleMaxEdit, "TextChanged", "EditRandomScale");
    SubscribeToEvent(spawnRadiusEdit, "TextChanged", "EditSpawnRadius");
    SubscribeToEvent(spawnCountEdit, "TextChanged", "EditSpawnCount");
    SubscribeToEvent(useNormalToggle, "Toggled", "ToggleUseNormal");
    SubscribeToEvent(NumberSpawnedObjectsEdit, "TextFinished", "UpdateNumberSpawnedObjects");
    SubscribeToEvent(spawnWindow.GetChild("SetSpawnMode", true), "Released", "SetSpawnMode");
    RefreshPickedObjects();
}

bool ShowSpawnEditor()
{
    spawnWindow.visible = true;
    spawnWindow.BringToFront();
    return true;
}

void HideSpawnEditor()
{
    spawnWindow.visible = false;
}

void PickSpawnObject()
{
    @resourcePicker = GetResourcePicker(ShortStringHash("Node"));
    if (resourcePicker is null)
        return;

    String lastPath = resourcePicker.lastPath;
    if (lastPath.empty)
        lastPath = sceneResourcePath;
    CreateFileSelector("Pick " + resourcePicker.typeName, "OK", "Cancel", lastPath, resourcePicker.filters, resourcePicker.lastFilter);
    SubscribeToEvent(uiFileSelector, "FileSelected", "PickSpawnObjectDone");
}

void EditRandomRotation(StringHash eventType, VariantMap& eventData)
{
    LineEdit@ edit = eventData["Element"].GetPtr();
    randomRotation = Vector3(randomRotationX.text.ToFloat(), randomRotationY.text.ToFloat(), randomRotationZ.text.ToFloat());
    UpdateHierarchyItem(editorScene);
}

void EditRandomScale(StringHash eventType, VariantMap& eventData)
{
    LineEdit@ edit = eventData["Element"].GetPtr();
    randomScaleMin = randomScaleMinEdit.text.ToFloat();
    randomScaleMax = randomScaleMaxEdit.text.ToFloat();
    UpdateHierarchyItem(editorScene);
}

void ToggleUseNormal(StringHash eventType, VariantMap& eventData)
{
    useNormal = cast<CheckBox>(eventData["Element"].GetPtr()).checked;
}

void UpdateNumberSpawnedObjects(StringHash eventType, VariantMap& eventData)
{
    LineEdit@ edit = eventData["Element"].GetPtr();
    numberSpawnedObjects=edit.text.ToFloat();
    edit.text=String(numberSpawnedObjects);
    RefreshPickedObjects();
}

void EditSpawnRadius(StringHash eventType, VariantMap& eventData)
{
    LineEdit@ edit = eventData["Element"].GetPtr();
    spawnRadius=edit.text.ToFloat();
}
void EditSpawnCount(StringHash eventType, VariantMap& eventData)
{
    LineEdit@ edit = eventData["Element"].GetPtr();
    spawnCount=edit.text.ToFloat();
}

void RefreshPickedObjects()
{
    spawnedObjectsNames.Resize(numberSpawnedObjects);
    ListView@ list = spawnWindow.GetChild("SpawnedObjects", true);
    list.RemoveAllItems();

    for (uint i = 0; i < numberSpawnedObjects; ++i)
    {
        UIElement@ parent = CreateAttributeEditorParentWithSeparatedLabel(list, "Object " +(i+1), i, 0, false);

        UIElement@ container = UIElement();
        container.SetLayout(LM_HORIZONTAL, 4, IntRect(10, 0, 4, 0));
        container.SetFixedHeight(ATTR_HEIGHT);
        parent.AddChild(container);

        LineEdit@ nameEdit = CreateAttributeLineEdit(container, null, i, 0);
        nameEdit.name = "TextureNameEdit" + String(i);

        Button@ pickButton = CreateResourcePickerButton(container, null, i, 0, "Pick");
        SubscribeToEvent(pickButton, "Released", "PickSpawnedObject");
        nameEdit.text = spawnedObjectsNames[i];

        SubscribeToEvent(nameEdit, "TextFinished", "EditSpawnedObjectName");
    }
}

void EditSpawnedObjectName(StringHash eventType, VariantMap& eventData)
{
    LineEdit@ nameEdit = eventData["Element"].GetPtr();
    int index = nameEdit.vars["Index"].GetUInt();
    String resourceName = nameEdit.text;
    XMLFile@ xml = cache.GetResource("XMLFile", resourceName);
    if(xml !is null)
        spawnedObjectsNames[index]=resourceName;
    else
        spawnedObjectsNames[index]=String("");
    RefreshPickedObjects();
}

void PickSpawnedObject(StringHash eventType, VariantMap& eventData)
{
    UIElement@ button = eventData["Element"].GetPtr();
    resourcePickIndex = button.vars["Index"].GetUInt();
    CreateFileSelector("Pick spawned object", "Pick", "Cancel", uiNodePath, uiSceneFilters, uiNodeFilter);

    SubscribeToEvent(uiFileSelector, "FileSelected", "PickSpawnedObjectNameDone");
}

void PickSpawnedObjectNameDone(StringHash eventType, VariantMap& eventData)
{
    StoreResourcePickerPath();
    CloseFileSelector();

    if (!eventData["OK"].GetBool())
    {
        @resourcePicker = null;
        return;
    }

    String resourceName = GetResourceNameFromFullName(eventData["FileName"].GetString());
    XMLFile@ xml = cache.GetResource("XMLFile", resourceName);
    if(xml !is null)
        spawnedObjectsNames[resourcePickIndex]=resourceName;
    else
        spawnedObjectsNames[resourcePickIndex]=String("");
    @resourcePicker = null;
    RefreshPickedObjects();
}

void SetSpawnMode(StringHash eventType, VariantMap& eventData)
{
    editMode=EDIT_SPAWN;
}

void PlaceObject(Vector3 spawnPosition, Vector3 normal)
{
    Quaternion spawnRotation;
    if(useNormal)spawnRotation=Quaternion(Vector3(0.f,1.f,0.f),normal);
    int number=RandomInt(0,spawnedObjectsNames.length);
    XMLFile@ xml = cache.GetResource("XMLFile", spawnedObjectsNames[number]);
    Node@ spawnedObject =editorScene.InstantiateXML(xml, spawnPosition, spawnRotation);
    if(spawnedObject is null)
    {
        spawnedObjectsNames[number]=spawnedObjectsNames[spawnedObjectsNames.length-1];
        --numberSpawnedObjects;
        RefreshPickedObjects();
        return;
    }

    spawnedObject.scale=spawnedObject.scale*Random(randomScaleMin, randomScaleMax);
    spawnedObject.Rotate(Quaternion(Random(-randomRotation.x,randomRotation.x),
    Random(-randomRotation.y,randomRotation.y),Random(-randomRotation.z,randomRotation.z)),false);
    CreateNodeAction action;
    action.Define(spawnedObject);
    SaveEditAction(action);
    SetSceneModified();
}

void SpawnObject()
{
    if(spawnedObjectsNames.length==0) return;
    IntRect view = activeViewport.viewport.rect;

    for(int i=0;i<spawnCount;i++)
    {
        Vector2 norm=Vector2(Random(-1,1),Random(-1,1));
        norm.Normalize();
        norm=norm*(spawnRadius*Random(0,1));
        IntVector2 pos = IntVector2(ui.cursorPosition.x+norm.x,ui.cursorPosition.y+norm.y);
        Ray cameraRay = camera.GetScreenRay(
            float(pos.x - view.left) / view.width,
            float(pos.y - view.top) / view.height);

        if (pickMode < PICK_RIGIDBODIES)
        {
            if (editorScene.octree is null)
                return;
            RayQueryResult result = editorScene.octree.RaycastSingle(cameraRay, RAY_TRIANGLE, camera.farClip,
                pickModeDrawableFlags[pickMode], 0x7fffffff);
            if (result.drawable !is null)
                PlaceObject(result.position, result.normal);
        }
        else
        {
            if (editorScene.physicsWorld is null)
                return;

            // If we are not running the actual physics update, refresh collisions before raycasting
            if (!runUpdate)
                editorScene.physicsWorld.UpdateCollisions();

            PhysicsRaycastResult result = editorScene.physicsWorld.RaycastSingle(cameraRay, camera.farClip);
            if (result.body !is null)
                PlaceObject(result.position, result.normal);
        }
    }
}

// Urho3D spawn editor

LineEdit@ randomRotationX;
LineEdit@ randomRotationY;
LineEdit@ randomRotationZ;
LineEdit@ randomScaleMinEdit;
LineEdit@ randomScaleMaxEdit;
LineEdit@ NumberSpawnedObjectsEdit;
LineEdit@ spawnRadiusEdit;
LineEdit@ spawnCountEdit;

Window@ spawnWindow;
Vector3 randomRotation=Vector3(0.f,0.f,0.f);
float randomScaleMin=1;
float randomScaleMax=1;
float spawnCount=1;
float spawnRadius=0;
bool useNormal=true;

int numberSpawnedObjects=1;
Array<String> spawnedObjectsNames;

void CreateSpawnEditor()
{
    if (spawnWindow !is null)
        return;

    spawnWindow = ui.LoadLayout(cache.GetResource("XMLFile", "UI/EditorSpawnWindow.xml"));
    ui.root.AddChild(spawnWindow);
    spawnWindow.opacity = uiMaxOpacity;

    int height = Min(ui.root.height - 60, 500);
    spawnWindow.SetSize(300, height);
    CenterDialog(spawnWindow);

    HideSpawnEditor();
    SubscribeToEvent(spawnWindow.GetChild("CloseButton", true), "Released", "HideSpawnEditor");
    randomRotationX=spawnWindow.GetChild("RandomRotation.x", true);
    randomRotationY=spawnWindow.GetChild("RandomRotation.y", true);
    randomRotationZ=spawnWindow.GetChild("RandomRotation.z", true);
    randomRotationX.text=String(randomRotation.x);
    randomRotationY.text=String(randomRotation.y);
    randomRotationZ.text=String(randomRotation.z);

    randomScaleMinEdit=spawnWindow.GetChild("RandomScaleMin", true);
    randomScaleMaxEdit=spawnWindow.GetChild("RandomScaleMax", true);
    randomScaleMinEdit.text=String(randomScaleMin);
    randomScaleMaxEdit.text=String(randomScaleMax);
    CheckBox@ useNormalToggle = spawnWindow.GetChild("UseNormal", true);
    useNormalToggle.checked = useNormal;

    NumberSpawnedObjectsEdit=spawnWindow.GetChild("NumberSpawnedObjects", true);
    NumberSpawnedObjectsEdit.text=String(numberSpawnedObjects);

    spawnRadiusEdit=spawnWindow.GetChild("SpawnRadius", true);
    spawnCountEdit=spawnWindow.GetChild("SpawnCount", true);
    spawnRadiusEdit.text=String(spawnRadius);
    spawnCountEdit.text=String(spawnCount);

    SubscribeToEvent(randomRotationX, "TextChanged", "EditRandomRotation");
    SubscribeToEvent(randomRotationY, "TextChanged", "EditRandomRotation");
    SubscribeToEvent(randomRotationZ, "TextChanged", "EditRandomRotation");
    SubscribeToEvent(randomScaleMinEdit, "TextChanged", "EditRandomScale");
    SubscribeToEvent(randomScaleMaxEdit, "TextChanged", "EditRandomScale");
    SubscribeToEvent(spawnRadiusEdit, "TextChanged", "EditSpawnRadius");
    SubscribeToEvent(spawnCountEdit, "TextChanged", "EditSpawnCount");
    SubscribeToEvent(useNormalToggle, "Toggled", "ToggleUseNormal");
    SubscribeToEvent(NumberSpawnedObjectsEdit, "TextFinished", "UpdateNumberSpawnedObjects");
    SubscribeToEvent(spawnWindow.GetChild("SetSpawnMode", true), "Released", "SetSpawnMode");
    RefreshPickedObjects();
}

bool ShowSpawnEditor()
{
    spawnWindow.visible = true;
    spawnWindow.BringToFront();
    return true;
}

void HideSpawnEditor()
{
    spawnWindow.visible = false;
}

void PickSpawnObject()
{
    @resourcePicker = GetResourcePicker(ShortStringHash("Node"));
    if (resourcePicker is null)
        return;

    String lastPath = resourcePicker.lastPath;
    if (lastPath.empty)
        lastPath = sceneResourcePath;
    CreateFileSelector("Pick " + resourcePicker.typeName, "OK", "Cancel", lastPath, resourcePicker.filters, resourcePicker.lastFilter);
    SubscribeToEvent(uiFileSelector, "FileSelected", "PickSpawnObjectDone");
}

void EditRandomRotation(StringHash eventType, VariantMap& eventData)
{
    LineEdit@ edit = eventData["Element"].GetPtr();
    randomRotation = Vector3(randomRotationX.text.ToFloat(), randomRotationY.text.ToFloat(), randomRotationZ.text.ToFloat());
    UpdateHierarchyItem(editorScene);
}

void EditRandomScale(StringHash eventType, VariantMap& eventData)
{
    LineEdit@ edit = eventData["Element"].GetPtr();
    randomScaleMin = randomScaleMinEdit.text.ToFloat();
    randomScaleMax = randomScaleMaxEdit.text.ToFloat();
    UpdateHierarchyItem(editorScene);
}

void ToggleUseNormal(StringHash eventType, VariantMap& eventData)
{
    useNormal = cast<CheckBox>(eventData["Element"].GetPtr()).checked;
}

void UpdateNumberSpawnedObjects(StringHash eventType, VariantMap& eventData)
{
    LineEdit@ edit = eventData["Element"].GetPtr();
    numberSpawnedObjects=edit.text.ToFloat();
    edit.text=String(numberSpawnedObjects);
    RefreshPickedObjects();
}

void EditSpawnRadius(StringHash eventType, VariantMap& eventData)
{
    LineEdit@ edit = eventData["Element"].GetPtr();
    spawnRadius=edit.text.ToFloat();
}
void EditSpawnCount(StringHash eventType, VariantMap& eventData)
{
    LineEdit@ edit = eventData["Element"].GetPtr();
    spawnCount=edit.text.ToFloat();
}

void RefreshPickedObjects()
{
    spawnedObjectsNames.Resize(numberSpawnedObjects);
    ListView@ list = spawnWindow.GetChild("SpawnedObjects", true);
    list.RemoveAllItems();

    for (uint i = 0; i < numberSpawnedObjects; ++i)
    {
        UIElement@ parent = CreateAttributeEditorParentWithSeparatedLabel(list, "Object " +(i+1), i, 0, false);

        UIElement@ container = UIElement();
        container.SetLayout(LM_HORIZONTAL, 4, IntRect(10, 0, 4, 0));
        container.SetFixedHeight(ATTR_HEIGHT);
        parent.AddChild(container);

        LineEdit@ nameEdit = CreateAttributeLineEdit(container, null, i, 0);
        nameEdit.name = "TextureNameEdit" + String(i);

        Button@ pickButton = CreateResourcePickerButton(container, null, i, 0, "Pick");
        SubscribeToEvent(pickButton, "Released", "PickSpawnedObject");
        nameEdit.text = spawnedObjectsNames[i];

        SubscribeToEvent(nameEdit, "TextFinished", "EditSpawnedObjectName");
    }
}

void EditSpawnedObjectName(StringHash eventType, VariantMap& eventData)
{
    LineEdit@ nameEdit = eventData["Element"].GetPtr();
    int index = nameEdit.vars["Index"].GetUInt();
    String resourceName = nameEdit.text;
    XMLFile@ xml = cache.GetResource("XMLFile", resourceName);
    if(xml !is null)
        spawnedObjectsNames[index]=resourceName;
    else
        spawnedObjectsNames[index]=String("");
    RefreshPickedObjects();
}

void PickSpawnedObject(StringHash eventType, VariantMap& eventData)
{
    UIElement@ button = eventData["Element"].GetPtr();
    resourcePickIndex = button.vars["Index"].GetUInt();
    CreateFileSelector("Pick spawned object", "Pick", "Cancel", uiNodePath, uiSceneFilters, uiNodeFilter);

    SubscribeToEvent(uiFileSelector, "FileSelected", "PickSpawnedObjectNameDone");
}

void PickSpawnedObjectNameDone(StringHash eventType, VariantMap& eventData)
{
    StoreResourcePickerPath();
    CloseFileSelector();

    if (!eventData["OK"].GetBool())
    {
        @resourcePicker = null;
        return;
    }

    String resourceName = GetResourceNameFromFullName(eventData["FileName"].GetString());
    XMLFile@ xml = cache.GetResource("XMLFile", resourceName);
    if(xml !is null)
        spawnedObjectsNames[resourcePickIndex]=resourceName;
    else
        spawnedObjectsNames[resourcePickIndex]=String("");
    @resourcePicker = null;
    RefreshPickedObjects();
}

void SetSpawnMode(StringHash eventType, VariantMap& eventData)
{
    editMode=EDIT_SPAWN;
}

void PlaceObject(Vector3 spawnPosition, Vector3 normal)
{
    Quaternion spawnRotation;
    if(useNormal)spawnRotation=Quaternion(Vector3(0.f,1.f,0.f),normal);
    int number=RandomInt(0,spawnedObjectsNames.length);
    XMLFile@ xml = cache.GetResource("XMLFile", spawnedObjectsNames[number]);
    Node@ spawnedObject =editorScene.InstantiateXML(xml, spawnPosition, spawnRotation);
    if(spawnedObject is null)
    {
        spawnedObjectsNames[number]=spawnedObjectsNames[spawnedObjectsNames.length-1];
        --numberSpawnedObjects;
        RefreshPickedObjects();
        return;
    }

    spawnedObject.scale=spawnedObject.scale*Random(randomScaleMin, randomScaleMax);
    spawnedObject.Rotate(Quaternion(Random(-randomRotation.x,randomRotation.x),
    Random(-randomRotation.y,randomRotation.y),Random(-randomRotation.z,randomRotation.z)),false);
    CreateNodeAction action;
    action.Define(spawnedObject);
    SaveEditAction(action);
    SetSceneModified();
}

Vector3 RandomizeSpawnPosition(const Vector3&in position)
{
    float angle = Random() * 360.0;
    float distance = Random() * spawnRadius;
    return position + Quaternion(0, angle, 0) * Vector3(0, 0, distance);
}

void SpawnObject()
{
    if(spawnedObjectsNames.length==0) return;
    IntRect view = activeViewport.viewport.rect;

    for(int i=0;i<spawnCount;i++)
    {
        IntVector2 pos = IntVector2(ui.cursorPosition.x,ui.cursorPosition.y);
        Ray cameraRay = camera.GetScreenRay(
            float(pos.x - view.left) / view.width,
            float(pos.y - view.top) / view.height);

        if (pickMode < PICK_RIGIDBODIES)
        {
            if (editorScene.octree is null)
                return;

            RayQueryResult result = editorScene.octree.RaycastSingle(cameraRay, RAY_TRIANGLE, camera.farClip,
                pickModeDrawableFlags[pickMode], 0x7fffffff);

            // Randomize in a circle around original hit position
            if (spawnRadius > 0)
            {
                Vector3 position = RandomizeSpawnPosition(result.position);
                position.y += spawnRadius;
                result = editorScene.octree.RaycastSingle(Ray(position, Vector3(0, -1, 0)), RAY_TRIANGLE, spawnRadius * 2.0,
                    pickModeDrawableFlags[pickMode], 0x7fffffff);
            }

            if (result.drawable !is null)
                PlaceObject(result.position, result.normal);
        }
        else
        {
            if (editorScene.physicsWorld is null)
                return;

            // If we are not running the actual physics update, refresh collisions before raycasting
            if (!runUpdate)
                editorScene.physicsWorld.UpdateCollisions();

            PhysicsRaycastResult result = editorScene.physicsWorld.RaycastSingle(cameraRay, camera.farClip);

            // Randomize in a circle around original hit position
            if (spawnRadius > 0)
            {
                Vector3 position = RandomizeSpawnPosition(result.position);
                position.y += spawnRadius;
                result = editorScene.physicsWorld.RaycastSingle(Ray(position, Vector3(0, -1, 0)), spawnRadius * 2.0);
            }

            if (result.body !is null)
                PlaceObject(result.position, result.normal);
        }
    }
}

Use spawnRadius parameter in world space.


package aerys.minko.type.clone
{
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.AnimationController;
	import aerys.minko.scene.controller.camera.CameraController;
	import aerys.minko.scene.controller.mesh.MeshVisibilityController;
	import aerys.minko.scene.controller.mesh.SkinningController;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.type.binding.DataProvider;
	import aerys.minko.type.binding.IDataProvider;
	import aerys.minko.type.enum.DataProviderUsage;

	public class CloneOptions
	{
		private var _clonedControllerTypes		: Vector.<Class>	= new <Class>[];
		private var _ignoredControllerTypes		: Vector.<Class>	= new <Class>[];
		private var _reassignedControllerTypes	: Vector.<Class>	= new <Class>[];
		private var _defaultControllerAction	: uint				= ControllerCloneAction.REASSIGN;

		public function get defaultControllerAction() : uint
		{
			return _defaultControllerAction;
		}
		public function set defaultControllerAction(v : uint) : void
		{
			if (v != ControllerCloneAction.CLONE
				&& v != ControllerCloneAction.IGNORE
				&& v != ControllerCloneAction.REASSIGN)
				throw new Error('Unknown action type.');

			_defaultControllerAction = v;
		}

		public function CloneOptions()
		{
		}

		public static function get defaultCloneOptions() : CloneOptions
		{
			var cloneOptions : CloneOptions = new CloneOptions();

			cloneOptions._clonedControllerTypes.push(AnimationController, SkinningController);
			cloneOptions._ignoredControllerTypes.push(MeshVisibilityController, CameraController);
			cloneOptions._defaultControllerAction = ControllerCloneAction.REASSIGN;

			return cloneOptions;
		}

		public static function get cloneAllOptions() : CloneOptions
		{
			var cloneOptions : CloneOptions = new CloneOptions();

			cloneOptions._ignoredControllerTypes.push(MeshVisibilityController, CameraController);
			cloneOptions._defaultControllerAction = ControllerCloneAction.REASSIGN;

			return cloneOptions;
		}

		public function addControllerAction(controllerClass : Class, action : uint) : void
		{
			switch (action)
			{
				case ControllerCloneAction.CLONE:
					_clonedControllerTypes.push(controllerClass);
					break;

				case ControllerCloneAction.IGNORE:
					_ignoredControllerTypes.push(controllerClass);
					break;

				case ControllerCloneAction.REASSIGN:
					_reassignedControllerTypes.push(controllerClass);
					break;

				default:
					throw new Error('Unknown action type.');
			}
		}

		public function removeControllerAction(controllerClass : Class) : void
		{
			throw new Error('Implement me.');
		}

		public function getActionForController(controller : AbstractController) : uint
		{
			var numControllersToClone		: uint = _clonedControllerTypes.length;
			var numControllersToIgnore		: uint = _ignoredControllerTypes.length;
			var numControllersToReassign	: uint = _reassignedControllerTypes.length;
			var controllerId				: uint;

			for (controllerId = 0; controllerId < numControllersToClone; ++controllerId)
				if (controller is _clonedControllerTypes[controllerId])
					return ControllerCloneAction.CLONE;

			for (controllerId = 0; controllerId < numControllersToIgnore; ++controllerId)
				if (controller is _ignoredControllerTypes[controllerId])
					return ControllerCloneAction.IGNORE;

			for (controllerId = 0; controllerId < numControllersToReassign; ++controllerId)
				if (controller is _reassignedControllerTypes[controllerId])
					return ControllerCloneAction.REASSIGN;

			return _defaultControllerAction;
		}

	}
}

package aerys.minko.type.clone
{
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.AnimationController;
	import aerys.minko.scene.controller.camera.CameraController;
	import aerys.minko.scene.controller.mesh.MeshVisibilityController;
	import aerys.minko.scene.controller.mesh.SkinningController;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.type.binding.DataProvider;
	import aerys.minko.type.binding.IDataProvider;
	import aerys.minko.type.enum.DataProviderUsage;

	public class CloneOptions
	{
		private var _clonedControllerTypes		: Vector.<Class>	= new <Class>[];
		private var _ignoredControllerTypes		: Vector.<Class>	= new <Class>[];
		private var _reassignedControllerTypes	: Vector.<Class>	= new <Class>[];
		private var _defaultControllerAction	: uint				= ControllerCloneAction.REASSIGN;

		public function get defaultControllerAction() : uint
		{
			return _defaultControllerAction;
		}
		public function set defaultControllerAction(v : uint) : void
		{
			if (v != ControllerCloneAction.CLONE
				&& v != ControllerCloneAction.IGNORE
				&& v != ControllerCloneAction.REASSIGN)
				throw new Error('Unknown action type.');

			_defaultControllerAction = v;
		}

		public function CloneOptions()
		{
		}

		public static function get defaultCloneOptions() : CloneOptions
		{
			var cloneOptions : CloneOptions = new CloneOptions();

			cloneOptions._clonedControllerTypes.push(AnimationController, SkinningController);
			cloneOptions._ignoredControllerTypes.push(MeshVisibilityController, CameraController);
			cloneOptions._defaultControllerAction = ControllerCloneAction.REASSIGN;

			return cloneOptions;
		}

		public static function get cloneAllOptions() : CloneOptions
		{
			var cloneOptions : CloneOptions = new CloneOptions();

			cloneOptions._ignoredControllerTypes.push(MeshVisibilityController, CameraController);
			cloneOptions._defaultControllerAction = ControllerCloneAction.CLONE;

			return cloneOptions;
		}

		public function addControllerAction(controllerClass : Class, action : uint) : void
		{
			switch (action)
			{
				case ControllerCloneAction.CLONE:
					_clonedControllerTypes.push(controllerClass);
					break;

				case ControllerCloneAction.IGNORE:
					_ignoredControllerTypes.push(controllerClass);
					break;

				case ControllerCloneAction.REASSIGN:
					_reassignedControllerTypes.push(controllerClass);
					break;

				default:
					throw new Error('Unknown action type.');
			}
		}

		public function removeControllerAction(controllerClass : Class) : void
		{
			throw new Error('Implement me.');
		}

		public function getActionForController(controller : AbstractController) : uint
		{
			var numControllersToClone		: uint = _clonedControllerTypes.length;
			var numControllersToIgnore		: uint = _ignoredControllerTypes.length;
			var numControllersToReassign	: uint = _reassignedControllerTypes.length;
			var controllerId				: uint;

			for (controllerId = 0; controllerId < numControllersToClone; ++controllerId)
				if (controller is _clonedControllerTypes[controllerId])
					return ControllerCloneAction.CLONE;

			for (controllerId = 0; controllerId < numControllersToIgnore; ++controllerId)
				if (controller is _ignoredControllerTypes[controllerId])
					return ControllerCloneAction.IGNORE;

			for (controllerId = 0; controllerId < numControllersToReassign; ++controllerId)
				if (controller is _reassignedControllerTypes[controllerId])
					return ControllerCloneAction.REASSIGN;

			return _defaultControllerAction;
		}

	}
}

Fix minor bug on CloneOptions

Fix minor bug on CloneOptions


//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.util {

import flash.errors.IllegalOperationError;

import flash.events.Event;
import flash.events.IEventDispatcher;

public class CommandEvent extends Event
{
    /** The event type for all controller events. */
    public static const COMMAND :String = "commandEvt";

    /**
     * Use this method to dispatch CommandEvents.
     */
    public static function dispatch (
            disp :IEventDispatcher, cmdOrFn :Object, arg :Object = null) :void
    {
        if (cmdOrFn is Function) {
            var fn :Function = (cmdOrFn as Function);
            // build our args array
            var args :Array;
            if (arg is Array) {
                // if we were passed an array, treat it as the arg array.
                // Note: if you want to pass a single array param, you've
                // got to wrap it in another array, so sorry.
                args = arg as Array;

            } else {
                args = [ arg ];
            }
            try {
                fn.apply(null, args);
            } catch (err :Error) {
                if (arg == null) {
                    try {
                        // try with no args
                        fn();
                        err = null; // on success, clear the error
                    } catch (err2 :Error) {
                        err = err2;
                    }
                }
                if (err != null) {
                    var log :Log = Log.getLog(CommandEvent);
                    log.warning("Unable to call command callback, stack trace follows.");
                    log.logStackTrace(err);
                }
            }

        } else if (cmdOrFn is String) {
            var cmd :String = String(cmdOrFn);
            // Create the event to dispatch
            var event :CommandEvent = create(cmd, arg);

            // Dispatch it. A return value of true means that the event was
            // never cancelled, so we complain.
            if (disp == null || disp.dispatchEvent(event)) {
                Log.getLog(CommandEvent).warning("Unhandled controller command " +
                    "[cmd=" + cmd + ", arg=" + arg + "].");
            }

        } else {
            throw new ArgumentError("Argument 'cmdOrFn' must be a command (String) or a Function");
        }
    }

    /** The command. */
    public var command :String;

    /** An optional argument. */
    public var arg :Object;

    /**
     * Command events may not be directly constructed, use the dispatch
     * method to do your work.
     */
    public function CommandEvent (command :String, arg :Object)
    {
        super(COMMAND, true, true);
        if (_blockConstructor) {
            throw new IllegalOperationError();
        }
        this.command = command;
        this.arg = arg;
    }

    /**
     * Mark this command as handled, stopping its propagation up the
     * hierarchy.
     */
    public function markAsHandled () :void
    {
        preventDefault();
        stopImmediatePropagation();
    }

    override public function clone () :Event
    {
        return create(command, arg);
    }

    override public function toString () :String
    {
        return "CommandEvent[" + command + " (" + arg + ")]";
    }

    /**
     * A factory method for privately creating command events.
     */
    protected static function create (cmd :String, arg :Object) :CommandEvent
    {
        var event :CommandEvent;
        _blockConstructor = false;
        try {
            event = new CommandEvent(cmd, arg);
        } finally {
            _blockConstructor = true;
        }
        return event;
    }

    /** Used to prevent unauthorized construction. */
    protected static var _blockConstructor :Boolean = true;
}
}

//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.util {

import flash.errors.IllegalOperationError;

import flash.events.Event;
import flash.events.IEventDispatcher;

public class CommandEvent extends Event
{
    /** The event type for all controller events. */
    public static const COMMAND :String = "commandEvt";

    /**
     * Use this method to dispatch CommandEvents.
     */
    public static function dispatch (
            disp :IEventDispatcher, cmdOrFn :Object, arg :Object = null) :void
    {
        if (cmdOrFn is Function) {
            var fn :Function = (cmdOrFn as Function);
            // build our args array
            var args :Array;
            if (arg is Array) {
                // if we were passed an array, treat it as the arg array.
                // Note: if you want to pass a single array param, you've
                // got to wrap it in another array, so sorry.
                args = arg as Array;

            } else {
                args = [ arg ];
            }
            try {
                fn.apply(null, args);
            } catch (err :Error) {
                if (arg == null) {
                    try {
                        // try with no args
                        fn();
                        err = null; // on success, clear the error
                    } catch (err2 :Error) {
                        err = err2;
                    }
                }
                if (err != null) {
                    var log :Log = Log.getLog(CommandEvent);
                    log.warning("Unable to call command callback, stack trace follows.");
                    log.logStackTrace(err);
                }
            }

        } else if (cmdOrFn is String) {
            var cmd :String = String(cmdOrFn);
            // Create the event to dispatch
            var event :CommandEvent = create(cmd, arg);

            // Dispatch it. A return value of true means that the event was
            // never cancelled, so we complain.
            if (disp == null || disp.dispatchEvent(event)) {
                Log.getLog(CommandEvent).warning("Unhandled controller command " +
                    "[cmd=" + cmd + ", arg=" + arg + ", disp=" + disp + "].");
            }

        } else {
            throw new ArgumentError("Argument 'cmdOrFn' must be a command (String) or a Function");
        }
    }

    /** The command. */
    public var command :String;

    /** An optional argument. */
    public var arg :Object;

    /**
     * Command events may not be directly constructed, use the dispatch
     * method to do your work.
     */
    public function CommandEvent (command :String, arg :Object)
    {
        super(COMMAND, true, true);
        if (_blockConstructor) {
            throw new IllegalOperationError();
        }
        this.command = command;
        this.arg = arg;
    }

    /**
     * Mark this command as handled, stopping its propagation up the
     * hierarchy.
     */
    public function markAsHandled () :void
    {
        preventDefault();
        stopImmediatePropagation();
    }

    override public function clone () :Event
    {
        return create(command, arg);
    }

    override public function toString () :String
    {
        return "CommandEvent[" + command + " (" + arg + ")]";
    }

    /**
     * A factory method for privately creating command events.
     */
    protected static function create (cmd :String, arg :Object) :CommandEvent
    {
        var event :CommandEvent;
        _blockConstructor = false;
        try {
            event = new CommandEvent(cmd, arg);
        } finally {
            _blockConstructor = true;
        }
        return event;
    }

    /** Used to prevent unauthorized construction. */
    protected static var _blockConstructor :Boolean = true;
}
}

Include the dispatcher here so we know if it was null or unresponsive.

git-svn-id: a1a4b28b82a3276cc491891159dd9963a0a72fae@5102 542714f4-19e9-0310-aa3c-eee0fc999fb1


////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2008-2013 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 com.esri.builder.views
{

import com.esri.builder.views.popups.HelpPopUp;

import flash.events.MouseEvent;
import flash.geom.Rectangle;

import mx.core.FlexGlobals;
import mx.core.LayoutDirection;
import mx.core.UIComponent;
import mx.managers.PopUpManager;

import spark.components.supportClasses.ButtonBase;

[Exclude(kind="property", name="toolTip")]
public class HelpButton extends ButtonBase
{
    [Bindable]
    public var title:String;
    [Bindable]
    public var helpText:String;

    private var helpPopUp:HelpPopUp;

    public function HelpButton()
    {
        addEventListener(MouseEvent.ROLL_OVER, rollOverHandler, false, 0, true);
        addEventListener(MouseEvent.ROLL_OUT, rollOutHandler, false, 0, true);
    }

    protected function rollOverHandler(event:MouseEvent):void
    {
        if (!helpPopUp)
        {
            helpPopUp = createHelpPopUp();
            PopUpManager.addPopUp(helpPopUp, this);
            positionHelpPopUp(this, helpPopUp);
        }
    }

    private function createHelpPopUp():HelpPopUp
    {
        helpPopUp = new HelpPopUp();
        helpPopUp.title = title;
        helpPopUp.content = helpText;
        return helpPopUp;
    }

    private function positionHelpPopUp(button:UIComponent, popUp:UIComponent):void
    {
        var app:UIComponent = FlexGlobals.topLevelApplication as UIComponent;
        var appBounds:Rectangle = app.getVisibleRect();
        var buttonRect:Rectangle = button.getBounds(app);
        var popUpRect:Rectangle = new Rectangle(buttonRect.x, buttonRect.y, popUp.width, popUp.height);

        var isLTR:Boolean = (layoutDirection == LayoutDirection.LTR);
        var leftOffset:Number = isLTR ? -popUpRect.width - anchorHalfWidth : buttonRect.width + anchorHalfWidth;
        var rightOffset:Number = isLTR ? buttonRect.width + anchorHalfWidth : -popUpRect.width - anchorHalfWidth;

        var leftPopUpRect:Rectangle = popUpRect.clone();
        var rightPopUpRect:Rectangle = popUpRect.clone();
        var bottomPopUpRect:Rectangle = popUpRect.clone();
        var topPopUpRect:Rectangle = popUpRect.clone();

        leftPopUpRect.x += leftOffset;
        rightPopUpRect.x += rightOffset;
        bottomPopUpRect.y += buttonRect.height;
        topPopUpRect.y += -popUpRect.height;

        var leftIntersectionRect:Rectangle = appBounds.intersection(leftPopUpRect);
        var rightIntersectionRect:Rectangle = appBounds.intersection(rightPopUpRect);
        var bottomIntersectionRect:Rectangle = appBounds.intersection(bottomPopUpRect);
        var topIntersectionRect:Rectangle = appBounds.intersection(topPopUpRect);

        var horizontalPosition:String;

        if (isLTR)
        {
            if (leftIntersectionRect.width > rightIntersectionRect.width)
            {
                popUp.x = leftPopUpRect.x;
                horizontalPosition = "LEFT";
            }
            else
            {
                popUp.x = rightPopUpRect.x;
                horizontalPosition = "RIGHT";
            }
        }
        else
        {
            if (leftIntersectionRect.width < rightIntersectionRect.width)
            {
                popUp.x = app.width - rightPopUpRect.x - rightPopUpRect.width;
                horizontalPosition = "LEFT";
            }
            else
            {
                popUp.x = app.width - leftPopUpRect.x - leftPopUpRect.width;
                horizontalPosition = "RIGHT";
            }
        }

        var verticalPosition:String;

        if (Math.round(topIntersectionRect.height) > Math.round(bottomIntersectionRect.height))
        {
            popUp.y = topPopUpRect.y;
            verticalPosition = "TOP";
        }
        else if (Math.round(topIntersectionRect.height) < Math.round(bottomIntersectionRect.height))
        {
            popUp.y = bottomPopUpRect.y;
            verticalPosition = "BOTTOM";
        }
        else
        {
            popUp.y = buttonRect.y + (buttonRect.height - popUpRect.height) * 0.5;
            verticalPosition = "MIDDLE";
        }

        var popUpPosition:String = verticalPosition + "_" + horizontalPosition;
        positionHelpPopUpAnchor(popUpPosition);
    }

    public function get anchorHalfWidth():Number
    {
        return helpPopUp.anchor.width;
    }

    private function positionHelpPopUpAnchor(popUpPosition:String):void
    {
        //we assume help pop-up anchor points to the right: <
        switch (popUpPosition)
        {
            case "MIDDLE_RIGHT":
            {
                helpPopUp.anchor.left = -anchorHalfWidth;
                helpPopUp.anchor.verticalCenter = 0;
                break;
            }
            case "MIDDLE_LEFT":
            {
                helpPopUp.anchor.right = -anchorHalfWidth;
                helpPopUp.anchor.rotation = 180;
                helpPopUp.anchor.verticalCenter = 0;
                break;
            }
            case "TOP_RIGHT":
            {
                helpPopUp.anchor.left = -anchorHalfWidth;
                helpPopUp.anchor.bottom = -anchorHalfWidth;
                helpPopUp.anchor.scaleX = 2.5;
                helpPopUp.anchor.rotation = -45;
                break;
            }
            case "TOP_LEFT":
            {
                helpPopUp.anchor.right = -anchorHalfWidth;
                helpPopUp.anchor.bottom = -anchorHalfWidth;
                helpPopUp.anchor.scaleX = 2.5;
                helpPopUp.anchor.rotation = -135;
                break;
            }
            case "BOTTOM_RIGHT":
            {
                helpPopUp.anchor.top = -anchorHalfWidth;
                helpPopUp.anchor.left = -anchorHalfWidth;
                helpPopUp.anchor.scaleX = 2.5;
                helpPopUp.anchor.rotation = 45;
                break;
            }
            case "BOTTOM_LEFT":
            {
                helpPopUp.anchor.top = -anchorHalfWidth;
                helpPopUp.anchor.right = -anchorHalfWidth;
                helpPopUp.anchor.scaleX = 2.5;
                helpPopUp.anchor.rotation = 135;
                break;
            }
        }
    }

    protected function rollOutHandler(event:MouseEvent):void
    {
        if (helpPopUp)
        {
            PopUpManager.removePopUp(helpPopUp);
            helpPopUp = null;
        }
    }
}
}

////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2008-2013 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 com.esri.builder.views
{

import com.esri.builder.views.popups.HelpPopUp;

import flash.events.MouseEvent;
import flash.geom.Rectangle;

import mx.core.FlexGlobals;
import mx.core.LayoutDirection;
import mx.core.UIComponent;
import mx.managers.PopUpManager;

import spark.components.supportClasses.ButtonBase;

[Exclude(kind="property", name="toolTip")]
public class HelpButton extends ButtonBase
{
    [Bindable]
    public var title:String;
    [Bindable]
    public var helpText:String;

    private var helpPopUp:HelpPopUp;

    public function HelpButton()
    {
        addEventListener(MouseEvent.ROLL_OVER, rollOverHandler, false, 0, true);
        addEventListener(MouseEvent.ROLL_OUT, rollOutHandler, false, 0, true);
    }

    protected function rollOverHandler(event:MouseEvent):void
    {
        if (!helpPopUp)
        {
            helpPopUp = createHelpPopUp();
            PopUpManager.addPopUp(helpPopUp, this);
            positionHelpPopUp(this, helpPopUp);
        }
    }

    private function createHelpPopUp():HelpPopUp
    {
        helpPopUp = new HelpPopUp();
        helpPopUp.title = title;
        helpPopUp.content = helpText;
        return helpPopUp;
    }

    private function positionHelpPopUp(button:UIComponent, popUp:UIComponent):void
    {
        var app:UIComponent = FlexGlobals.topLevelApplication as UIComponent;
        var appBounds:Rectangle = app.getVisibleRect();
        var buttonRect:Rectangle = button.getBounds(app);
        var popUpRect:Rectangle = new Rectangle(buttonRect.x, buttonRect.y, popUp.width, popUp.height);

        var isLTR:Boolean = (layoutDirection == LayoutDirection.LTR);
        var anchorWidth:Number = helpPopUp.anchor.width;
        var leftOffset:Number = isLTR ? -popUpRect.width - anchorWidth : buttonRect.width + anchorWidth;
        var rightOffset:Number = isLTR ? buttonRect.width + anchorWidth : -popUpRect.width - anchorWidth;

        var leftPopUpRect:Rectangle = popUpRect.clone();
        var rightPopUpRect:Rectangle = popUpRect.clone();
        var bottomPopUpRect:Rectangle = popUpRect.clone();
        var topPopUpRect:Rectangle = popUpRect.clone();

        leftPopUpRect.x += leftOffset;
        rightPopUpRect.x += rightOffset;
        bottomPopUpRect.y += buttonRect.height;
        topPopUpRect.y += -popUpRect.height;

        var leftIntersectionRect:Rectangle = appBounds.intersection(leftPopUpRect);
        var rightIntersectionRect:Rectangle = appBounds.intersection(rightPopUpRect);
        var bottomIntersectionRect:Rectangle = appBounds.intersection(bottomPopUpRect);
        var topIntersectionRect:Rectangle = appBounds.intersection(topPopUpRect);

        var horizontalPosition:String;

        if (isLTR)
        {
            if (leftIntersectionRect.width > rightIntersectionRect.width)
            {
                popUp.x = leftPopUpRect.x;
                horizontalPosition = "LEFT";
            }
            else
            {
                popUp.x = rightPopUpRect.x;
                horizontalPosition = "RIGHT";
            }
        }
        else
        {
            if (leftIntersectionRect.width < rightIntersectionRect.width)
            {
                popUp.x = app.width - rightPopUpRect.x - rightPopUpRect.width;
                horizontalPosition = "LEFT";
            }
            else
            {
                popUp.x = app.width - leftPopUpRect.x - leftPopUpRect.width;
                horizontalPosition = "RIGHT";
            }
        }

        var verticalPosition:String;

        if (Math.round(topIntersectionRect.height) > Math.round(bottomIntersectionRect.height))
        {
            popUp.y = topPopUpRect.y;
            verticalPosition = "TOP";
        }
        else if (Math.round(topIntersectionRect.height) < Math.round(bottomIntersectionRect.height))
        {
            popUp.y = bottomPopUpRect.y;
            verticalPosition = "BOTTOM";
        }
        else
        {
            popUp.y = buttonRect.y + (buttonRect.height - popUpRect.height) * 0.5;
            verticalPosition = "MIDDLE";
        }

        var popUpPosition:String = verticalPosition + "_" + horizontalPosition;
        positionHelpPopUpAnchor(popUpPosition);
    }

    private function positionHelpPopUpAnchor(popUpPosition:String):void
    {
        var anchorWidth:Number = helpPopUp.anchor.width;
        //we assume help pop-up anchor points to the right: <
        switch (popUpPosition)
        {
            case "MIDDLE_RIGHT":
            {
                helpPopUp.anchor.left = -anchorWidth;
                helpPopUp.anchor.verticalCenter = 0;
                break;
            }
            case "MIDDLE_LEFT":
            {
                helpPopUp.anchor.right = -anchorWidth;
                helpPopUp.anchor.rotation = 180;
                helpPopUp.anchor.verticalCenter = 0;
                break;
            }
            case "TOP_RIGHT":
            {
                helpPopUp.anchor.left = -anchorWidth;
                helpPopUp.anchor.bottom = -anchorWidth;
                helpPopUp.anchor.scaleX = 2.5;
                helpPopUp.anchor.rotation = -45;
                break;
            }
            case "TOP_LEFT":
            {
                helpPopUp.anchor.right = -anchorWidth;
                helpPopUp.anchor.bottom = -anchorWidth;
                helpPopUp.anchor.scaleX = 2.5;
                helpPopUp.anchor.rotation = -135;
                break;
            }
            case "BOTTOM_RIGHT":
            {
                helpPopUp.anchor.top = -anchorWidth;
                helpPopUp.anchor.left = -anchorWidth;
                helpPopUp.anchor.scaleX = 2.5;
                helpPopUp.anchor.rotation = 45;
                break;
            }
            case "BOTTOM_LEFT":
            {
                helpPopUp.anchor.top = -anchorWidth;
                helpPopUp.anchor.right = -anchorWidth;
                helpPopUp.anchor.scaleX = 2.5;
                helpPopUp.anchor.rotation = 135;
                break;
            }
        }
    }

    protected function rollOutHandler(event:MouseEvent):void
    {
        if (helpPopUp)
        {
            PopUpManager.removePopUp(helpPopUp);
            helpPopUp = null;
        }
    }
}
}

Clean up.

Clean up.


// makeswf -v 7 -r 1 -o global-variable-properties-7.swf global-variable-properties.as

#include "trace_properties.as"

trace_properties (_global.Infinity, "_global", "Infinity");
trace_properties (_global.NaN, "_global", "NaN");
trace_properties (_global.o, "_global", "o");
// _global.flash is undefined, so we need to check extra
//trace (hasOwnProperty (_global, "flash"));
//trace_properties (_global.flash, "_global", "flash");

loadMovie ("FSCommand:quit", "");

// makeswf -v 7 -r 1 -o global-variable-properties-7.swf global-variable-properties.as

#include "trace_properties.as"

trace_properties (_global.Infinity, "_global", "Infinity");
trace_properties (_global.NaN, "_global", "NaN");
trace_properties (_global.o, "_global", "o");
// Need to unhide it first on version < 8
//ASSetPropFlags (_global, "flash", 0, 5248);
//trace_properties (_global.flash, "_global", "flash");

loadMovie ("FSCommand:quit", "");

Update comment that was wrong in global-variable-properties.as


package aerys.minko.render.material.basic
{
	import aerys.minko.render.RenderTarget;
	import aerys.minko.render.shader.SFloat;
	import aerys.minko.render.shader.Shader;
	import aerys.minko.render.shader.ShaderSettings;
	import aerys.minko.render.shader.part.DiffuseShaderPart;
	import aerys.minko.render.shader.part.animation.VertexAnimationShaderPart;
	import aerys.minko.type.enum.Blending;
	import aerys.minko.type.enum.BlendingSource;
	import aerys.minko.type.enum.DepthTest;
	import aerys.minko.type.enum.StencilAction;
	import aerys.minko.type.enum.TriangleCulling;

	/**
	 * The BasicShader is a simple shader program handling hardware vertex
	 * animations (skinning and morphing), a diffuse color or a texture and
	 * a directional light.
	 *
	 *

	 *

	 * 	Property Name
	 * 	Source
	 * 	Type
	 * 	Description
	 * 	Requires
	 *

	 *

	 * 	lightEnabled
	 * 	Scene
	 * 	Boolean
	 * 	Whether the light is enabled or not on the scene.
	 * 	lightDirection, lightAmbient, lightAmbientColor, lightDiffuse, lightDiffuseColor
	 *

	 *

	 * 	lightDirection
	 * 	Scene
	 * 	Vector4
	 * 	The direction of the light.
	 *
	 *

	 *

	 * 	lightAmbient
	 * 	Scene
	 * 	Number
	 * 	The ambient factor of the light.
	 *
	 *

	 *

	 * 	lightAmbientColor
	 * 	Scene
	 * 	uint or Vector4
	 * 	The ambient color of the light.
	 *
	 *

	 *

	 * 	lightDiffuse
	 * 	Scene
	 * 	Number
	 * 	The diffuse factor of the light
	 *
	 *

	 *

	 * 	lightDiffuseColor
	 * 	Scene
	 * 	uint or Vector4
	 * 	The diffuse color of the light.
	 *
	 *

	 *

	 * 	lightEnabled
	 * 	Mesh
	 * 	Boolean
	 * 	Whether the light is enabled or not on the mesh.
	 *
	 *

	 *

	 * 	diffuseMap
	 * 	Mesh
	 * 	TextureResource
	 * 	The texture to use for rendering.
	 *
	 *

	 *

	 * 	diffuseColor
	 * 	Mesh
	 * 	uint or Vector4
	 * 	The color to use for rendering. If the "diffuseMap" binding is set, this
	 * 	value is not used.
	 *
	 *

	 *

	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class BasicShader extends Shader
	{
		private var _vertexAnimationPart	: VertexAnimationShaderPart;
		private var _diffuseShaderPart		: DiffuseShaderPart;

		protected function get diffuse() : DiffuseShaderPart
		{
			return _diffuseShaderPart;
		}

		protected function get vertexAnimation() : VertexAnimationShaderPart
		{
			return _vertexAnimationPart;
		}

		/**
		 * @param priority Default value is 0.
		 * @param target Default value is null.
		 */
		public function BasicShader(target		: RenderTarget	= null,
									priority	: Number		= 0.)
		{
			super(target, priority);

			// init shader parts
			_vertexAnimationPart	= new VertexAnimationShaderPart(this);
			_diffuseShaderPart		= new DiffuseShaderPart(this);
		}

		override protected function initializeSettings(settings : ShaderSettings) : void
		{
			super.initializeSettings(settings);

			// depth test
			settings.depthWriteEnabled = meshBindings.getProperty(
				BasicProperties.DEPTH_WRITE_ENABLED, true
			);
			settings.depthTest = meshBindings.getProperty(
				BasicProperties.DEPTH_TEST, DepthTest.LESS
			);

			settings.triangleCulling = meshBindings.getProperty(
				BasicProperties.TRIANGLE_CULLING, TriangleCulling.BACK
			);

			// stencil operations
			settings.stencilTriangleFace = meshBindings.getProperty(
				BasicProperties.STENCIL_TRIANGLE_FACE, TriangleCulling.BOTH
			);
			settings.stencilCompareMode = meshBindings.getProperty(
				BasicProperties.STENCIL_COMPARE_MODE, DepthTest.EQUAL
			);
			settings.stencilActionOnBothPass = meshBindings.getProperty(
				BasicProperties.STENCIL_ACTION_BOTH_PASS, StencilAction.KEEP
			);
			settings.stencilActionOnDepthFail = meshBindings.getProperty(
				BasicProperties.STENCIL_ACTION_DEPTH_FAIL, StencilAction.KEEP
			);
			settings.stencilActionOnDepthPassStencilFail = meshBindings.getProperty(
				BasicProperties.STENCIL_ACTION_DEPTH_PASS_STENCIL_FAIL, StencilAction.KEEP
			);
			settings.stencilReferenceValue = meshBindings.getProperty(
				BasicProperties.STENCIL_REFERENCE_VALUE, 0
			);
			settings.stencilReadMask = meshBindings.getProperty(
				BasicProperties.STENCIL_READ_MASK, 255
			);
			settings.stencilWriteMask = meshBindings.getProperty(
				BasicProperties.STENCIL_WRITE_MASK, 255
			);

			// blending and priority
			var blending : uint = meshBindings.getProperty(
				BasicProperties.BLENDING, Blending.OPAQUE
			);

			if ((blending & 0xff) == BlendingSource.SOURCE_ALPHA)
			{
				settings.priority -= 0.5;
				settings.depthSortDrawCalls = true;
			}

			settings.blending			= blending;
			settings.enabled			= true;
			settings.scissorRectangle	= null;
		}

		/**
		 * @return The position of the vertex in clip space (normalized
		 * screen space).
		 *
		 */
		override protected function getVertexPosition() : SFloat
		{
			return localToScreen(
				_vertexAnimationPart.getAnimatedVertexPosition()
			);
		}

		/**
		 * @return The pixel color using a diffuse color/map and an optional
		 * directional light.
		 */
		override protected function getPixelColor() : SFloat
		{
			return _diffuseShaderPart.getDiffuseColor();
		}
	}
}

package aerys.minko.render.material.basic
{
	import aerys.minko.render.RenderTarget;
	import aerys.minko.render.shader.SFloat;
	import aerys.minko.render.shader.Shader;
	import aerys.minko.render.shader.ShaderSettings;
	import aerys.minko.render.shader.part.DiffuseShaderPart;
	import aerys.minko.render.shader.part.animation.VertexAnimationShaderPart;
	import aerys.minko.type.enum.Blending;
	import aerys.minko.type.enum.BlendingDestination;
	import aerys.minko.type.enum.BlendingSource;
	import aerys.minko.type.enum.DepthTest;
	import aerys.minko.type.enum.StencilAction;
	import aerys.minko.type.enum.TriangleCulling;

	/**
	 * The BasicShader is a simple shader program handling hardware vertex
	 * animations (skinning and morphing), a diffuse color or a texture and
	 * a directional light.
	 *
	 *

	 *

	 * 	Property Name
	 * 	Source
	 * 	Type
	 * 	Description
	 * 	Requires
	 *

	 *

	 * 	lightEnabled
	 * 	Scene
	 * 	Boolean
	 * 	Whether the light is enabled or not on the scene.
	 * 	lightDirection, lightAmbient, lightAmbientColor, lightDiffuse, lightDiffuseColor
	 *

	 *

	 * 	lightDirection
	 * 	Scene
	 * 	Vector4
	 * 	The direction of the light.
	 *
	 *

	 *

	 * 	lightAmbient
	 * 	Scene
	 * 	Number
	 * 	The ambient factor of the light.
	 *
	 *

	 *

	 * 	lightAmbientColor
	 * 	Scene
	 * 	uint or Vector4
	 * 	The ambient color of the light.
	 *
	 *

	 *

	 * 	lightDiffuse
	 * 	Scene
	 * 	Number
	 * 	The diffuse factor of the light
	 *
	 *

	 *

	 * 	lightDiffuseColor
	 * 	Scene
	 * 	uint or Vector4
	 * 	The diffuse color of the light.
	 *
	 *

	 *

	 * 	lightEnabled
	 * 	Mesh
	 * 	Boolean
	 * 	Whether the light is enabled or not on the mesh.
	 *
	 *

	 *

	 * 	diffuseMap
	 * 	Mesh
	 * 	TextureResource
	 * 	The texture to use for rendering.
	 *
	 *

	 *

	 * 	diffuseColor
	 * 	Mesh
	 * 	uint or Vector4
	 * 	The color to use for rendering. If the "diffuseMap" binding is set, this
	 * 	value is not used.
	 *
	 *

	 *

	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class BasicShader extends Shader
	{
		private var _vertexAnimationPart	: VertexAnimationShaderPart;
		private var _diffuseShaderPart		: DiffuseShaderPart;

		protected function get diffuse() : DiffuseShaderPart
		{
			return _diffuseShaderPart;
		}

		protected function get vertexAnimation() : VertexAnimationShaderPart
		{
			return _vertexAnimationPart;
		}

		/**
		 * @param priority Default value is 0.
		 * @param target Default value is null.
		 */
		public function BasicShader(target		: RenderTarget	= null,
									priority	: Number		= 0.)
		{
			super(target, priority);

			// init shader parts
			_vertexAnimationPart	= new VertexAnimationShaderPart(this);
			_diffuseShaderPart		= new DiffuseShaderPart(this);
		}

		override protected function initializeSettings(settings : ShaderSettings) : void
		{
			super.initializeSettings(settings);

			// depth test
			settings.depthWriteEnabled = meshBindings.getProperty(
				BasicProperties.DEPTH_WRITE_ENABLED, true
			);
			settings.depthTest = meshBindings.getProperty(
				BasicProperties.DEPTH_TEST, DepthTest.LESS
			);

			settings.triangleCulling = meshBindings.getProperty(
				BasicProperties.TRIANGLE_CULLING, TriangleCulling.BACK
			);

			// stencil operations
			settings.stencilTriangleFace = meshBindings.getProperty(
				BasicProperties.STENCIL_TRIANGLE_FACE, TriangleCulling.BOTH
			);
			settings.stencilCompareMode = meshBindings.getProperty(
				BasicProperties.STENCIL_COMPARE_MODE, DepthTest.EQUAL
			);
			settings.stencilActionOnBothPass = meshBindings.getProperty(
				BasicProperties.STENCIL_ACTION_BOTH_PASS, StencilAction.KEEP
			);
			settings.stencilActionOnDepthFail = meshBindings.getProperty(
				BasicProperties.STENCIL_ACTION_DEPTH_FAIL, StencilAction.KEEP
			);
			settings.stencilActionOnDepthPassStencilFail = meshBindings.getProperty(
				BasicProperties.STENCIL_ACTION_DEPTH_PASS_STENCIL_FAIL, StencilAction.KEEP
			);
			settings.stencilReferenceValue = meshBindings.getProperty(
				BasicProperties.STENCIL_REFERENCE_VALUE, 0
			);
			settings.stencilReadMask = meshBindings.getProperty(
				BasicProperties.STENCIL_READ_MASK, 255
			);
			settings.stencilWriteMask = meshBindings.getProperty(
				BasicProperties.STENCIL_WRITE_MASK, 255
			);

			// blending and priority
			var blending : uint = meshBindings.getProperty(
				BasicProperties.BLENDING, Blending.OPAQUE
			);

			if ((blending & 0xff0000) != BlendingDestination.ZERO)
			{
				settings.priority -= 0.5;
				settings.depthSortDrawCalls = true;
			}

			settings.blending			= blending;
			settings.enabled			= true;
			settings.scissorRectangle	= null;
		}

		/**
		 * @return The position of the vertex in clip space (normalized
		 * screen space).
		 *
		 */
		override protected function getVertexPosition() : SFloat
		{
			return localToScreen(
				_vertexAnimationPart.getAnimatedVertexPosition()
			);
		}

		/**
		 * @return The pixel color using a diffuse color/map and an optional
		 * directional light.
		 */
		override protected function getPixelColor() : SFloat
		{
			return _diffuseShaderPart.getDiffuseColor();
		}
	}
}

Fix auto depth sorting according to blending destination


//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.geom.Point;

import flump.SwfTexture;
import flump.mold.KeyframeMold;
import flump.mold.MovieMold;
import flump.xfl.XflLibrary;
import flump.xfl.XflTexture;

import com.threerings.util.Comparators;

public class Packer
{
    public const atlases :Vector.<Atlas> = new Vector.<Atlas>();

    public function Packer (lib :XflLibrary, scale :Number=1.0, prefix :String="", suffix :String="") {
        for each (var tex :XflTexture in lib.textures) {
            _unpacked.push(SwfTexture.fromTexture(lib.swf, tex, scale));
        }
        for each (var movie :MovieMold in lib.movies) {
            if (!movie.flipbook) continue;
            for each (var kf :KeyframeMold in movie.layers[0].keyframes) {
                _unpacked.push(SwfTexture.fromFlipbook(lib, movie, kf.index, scale));
            }
        }
        _unpacked.sort(Comparators.createReverse(Comparators.createFields(["a", "w", "h"])));
        while (_unpacked.length > 0) {
            // Add a new atlas
            const size :Point = findOptimalSize();
            atlases.push(new Atlas(prefix + "atlas" + atlases.length + suffix, size.x, size.y));

            // Try to pack each texture into any atlas
            for (var ii :int = 0; ii < _unpacked.length; ++ii) {
                var unpacked :SwfTexture = _unpacked[ii];

                if (unpacked.w > MAX_SIZE || unpacked.h > MAX_SIZE) {
                    throw new Error("Too large to fit in an atlas");
                }

                for each (var atlas :Atlas in atlases) {
                    // TODO(bruno): Support rotated textures?
                    if (atlas.place(unpacked)) {
                        _unpacked.splice(ii--, 1);
                        break;
                    }
                }
            }
        }
    }

    // Estimate the optimal size for the next atlas
    protected function findOptimalSize () :Point {
        var area :int = 0;
        var maxW :int = 0;
        var maxH :int = 0;

        for each (var tex :SwfTexture in _unpacked) {
            const w :int = tex.w + Atlas.PADDING;
            const h :int = tex.h + Atlas.PADDING;
            area += w * h;
            maxW = Math.max(maxW, w);
            maxH = Math.max(maxH, h);
        }

        const size :Point = new Point(nextPowerOfTwo(maxW), nextPowerOfTwo(maxH));

        // Double the area until it's big enough
        while (size.x * size.y < area) {
            if (size.x < size.y) size.x *= 2;
            else size.y *= 2;
        }

        size.x = Math.min(size.x, MAX_SIZE);
        size.y = Math.min(size.y, MAX_SIZE);

        return size;
    }

    protected static function nextPowerOfTwo (n :int) :int {
        var p :int = 1;
        while (p < n) p *= 2;
        return p;
    }

    protected const _unpacked :Vector.<SwfTexture> = new Vector.<SwfTexture>();

    // Maximum width or height of a texture atlas
    private static const MAX_SIZE :int = 1024;
}
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.geom.Point;

import flump.SwfTexture;
import flump.mold.KeyframeMold;
import flump.mold.MovieMold;
import flump.xfl.XflLibrary;
import flump.xfl.XflTexture;

import com.threerings.util.Comparators;

public class Packer
{
    public const atlases :Vector.<Atlas> = new Vector.<Atlas>();

    public function Packer (lib :XflLibrary, scale :Number=1.0, prefix :String="", suffix :String="") {
        for each (var tex :XflTexture in lib.textures) {
            _unpacked.push(SwfTexture.fromTexture(lib.swf, tex, scale));
        }
        for each (var movie :MovieMold in lib.movies) {
            if (!movie.flipbook) continue;
            for each (var kf :KeyframeMold in movie.layers[0].keyframes) {
                _unpacked.push(SwfTexture.fromFlipbook(lib, movie, kf.index, scale));
            }
        }
        _unpacked.sort(Comparators.createReverse(Comparators.createFields(["a", "w", "h"])));
        while (_unpacked.length > 0) {
            // Add a new atlas
            const size :Point = findOptimalSize();
            atlases.push(new Atlas(prefix + "atlas" + atlases.length + suffix, size.x, size.y));

            // Try to pack each texture into any atlas
            for (var ii :int = 0; ii < _unpacked.length; ++ii) {
                var unpacked :SwfTexture = _unpacked[ii];

                if (unpacked.w > MAX_SIZE || unpacked.h > MAX_SIZE) {
                    throw new Error("Too large to fit in an atlas: " + unpacked.w + ", " + unpacked.h + " " + unpacked.symbol);
                }

                for each (var atlas :Atlas in atlases) {
                    // TODO(bruno): Support rotated textures?
                    if (atlas.place(unpacked)) {
                        _unpacked.splice(ii--, 1);
                        break;
                    }
                }
            }
        }
    }

    // Estimate the optimal size for the next atlas
    protected function findOptimalSize () :Point {
        var area :int = 0;
        var maxW :int = 0;
        var maxH :int = 0;

        for each (var tex :SwfTexture in _unpacked) {
            const w :int = tex.w + Atlas.PADDING;
            const h :int = tex.h + Atlas.PADDING;
            area += w * h;
            maxW = Math.max(maxW, w);
            maxH = Math.max(maxH, h);
        }

        const size :Point = new Point(nextPowerOfTwo(maxW), nextPowerOfTwo(maxH));

        // Double the area until it's big enough
        while (size.x * size.y < area) {
            if (size.x < size.y) size.x *= 2;
            else size.y *= 2;
        }

        size.x = Math.min(size.x, MAX_SIZE);
        size.y = Math.min(size.y, MAX_SIZE);

        return size;
    }

    protected static function nextPowerOfTwo (n :int) :int {
        var p :int = 1;
        while (p < n) p *= 2;
        return p;
    }

    protected const _unpacked :Vector.<SwfTexture> = new Vector.<SwfTexture>();

    // Maximum width or height of a texture atlas
    private static const MAX_SIZE :int = 2048;
}
}

Bump the max atlas size up to 2048

Bump the max atlas size up to 2048


package cc.milkshape.main
{
	import cc.milkshape.preloader.events.PreloaderEvent;
	import cc.milkshape.utils.Constance;
	import flash.net.URLRequest;
	import flash.net.navigateToURL;
	import flash.events.MouseEvent;

	public class SubMenu extends SubMenuClp
	{

		public function SubMenu()
		{
			rss.buttonMode = true;
			terms.buttonMode = true;
			rss.slug = 'rss';
			terms.slug = 'terms';
			rss.addEventListener(MouseEvent.MOUSE_OVER, _overHandler);
			rss.addEventListener(MouseEvent.MOUSE_OUT, _outHandler);
			rss.addEventListener(MouseEvent.CLICK, _clickHandlerRSS);
			terms.addEventListener(MouseEvent.MOUSE_OVER, _overHandler);
			terms.addEventListener(MouseEvent.MOUSE_OUT, _outHandler);
			terms.addEventListener(MouseEvent.CLICK, _clickHandlerTerms);
		}

		private function _overHandler(e:MouseEvent):void
		{
			e.currentTarget.gotoAndPlay('over');
		}

		private function _outHandler(e:MouseEvent):void
		{
			e.currentTarget.gotoAndPlay('out');
		}

		private function _clickHandlerTerms(e:MouseEvent):void
		{
			dispatchEvent(new PreloaderEvent(PreloaderEvent.LOAD, {url: Constance.TERMS_SWF}));
		}

		private function _clickHandlerRSS(e:MouseEvent):void
		{
			navigateToURL(new URLRequest(Constance.url('/square/feeds/rss/')), 'blank');
		}

	}
}

package cc.milkshape.main
{
	import cc.milkshape.preloader.events.PreloaderEvent;
	import cc.milkshape.utils.Constance;
	import flash.net.URLRequest;
	import flash.net.navigateToURL;
	import flash.events.MouseEvent;

	public class SubMenu extends SubMenuClp
	{

		public function SubMenu()
		{
			rss.buttonMode = true;
			terms.buttonMode = true;
			rss.slug = 'rss';
			terms.slug = 'terms';
			rss.addEventListener(MouseEvent.MOUSE_OVER, _overHandler);
			rss.addEventListener(MouseEvent.MOUSE_OUT, _outHandler);
			rss.addEventListener(MouseEvent.CLICK, _clickHandlerRSS);
			terms.addEventListener(MouseEvent.MOUSE_OVER, _overHandler);
			terms.addEventListener(MouseEvent.MOUSE_OUT, _outHandler);
			terms.addEventListener(MouseEvent.CLICK, _clickHandlerTerms);
		}

		private function _overHandler(e:MouseEvent):void
		{
			e.currentTarget.gotoAndPlay('over');
		}

		private function _outHandler(e:MouseEvent):void
		{
			e.currentTarget.gotoAndPlay('out');
		}

		private function _clickHandlerTerms(e:MouseEvent):void
		{
			dispatchEvent(new PreloaderEvent(PreloaderEvent.LOAD, {url: Constance.TERMS_SWF}));
		}

		private function _clickHandlerRSS(e:MouseEvent):void
		{
			navigateToURL(new URLRequest(Constance.url('square/feeds/rss/')), 'blank');
		}

	}
}

fix submenu

fix submenu