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

    import mx.states.AddItems;
    import mx.states.SetEventHandler;
    import mx.states.SetProperty;
    import mx.states.State;

    import org.apache.flex.core.IParent;
    import org.apache.flex.core.IStatesObject;
    import org.apache.flex.effects.Effect;
    import org.apache.flex.events.Event;
    import org.apache.flex.events.EventDispatcher;
    import org.apache.flex.events.IEventDispatcher;
    import org.apache.flex.events.ValueChangeEvent;
    import org.apache.flex.states.Transition;
    import org.apache.flex.utils.MXMLDataInterpreter;

    /**
     *  The StatesWithTransitionsImpl class implements a set of
     *  view state functionality that includes transitions between states.
     *  It only supports AddItems and SetProperty and SetEventHandler
     *  changes at this time.
     *
     *  @flexjsignoreimport org.apache.flex.core.IStatesObject
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
	public class StatesWithTransitionsImpl extends EventDispatcher implements IStatesImpl, IBead
	{
        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function StatesWithTransitionsImpl()
		{
			super();
		}

        private var _strand:IStrand;

        private var sawInitComplete:Boolean;

        /**
         *  @copy org.apache.flex.core.IBead#strand
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function set strand(value:IStrand):void
        {
            _strand = value;
            IEventDispatcher(_strand).addEventListener("currentStateChange", stateChangeHandler);
            IEventDispatcher(_strand).addEventListener("initComplete", initialStateHandler);
        }

        /**
         *  @private
         *  @flexjsignorecoercion org.apache.flex.core.IStatesObject
         */
        private function initialStateHandler(event:org.apache.flex.events.Event):void
        {
            sawInitComplete = true;
            stateChangeHandler(new ValueChangeEvent("currentStateChange", false, false, null,
                IStatesObject(_strand).currentState));
        }

        /**
         *  @private
         *  @flexjsignorecoercion org.apache.flex.core.IStatesObject
         */
        private function stateChangeHandler(event:ValueChangeEvent):void
        {
            if (!sawInitComplete)
                return;

            var doc:IStatesObject = _strand as IStatesObject;
            var transitions:Array = doc.transitions;
            if (transitions && transitions.length > 0)
            {
                for each (var t:Transition in transitions)
                {
                    if (t.fromState == "*" || t.fromState == event.oldValue)
                    {
                        if (t.toState == "*" || t.toState == event.newValue)
                        {
                            transitionEffects = t.effects.slice();
                            for each (var e:Effect in transitionEffects)
                            {
                                e.captureStartValues();
                            }
                            break;
                        }
                    }
                }
            }
            var arr:Array = doc.states;
            for each (var s:State in arr)
            {
                if (s.name == event.oldValue)
                {
                    revert(s);
                    break;
                }
            }
            for each (s in arr)
            {
                if (s.name == event.newValue)
                {
                    apply(s);
                    break;
                }
            }
            if (transitionEffects && transitionEffects.length > 0)
            {
                for each (e in transitionEffects)
                {
                    e.captureEndValues();
                }
            }
            var playingTransition:Boolean;
            if (transitionEffects && transitionEffects.length > 0)
            {
                playingTransition = true;
                for each (e in transitionEffects)
                {
                    e.addEventListener(Effect.EFFECT_END, effectEndHandler);
                    e.play();
                }
            }
            if (!playingTransition)
                doc.dispatchEvent(new Event("stateChangeComplete"));
        }

        private var transitionEffects:Array;

        /**
         *  @private
         *  @flexjsignorecoercion org.apache.flex.core.IStatesObject
         */
        private function effectEndHandler(event:Event):void
        {
            // in case of extraneous calls to effectEndHandler
            if (transitionEffects == null)
                return;

            var n:int = transitionEffects.length;
            for (var i:int = 0; i < n; i++)
            {
                event.target.removeEventListener(Effect.EFFECT_END, effectEndHandler);
                if (transitionEffects[i] == event.target)
                    transitionEffects.splice(i, 1);
            }
            if (transitionEffects.length == 0)
            {
                transitionEffects = null;
                var doc:IStatesObject = _strand as IStatesObject;
                doc.dispatchEvent(new Event("stateChangeComplete"));
            }
        }

        private function revert(s:State):void
        {
            var arr:Array = s.overrides;
            for each (var o:Object in arr)
            {
                if (o is AddItems)
                {
                    var ai:AddItems = AddItems(o);
                    for each (var item:IChild in ai.items)
                    {
                        var parent:IParent = item.parent as IParent;
                        parent.removeElement(item);
                    }
                    if (parent is IContainer)
                        IContainer(parent).childrenAdded();
                }
                else if (o is SetProperty)
                {
                    var sp:SetProperty = SetProperty(o);
                    if (sp.target != null)
                        setProperty(getProperty(sp.document, sp.target), sp.name, sp.previousValue);
                    else
                        setProperty(sp.document, sp.name, sp.previousValue);
                }
                else if (o is SetEventHandler)
                {
                    var seh:SetEventHandler = SetEventHandler(o);
                    if (seh.target != null)
                    {
                        getProperty(seh.document, seh.target).removeEventListener(seh.name, seh.handlerFunction);
                    }
                    else
                    {
                        seh.document.removeEventListener(seh.name, seh.handlerFunction);
                    }
                }
            }
        }

        private function apply(s:State):void
        {
            var arr:Array = s.overrides;
            for each (var o:Object in arr)
            {
                if (o is AddItems)
                {
                    var ai:AddItems = AddItems(o);
                    if (ai.items == null)
                    {
                        ai.items = ai.itemsDescriptor.items as Array;
                        if (ai.items == null)
                        {
                            ai.items =
                                MXMLDataInterpreter.generateMXMLArray(ai.document,
                                    null, ai.itemsDescriptor.descriptor);
                            ai.itemsDescriptor.items = ai.items;
                        }
                    }
                    for each (var item:Object in ai.items)
                    {
                        var parent:IParent = ai.document as IParent;
                        if (ai.destination != null)
                            parent = parent[ai.destination] as IParent;
                        if (ai.relativeTo != null)
                        {
                            var child:Object = ai.document[ai.relativeTo];
                            if (ai.destination == null)
                                parent = child.parent as IParent;
                            var index:int = parent.getElementIndex(child);
                            if (ai.position == "after")
                                index++;
                            parent.addElementAt(item, index);
                        }
                        else
                        {
                            parent.addElement(item);
                        }
                    }
                    if (parent is IContainer)
                        IContainer(parent).childrenAdded();
                }
                else if (o is SetProperty)
                {
                    var sp:SetProperty = SetProperty(o);
                    if (sp.target != null)
                    {
                        sp.previousValue = getProperty(getProperty(sp.document, sp.target), sp.name);
                        setProperty(getProperty(sp.document, sp.target), sp.name, sp.value);
                    }
                    else
                    {
                        sp.previousValue = getProperty(sp.document, sp.name);
                        setProperty(sp.document, sp.name, sp.value);
                    }
                }
                else if (o is SetEventHandler)
                {
                    var seh:SetEventHandler = SetEventHandler(o);
                    if (seh.target != null)
                    {
                        getProperty(seh.document, seh.target).addEventListener(seh.name, seh.handlerFunction);
                    }
                    else
                    {
                        seh.document.addEventListener(seh.name, seh.handlerFunction);
                    }
                }
            }
        }
	}
}

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

    import mx.states.AddItems;
    import mx.states.SetEventHandler;
    import mx.states.SetProperty;
    import mx.states.State;

    import org.apache.flex.core.IParent;
    import org.apache.flex.core.IStatesObject;
    import org.apache.flex.effects.Effect;
    import org.apache.flex.events.Event;
    import org.apache.flex.events.EventDispatcher;
    import org.apache.flex.events.IEventDispatcher;
    import org.apache.flex.events.ValueChangeEvent;
    import org.apache.flex.states.Transition;
    import org.apache.flex.utils.MXMLDataInterpreter;

    /**
     *  The StatesWithTransitionsImpl class implements a set of
     *  view state functionality that includes transitions between states.
     *  It only supports AddItems and SetProperty and SetEventHandler
     *  changes at this time.
     *
     *  @flexjsignoreimport org.apache.flex.core.IStatesObject
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
	public class StatesWithTransitionsImpl extends EventDispatcher implements IStatesImpl, IBead
	{
        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function StatesWithTransitionsImpl()
		{
			super();
		}

        private var _strand:IStrand;

        private var sawInitComplete:Boolean;

        /**
         *  @copy org.apache.flex.core.IBead#strand
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function set strand(value:IStrand):void
        {
            _strand = value;
            IEventDispatcher(_strand).addEventListener("currentStateChange", stateChangeHandler);
            IEventDispatcher(_strand).addEventListener("initComplete", initialStateHandler);
        }

        /**
         *  @private
         *  @flexjsignorecoercion org.apache.flex.core.IStatesObject
         */
        private function initialStateHandler(event:org.apache.flex.events.Event):void
        {
            sawInitComplete = true;
            stateChangeHandler(new ValueChangeEvent("currentStateChange", false, false, null,
                IStatesObject(_strand).currentState));
        }

        /**
         *  @private
         *  @flexjsignorecoercion org.apache.flex.core.IStatesObject
         */
        private function stateChangeHandler(event:ValueChangeEvent):void
        {
            if (!sawInitComplete)
                return;

            var doc:IStatesObject = _strand as IStatesObject;
            var transitions:Array = doc.transitions;
            if (transitions && transitions.length > 0)
            {
                for each (var t:Transition in transitions)
                {
                    if (t.fromState == "*" || t.fromState == event.oldValue)
                    {
                        if (t.toState == "*" || t.toState == event.newValue)
                        {
                            transitionEffects = t.effects.slice();
                            for each (var e:Effect in transitionEffects)
                            {
                                e.captureStartValues();
                            }
                            break;
                        }
                    }
                }
            }
            var arr:Array = doc.states;
            for each (var s:State in arr)
            {
                if (s.name == event.oldValue)
                {
                    revert(s);
                    break;
                }
            }
            for each (s in arr)
            {
                if (s.name == event.newValue)
                {
                    apply(s);
                    break;
                }
            }
            if (transitionEffects && transitionEffects.length > 0)
            {
                for each (e in transitionEffects)
                {
                    e.captureEndValues();
                }
            }
            var playingTransition:Boolean;
            if (transitionEffects && transitionEffects.length > 0)
            {
                playingTransition = true;
                for each (e in transitionEffects)
                {
                    e.addEventListener(Effect.EFFECT_END, effectEndHandler);
                    e.play();
                }
            }
            if (!playingTransition)
                doc.dispatchEvent(new Event("stateChangeComplete"));
        }

        private var transitionEffects:Array;

        /**
         *  @private
         *  @flexjsignorecoercion org.apache.flex.core.IStatesObject
         */
        private function effectEndHandler(event:Event):void
        {
            // in case of extraneous calls to effectEndHandler
            if (transitionEffects == null)
                return;

            var n:int = transitionEffects.length;
            for (var i:int = 0; i < n; i++)
            {
                event.target.removeEventListener(Effect.EFFECT_END, effectEndHandler);
                if (transitionEffects[i] == event.target)
                    transitionEffects.splice(i, 1);
            }
            if (transitionEffects.length == 0)
            {
                transitionEffects = null;
                var doc:IStatesObject = _strand as IStatesObject;
                doc.dispatchEvent(new Event("stateChangeComplete"));
            }
        }

        private function revert(s:State):void
        {
            var arr:Array = s.overrides;
            for each (var o:Object in arr)
            {
                if (o is AddItems)
                {
                    var ai:AddItems = AddItems(o);
                    for each (var item:IChild in ai.items)
                    {
                        var parent:IParent = item.parent as IParent;
                        parent.removeElement(item);
                    }
                    if (parent is IContainer)
                        IContainer(parent).childrenAdded();
                }
                else if (o is SetProperty)
                {
                    var sp:SetProperty = SetProperty(o);
                    if (sp.target != null)
                        setProperty(getProperty(sp.document, sp.target), sp.name, sp.previousValue);
                    else
                        setProperty(sp.document, sp.name, sp.previousValue);
                }
                else if (o is SetEventHandler)
                {
                    var seh:SetEventHandler = SetEventHandler(o);
                    if (seh.target != null)
                    {
                        getProperty(seh.document, seh.target).removeEventListener(seh.name, seh.handlerFunction);
                    }
                    else
                    {
                        seh.document.removeEventListener(seh.name, seh.handlerFunction);
                    }
                }
            }
        }

        private function apply(s:State):void
        {
            var arr:Array = s.overrides;
            for each (var o:Object in arr)
            {
                if (o is AddItems)
                {
                    var ai:AddItems = AddItems(o);
                    if (ai.items == null)
                    {
                        ai.items = ai.itemsDescriptor.items as Array;
                        if (ai.items == null)
                        {
                            ai.items =
                                MXMLDataInterpreter.generateMXMLArray(ai.document,
                                    null, ai.itemsDescriptor.descriptor);
                            ai.itemsDescriptor.items = ai.items;
                        }
                    }
                    for each (var item:Object in ai.items)
                    {
                        var parent:IParent = ai.document as IParent;
                        if (ai.destination)
                            parent = getProperty(parent, ai.destination) as IParent;
                        if (ai.relativeTo != null)
                        {
                            var child:Object = getProperty(ai.document, ai.relativeTo);
                            if (ai.destination)
                                parent = IChild(child).parent as IParent;
                            var index:int = parent.getElementIndex(child);
                            if (ai.position == "after")
                                index++;
                            parent.addElementAt(item, index);
                        }
                        else
                        {
                            parent.addElement(item);
                        }
                    }
                    if (parent is IContainer)
                        IContainer(parent).childrenAdded();
                }
                else if (o is SetProperty)
                {
                    var sp:SetProperty = SetProperty(o);
                    if (sp.target != null)
                    {
                        sp.previousValue = getProperty(getProperty(sp.document, sp.target), sp.name);
                        setProperty(getProperty(sp.document, sp.target), sp.name, sp.value);
                    }
                    else
                    {
                        sp.previousValue = getProperty(sp.document, sp.name);
                        setProperty(sp.document, sp.name, sp.value);
                    }
                }
                else if (o is SetEventHandler)
                {
                    var seh:SetEventHandler = SetEventHandler(o);
                    if (seh.target != null)
                    {
                        getProperty(seh.document, seh.target).addEventListener(seh.name, seh.handlerFunction);
                    }
                    else
                    {
                        seh.document.addEventListener(seh.name, seh.handlerFunction);
                    }
                }
            }
        }
	}
}

handle property fetches

handle property fetches


// Huge object count example.
// This sample demonstrates:
//     - Creating a scene with 250 x 250 simple objects
//     - Competing with http://yosoygames.com.ar/wp/2013/07/ogre-2-0-is-up-to-3x-faster/ :)
//     - Allowing examination of performance hotspots in the rendering code
//     - Optionally speeding up rendering by grouping objects with the StaticModelGroup component

#include "Scripts/Utilities/Sample.as"

Array<Node@> boxNodes;
bool animate = false;
bool useGroups = false;

void Start()
{
    // Execute the common startup for samples
    SampleStart();

    // Create the scene content
    CreateScene();

    // Create the UI content
    CreateInstructions();

    // Setup the viewport for displaying the scene
    SetupViewport();

    // Hook up to the frame update events
    SubscribeToEvents();
}

void CreateScene()
{
    if (scene_ is null)
        scene_ = Scene();
    else
    {
        scene_.Clear();
        boxNodes.Clear();
    }

    // Create the Octree component to the scene so that drawable objects can be rendered. Use default volume
    // (-1000, -1000, -1000) to (1000, 1000, 1000)
    scene_.CreateComponent("Octree");

    // Create a Zone for ambient light & fog control
    Node@ zoneNode = scene_.CreateChild("Zone");
    Zone@ zone = zoneNode.CreateComponent("Zone");
    zone.boundingBox = BoundingBox(-1000.0f, 1000.0f);
    zone.fogColor = Color(0.2f, 0.2f, 0.2f);
    zone.fogStart = 200.0f;
    zone.fogEnd = 300.0f;

    // Create a directional light
    Node@ lightNode = scene_.CreateChild("DirectionalLight");
    lightNode.direction = Vector3(-0.6f, -1.0f, -0.8f); // The direction vector does not need to be normalized
    Light@ light = lightNode.CreateComponent("Light");
    light.lightType = LIGHT_DIRECTIONAL;
    light.castShadows = true;

    {
        // Create a floor object, 1000 x 1000 world units. Adjust position so that the ground is at zero Y
        Node@ floorNode = scene_.CreateChild("Floor");
        floorNode.position = Vector3(0.0f, -2.0f, 0.0f);
        floorNode.scale = Vector3(100.0f, 1.0f, 100.0f);
        StaticModel@ floorObject = floorNode.CreateComponent("StaticModel");
        floorObject.model = cache.GetResource("Model", "Models/Box.mdl");

        // Make the floor physical by adding RigidBody and CollisionShape components. The RigidBody's default
        // parameters make the object static (zero mass.) Note that a CollisionShape by itself will not participate
        // in the physics simulation
        RigidBody@ body = floorNode.CreateComponent("RigidBody");
        CollisionShape@ shape = floorNode.CreateComponent("CollisionShape");
        // Set a box shape of size 1 x 1 x 1 for collision. The shape will be scaled with the scene node scale, so the
        // rendering and physics representation sizes should match (the box model is also 1 x 1 x 1.)
        shape.SetBox(Vector3(1.0f, 1.0f, 1.0f));
    }

    if (!useGroups)
    {
        light.color = Color(0.7f, 0.35f, 0.0f);

        // Create individual box StaticModels in the scene
        for (int y = -125; y < 125; ++y)
        {
            for (int x = -125; x < 125; ++x)
            {
                Node@ boxNode = scene_.CreateChild("Box");
                boxNode.position = Vector3(x * 0.3f, 0.0f, y * 0.3f);
                boxNode.SetScale(0.25f);
                StaticModel@ boxObject = boxNode.CreateComponent("StaticModel");
                boxObject.castShadows = true;
                boxObject.model = cache.GetResource("Model", "Models/Plane.mdl");
                boxObject.material = cache.GetResource("Material", "Materials/List.xml");
                boxNodes.Push(boxNode);
            }
        }
    }
    else
    {
        light.color = Color(0.6f, 0.6f, 0.6f);
        light.specularIntensity = 1.5f;

        // Create StaticModelGroups in the scene
        StaticModelGroup@ lastGroup;

        for (int y = -125; y < 125; ++y)
        {
            for (int x = -125; x < 125; ++x)
            {
                // Create new group if no group yet, or the group has already "enough" objects. The tradeoff is between culling
                // accuracy and the amount of CPU processing needed for all the objects. Note that the group's own transform
                // does not matter, and it does not render anything if instance nodes are not added to it
                if (lastGroup is null || lastGroup.numInstanceNodes >= 25 * 25)
                {
                    Node@ boxGroupNode = scene_.CreateChild("BoxGroup");
                    lastGroup = boxGroupNode.CreateComponent("StaticModelGroup");
                    lastGroup.model = cache.GetResource("Model", "Models/Plane.mdl");
                    lastGroup.material = cache.GetResource("Material", "Materials/List.xml");
                    lastGroup.castShadows = true;
                }

                Node@ boxNode = scene_.CreateChild("Box");
                boxNode.position = Vector3(x * 0.3f, 0.0f, y * 0.3f);
                boxNode.SetScale(0.25f);
                boxNodes.Push(boxNode);
                lastGroup.AddInstanceNode(boxNode);
            }
        }
    }

    // Create the camera. Create it outside the scene so that we can clear the whole scene without affecting it
    if (cameraNode is null)
    {
        cameraNode = Node("Camera");
        cameraNode.position = Vector3(0.0f, 10.0f, -100.0f);
        Camera@ camera = cameraNode.CreateComponent("Camera");
        camera.farClip = 300.0f;
    }
}

void CreateInstructions()
{
    // Construct new Text object, set string to display and font to use
    Text@ instructionText = ui.root.CreateChild("Text");
    instructionText.text =
        "Use WASD keys and mouse to move\n"
        "Space to toggle animation\n"
        "G to toggle object group optimization";
    instructionText.SetFont(cache.GetResource("Font", "Fonts/Anonymous Pro.ttf"), 15);
    // The text has multiple rows. Center them in relation to each other
    instructionText.textAlignment = HA_CENTER;

    // Position the text relative to the screen center
    instructionText.horizontalAlignment = HA_CENTER;
    instructionText.verticalAlignment = VA_CENTER;
    instructionText.SetPosition(0, ui.root.height / 4);
}

void SetupViewport()
{
    // Set up a viewport to the Renderer subsystem so that the 3D scene can be seen
    Viewport@ viewport = Viewport(scene_, cameraNode.GetComponent("Camera"));
    renderer.viewports[0] = viewport;
}

void SubscribeToEvents()
{
    // Subscribe HandleUpdate() function for processing update events
    SubscribeToEvent("Update", "HandleUpdate");
}

void MoveCamera(float timeStep)
{
    // Do not move if the UI has a focused element (the console)
    if (ui.focusElement !is null)
        return;

    // Movement speed as world units per second
    const float MOVE_SPEED = 20.0f;
    // Mouse sensitivity as degrees per pixel
    const float MOUSE_SENSITIVITY = 0.1f;

    // Use this frame's mouse motion to adjust camera node yaw and pitch. Clamp the pitch between -90 and 90 degrees
    IntVector2 mouseMove = input.mouseMove;
    yaw += MOUSE_SENSITIVITY * mouseMove.x;
    pitch += MOUSE_SENSITIVITY * mouseMove.y;
    pitch = Clamp(pitch, -90.0f, 90.0f);

    // Construct new orientation for the camera scene node from yaw and pitch. Roll is fixed to zero
    cameraNode.rotation = Quaternion(pitch, yaw, 0.0f);

    // Read WASD keys and move the camera scene node to the corresponding direction if they are pressed
    if (input.keyDown['W'])
        cameraNode.Translate(Vector3(0.0f, 0.0f, 1.0f) * MOVE_SPEED * timeStep);
    if (input.keyDown['S'])
        cameraNode.Translate(Vector3(0.0f, 0.0f, -1.0f) * MOVE_SPEED * timeStep);
    if (input.keyDown['A'])
        cameraNode.Translate(Vector3(-1.0f, 0.0f, 0.0f) * MOVE_SPEED * timeStep);
    if (input.keyDown['D'])
        cameraNode.Translate(Vector3(1.0f, 0.0f, 0.0f) * MOVE_SPEED * timeStep);
}

void AnimateObjects(float timeStep)
{
    const float ROTATE_SPEED = 15.0f;
    // Rotate about the Z axis (roll)
    Quaternion rotateQuat(ROTATE_SPEED * timeStep, Vector3(0.0f, 0.0f, 1.0f));

    for (uint i = 0; i < boxNodes.length; ++i)
        boxNodes[i].Rotate(rotateQuat);
}

void HandleUpdate(StringHash eventType, VariantMap& eventData)
{
    // Take the frame time step, which is stored as a float
    float timeStep = eventData["TimeStep"].GetFloat();

    // Toggle animation with space
    if (input.keyPress[KEY_SPACE])
        animate = !animate;

    // Toggle grouped / ungrouped mode
    if (input.keyPress['G'])
    {
        useGroups = !useGroups;
        CreateScene();
    }

    // Move the camera, scale movement with time step
    MoveCamera(timeStep);

    // Animate scene if enabled
    if (animate)
        AnimateObjects(timeStep);
}

// Create XML patch instructions for screen joystick layout specific to this sample app
String patchInstructions =
        "<patch>" +
        "    <remove sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]/attribute[@name='Is Visible']\" />" +
        "    <replace sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]/element[./attribute[@name='Name' and @value='Label']]/attribute[@name='Text']/@value\">Group</replace>" +
        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]\">" +
        "        <element type=\"Text\">" +
        "            <attribute name=\"Name\" value=\"KeyBinding\" />" +
        "            <attribute name=\"Text\" value=\"G\" />" +
        "        </element>" +
        "    </add>" +
        "    <remove sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]/attribute[@name='Is Visible']\" />" +
        "    <replace sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]/element[./attribute[@name='Name' and @value='Label']]/attribute[@name='Text']/@value\">Animation</replace>" +
        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]\">" +
        "        <element type=\"Text\">" +
        "            <attribute name=\"Name\" value=\"KeyBinding\" />" +
        "            <attribute name=\"Text\" value=\"SPACE\" />" +
        "        </element>" +
        "    </add>" +
        "</patch>";

// Huge object count example.
// This sample demonstrates:
//     - Creating a scene with 250 x 250 simple objects
//     - Competing with http://yosoygames.com.ar/wp/2013/07/ogre-2-0-is-up-to-3x-faster/ :)
//     - Allowing examination of performance hotspots in the rendering code
//     - Optionally speeding up rendering by grouping objects with the StaticModelGroup component

#include "Scripts/Utilities/Sample.as"

Array<Node@> boxNodes;
bool animate = false;
bool useGroups = false;

void Start()
{
    // Execute the common startup for samples
    SampleStart();

    // Create the scene content
    CreateScene();

    // Create the UI content
    CreateInstructions();

    // Setup the viewport for displaying the scene
    SetupViewport();

    // Hook up to the frame update events
    SubscribeToEvents();
}

void CreateScene()
{
    if (scene_ is null)
        scene_ = Scene();
    else
    {
        scene_.Clear();
        boxNodes.Clear();
    }

    // Create the Octree component to the scene so that drawable objects can be rendered. Use default volume
    // (-1000, -1000, -1000) to (1000, 1000, 1000)
    scene_.CreateComponent("Octree");

    // Create a Zone for ambient light & fog control
    Node@ zoneNode = scene_.CreateChild("Zone");
    Zone@ zone = zoneNode.CreateComponent("Zone");
    zone.boundingBox = BoundingBox(-1000.0f, 1000.0f);
    zone.fogColor = Color(0.2f, 0.2f, 0.2f);
    zone.fogStart = 200.0f;
    zone.fogEnd = 300.0f;

    // Create a directional light
    Node@ lightNode = scene_.CreateChild("DirectionalLight");
    lightNode.direction = Vector3(-0.6f, -1.0f, -0.8f); // The direction vector does not need to be normalized
    Light@ light = lightNode.CreateComponent("Light");
    light.lightType = LIGHT_DIRECTIONAL;

    if (!useGroups)
    {
        light.color = Color(0.7f, 0.35f, 0.0f);

        // Create individual box StaticModels in the scene
        for (int y = -125; y < 125; ++y)
        {
            for (int x = -125; x < 125; ++x)
            {
                Node@ boxNode = scene_.CreateChild("Box");
                boxNode.position = Vector3(x * 0.3f, 0.0f, y * 0.3f);
                boxNode.SetScale(0.25f);
                StaticModel@ boxObject = boxNode.CreateComponent("StaticModel");
                boxObject.model = cache.GetResource("Model", "Models/Box.mdl");
                boxNodes.Push(boxNode);
            }
        }
    }
    else
    {
        light.color = Color(0.6f, 0.6f, 0.6f);
        light.specularIntensity = 1.5f;

        // Create StaticModelGroups in the scene
        StaticModelGroup@ lastGroup;

        for (int y = -125; y < 125; ++y)
        {
            for (int x = -125; x < 125; ++x)
            {
                // Create new group if no group yet, or the group has already "enough" objects. The tradeoff is between culling
                // accuracy and the amount of CPU processing needed for all the objects. Note that the group's own transform
                // does not matter, and it does not render anything if instance nodes are not added to it
                if (lastGroup is null || lastGroup.numInstanceNodes >= 25 * 25)
                {
                    Node@ boxGroupNode = scene_.CreateChild("BoxGroup");
                    lastGroup = boxGroupNode.CreateComponent("StaticModelGroup");
                    lastGroup.model = cache.GetResource("Model", "Models/Box.mdl");
                }

                Node@ boxNode = scene_.CreateChild("Box");
                boxNode.position = Vector3(x * 0.3f, 0.0f, y * 0.3f);
                boxNode.SetScale(0.25f);
                boxNodes.Push(boxNode);
                lastGroup.AddInstanceNode(boxNode);
            }
        }
    }

    // Create the camera. Create it outside the scene so that we can clear the whole scene without affecting it
    if (cameraNode is null)
    {
        cameraNode = Node("Camera");
        cameraNode.position = Vector3(0.0f, 10.0f, -100.0f);
        Camera@ camera = cameraNode.CreateComponent("Camera");
        camera.farClip = 300.0f;
    }
}

void CreateInstructions()
{
    // Construct new Text object, set string to display and font to use
    Text@ instructionText = ui.root.CreateChild("Text");
    instructionText.text =
        "Use WASD keys and mouse to move\n"
        "Space to toggle animation\n"
        "G to toggle object group optimization";
    instructionText.SetFont(cache.GetResource("Font", "Fonts/Anonymous Pro.ttf"), 15);
    // The text has multiple rows. Center them in relation to each other
    instructionText.textAlignment = HA_CENTER;

    // Position the text relative to the screen center
    instructionText.horizontalAlignment = HA_CENTER;
    instructionText.verticalAlignment = VA_CENTER;
    instructionText.SetPosition(0, ui.root.height / 4);
}

void SetupViewport()
{
    // Set up a viewport to the Renderer subsystem so that the 3D scene can be seen
    Viewport@ viewport = Viewport(scene_, cameraNode.GetComponent("Camera"));
    renderer.viewports[0] = viewport;
}

void SubscribeToEvents()
{
    // Subscribe HandleUpdate() function for processing update events
    SubscribeToEvent("Update", "HandleUpdate");
}

void MoveCamera(float timeStep)
{
    // Do not move if the UI has a focused element (the console)
    if (ui.focusElement !is null)
        return;

    // Movement speed as world units per second
    const float MOVE_SPEED = 20.0f;
    // Mouse sensitivity as degrees per pixel
    const float MOUSE_SENSITIVITY = 0.1f;

    // Use this frame's mouse motion to adjust camera node yaw and pitch. Clamp the pitch between -90 and 90 degrees
    IntVector2 mouseMove = input.mouseMove;
    yaw += MOUSE_SENSITIVITY * mouseMove.x;
    pitch += MOUSE_SENSITIVITY * mouseMove.y;
    pitch = Clamp(pitch, -90.0f, 90.0f);

    // Construct new orientation for the camera scene node from yaw and pitch. Roll is fixed to zero
    cameraNode.rotation = Quaternion(pitch, yaw, 0.0f);

    // Read WASD keys and move the camera scene node to the corresponding direction if they are pressed
    if (input.keyDown['W'])
        cameraNode.Translate(Vector3(0.0f, 0.0f, 1.0f) * MOVE_SPEED * timeStep);
    if (input.keyDown['S'])
        cameraNode.Translate(Vector3(0.0f, 0.0f, -1.0f) * MOVE_SPEED * timeStep);
    if (input.keyDown['A'])
        cameraNode.Translate(Vector3(-1.0f, 0.0f, 0.0f) * MOVE_SPEED * timeStep);
    if (input.keyDown['D'])
        cameraNode.Translate(Vector3(1.0f, 0.0f, 0.0f) * MOVE_SPEED * timeStep);
}

void AnimateObjects(float timeStep)
{
    const float ROTATE_SPEED = 15.0f;
    // Rotate about the Z axis (roll)
    Quaternion rotateQuat(ROTATE_SPEED * timeStep, Vector3(0.0f, 0.0f, 1.0f));

    for (uint i = 0; i < boxNodes.length; ++i)
        boxNodes[i].Rotate(rotateQuat);
}

void HandleUpdate(StringHash eventType, VariantMap& eventData)
{
    // Take the frame time step, which is stored as a float
    float timeStep = eventData["TimeStep"].GetFloat();

    // Toggle animation with space
    if (input.keyPress[KEY_SPACE])
        animate = !animate;

    // Toggle grouped / ungrouped mode
    if (input.keyPress['G'])
    {
        useGroups = !useGroups;
        CreateScene();
    }

    // Move the camera, scale movement with time step
    MoveCamera(timeStep);

    // Animate scene if enabled
    if (animate)
        AnimateObjects(timeStep);
}

// Create XML patch instructions for screen joystick layout specific to this sample app
String patchInstructions =
        "<patch>" +
        "    <remove sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]/attribute[@name='Is Visible']\" />" +
        "    <replace sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]/element[./attribute[@name='Name' and @value='Label']]/attribute[@name='Text']/@value\">Group</replace>" +
        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]\">" +
        "        <element type=\"Text\">" +
        "            <attribute name=\"Name\" value=\"KeyBinding\" />" +
        "            <attribute name=\"Text\" value=\"G\" />" +
        "        </element>" +
        "    </add>" +
        "    <remove sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]/attribute[@name='Is Visible']\" />" +
        "    <replace sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]/element[./attribute[@name='Name' and @value='Label']]/attribute[@name='Text']/@value\">Animation</replace>" +
        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]\">" +
        "        <element type=\"Text\">" +
        "            <attribute name=\"Name\" value=\"KeyBinding\" />" +
        "            <attribute name=\"Text\" value=\"SPACE\" />" +
        "        </element>" +
        "    </add>" +
        "</patch>";

Revert mistaken change to 20_HugeObjectCount.as.


package  {
	import Modules.*;
	import Testing.*;
	import Values.OpcodeValue;
	/**
	 * ...
	 * @author Nicholas "PleasingFungus" Feinberg
	 */
	public class Level {

		public var name:String;
		public var goal:LevelGoal;
		public var modules:Vector.<Module>;
		public var expectedOps:Vector.<OpcodeValue>
		public var allowedModules:Vector.<Class>
		public var predecessors:Vector.<Level>;
		public var delay:Boolean;

		public function Level(Name:String, Goal:LevelGoal, delay:Boolean = false, AllowedModules:Array = null, ExpectedOps:Array = null, Modules:Array = null) {
			name = Name;
			this.goal = Goal;

			modules = new Vector.<Module>;
			if (Modules)
				for each (var module:Module in Modules)
					modules.push(module);

			expectedOps = new Vector.<OpcodeValue>;
			if (ExpectedOps)
				for each (var op:OpcodeValue in ExpectedOps)
					expectedOps.push(op);

			allowedModules = new Vector.<Class>;
			if (AllowedModules)
				for each (var allowedModule:Class in AllowedModules)
					allowedModules.push(allowedModule);
			else
				allowedModules = Module.ALL_MODULES;

			this.delay = delay;

			predecessors = new Vector.<Level>;
		}

		public static function list():Vector.<Level> {
			var levels:Vector.<Level> = new Vector.<Level>;

			levels.push(new Level("Tutorial 1: Wires",
								  new WireTutorialGoal,
								  false,
								  [], [],
								  [new ConstIn(12, 16, 1), new Adder(20, 16), new DataWriter(28, 16)]),
						new Level("Tutorial 2: Acc.",
								  new AccumulatorTutorialGoal,
								  false,
								  [ConstIn, Adder, Latch, DataWriter], []));

			var addCPU:Level = new Level("Add-CPU",
										 new GeneratedGoal("Set-Add-Save!", Test),
										 false,
										 [ConstIn, And, Adder, Clock, Latch, InstructionMemory, DataMemory, Regfile, InstructionMux, InstructionDemux],
										 [OpcodeValue.OP_SET, OpcodeValue.OP_ADD, OpcodeValue.OP_SAV]);

			var addCPU_D:Level = new Level("Add-CPU Delay",
										   new GeneratedGoal("Set-Add-Save!", Test, 12, 10000),
										   true,
										   null,
										   [OpcodeValue.OP_SET, OpcodeValue.OP_ADD, OpcodeValue.OP_SAV]);

			var cpuJMP:Level = new Level("Jump! Jump!",
										 new GeneratedGoal("Jump!", JumpTest),
										 false,
										 [ConstIn, And, Adder, Clock, Latch, InstructionMemory, DataMemory, Regfile, InstructionMux, InstructionDemux],
										 [OpcodeValue.OP_SET, OpcodeValue.OP_ADD, OpcodeValue.OP_SAV, OpcodeValue.OP_JMP]);

			addCPU_D.predecessors.push(addCPU);
			cpuJMP.predecessors.push(addCPU);

			levels.push(addCPU, addCPU_D, cpuJMP);

			return levels;
		}
	}

}

package  {
	import Modules.*;
	import Testing.*;
	import Values.OpcodeValue;
	/**
	 * ...
	 * @author Nicholas "PleasingFungus" Feinberg
	 */
	public class Level {

		public var name:String;
		public var goal:LevelGoal;
		public var modules:Vector.<Module>;
		public var expectedOps:Vector.<OpcodeValue>
		public var allowedModules:Vector.<Class>
		public var predecessors:Vector.<Level>;
		public var delay:Boolean;

		public function Level(Name:String, Goal:LevelGoal, delay:Boolean = false, AllowedModules:Array = null, ExpectedOps:Array = null, Modules:Array = null) {
			name = Name;
			this.goal = Goal;

			modules = new Vector.<Module>;
			if (Modules)
				for each (var module:Module in Modules)
					modules.push(module);

			expectedOps = new Vector.<OpcodeValue>;
			if (ExpectedOps)
				for each (var op:OpcodeValue in ExpectedOps)
					expectedOps.push(op);

			allowedModules = new Vector.<Class>;
			if (AllowedModules)
				for each (var allowedModule:Class in AllowedModules)
					allowedModules.push(allowedModule);
			else
				allowedModules = Module.ALL_MODULES;

			this.delay = delay;

			predecessors = new Vector.<Level>;
		}

		public static function list():Vector.<Level> {
			var levels:Vector.<Level> = new Vector.<Level>;

			levels.push(new Level("Tutorial 1A: Wires",
								  new WireTutorialGoal,
								  false,
								  [], [],
								  [new ConstIn(12, 12, 1), new ConstIn(12, 20, 2), new DataWriter(22, 16)]),
						new Level("Tutorial 1B: Modules",
								  new WireTutorialGoal,
								  false,
								  [Adder, DataWriter], [],
								  [new ConstIn(12, 16, 1)]),
						new Level("Tutorial 2: Acc.",
								  new AccumulatorTutorialGoal,
								  false,
								  [ConstIn, Adder, Latch, DataWriter], []));

			var addCPU:Level = new Level("Add-CPU",
										 new GeneratedGoal("Set-Add-Save!", Test),
										 false,
										 [ConstIn, And, Adder, Clock, Latch, InstructionMemory, DataMemory, Regfile, InstructionMux, InstructionDemux],
										 [OpcodeValue.OP_SET, OpcodeValue.OP_ADD, OpcodeValue.OP_SAV]);

			var addCPU_D:Level = new Level("Add-CPU Delay",
										   new GeneratedGoal("Set-Add-Save!", Test, 12, 10000),
										   true,
										   null,
										   [OpcodeValue.OP_SET, OpcodeValue.OP_ADD, OpcodeValue.OP_SAV]);

			var cpuJMP:Level = new Level("Jump! Jump!",
										 new GeneratedGoal("Jump!", JumpTest),
										 false,
										 [ConstIn, And, Adder, Clock, Latch, InstructionMemory, DataMemory, Regfile, InstructionMux, InstructionDemux],
										 [OpcodeValue.OP_SET, OpcodeValue.OP_ADD, OpcodeValue.OP_SAV, OpcodeValue.OP_JMP]);

			addCPU_D.predecessors.push(addCPU);
			cpuJMP.predecessors.push(addCPU);

			levels.push(addCPU, addCPU_D, cpuJMP);

			return levels;
		}
	}

}

Split first tutorial in 1/2

Split first tutorial in 1/2


//
// Flump - Copyright 2012 Three Rings Design

package flump.display {

import flash.utils.ByteArray;

import flump.executor.Executor;
import flump.executor.Future;

import starling.core.Starling;

/**
 * Loads zip files created by the flump exporter and parses them into Library instances.
 */
public class LibraryLoader
{
    /**
     * Loads a Library from the zip in the given bytes.
     *
     * @param bytes The bytes containing the zip
     *
     * @param executor The executor on which the loading should run. If not specified, it'll run on
     * a new single-use executor.
     *
     * @param scaleFactor the desired scale factor of the textures to load. If the Library contains
     * textures with multiple scale factors, loader will load the textures with the scale factor
     * closest to this value. If scaleFactor <= 0 (the default), Starling.contentScaleFactor will be
     * used.
     *
     * @return a Future to use to track the success or failure of loading the resources out of the
     * bytes. If the loading succeeds, the Future's onSuccess will fire with an instance of
     * Library. If it fails, the Future's onFail will fire with the Error that caused the
     * loading failure.
     */
    public static function loadBytes (bytes :ByteArray, executor :Executor=null, scaleFactor :Number=-1) :Future {
        return (executor || new Executor(1)).submit(new Loader(bytes, scaleFactor).load);
    }

    /**
     * Loads a Library from the zip at the given url.
     *
     * @param bytes The url where the zip can be found
     *
     * @param executor The executor on which the loading should run. If not specified, it'll run on
     * a new single-use executor.
     *
     * @param scaleFactor the desired scale factor of the textures to load. If the Library contains
     * textures with multiple scale factors, loader will load the textures with the scale factor
     * closest to this value. If scaleFactor <= 0 (the default), Starling.contentScaleFactor will be
     * used.
     *
     * @return a Future to use to track the success or failure of loading the resources from the
     * url. If the loading succeeds, the Future's onSuccess will fire with an instance of
     * Library. If it fails, the Future's onFail will fire with the Error that caused the
     * loading failure.
     */
    public static function loadURL (url :String, executor :Executor=null, scaleFactor :Number=-1) :Future {
        return (executor || new Executor(1)).submit(new Loader(url, scaleFactor).load);
    }

    /** @private */
    public static const LIBRARY_LOCATION :String = "library.json";
    /** @private */
    public static const MD5_LOCATION :String = "md5";
    /** @private */
    public static const VERSION_LOCATION :String = "version";

    /**
     * @private
     * The version produced and parsable by this version of the code. The version in a resources
     * zip must equal the version compiled into the parsing code for parsing to succeed.
     */
    public static const VERSION :String = "1";
}

}

import flash.events.Event;
import flash.geom.Point;
import flash.net.URLRequest;
import flash.utils.ByteArray;
import flash.utils.Dictionary;

import deng.fzip.FZip;
import deng.fzip.FZipErrorEvent;
import deng.fzip.FZipEvent;
import deng.fzip.FZipFile;

import flump.display.Library;
import flump.display.LibraryLoader;
import flump.display.Movie;
import flump.executor.Executor;
import flump.executor.Future;
import flump.executor.FutureTask;
import flump.executor.load.ImageLoader;
import flump.executor.load.LoadedImage;
import flump.mold.AtlasMold;
import flump.mold.AtlasTextureMold;
import flump.mold.LibraryMold;
import flump.mold.MovieMold;
import flump.mold.TextureGroupMold;

import starling.core.Starling;
import starling.display.DisplayObject;
import starling.display.Image;
import starling.display.Sprite;
import starling.textures.Texture;

interface SymbolCreator
{
    function create (library :Library) :DisplayObject;
}

class LibraryImpl
    implements Library
{
    public function LibraryImpl (creators :Dictionary) {
        _creators = creators;
    }

    public function createMovie (symbol :String) :Movie {
        return Movie(createDisplayObject(symbol));
    }

    public function createImage (symbol :String) :DisplayObject {
        const disp :DisplayObject = createDisplayObject(symbol);
        if (disp is Movie) throw new Error(symbol + " is a movie, not a texture");
        return disp;
    }

    public function get movieSymbols () :Vector.<String> {
        const names :Vector.<String> = new Vector.<String>();
        for (var creatorName :String in _creators) {
            if (_creators[creatorName] is MovieCreator) names.push(creatorName);
        }
        return names;
    }

    public function get imageSymbols () :Vector.<String> {
        const names :Vector.<String> = new Vector.<String>();
        for (var creatorName :String in _creators) {
            if (_creators[creatorName] is ImageCreator) names.push(creatorName);
        }
        return names;
    }

    public function createDisplayObject (name :String) :DisplayObject {
        var creator :SymbolCreator = _creators[name];
        if (creator == null) throw new Error("No such id '" + name + "'");
        return creator.create(this);
    }

    protected var _creators :Dictionary;
}

class Loader
{
    public function Loader (toLoad :Object, scaleFactor :Number) {
        _scaleFactor = (scaleFactor > 0 ? scaleFactor : Starling.contentScaleFactor);
        _toLoad = toLoad;
    }

    public function load (future :FutureTask) :void {
        _future = future;

        _zip.addEventListener(Event.COMPLETE, _future.monitoredCallback(onZipLoadingComplete));
        _zip.addEventListener(FZipErrorEvent.PARSE_ERROR, _future.fail);
        _zip.addEventListener(FZipEvent.FILE_LOADED, _future.monitoredCallback(onFileLoaded));

        if (_toLoad is String) _zip.load(new URLRequest(String(_toLoad)));
        else _zip.loadBytes(ByteArray(_toLoad));
    }

    protected function onFileLoaded (e :FZipEvent) :void {
        const loaded :FZipFile = _zip.removeFileAt(_zip.getFileCount() - 1);
        const name :String = loaded.filename;
        if (name == LibraryLoader.LIBRARY_LOCATION) {
            const jsonString :String = loaded.content.readUTFBytes(loaded.content.length);
            _lib = LibraryMold.fromJSON(JSON.parse(jsonString));
        } else if (name.indexOf(PNG, name.length - PNG.length) != -1) {
            _pngBytes[name] = loaded.content;
        } else if (name == LibraryLoader.VERSION_LOCATION) {
            const zipVersion :String = loaded.content.readUTFBytes(loaded.content.length)
            if (zipVersion != LibraryLoader.VERSION) {
                throw new Error("Zip is version " + zipVersion + " but the code needs " + LibraryLoader.VERSION);
            }
            _versionChecked = true;
        } else if (name == LibraryLoader.MD5_LOCATION ) { // Nothing to verify
        } else {} // ignore unknown files
    }

    protected function onZipLoadingComplete (..._) :void {
        _zip = null;
        if (_lib == null) throw new Error(LibraryLoader.LIBRARY_LOCATION + " missing from zip");
        if (!_versionChecked) throw new Error(LibraryLoader.VERSION_LOCATION + " missing from zip");
        const loader :ImageLoader = new ImageLoader();
        _pngLoaders.terminated.add(_future.monitoredCallback(onPngLoadingComplete));

        // Determine the scale factor we want to use
        var textureGroup :TextureGroupMold = _lib.bestTextureGroupForScaleFactor(_scaleFactor);
        if (textureGroup != null) {
            for each (var atlas :AtlasMold in textureGroup.atlases) {
                loadAtlas(loader, atlas);
            }
        }
        _pngLoaders.shutdown();
    }

    protected function loadAtlas (loader :ImageLoader, atlas :AtlasMold) :void {
        const pngBytes :* = _pngBytes[atlas.file];
        if (pngBytes === undefined) {
            throw new Error("Expected an atlas '" + atlas.file + "', but it wasn't in the zip");
        }
        const atlasFuture :Future = loader.loadFromBytes(pngBytes, _pngLoaders);
        atlasFuture.failed.add(onPngLoadingFailed);
        atlasFuture.succeeded.add(function (img :LoadedImage) :void {
            const baseTexture :Texture = Texture.fromBitmapData(
                img.bitmapData,
                true,   // generateMipMaps - do we want this?
                false,  // optimizeForRenderToTexture
                atlas.scaleFactor);

            for each (var atlasTexture :AtlasTextureMold in atlas.textures) {
                _creators[atlasTexture.symbol] = new ImageCreator(
                    Texture.fromTexture(baseTexture, atlasTexture.bounds),
                    atlasTexture.offset,
                    atlasTexture.symbol);
            }
        });
    }

    protected function onPngLoadingComplete (..._) :void {
        for each (var movie :MovieMold in _lib.movies) {
            movie.fillLabels();
            _creators[movie.id] = new MovieCreator(movie, _lib.frameRate);
        }
        _future.succeed(new LibraryImpl(_creators));
    }

    protected function onPngLoadingFailed (e :*) :void {
        if (_future.isComplete) return;
        _future.fail(e);
        _pngLoaders.shutdownNow();
    }

    protected var _toLoad :Object;
    protected var _scaleFactor :Number;
    protected var _future :FutureTask;
    protected var _versionChecked :Boolean;

    protected var _zip :FZip = new FZip();
    protected var _lib :LibraryMold;

    protected const _creators :Dictionary = new Dictionary();//<name, ImageCreator/MovieCreator>
    protected const _pngBytes :Dictionary = new Dictionary();//<String name, ByteArray>
    protected const _pngLoaders :Executor = new Executor(1);

    protected static const PNG :String = ".png";
}

class ImageCreator
    implements SymbolCreator
{
    public var texture :Texture;
    public var offset :Point;
    public var symbol :String;

    public function ImageCreator (texture :Texture, offset :Point, symbol :String) {
        this.texture = texture;
        this.offset = offset;
        this.symbol = symbol;
    }

    public function create (library :Library) :DisplayObject {
        const image :Image = new Image(texture);
        image.x = offset.x;
        image.y = offset.y;
        const holder :Sprite = new Sprite();
        holder.addChild(image);
        holder.name = symbol;
        return holder;
    }
}

class MovieCreator
    implements SymbolCreator
{
    public var mold :MovieMold;
    public var frameRate :Number;

    public function MovieCreator (mold :MovieMold, frameRate :Number) {
        this.mold = mold;
        this.frameRate = frameRate;
    }

    public function create (library :Library) :DisplayObject {
        return new Movie(mold, frameRate, library);
    }
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.display {

import flash.utils.ByteArray;

import flump.executor.Executor;
import flump.executor.Future;

import starling.core.Starling;

/**
 * Loads zip files created by the flump exporter and parses them into Library instances.
 */
public class LibraryLoader
{
    /**
     * Loads a Library from the zip in the given bytes.
     *
     * @param bytes The bytes containing the zip
     *
     * @param executor The executor on which the loading should run. If not specified, it'll run on
     * a new single-use executor.
     *
     * @param scaleFactor the desired scale factor of the textures to load. If the Library contains
     * textures with multiple scale factors, loader will load the textures with the scale factor
     * closest to this value. If scaleFactor <= 0 (the default), Starling.contentScaleFactor will be
     * used.
     *
     * @return a Future to use to track the success or failure of loading the resources out of the
     * bytes. If the loading succeeds, the Future's onSuccess will fire with an instance of
     * Library. If it fails, the Future's onFail will fire with the Error that caused the
     * loading failure.
     */
    public static function loadBytes (bytes :ByteArray, executor :Executor=null, scaleFactor :Number=-1) :Future {
        return (executor || new Executor(1)).submit(new Loader(bytes, scaleFactor).load);
    }

    /**
     * Loads a Library from the zip at the given url.
     *
     * @param bytes The url where the zip can be found
     *
     * @param executor The executor on which the loading should run. If not specified, it'll run on
     * a new single-use executor.
     *
     * @param scaleFactor the desired scale factor of the textures to load. If the Library contains
     * textures with multiple scale factors, loader will load the textures with the scale factor
     * closest to this value. If scaleFactor <= 0 (the default), Starling.contentScaleFactor will be
     * used.
     *
     * @return a Future to use to track the success or failure of loading the resources from the
     * url. If the loading succeeds, the Future's onSuccess will fire with an instance of
     * Library. If it fails, the Future's onFail will fire with the Error that caused the
     * loading failure.
     */
    public static function loadURL (url :String, executor :Executor=null, scaleFactor :Number=-1) :Future {
        return (executor || new Executor(1)).submit(new Loader(url, scaleFactor).load);
    }

    /** @private */
    public static const LIBRARY_LOCATION :String = "library.json";
    /** @private */
    public static const MD5_LOCATION :String = "md5";
    /** @private */
    public static const VERSION_LOCATION :String = "version";

    /**
     * @private
     * The version produced and parsable by this version of the code. The version in a resources
     * zip must equal the version compiled into the parsing code for parsing to succeed.
     */
    public static const VERSION :String = "1";
}

}

import flash.events.Event;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.net.URLRequest;
import flash.utils.ByteArray;
import flash.utils.Dictionary;

import deng.fzip.FZip;
import deng.fzip.FZipErrorEvent;
import deng.fzip.FZipEvent;
import deng.fzip.FZipFile;

import flump.display.Library;
import flump.display.LibraryLoader;
import flump.display.Movie;
import flump.executor.Executor;
import flump.executor.Future;
import flump.executor.FutureTask;
import flump.executor.load.ImageLoader;
import flump.executor.load.LoadedImage;
import flump.mold.AtlasMold;
import flump.mold.AtlasTextureMold;
import flump.mold.LibraryMold;
import flump.mold.MovieMold;
import flump.mold.TextureGroupMold;

import starling.core.Starling;
import starling.display.DisplayObject;
import starling.display.Image;
import starling.display.Sprite;
import starling.textures.Texture;

interface SymbolCreator
{
    function create (library :Library) :DisplayObject;
}

class LibraryImpl
    implements Library
{
    public function LibraryImpl (creators :Dictionary) {
        _creators = creators;
    }

    public function createMovie (symbol :String) :Movie {
        return Movie(createDisplayObject(symbol));
    }

    public function createImage (symbol :String) :DisplayObject {
        const disp :DisplayObject = createDisplayObject(symbol);
        if (disp is Movie) throw new Error(symbol + " is a movie, not a texture");
        return disp;
    }

    public function get movieSymbols () :Vector.<String> {
        const names :Vector.<String> = new Vector.<String>();
        for (var creatorName :String in _creators) {
            if (_creators[creatorName] is MovieCreator) names.push(creatorName);
        }
        return names;
    }

    public function get imageSymbols () :Vector.<String> {
        const names :Vector.<String> = new Vector.<String>();
        for (var creatorName :String in _creators) {
            if (_creators[creatorName] is ImageCreator) names.push(creatorName);
        }
        return names;
    }

    public function createDisplayObject (name :String) :DisplayObject {
        var creator :SymbolCreator = _creators[name];
        if (creator == null) throw new Error("No such id '" + name + "'");
        return creator.create(this);
    }

    protected var _creators :Dictionary;
}

class Loader
{
    public function Loader (toLoad :Object, scaleFactor :Number) {
        _scaleFactor = (scaleFactor > 0 ? scaleFactor : Starling.contentScaleFactor);
        _toLoad = toLoad;
    }

    public function load (future :FutureTask) :void {
        _future = future;

        _zip.addEventListener(Event.COMPLETE, _future.monitoredCallback(onZipLoadingComplete));
        _zip.addEventListener(FZipErrorEvent.PARSE_ERROR, _future.fail);
        _zip.addEventListener(FZipEvent.FILE_LOADED, _future.monitoredCallback(onFileLoaded));

        if (_toLoad is String) _zip.load(new URLRequest(String(_toLoad)));
        else _zip.loadBytes(ByteArray(_toLoad));
    }

    protected function onFileLoaded (e :FZipEvent) :void {
        const loaded :FZipFile = _zip.removeFileAt(_zip.getFileCount() - 1);
        const name :String = loaded.filename;
        if (name == LibraryLoader.LIBRARY_LOCATION) {
            const jsonString :String = loaded.content.readUTFBytes(loaded.content.length);
            _lib = LibraryMold.fromJSON(JSON.parse(jsonString));
        } else if (name.indexOf(PNG, name.length - PNG.length) != -1) {
            _pngBytes[name] = loaded.content;
        } else if (name == LibraryLoader.VERSION_LOCATION) {
            const zipVersion :String = loaded.content.readUTFBytes(loaded.content.length)
            if (zipVersion != LibraryLoader.VERSION) {
                throw new Error("Zip is version " + zipVersion + " but the code needs " + LibraryLoader.VERSION);
            }
            _versionChecked = true;
        } else if (name == LibraryLoader.MD5_LOCATION ) { // Nothing to verify
        } else {} // ignore unknown files
    }

    protected function onZipLoadingComplete (..._) :void {
        _zip = null;
        if (_lib == null) throw new Error(LibraryLoader.LIBRARY_LOCATION + " missing from zip");
        if (!_versionChecked) throw new Error(LibraryLoader.VERSION_LOCATION + " missing from zip");
        const loader :ImageLoader = new ImageLoader();
        _pngLoaders.terminated.add(_future.monitoredCallback(onPngLoadingComplete));

        // Determine the scale factor we want to use
        var textureGroup :TextureGroupMold = _lib.bestTextureGroupForScaleFactor(_scaleFactor);
        if (textureGroup != null) {
            for each (var atlas :AtlasMold in textureGroup.atlases) {
                loadAtlas(loader, atlas);
            }
        }
        _pngLoaders.shutdown();
    }

    protected function loadAtlas (loader :ImageLoader, atlas :AtlasMold) :void {
        const pngBytes :* = _pngBytes[atlas.file];
        if (pngBytes === undefined) {
            throw new Error("Expected an atlas '" + atlas.file + "', but it wasn't in the zip");
        }
        const atlasFuture :Future = loader.loadFromBytes(pngBytes, _pngLoaders);
        atlasFuture.failed.add(onPngLoadingFailed);
        atlasFuture.succeeded.add(function (img :LoadedImage) :void {
            var scale :Number = atlas.scaleFactor;
            const baseTexture :Texture = Texture.fromBitmapData(
                img.bitmapData,
                false,   // generateMipMaps
                false,  // optimizeForRenderToTexture
                scale);

            for each (var atlasTexture :AtlasTextureMold in atlas.textures) {
                var bounds :Rectangle = atlasTexture.bounds;
                var offset :Point = atlasTexture.offset;

                // Starling expects subtexture bounds to be unscaled
                if (scale != 1) {
                    bounds = bounds.clone();
                    bounds.x /= scale;
                    bounds.y /= scale;
                    bounds.width /= scale;
                    bounds.height /= scale;

                    offset = offset.clone();
                    offset.x /= scale;
                    offset.y /= scale;
                }

                _creators[atlasTexture.symbol] = new ImageCreator(
                    Texture.fromTexture(baseTexture, bounds),
                    offset,
                    atlasTexture.symbol);
            }
        });
    }

    protected function onPngLoadingComplete (..._) :void {
        for each (var movie :MovieMold in _lib.movies) {
            movie.fillLabels();
            _creators[movie.id] = new MovieCreator(movie, _lib.frameRate);
        }
        _future.succeed(new LibraryImpl(_creators));
    }

    protected function onPngLoadingFailed (e :*) :void {
        if (_future.isComplete) return;
        _future.fail(e);
        _pngLoaders.shutdownNow();
    }

    protected var _toLoad :Object;
    protected var _scaleFactor :Number;
    protected var _future :FutureTask;
    protected var _versionChecked :Boolean;

    protected var _zip :FZip = new FZip();
    protected var _lib :LibraryMold;

    protected const _creators :Dictionary = new Dictionary();//<name, ImageCreator/MovieCreator>
    protected const _pngBytes :Dictionary = new Dictionary();//<String name, ByteArray>
    protected const _pngLoaders :Executor = new Executor(1);

    protected static const PNG :String = ".png";
}

class ImageCreator
    implements SymbolCreator
{
    public var texture :Texture;
    public var offset :Point;
    public var symbol :String;

    public function ImageCreator (texture :Texture, offset :Point, symbol :String) {
        this.texture = texture;
        this.offset = offset;
        this.symbol = symbol;
    }

    public function create (library :Library) :DisplayObject {
        const image :Image = new Image(texture);
        image.x = offset.x;
        image.y = offset.y;
        const holder :Sprite = new Sprite();
        holder.addChild(image);
        holder.name = symbol;
        return holder;
    }
}

class MovieCreator
    implements SymbolCreator
{
    public var mold :MovieMold;
    public var frameRate :Number;

    public function MovieCreator (mold :MovieMold, frameRate :Number) {
        this.mold = mold;
        this.frameRate = frameRate;
    }

    public function create (library :Library) :DisplayObject {
        return new Movie(mold, frameRate, library);
    }
}

Fix atlas subtexture creation

Fix atlas subtexture creation

We were doing the wrong thing when scaleFactor != 1


/**
 * Copyright 2014 Mozilla Foundation
 *
 * 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 avm1lib {
  import flash.display.MovieClip;
  import flash.display.Stage;

  [native(cls="AS2Utils")]
  public class AS2Utils {
    public static native function getAS2Object(nativeObject: Object) : Object;
    public static native function addProperty(obj: Object, name: String, getter: Function, setter: Function, enumerable: Boolean = true);
    public static native function resolveTarget(target_mc:* = undefined) : MovieClip;
    public static native function resolveLevel(level: Number) : MovieClip;
    public static native function get currentStage() : Stage;

    public static function getTarget(mc: Object) {
      var nativeObject = mc._as3Object;
      if (nativeObject === nativeObject.root) {
        return '/';
      }
      var path = '';
      do {
        path = '/' + nativeObject.name + path;
        nativeObject = nativeObject.parent;
      } while (nativeObject !== nativeObject.root);
      return path;
    }

    public static function addEventHandlerProxy(obj: Object, propertyName: String, eventName: String, argsConverter: Function = null)
    {
      _addEventHandlerProxy(obj, propertyName, eventName, argsConverter);
    }

    private static native function _installObjectMethods();

    {
      _installObjectMethods();
    }
  }
}

import avm1lib.AS2Utils;

AS2Utils;

function _addEventHandlerProxy(obj: Object, propertyName: String, eventName: String, argsConverter: Function)
{
  var currentHandler: Function = null;
  var handlerRunner: Function = null;
  AS2Utils.addProperty(obj, propertyName,
    function(): Function {
      return currentHandler;
    },
    function setter(newHandler: Function) {
      if (!this._as3Object) { // prototype/class ?
        var defaultListeners = this._as2DefaultListeners ||
          (this._as2DefaultListeners = []);
        defaultListeners.push({setter: setter, value: newHandler});
        // see also initDefaultListeners()
        return;
      }
      if (propertyName === 'onRelease' ||
          propertyName === 'onReleaseOutside' ||
          propertyName === 'onRollOut' ||
          propertyName === 'onRollOver') {
        this._as3Object.mouseEnabled = true;
        this._as3Object.buttonMode = true;
      }
      if (currentHandler === newHandler) {
        return;
      }
      if (currentHandler != null) {
        this._as3Object.removeEventListener(eventName, handlerRunner);
      }
      currentHandler = newHandler;
      if (currentHandler != null) {
        handlerRunner = (function (obj: Object, handler: Function) {
          return function handlerRunner() {
            var args = argsConverter != null ? argsConverter(arguments) : null;
            return handler.apply(obj, args);
          };
        })(this, currentHandler);
        this._as3Object.addEventListener(eventName, handlerRunner);
      } else {
        handlerRunner = null;
      }
    },
    false);
}

/**
 * Copyright 2014 Mozilla Foundation
 *
 * 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 avm1lib {
  import flash.display.MovieClip;
  import flash.display.Stage;

  [native(cls="AS2Utils")]
  public class AS2Utils {
    public static native function getAS2Object(nativeObject: Object) : Object;
    public static native function addProperty(obj: Object, name: String, getter: Function, setter: Function, enumerable: Boolean = true);
    public static native function resolveTarget(target_mc:* = undefined) : MovieClip;
    public static native function resolveLevel(level: Number) : MovieClip;
    public static native function get currentStage() : Stage;

    public static function getTarget(mc: Object) {
      var nativeObject = mc._as3Object;
      if (nativeObject === nativeObject.root) {
        return '/';
      }
      var path = '';
      do {
        path = '/' + nativeObject.name + path;
        nativeObject = nativeObject.parent;
      } while (nativeObject !== nativeObject.root);
      return path;
    }

    public static function addEventHandlerProxy(obj: Object, propertyName: String, eventName: String, argsConverter: Function = null)
    {
      _addEventHandlerProxy(obj, propertyName, eventName, argsConverter);
    }

    private static native function _installObjectMethods();

    {
      _installObjectMethods();
    }
  }
}

import avm1lib.AS2Utils;

AS2Utils;

function _addEventHandlerProxy(obj: Object, propertyName: String, eventName: String, argsConverter: Function)
{
  var currentHandler: Function = null;
  var handlerRunner: Function = null;
  AS2Utils.addProperty(obj, propertyName,
    function(): Function {
      return currentHandler;
    },
    function setter(newHandler: Function) {
      if (!this._as3Object) { // prototype/class ?
        var defaultListeners = this._as2DefaultListeners ||
          (this._as2DefaultListeners = []);
        defaultListeners.push({setter: setter, value: newHandler});
        // see also initDefaultListeners()
        return;
      }
      // AS2 MovieClips don't receive roll/release events by default until they set one of the following properties.
      // This behaviour gets triggered whenever those properties are set, despite of the actual value they are set to.
      if (propertyName === 'onRelease' ||
          propertyName === 'onReleaseOutside' ||
          propertyName === 'onRollOut' ||
          propertyName === 'onRollOver') {
        this._as3Object.mouseEnabled = true;
        this._as3Object.buttonMode = true;
      }
      if (currentHandler === newHandler) {
        return;
      }
      if (currentHandler != null) {
        this._as3Object.removeEventListener(eventName, handlerRunner);
      }
      currentHandler = newHandler;
      if (currentHandler != null) {
        handlerRunner = (function (obj: Object, handler: Function) {
          return function handlerRunner() {
            var args = argsConverter != null ? argsConverter(arguments) : null;
            return handler.apply(obj, args);
          };
        })(this, currentHandler);
        this._as3Object.addEventListener(eventName, handlerRunner);
      } else {
        handlerRunner = null;
      }
    },
    false);
}

Add comment to _addEventHandlerProxy

Add comment to _addEventHandlerProxy


##                                                         -*- shell-script -*-
## urbi.as: This file is part of build-aux.
## Copyright (C) Gostai S.A.S., 2006-2008.
##
## This software is provided "as is" without warranty of any kind,
## either expressed or implied, including but not limited to the
## implied warranties of fitness for a particular purpose.
##
## See the LICENSE file for more information.
## For comments, bug reports and feedback: http://www.urbiforge.com
##

m4_pattern_allow([^URBI_SERVER$])

m4_divert_text([URBI-INIT],
[
# check_dir VARIABLE WITNESS
# --------------------------
# Check that VARIABLE contains a directory name that contains WITNESS.
check_dir ()
{
  local var=$[1]
  local witness=$[2]
  local dir
  eval "dir=\$$[1]"
  test x"$dir" != x ||
    fatal "undefined variable: $var"
  shift
  test -e "$dir" ||
    fatal "$var does not exist: $dir" "(pwd = $(pwd))"
  test -d "$dir" ||
    fatal "$var is not a directory: $dir" "(pwd = $(pwd))"
  if test x"$witness" != x; then
    test -f "$dir/$witness" ||
      fatal "$var does not contain $witness: $dir" "(pwd = $(pwd))"
  fi
}

# check_and_abs_dir VAR WITNESS
# -----------------------------
# Check that $VAR/WITNESS exists, and set VAR to $(absolute $VAR).
check_and_abs_dir ()
{
  local var=$[1]
  local witness=$[2]
  check_dir "$[@]"
  # Normalize the directory name, and as safety belts, run the same
  # tests on it.  But save time if possible.  So put in "$@" the dirs
  # to check, the last one being the actual result.
  AS_IF([! is_absolute "$val"],
	[local dir
         eval "dir=\$$[1]"
         dir=$(absolute "$val")
         check_dir "$dir" "$witness"
         eval "$var='$dir'"
         ])
}

# find_srcdir WITNESS
# -------------------
# Find the location of the src directory of the tests suite.
# Make sure the value is correct by checking for the presence of WITNESS.
find_srcdir ()
{
  # Guess srcdir if not defined.
  if test -z "$srcdir"; then
    # Try to compute it from $[0].
    srcdir=$(dirname "$[0]")
  fi

  check_dir srcdir "$[1]"
}

# find_top_builddir [POSSIBILITIES]
# ---------------------------------
# Set/check top_builddir.
# - $top_builddir   if the user wants to define it,
# - (dirname $0)/.. since that's where we are supposed to be
# - ../..           for the common case where we're in tests/my-test.dir
# - ..              if we're in tests/
# - .               if we're in top-builddir.
find_top_builddir ()
{
  if test x"$top_builddir" = x; then
    if test $[#] = 0; then
      set $(dirname "$0")/.. ../.. .. .
    fi
    for d
    do
       if test -f "$d/config.status"; then
	 top_builddir=$d
	 break
       fi
    done
  fi

  check_dir top_builddir "config.status"
}

# find_urbi_server
# ----------------
# Set URBI_SERVER to the location of urbi-server.
find_urbi_server ()
{
  case $URBI_SERVER in
    ('')
       # If URBI_SERVER is not defined, try to find one.  If we are in
       # $top_builddir/tests/TEST.dir, then look in $top_builddir/src.
       URBI_SERVER=$(find_prog "urbi-server" \
			       "$top_builddir/src${PATH_SEPARATOR}.")
       ;;

    (*[[\\/]]*) # A path, relative or absolute.  Make it absolute.
       URBI_SERVER=$(absolute "$URBI_SERVER")
       ;;

    (*) # A simple name, most certainly urbi-server.
       # Find it in the PATH.
       local res
       res=$(find_prog "$URBI_SERVER")
       # If we can't find it, then ucore-pc was probably not installed.
       # Skip.
       test x"$res" != x ||
         error SKIP "cannot find $URBI_SERVER in $PATH"
       URBI_SERVER=$res
       ;;
  esac

  if test -z "$URBI_SERVER"; then
    fatal "cannot find urbi-server, please define URBI_SERVER"
  fi

  if test ! -f "$URBI_SERVER"; then
    fatal "cannot find urbi-server, please check \$URBI_SERVER: $URBI_SERVER"
  fi

  # Check its version.
  if ! run "Server version" "$URBI_SERVER" --version >&3; then
    fatal "cannot run $URBI_SERVER --version"
  fi
}

# spawn_urbi_server FLAGS
# -----------------------
# Spawn an $URBI_SERVER in back-ground, registering it as the child "server".
# Wait until the server.port file is created.  Make it fatal if this does
# not happen with 10s.
#
# Dies if the server does not create server.port for whatever reason.
spawn_urbi_server ()
{
  rm -f server.port
  local flags="--port 0 --port-file server.port $*"
  local cmd="$(instrument "server.val") $URBI_SERVER $flags"
  echo "$cmd" >server.cmd
  $cmd </dev/null >server.out 2>server.err &
  children_register server

  # Wait for the port file to be completed: it must have one full line
  # (with \n to be sure it is complete).
  local t=0
  local tmax=8
  local dt=.5
  # 0 if we stop, 1 to continue sleeping.
  local cont
  while children_alive server &&
          { test ! -f server.port ||
            test $(wc -l <server.port) = 0; };
  do
    # test/expr don't like floating points.
    cont=$(echo "$t <= $tmax" | bc)
    case $cont in
      (1) sleep $dt
          t=$(echo "$t + $dt" | bc);;
      (0)
      fatal "$URBI_SERVER did not issue port in server.port in ${tmax}s";;
    esac
  done
  test -f server.port ||
    fatal "$URBI_SERVER failed before creating server.por"
}
])

##                                                         -*- shell-script -*-
## urbi.as: This file is part of build-aux.
## Copyright (C) Gostai S.A.S., 2006-2008.
##
## This software is provided "as is" without warranty of any kind,
## either expressed or implied, including but not limited to the
## implied warranties of fitness for a particular purpose.
##
## See the LICENSE file for more information.
## For comments, bug reports and feedback: http://www.urbiforge.com
##

m4_pattern_allow([^URBI_SERVER$])

m4_divert_text([URBI-INIT],
[
# check_dir VARIABLE WITNESS
# --------------------------
# Check that VARIABLE contains a directory name that contains WITNESS.
check_dir ()
{
  local var=$[1]
  local witness=$[2]
  local dir
  eval "dir=\$$[1]"
  test x"$dir" != x ||
    fatal "undefined variable: $var"
  shift
  test -e "$dir" ||
    fatal "$var does not exist: $dir" "(pwd = $(pwd))"
  test -d "$dir" ||
    fatal "$var is not a directory: $dir" "(pwd = $(pwd))"
  if test x"$witness" != x; then
    test -f "$dir/$witness" ||
      fatal "$var does not contain $witness: $dir" "(pwd = $(pwd))"
  fi
}

# check_and_abs_dir VAR WITNESS
# -----------------------------
# Check that $VAR/WITNESS exists, and set VAR to $(absolute $VAR).
check_and_abs_dir ()
{
  local var=$[1]
  local witness=$[2]
  check_dir "$[@]"
  # Normalize the directory name, and as safety belts, run the same
  # tests on it.  But save time if possible.  So put in "$@" the dirs
  # to check, the last one being the actual result.
  AS_IF([! is_absolute "$val"],
	[local dir
         eval "dir=\$$[1]"
         dir=$(absolute "$val")
         check_dir "$dir" "$witness"
         eval "$var='$dir'"
         ])
}

# find_srcdir WITNESS
# -------------------
# Find the location of the src directory of the tests suite.
# Make sure the value is correct by checking for the presence of WITNESS.
find_srcdir ()
{
  # Guess srcdir if not defined.
  if test -z "$srcdir"; then
    # Try to compute it from $[0].
    srcdir=$(dirname "$[0]")
  fi

  check_dir srcdir "$[1]"
}

# find_top_builddir [POSSIBILITIES]
# ---------------------------------
# Set/check top_builddir.
# - $top_builddir   if the user wants to define it,
# - (dirname $0)/.. since that's where we are supposed to be
# - ../..           for the common case where we're in tests/my-test.dir
# - ..              if we're in tests/
# - .               if we're in top-builddir.
find_top_builddir ()
{
  if test x"$top_builddir" = x; then
    if test $[#] = 0; then
      set $(dirname "$0")/.. ../.. .. .
    fi
    for d
    do
       if test -f "$d/config.status"; then
	 top_builddir=$d
	 break
       fi
    done
  fi

  check_dir top_builddir "config.status"
}

# find_urbi_server
# ----------------
# Set URBI_SERVER to the location of urbi-server.
find_urbi_server ()
{
  case $URBI_SERVER in
    ('')
       # If URBI_SERVER is not defined, try to find one.  If we are in
       # $top_builddir/tests/TEST.dir, then look in $top_builddir/src.
       URBI_SERVER=$(find_prog "urbi-server" \
			       "$top_builddir/src${PATH_SEPARATOR}.")
       ;;

    (*[[\\/]]*) # A path, relative or absolute.  Make it absolute.
       URBI_SERVER=$(absolute "$URBI_SERVER")
       ;;

    (*) # A simple name, most certainly urbi-server.
       # Find it in the PATH.
       local res
       res=$(find_prog "$URBI_SERVER")
       # If we can't find it, then ucore-pc was probably not installed.
       # Skip.
       test x"$res" != x ||
         error SKIP "cannot find $URBI_SERVER in $PATH"
       URBI_SERVER=$res
       ;;
  esac

  if test -z "$URBI_SERVER"; then
    fatal "cannot find urbi-server, please define URBI_SERVER"
  fi

  if test ! -f "$URBI_SERVER"; then
    fatal "cannot find urbi-server, please check \$URBI_SERVER: $URBI_SERVER"
  fi

  # Check its version.
  if ! run "Server version" "$URBI_SERVER" --version >&3; then
    fatal "cannot run $URBI_SERVER --version"
  fi
}

# spawn_urbi_server FLAGS
# -----------------------
# Spawn an $URBI_SERVER in back-ground, registering it as the child "server".
# Wait until the server.port file is created.  Make it fatal if this does
# not happen with 10s.
#
# Dies if the server does not create server.port for whatever reason.
spawn_urbi_server ()
{
  rm -f server.port
  local flags="--port 0 --port-file server.port $*"
  local cmd="$(instrument "server.val") $URBI_SERVER $flags"
  echo "$cmd" >server.cmd
  $cmd </dev/null >server.out 2>server.err &
  children_register server

  # Wait for the port file to be completed: it must have one full line
  # (with \n to be sure it is complete).
  local t=0
  local tmax=20
  local dt=.5
  # 0 if we stop, 1 to continue sleeping.
  local cont
  while children_alive server &&
          { test ! -f server.port ||
            test $(wc -l <server.port) = 0; };
  do
    # test/expr don't like floating points.
    cont=$(echo "$t <= $tmax" | bc)
    case $cont in
      (1) sleep $dt
          t=$(echo "$t + $dt" | bc);;
      (0)
      fatal "$URBI_SERVER did not issue port in server.port in ${tmax}s";;
    esac
  done
  test -f server.port ||
    fatal "$URBI_SERVER failed before creating server.por"
}
])

Increase wait time to help tests requiring qemu.

Pretty much harmless in other cases, as this timeout is only reached in
rare conditions.

	* build-aux/urbi.as: Wait for server.port for 20s.


package org.mangui.HLS.muxing {
    import flash.utils.ByteArray;

    /** Representation of a Packetized Elementary Stream. **/
    public class PES {
        /** Is it AAC audio or AVC video. **/
        public var audio : Boolean;
        /** The PES data (including headers). **/
        public var data : ByteArray;
        /** Start of the payload. **/
        public var payload : Number;
        /** Timestamp from the PTS header. **/
        public var pts : Number;
        /** Timestamp from the DTS header. **/
        public var dts : Number;
        /** PES packet len **/
        public var len : Number;
        /** PES packet len **/
        public var payload_len : Number;

        /** Save the first chunk of PES data. **/
        public function PES(dat : ByteArray, aud : Boolean) {
            data = dat;
            audio = aud;
            parse();
        };

        /** When all data is appended, parse the PES headers. **/
        private function parse() : void {
            data.position = 0;
            // Start code prefix and packet ID.
            var prefix : Number = data.readUnsignedInt();
            /*Audio streams (0x1C0-0x1DF)
            Video streams (0x1E0-0x1EF)
            0x1BD is special case, could be audio or video (ffmpeg\libavformat\mpeg.c)
             */
            if ((audio && (prefix > 0x1df || prefix < 0x1c0 && prefix != 0x1bd)) || (!audio && prefix != 0x1e0 && prefix != 0x1ea && prefix != 0x1bd)) {
                throw new Error("PES start code not found or not AAC/AVC: " + prefix);
            }
            // read len
            len = data.readUnsignedShort();
            // Ignore marker bits.
            data.position += 1;
            // Check for PTS
            var flags : uint = (data.readUnsignedByte() & 192) >> 6;
            // Check PES header length
            var length : uint = data.readUnsignedByte();

            if (flags == 2 || flags == 3) {
                // Grab the timestamp from PTS data (spread out over 5 bytes):
                // XXXX---X -------- -------X -------- -------X

                var _pts : Number = Number((data.readUnsignedByte() & 0x0e)) * Number(1 << 29) + Number((data.readUnsignedShort() >> 1) << 15) + Number((data.readUnsignedShort() >> 1));
                // check if greater than 2^32 -1
                if (_pts > 4294967295) {
                    // if greater, it is a negative timestamp, compute 2 complement (XOR with 2^32 - 1), then add 1
                    _pts ^= 4294967295;
                    _pts = -(_pts+1);
                }
                length -= 5;
                var _dts : Number = _pts;
                if (flags == 3) {
                    // Grab the DTS (like PTS)
                    _dts = Number((data.readUnsignedByte() & 0x0e)) * Number(1 << 29) + Number((data.readUnsignedShort() >> 1) << 15) + Number((data.readUnsignedShort() >> 1));
                    // check if greater than 2^32 -1
                    if (_dts > 4294967295) {
                        // if greater, it is a negative timestamp, compute 2 complement (XOR with 2^32 - 1), then add 1
                        _dts ^= 4294967295;
                        _dts = -(_dts+1);
                    }
                    length -= 5;
                }
                pts = Math.round(_pts / 90);
                dts = Math.round(_dts / 90);
                // Log.info("pts/dts: " + pts + "/"+ dts);
            }
            // Skip other header data and parse payload.
            data.position += length;
            payload = data.position;
            if(len) {
                payload_len = len - data.position + 6;
            } else {
                payload_len = 0;
            }
        };
    }
}

package org.mangui.HLS.muxing {
    import flash.utils.ByteArray;

    /** Representation of a Packetized Elementary Stream. **/
    public class PES {
        /** Is it AAC audio or AVC video. **/
        public var audio : Boolean;
        /** The PES data (including headers). **/
        public var data : ByteArray;
        /** Start of the payload. **/
        public var payload : Number;
        /** Timestamp from the PTS header. **/
        public var pts : Number;
        /** Timestamp from the DTS header. **/
        public var dts : Number;
        /** PES packet len **/
        public var len : Number;
        /** PES packet len **/
        public var payload_len : Number;

        /** Save the first chunk of PES data. **/
        public function PES(dat : ByteArray, aud : Boolean) {
            data = dat;
            audio = aud;
            parse();
        };

        /** When all data is appended, parse the PES headers. **/
        private function parse() : void {
            data.position = 0;
            // Start code prefix and packet ID.
            var prefix : Number = data.readUnsignedInt();
            /*Audio streams (0x1C0-0x1DF)
            Video streams (0x1E0-0x1EF)
            0x1BD is special case, could be audio or video (ffmpeg\libavformat\mpeg.c)
             */
            if ((audio && (prefix > 0x1df || prefix < 0x1c0 && prefix != 0x1bd)) || (!audio && prefix != 0x1e0 && prefix != 0x1ea && prefix != 0x1bd)) {
                throw new Error("PES start code not found or not AAC/AVC: " + prefix);
            }
            // read len
            len = data.readUnsignedShort();
            // Ignore marker bits.
            data.position += 1;
            // Check for PTS
            var flags : uint = (data.readUnsignedByte() & 192) >> 6;
            // Check PES header length
            var length : uint = data.readUnsignedByte();

            if (flags == 2 || flags == 3) {
                // Grab the timestamp from PTS data (spread out over 5 bytes):
                // XXXX---X -------- -------X -------- -------X

                var _pts : Number = Number((data.readUnsignedByte() & 0x0e)) * Number(1 << 29) + Number((data.readUnsignedShort() >> 1) << 15) + Number((data.readUnsignedShort() >> 1));
                // check if greater than 2^32 -1
                if (_pts > 4294967295) {
                    // decrement 2^33
                    _pts -= 8589934592;
                }
                length -= 5;
                var _dts : Number = _pts;
                if (flags == 3) {
                    // Grab the DTS (like PTS)
                    _dts = Number((data.readUnsignedByte() & 0x0e)) * Number(1 << 29) + Number((data.readUnsignedShort() >> 1) << 15) + Number((data.readUnsignedShort() >> 1));
                    // check if greater than 2^32 -1
                    if (_dts > 4294967295) {
                        // decrement 2^33
                        _dts -= 8589934592;
                    }
                    length -= 5;
                }
                pts = Math.round(_pts / 90);
                dts = Math.round(_dts / 90);
                // Log.info("pts/dts: " + pts + "/"+ dts);
            }
            // Skip other header data and parse payload.
            data.position += length;
            payload = data.position;
            if(len) {
                payload_len = len - data.position + 6;
            } else {
                payload_len = 0;
            }
        };
    }
}

fix computation of negative PTS/DTS value


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

	[DefaultProperty("transformModels")]
	public class TransformCompoundModel extends TransformModel
	{
		public function set transformModels(value:Array):void
		{
			if (value && value.length > 0)
			{
				var length:int = value.length;
				var product:Matrix = (value[0] as ITransformModel).matrix.clone();
				for (var i:int = 1; i < length; i++)
				{
					var current:Matrix = (value[i] as ITransformModel).matrix;
					concat(product, current);
				}
				matrix = product;
			} else
			{
				matrix = null;
			}
		}

		private function concat(product:Matrix, factor:Matrix):void
		{
			var result_a:Number = product.a * factor.a;
			var result_b:Number = 0.0;
			var result_c:Number = 0.0;
			var result_d:Number = product.d * factor.d;
			var result_tx:Number = product.tx * factor.a + factor.tx;
			var result_ty:Number = product.ty * factor.d + factor.ty;
			if (product.b != 0.0 || product.c != 0.0 || factor.b != 0.0 || factor.c != 0.0)
			{
				result_a = result_a + product.b * factor.c;
				result_d = result_d + product.c * factor.b;
				result_b = result_b + (product.a * factor.b + product.b * factor.d);
				result_c = result_c + (product.c * factor.a + product.d * factor.c);
				result_tx = result_tx + product.ty * factor.c;
				result_ty = result_ty + product.tx * factor.b;
			}
			product.a = result_a;
			product.b = result_b;
			product.c = result_c;
			product.d = result_d;
			product.tx = result_tx;
			product.ty = result_ty;
		}

	}
}

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

	[DefaultProperty("transformModels")]
	public class TransformCompoundModel extends TransformModel
	{
		public function set transformModels(value:Array):void
		{
			if (value && value.length > 0)
			{
				var length:int = value.length;
				var product:Matrix = (value[0] as ITransformModel).matrix.clone();
				for (var i:int = 1; i < length; i++)
				{
					var current:Matrix = (value[i] as ITransformModel).matrix;
					product.concat(current);
				}
				matrix = product;
			} else
			{
				matrix = null;
			}
		}
	}
}

Use Matrix concat

Use Matrix concat