// 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, 0, 0);
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;
    spawnedObjectsNames[index] = VerifySpawnedObjectFile(resourceName);
    RefreshPickedObjects();
}

String VerifySpawnedObjectFile(const String&in resourceName)
{
    File@ file = cache.GetFile(resourceName);
    if(file !is null)
        return resourceName;
    else
        return String();
}

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());
    spawnedObjectsNames[resourcePickIndex] = VerifySpawnedObjectFile(resourceName);
    @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, 1, 0), normal);
    spawnRotation = Quaternion(Random(-randomRotation.x, randomRotation.x),
        Random(-randomRotation.y, randomRotation.y), Random(-randomRotation.z, randomRotation.z)) * spawnRotation;

    int number = RandomInt(0, spawnedObjectsNames.length);
    File@ file = cache.GetFile(spawnedObjectsNames[number]);
    Node@ spawnedObject = InstantiateNodeFromFile(file, spawnPosition, spawnRotation, Random(randomScaleMin, randomScaleMax));
    if (spawnedObject is null)
    {
        spawnedObjectsNames[number] = spawnedObjectsNames[spawnedObjectsNames.length - 1];
        --numberSpawnedObjects;
        RefreshPickedObjects();
        return;
    }
}

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);
        }
    }
}

// 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, 0, 0);
float randomScaleMin = 1;
float randomScaleMax = 1;
uint spawnCount = 1;
float spawnRadius = 0;
bool useNormal = true;

uint 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.ToUInt();
    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.ToUInt();
}

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 = VerifySpawnedObjectFile(nameEdit.text);
    nameEdit.text = resourceName;
    spawnedObjectsNames[index] = resourceName;
}

String VerifySpawnedObjectFile(const String&in resourceName)
{
    File@ file = cache.GetFile(resourceName);
    if(file !is null)
        return resourceName;
    else
        return String();
}

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());
    spawnedObjectsNames[resourcePickIndex] = VerifySpawnedObjectFile(resourceName);
    @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, 1, 0), normal);
    spawnRotation = Quaternion(Random(-randomRotation.x, randomRotation.x),
        Random(-randomRotation.y, randomRotation.y), Random(-randomRotation.z, randomRotation.z)) * spawnRotation;

    int number = RandomInt(0, spawnedObjectsNames.length);
    File@ file = cache.GetFile(spawnedObjectsNames[number]);
    Node@ spawnedObject = InstantiateNodeFromFile(file, spawnPosition, spawnRotation, Random(randomScaleMin, randomScaleMax));
    if (spawnedObject is null)
    {
        spawnedObjectsNames[number] = spawnedObjectsNames[spawnedObjectsNames.length - 1];
        --numberSpawnedObjects;
        RefreshPickedObjects();
        return;
    }
}

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);
        }
    }
}

Correct data type for spawn object counting variable.


package aerys.minko.type.data
{
	import aerys.minko.type.Signal;
	import aerys.minko.type.enum.DataProviderUsage;

	import flash.utils.Dictionary;
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;

	public dynamic class DataProvider extends Proxy implements IDataProvider
	{
		private var _usage				: uint			= 1;
		private var _name				: String		= null;
		private var _descriptor			: Object		= {};

		private var _changed			: Signal		= new Signal('DataProvider.changed');
		private var _propertyChanged	: Signal		= new Signal('DataProvider.propertyChanged');

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

		public function get usage() : uint
		{
			return _usage;
		}

		public function get dataDescriptor() : Object
		{
			return _descriptor;
		}

		public function get changed() : Signal
		{
			return _changed;
		}

		public function get propertyChanged() : Signal
		{
			return _propertyChanged;
		}

		public function DataProvider(properties	: Object	= null,
									 name		: String	= null,
									 usage		: uint		= 1)
		{
			_name	= name;
			_usage	= usage;

			initialize(properties);
		}

		private function initialize(properties : Object) : void
		{
			if (properties)
				for (var propertyName : String in properties)
					setProperty(propertyName, properties[propertyName]);
		}

		override flash_proxy function getProperty(name : *) : *
		{
			return getProperty(String(name));
		}

		override flash_proxy function setProperty(name : *, value : *) : void
		{
			setProperty(String(name), value);
		}

		override flash_proxy function deleteProperty(name : *) : Boolean
		{
			removeProperty(String(name));

			return true;
		}

		public function getProperty(name : String) : *
		{
			return _nameToProperty[name];
		}

		public function setProperty(name : String, newValue : Object) : DataProvider
		{
			var oldValue : Object	= _nameToProperty[name];
			var oldMonitoredValue	: IMonitoredData	= oldValue as IMonitoredData;
			var newMonitoredValue	: IMonitoredData	= newValue as IMonitoredData;
			var oldPropertyNames	: Vector.<String>	= _propertyToNames[oldMonitoredValue];
			var newPropertyNames	: Vector.<String>	= _propertyToNames[newMonitoredValue];

			if (oldMonitoredValue != null)
			{
				if (oldPropertyNames.length == 1)
				{
					oldMonitoredValue.changed.remove(propertyChangedHandler);
					delete _propertyToNames[oldMonitoredValue];
				}
				else
					oldPropertyNames.splice(oldPropertyNames.indexOf(name), 1);
			}

			if (newMonitoredValue != null)
			{
				if (newPropertyNames == null)
				{
					newPropertyNames = _propertyToNames[newMonitoredValue] = new <String>[name];
					newMonitoredValue.changed.add(propertyChangedHandler);
				}
				else
					newPropertyNames.push(name);
			}

			_descriptor[name]		= name;
			_nameToProperty[name]	= newValue;

			if (oldValue === null)
				_changed.execute(this, 'dataDescriptor');
			else
				_changed.execute(this, name);

			return this;
		}

		public function setProperties(properties : Object) : DataProvider
		{
			for (var propertyName : String in properties)
				setProperty(propertyName, properties[propertyName]);

			return this;
		}

		public function removeProperty(name : String) : DataProvider
		{
			var oldMonitoredValue	: IMonitoredData	= _nameToProperty[name] as IMonitoredData;
			var oldPropertyNames	: Vector.<String>	= _propertyToNames[oldMonitoredValue];

			delete _descriptor[name];
			delete _nameToProperty[name];

			if (oldMonitoredValue != null)
			{
				if (oldPropertyNames.length == 1)
				{
					oldMonitoredValue.changed.remove(propertyChangedHandler);
					delete _propertyToNames[oldMonitoredValue];
				}
				else
					oldPropertyNames.splice(oldPropertyNames.indexOf(name), 1);
			}

			_changed.execute(this, 'dataDescriptor');

			return this;
		}

		public function removeAllProperties() : DataProvider
		{
			for (var propertyName : String in _nameToProperty)
				removeProperty(propertyName);

			return this;
		}

		public function propertyExists(name : String) : Boolean
		{
			return _descriptor.hasOwnProperty(name);
		}

		public function invalidate() : DataProvider
		{
			_changed.execute(this, null);

			return this;
		}

		public function clone() : IDataProvider
		{
			switch (_usage)
			{
				case DataProviderUsage.EXCLUSIVE:
				case DataProviderUsage.SHARED:
					return new DataProvider(_nameToProperty, _name + '_cloned', _usage);

				case DataProviderUsage.MANAGED:
					throw new Error('This dataprovider is managed, and must not be cloned');

				default:
					throw new Error('Unkown usage value');
			}
		}

		private function propertyChangedHandler(source : IMonitoredData, key : String) : void
		{
			var names		: Vector.<String>	= _propertyToNames[source];
			var numNames	: uint				= names.length;

			for (var nameId : uint = 0; nameId < numNames; ++nameId)
				_propertyChanged.execute(this, names[nameId]);
		}
	}
}

package aerys.minko.type.data
{
	import aerys.minko.type.Signal;
	import aerys.minko.type.enum.DataProviderUsage;

	import flash.utils.Dictionary;
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;

	public dynamic class DataProvider extends Proxy implements IDataProvider
	{
		private var _usage				: uint			= 1;
		private var _name				: String		= null;
		private var _descriptor			: Object		= {};

		private var _changed			: Signal		= new Signal('DataProvider.changed');
		private var _propertyChanged	: Signal		= new Signal('DataProvider.propertyChanged');

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

		public function get usage() : uint
		{
			return _usage;
		}

		public function get dataDescriptor() : Object
		{
			return _descriptor;
		}

		public function get changed() : Signal
		{
			return _changed;
		}

		public function get propertyChanged() : Signal
		{
			return _propertyChanged;
		}

		public function get name() : String
		{
			return _name;
		}

		public function set name(v : String) : void
		{
			_name = v;
		}

		public function DataProvider(properties	: Object	= null,
									 name		: String	= null,
									 usage		: uint		= 1)
		{
			_name	= name;
			_usage	= usage;

			initialize(properties);
		}

		private function initialize(properties : Object) : void
		{
			if (properties)
				for (var propertyName : String in properties)
					setProperty(propertyName, properties[propertyName]);
		}

		override flash_proxy function getProperty(name : *) : *
		{
			return getProperty(String(name));
		}

		override flash_proxy function setProperty(name : *, value : *) : void
		{
			setProperty(String(name), value);
		}

		override flash_proxy function deleteProperty(name : *) : Boolean
		{
			removeProperty(String(name));

			return true;
		}

		public function getProperty(name : String) : *
		{
			return _nameToProperty[name];
		}

		public function setProperty(name : String, newValue : Object) : DataProvider
		{
			var oldValue : Object	= _nameToProperty[name];
			var oldMonitoredValue	: IMonitoredData	= oldValue as IMonitoredData;
			var newMonitoredValue	: IMonitoredData	= newValue as IMonitoredData;
			var oldPropertyNames	: Vector.<String>	= _propertyToNames[oldMonitoredValue];
			var newPropertyNames	: Vector.<String>	= _propertyToNames[newMonitoredValue];

			if (oldMonitoredValue != null)
			{
				if (oldPropertyNames.length == 1)
				{
					oldMonitoredValue.changed.remove(propertyChangedHandler);
					delete _propertyToNames[oldMonitoredValue];
				}
				else
					oldPropertyNames.splice(oldPropertyNames.indexOf(name), 1);
			}

			if (newMonitoredValue != null)
			{
				if (newPropertyNames == null)
				{
					newPropertyNames = _propertyToNames[newMonitoredValue] = new <String>[name];
					newMonitoredValue.changed.add(propertyChangedHandler);
				}
				else
					newPropertyNames.push(name);
			}

			_descriptor[name]		= name;
			_nameToProperty[name]	= newValue;

			if (oldValue === null)
				_changed.execute(this, 'dataDescriptor');
			else
				_changed.execute(this, name);

			return this;
		}

		public function setProperties(properties : Object) : DataProvider
		{
			for (var propertyName : String in properties)
				setProperty(propertyName, properties[propertyName]);

			return this;
		}

		public function removeProperty(name : String) : DataProvider
		{
			var oldMonitoredValue	: IMonitoredData	= _nameToProperty[name] as IMonitoredData;
			var oldPropertyNames	: Vector.<String>	= _propertyToNames[oldMonitoredValue];

			delete _descriptor[name];
			delete _nameToProperty[name];

			if (oldMonitoredValue != null)
			{
				if (oldPropertyNames.length == 1)
				{
					oldMonitoredValue.changed.remove(propertyChangedHandler);
					delete _propertyToNames[oldMonitoredValue];
				}
				else
					oldPropertyNames.splice(oldPropertyNames.indexOf(name), 1);
			}

			_changed.execute(this, 'dataDescriptor');

			return this;
		}

		public function removeAllProperties() : DataProvider
		{
			for (var propertyName : String in _nameToProperty)
				removeProperty(propertyName);

			return this;
		}

		public function propertyExists(name : String) : Boolean
		{
			return _descriptor.hasOwnProperty(name);
		}

		public function invalidate() : DataProvider
		{
			_changed.execute(this, null);

			return this;
		}

		public function clone() : IDataProvider
		{
			switch (_usage)
			{
				case DataProviderUsage.EXCLUSIVE:
				case DataProviderUsage.SHARED:
					return new DataProvider(_nameToProperty, _name + '_cloned', _usage);

				case DataProviderUsage.MANAGED:
					throw new Error('This dataprovider is managed, and must not be cloned');

				default:
					throw new Error('Unkown usage value');
			}
		}

		private function propertyChangedHandler(source : IMonitoredData, key : String) : void
		{
			var names		: Vector.<String>	= _propertyToNames[source];
			var numNames	: uint				= names.length;

			for (var nameId : uint = 0; nameId < numNames; ++nameId)
				_propertyChanged.execute(this, names[nameId]);
		}
	}
}

Add name getter/setter to providers

Add name getter/setter to providers


package aerys.minko.scene.controller.mesh
{
	import flash.display.BitmapData;

	import aerys.minko.ns.minko_math;
	import aerys.minko.render.Viewport;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.scene.node.camera.AbstractCamera;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.binding.DataProvider;
	import aerys.minko.type.enum.DataProviderUsage;
	import aerys.minko.type.enum.FrustumCulling;
	import aerys.minko.type.math.BoundingBox;
	import aerys.minko.type.math.BoundingSphere;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	/**
	 * The MeshVisibilityController watches the Mesh and the active Camera of a Scene
	 * to determine whether the object is actually inside the view frustum or not.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class MeshVisibilityController extends AbstractController
	{
		use namespace minko_math;

		private static const TMP_VECTOR4		: Vector4	= new Vector4();
        private static const TMP_VECTOR4_2		: Vector4	= new Vector4();

		private static const STATE_UNDEFINED	: uint		= 0;
		private static const STATE_INSIDE		: uint		= 1;
		private static const STATE_OUTSIDE		: uint		= 2;

		private var _mesh			    : Mesh;
		private var _state			    : uint;
		private var _lastTest		    : int;
		private var _boundingBox	    : BoundingBox;
		private var _boundingSphere	    : BoundingSphere;

		private var _data				: DataProvider;

        private var _frustumCulling     : uint;
        private var _insideFrustum      : Boolean;

		public function get frustumCulling() : uint
		{
			return _frustumCulling;
		}
		public function set frustumCulling(value : uint) : void
		{
			if (value != _frustumCulling)
			{
				_frustumCulling = value;
				if (value == FrustumCulling.DISABLED)
				{
					_data.computedVisibility = true;
					if (_mesh.localToWorldTransformChanged.hasCallback(meshLocalToWorldChangedHandler))
						_mesh.localToWorldTransformChanged.remove(meshLocalToWorldChangedHandler);
				}
				else if (_mesh && _mesh.scene)
				{
					_mesh.localToWorldTransformChanged.add(meshLocalToWorldChangedHandler);
	            	testCulling();
				}
			}
		}

		public function get insideFrustum() : Boolean
		{
			return _insideFrustum;
		}

        public function get computedVisibility() : Boolean
        {
            return _data.computedVisibility;
        }

		public function MeshVisibilityController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			_data = new DataProvider(
				{ computedVisibility : true },
				'MeshVisibilityDataProvider',
				DataProviderUsage.EXCLUSIVE
			);

			_boundingBox = new BoundingBox(Vector4.ZERO, Vector4.ONE);
			_boundingSphere = new BoundingSphere(Vector4.ZERO, 0.);

            _state = STATE_UNDEFINED;

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

		private function targetAddedHandler(ctrl	: MeshVisibilityController,
											target	: Mesh) : void
		{
			if (_mesh != null)
				throw new Error();

			_mesh = target;

			target.added.add(addedHandler);
			target.removed.add(removedHandler);

			if (target.root is Scene)
				addedHandler(target, target.root as Scene);

			if (_frustumCulling)
				testCulling();
		}

		private function targetRemovedHandler(ctrl		: MeshVisibilityController,
											  target	: Mesh) : void
		{
			_mesh = null;

			target.added.remove(addedHandler);
			target.removed.remove(removedHandler);

			if (target.root is Scene)
				removedHandler(target, target.root as Scene);
		}

		private function addedHandler(mesh : Mesh, ancestor : Group) : void
		{
			var scene : Scene = mesh.scene;

			if (!scene)
				return ;

			scene.bindings.addCallback('worldToScreen', worldToScreenChangedHandler);

            if (_frustumCulling)
                scene.renderingBegin.add(sceneRenderingBeginHandler);

            _mesh.computedVisibilityChanged.add(computedVisiblityChangedHandler);
            _mesh.bindings.addProvider(_data);
		}

        private function sceneRenderingBeginHandler(scene			: Scene,
                                                    viewport		: Viewport,
                                                    destination	    : BitmapData,
                                                    time			: Number) : void
        {
            scene.renderingBegin.remove(sceneRenderingBeginHandler);

            meshLocalToWorldChangedHandler(_mesh, _mesh.getLocalToWorldTransform());
            _mesh.localToWorldTransformChanged.add(meshLocalToWorldChangedHandler);
        }

		private function removedHandler(mesh : Mesh, ancestor : Group) : void
		{
			var scene : Scene = ancestor.scene;

			if (!scene)
				return ;

            if (scene.renderingBegin.hasCallback(sceneRenderingBeginHandler))
                scene.renderingBegin.remove(sceneRenderingBeginHandler);

			if (scene.bindings.hasCallback('worldToScreen', worldToScreenChangedHandler))
				scene.bindings.removeCallback('worldToScreen', worldToScreenChangedHandler);

			if (_frustumCulling
                && mesh.localToWorldTransformChanged.hasCallback(meshLocalToWorldChangedHandler))
				mesh.localToWorldTransformChanged.remove(meshLocalToWorldChangedHandler);

			if (mesh.computedVisibilityChanged.hasCallback(computedVisiblityChangedHandler))
			{
				mesh.computedVisibilityChanged.remove(computedVisiblityChangedHandler);
            	mesh.bindings.removeProvider(_data);
			}
		}

        private function computedVisiblityChangedHandler(node               : ISceneNode,
                                                         computedVisibility : Boolean) : void
        {
            _data.computedVisibility = computedVisibility;
        }

		private function worldToScreenChangedHandler(bindings	    : DataBindings,
													 bindingName	: String,
													 oldValue		: Matrix4x4,
                                                     value			: Matrix4x4) : void
		{
			testCulling();
		}

		private function meshLocalToWorldChangedHandler(mesh : Mesh, transform : Matrix4x4) : void
		{
			var geom 	: Geometry 	= _mesh.geometry;
			var culling	: uint		= _frustumCulling;

			if (!geom || !geom.boundingBox || !geom.boundingSphere || culling == FrustumCulling.DISABLED)
				return ;

			if (culling & FrustumCulling.BOX)
				transform.transformRawVectors(geom.boundingBox._vertices, _boundingBox._vertices);

			if (culling & FrustumCulling.SPHERE)
			{
				var center 	: Vector4 	= transform.transformVector(geom.boundingSphere.center, TMP_VECTOR4);
				var scale 	: Vector4 	= transform.deltaTransformVector(Vector4.ONE, TMP_VECTOR4_2);
				var radius	: Number	= geom.boundingSphere.radius * Math.max(
					Math.abs(scale.x), Math.abs(scale.y), Math.abs(scale.z)
				);

				_boundingSphere.update(center, radius);
			}

			testCulling();
		}

		private function testCulling() : void
		{
			var culling	: uint	= _frustumCulling;

			if (_mesh && _mesh.geometry && _mesh.geometry.boundingBox && _mesh.visible && _mesh.root is Scene)
			{
				var camera : AbstractCamera = (_mesh.root as Scene).activeCamera;

				if (!camera)
					return ;

				_lastTest = camera.frustum.testBoundingVolume(
					_boundingSphere,
					_boundingBox,
					null,
					culling,
					_lastTest
				);

				var inside : Boolean = _lastTest == -1;

				if (inside && _state != STATE_INSIDE)
				{
					_insideFrustum = true;
                    _data.computedVisibility = _mesh.parent.computedVisibility && _mesh.visible;
                    _mesh.computedVisibilityChanged.execute(_mesh, computedVisibility);
					_state = STATE_INSIDE;
				}
				else if (!inside && _state != STATE_OUTSIDE)
				{
					_insideFrustum = false;
                    _data.computedVisibility = false;
                    _mesh.computedVisibilityChanged.execute(_mesh, false);
					_state = STATE_OUTSIDE;
				}
			}
		}

		override public function clone() : AbstractController
		{
			return new MeshVisibilityController();
		}
	}
}

package aerys.minko.scene.controller.mesh
{
	import flash.display.BitmapData;

	import aerys.minko.ns.minko_math;
	import aerys.minko.render.Viewport;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.scene.node.camera.AbstractCamera;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.binding.DataProvider;
	import aerys.minko.type.enum.DataProviderUsage;
	import aerys.minko.type.enum.FrustumCulling;
	import aerys.minko.type.math.BoundingBox;
	import aerys.minko.type.math.BoundingSphere;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	/**
	 * The MeshVisibilityController watches the Mesh and the active Camera of a Scene
	 * to determine whether the object is actually inside the view frustum or not.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class MeshVisibilityController extends AbstractController
	{
		use namespace minko_math;

		private static const TMP_VECTOR4		: Vector4	= new Vector4();
        private static const TMP_VECTOR4_2		: Vector4	= new Vector4();

		private static const STATE_UNDEFINED	: uint		= 0;
		private static const STATE_INSIDE		: uint		= 1;
		private static const STATE_OUTSIDE		: uint		= 2;

		private var _mesh			    : Mesh;
		private var _state			    : uint;
		private var _lastTest		    : int;
		private var _boundingBox	    : BoundingBox;
		private var _boundingSphere	    : BoundingSphere;

		private var _data				: DataProvider;

        private var _frustumCulling     : uint;
        private var _insideFrustum      : Boolean;

		public function get frustumCulling() : uint
		{
			return _frustumCulling;
		}
		public function set frustumCulling(value : uint) : void
		{
			if (value != _frustumCulling)
			{
				_frustumCulling = value;
				if (value == FrustumCulling.DISABLED)
				{
					_data.computedVisibility = true;
					if (_mesh.localToWorldTransformChanged.hasCallback(meshLocalToWorldChangedHandler))
						_mesh.localToWorldTransformChanged.remove(meshLocalToWorldChangedHandler);
				}
				else if (_mesh && _mesh.scene)
				{
					_mesh.localToWorldTransformChanged.add(meshLocalToWorldChangedHandler);
	            	testCulling();
				}
			}
		}

		public function get insideFrustum() : Boolean
		{
			return _insideFrustum;
		}

        public function get computedVisibility() : Boolean
        {
            return _data.computedVisibility;
        }

		public function MeshVisibilityController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			_data = new DataProvider(
				{ computedVisibility : true },
				'MeshVisibilityDataProvider',
				DataProviderUsage.EXCLUSIVE
			);

			_boundingBox = new BoundingBox(Vector4.ZERO, Vector4.ONE);
			_boundingSphere = new BoundingSphere(Vector4.ZERO, 0.);

            _state = STATE_UNDEFINED;

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

		private function targetAddedHandler(ctrl	: MeshVisibilityController,
											target	: Mesh) : void
		{
			if (_mesh != null)
				throw new Error();

			_mesh = target;

			target.added.add(addedHandler);
			target.removed.add(removedHandler);

			if (target.root is Scene)
				addedHandler(target, target.root as Scene);

			if (_frustumCulling)
				testCulling();
		}

		private function targetRemovedHandler(ctrl		: MeshVisibilityController,
											  target	: Mesh) : void
		{
			_mesh = null;

			target.added.remove(addedHandler);
			target.removed.remove(removedHandler);

			if (target.root is Scene)
				removedHandler(target, target.root as Scene);
		}

		private function addedHandler(mesh : Mesh, ancestor : Group) : void
		{
			var scene : Scene = ancestor.scene;

			if (!scene)
				return ;

			scene.bindings.addCallback('worldToScreen', worldToScreenChangedHandler);

            if (_frustumCulling)
                scene.renderingBegin.add(sceneRenderingBeginHandler);

            _mesh.computedVisibilityChanged.add(computedVisiblityChangedHandler);
            _mesh.bindings.addProvider(_data);
		}

        private function sceneRenderingBeginHandler(scene			: Scene,
                                                    viewport		: Viewport,
                                                    destination	    : BitmapData,
                                                    time			: Number) : void
        {
            scene.renderingBegin.remove(sceneRenderingBeginHandler);

            meshLocalToWorldChangedHandler(_mesh, _mesh.getLocalToWorldTransform());
            _mesh.localToWorldTransformChanged.add(meshLocalToWorldChangedHandler);
        }

		private function removedHandler(mesh : Mesh, ancestor : Group) : void
		{
			var scene : Scene = ancestor.scene;

			if (!scene)
				return ;

            if (scene.renderingBegin.hasCallback(sceneRenderingBeginHandler))
                scene.renderingBegin.remove(sceneRenderingBeginHandler);

			scene.bindings.removeCallback('worldToScreen', worldToScreenChangedHandler);

			if (_frustumCulling
                && mesh.localToWorldTransformChanged.hasCallback(meshLocalToWorldChangedHandler))
				mesh.localToWorldTransformChanged.remove(meshLocalToWorldChangedHandler);

				mesh.computedVisibilityChanged.remove(computedVisiblityChangedHandler);
            	mesh.bindings.removeProvider(_data);
		}

        private function computedVisiblityChangedHandler(node               : ISceneNode,
                                                         computedVisibility : Boolean) : void
        {
            _data.computedVisibility = computedVisibility;
        }

		private function worldToScreenChangedHandler(bindings	    : DataBindings,
													 bindingName	: String,
													 oldValue		: Matrix4x4,
                                                     value			: Matrix4x4) : void
		{
			testCulling();
		}

		private function meshLocalToWorldChangedHandler(mesh : Mesh, transform : Matrix4x4) : void
		{
			var geom 	: Geometry 	= _mesh.geometry;
			var culling	: uint		= _frustumCulling;

			if (!geom || !geom.boundingBox || !geom.boundingSphere || culling == FrustumCulling.DISABLED)
				return ;

			if (culling & FrustumCulling.BOX)
				transform.transformRawVectors(geom.boundingBox._vertices, _boundingBox._vertices);

			if (culling & FrustumCulling.SPHERE)
			{
				var center 	: Vector4 	= transform.transformVector(geom.boundingSphere.center, TMP_VECTOR4);
				var scale 	: Vector4 	= transform.deltaTransformVector(Vector4.ONE, TMP_VECTOR4_2);
				var radius	: Number	= geom.boundingSphere.radius * Math.max(
					Math.abs(scale.x), Math.abs(scale.y), Math.abs(scale.z)
				);

				_boundingSphere.update(center, radius);
			}

			testCulling();
		}

		private function testCulling() : void
		{
			var culling	: uint	= _frustumCulling;

			if (_mesh && _mesh.geometry && _mesh.geometry.boundingBox && _mesh.visible && _mesh.root is Scene)
			{
				var camera : AbstractCamera = (_mesh.root as Scene).activeCamera;

				if (!camera)
					return ;

				_lastTest = camera.frustum.testBoundingVolume(
					_boundingSphere,
					_boundingBox,
					null,
					culling,
					_lastTest
				);

				var inside : Boolean = _lastTest == -1;

				if (inside && _state != STATE_INSIDE)
				{
					_insideFrustum = true;
                    _data.computedVisibility = _mesh.parent.computedVisibility && _mesh.visible;
                    _mesh.computedVisibilityChanged.execute(_mesh, computedVisibility);
					_state = STATE_INSIDE;
				}
				else if (!inside && _state != STATE_OUTSIDE)
				{
					_insideFrustum = false;
                    _data.computedVisibility = false;
                    _mesh.computedVisibilityChanged.execute(_mesh, false);
					_state = STATE_OUTSIDE;
				}
			}
		}

		override public function clone() : AbstractController
		{
			return new MeshVisibilityController();
		}
	}
}

Fix when a mesh is added to the scene

Fix when a mesh is added to the scene


package com.ryanberdeen.echonest.api.v3.track.utils {
  import com.ryanberdeen.echonest.api.v3.EchoNestError;
  import com.ryanberdeen.echonest.api.v3.EchoNestErrorEvent;
  import com.ryanberdeen.echonest.api.v3.track.AnalysisEvent;
  import com.ryanberdeen.echonest.api.v3.track.AnalysisLoader;
  import com.ryanberdeen.echonest.api.v3.track.TrackApi;
  import com.ryanberdeen.utils.MD5Calculator;

  import flash.events.Event;
  import flash.events.EventDispatcher;
  import flash.events.IOErrorEvent;
  import flash.events.SecurityErrorEvent;
  import flash.media.Sound;
  import flash.net.FileFilter;
  import flash.net.FileReference;

  import org.audiofx.mp3.MP3FileReferenceLoader;
  import org.audiofx.mp3.MP3SoundEvent;

  public class TrackLoader extends EventDispatcher {
    private var trackApi:TrackApi;

    private var _fileReference:FileReference;
    private var mp3Loader:MP3FileReferenceLoader;
    private var _md5Calculator:MD5Calculator;
    private var _analysisLoader:AnalysisLoader;

    private var _alwaysUpload:Boolean;

    private var _sound:Sound;

    private var _md5:String;
    private var _id:String;

    public function TrackLoader(trackApi:TrackApi) {
      this.trackApi = trackApi;
      _fileReference = new FileReference();
      _md5Calculator = new MD5Calculator();
      _analysisLoader = new AnalysisLoader(trackApi);
      _alwaysUpload = false;
    }

    public function set alwaysUpload(alwaysUpload:Boolean):void {
      _alwaysUpload = alwaysUpload;
    }

    public function get fileReference():FileReference {
      return _fileReference;
    }

    public function get md5Calculator():MD5Calculator {
      return _md5Calculator;
    }

    public function get analysisLoader():AnalysisLoader {
      return _analysisLoader;
    }

    public function get sound():Sound {
      return _sound;
    }

    public function load(...properties):void {
      _analysisLoader.properties = properties;
      _fileReference.addEventListener(Event.SELECT, fileReferenceSelectHandler);
      _fileReference.browse([new FileFilter("MP3 Files", "*.mp3")]);
    }

    private function fileReferenceSelectHandler(e:Event):void {
      dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.LOADING_SOUND));
      mp3Loader = new MP3FileReferenceLoader();
      mp3Loader.addEventListener(Event.COMPLETE, soundLoadCompleteHandler);
      mp3Loader.getSound(_fileReference);
    }

    private function soundLoadCompleteHandler(e:MP3SoundEvent):void {
      _sound = e.sound;
      dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.SOUND_LOADED));
      mp3Loader.removeEventListener(Event.COMPLETE, soundLoadCompleteHandler);

      if (_alwaysUpload) {
        uploadFile();
      }
      else {
        calculateMd5();
      }
    }

    private function calculateMd5():void {
      dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.CALCULATING_MD5));
      _md5Calculator.addEventListener(Event.COMPLETE, md5CompleteHandler);
      _md5Calculator.calculate(_fileReference.data);
    }

    private function md5CompleteHandler(e:Event):void {
      dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.MD5_CALCULATED));
      _md5 = _md5Calculator.md5;
      _md5Calculator = null;

      dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.CHECKING_ANALYSIS));
      loadAnalysis({md5: _md5});
    }

    private function uploadFile():void {
      dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.UPLOADING_FILE));
      trackApi.uploadFileReference({file: _fileReference, wait: "N"}, {
        onResponse: function(track:Object):void {
          _id = track.id;
          dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.FILE_UPLOADED));
          dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.LOADING_ANALYSIS));
          loadAnalysis({id: _id});
        },
        onEchoNestError: function(error:EchoNestError):void {
          dispatchEvent(error.createEvent());
        },
        onError: dispatchEvent
      });
    }

    private function loadAnalysis(parameters:Object):void {
      _analysisLoader.addEventListener(AnalysisEvent.UNKNOWN, analysisUnknownHandler);
      _analysisLoader.load(parameters);
    }

    private function analysisUnknownHandler(e:Event):void {
      uploadFile();
      dispatchEvent(e);
    }
  }
}

package com.ryanberdeen.echonest.api.v3.track.utils {
  import com.ryanberdeen.echonest.api.v3.EchoNestError;
  import com.ryanberdeen.echonest.api.v3.EchoNestErrorEvent;
  import com.ryanberdeen.echonest.api.v3.track.AnalysisEvent;
  import com.ryanberdeen.echonest.api.v3.track.AnalysisLoader;
  import com.ryanberdeen.echonest.api.v3.track.TrackApi;
  import com.ryanberdeen.utils.MD5Calculator;

  import flash.events.Event;
  import flash.events.EventDispatcher;
  import flash.events.IOErrorEvent;
  import flash.events.SecurityErrorEvent;
  import flash.media.Sound;
  import flash.net.FileFilter;
  import flash.net.FileReference;

  import org.audiofx.mp3.MP3FileReferenceLoader;
  import org.audiofx.mp3.MP3SoundEvent;

  public class TrackLoader extends EventDispatcher {
    private var trackApi:TrackApi;

    private var _fileReference:FileReference;
    private var mp3Loader:MP3FileReferenceLoader;
    private var _md5Calculator:MD5Calculator;
    private var _analysisLoader:AnalysisLoader;

    private var _alwaysUpload:Boolean;

    private var _sound:Sound;

    private var _md5:String;
    private var _id:String;

    public function TrackLoader(trackApi:TrackApi) {
      this.trackApi = trackApi;
      _fileReference = new FileReference();
      _fileReference.addEventListener(Event.SELECT, fileReferenceSelectHandler);
      _md5Calculator = new MD5Calculator();
      _analysisLoader = new AnalysisLoader(trackApi);
      _alwaysUpload = false;
    }

    public function set alwaysUpload(alwaysUpload:Boolean):void {
      _alwaysUpload = alwaysUpload;
    }

    public function get fileReference():FileReference {
      return _fileReference;
    }

    public function get md5Calculator():MD5Calculator {
      return _md5Calculator;
    }

    public function get analysisLoader():AnalysisLoader {
      return _analysisLoader;
    }

    public function get sound():Sound {
      return _sound;
    }

    public function load(...properties):void {
      _analysisLoader.properties = properties;
      _fileReference.browse([new FileFilter("MP3 Files", "*.mp3")]);
    }

    private function fileReferenceSelectHandler(e:Event):void {
      dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.LOADING_SOUND));
      mp3Loader = new MP3FileReferenceLoader();
      mp3Loader.addEventListener(Event.COMPLETE, soundLoadCompleteHandler);
      mp3Loader.getSound(_fileReference);
    }

    private function soundLoadCompleteHandler(e:MP3SoundEvent):void {
      _sound = e.sound;
      dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.SOUND_LOADED));
      mp3Loader.removeEventListener(Event.COMPLETE, soundLoadCompleteHandler);

      if (_alwaysUpload) {
        uploadFile();
      }
      else {
        calculateMd5();
      }
    }

    private function calculateMd5():void {
      dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.CALCULATING_MD5));
      _md5Calculator.addEventListener(Event.COMPLETE, md5CompleteHandler);
      _md5Calculator.calculate(_fileReference.data);
    }

    private function md5CompleteHandler(e:Event):void {
      dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.MD5_CALCULATED));
      _md5 = _md5Calculator.md5;
      _md5Calculator = null;

      dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.CHECKING_ANALYSIS));
      loadAnalysis({md5: _md5});
    }

    private function uploadFile():void {
      dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.UPLOADING_FILE));
      trackApi.uploadFileReference({file: _fileReference, wait: "N"}, {
        onResponse: function(track:Object):void {
          _id = track.id;
          dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.FILE_UPLOADED));
          dispatchEvent(new TrackLoaderEvent(TrackLoaderEvent.LOADING_ANALYSIS));
          loadAnalysis({id: _id});
        },
        onEchoNestError: function(error:EchoNestError):void {
          dispatchEvent(error.createEvent());
        },
        onError: dispatchEvent
      });
    }

    private function loadAnalysis(parameters:Object):void {
      _analysisLoader.addEventListener(AnalysisEvent.UNKNOWN, analysisUnknownHandler);
      _analysisLoader.load(parameters);
    }

    private function analysisUnknownHandler(e:Event):void {
      uploadFile();
      dispatchEvent(e);
    }
  }
}

fix track loader to only add file selected handler once


/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.hola {
    import flash.events.*;
    import flash.external.ExternalInterface;
    import flash.net.URLRequest;
    import flash.net.URLStream;
    import flash.utils.ByteArray;
    import org.hola.ZExternalInterface;
    import org.hola.ZErr;
    import org.hola.Base64;
    import org.hola.WorkerUtils;
    import org.hola.HEvent;
    import org.hola.HSettings;
    import org.hola.FlashFetchBin;

    public dynamic class JSURLStream extends URLStream {
        private static var js_api_inited : Boolean = false;
        private static var req_count : Number = 0;
        private static var reqs : Object = {};
        private var _connected : Boolean;
        private var _resource : ByteArray = new ByteArray();
        private var _curr_data : Object;
        private var _hola_managed : Boolean = false;
        private var _req_id : String;

        public function JSURLStream(){
            _hola_managed = HSettings.hls_mode && ZExternalInterface.avail();
            addEventListener(Event.OPEN, onopen);
            super();
            if (!ZExternalInterface.avail() || js_api_inited)
                return;
            /* XXX arik: setting this to true will pass js exceptions to
             * as3 and as3 exceptions to js. this may break current customer
             * code
             ExternalInterface.marshallExceptions = true;
             */
            ExternalInterface.addCallback('hola_onFragmentData',
                hola_onFragmentData);
            js_api_inited = true;
        }

        protected function _trigger(cb : String, data : Object) : void {
            if (!_hola_managed)
                return ZErr.log('invalid trigger'); // XXX arik: ZErr.throw
            ExternalInterface.call('window.hola_'+cb,
                {objectID: ExternalInterface.objectID, data: data});
        }

        override public function get connected() : Boolean {
            if (!_hola_managed)
                return super.connected;
            return _connected;
        }

        override public function get bytesAvailable() : uint {
            if (!_hola_managed)
                return super.bytesAvailable;
            return _resource.bytesAvailable;
        }

        override public function readByte() : int {
            if (!_hola_managed)
                return super.readByte();
            return _resource.readByte();
        }

        override public function readUnsignedShort() : uint {
            if (!_hola_managed)
                return super.readUnsignedShort();
            return _resource.readUnsignedShort();
        }

        override public function readBytes(bytes : ByteArray,
            offset : uint = 0, length : uint = 0) : void
        {
            if (!_hola_managed)
                return super.readBytes(bytes, offset, length);
            _resource.readBytes(bytes, offset, length);
        }

        override public function close() : void {
            if (_hola_managed)
            {
                if (reqs[_req_id])
                {
                    _delete();
                    _trigger('abortFragment', {req_id: _req_id});
                }
                WorkerUtils.removeEventListener(HEvent.WORKER_MESSAGE, onmsg);
            }
            if (super.connected)
                super.close();
            _connected = false;
        }

        override public function load(request : URLRequest) : void {
            if (_hola_managed)
            {
                if (reqs[_req_id])
                {
                    _delete();
                    _trigger('abortFragment', {req_id: _req_id});
                }
                WorkerUtils.removeEventListener(HEvent.WORKER_MESSAGE, onmsg);
            }
            _hola_managed = HSettings.enabled && ZExternalInterface.avail();
            req_count++;
            _req_id = 'req'+req_count;
            if (!_hola_managed)
                return super.load(request);
            WorkerUtils.addEventListener(HEvent.WORKER_MESSAGE, onmsg);
            reqs[_req_id] = this;
            _resource = new ByteArray();
            _trigger('requestFragment', {url: request.url, req_id: _req_id});
            this.dispatchEvent(new Event(Event.OPEN));
        }

        private function onopen(e : Event) : void { _connected = true; }

        private function decode(str : String) : void {
            if (!str)
                return on_decoded_data(null);
            if (!HSettings.use_worker)
                return on_decoded_data(Base64.decode_str(str));
            var data : ByteArray = new ByteArray();
            data.shareable = true;
            data.writeUTFBytes(str);
            WorkerUtils.send({cmd: "b64.decode", id: _req_id});
            WorkerUtils.send(data);
        }

        private function onmsg(e : HEvent) : void {
            var msg : Object = e.data;
            if (!_req_id || _req_id!=msg.id || msg.cmd!="b64.decode")
                return;
            on_decoded_data(WorkerUtils.recv());
        }

        private function on_decoded_data(data : ByteArray) : void {
            if (data)
            {
                data.position = 0;
                if (_resource)
                {
                    var prev : uint = _resource.position;
                    data.readBytes(_resource, _resource.length);
                    _resource.position = prev;
                }
                else
                    _resource = data;
                // XXX arik: get finalLength from js
                var finalLength : uint = _resource.length;
                dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false,
                    false, _resource.length, finalLength));
            }
            // XXX arik: dispatch httpStatus/httpResponseStatus
            if (_curr_data.status)
                resourceLoadingSuccess();
        }

        private function on_fragment_data(o : Object) : void {
            _curr_data = o;
            if (o.error)
                return resourceLoadingError();
            if (o.fetchBinReqId)
                return fetch_bin(o);
            decode(o.data);
        }

        private function fetch_bin(o : Object) : void {
            if (!(o.fetchBinReq = FlashFetchBin.req_list[o.fetchBinReqId]))
                throw new Error('fetchBinReqId not found '+o.fetchBinReqId);
            _fetch_bin(o);
        }

        private function _fetch_bin(o : Object) : void {
            var fetchBinStream : URLStream = o.fetchBinReq.stream;
            _resource = _resource || new ByteArray();
            var prev : Number = _resource.position;
            var len : Number = Math.min(fetchBinStream.bytesAvailable,
                HSettings.fetch_bin_chunk_size);
            if (len)
            {
                fetchBinStream.readBytes(_resource, _resource.length, len);
                _resource.position = prev;
                dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false,
                    false, _resource.length, o.fetchBinReq.bytesTotal));
            }
            if (_resource.length < o.fetchBinReq.bytesTotal)
            {
                FlashFetchBin.consumeDataTimeout(o.fetchBinReqId,
                    _fetch_bin, HSettings.fetch_bin_delay, o);
            }
            else
            {
                resourceLoadingSuccess();
                FlashFetchBin.hola_fetchBinRemove(o.fetchBinReqId);
            }
        }

        private static function hola_onFragmentData(o : Object) : void {
            var stream : JSURLStream;
            try {
                if (!(stream = reqs[o.req_id]))
                    return ZErr.log('req_id not found '+o.req_id);
                stream.on_fragment_data(o);
            } catch(err : Error){
                ZErr.log('Error in hola_onFragmentData', ''+err,
                    ''+err.getStackTrace());
                if (stream)
                    stream.resourceLoadingError();
                throw err;
            }
        }

        private function _delete() : void {
            delete reqs[_req_id];
        }

        protected function resourceLoadingError() : void {
            _delete();
            dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR));
        }

        protected function resourceLoadingSuccess() : void {
            _delete();
            dispatchEvent(new Event(Event.COMPLETE));
        }
    }
}

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.hola {
    import flash.events.*;
    import flash.external.ExternalInterface;
    import flash.net.URLRequest;
    import flash.net.URLStream;
    import flash.utils.ByteArray;
    import org.hola.ZExternalInterface;
    import org.hola.ZErr;
    import org.hola.Base64;
    import org.hola.WorkerUtils;
    import org.hola.HEvent;
    import org.hola.HSettings;
    import org.hola.FlashFetchBin;

    public dynamic class JSURLStream extends URLStream {
        private static var js_api_inited : Boolean = false;
        private static var req_count : Number = 0;
        private static var reqs : Object = {};
        private var _connected : Boolean;
        private var _resource : ByteArray = new ByteArray();
        private var _curr_data : Object;
        private var _hola_managed : Boolean = false;
        private var _req_id : String;

        public function JSURLStream(){
            _hola_managed = HSettings.hls_mode && ZExternalInterface.avail();
            addEventListener(Event.OPEN, onopen);
            super();
            if (!ZExternalInterface.avail() || js_api_inited)
                return;
            /* XXX arik: setting this to true will pass js exceptions to
             * as3 and as3 exceptions to js. this may break current customer
             * code
             ExternalInterface.marshallExceptions = true;
             */
            ExternalInterface.addCallback('hola_onFragmentData',
                hola_onFragmentData);
            js_api_inited = true;
        }

        protected function _trigger(cb : String, data : Object) : void {
            if (!_hola_managed)
                return ZErr.log('invalid trigger'); // XXX arik: ZErr.throw
            ExternalInterface.call('window.hola_'+cb,
                {objectID: ExternalInterface.objectID, data: data});
        }

        override public function get connected() : Boolean {
            if (!_hola_managed)
                return super.connected;
            return _connected;
        }

        override public function get bytesAvailable() : uint {
            if (!_hola_managed)
                return super.bytesAvailable;
            return _resource.bytesAvailable;
        }

        override public function readByte() : int {
            if (!_hola_managed)
                return super.readByte();
            return _resource.readByte();
        }

        override public function readUnsignedShort() : uint {
            if (!_hola_managed)
                return super.readUnsignedShort();
            return _resource.readUnsignedShort();
        }

        override public function readBytes(bytes : ByteArray,
            offset : uint = 0, length : uint = 0) : void
        {
            if (!_hola_managed)
                return super.readBytes(bytes, offset, length);
            _resource.readBytes(bytes, offset, length);
        }

        override public function close() : void {
            if (_hola_managed)
            {
                if (reqs[_req_id])
                {
                    _delete();
                    _trigger('abortFragment', {req_id: _req_id});
                }
                WorkerUtils.removeEventListener(HEvent.WORKER_MESSAGE, onmsg);
            }
            if (super.connected)
                super.close();
            _connected = false;
        }

        override public function load(request : URLRequest) : void {
            if (_hola_managed)
            {
                if (reqs[_req_id])
                {
                    _delete();
                    _trigger('abortFragment', {req_id: _req_id});
                }
                WorkerUtils.removeEventListener(HEvent.WORKER_MESSAGE, onmsg);
            }
            _hola_managed = HSettings.enabled && ZExternalInterface.avail();
            req_count++;
            _req_id = 'req'+req_count;
            if (!_hola_managed)
                return super.load(request);
            WorkerUtils.addEventListener(HEvent.WORKER_MESSAGE, onmsg);
            reqs[_req_id] = this;
            _resource = new ByteArray();
            _trigger('requestFragment', {url: request.url, req_id: _req_id});
            this.dispatchEvent(new Event(Event.OPEN));
        }

        private function onopen(e : Event) : void { _connected = true; }

        private function decode(str : String) : void {
            if (!str)
                return on_decoded_data(null);
            if (!HSettings.use_worker)
                return on_decoded_data(Base64.decode_str(str));
            var data : ByteArray = new ByteArray();
            CONFIG::HAVE_WORKER {
            data.shareable = true;
            }
            data.writeUTFBytes(str);
            WorkerUtils.send({cmd: "b64.decode", id: _req_id});
            WorkerUtils.send(data);
        }

        private function onmsg(e : HEvent) : void {
            var msg : Object = e.data;
            if (!_req_id || _req_id!=msg.id || msg.cmd!="b64.decode")
                return;
            on_decoded_data(WorkerUtils.recv());
        }

        private function on_decoded_data(data : ByteArray) : void {
            if (data)
            {
                data.position = 0;
                if (_resource)
                {
                    var prev : uint = _resource.position;
                    data.readBytes(_resource, _resource.length);
                    _resource.position = prev;
                }
                else
                    _resource = data;
                // XXX arik: get finalLength from js
                var finalLength : uint = _resource.length;
                dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false,
                    false, _resource.length, finalLength));
            }
            // XXX arik: dispatch httpStatus/httpResponseStatus
            if (_curr_data.status)
                resourceLoadingSuccess();
        }

        private function on_fragment_data(o : Object) : void {
            _curr_data = o;
            if (o.error)
                return resourceLoadingError();
            if (o.fetchBinReqId)
                return fetch_bin(o);
            decode(o.data);
        }

        private function fetch_bin(o : Object) : void {
            if (!(o.fetchBinReq = FlashFetchBin.req_list[o.fetchBinReqId]))
                throw new Error('fetchBinReqId not found '+o.fetchBinReqId);
            _fetch_bin(o);
        }

        private function _fetch_bin(o : Object) : void {
            var fetchBinStream : URLStream = o.fetchBinReq.stream;
            _resource = _resource || new ByteArray();
            var prev : Number = _resource.position;
            var len : Number = Math.min(fetchBinStream.bytesAvailable,
                HSettings.fetch_bin_chunk_size);
            if (len)
            {
                fetchBinStream.readBytes(_resource, _resource.length, len);
                _resource.position = prev;
                dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false,
                    false, _resource.length, o.fetchBinReq.bytesTotal));
            }
            if (_resource.length < o.fetchBinReq.bytesTotal)
            {
                FlashFetchBin.consumeDataTimeout(o.fetchBinReqId,
                    _fetch_bin, HSettings.fetch_bin_delay, o);
            }
            else
            {
                resourceLoadingSuccess();
                FlashFetchBin.hola_fetchBinRemove(o.fetchBinReqId);
            }
        }

        private static function hola_onFragmentData(o : Object) : void {
            var stream : JSURLStream;
            try {
                if (!(stream = reqs[o.req_id]))
                    return ZErr.log('req_id not found '+o.req_id);
                stream.on_fragment_data(o);
            } catch(err : Error){
                ZErr.log('Error in hola_onFragmentData', ''+err,
                    ''+err.getStackTrace());
                if (stream)
                    stream.resourceLoadingError();
                throw err;
            }
        }

        private function _delete() : void {
            delete reqs[_req_id];
        }

        protected function resourceLoadingError() : void {
            _delete();
            dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR));
        }

        protected function resourceLoadingSuccess() : void {
            _delete();
            dispatchEvent(new Event(Event.COMPLETE));
        }
    }
}

support older compiler

support older compiler


package {

    import flash.display.Sprite;
    import krewfw.KrewConfig;
    import krewfw.utils.krew;

    /**
     * Customize options or components for Flash publishing.
     */
    public class WebMain extends Sprite {

        public function WebMain() {
            krew.log("Kicked from WebMain");

            KrewConfig.IS_AIR = false;
            KrewConfig.ASSET_URL_SCHEME = "http://uri/to/assets/";

            var main:Main = new Main(this);
        }
    }
}

package {

    import flash.display.Sprite;
    import krewfw.KrewConfig;
    import krewfw.utils.krew;

    /**
     * Customize options or components for Flash publishing.
     */
    public class WebMain extends Sprite {

        public function WebMain() {
            krew.log("Kicked from WebMain");

            KrewConfig.IS_AIR = false;
            KrewConfig.ASSET_URL_SCHEME = "http://docs.tatsuya-koyama.com/assets/media/swf/krewsample/";

            var main:Main = new Main(this);
        }
    }
}

Modify sample web project

Modify sample web project


package aerys.minko.scene.controller.debug
{
	import aerys.minko.render.geometry.primitive.CubeGeometry;
	import aerys.minko.render.material.Material;
	import aerys.minko.render.material.basic.BasicMaterial;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.mesh.skinning.SkinningController;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.type.enum.DepthTest;
	import aerys.minko.type.math.Vector4;

	/**
	 * Add debug meshes to see the joints/bones of the skeleton of a skinned Mesh.
	 * This controller can target all the meshes with a SkinningController:
	 *
	 * <pre>
	 * var debugCtrl : JointsDebugController = new JointsDebugController();
	 *
	 * for each (var mesh : Mesh in scene.get('//mesh[hasController(SkinningController)]'))
	 *   mesh.addController(debugCtrl);
	 * </pre>
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class JointsDebugController extends AbstractController
	{
		private var _jointsMaterial	: Material;

		public function JointsDebugController(jointsMaterial : Material	= null)
		{
			super(Mesh);

			initialize(jointsMaterial);
		}

		private function initialize(jointsMaterial	: Material) : void
		{
			_jointsMaterial = jointsMaterial;
			if (!_jointsMaterial)
			{
				var jointsBasicMaterial : BasicMaterial = new BasicMaterial();

				jointsBasicMaterial.diffuseColor = 0xff0000ff;
				jointsBasicMaterial.depthWriteEnabled = false;
				jointsBasicMaterial.depthTest = DepthTest.ALWAYS;
				_jointsMaterial = jointsBasicMaterial;
			}

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

		private function targetAddedHandler(ctrl	: AbstractController,
											target	: Mesh) : void
		{
			var skinningCtrl : SkinningController = target.getControllersByType(SkinningController)[0]
				as SkinningController;

			for each (var joint : Group in skinningCtrl.joints)
				addJointsMeshes(joint);
		}

		private function targetRemovedHandler(ctrl 		: AbstractController,
											  target	: Mesh) : void
		{
			var skinningCtrl : SkinningController = target.getControllersByType(SkinningController)[0]
				as SkinningController;

			for each (var joint : Group in skinningCtrl.joints)
				joint.getChildByName('__joint__').parent = null;
		}

		private function addJointsMeshes(joint : Group) : void
		{
			if (joint.getChildByName('__joint__'))
				return ;

			var numChildren : uint = joint.numChildren;

			for (var i : uint = 0; i < numChildren; ++i)
			{
				var child : Group = joint.getChildAt(i) as Group;

				if (child != null)
				{
					var jointMesh   : Mesh  = new Mesh(
						CubeGeometry.cubeGeometry, _jointsMaterial, '__joint__'
					);

					jointMesh.transform.appendUniformScale(.08);
					joint.addChild(jointMesh);
				}
			}
		}
	}
}

package aerys.minko.scene.controller.debug
{
	import aerys.minko.render.geometry.primitive.CubeGeometry;
	import aerys.minko.render.material.Material;
	import aerys.minko.render.material.basic.BasicMaterial;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.mesh.skinning.SkinningController;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.type.enum.DepthTest;
	import aerys.minko.type.math.Vector4;

	/**
	 * Add debug meshes to see the joints/bones of the skeleton of a skinned Mesh.
	 * This controller can target all the meshes with a SkinningController:
	 *
	 * <pre>
	 * var debugCtrl : JointsDebugController = new JointsDebugController();
	 *
	 * for each (var mesh : Mesh in scene.get('//mesh[hasController(SkinningController)]'))
	 *   mesh.addController(debugCtrl);
	 * </pre>
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class JointsDebugController extends AbstractController
	{
		private var _jointSize		: Number;
		private var _jointsMaterial	: Material;

		public function JointsDebugController(jointsSize		: Number	= 0.08,
											  jointsMaterial 	: Material	= null)
		{
			super(Mesh);

			initialize(jointsSize, jointsMaterial);
		}

		private function initialize(jointSize : Number, jointsMaterial	: Material) : void
		{
			_jointSize = jointSize;
			_jointsMaterial = jointsMaterial;
			if (!_jointsMaterial)
			{
				var jointsBasicMaterial : BasicMaterial = new BasicMaterial();

				jointsBasicMaterial.diffuseColor = 0xff0000ff;
				jointsBasicMaterial.depthWriteEnabled = false;
				jointsBasicMaterial.depthTest = DepthTest.ALWAYS;
				_jointsMaterial = jointsBasicMaterial;
			}

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

		private function targetAddedHandler(ctrl	: AbstractController,
											target	: Mesh) : void
		{
			var skinningCtrl : SkinningController = target.getControllersByType(SkinningController)[0]
				as SkinningController;

			for each (var joint : Group in skinningCtrl.joints)
				addJointsMeshes(joint);
		}

		private function targetRemovedHandler(ctrl 		: AbstractController,
											  target	: Mesh) : void
		{
			var skinningCtrl : SkinningController = target.getControllersByType(SkinningController)[0]
				as SkinningController;

			for each (var joint : Group in skinningCtrl.joints)
				joint.getChildByName('__joint__').parent = null;
		}

		private function addJointsMeshes(joint : Group) : void
		{
			if (joint.getChildByName('__joint__'))
				return ;

			var numChildren : uint = joint.numChildren;

			for (var i : uint = 0; i < numChildren; ++i)
			{
				var child : Group = joint.getChildAt(i) as Group;

				if (child != null)
				{
					var jointMesh   : Mesh  = new Mesh(
						CubeGeometry.cubeGeometry, _jointsMaterial, '__joint__'
					);

					jointMesh.transform.appendUniformScale(_jointSize);
					joint.addChild(jointMesh);
				}
			}
		}
	}
}

add customizable size for the joints debug meshes