Browse Source

Camera settings dialog expanded to be a general editor settings dialog.
Added object move/rotate/scale by ctrl + arrow keys.
Math script API additions.
Merged the license texts of different libraries into License.txt.

Lasse Öörni 14 years ago
parent
commit
bb39d663c9

+ 367 - 60
Bin/CoreData/Scripts/EditorCamera.as

@@ -1,19 +1,40 @@
 // Urho3D editor camera functions
 
 Camera@ camera;
-Window@ cameraDialog;
+Window@ editorSettingsDialog;
+
+enum ObjectMoveMode
+{
+    OBJ_MOVE = 0,
+    OBJ_ROTATE,
+    OBJ_SCALE
+}
 
 float cameraBaseSpeed = 10;
 float cameraBaseRotationSpeed = 0.2;
 float cameraShiftSpeedMultiplier = 5;
 float cameraYaw = 0;
 float cameraPitch = 0;
-float updateStatsAcc = 0;
+
+float newNodeDistance = 20;
+float moveStep = 0.5;
+float rotateStep = 5;
+float scaleStep = 0.1;
+bool moveSnap = false;
+bool rotateSnap = false;
+bool scaleSnap = false;
+ObjectMoveMode moveMode = OBJ_MOVE;
 
 Text@ renderStatsText;
 Text@ cameraPosText;
 bool subscribedToCameraEdits = false;
 
+array<string> moveModeText = {
+    "Move    ",
+    "Rotate  ",
+    "Scale   "
+};
+
 void createCamera()
 {
     // Note: this camera will not be bound into a scene entity, so that it does not get listed in the editor UI
@@ -23,41 +44,6 @@ void createCamera()
     pipeline.setViewport(0, Viewport(editorScene, camera));
 }
 
-void moveCamera(float timeStep)
-{
-    if ((ui.getFocusElement() is null) && (!input.getKeyDown(KEY_CTRL)))
-    {
-        float speedMultiplier = 1.0f;
-        if (input.getKeyDown(KEY_SHIFT))
-            speedMultiplier = cameraShiftSpeedMultiplier;
-
-        if ((input.getKeyDown('W')) || (input.getKeyDown(KEY_UP)))
-            camera.translateRelative(Vector3(0, 0, cameraBaseSpeed) * timeStep * speedMultiplier);
-        if ((input.getKeyDown('S')) || (input.getKeyDown(KEY_DOWN)))
-            camera.translateRelative(Vector3(0, 0, -cameraBaseSpeed) * timeStep * speedMultiplier);
-        if ((input.getKeyDown('A')) || (input.getKeyDown(KEY_LEFT)))
-            camera.translateRelative(Vector3(-cameraBaseSpeed, 0, 0) * timeStep * speedMultiplier);
-        if ((input.getKeyDown('D')) || (input.getKeyDown(KEY_RIGHT)))
-            camera.translateRelative(Vector3(cameraBaseSpeed, 0, 0) * timeStep * speedMultiplier);
-    }
-    
-    if (input.getMouseButtonDown(MOUSEB_RIGHT))
-    {
-        IntVector2 mouseMove = input.getMouseMove();
-        if ((mouseMove.x != 0) || (mouseMove.y != 0))
-        {
-            cameraYaw += mouseMove.x * cameraBaseRotationSpeed;
-            cameraPitch += mouseMove.y * cameraBaseRotationSpeed;
-            if (cameraPitch < -90.0f)
-                cameraPitch = -90.0f;
-            if (cameraPitch > 90.0f)
-                cameraPitch = 90.0f;
-
-            camera.setRotation(Quaternion(cameraPitch, cameraYaw, 0));
-        }
-    }
-}
-
 void resetCamera()
 {
     camera.setPosition(Vector3(0, 10, 0));
@@ -66,35 +52,56 @@ void resetCamera()
     cameraYaw = 0;
 }
 
-void createCameraDialog()
+void createEditorSettingsDialog()
 {
-    if (!(cameraDialog is null))
+    if (!(editorSettingsDialog is null))
         return;
     
-    @cameraDialog = ui.loadLayout(cache.getResource("XMLFile", "UI/CameraDialog.xml"), uiStyle);
-    uiRoot.addChild(cameraDialog);
-    centerDialog(cameraDialog);
-    updateCameraDialog();
-    hideCameraDialog();
+    @editorSettingsDialog = ui.loadLayout(cache.getResource("XMLFile", "UI/EditorSettingsDialog.xml"), uiStyle);
+    uiRoot.addChild(editorSettingsDialog);
+    centerDialog(editorSettingsDialog);
+    updateEditorSettingsDialog();
+    hideEditorSettingsDialog();
 }
 
-void updateCameraDialog()
+void updateEditorSettingsDialog()
 {
-    if (cameraDialog is null)
+    if (editorSettingsDialog is null)
         return;
-    
-    LineEdit@ nearClipEdit = cameraDialog.getChild("NearClipEdit", true);
+
+    LineEdit@ nearClipEdit = editorSettingsDialog.getChild("NearClipEdit", true);
     nearClipEdit.setText(toString(camera.getNearClip()));
     
-    LineEdit@ farClipEdit = cameraDialog.getChild("FarClipEdit", true);
+    LineEdit@ farClipEdit = editorSettingsDialog.getChild("FarClipEdit", true);
     farClipEdit.setText(toString(camera.getFarClip()));
     
-    LineEdit@ fovEdit = cameraDialog.getChild("FOVEdit", true);
+    LineEdit@ fovEdit = editorSettingsDialog.getChild("FOVEdit", true);
     fovEdit.setText(toString(camera.getFov()));
 
-    LineEdit@ speedEdit = cameraDialog.getChild("SpeedEdit", true);
+    LineEdit@ speedEdit = editorSettingsDialog.getChild("SpeedEdit", true);
     speedEdit.setText(toString(cameraBaseSpeed));
 
+    LineEdit@ distanceEdit = editorSettingsDialog.getChild("DistanceEdit", true);
+    distanceEdit.setText(toString(newNodeDistance));
+
+    LineEdit@ moveStepEdit = editorSettingsDialog.getChild("MoveStepEdit", true);
+    moveStepEdit.setText(toString(moveStep));
+    CheckBox@ moveSnapToggle = editorSettingsDialog.getChild("MoveSnapToggle", true);
+    moveSnapToggle.setChecked(moveSnap);
+
+    LineEdit@ rotateStepEdit = editorSettingsDialog.getChild("RotateStepEdit", true);
+    rotateStepEdit.setText(toString(rotateStep));
+    CheckBox@ rotateSnapToggle = editorSettingsDialog.getChild("RotateSnapToggle", true);
+    rotateSnapToggle.setChecked(rotateSnap);
+
+    LineEdit@ scaleStepEdit = editorSettingsDialog.getChild("ScaleStepEdit", true);
+    scaleStepEdit.setText(toString(scaleStep));
+    CheckBox@ scaleSnapToggle = editorSettingsDialog.getChild("ScaleSnapToggle", true);
+    scaleSnapToggle.setChecked(scaleSnap);
+
+    CheckBox@ localIDToggle = editorSettingsDialog.getChild("LocalIDToggle", true);
+    localIDToggle.setChecked(useLocalIDs);
+
     if (!subscribedToCameraEdits)
     {
         subscribeToEvent(nearClipEdit, "TextChanged", "editCameraNearClip");
@@ -103,23 +110,35 @@ void updateCameraDialog()
         subscribeToEvent(farClipEdit, "TextFinished", "editCameraFarClip");
         subscribeToEvent(fovEdit, "TextChanged", "editCameraFOV");
         subscribeToEvent(fovEdit, "TextFinished", "editCameraFOV");
-        subscribeToEvent(fovEdit, "TextChanged", "editCameraSpeed");
+        subscribeToEvent(speedEdit, "TextChanged", "editCameraSpeed");
         subscribeToEvent(speedEdit, "TextFinished", "editCameraSpeed");
-        subscribeToEvent(cameraDialog.getChild("CloseButton", true), "Released", "hideCameraDialog");
+        subscribeToEvent(distanceEdit, "TextChanged", "editNewNodeDistance");
+        subscribeToEvent(distanceEdit, "TextFinished", "editNewNodeDistance");
+        subscribeToEvent(moveStepEdit, "TextChanged", "editMoveStep");
+        subscribeToEvent(moveStepEdit, "TextFinished", "editMoveStep");
+        subscribeToEvent(rotateStepEdit, "TextChanged", "editRotateStep");
+        subscribeToEvent(rotateStepEdit, "TextFinished", "editRotateStep");
+        subscribeToEvent(scaleStepEdit, "TextChanged", "editScaleStep");
+        subscribeToEvent(scaleStepEdit, "TextFinished", "editScaleStep");
+        subscribeToEvent(moveSnapToggle, "Toggled", "editMoveSnap");
+        subscribeToEvent(rotateSnapToggle, "Toggled", "editRotateSnap");
+        subscribeToEvent(scaleSnapToggle, "Toggled", "editScaleSnap");
+        subscribeToEvent(localIDToggle, "Toggled", "editUseLocalIDs");
+        subscribeToEvent(editorSettingsDialog.getChild("CloseButton", true), "Released", "hideEditorSettingsDialog");
         subscribedToCameraEdits = true;
     }
 }
 
-void showCameraDialog()
+void showEditorSettingsDialog()
 {
-    updateCameraDialog();
-    cameraDialog.setVisible(true);
-    cameraDialog.bringToFront();
+    updateEditorSettingsDialog();
+    editorSettingsDialog.setVisible(true);
+    editorSettingsDialog.bringToFront();
 }
 
-void hideCameraDialog()
+void hideEditorSettingsDialog()
 {
-    cameraDialog.setVisible(false);
+    editorSettingsDialog.setVisible(false);
 }
 
 void editCameraNearClip(StringHash eventType, VariantMap& eventData)
@@ -154,6 +173,62 @@ void editCameraSpeed(StringHash eventType, VariantMap& eventData)
         edit.setText(toString(cameraBaseSpeed));
 }
 
+void editNewNodeDistance(StringHash eventType, VariantMap& eventData)
+{
+    LineEdit@ edit = eventData["Element"].getUIElement();
+    newNodeDistance = max(edit.getText().toFloat(), 0);
+    if (eventType == StringHash("TextFinished"))
+        edit.setText(toString(newNodeDistance));
+}
+
+void editMoveStep(StringHash eventType, VariantMap& eventData)
+{
+    LineEdit@ edit = eventData["Element"].getUIElement();
+    moveStep = max(edit.getText().toFloat(), 0);
+    if (eventType == StringHash("TextFinished"))
+        edit.setText(toString(moveStep));
+}
+
+void editRotateStep(StringHash eventType, VariantMap& eventData)
+{
+    LineEdit@ edit = eventData["Element"].getUIElement();
+    rotateStep = max(edit.getText().toFloat(), 0);
+    if (eventType == StringHash("TextFinished"))
+        edit.setText(toString(rotateStep));
+}
+
+void editScaleStep(StringHash eventType, VariantMap& eventData)
+{
+    LineEdit@ edit = eventData["Element"].getUIElement();
+    scaleStep = max(edit.getText().toFloat(), 0);
+    if (eventType == StringHash("TextFinished"))
+        edit.setText(toString(scaleStep));
+}
+
+void editMoveSnap(StringHash eventType, VariantMap& eventData)
+{
+    CheckBox@ edit = eventData["Element"].getUIElement();
+    moveSnap = edit.isChecked();
+}
+
+void editRotateSnap(StringHash eventType, VariantMap& eventData)
+{
+    CheckBox@ edit = eventData["Element"].getUIElement();
+    rotateSnap = edit.isChecked();
+}
+
+void editScaleSnap(StringHash eventType, VariantMap& eventData)
+{
+    CheckBox@ edit = eventData["Element"].getUIElement();
+    scaleSnap = edit.isChecked();
+}
+
+void editUseLocalIDs(StringHash eventType, VariantMap& eventData)
+{
+    CheckBox@ edit = eventData["Element"].getUIElement();
+    useLocalIDs = edit.isChecked();
+}
+
 void createStatsBar()
 {
     Font@ font = cache.getResource("Font", "cour.ttf");
@@ -201,8 +276,240 @@ void updateStats(float timeStep)
     yText.resize(8);
     zText.resize(8);
     
-    cameraPosText.setText("Physics: " + (runPhysics ? "Running " : "Paused  ") + " Camera pos: " + xText + " " + yText + " " + zText + " ");
+    cameraPosText.setText(moveModeText[moveMode] + "Physics: " + (runPhysics ? "Running " : "Paused  ") + " Camera pos: " + xText
+        + " " + yText + " " + zText + " ");
     
     renderStatsText.setSize(renderStatsText.getMinSize());
     cameraPosText.setSize(cameraPosText.getMinSize());
 }
+
+void moveCamera(float timeStep)
+{
+    // Move camera
+    if ((ui.getFocusElement() is null) && (!input.getKeyDown(KEY_CTRL)))
+    {
+        float speedMultiplier = 1.0;
+        if (input.getKeyDown(KEY_SHIFT))
+            speedMultiplier = cameraShiftSpeedMultiplier;
+
+        if ((input.getKeyDown('W')) || (input.getKeyDown(KEY_UP)))
+            camera.translateRelative(Vector3(0, 0, cameraBaseSpeed) * timeStep * speedMultiplier);
+        if ((input.getKeyDown('S')) || (input.getKeyDown(KEY_DOWN)))
+            camera.translateRelative(Vector3(0, 0, -cameraBaseSpeed) * timeStep * speedMultiplier);
+        if ((input.getKeyDown('A')) || (input.getKeyDown(KEY_LEFT)))
+            camera.translateRelative(Vector3(-cameraBaseSpeed, 0, 0) * timeStep * speedMultiplier);
+        if ((input.getKeyDown('D')) || (input.getKeyDown(KEY_RIGHT)))
+            camera.translateRelative(Vector3(cameraBaseSpeed, 0, 0) * timeStep * speedMultiplier);
+    }
+
+    // Rotate camera
+    if (input.getMouseButtonDown(MOUSEB_RIGHT))
+    {
+        IntVector2 mouseMove = input.getMouseMove();
+        if ((mouseMove.x != 0) || (mouseMove.y != 0))
+        {
+            cameraYaw += mouseMove.x * cameraBaseRotationSpeed;
+            cameraPitch += mouseMove.y * cameraBaseRotationSpeed;
+            if (cameraPitch < -90.0f)
+                cameraPitch = -90.0f;
+            if (cameraPitch > 90.0f)
+                cameraPitch = 90.0f;
+
+            camera.setRotation(Quaternion(cameraPitch, cameraYaw, 0));
+        }
+    }
+
+    // Move/rotate/scale object
+    if ((selectedComponent !is null) && (ui.getFocusElement() is null) && (input.getKeyDown(KEY_CTRL)))
+    {
+        Node@ node = cast<Node>(selectedComponent);
+        if (node !is null)
+        {
+            bool changed = false;
+            Vector3 adjust(0, 0, 0);
+            if (input.getKeyDown(KEY_UP))
+                adjust.z = 1;
+            if (input.getKeyDown(KEY_DOWN))
+                adjust.z = -1;
+            if (input.getKeyDown(KEY_LEFT))
+                adjust.x = -1;
+            if (input.getKeyDown(KEY_RIGHT))
+                adjust.x = 1;
+            if (input.getKeyDown(KEY_PAGEUP))
+                adjust.y = 1;
+            if (input.getKeyDown(KEY_PAGEDOWN))
+                adjust.y = -1;
+            if (moveMode == OBJ_SCALE)
+            {
+                if ((input.getKeyDown(KEY_ADD)) || (input.getKeyDown(KEY_OEM_PLUS)))
+                    adjust = Vector3(1, 1, 1);
+                if ((input.getKeyDown(KEY_SUBTRACT)) || (input.getKeyDown(KEY_OEM_MINUS)))
+                    adjust = Vector3(-1, -1, -1);
+            }
+
+            if (adjust != Vector3(0, 0, 0))
+            {
+                adjust *= timeStep * 10;
+
+                if (input.getKeyDown(KEY_SHIFT))
+                    adjust *= cameraShiftSpeedMultiplier;
+
+                switch (moveMode)
+                {
+                case OBJ_MOVE:
+                    if (!moveSnap)
+                    {
+                        node.setPosition(node.getPosition() + adjust * moveStep);
+                        changed = true;
+                    }
+                    break;
+    
+                case OBJ_ROTATE:
+                    if (!rotateSnap)
+                    {
+                        Vector3 euler = node.getRotation().getEulerAngles();
+                        euler.x += adjust.z * rotateStep;
+                        euler.y += adjust.x * rotateStep;
+                        euler.z += adjust.y * rotateStep;
+                        node.setRotation(Quaternion(euler));
+                        changed = true;
+                    }
+                    break;
+    
+                case OBJ_SCALE:
+                    if (!scaleSnap)
+                    {
+                        node.setScale(node.getScale() + adjust * scaleStep);
+                        changed = true;
+                    }
+                    break;
+                }
+            }
+
+            if (changed)
+            {
+                // If is a physics body, make sure the physics and rendering transforms are in sync
+                RigidBody@ body = cast<RigidBody>(node);
+                if (body !is null)
+                    body.setTransform(node.getPosition(), node.getRotation(), node.getScale());
+
+                updateComponentAttributes();
+            }
+        }
+    }
+}
+
+void steppedObjectManipulation(int key)
+{
+    Node@ node = cast<Node>(selectedComponent);
+    if (node is null)
+        return;
+
+    // Do not react in non-snapped mode, because that is handled in frame update
+    if ((moveMode == OBJ_MOVE) && (!moveSnap))
+        return;
+    if ((moveMode == OBJ_ROTATE) && (!rotateSnap))
+        return;
+    if ((moveMode == OBJ_SCALE) && (!scaleSnap))
+        return;
+
+    Vector3 adjust(0, 0, 0);
+    if (key == KEY_UP)
+        adjust.z = 1;
+    if (key == KEY_DOWN)
+        adjust.z = -1;
+    if (key == KEY_LEFT)
+        adjust.x = -1;
+    if (key == KEY_RIGHT)
+        adjust.x = 1;
+    if (key == KEY_PAGEUP)
+        adjust.y = 1;
+    if (key == KEY_PAGEDOWN)
+        adjust.y = -1;
+    if (moveMode == OBJ_SCALE)
+    {
+        if ((key == KEY_ADD) || (key == KEY_OEM_PLUS))
+            adjust = Vector3(1, 1, 1);
+        if ((key == KEY_SUBTRACT) || (key == KEY_OEM_MINUS))
+            adjust = Vector3(-1, -1, -1);
+    }
+
+    if (adjust == Vector3(0, 0, 0))
+        return;
+
+    switch (moveMode)
+    {
+    case OBJ_MOVE:
+        {
+            Vector3 pos = node.getPosition();
+            if (adjust.x != 0)
+            {
+                pos.x += adjust.x * moveStep;
+                pos.x = floor(pos.x / moveStep + 0.5) * moveStep;
+            }
+            if (adjust.y != 0)
+            {
+                pos.y += adjust.y * moveStep;
+                pos.y = floor(pos.y / moveStep + 0.5) * moveStep;
+            }
+            if (adjust.z != 0)
+            {
+                pos.z += adjust.z * moveStep;
+                pos.z = floor(pos.z / moveStep + 0.5) * moveStep;
+            }
+            node.setPosition(pos);
+        }
+        break;
+
+    case OBJ_ROTATE:
+        {
+            Vector3 rot = node.getRotation().getEulerAngles();
+            if (adjust.z != 0)
+            {
+                rot.x += adjust.z * rotateStep;
+                rot.x = floor(rot.x / rotateStep + 0.5) * rotateStep;
+            }
+            if (adjust.x != 0)
+            {
+                rot.y += adjust.x * rotateStep;
+                rot.y = floor(rot.y / rotateStep + 0.5) * rotateStep;
+            }
+            if (adjust.y != 0)
+            {
+                rot.z += adjust.y * rotateStep;
+                rot.z = floor(rot.z / rotateStep + 0.5) * rotateStep;
+            }
+            node.setRotation(Quaternion(rot));
+        }
+        break;
+
+    case OBJ_SCALE:
+        {
+            Vector3 scale = node.getScale();
+            if (adjust.x != 0)
+            {
+                scale.x += adjust.x * scaleStep;
+                scale.x = floor(scale.x / scaleStep + 0.5) * scaleStep;
+            }
+            if (adjust.y != 0)
+            {
+                scale.y += adjust.y * scaleStep;
+                scale.y = floor(scale.y / scaleStep + 0.5) * scaleStep;
+            }
+            if (adjust.z != 0)
+            {
+                scale.z += adjust.z * scaleStep;
+                scale.z = floor(scale.z / scaleStep + 0.5) * scaleStep;
+            }
+            node.setScale(scale);
+        }
+        break;
+    }
+
+    // If is a physics body, make sure the physics and rendering transforms are in sync
+    RigidBody@ body = cast<RigidBody>(node);
+    if (body !is null)
+        body.setTransform(node.getPosition(), node.getRotation(), node.getScale());
+
+    updateComponentAttributes();
+}

+ 7 - 2
Bin/CoreData/Scripts/EditorImport.as

@@ -1,5 +1,7 @@
 // Urho3D editor import functions
 
+bool useLocalIDs = false;
+
 void importModel(const string& in fileName)
 {
     string modelName = "Models/" + getFileName(fileName) + ".mdl";
@@ -53,6 +55,9 @@ void importScene(const string& in fileName)
         args.push("\"" + tempSceneName + "\"");
         args.push("-p\"" + sceneResourcePath + "\"");
         
+        if (useLocalIDs)
+            args.push("-i");
+        
         if (systemRun(getExecutableDirectory() + "AssetImporter.exe", args) == 0)
         {
             string currentFileName = sceneFileName;
@@ -136,7 +141,7 @@ void importTundraScene(const string& in fileName)
     // Clear old scene, then create a zone and a directional light first
     createScene();
 
-    Entity@ zoneEntity = editorScene.createEntity();
+    Entity@ zoneEntity = editorScene.createEntity("", useLocalIDs);
     Zone@ zone = zoneEntity.createComponent("Zone");
     Light@ sunLight = zoneEntity.createComponent("Light");
     sunLight.setLightType(LIGHT_DIRECTIONAL);
@@ -226,7 +231,7 @@ void importTundraScene(const string& in fileName)
         if (!found)
             convertModel(meshName, filePath);
 
-        Entity@ newEntity = editorScene.createEntity(entityName);
+        Entity@ newEntity = editorScene.createEntity(entityName, useLocalIDs);
         StaticModel@ model = newEntity.createComponent("StaticModel");
         
         model.setTransform(pos, Quaternion(rot), scale);

+ 0 - 1
Bin/CoreData/Scripts/EditorScene.as

@@ -8,7 +8,6 @@ Window@ sceneSettingsDialog;
 
 string sceneFileName;
 string sceneResourcePath;
-float newNodeDistance = 20;
 bool sceneModified = false;
 bool runPhysics = false;
 bool renderingDebug = false;

+ 17 - 5
Bin/CoreData/Scripts/EditorUI.as

@@ -18,8 +18,8 @@ void createUI()
     createMenuBar();
     createSceneWindow();
     createComponentWindow();
-    createCameraDialog();
     createSceneSettingsDialog();
+    createEditorSettingsDialog();
     createStatsBar();
     createConsole();
     
@@ -85,7 +85,7 @@ void createMenuBar()
         filePopup.addChild(createMenuItem("Scene hierarchy", 'H', QUAL_CTRL));
         filePopup.addChild(createMenuItem("Entity / component edit", 'E', QUAL_CTRL));
         filePopup.addChild(createMenuItem("Global scene settings", 0, 0));
-        filePopup.addChild(createMenuItem("Camera settings", 0, 0));
+        filePopup.addChild(createMenuItem("Editor settings", 0, 0));
         uiMenuBar.addChild(fileMenu);
     }
 
@@ -252,8 +252,8 @@ void handleMenuSelected(StringHash eventType, VariantMap& eventData)
     if (action == "Entity / component edit")
         showComponentWindow();
 
-    if (action == "Camera settings")
-        showCameraDialog();
+    if (action == "Editor settings")
+        showEditorSettingsDialog();
     
     if (action == "Cut")
         sceneCut();
@@ -357,7 +357,7 @@ void handleKeyDown(StringHash eventType, VariantMap& eventData)
         UIElement@ front = ui.getFrontElement();
         if ((uiFileSelector !is null) && (front is uiFileSelector.getWindow()))
             closeFileSelector();
-        else if ((front is sceneSettingsDialog) || (front is cameraDialog) || (front is sceneWindow) || (front is componentWindow))
+        else if ((front is sceneSettingsDialog) || (front is editorSettingsDialog) || (front is sceneWindow) || (front is componentWindow))
             front.setVisible(false);
     }
 
@@ -367,4 +367,16 @@ void handleKeyDown(StringHash eventType, VariantMap& eventData)
         togglePhysicsDebug();
     if (key == KEY_F3)
         toggleOctreeDebug();
+        
+    if (eventData["Qualifiers"].getInt() == QUAL_CTRL)
+    {
+        if (key == '1')
+            moveMode = OBJ_MOVE;
+        else if (key == '2')
+            moveMode = OBJ_ROTATE;
+        else if (key == '3')
+            moveMode = OBJ_SCALE;
+        else
+            steppedObjectManipulation(key);
+    }
 }

+ 0 - 55
Bin/CoreData/UI/CameraDialog.xml

@@ -1,55 +0,0 @@
-<element type="Window" name="CameraDialog">
-    <movable enable="true" />
-    <layout mode="vertical" spacing="4" border="6 6 6 6" />
-    <element>
-        <fixedheight value="16" />
-        <layout mode="horizontal" />
-        <element type="Text">
-            <text value="Editor camera settings" />
-        </element>
-        <element type="Button" style="CloseButton" name="CloseButton" />
-    </element>
-    <element type="BorderImage" style="EditorDivider">
-        <fixedheight value="4" />
-    </element>
-    <element>
-        <fixedheight value="17" />
-        <layout mode="horizontal" spacing="20" />
-        <element type="Text">
-            <text value="Near clip distance" />
-        </element>
-        <element type="LineEdit" name="NearClipEdit">
-            <fixedwidth value="80" />
-        </element>
-    </element>
-    <element>
-        <fixedheight value="17" />
-        <layout mode="horizontal" spacing="20" />
-        <element type="Text">
-            <text value="Far clip distance" />
-        </element>
-       <element type="LineEdit" name="FarClipEdit">
-            <fixedwidth value="80" />
-        </element>
-    </element>
-    <element>
-        <fixedheight value="17" />
-        <layout mode="horizontal" spacing="20" />
-        <element type="Text">
-            <text value="Field of view" />
-        </element>
-       <element type="LineEdit" name="FOVEdit">
-            <fixedwidth value="80" />
-       </element>
-    </element>
-    <element>
-        <fixedheight value="17" />
-        <layout mode="horizontal" spacing="20" />
-        <element type="Text">
-            <text value="Movement speed" />
-        </element>
-       <element type="LineEdit" name="SpeedEdit">
-            <fixedwidth value="80" />
-       </element>
-    </element>
-</element>

+ 129 - 0
Bin/CoreData/UI/EditorSettingsDialog.xml

@@ -0,0 +1,129 @@
+<element type="Window" name="CameraDialog">
+    <movable enable="true" />
+    <layout mode="vertical" spacing="4" border="6 6 6 6" />
+    <element>
+        <fixedheight value="16" />
+        <layout mode="horizontal" />
+        <element type="Text">
+            <text value="Editor camera settings" />
+        </element>
+        <element type="Button" style="CloseButton" name="CloseButton" />
+    </element>
+    <element type="BorderImage" style="EditorDivider">
+        <fixedheight value="4" />
+    </element>
+    <element>
+        <fixedheight value="17" />
+        <layout mode="horizontal" spacing="20" />
+        <element type="Text">
+            <text value="Near clip distance" />
+        </element>
+        <element type="LineEdit" name="NearClipEdit">
+            <fixedwidth value="80" />
+        </element>
+    </element>
+    <element>
+        <fixedheight value="17" />
+        <layout mode="horizontal" spacing="20" />
+        <element type="Text">
+            <text value="Far clip distance" />
+        </element>
+        <element type="LineEdit" name="FarClipEdit">
+            <fixedwidth value="80" />
+         </element>
+    </element>
+    <element>
+        <fixedheight value="17" />
+        <layout mode="horizontal" spacing="20" />
+        <element type="Text">
+            <text value="Field of view" />
+        </element>
+        <element type="LineEdit" name="FOVEdit">
+            <fixedwidth value="80" />
+        </element>
+    </element>
+    <element>
+        <fixedheight value="17" />
+        <layout mode="horizontal" spacing="20" />
+        <element type="Text">
+            <text value="Movement speed" />
+        </element>
+        <element type="LineEdit" name="SpeedEdit">
+            <fixedwidth value="80" />
+        </element>
+    </element>
+    <element type="BorderImage" style="EditorDivider">
+        <fixedheight value="4" />
+    </element>
+    <element>
+        <fixedheight value="17" />
+        <layout mode="horizontal" spacing="20" />
+        <element type="Text">
+            <text value="New node distance" />
+        </element>
+        <element type="LineEdit" name="DistanceEdit">
+            <fixedwidth value="80" />
+        </element>
+    </element>
+    <element>
+        <fixedheight value="17" />
+        <layout mode="horizontal" spacing="8" />
+        <element type="Text">
+            <text value="Node move step" />
+        </element>
+        <element type="CheckBox" name="MoveSnapToggle">
+            <fixedsize value="16 16" />
+        </element>
+        <element type="Text">
+            <fixedwidth value="34" />
+            <text value="Snap" />
+        </element>
+        <element type="LineEdit" name="MoveStepEdit">
+            <fixedwidth value="80" />
+        </element>
+    </element>
+    <element>
+        <fixedheight value="17" />
+        <layout mode="horizontal" spacing="8" />
+        <element type="Text">
+            <text value="Node rotate step" />
+        </element>
+        <element type="CheckBox" name="RotateSnapToggle">
+            <fixedsize value="16 16" />
+        </element>
+        <element type="Text">
+            <fixedwidth value="34" />
+            <text value="Snap" />
+        </element>
+        <element type="LineEdit" name="RotateStepEdit">
+            <fixedwidth value="80" />
+        </element>
+    </element>
+    <element>
+        <fixedheight value="17" />
+        <layout mode="horizontal" spacing="8" />
+        <element type="Text">
+            <text value="Node scale step" />
+        </element>
+        <element type="CheckBox" name="ScaleSnapToggle">
+            <fixedsize value="16 16" />
+        </element>
+        <element type="Text">
+            <fixedwidth value="34" />
+            <text value="Snap" />
+        </element>
+        <element type="LineEdit" name="ScaleStepEdit">
+            <fixedwidth value="80" />
+        </element>
+    </element>
+    <element>
+        <fixedheight value="17" />
+        <layout mode="horizontal" spacing="8" />
+        <element type="CheckBox" name="LocalIDToggle">
+            <fixedsize value="16 16" />
+        </element>
+        <element type="Text">
+            <text value="Use local entity IDs on import" />
+        </element>
+    </element>
+</element>

+ 1 - 1
Bin/Editor.bat

@@ -1 +1 @@
-Urho3D Scripts/Editor.as -w -x1024 -y768 %1 %2 %3 %4 %5 %6 %7 %8
+Urho3D Scripts/Editor.as -w -x1024 -y640 %1 %2 %3 %4 %5 %6 %7 %8

+ 25 - 18
Editor.txt

@@ -10,24 +10,31 @@ Urho3D.exe Scripts/Editor.as
 Controls
 --------
 
-Left mouse     - Select renderable components
-Right mouse    - Hold down and move mouse to rotate camera
-
-WSAD or arrows - Move
-Shift+WSAD     - Move faster
-Ctrl+O         - Open scene
-Ctrl+S         - Save scene
-Ctrl+Shift+S   - Save scene as
-Ctrl+X,C,V     - Cut/copy/paste entity or component
-Ctrl+E	       - Open the Entity / component edit window
-Ctrl+H	       - Open the Scene hierarchy window
-Ctrl+P         - Toggle physics on/off
-Ctrl+R         - Reload resources
-ESC            - Close the topmost window
-DEL            - Delete entity or component
-F1             - Toggle rendering debug geometry
-F2             - Toggle physics debug geometry
-F3             - Toggle octree debug geometry
+Left mouse      - Select renderable objects (components)
+Right mouse     - Hold down and move mouse to rotate camera
+
+WSAD or arrows  - Move
+Shift+WSAD      - Move faster
+Ctrl+1,2,3      - Select manipulation mode: move/rotate/scale
+Ctrl+arrows     - Manipulate object in X & Z directions
+Ctrl+pgup/pgdn  - Manipulate object in Y direction
+Ctrl+plus/minus - Scale object uniformly (scale mode only)
+Ctrl+O          - Open scene
+Ctrl+S          - Save scene
+Ctrl+Shift+S    - Save scene as
+Ctrl+X,C,V      - Cut/copy/paste entity or component
+Ctrl+E	        - Open the Entity / component edit window
+Ctrl+H	        - Open the Scene hierarchy window
+Ctrl+P          - Toggle physics on/off
+Ctrl+R          - Reload resources
+ESC             - Close the topmost window
+DEL             - Delete entity or component
+F1              - Toggle rendering debug geometry
+F2              - Toggle physics debug geometry
+F3              - Toggle octree debug geometry
+
+Press right mouse button in the 3D view if you want to defocus the active
+window without changing the object selection.
 
 
 Workflow

+ 10 - 7
Engine/Engine/RegisterMath.cpp

@@ -86,6 +86,9 @@ static void registerMathFunctions(asIScriptEngine* engine)
     engine->RegisterGlobalFunction("float max(float, float)", asFUNCTIONPR(max, (float, float), float), asCALL_CDECL);
     engine->RegisterGlobalFunction("float clamp(float, float, float)", asFUNCTIONPR(clamp, (float, float, float), float), asCALL_CDECL);
     engine->RegisterGlobalFunction("float lerp(float, float, float)", asFUNCTIONPR(lerp, (float, float, float), float), asCALL_CDECL);
+    engine->RegisterGlobalFunction("float mod(float, float)", asFUNCTION(fmodf), asCALL_CDECL);
+    engine->RegisterGlobalFunction("float floor(float)", asFUNCTION(floorf), asCALL_CDECL);
+    engine->RegisterGlobalFunction("float ceil(float)", asFUNCTION(ceilf), asCALL_CDECL);
 }
 
 static void ConstructIntRect(IntRect* ptr)
@@ -111,7 +114,7 @@ static void registerIntRect(asIScriptEngine* engine)
     engine->RegisterObjectBehaviour("IntRect", asBEHAVE_CONSTRUCT, "void f(const IntRect& in)", asFUNCTION(ConstructIntRectCopy), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("IntRect", asBEHAVE_CONSTRUCT, "void f(int, int, int, int)", asFUNCTION(ConstructIntRectInit), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("IntRect", "IntRect &opAssign(const IntRect& in)", asMETHOD(IntRect, operator =), asCALL_THISCALL);
-    engine->RegisterObjectMethod("IntRect", "bool &opEquals(const IntRect& in) const", asMETHOD(IntRect, operator ==), asCALL_THISCALL);
+    engine->RegisterObjectMethod("IntRect", "bool opEquals(const IntRect& in) const", asMETHOD(IntRect, operator ==), asCALL_THISCALL);
     engine->RegisterObjectProperty("IntRect", "int left", offsetof(IntRect, mLeft));
     engine->RegisterObjectProperty("IntRect", "int top", offsetof(IntRect, mTop));
     engine->RegisterObjectProperty("IntRect", "int right", offsetof(IntRect, mRight));
@@ -145,7 +148,7 @@ static void registerIntVector2(asIScriptEngine* engine)
     engine->RegisterObjectMethod("IntVector2", "IntVector2 &opSubAssign(const IntVector2& in)", asMETHOD(IntVector2, operator -=), asCALL_THISCALL);
     engine->RegisterObjectMethod("IntVector2", "IntVector2 &opMulAssign(int)", asMETHODPR(IntVector2, operator *=, (int), IntVector2&), asCALL_THISCALL);
     engine->RegisterObjectMethod("IntVector2", "IntVector2 &opDivAssign(int)", asMETHODPR(IntVector2, operator /=, (int), IntVector2&), asCALL_THISCALL);
-    engine->RegisterObjectMethod("IntVector2", "bool &opEquals(const IntVector2& in) const", asMETHOD(IntVector2, operator ==), asCALL_THISCALL);
+    engine->RegisterObjectMethod("IntVector2", "bool opEquals(const IntVector2& in) const", asMETHOD(IntVector2, operator ==), asCALL_THISCALL);
     engine->RegisterObjectMethod("IntVector2", "IntVector2 opNeg() const", asMETHODPR(IntVector2, operator -, () const, IntVector2), asCALL_THISCALL);
     engine->RegisterObjectMethod("IntVector2", "IntVector2 opAdd(const IntVector2& in) const", asMETHOD(IntVector2, operator +), asCALL_THISCALL);
     engine->RegisterObjectMethod("IntVector2", "IntVector2 opSub(const IntVector2& in) const", asMETHODPR(IntVector2, operator -, (const IntVector2&) const, IntVector2), asCALL_THISCALL);
@@ -185,7 +188,7 @@ static void registerVector2(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Vector2", "Vector2 &opMulAssign(float)", asMETHODPR(Vector2, operator *=, (float), Vector2&), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector2", "Vector2 &opDivAssign(const Vector2& in)", asMETHODPR(Vector2, operator /=, (const Vector2&), Vector2&), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector2", "Vector2 &opDivAssign(float)", asMETHODPR(Vector2, operator /=, (float), Vector2&), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Vector2", "bool &opEquals(const Vector2& in) const", asMETHOD(Vector2, operator ==), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Vector2", "bool opEquals(const Vector2& in) const", asMETHOD(Vector2, operator ==), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector2", "Vector2 opNeg() const", asMETHODPR(Vector2, operator -, () const, Vector2), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector2", "Vector2 opAdd(const Vector2& in) const", asMETHOD(Vector2, operator +), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector2", "Vector2 opSub(const Vector2& in) const", asMETHODPR(Vector2, operator -, (const Vector2&) const, Vector2), asCALL_THISCALL);
@@ -234,7 +237,7 @@ static void registerVector3(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Vector3", "Vector3 &opMulAssign(float)", asMETHODPR(Vector3, operator *=, (float), Vector3&), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector3", "Vector3 &opDivAssign(const Vector3& in)", asMETHODPR(Vector3, operator /=, (const Vector3&), Vector3&), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector3", "Vector3 &opDivAssign(float)", asMETHODPR(Vector3, operator /=, (float), Vector3&), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Vector3", "bool &opEquals(const Vector3& in) const", asMETHOD(Vector3, operator ==), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Vector3", "bool opEquals(const Vector3& in) const", asMETHOD(Vector3, operator ==), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector3", "Vector3 opNeg() const", asMETHODPR(Vector3, operator -, () const, Vector3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector3", "Vector3 opAdd(const Vector3& in) const", asMETHOD(Vector3, operator +), asCALL_THISCALL);
     engine->RegisterObjectMethod("Vector3", "Vector3 opSub(const Vector3& in) const", asMETHODPR(Vector3, operator -, (const Vector3&) const, Vector3), asCALL_THISCALL);
@@ -401,7 +404,7 @@ static void registerRay(asIScriptEngine* engine)
     engine->RegisterObjectBehaviour("Ray", asBEHAVE_CONSTRUCT, "void f(const Ray& in)", asFUNCTION(ConstructRayCopy), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("Ray", asBEHAVE_CONSTRUCT, "void f(const Vector3& in, const Vector3& in)", asFUNCTION(ConstructRayInit), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Ray", "Ray &opAssign(const Ray& in)", asMETHOD(Ray, operator =), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Ray", "bool &opEquals(const Ray& in) const", asMETHOD(Ray, operator ==), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Ray", "bool opEquals(const Ray& in) const", asMETHOD(Ray, operator ==), asCALL_THISCALL);
     engine->RegisterObjectMethod("Ray", "void define(const Vector3& in, const Vector3& in)", asMETHOD(Ray, define), asCALL_THISCALL);
     engine->RegisterObjectMethod("Ray", "float getDistance(const Vector3& in, const Vector3& in, const Vector3& in) const", asMETHODPR(Ray, getDistance, (const Vector3&, const Vector3&, const Vector3&) const, float), asCALL_THISCALL);
     engine->RegisterObjectProperty("Ray", "Vector3 origin", offsetof(Ray, mOrigin));
@@ -437,7 +440,7 @@ static void registerRect(asIScriptEngine* engine)
     engine->RegisterObjectBehaviour("Rect", asBEHAVE_CONSTRUCT, "void f(float, float, float, float)", asFUNCTION(ConstructRectInit), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("Rect", asBEHAVE_CONSTRUCT, "void f(const Vector2& in, const Vector2& in)", asFUNCTION(ConstructRectInitVec), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Rect", "Rect &opAssign(const Rect& in)", asMETHOD(Rect, operator =), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Rect", "bool &opEquals(const Rect& in) const", asMETHOD(Rect, operator ==), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Rect", "bool opEquals(const Rect& in) const", asMETHOD(Rect, operator ==), asCALL_THISCALL);
     engine->RegisterObjectMethod("Rect", "void define(const Vector2& in, const Vector2& in)", asMETHODPR(Rect, define, (const Vector2&, const Vector2&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Rect", "void define(const Vector2& in)", asMETHODPR(Rect, define, (const Vector2&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Rect", "void merge(const Vector2& in)", asMETHODPR(Rect, merge, (const Vector2&), void), asCALL_THISCALL);
@@ -524,7 +527,7 @@ static void registerVolumes(asIScriptEngine* engine)
     engine->RegisterObjectBehaviour("BoundingBox", asBEHAVE_CONSTRUCT, "void f(const Vector3& in, const Vector3& in)", asFUNCTION(ConstructBoundingBoxInit), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("BoundingBox", asBEHAVE_CONSTRUCT, "void f(float, float)", asFUNCTION(ConstructBoundingBoxFloat), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("BoundingBox", "BoundingBox &opAssign(const BoundingBox& in)", asMETHODPR(BoundingBox, operator =, (const BoundingBox&), BoundingBox&), asCALL_THISCALL);
-    engine->RegisterObjectMethod("BoundingBox", "bool &opEquals(const BoundingBox& in) const", asMETHOD(BoundingBox, operator ==), asCALL_THISCALL);
+    engine->RegisterObjectMethod("BoundingBox", "bool opEquals(const BoundingBox& in) const", asMETHOD(BoundingBox, operator ==), asCALL_THISCALL);
     engine->RegisterObjectMethod("BoundingBox", "void define(const Vector3& in, const Vector3& in)", asMETHODPR(BoundingBox, define, (const Vector3&, const Vector3&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("BoundingBox", "void define(float, float)", asMETHODPR(BoundingBox, define, (float, float), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("BoundingBox", "void define(const Frustum& in)", asMETHODPR(BoundingBox, define, (const Frustum&), void), asCALL_THISCALL);

+ 4 - 1
Engine/Physics/RigidBody.cpp

@@ -565,8 +565,11 @@ void RigidBody::setTransform(const Vector3& position, const Quaternion& rotation
 
 void RigidBody::setTransform(const Vector3& position, const Quaternion& rotation, const Vector3& scale)
 {
+    // Note: here we always update geometries. This form is called from the editor, which actually changes the Node scale first,
+    // so the usual check for changed scale would fail. Is slow and not to be called from any game loop logic or network code
     setTransform(position, rotation);
-    setScale(scale);
+    Node::setScale(scale);
+    updateGeometries();
 }
 
 void RigidBody::scale(float scale)

+ 3 - 2
Engine/UI/Text.cpp

@@ -482,8 +482,9 @@ void Text::updateText(bool inResize)
         mCharPositions[mText.length()] = IntVector2(x, y);
     }
     
-    // Set minimum size according to the text size
-    setMinWidth(width);
+    // Set minimum size according to the text size, but respect fixed width if set
+    if (getMinWidth() != getMaxWidth())
+        setMinWidth(width);
     setFixedHeight(height);
 }
 

+ 212 - 11
License.txt

@@ -1,20 +1,221 @@
+Urho3D license
+--------------
+
 Urho3D Engine
 Copyright (c) 2008-2011 Lasse Öörni
 
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+DEALINGS IN THE SOFTWARE.
+
+
+AngelScript license
+-------------------
+
+AngelCode Scripting Library
+Copyright (c) 2003-2011 Andreas Jonsson
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you
+   must not claim that you wrote the original software. If you use
+   this software in a product, an acknowledgment in the product
+   documentation would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+   must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+   distribution.
+
+The original version of this library can be located at:
+http://www.angelcode.com/angelscript/
+
+Andreas Jonsson
[email protected]
+
+
+Open Asset Import Library license
+---------------------------------
+
+Open Asset Import Library (Assimp)
+
+
+Copyright (c) 2006-2010, Assimp Development Team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the ASSIMP team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the ASSIMP Development Team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+ENet license
+------------
+
+Copyright (c) 2002-2010 Lee Salzman
+
+Permission is hereby granted, free of charge, to any person obtaining a 
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation 
+the rights to use, copy, modify, merge, publish, distribute, sublicense, 
+and/or sell copies of the Software, and to permit persons to whom the 
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+DEALINGS IN THE SOFTWARE.
+
+
+The FreeType Project disclaimer
+-------------------------------
+
+Portions of this software are copyright © 2010 The FreeType Project 
+(www.freetype.org).  All rights reserved.
+
+
+Open Dynamics Engine license
+----------------------------
+
+Open Dynamics Engine
+Copyright (c) 2001-2007, Russell L. Smith.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+Neither the names of ODE's copyright owner nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+StanHull license
+----------------
+
+Copyright (c) 2004 Open Dynamics Framework Group
+			www.physicstools.org
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without 
+modification, are permitted provided that the following conditions 
+are met:
+
+Redistributions of source code must retain the above copyright notice, 
+this list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation 
+and/or other materials provided with the distribution.
+
+Neither the name of the Open Dynamics Framework Group nor the names of
+its contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR 
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+TinyXML license
+---------------
+
+TinyXML is released under the zlib license:
+
+This software is provided 'as-is', without any express or implied 
+warranty. In no event will the authors be held liable for any 
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any 
+purpose, including commercial applications, and to alter it and 
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must 
+not claim that you wrote the original software. If you use this 
+software in a product, an acknowledgment in the product documentation 
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and 
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source 
+distribution.

+ 0 - 3
Readme.txt

@@ -41,9 +41,6 @@ Urho3D uses the following third-party libraries:
 - stb_vorbis (0.99996)
 - TinyXML (2.6.1)
 
-See ThirdParty/<libraryname> for third-party license information where
-available.
-
 Ninja model, BlueHighway font and smoke/flare/status bar textures are from OGRE.
 
 Jack and mushroom models are from the realXtend project. (http://www.realxtend.org)