Browse Source

Some renames. CollisionGroup -> CollisionLayer, Scene::GetNodeByID() -> GetNode(), Ray::Distance() -> HitDistance().
Moved all hit distance tests to Ray.
Tundra scene physics import.

Lasse Öörni 14 years ago
parent
commit
3f7fffbf49
40 changed files with 389 additions and 304 deletions
  1. 5 0
      Bin/CoreData/Materials/DefaultGrey.xml
  2. 136 49
      Bin/Data/Scripts/Editor/EditorImport.as
  3. 3 3
      Bin/Data/Scripts/Editor/EditorNodeWindow.as
  4. 6 6
      Bin/Data/Scripts/Editor/EditorSceneWindow.as
  5. 3 3
      Bin/Data/Scripts/NinjaSnowWar.as
  6. 1 1
      Bin/Data/Scripts/NinjaSnowWar/GameObject.as
  7. 1 1
      Bin/Data/Scripts/NinjaSnowWar/Ninja.as
  8. 2 2
      Bin/Data/Scripts/NinjaSnowWar/Potion.as
  9. 1 1
      Bin/Data/Scripts/NinjaSnowWar/SnowBall.as
  10. 1 1
      Bin/Data/Scripts/NinjaSnowWar/SnowCrate.as
  11. 5 5
      Bin/Data/Scripts/TestScene.as
  12. 1 1
      Docs/Reference.dox
  13. 18 18
      Docs/ScriptAPI.dox
  14. 3 3
      Engine/Engine/APITemplates.h
  15. 6 5
      Engine/Engine/MathAPI.cpp
  16. 2 2
      Engine/Engine/PhysicsAPI.cpp
  17. 2 2
      Engine/Engine/SceneAPI.cpp
  18. 4 4
      Engine/Graphics/AnimatedModel.cpp
  19. 1 1
      Engine/Graphics/Geometry.cpp
  20. 2 2
      Engine/Graphics/Octree.cpp
  21. 2 2
      Engine/Graphics/StaticModel.cpp
  22. 0 79
      Engine/Math/BoundingBox.cpp
  23. 0 3
      Engine/Math/BoundingBox.h
  24. 0 13
      Engine/Math/Plane.h
  25. 123 4
      Engine/Math/Ray.cpp
  26. 14 4
      Engine/Math/Ray.h
  27. 0 28
      Engine/Math/Sphere.cpp
  28. 0 3
      Engine/Math/Sphere.h
  29. 13 13
      Engine/Network/Connection.cpp
  30. 5 5
      Engine/Physics/CollisionShape.cpp
  31. 3 3
      Engine/Physics/CollisionShape.h
  32. 2 2
      Engine/Physics/Joint.cpp
  33. 1 0
      Engine/Physics/PhysicsWorld.cpp
  34. 2 2
      Engine/Scene/Component.cpp
  35. 4 4
      Engine/Scene/Component.h
  36. 3 14
      Engine/Scene/Node.cpp
  37. 4 6
      Engine/Scene/Node.h
  38. 2 2
      Engine/Scene/Scene.cpp
  39. 3 2
      Engine/Scene/Scene.h
  40. 5 5
      Tools/AssetImporter/AssetImporter.cpp

+ 5 - 0
Bin/CoreData/Materials/DefaultGrey.xml

@@ -0,0 +1,5 @@
+<material>
+    <technique name="Techniques/NoTexture.xml" />
+    <parameter name="MatDiffColor" value="0.5 0.5 0.5 1" />
+    <parameter name="MatSpecProperties" value="0.5 16" />
+</material>

+ 136 - 49
Bin/Data/Scripts/Editor/EditorImport.as

@@ -77,7 +77,6 @@ void ImportScene(const String&in fileName)
     }
 }
 
-
 void ImportTundraScene(const String&in fileName)
 {
     fileSystem.CreateDir(sceneResourcePath + "Materials");
@@ -97,21 +96,27 @@ void ImportTundraScene(const String&in fileName)
 
     // Clear old scene, then create a zone and a directional light first
     CreateScene();
+    
+    // Set standard gravity
+    editorScene.physicsWorld.gravity = Vector3(0, -9.81, 0);
 
+    // Create zone & global light
     Node@ zoneNode = editorScene.CreateChild("Zone", useLocalIDs ? LOCAL : REPLICATED);
     Zone@ zone = zoneNode.CreateComponent("Zone");
+    zone.boundingBox = BoundingBox(-1000, 1000);
+    zone.ambientColor = Color(0.5, 0.5, 0.5);
+    zone.fogColor = Color(0.5, 0.7, 1.0);
+    zone.fogStart = 100.0;
+    zone.fogEnd = 500.0;
+
     Node@ lightNode = editorScene.CreateChild("GlobalLight", useLocalIDs ? LOCAL : REPLICATED);
     Light@ light = lightNode.CreateComponent("Light");
     lightNode.rotation = Quaternion(60, 30, 0);
     light.lightType = LIGHT_DIRECTIONAL;
     light.castShadows = true;
     light.shadowCascade = CascadeParameters(3, 0.95, 0.2, 1000000);
-    zone.boundingBox = BoundingBox(-1000, 1000);
-    zone.ambientColor = Color(0.5, 0.5, 0.5);
-    zone.fogColor = Color(0.5, 0.7, 1.0);
-    zone.fogStart = 100.0;
-    zone.fogEnd = 500.0;
 
+    // Loop through scene entities
     while (!entityElem.isNull)
     {
         String nodeName;
@@ -126,6 +131,15 @@ void ImportTundraScene(const String&in fileName)
         bool castShadows = false;
         float drawDistance = 0;
         Array<String> materialNames;
+        
+        int shapeType = -1;
+        float mass = 0.0f;
+        Vector3 bodySize;
+        bool phantom = false;
+        bool kinematic = false;
+        uint collisionLayer;
+        uint collisionMask;
+        String collisionMeshName;
 
         XMLElement compElem = entityElem.GetChild("component");
         while (!compElem.isNull)
@@ -158,49 +172,37 @@ void ImportTundraScene(const String&in fileName)
                 scale = GetVector3FromStrings(coords, 6);
                 parentName = GetComponentAttribute(compElem, "Parent entity ref");
             }
-            
+            if (compType == "EC_RigidBody")
+            {
+                shapeType = GetComponentAttribute(compElem, "Shape type").ToInt();
+                mass = GetComponentAttribute(compElem, "Mass").ToFloat();
+                bodySize = GetComponentAttribute(compElem, "Size").ToVector3();
+                collisionMeshName = GetComponentAttribute(compElem, "Collision mesh ref");
+                phantom = GetComponentAttribute(compElem, "Phantom").ToBool();
+                kinematic = GetComponentAttribute(compElem, "Kinematic").ToBool();
+                collisionLayer = GetComponentAttribute(compElem, "Collision Layer").ToInt();
+                collisionMask = GetComponentAttribute(compElem, "Collision Mask").ToInt();
+                ProcessRef(collisionMeshName);
+            }
+
             compElem = compElem.GetNext("component");
         }
 
-        // For now we are only interested of meshes
-        if (!meshName.empty)
+        // If collision mesh not specified for the rigid body, assume same as the visible mesh
+        if ((shapeType == 4 || shapeType == 6) && collisionMeshName.Trimmed().empty)
+            collisionMeshName = meshName;
+
+        if (!meshName.empty || shapeType >= 0)
         {
             for (uint i = 0; i < materialNames.length; ++i)
-            {
-                bool found = false;
-                for (uint j = 0; j < convertedMaterials.length; ++j)
-                {
-                    if (convertedMaterials[j] == materialNames[i])
-                    {
-                        found = true;
-                        break;
-                    }                    
-                }
-    
-                if (!found)
-                {
-                    ConvertMaterial(materialNames[i], filePath);
-                    convertedMaterials.Push(materialNames[i]);
-                }
-            }
-    
-            bool found = false;
-            for (uint i = 0; i < convertedMeshes.length; ++i)
-            {
-                if (convertedMeshes[i] == meshName)
-                {
-                    found = true;
-                    break;
-                }
-            }
-            if (!found)
-                ConvertModel(meshName, filePath);
-    
+                ConvertMaterial(materialNames[i], filePath, convertedMaterials);
+            
+            ConvertModel(meshName, filePath, convertedMeshes);
+            ConvertModel(collisionMeshName, filePath, convertedMeshes);
+
             Node@ newNode = editorScene.CreateChild(nodeName, useLocalIDs ? LOCAL : REPLICATED);
-            StaticModel@ model = newNode.CreateComponent("StaticModel");
 
             // Calculate final transform in an Ogre-like fashion
-            /// \todo Tundra 2.0 supports entity parenting. It is not yet taken into account
             Quaternion quat = GetTransformQuaternion(rot);
             Quaternion meshQuat = GetTransformQuaternion(meshRot);
             Quaternion finalQuat = quat * meshQuat;
@@ -208,12 +210,75 @@ void ImportTundraScene(const String&in fileName)
             Vector3 finalPos = pos + quat * (scale * meshPos);
 
             newNode.SetTransform(finalPos, finalQuat, finalScale);
-            model.model = cache.GetResource("Model", "Models/" + meshName.Replaced(".mesh", ".mdl"));
-            model.drawDistance = drawDistance;
-            model.castShadows = castShadows;
-            for (uint i = 0; i < materialNames.length; ++i)
-                model.materials[i] = cache.GetResource("Material", "Materials/" + materialNames[i].Replaced(".material", ".xml"));
+
+            // Create model
+            if (!meshName.empty)
+            {
+                StaticModel@ model = newNode.CreateComponent("StaticModel");
+                model.model = cache.GetResource("Model", "Models/" + meshName.Replaced(".mesh", ".mdl"));
+                model.drawDistance = drawDistance;
+                model.castShadows = castShadows;
+                // Set default grey material to match Tundra defaults
+                model.material = cache.GetResource("Material", "Materials/DefaultGrey.xml");
+                // Then try to assign the actual materials
+                for (uint i = 0; i < materialNames.length; ++i)
+                {
+                    Material@ mat = cache.GetResource("Material", "Materials/" + materialNames[i].Replaced(".material", ".xml"));
+                    if (mat !is null)
+                        model.materials[i] = mat;
+                }
+            }
+            
+            // Create collision shape
+            if (shapeType >= 0)
+            {
+                // If mesh has scaling, undo it for the collision shape
+                bodySize.x /= meshScale.x;
+                bodySize.y /= meshScale.y;
+                bodySize.z /= meshScale.z;
+
+                CollisionShape@ shape = newNode.CreateComponent("CollisionShape");
+                switch (shapeType)
+                {
+                case 0:
+                    shape.SetBox(bodySize);
+                    break;
+
+                case 1:
+                    shape.SetSphere(bodySize.x * 0.5);
+                    break;
+
+                case 2:
+                    shape.SetCylinder(bodySize.x * 0.5, bodySize.y, Vector3(0, 0, 0), Quaternion(90, 0, 0));
+                    break;
+
+                case 3:
+                    shape.SetCapsule(bodySize.x * 0.5, bodySize.y - bodySize.x, Vector3(0, 0, 0), Quaternion(90, 0, 0));
+                    break;
+                    
+                case 4:
+                    shape.SetTriangleMesh(cache.GetResource("Model", "Models/" + collisionMeshName.Replaced(".mesh", ".mdl")), 0, bodySize);
+                    break;
+                    
+                case 6:
+                    shape.SetConvexHull(cache.GetResource("Model", "Models/" + collisionMeshName.Replaced(".mesh", ".mdl")), 0.1, 0, bodySize);
+                    break;
+                }
                 
+                shape.collisionLayer = collisionLayer;
+                shape.collisionMask = collisionMask;
+                shape.phantom = phantom;
+
+                // Create rigid body if the object should be dynamic or kinematic
+                if (mass > 0.0)
+                {
+                    RigidBody@ body = newNode.CreateComponent("RigidBody");
+                    //if (kinematic)
+                    //    mass = 0.0;
+                    body.mass = mass;
+                }
+            }
+
             // Store pending parent assignment if necessary
             if (!parentName.empty)
             {
@@ -230,7 +295,7 @@ void ImportTundraScene(const String&in fileName)
     // Process any parent assignments now
     for (uint i = 0; i < parentAssignments.length; ++i)
     {
-        Node@ childNode = editorScene.GetNodeByID(parentAssignments[i].childID);
+        Node@ childNode = editorScene.GetNode(parentAssignments[i].childID);
         Node@ parentNode = editorScene.GetChild(parentAssignments[i].parentName, true);
         if (childNode !is null && parentNode !is null)
             childNode.parent = parentNode;
@@ -276,8 +341,17 @@ void ProcessRef(String& ref)
         ref = ref.Substring(7);
 }
 
-void ConvertModel(const String&in modelName, const String&in filePath)
+void ConvertModel(const String&in modelName, const String&in filePath, Array<String>@ convertedModels)
 {
+    if (modelName.Trimmed().empty)
+        return;
+
+    for (uint i = 0; i < convertedModels.length; ++i)
+    {
+        if (convertedModels[i] == modelName)
+            return;
+    }
+
     // Convert .mesh to .mesh.xml
     String cmdLine = "ogrexmlconverter.exe \"" + filePath + modelName + "\" \"" + filePath + modelName + ".xml\"";
     fileSystem.SystemCommand(cmdLine.Replaced('/', '\\'));
@@ -288,10 +362,21 @@ void ConvertModel(const String&in modelName, const String&in filePath)
     args.Push("\"" + sceneResourcePath + "Models/" + modelName.Replaced(".mesh", ".mdl") + "\"");
     args.Push("-a");
     fileSystem.SystemRun(fileSystem.programDir + "OgreImporter.exe", args);
+    
+    convertedModels.Push(modelName);
 }
 
-void ConvertMaterial(const String&in materialName, const String&in filePath)
+void ConvertMaterial(const String&in materialName, const String&in filePath, Array<String>@ convertedMaterials)
 {
+    if (materialName.Trimmed().empty)
+        return;
+
+    for (uint i = 0; i < convertedMaterials.length; ++i)
+    {
+        if (convertedMaterials[i] == materialName)
+            return;
+    }
+
     String fileName = filePath + materialName;
     String outFileName = sceneResourcePath + "Materials/" + GetFileName(materialName) + ".xml";
 
@@ -341,4 +426,6 @@ void ConvertMaterial(const String&in materialName, const String&in filePath)
     
         fileSystem.Copy(filePath + textureName, sceneResourcePath + "Textures/" + textureName);
     }
+    
+    convertedMaterials.Push(materialName);
 }

+ 3 - 3
Bin/Data/Scripts/Editor/EditorNodeWindow.as

@@ -319,9 +319,9 @@ void SetAttributeEditorID(UIElement@ attrEdit, Serializable@ serializable)
 Serializable@ GetAttributeEditorTarget(UIElement@ attrEdit)
 {
     if (attrEdit.vars.Contains("NodeID"))
-        return editorScene.GetNodeByID(attrEdit.vars["NodeID"].GetUInt());
+        return editorScene.GetNode(attrEdit.vars["NodeID"].GetUInt());
     else if (attrEdit.vars.Contains("ComponentID"))
-        return editorScene.GetComponentByID(attrEdit.vars["ComponentID"].GetUInt());
+        return editorScene.GetComponent(attrEdit.vars["ComponentID"].GetUInt());
     else
         return null;
 }
@@ -866,7 +866,7 @@ void PickResourceDone(StringHash eventType, VariantMap& eventData)
         return;
     }
 
-    Component@ target = editorScene.GetComponentByID(resourcePickID);
+    Component@ target = editorScene.GetComponent(resourcePickID);
     if (target is null || resourcePicker is null)
         return;
 

+ 6 - 6
Bin/Data/Scripts/Editor/EditorSceneWindow.as

@@ -280,7 +280,7 @@ Node@ GetListNode(uint index)
     if (item is null)
         return null;
 
-    return editorScene.GetNodeByID(item.vars["NodeID"].GetUInt());
+    return editorScene.GetNode(item.vars["NodeID"].GetUInt());
 }
 
 Component@ GetListComponent(uint index)
@@ -298,7 +298,7 @@ Component@ GetListComponent(UIElement@ item)
     if (item.vars["Type"].GetInt() != ITEM_COMPONENT)
         return null;
 
-    return editorScene.GetComponentByID(item.vars["ComponentID"].GetUInt());
+    return editorScene.GetComponent(item.vars["ComponentID"].GetUInt());
 }
 
 uint GetComponentListIndex(Component@ component)
@@ -493,8 +493,8 @@ void HandleDragDropFinish(StringHash eventType, VariantMap& eventData)
     if (!accept)
         return;
 
-    Node@ sourceNode = editorScene.GetNodeByID(source.vars["NodeID"].GetUInt());
-    Node@ targetNode = editorScene.GetNodeByID(target.vars["NodeID"].GetUInt());
+    Node@ sourceNode = editorScene.GetNode(source.vars["NodeID"].GetUInt());
+    Node@ targetNode = editorScene.GetNode(target.vars["NodeID"].GetUInt());
 
     // If target is null, parent to scene
     if (targetNode is null)
@@ -542,9 +542,9 @@ bool TestSceneWindowElements(UIElement@ source, UIElement@ target)
     Node@ sourceNode;
     Node@ targetNode;
     if (source.vars.Contains("NodeID"))
-        sourceNode = editorScene.GetNodeByID(source.vars["NodeID"].GetUInt());
+        sourceNode = editorScene.GetNode(source.vars["NodeID"].GetUInt());
     if (target.vars.Contains("NodeID"))
-        editorScene.GetNodeByID(target.vars["NodeID"].GetUInt());
+        editorScene.GetNode(target.vars["NodeID"].GetUInt());
 
     if (sourceNode is null)
         return false;

+ 3 - 3
Bin/Data/Scripts/NinjaSnowWar.as

@@ -164,7 +164,7 @@ void InitScene()
     staticModel.material = cache.GetResource("Material", "Materials/Snow.xml");
     CollisionShape@ shape = staticNode.CreateComponent("CollisionShape");
     shape.SetTriangleMesh(cache.GetResource("Model", "Models/Level.mdl"), 0);
-    shape.collisionGroup = 2;
+    shape.collisionLayer = 2;
     shape.collisionMask = 3;
 
     Node@ skyNode = gameScene.CreateChild("Sky");
@@ -563,7 +563,7 @@ int FindPlayerIndex(uint nodeID)
 Node@ FindPlayerNode(int playerIndex)
 {
     if (playerIndex >= 0 && playerIndex < int(players.length))
-        return gameScene.GetNodeByID(players[playerIndex].nodeID);
+        return gameScene.GetNode(players[playerIndex].nodeID);
     else
         return null;
 }
@@ -573,7 +573,7 @@ Node@ FindOwnNode()
     if (singlePlayer)
         return gameScene.GetChild("Player", true);
     else
-        return gameScene.GetNodeByID(clientNodeID);
+        return gameScene.GetNode(clientNodeID);
 }
 
 bool CheckHiscore(int playerIndex)

+ 1 - 1
Bin/Data/Scripts/NinjaSnowWar/GameObject.as

@@ -135,7 +135,7 @@ class GameObject : ScriptObject
         CollisionShape@ otherShape = eventData["OtherShape"].GetCollisionShape();
 
         // If the other collision shape belongs to static geometry, perform world collision
-        if (otherShape.collisionGroup == 2)
+        if (otherShape.collisionLayer == 2)
             WorldCollision(eventData);
 
         // If the other node is scripted, perform object-to-object collision

+ 1 - 1
Bin/Data/Scripts/NinjaSnowWar/Ninja.as

@@ -85,7 +85,7 @@ class Ninja : GameObject
         // Create collision shape
         CollisionShape@ shape = node.CreateComponent("CollisionShape");
         shape.SetCapsule(35, 110, Vector3(), Quaternion(90, 0, 0));
-        shape.collisionGroup = 1;
+        shape.collisionLayer = 1;
         shape.collisionMask = 3;
         shape.friction = ninjaFriction;
 

+ 2 - 2
Bin/Data/Scripts/NinjaSnowWar/Potion.as

@@ -18,7 +18,7 @@ class Potion : GameObject
     {
         SubscribeToEvent("NodeCollision", "HandleNodeCollision");
     }
-    
+
     void Create(const Vector3&in position, const Quaternion&in rotation)
     {
         node.position = position;
@@ -40,7 +40,7 @@ class Potion : GameObject
         // Create collision shape
         CollisionShape@ shape = node.CreateComponent("CollisionShape");
         shape.SetBox(Vector3(20, 40, 20));
-        shape.collisionGroup = 1;
+        shape.collisionLayer = 1;
         shape.collisionMask = 3;
         shape.friction = potionFriction;
 

+ 1 - 1
Bin/Data/Scripts/NinjaSnowWar/SnowBall.as

@@ -46,7 +46,7 @@ class SnowBall : GameObject
         // Create collision shape. Create as local to avoid divergent simulation by the client
         CollisionShape@ shape = node.CreateComponent("CollisionShape", LOCAL);
         shape.SetBox(Vector3(15, 15, 15));
-        shape.collisionGroup = 1;
+        shape.collisionLayer = 1;
         shape.collisionMask = 3;
         shape.friction = snowballFriction;
 

+ 1 - 1
Bin/Data/Scripts/NinjaSnowWar/SnowCrate.as

@@ -39,7 +39,7 @@ class SnowCrate : GameObject
         // Create collision shape
         CollisionShape@ shape = node.CreateComponent("CollisionShape");
         shape.SetBox(Vector3(80, 80, 80));
-        shape.collisionGroup = 2;
+        shape.collisionLayer = 2;
         shape.collisionMask = 3;
         shape.friction = snowcrateFriction;
 

+ 5 - 5
Bin/Data/Scripts/TestScene.as

@@ -134,7 +134,7 @@ void InitScene()
 
         CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
         shape.SetBox(Vector3(2.0, 2.0, 2.0));
-        shape.collisionGroup = 2;
+        shape.collisionLayer = 2;
         shape.collisionMask = 1;
     }
 
@@ -150,7 +150,7 @@ void InitScene()
 
         CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
         shape.SetBox(Vector3(2.0, 2.0, 2.0));
-        shape.collisionGroup = 2;
+        shape.collisionLayer = 2;
         shape.collisionMask = 1;
     }
 
@@ -168,7 +168,7 @@ void InitScene()
 
         CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
         shape.SetBox(Vector3(2.0, 2.0, 2.0));
-        shape.collisionGroup = 2;
+        shape.collisionLayer = 2;
         shape.collisionMask = 1;
     }
 
@@ -186,7 +186,7 @@ void InitScene()
 
         CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
         shape.SetTriangleMesh(cache.GetResource("Model", "Models/Mushroom.mdl"), 0);
-        shape.collisionGroup = 2;
+        shape.collisionLayer = 2;
         shape.collisionMask = 1;
     }
 
@@ -414,7 +414,7 @@ void HandleSpawnBox(StringHash eventType, VariantMap& eventData)
     CollisionShape@ shape = newNode.CreateComponent("CollisionShape");
     shape.SetBox(Vector3(2, 2, 2));
     shape.friction = 1.0;
-    shape.collisionGroup = 1;
+    shape.collisionLayer = 1;
     shape.collisionMask = 3;
 
     RigidBody@ body = newNode.CreateComponent("RigidBody");

+ 1 - 1
Docs/Reference.dox

@@ -723,7 +723,7 @@ The other physics components are:
 
 Triangle meshes, convex hulls and heightfields are created by specifying a Model resource.
 
-Several collision shapes may exist in the same scene node to create compound shapes. An offset position and rotation relative to the node's transform can be specified for each. The shape (instead of RigidBody) also contains collision behaviour parameters: which other objects to collide with (see \ref CollisionShape::SetCollisionGroup "SetCollisionGroup()" and \ref CollisionShape::SetCollisionMask "SetCollisionMask()"), the friction coefficient, and the bounce coefficient.
+Several collision shapes may exist in the same scene node to create compound shapes. An offset position and rotation relative to the node's transform can be specified for each. The shape (instead of RigidBody) also contains collision behaviour parameters: which other objects to collide with (see \ref CollisionShape::SetCollisionLayer "SetCollisionLayer()" and \ref CollisionShape::SetCollisionMask "SetCollisionMask()"), the friction coefficient, and the bounce coefficient.
 
 Note that static physics objects such as unmoving level geometry should not have RigidBody components at all.
 

+ 18 - 18
Docs/ScriptAPI.dox

@@ -342,17 +342,6 @@ Properties:<br>
 - float z
 
 
-Ray
-
-Methods:<br>
-- void Define(const Vector3&, const Vector3&)
-- float Distance(const Vector3&, const Vector3&, const Vector3&) const
-
-Properties:<br>
-- Vector3 origin
-- Vector3 direction
-
-
 Rect
 
 Methods:<br>
@@ -386,7 +375,6 @@ Methods:<br>
 - Intersection IsInside(const Vector3&) const
 - Intersection IsInside(const Sphere&) const
 - Intersection IsInside(const BoundingBox&) const
-- float Distance(const Ray&) const
 
 Properties:<br>
 - Vector3 center (readonly)
@@ -410,7 +398,6 @@ Methods:<br>
 - Intersection IsInside(const Vector3&) const
 - Intersection IsInside(const Sphere&) const
 - Intersection IsInside(const BoundingBox&) const
-- float Distance(const Ray&) const
 
 Properties:<br>
 - Vector3 center
@@ -430,6 +417,19 @@ Properties:<br>
 - bool defined
 
 
+Ray
+
+Methods:<br>
+- void Define(const Vector3&, const Vector3&)
+- float HitDistance(const Sphere&) const
+- float HitDistance(const BoundingBox&) const
+- float HitDistance(const Vector3&, const Vector3&, const Vector3&) const
+
+Properties:<br>
+- Vector3 origin
+- Vector3 direction
+
+
 Color
 
 Methods:<br>
@@ -1053,7 +1053,7 @@ Methods:<br>
 - Node@[]@ GetChildrenWithScript(const String&, bool arg1 = false) const
 - Node@ GetChild(const String&, bool arg1 = false) const
 - Component@[]@ GetComponents(const String&) const
-- Component@ GetComponent(const String&, uint arg1 = 0) const
+- Component@ GetComponent(const String&) const
 - bool HasComponent(const String&) const
 - ScriptObject@ CreateScriptObject(ScriptFile@, const String&, CreateMode arg2 = REPLICATED)
 - ScriptObject@ CreateScriptObject(const String&, const String&, CreateMode arg2 = REPLICATED)
@@ -1131,7 +1131,7 @@ Methods:<br>
 - Node@[]@ GetChildrenWithScript(const String&, bool arg1 = false) const
 - Node@ GetChild(const String&, bool arg1 = false) const
 - Component@[]@ GetComponents(const String&) const
-- Component@ GetComponent(const String&, uint arg1 = 0) const
+- Component@ GetComponent(const String&) const
 - bool HasComponent(const String&) const
 - bool LoadXML(File@)
 - bool SaveXML(File@)
@@ -1144,8 +1144,8 @@ Methods:<br>
 - void RegisterVar(const String&)
 - void UnregisterVar(const String&)
 - void UnregisterAllVars(const String&)
-- Component@ GetComponentByID(uint)
-- Node@ GetNodeByID(uint)
+- Component@ GetComponent(uint)
+- Node@ GetNode(uint)
 - const String& GetVarName(ShortStringHash) const
 - void Update(float)
 
@@ -3624,7 +3624,7 @@ Properties:<br>
 - ShapeType shapeType (readonly)
 - Vector3& position
 - Quaternion& rotation
-- uint collisionGroup
+- uint collisionLayer
 - uint collisionMask
 - float friction
 - float bounce

+ 3 - 3
Engine/Engine/APITemplates.h

@@ -399,9 +399,9 @@ static Component* NodeGetComponent(unsigned index, Node* ptr)
         return components[index];
 }
 
-static Component* NodeGetComponentWithTypeAndIndex(const String& typeName, unsigned index, Node* ptr)
+static Component* NodeGetComponentWithType(const String& typeName, Node* ptr)
 {
-    return ptr->GetComponent(ShortStringHash(typeName), index);
+    return ptr->GetComponent(ShortStringHash(typeName));
 }
 
 static CScriptArray* NodeGetComponentsWithType(const String& typeName, Node* ptr)
@@ -516,7 +516,7 @@ template <class T> void RegisterNode(asIScriptEngine* engine, const char* classN
     engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithScript(const String&in, bool recursive = false) const", asFUNCTION(NodeGetChildrenWithClassName), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Node@+ GetChild(const String&in, bool recursive = false) const", asMETHODPR(T, GetChild, (const String&, bool) const, Node*), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Array<Component@>@ GetComponents(const String&in) const", asFUNCTION(NodeGetComponentsWithType), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectMethod(className, "Component@+ GetComponent(const String&in, uint index = 0) const", asFUNCTION(NodeGetComponentWithTypeAndIndex), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod(className, "Component@+ GetComponent(const String&in) const", asFUNCTION(NodeGetComponentWithType), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "bool HasComponent(const String&in) const", asFUNCTION(NodeHasComponent), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "void set_position(const Vector3&in)", asMETHOD(T, SetPosition), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "const Vector3& get_position() const", asMETHOD(T, GetPosition), asCALL_THISCALL);

+ 6 - 5
Engine/Engine/MathAPI.cpp

@@ -24,6 +24,7 @@
 #include "Precompiled.h"
 #include "Color.h"
 #include "Frustum.h"
+#include "Ray.h"
 
 #include <angelscript.h>
 
@@ -404,7 +405,9 @@ static void RegisterRay(asIScriptEngine* engine)
     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", "void Define(const Vector3&in, const Vector3&in)", asMETHOD(Ray, Define), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Ray", "float Distance(const Vector3&in, const Vector3&in, const Vector3&in) const", asMETHODPR(Ray, Distance, (const Vector3&, const Vector3&, const Vector3&) const, float), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Ray", "float HitDistance(const Sphere&in) const", asMETHODPR(Ray, HitDistance, (const Sphere&) const, float), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Ray", "float HitDistance(const BoundingBox&in) const", asMETHODPR(Ray, HitDistance, (const BoundingBox&) const, float), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Ray", "float HitDistance(const Vector3&in, const Vector3&in, const Vector3&in) const", asMETHODPR(Ray, HitDistance, (const Vector3&, const Vector3&, const Vector3&) const, float), asCALL_THISCALL);
     engine->RegisterObjectProperty("Ray", "Vector3 origin", offsetof(Ray, origin_));
     engine->RegisterObjectProperty("Ray", "Vector3 direction", offsetof(Ray, direction_));
 }
@@ -538,7 +541,6 @@ static void RegisterVolumes(asIScriptEngine* engine)
     engine->RegisterObjectMethod("BoundingBox", "Intersection IsInside(const Vector3&in) const", asMETHODPR(BoundingBox, IsInside, (const Vector3&) const, Intersection), asCALL_THISCALL);
     engine->RegisterObjectMethod("BoundingBox", "Intersection IsInside(const Sphere&in) const", asMETHODPR(BoundingBox, IsInside, (const Sphere&) const, Intersection), asCALL_THISCALL);
     engine->RegisterObjectMethod("BoundingBox", "Intersection IsInside(const BoundingBox&in) const", asMETHODPR(BoundingBox, IsInside, (const BoundingBox&) const, Intersection), asCALL_THISCALL);
-    engine->RegisterObjectMethod("BoundingBox", "float Distance(const Ray&in) const", asMETHOD(BoundingBox, Distance), asCALL_THISCALL);
     engine->RegisterObjectMethod("BoundingBox", "Vector3 get_center() const", asMETHOD(BoundingBox, Center), asCALL_THISCALL);
     engine->RegisterObjectMethod("BoundingBox", "Vector3 get_size() const", asMETHOD(BoundingBox, Size), asCALL_THISCALL);
     engine->RegisterObjectMethod("BoundingBox", "Vector3 get_halfSize() const", asMETHOD(BoundingBox, HalfSize), asCALL_THISCALL);
@@ -561,7 +563,6 @@ static void RegisterVolumes(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Sphere", "Intersection IsInside(const Vector3&in) const", asMETHODPR(Sphere, IsInside, (const Vector3&) const, Intersection), asCALL_THISCALL);
     engine->RegisterObjectMethod("Sphere", "Intersection IsInside(const Sphere&in) const", asMETHODPR(Sphere, IsInside, (const Sphere&) const, Intersection), asCALL_THISCALL);
     engine->RegisterObjectMethod("Sphere", "Intersection IsInside(const BoundingBox&in) const", asMETHODPR(Sphere, IsInside, (const BoundingBox&) const, Intersection), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Sphere", "float Distance(const Ray&in) const", asMETHOD(Sphere, Distance), asCALL_THISCALL);
     engine->RegisterObjectProperty("Sphere", "Vector3 center", offsetof(Sphere, center_));
     engine->RegisterObjectProperty("Sphere", "float radius", offsetof(Sphere, radius_));
     engine->RegisterObjectProperty("Sphere", "bool defined", offsetof(Sphere, defined_));
@@ -628,10 +629,10 @@ void RegisterMathAPI(asIScriptEngine* engine)
     RegisterVector3(engine);
     RegisterVector4(engine);
     RegisterQuaternion(engine);
-    RegisterRay(engine);
     RegisterRect(engine);
     RegisterVolumes(engine);
+    RegisterRay(engine);
     RegisterColor(engine);
     
-    /// \todo Register Matrix types
+    /// \todo Register matrix types
 }

+ 2 - 2
Engine/Engine/PhysicsAPI.cpp

@@ -89,8 +89,8 @@ static void RegisterCollisionShape(asIScriptEngine* engine)
     engine->RegisterObjectMethod("CollisionShape", "const Vector3& get_position() const", asMETHOD(CollisionShape, GetPosition), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "void set_rotation(const Quaternion&in)", asMETHOD(CollisionShape, SetRotation), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "const Quaternion& get_rotation() const", asMETHOD(CollisionShape, GetRotation), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CollisionShape", "void set_collisionGroup(uint)", asMETHOD(CollisionShape, SetCollisionGroup), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CollisionShape", "uint get_collisionGroup() const", asMETHOD(CollisionShape, GetCollisionGroup), asCALL_THISCALL);
+    engine->RegisterObjectMethod("CollisionShape", "void set_collisionLayer(uint)", asMETHOD(CollisionShape, SetCollisionLayer), asCALL_THISCALL);
+    engine->RegisterObjectMethod("CollisionShape", "uint get_collisionLayer() const", asMETHOD(CollisionShape, GetCollisionLayer), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "void set_collisionMask(uint)", asMETHOD(CollisionShape, SetCollisionMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "uint get_collisionMask() const", asMETHOD(CollisionShape, GetCollisionMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "void set_friction(float)", asMETHOD(CollisionShape, SetFriction), asCALL_THISCALL);

+ 2 - 2
Engine/Engine/SceneAPI.cpp

@@ -119,8 +119,8 @@ static void RegisterScene(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Scene", "void RegisterVar(const String&in)", asMETHOD(Scene, RegisterVar), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void UnregisterVar(const String&in)", asMETHOD(Scene, UnregisterVar), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void UnregisterAllVars(const String&in)", asMETHOD(Scene, UnregisterAllVars), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Scene", "Component@+ GetComponentByID(uint)", asMETHOD(Scene, GetComponentByID), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Scene", "Node@+ GetNodeByID(uint)", asMETHOD(Scene, GetNodeByID), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Scene", "Component@+ GetComponent(uint)", asMETHODPR(Scene, GetComponent, (unsigned) const, Component*), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Scene", "Node@+ GetNode(uint)", asMETHOD(Scene, GetNode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "const String& GetVarName(ShortStringHash) const", asMETHOD(Scene, GetVarName), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void Update(float)", asMETHOD(Scene, Update), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void set_active(bool)", asMETHOD(Scene, SetActive), asCALL_THISCALL);

+ 4 - 4
Engine/Graphics/AnimatedModel.cpp

@@ -130,7 +130,7 @@ void AnimatedModel::ProcessRayQuery(RayOctreeQuery& query, float initialDistance
             // Do an initial crude test using the bone's AABB
             const BoundingBox& box = bone.boundingBox_;
             const Matrix3x4& transform = bone.node_->GetWorldTransform();
-            float distance = box.Transformed(transform).Distance(query.ray_);
+            float distance = query.ray_.HitDistance(box.Transformed(transform));
             if (distance < query.maxDistance_)
             {
                 if (level == RAY_AABB)
@@ -147,7 +147,7 @@ void AnimatedModel::ProcessRayQuery(RayOctreeQuery& query, float initialDistance
                     // Follow with an OBB test if required
                     Matrix3x4 inverse = transform.Inverse();
                     Ray localRay(inverse * query.ray_.origin_, inverse * Vector4(query.ray_.direction_, 0.0f));
-                    distance = box.Distance(localRay);
+                    distance = localRay.HitDistance(box);
                     if (distance < query.maxDistance_)
                     {
                         RayQueryResult result;
@@ -164,7 +164,7 @@ void AnimatedModel::ProcessRayQuery(RayOctreeQuery& query, float initialDistance
         {
             boneSphere.center_ = bone.node_->GetWorldPosition();
             boneSphere.radius_ = bone.radius_;
-            float distance = boneSphere.Distance(query.ray_);
+            float distance = query.ray_.HitDistance(boneSphere);
             if (distance < query.maxDistance_)
             {
                 RayQueryResult result;
@@ -709,7 +709,7 @@ void AnimatedModel::OnNodeSet(Node* node)
     Drawable::OnNodeSet(node);
     
     // If this AnimatedModel is the first in the node, it is the master which controls animation & morphs
-    isMaster_ = GetComponent<AnimatedModel>(0) == this;
+    isMaster_ = GetComponent<AnimatedModel>() == this;
 }
 
 void AnimatedModel::OnMarkedDirty(Node* node)

+ 1 - 1
Engine/Graphics/Geometry.cpp

@@ -224,7 +224,7 @@ float Geometry::GetDistance(const Ray& ray)
     if (!rawIndexData_ || !rawVertexData_ || !indexBuffer_)
         return M_INFINITY;
     
-    return ray.Distance(rawVertexData_.Get(), 3 * sizeof(float), rawIndexData_.Get(), indexBuffer_->GetIndexSize(), indexStart_, indexCount_);
+    return ray.HitDistance(rawVertexData_.Get(), 3 * sizeof(float), rawIndexData_.Get(), indexBuffer_->GetIndexSize(), indexStart_, indexCount_);
 }
 
 void Geometry::GetPositionBufferIndex()

+ 2 - 2
Engine/Graphics/Octree.cpp

@@ -205,7 +205,7 @@ void Octant::GetDrawablesInternal(RayOctreeQuery& query) const
     if (!numDrawables_)
         return;
     
-    float octantDist = cullingBox_.Distance(query.ray_);
+    float octantDist = query.ray_.HitDistance(cullingBox_);
     if (octantDist >= query.maxDistance_)
         return;
     
@@ -219,7 +219,7 @@ void Octant::GetDrawablesInternal(RayOctreeQuery& query) const
             !drawable->GetCastShadows()))
             continue;
         
-        float drawableDist = drawable->GetWorldBoundingBox().Distance(query.ray_);
+        float drawableDist = query.ray_.HitDistance(drawable->GetWorldBoundingBox());
         // The drawable will possibly do more accurate collision testing, then store the result(s)
         if (drawableDist < query.maxDistance_)
             drawable->ProcessRayQuery(query, drawableDist);

+ 2 - 2
Engine/Graphics/StaticModel.cpp

@@ -91,7 +91,7 @@ void StaticModel::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)
         {
             Matrix3x4 inverse(GetWorldTransform().Inverse());
             Ray localRay(inverse * query.ray_.origin_, inverse * Vector4(query.ray_.direction_, 0.0f));
-            float distance = boundingBox_.Distance(localRay);
+            float distance = localRay.HitDistance(boundingBox_);
             if (distance < query.maxDistance_)
             {
                 RayQueryResult result;
@@ -108,7 +108,7 @@ void StaticModel::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)
             // Do a pretest using the OBB
             Matrix3x4 inverse(GetWorldTransform().Inverse());
             Ray localRay(inverse * query.ray_.origin_, inverse * Vector4(query.ray_.direction_, 0.0f));
-            float distance = boundingBox_.Distance(localRay);
+            float distance = localRay.HitDistance(boundingBox_);
             if (distance < query.maxDistance_)
             {
                 // Then the actual test using triangle geometry

+ 0 - 79
Engine/Math/BoundingBox.cpp

@@ -280,82 +280,3 @@ Intersection BoundingBox::IsInsideFast(const Sphere& sphere) const
     else
         return INSIDE;
 }
-
-float BoundingBox::Distance(const Ray& ray) const
-{
-    // If undefined, no hit (infinite distance)
-    if (!defined_)
-        return M_INFINITY;
-    
-    // Check for ray origin being inside the box
-    if (IsInside(ray.origin_))
-        return 0.0f;
-    
-    float dist = M_INFINITY;
-    
-    // Check for intersecting in the X-direction
-    if (ray.origin_.x_ < min_.x_ && ray.direction_.x_ > 0.0f)
-    {
-        float x = (min_.x_ - ray.origin_.x_) / ray.direction_.x_;
-        if (x < dist)
-        {
-            Vector3 point = ray.origin_ + x * ray.direction_;
-            if (point.y_ >= min_.y_ && point.y_ <= max_.y_ && point.z_ >= min_.z_ && point.z_ <= max_.z_)
-                dist = x;
-        }
-    }
-    if (ray.origin_.x_ > max_.x_ && ray.direction_.x_ < 0.0f)
-    {
-        float x = (max_.x_ - ray.origin_.x_) / ray.direction_.x_;
-        if (x < dist)
-        {
-            Vector3 point = ray.origin_ + x * ray.direction_;
-            if (point.y_ >= min_.y_ && point.y_ <= max_.y_ && point.z_ >= min_.z_ && point.z_ <= max_.z_)
-                dist = x;
-        }
-    }
-    // Check for intersecting in the Y-direction
-    if (ray.origin_.y_ < min_.y_ && ray.direction_.y_ > 0.0f)
-    {
-        float x = (min_.y_ - ray.origin_.y_) / ray.direction_.y_;
-        if (x < dist)
-        {
-            Vector3 point = ray.origin_ + x * ray.direction_;
-            if (point.x_ >= min_.x_ && point.x_ <= max_.x_ && point.z_ >= min_.z_ && point.z_ <= max_.z_)
-                dist = x;
-        }
-    }
-    if (ray.origin_.y_ > max_.y_ && ray.direction_.y_ < 0.0f)
-    {
-        float x = (max_.y_ - ray.origin_.y_) / ray.direction_.y_;
-        if (x < dist)
-        {
-            Vector3 point = ray.origin_ + x * ray.direction_;
-            if (point.x_ >= min_.x_ && point.x_ <= max_.x_ && point.z_ >= min_.z_ && point.z_ <= max_.z_)
-                dist = x;
-        }
-    }
-    // Check for intersecting in the Z-direction
-    if (ray.origin_.z_ < min_.z_ && ray.direction_.z_ > 0.0f)
-    {
-        float x = (min_.z_ - ray.origin_.z_) / ray.direction_.z_;
-        if (x < dist)
-        {
-            Vector3 point = ray.origin_ + x * ray.direction_;
-            if (point.x_ >= min_.x_ && point.x_ <= max_.x_ && point.y_ >= min_.y_ && point.y_ <= max_.y_)
-                dist = x;
-        }
-    }
-    if (ray.origin_.z_ > max_.z_ && ray.direction_.z_ < 0.0f)
-    {
-        float x = (max_.z_ - ray.origin_.z_) / ray.direction_.z_;
-        if (x < dist)
-        {
-            Vector3 point = ray.origin_ + x * ray.direction_;
-            if (point.x_ >= min_.x_ && point.x_ <= max_.x_ && point.y_ >= min_.y_ && point.y_ <= max_.y_)
-                dist = x;
-        }
-    }
-    
-    return dist;
-}

+ 0 - 3
Engine/Math/BoundingBox.h

@@ -30,7 +30,6 @@ class Frustum;
 class Matrix3;
 class Matrix4;
 class Matrix3x4;
-class Ray;
 class Sphere;
 
 /// Three-dimensional axis-aligned bounding box.
@@ -243,8 +242,6 @@ public:
     Intersection IsInside(const Sphere& sphere) const;
     /// Test if a sphere is (partially) inside or outside.
     Intersection IsInsideFast(const Sphere& sphere) const;
-    /// Return ray hit distance, or infinity if no hit.
-    float Distance(const Ray& ray) const;
     
     /// Minimum vector.
     Vector3 min_;

+ 0 - 13
Engine/Math/Plane.h

@@ -23,11 +23,8 @@
 
 #pragma once
 
-#include "Ray.h"
 #include "Vector3.h"
 
-class Ray;
-
 /// Surface in three-dimensional space.
 class Plane
 {
@@ -87,16 +84,6 @@ public:
         return absNormal_.DotProduct(absPoint);
     }
     
-    /// Return ray hit distance, or infinity if no hit.
-    float Distance(const Ray& ray) const
-    {
-        float d = normal_.DotProduct(ray.direction_);
-        if (fabsf(d) >= M_EPSILON)
-            return (-normal_.DotProduct(ray.origin_) + intercept_) / d;
-        else
-            return M_INFINITY;
-    }
-    
     /// Plane normal.
     Vector3 normal_;
     /// Plane absolute normal.

+ 123 - 4
Engine/Math/Ray.cpp

@@ -22,7 +22,10 @@
 //
 
 #include "Precompiled.h"
+#include "BoundingBox.h"
+#include "Plane.h"
 #include "Ray.h"
+#include "Sphere.h"
 
 Vector3 Ray::Project(const Vector3& point) const
 {
@@ -30,7 +33,123 @@ Vector3 Ray::Project(const Vector3& point) const
     return origin_ + offset.DotProduct(direction_) * direction_;
 }
 
-float Ray::Distance(const Vector3& v0, const Vector3& v1, const Vector3& v2) const
+float Ray::HitDistance(const Plane& plane) const
+{
+    float d = plane.normal_.DotProduct(direction_);
+    if (fabsf(d) >= M_EPSILON)
+        return (-plane.normal_.DotProduct(origin_) + plane.intercept_) / d;
+    else
+        return M_INFINITY;
+}
+
+float Ray::HitDistance(const Sphere& sphere) const
+{
+    Vector3 centeredOrigin = origin_ - sphere.center_;
+    float squaredRadius = sphere.radius_ * sphere.radius_;
+    
+    // Check if ray originates inside the sphere
+    if (centeredOrigin.LengthSquared() <= squaredRadius)
+        return 0.0f;
+    
+    // Calculate intersection by quadratic equation
+    float a = direction_.DotProduct(direction_);
+    float b = 2.0f * centeredOrigin.DotProduct(direction_);
+    float c = centeredOrigin.DotProduct(centeredOrigin) - squaredRadius;
+    float d = b * b - 4.0f * a * c;
+    
+    // No solution
+    if (d < 0.0f)
+        return M_INFINITY;
+    
+    // Get the nearer solution
+    float dSqrt = sqrtf(d);
+    float dist = (-b - dSqrt) / (2.0f * a);
+    if (dist >= 0.0f)
+        return dist;
+    else
+        return (-b + dSqrt) / (2.0f * a);
+}
+
+float Ray::HitDistance(const BoundingBox& box) const
+{
+    // If undefined, no hit (infinite distance)
+    if (!box.defined_)
+        return M_INFINITY;
+    
+    // Check for ray origin being inside the box
+    if (box.IsInside(origin_))
+        return 0.0f;
+    
+    float dist = M_INFINITY;
+    
+    // Check for intersecting in the X-direction
+    if (origin_.x_ < box.min_.x_ && direction_.x_ > 0.0f)
+    {
+        float x = (box.min_.x_ - origin_.x_) / direction_.x_;
+        if (x < dist)
+        {
+            Vector3 point = origin_ + x * direction_;
+            if (point.y_ >= box.min_.y_ && point.y_ <= box.max_.y_ && point.z_ >= box.min_.z_ && point.z_ <= box.max_.z_)
+                dist = x;
+        }
+    }
+    if (origin_.x_ > box.max_.x_ && direction_.x_ < 0.0f)
+    {
+        float x = (box.max_.x_ - origin_.x_) / direction_.x_;
+        if (x < dist)
+        {
+            Vector3 point = origin_ + x * direction_;
+            if (point.y_ >= box.min_.y_ && point.y_ <= box.max_.y_ && point.z_ >= box.min_.z_ && point.z_ <= box.max_.z_)
+                dist = x;
+        }
+    }
+    // Check for intersecting in the Y-direction
+    if (origin_.y_ < box.min_.y_ && direction_.y_ > 0.0f)
+    {
+        float x = (box.min_.y_ - origin_.y_) / direction_.y_;
+        if (x < dist)
+        {
+            Vector3 point = origin_ + x * direction_;
+            if (point.x_ >= box.min_.x_ && point.x_ <= box.max_.x_ && point.z_ >= box.min_.z_ && point.z_ <= box.max_.z_)
+                dist = x;
+        }
+    }
+    if (origin_.y_ > box.max_.y_ && direction_.y_ < 0.0f)
+    {
+        float x = (box.max_.y_ - origin_.y_) / direction_.y_;
+        if (x < dist)
+        {
+            Vector3 point = origin_ + x * direction_;
+            if (point.x_ >= box.min_.x_ && point.x_ <= box.max_.x_ && point.z_ >= box.min_.z_ && point.z_ <= box.max_.z_)
+                dist = x;
+        }
+    }
+    // Check for intersecting in the Z-direction
+    if (origin_.z_ < box.min_.z_ && direction_.z_ > 0.0f)
+    {
+        float x = (box.min_.z_ - origin_.z_) / direction_.z_;
+        if (x < dist)
+        {
+            Vector3 point = origin_ + x * direction_;
+            if (point.x_ >= box.min_.x_ && point.x_ <= box.max_.x_ && point.y_ >= box.min_.y_ && point.y_ <= box.max_.y_)
+                dist = x;
+        }
+    }
+    if (origin_.z_ > box.max_.z_ && direction_.z_ < 0.0f)
+    {
+        float x = (box.max_.z_ - origin_.z_) / direction_.z_;
+        if (x < dist)
+        {
+            Vector3 point = origin_ + x * direction_;
+            if (point.x_ >= box.min_.x_ && point.x_ <= box.max_.x_ && point.y_ >= box.min_.y_ && point.y_ <= box.max_.y_)
+                dist = x;
+        }
+    }
+    
+    return dist;
+}
+
+float Ray::HitDistance(const Vector3& v0, const Vector3& v1, const Vector3& v2) const
 {
     // Based on Fast, Minimum Storage Ray/Triangle Intersection by Möller & Trumbore
     // http://www.graphics.cornell.edu/pubs/1997/MT97.pdf
@@ -61,7 +180,7 @@ float Ray::Distance(const Vector3& v0, const Vector3& v1, const Vector3& v2) con
     return M_INFINITY;
 }
 
-float Ray::Distance(const void* vertexData, unsigned vertexSize, const void* indexData, unsigned indexSize, unsigned indexStart, unsigned indexCount) const
+float Ray::HitDistance(const void* vertexData, unsigned vertexSize, const void* indexData, unsigned indexSize, unsigned indexStart, unsigned indexCount) const
 {
     float nearest = M_INFINITY;
     const unsigned char* vertices = (const unsigned char*)vertexData;
@@ -76,7 +195,7 @@ float Ray::Distance(const void* vertexData, unsigned vertexSize, const void* ind
             const Vector3& v0 = *((const Vector3*)(&vertices[indices[i] * vertexSize]));
             const Vector3& v1 = *((const Vector3*)(&vertices[indices[i + 1] * vertexSize]));
             const Vector3& v2 = *((const Vector3*)(&vertices[indices[i + 2] * vertexSize]));
-            nearest = Min(nearest, Distance(v0, v1, v2));
+            nearest = Min(nearest, HitDistance(v0, v1, v2));
         }
     }
     // 32-bit indices
@@ -89,7 +208,7 @@ float Ray::Distance(const void* vertexData, unsigned vertexSize, const void* ind
             const Vector3& v0 = *((const Vector3*)(&vertices[indices[i] * vertexSize]));
             const Vector3& v1 = *((const Vector3*)(&vertices[indices[i + 1] * vertexSize]));
             const Vector3& v2 = *((const Vector3*)(&vertices[indices[i + 2] * vertexSize]));
-            nearest = Min(nearest, Distance(v0, v1, v2));
+            nearest = Min(nearest, HitDistance(v0, v1, v2));
         }
     }
     

+ 14 - 4
Engine/Math/Ray.h

@@ -25,6 +25,10 @@
 
 #include "Vector3.h"
 
+class BoundingBox;
+class Plane;
+class Sphere;
+
 /// Infinite straight line in three-dimensional space.
 class Ray
 {
@@ -70,10 +74,16 @@ public:
     
     /// Project a point on the ray.
     Vector3 Project(const Vector3& point) const;
-    /// Return minimum distance to a triangle, or infinity if no hit.
-    float Distance(const Vector3& v0, const Vector3& v1, const Vector3& v2) const;
-    /// Return minimum distance to a triangle mesh defined by vertex and index data.
-    float Distance(const void* vertexData, unsigned vertexSize, const void* indexData, unsigned indexSize, unsigned indexStart, unsigned indexCount) const;
+    /// Return hit distance to a plane, or infinity if no hit.
+    float HitDistance(const Plane& plane) const;
+    /// Return hit distance to a sphere, or infinity if no hit.
+    float HitDistance(const Sphere& sphere) const;
+    /// Return hit distance to a bounding box, or infinity if no hit.
+    float HitDistance(const BoundingBox& box) const;
+    /// Return hit distance to a triangle, or infinity if no hit.
+    float HitDistance(const Vector3& v0, const Vector3& v1, const Vector3& v2) const;
+    /// Return hit distance to a triangle mesh defined by vertex and index data, or infinity if no hit.
+    float HitDistance(const void* vertexData, unsigned vertexSize, const void* indexData, unsigned indexSize, unsigned indexStart, unsigned indexCount) const;
     
     /// Ray origin.
     Vector3 origin_;

+ 0 - 28
Engine/Math/Sphere.cpp

@@ -235,31 +235,3 @@ Intersection Sphere::IsInsideFast(const BoundingBox& box) const
     else
         return INSIDE;
 }
-
-float Sphere::Distance(const Ray& ray) const
-{
-    Vector3 centeredOrigin = ray.origin_ - center_;
-    float squaredRadius = radius_ * radius_;
-    
-    // Check if ray originates inside the sphere
-    if (centeredOrigin.LengthSquared() <= squaredRadius)
-        return 0.0f;
-    
-    // Calculate intersection by quadratic equation
-    float a = ray.direction_.DotProduct(ray.direction_);
-    float b = 2.0f * centeredOrigin.DotProduct(ray.direction_);
-    float c = centeredOrigin.DotProduct(centeredOrigin) - squaredRadius;
-    float d = b * b - 4.0f * a * c;
-    
-    // No solution
-    if (d < 0.0f)
-        return M_INFINITY;
-    
-    // Get the nearer solution
-    float dSqrt = sqrtf(d);
-    float dist = (-b - dSqrt) / (2.0f * a);
-    if (dist >= 0.0f)
-        return dist;
-    else
-        return (-b + dSqrt) / (2.0f * a);
-}

+ 0 - 3
Engine/Math/Sphere.h

@@ -27,7 +27,6 @@
 
 class BoundingBox;
 class Frustum;
-class Ray;
 
 /// %Sphere in three-dimensional space.
 class Sphere
@@ -153,8 +152,6 @@ public:
     Intersection IsInside(const BoundingBox& box) const;
     /// Test if a bounding box is (partially) inside or outside.
     Intersection IsInsideFast(const BoundingBox& box) const;
-    /// Return distance to a ray, or infinity if no intersection.
-    float Distance(const Ray& ray) const;
     
     /// Sphere center.
     Vector3 center_;

+ 13 - 13
Engine/Network/Connection.cpp

@@ -344,7 +344,7 @@ void Connection::ProcessPendingLatestData()
     for (HashMap<unsigned, PODVector<unsigned char> >::Iterator i = nodeLatestData_.Begin(); i != nodeLatestData_.End();)
     {
         HashMap<unsigned, PODVector<unsigned char> >::Iterator current = i++;
-        Node* node = scene_->GetNodeByID(current->first_);
+        Node* node = scene_->GetNode(current->first_);
         if (node)
         {
             MemoryBuffer msg(current->second_);
@@ -358,7 +358,7 @@ void Connection::ProcessPendingLatestData()
     for (HashMap<unsigned, PODVector<unsigned char> >::Iterator i = componentLatestData_.Begin(); i != componentLatestData_.End();)
     {
         HashMap<unsigned, PODVector<unsigned char> >::Iterator current = i++;
-        Component* component = scene_->GetComponentByID(current->first_);
+        Component* component = scene_->GetComponent(current->first_);
         if (component)
         {
             MemoryBuffer msg(current->second_);
@@ -497,7 +497,7 @@ void Connection::ProcessSceneUpdate(int msgID, MemoryBuffer& msg)
         {
             unsigned nodeID = msg.ReadNetID();
             // In case of the root node (scene), it should already exist. Do not create in that case
-            Node* node = scene_->GetNodeByID(nodeID);
+            Node* node = scene_->GetNode(nodeID);
             if (!node)
             {
                 // Add initially to the root level. May be moved as we receive the parent attribute
@@ -532,7 +532,7 @@ void Connection::ProcessSceneUpdate(int msgID, MemoryBuffer& msg)
                 unsigned componentID = msg.ReadNetID();
                 
                 // Check if the component by this ID and type already exists in this node
-                Component* component = scene_->GetComponentByID(componentID);
+                Component* component = scene_->GetComponent(componentID);
                 if (!component || component->GetType() != type || component->GetNode() != node)
                 {
                     if (component)
@@ -557,7 +557,7 @@ void Connection::ProcessSceneUpdate(int msgID, MemoryBuffer& msg)
     case MSG_NODEDELTAUPDATE:
         {
             unsigned nodeID = msg.ReadNetID();
-            Node* node = scene_->GetNodeByID(nodeID);
+            Node* node = scene_->GetNode(nodeID);
             if (node)
             {
                 node->ReadDeltaUpdate(msg, deltaUpdateBits_);
@@ -580,7 +580,7 @@ void Connection::ProcessSceneUpdate(int msgID, MemoryBuffer& msg)
     case MSG_NODELATESTDATA:
         {
             unsigned nodeID = msg.ReadNetID();
-            Node* node = scene_->GetNodeByID(nodeID);
+            Node* node = scene_->GetNode(nodeID);
             if (node)
                 node->ReadLatestDataUpdate(msg);
             else
@@ -596,7 +596,7 @@ void Connection::ProcessSceneUpdate(int msgID, MemoryBuffer& msg)
     case MSG_REMOVENODE:
         {
             unsigned nodeID = msg.ReadNetID();
-            Node* node = scene_->GetNodeByID(nodeID);
+            Node* node = scene_->GetNode(nodeID);
             if (node)
                 node->Remove();
             nodeLatestData_.Erase(nodeID);
@@ -606,14 +606,14 @@ void Connection::ProcessSceneUpdate(int msgID, MemoryBuffer& msg)
     case MSG_CREATECOMPONENT:
         {
             unsigned nodeID = msg.ReadNetID();
-            Node* node = scene_->GetNodeByID(nodeID);
+            Node* node = scene_->GetNode(nodeID);
             if (node)
             {
                 ShortStringHash type = msg.ReadShortStringHash();
                 unsigned componentID = msg.ReadNetID();
                 
                 // Check if the component by this ID and type already exists in this node
-                Component* component = scene_->GetComponentByID(componentID);
+                Component* component = scene_->GetComponent(componentID);
                 if (!component || component->GetType() != type || component->GetNode() != node)
                 {
                     if (component)
@@ -640,7 +640,7 @@ void Connection::ProcessSceneUpdate(int msgID, MemoryBuffer& msg)
     case MSG_COMPONENTDELTAUPDATE:
         {
             unsigned componentID = msg.ReadNetID();
-            Component* component = scene_->GetComponentByID(componentID);
+            Component* component = scene_->GetComponent(componentID);
             if (component)
             {
                 component->ReadDeltaUpdate(msg, deltaUpdateBits_);
@@ -654,7 +654,7 @@ void Connection::ProcessSceneUpdate(int msgID, MemoryBuffer& msg)
     case MSG_COMPONENTLATESTDATA:
         {
             unsigned componentID = msg.ReadNetID();
-            Component* component = scene_->GetComponentByID(componentID);
+            Component* component = scene_->GetComponent(componentID);
             if (component)
             {
                 component->ReadLatestDataUpdate(msg);
@@ -673,7 +673,7 @@ void Connection::ProcessSceneUpdate(int msgID, MemoryBuffer& msg)
     case MSG_REMOVECOMPONENT:
         {
             unsigned componentID = msg.ReadNetID();
-            Component* component = scene_->GetComponentByID(componentID);
+            Component* component = scene_->GetComponent(componentID);
             if (component)
                 component->Remove();
             componentLatestData_.Erase(componentID);
@@ -925,7 +925,7 @@ void Connection::ProcessRemoteEvent(int msgID, MemoryBuffer& msg)
         }
         
         VariantMap eventData = msg.ReadVariantMap();
-        Node* receiver = scene_->GetNodeByID(nodeID);
+        Node* receiver = scene_->GetNode(nodeID);
         if (!receiver)
         {
             LOGWARNING("Missing receiver for remote node event, discarding");

+ 5 - 5
Engine/Physics/CollisionShape.cpp

@@ -307,7 +307,7 @@ CollisionShape::CollisionShape(Context* context) :
     position_(Vector3::ZERO),
     rotation_(Quaternion::IDENTITY),
     geometryScale_(Vector3::UNITY),
-    collisionGroup_(M_MAX_UNSIGNED),
+    collisionLayer_(M_MAX_UNSIGNED),
     collisionMask_(M_MAX_UNSIGNED),
     friction_(DEFAULT_FRICTION),
     bounce_(DEFAULT_BOUNCE),
@@ -334,7 +334,7 @@ void CollisionShape::RegisterObject(Context* context)
     ATTRIBUTE(CollisionShape, VAR_FLOAT, "Hull Thickness", thickness_, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(CollisionShape, VAR_FLOAT, "Friction", GetFriction, SetFriction, float, DEFAULT_FRICTION, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(CollisionShape, VAR_FLOAT, "Bounce", GetBounce, SetBounce, float, DEFAULT_BOUNCE, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(CollisionShape, VAR_INT, "Collision Group", GetCollisionGroup, SetCollisionGroup, unsigned, M_MAX_UNSIGNED, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(CollisionShape, VAR_INT, "Collision Group", GetCollisionLayer, SetCollisionLayer, unsigned, M_MAX_UNSIGNED, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(CollisionShape, VAR_INT, "Collision Mask", GetCollisionMask, SetCollisionMask, unsigned, M_MAX_UNSIGNED, AM_DEFAULT);
     ATTRIBUTE(CollisionShape, VAR_BOOL, "Is Phantom", phantom_, false, AM_DEFAULT);
 }
@@ -511,9 +511,9 @@ void CollisionShape::SetTransform(const Vector3& position, const Quaternion& rot
     UpdateTransform();
 }
 
-void CollisionShape::SetCollisionGroup(unsigned group)
+void CollisionShape::SetCollisionLayer(unsigned group)
 {
-    collisionGroup_ = group;
+    collisionLayer_ = group;
     if (geometry_)
         dGeomSetCategoryBits(geometry_, group);
 }
@@ -923,7 +923,7 @@ void CollisionShape::CreateGeometry()
     // Set collision group and mask & userdata
     if (geometry_)
     {
-        dGeomSetCategoryBits(geometry_, collisionGroup_);
+        dGeomSetCategoryBits(geometry_, collisionLayer_);
         dGeomSetCollideBits(geometry_, collisionMask_);
         dGeomSetData(geometry_, this);
     }

+ 3 - 3
Engine/Physics/CollisionShape.h

@@ -127,7 +127,7 @@ public:
     /// %Set offset transform.
     void SetTransform(const Vector3& position, const Quaternion& rotation);
     /// %Set collision group bits.
-    void SetCollisionGroup(unsigned group);
+    void SetCollisionLayer(unsigned group);
     /// %Set collision mask bits.
     void SetCollisionMask(unsigned mask);
     /// %Set friction coefficient.
@@ -158,7 +158,7 @@ public:
     /// Return rotation.
     const Quaternion& GetRotation() const { return rotation_; }
     /// Return collision group bits.
-    unsigned GetCollisionGroup() const { return collisionGroup_; }
+    unsigned GetCollisionLayer() const { return collisionLayer_; }
     /// Return collision mask bits.
     unsigned GetCollisionMask() const { return collisionMask_; }
     /// Return friction coefficient.
@@ -215,7 +215,7 @@ private:
     /// Scene node scale used to create the geometry.
     Vector3 geometryScale_;
     /// Collision group bits.
-    unsigned collisionGroup_;
+    unsigned collisionLayer_;
     /// Collision mask bits.
     unsigned collisionMask_;
     /// Friction coefficient.

+ 2 - 2
Engine/Physics/Joint.cpp

@@ -260,14 +260,14 @@ Vector3 Joint::GetAxis() const
 void Joint::SetBodyAAttr(int value)
 {
     Scene* scene = node_ ? node_->GetScene() : 0;
-    bodyA_ = scene ? dynamic_cast<RigidBody*>(scene->GetComponentByID(value)) : (RigidBody*)0;
+    bodyA_ = scene ? dynamic_cast<RigidBody*>(scene->GetComponent(value)) : (RigidBody*)0;
     recreateJoint_ = true;
 }
 
 void Joint::SetBodyBAttr(int value)
 {
     Scene* scene = node_ ? node_->GetScene() : 0;
-    bodyB_ = scene ? dynamic_cast<RigidBody*>(scene->GetComponentByID(value)) : (RigidBody*)0;
+    bodyB_ = scene ? dynamic_cast<RigidBody*>(scene->GetComponent(value)) : (RigidBody*)0;
     recreateJoint_ = true;
 }
 

+ 1 - 0
Engine/Physics/PhysicsWorld.cpp

@@ -32,6 +32,7 @@
 #include "PhysicsWorld.h"
 #include "ProcessUtils.h"
 #include "Profiler.h"
+#include "Ray.h"
 #include "RigidBody.h"
 #include "Scene.h"
 #include "SceneEvents.h"

+ 2 - 2
Engine/Scene/Component.cpp

@@ -61,9 +61,9 @@ bool Component::HasComponent(ShortStringHash type) const
     return node_ ? node_->HasComponent(type) : false;
 }
 
-Component* Component::GetComponent(ShortStringHash type, unsigned index) const
+Component* Component::GetComponent(ShortStringHash type) const
 {
-    return node_ ? node_->GetComponent(type, index) : 0;
+    return node_ ? node_->GetComponent(type) : 0;
 }
 
 void Component::GetComponents(PODVector<Component*>& dest, ShortStringHash type) const

+ 4 - 4
Engine/Scene/Component.h

@@ -67,12 +67,12 @@ public:
     
     /// Return components in the same scene node by type.
     void GetComponents(PODVector<Component*>& dest, ShortStringHash type) const;
-    /// Return component in the same scene node by type. The optional index allows to specify which component, if there are several.
-    Component* GetComponent(ShortStringHash type, unsigned index = 0) const;
+    /// Return component in the same scene node by type. If there are several, returns the first.
+    Component* GetComponent(ShortStringHash type) const;
     /// Return whether the same scene node has a specific component.
     bool HasComponent(ShortStringHash type) const;
     /// Template version of returning a component in the same scene node by type.
-    template <class T> T* GetComponent(unsigned index = 0) const;
+    template <class T> T* GetComponent() const;
     /// Template version of returning components in the same scene node by type.
     template <class T> void GetComponents(PODVector<T*>& dest) const;
     
@@ -88,5 +88,5 @@ protected:
     Node* node_;
 };
 
-template <class T> T* Component::GetComponent(unsigned index) const { return static_cast<T*>(GetComponent(T::GetTypeStatic(), index)); }
+template <class T> T* Component::GetComponent() const { return static_cast<T*>(GetComponent(T::GetTypeStatic())); }
 template <class T> void Component::GetComponents(PODVector<T*>& dest) const { GetComponents(reinterpret_cast<PODVector<Component*>&>(dest), T::GetTypeStatic()); }

+ 3 - 14
Engine/Scene/Node.cpp

@@ -699,24 +699,13 @@ bool Node::HasComponent(ShortStringHash type) const
     return false;
 }
 
-Component* Node::GetComponent(unsigned index) const
+Component* Node::GetComponent(ShortStringHash type) const
 {
-    return index < components_.Size() ? components_[index].Get() : 0;
-}
-
-Component* Node::GetComponent(ShortStringHash type, unsigned index) const
-{
-    unsigned cmpIndex = 0;
     for (Vector<SharedPtr<Component> >::ConstIterator i = components_.Begin(); i != components_.End(); ++i)
     {
         if ((*i)->GetType() == type)
-        {
-            if (cmpIndex == index)
-                return *i;
-            ++cmpIndex;
-        }
+            return *i;
     }
-    
     return 0;
 }
 
@@ -767,7 +756,7 @@ void Node::SetNetParentAttr(const PODVector<unsigned char>& value)
     }
     
     unsigned baseNodeID = buf.ReadNetID();
-    Node* baseNode = scene->GetNodeByID(baseNodeID);
+    Node* baseNode = scene->GetNode(baseNodeID);
     if (!baseNode)
     {
         LOGWARNING("Failed to find parent node " + String(baseNodeID));

+ 4 - 6
Engine/Scene/Node.h

@@ -253,10 +253,8 @@ public:
     const Vector<SharedPtr<Component> >& GetComponents() const { return components_; }
     /// Return all components of type.
     void GetComponents(PODVector<Component*>& dest, ShortStringHash type) const;
-    /// Return component by index.
-    Component* GetComponent(unsigned index) const;
-    /// Return component by type. The optional index allows to specify which component, if there are several.
-    Component* GetComponent(ShortStringHash type, unsigned index = 0) const;
+    /// Return component by type. If there are several, returns the first.
+    Component* GetComponent(ShortStringHash type) const;
     /// Return whether has a specific component.
     bool HasComponent(ShortStringHash type) const;
     /// Return listener components.
@@ -268,7 +266,7 @@ public:
     /// Template version of returning child nodes with a specific component.
     template <class T> void GetChildrenWithComponent(PODVector<Node*>& dest, bool recursive = false) const;
     /// Template version of returning a component by type.
-    template <class T> T* GetComponent(unsigned index = 0) const;
+    template <class T> T* GetComponent() const;
     /// Template version of returning all components of type.
     template <class T> void GetComponents(PODVector<T*>& dest) const;
     /// Template version of checking whether has a specific component.
@@ -357,6 +355,6 @@ private:
 template <class T> T* Node::CreateComponent(CreateMode mode) { return static_cast<T*>(CreateComponent(T::GetTypeStatic(), mode)); }
 template <class T> T* Node::GetOrCreateComponent(CreateMode mode) { return static_cast<T*>(GetOrCreateComponent(T::GetTypeStatic(), mode)); }
 template <class T> void Node::GetChildrenWithComponent(PODVector<Node*>& dest, bool recursive) const { GetChildrenWithComponent(dest, T::GetTypeStatic(), recursive); }
-template <class T> T* Node::GetComponent(unsigned index) const { return static_cast<T*>(GetComponent(T::GetTypeStatic(), index)); }
+template <class T> T* Node::GetComponent() const { return static_cast<T*>(GetComponent(T::GetTypeStatic())); }
 template <class T> void Node::GetComponents(PODVector<T*>& dest) const { GetComponents(reinterpret_cast<PODVector<Component*>&>(dest), T::GetTypeStatic()); }
 template <class T> bool Node::HasComponent() const { return HasComponent(T::GetTypeStatic()); }

+ 2 - 2
Engine/Scene/Scene.cpp

@@ -323,7 +323,7 @@ void Scene::UnregisterAllVars()
     varNames_.Clear();
 }
 
-Node* Scene::GetNodeByID(unsigned id) const
+Node* Scene::GetNode(unsigned id) const
 {
     Map<unsigned, Node*>::ConstIterator i = allNodes_.Find(id);
     if (i != allNodes_.End())
@@ -332,7 +332,7 @@ Node* Scene::GetNodeByID(unsigned id) const
         return 0;
 }
 
-Component* Scene::GetComponentByID(unsigned id) const
+Component* Scene::GetComponent(unsigned id) const
 {
     Map<unsigned, Component*>::ConstIterator i = allComponents_.Find(id);
     if (i != allComponents_.End())

+ 3 - 2
Engine/Scene/Scene.h

@@ -54,6 +54,7 @@ class Scene : public Node
 {
     OBJECT(Scene);
     
+    using Node::GetComponent;
     using Node::SaveXML;
     
 public:
@@ -103,9 +104,9 @@ public:
     void UnregisterAllVars();
     
     /// Return node from the whole scene by ID, or null if not found.
-    Node* GetNodeByID(unsigned id) const;
+    Node* GetNode(unsigned id) const;
     /// Return component from the whole scene by ID, or null if not found.
-    Component* GetComponentByID(unsigned id) const;
+    Component* GetComponent(unsigned id) const;
     /// Return active flag.
     bool IsActive() const { return active_; }
     /// Return asynchronous loading flag.

+ 5 - 5
Tools/AssetImporter/AssetImporter.cpp

@@ -149,7 +149,7 @@ void WriteVertex(float*& dest, aiMesh* mesh, unsigned index, unsigned elementMas
     Vector<PODVector<float> >& blendWeights);
 unsigned GetElementMask(aiMesh* mesh);
 
-aiNode* FindNode(const String& name, aiNode* rootNode, bool caseSensitive = true);
+aiNode* GetNode(const String& name, aiNode* rootNode, bool caseSensitive = true);
 aiMatrix4x4 GetDerivedTransform(aiNode* node, aiNode* rootNode);
 aiMatrix4x4 GetDerivedTransform(aiMatrix4x4 transform, aiNode* node, aiNode* rootNode);
 aiMatrix4x4 GetMeshBakingTransform(aiNode* meshNode, aiNode* modelRootNode);
@@ -327,7 +327,7 @@ void Run(const Vector<String>& arguments)
         rootNode_ = scene_->mRootNode;
         if (!rootNodeName.Empty())
         {
-            rootNode_ = FindNode(rootNodeName, rootNode_, false);
+            rootNode_ = GetNode(rootNodeName, rootNode_, false);
             if (!rootNode_)
                 ErrorExit("Could not find scene node " + rootNodeName);
         }
@@ -491,7 +491,7 @@ void CollectBones(OutModel& model)
         {
             aiBone* bone = mesh->mBones[j];
             String boneName(FromAIString(bone->mName));
-            aiNode* boneNode = FindNode(boneName, scene_->mRootNode, true);
+            aiNode* boneNode = GetNode(boneName, scene_->mRootNode, true);
             if (!boneNode)
                 ErrorExit("Could not find scene node for bone " + boneName);
             necessary.Insert(boneNode);
@@ -1571,7 +1571,7 @@ unsigned GetElementMask(aiMesh* mesh)
     return elementMask;
 }
 
-aiNode* FindNode(const String& name, aiNode* rootNode, bool caseSensitive)
+aiNode* GetNode(const String& name, aiNode* rootNode, bool caseSensitive)
 {
     if (!rootNode)
         return 0;
@@ -1579,7 +1579,7 @@ aiNode* FindNode(const String& name, aiNode* rootNode, bool caseSensitive)
         return rootNode;
     for (unsigned i = 0; i < rootNode->mNumChildren; ++i)
     {
-        aiNode* found = FindNode(name, rootNode->mChildren[i], caseSensitive);
+        aiNode* found = GetNode(name, rootNode->mChildren[i], caseSensitive);
         if (found)
             return found;
     }