Jelajahi Sumber

Merge branch 'master' into editor-terrain

xDarkShadowKnightx 11 tahun lalu
induk
melakukan
70e5917d40
56 mengubah file dengan 918 tambahan dan 261 penghapusan
  1. 2 2
      .travis.yml
  2. 1 0
      Bin/Data/Scripts/Editor/EditorImport.as
  3. 7 4
      Docs/AngelScriptAPI.h
  4. 16 24
      Docs/LuaScriptAPI.dox
  5. 88 2
      Docs/Reference.dox
  6. 9 6
      Docs/ScriptAPI.dox
  7. 6 6
      Docs/Urho3D.dox
  8. 5 3
      Rakefile
  9. 2 0
      Readme.txt
  10. 12 0
      Source/CMake/Modules/Urho3D-CMake-common.cmake
  11. 33 21
      Source/CMake/Toolchains/android.toolchain.cmake
  12. 13 1
      Source/CMakeLists.txt
  13. 1 1
      Source/Engine/.soversion
  14. 19 8
      Source/Engine/CMakeLists.txt
  15. 10 0
      Source/Engine/Engine/Engine.cpp
  16. 11 6
      Source/Engine/Graphics/AnimatedModel.cpp
  17. 124 0
      Source/Engine/IO/Compression.cpp
  18. 49 0
      Source/Engine/IO/Compression.h
  19. 21 6
      Source/Engine/IO/FileWatcher.cpp
  20. 9 2
      Source/Engine/IO/FileWatcher.h
  21. 21 2
      Source/Engine/LuaScript/CMakeLists.txt
  22. 12 0
      Source/Engine/LuaScript/LuaScript.cpp
  23. 12 3
      Source/Engine/LuaScript/LuaScriptInstance.cpp
  24. 2 0
      Source/Engine/LuaScript/LuaScriptInstance.h
  25. 4 0
      Source/Engine/LuaScript/ToluaUtils.cpp
  26. 6 0
      Source/Engine/LuaScript/ToluaUtils.h
  27. 1 0
      Source/Engine/LuaScript/pkgs/Core/Variant.pkg
  28. 4 0
      Source/Engine/LuaScript/pkgs/IO/Compression.pkg
  29. 0 9
      Source/Engine/LuaScript/pkgs/IO/FileWatcher.pkg
  30. 1 1
      Source/Engine/LuaScript/pkgs/IOLuaAPI.pkg
  31. 4 4
      Source/Engine/LuaScript/pkgs/Urho2D/TileMap2D.pkg
  32. 6 5
      Source/Engine/LuaScript/pkgs/Urho2D/TileMapDefs2D.pkg
  33. 1 1
      Source/Engine/LuaScript/pkgs/Urho2D/TileMapLayer2D.pkg
  34. 10 5
      Source/Engine/Math/Ray.cpp
  35. 8 3
      Source/Engine/Navigation/NavigationMesh.cpp
  36. 7 1
      Source/Engine/Scene/LogicComponent.cpp
  37. 2 1
      Source/Engine/Scene/LogicComponent.h
  38. 5 2
      Source/Engine/Script/CMakeLists.txt
  39. 5 0
      Source/Engine/Script/IOAPI.cpp
  40. 2 0
      Source/Engine/Script/NavigationAPI.cpp
  41. 2 0
      Source/Engine/Script/PhysicsAPI.cpp
  42. 4 0
      Source/Engine/Script/Script.cpp
  43. 4 0
      Source/Engine/Script/ScriptAPI.h
  44. 8 3
      Source/Engine/Script/ScriptInstance.cpp
  45. 2 0
      Source/Engine/Script/ScriptInstance.h
  46. 16 15
      Source/Engine/Script/Urho2DAPI.cpp
  47. 53 5
      Source/Engine/Urho2D/TileMap2D.cpp
  48. 9 4
      Source/Engine/Urho2D/TileMap2D.h
  49. 95 32
      Source/Engine/Urho2D/TileMapDefs2D.cpp
  50. 17 14
      Source/Engine/Urho2D/TileMapDefs2D.h
  51. 74 9
      Source/Engine/Urho2D/TileMapLayer2D.cpp
  52. 8 4
      Source/Engine/Urho2D/TileMapLayer2D.h
  53. 46 33
      Source/Engine/Urho2D/TmxFile2D.cpp
  54. 13 9
      Source/Engine/Urho2D/TmxFile2D.h
  55. 10 4
      Source/Samples/CMakeLists.txt
  56. 6 0
      Source/Tools/AssetImporter/AssetImporter.cpp

+ 2 - 2
.travis.yml

@@ -50,7 +50,7 @@ before_install:
     - bash -c "[ '$TRAVIS_BRANCH' == 'master' ] && [ '$TRAVIS_PULL_REQUEST' == 'false' ]" && export ON_MASTER_COMMIT=1 && bash -c "[ $SITE_UPDATE ]" && export SITE_UPDATE_ON_MASTER_COMMIT=1 || true
     - bash -c "[ $ON_MASTER_COMMIT ]" && export COMMIT_MESSAGE=$(git log --format=%B -n 1 $TRAVIS_COMMIT) && echo $COMMIT_MESSAGE |grep -cq '\[ci package\]' && git fetch --depth=2000 --tags origin $TRAVIS_BRANCH && export PACKAGE_UPLOAD=1 || true
     - bash -c "[ $ON_MASTER_COMMIT ]" && export RELEASE_TAG=$(git describe --tags --exact-match $TRAVIS_COMMIT 2>/dev/null) && bash -c "[ $RELEASE_TAG ]" && export PACKAGE_UPLOAD=1 || true
-    - bash -c "[ $ANDROID ]" && wget -q http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86_64.tar.bz2 && tar xjf *.bz2 && rm *.bz2 && ln -s android-ndk* android-ndk && export ANDROID_NDK=$(pwd)/android-ndk && bash -c "[ $PACKAGE_UPLOAD ]" && wget -q http://dl.google.com/android/android-sdk_r22.6.1-linux.tgz && tar xzf *.tgz && rm *.tgz && ln -s android-sdk* android-sdk && export ANDROID_SDK=$(pwd)/android-sdk || true
+    - bash -c "[ $ANDROID ]" && wget -q http://dl.google.com/android/ndk/android-ndk32-r10-linux-x86_64.tar.bz2 && tar xjf *.bz2 && rm *.bz2 && ln -s android-ndk* android-ndk && export ANDROID_NDK=$(pwd)/android-ndk && bash -c "[ $PACKAGE_UPLOAD ]" && wget -q http://dl.google.com/android/android-sdk_r23.0.2-linux.tgz && tar xzf *.tgz && rm *.tgz && ln -s android-sdk* android-sdk && export ANDROID_SDK=$(pwd)/android-sdk || true
     - bash -c "[ $RPI ]" && git clone --depth 1 https://github.com/raspberrypi/tools.git rpi-tools && export RASPI_TOOL=$(pwd)/rpi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin && git clone --depth=1 https://github.com/urho3d/rpi-sysroot.git rpi-sysroot && export RASPI_ROOT=$(pwd)/rpi-sysroot || true
     - bash -c "( [ $SITE_UPDATE_ON_MASTER_COMMIT ] || [ $PACKAGE_UPLOAD ] )" && travis_retry sudo add-apt-repository ppa:george-edison55/precise-backports -y || true
     - travis_retry sudo apt-get update -q -y
@@ -60,7 +60,7 @@ install:
     - bash -c "( [ $SITE_UPDATE_ON_MASTER_COMMIT ] || [ $PACKAGE_UPLOAD ] )" && travis_retry sudo apt-get install -q -y --no-install-recommends doxygen graphviz || true
     - bash -c "[ $WINDOWS ]" && travis_retry sudo apt-get install -q -y gcc-mingw-w64 gcc-mingw-w64-i686 gcc-mingw-w64-x86-64 g++-mingw-w64 g++-mingw-w64-i686 g++-mingw-w64-x86-64 binutils-mingw-w64 binutils-mingw-w64-i686 binutils-mingw-w64-x86-64 && export MINGW_PREFIX=/usr/bin/${ARCH}-w64-mingw32 || true
     - bash -c "( [ $LINUX ] || [ $RPI ] ) && [ $PACKAGE_UPLOAD ]" && travis_retry sudo apt-get install -q -y rpm || true
-    - bash -c "[ $ANDROID ] && [ $PACKAGE_UPLOAD ]" && (while :; do echo 'y'; sleep 1; done) |android-sdk/tools/android update sdk --no-ui --filter platform-tool,build-tools-19.0.3,android-19,system-image,extra-android-support || true
+    - bash -c "[ $ANDROID ] && [ $PACKAGE_UPLOAD ]" && (while :; do echo 'y'; sleep 1; done) |android-sdk/tools/android update sdk --no-ui --filter platform-tool,build-tools-20.0.0,android-19,system-image,extra-android-support || true
     - bash -e /etc/init.d/xvfb start
 script: rake travis_ci
 after_success:

+ 1 - 0
Bin/Data/Scripts/Editor/EditorImport.as

@@ -122,6 +122,7 @@ void ImportTundraScene(const String&in fileName)
     ResetScene();
 
     // Set standard gravity
+    editorScene.CreateComponent("PhysicsWorld");
     editorScene.physicsWorld.gravity = Vector3(0, -9.81, 0);
 
     // Create zone & global light

+ 7 - 4
Docs/AngelScriptAPI.h

@@ -10100,12 +10100,11 @@ float GetAttributeAnimationSpeed(const String&) const;
 WrapMode GetAttributeAnimationWrapMode(const String&) const;
 Variant GetAttributeDefault(const String&) const;
 TileMapLayer2D GetLayer(uint) const;
-Vector2 IndexToPosition(int, int) const;
 bool Load(File, bool = false);
 bool Load(VectorBuffer&, bool = false);
 bool LoadXML(const XMLElement&, bool = false);
 void MarkNetworkUpdate() const;
-bool PositionToIndex(int&, int&, const Vector2&) const;
+bool PositionToTileIndex(int&, int&, const Vector2&) const;
 void Remove();
 void RemoveInstanceDefault();
 void ResetToDefault();
@@ -10117,6 +10116,7 @@ bool SetAttribute(const String&, const Variant&);
 void SetAttributeAnimation(const String&, ValueAnimation, WrapMode = WM_LOOP, float = 1.0f);
 void SetAttributeAnimationSpeed(const String&, float);
 void SetAttributeAnimationWrapMode(const String&, WrapMode);
+Vector2 TileIndexToPosition(int, int) const;
 
 // Properties:
 bool animationEnabled;
@@ -10180,7 +10180,7 @@ ValueAnimation GetAttributeAnimation(const String&) const;
 float GetAttributeAnimationSpeed(const String&) const;
 WrapMode GetAttributeAnimationWrapMode(const String&) const;
 Variant GetAttributeDefault(const String&) const;
-TileObject2D GetObject(uint) const;
+TileMapObject2D GetObject(uint) const;
 Node GetObjectNode(uint) const;
 Tile2D GetTile(int, int) const;
 Node GetTileNode(int, int) const;
@@ -10249,7 +10249,7 @@ int weakRefs;
 int width;
 };
 
-class TileObject2D
+class TileMapObject2D
 {
 // Methods:
 bool HasProperty(const String&) const;
@@ -11851,6 +11851,7 @@ enum Orientation2D
 {
 O_ORTHOGONAL,
 O_ISOMETRIC,
+O_STAGGERED,
 };
 
 enum PassLightingMode
@@ -12072,7 +12073,9 @@ float Ceil(float);
 float Clamp(float, float, float);
 int Clamp(int, int, int);
 void ClearDelayedExecute(const String& = String ( ));
+VectorBuffer CompressVectorBuffer(VectorBuffer&);
 float Cos(float);
+VectorBuffer DecompressVectorBuffer(VectorBuffer&);
 void DelayedExecute(float, bool, const String&);
 void DelayedExecute(float, bool, const String&, const Array<Variant>);
 bool Equals(float, float);

+ 16 - 24
Docs/LuaScriptAPI.dox

@@ -78,7 +78,6 @@ namespace Urho3D
 <a href="#Class_FileSelector"><b>FileSelector</b></a>
 <a href="#Class_FileSelectorEntry"><b>FileSelectorEntry</b></a>
 <a href="#Class_FileSystem"><b>FileSystem</b></a>
-<a href="#Class_FileWatcher"><b>FileWatcher</b></a>
 <a href="#Class_FocusParameters"><b>FocusParameters</b></a>
 <a href="#Class_Font"><b>Font</b></a>
 <a href="#Class_Frustum"><b>Frustum</b></a>
@@ -177,7 +176,7 @@ namespace Urho3D
 <a href="#Class_TileMap2D"><b>TileMap2D</b></a>
 <a href="#Class_TileMapInfo2D"><b>TileMapInfo2D</b></a>
 <a href="#Class_TileMapLayer2D"><b>TileMapLayer2D</b></a>
-<a href="#Class_TileObject2D"><b>TileObject2D</b></a>
+<a href="#Class_TileMapObject2D"><b>TileMapObject2D</b></a>
 <a href="#Class_Time"><b>Time</b></a>
 <a href="#Class_TmxFile2D"><b>TmxFile2D</b></a>
 <a href="#Class_ToolTip"><b>ToolTip</b></a>
@@ -2153,16 +2152,6 @@ Methods:
 - String GetUserDocumentsDir() const
 - String GetAppPreferencesDir(const String org, const String app) const
 
-<a name="Class_FileWatcher"></a>
-### FileWatcher : Object
-
-Methods:
-
-- bool StartWatching(const String pathName, bool watchSubDirs)
-- void StopWatching()
-- void AddChange(const String fileName)
-- const String GetPath() const
-
 <a name="Class_FocusParameters"></a>
 ### FocusParameters
 
@@ -5533,8 +5522,8 @@ Methods:
 - const TileMapInfo2D& GetInfo() const
 - unsigned GetNumLayers() const
 - TileMapLayer2D* GetLayer(unsigned index) const
-- Vector2 IndexToPosition(int x, int y) const
-- bool PositionToIndex(const Vector2& position, int x = 0, int y = 0) const
+- Vector2 TileIndexToPosition(int x, int y) const
+- bool PositionToTileIndex(const Vector2& position, int x = 0, int y = 0) const
 
 Properties:
 
@@ -5578,7 +5567,7 @@ Methods:
 - Node* GetTileNode(int x, int y) const
 - Tile2D* GetTile(int x, int y) const
 - unsigned GetNumObjects() const
-- TileObject2D* GetObject(unsigned index) const
+- TileMapObject2D* GetObject(unsigned index) const
 - Node* GetObjectNode(unsigned index) const
 - Node* GetImageNode() const
 
@@ -5592,13 +5581,13 @@ Properties:
 - unsigned numObjects (readonly)
 - Node* imageNode (readonly)
 
-<a name="Class_TileObject2D"></a>
-### TileObject2D
+<a name="Class_TileMapObject2D"></a>
+### TileMapObject2D
 
 
 Methods:
 
-- TileObjectType2D GetObjectType() const
+- TileMapObjectType2D GetObjectType() const
 - const String GetName() const
 - const String GetType() const
 - const Vector2& GetPosition() const
@@ -5612,7 +5601,7 @@ Methods:
 
 Properties:
 
-- TileObjectType2D objectType (readonly)
+- TileMapObjectType2D objectType (readonly)
 - String name (readonly)
 - String type (readonly)
 - Vector2 position (readonly)
@@ -6878,6 +6867,7 @@ Properties:
 
 - int O_ORTHOGONAL
 - int O_ISOMETRIC
+- int O_STAGGERED
 
 ### PassLightingMode
 
@@ -7017,7 +7007,7 @@ Properties:
 - int LT_IMAGE_LAYER
 - int LT_INVALID
 
-### TileObjectType2D
+### TileMapObjectType2D
 
 - int OT_RECTANGLE
 - int OT_ELLIPSE
@@ -7116,7 +7106,9 @@ Properties:
 - float Atan2(float y, float x)
 - float Clamp(float value, float min, float max)
 - int ClampInt(int value, int min, int max)
+- VectorBuffer CompressVectorBuffer(VectorBuffer& src)
 - float Cos(float angle)
+- VectorBuffer DecompressVectorBuffer(VectorBuffer& src)
 - bool Equals(float lhs, float rhs)
 - void ErrorDialog(const String title, const String message)
 - void ErrorExit(const String message = String::EMPTY, int exitCode = EXIT_FAILURE)
@@ -7165,11 +7157,11 @@ Properties:
 - void PrintLine(const String str, bool error = false)
 - int Rand()
 - float RandStandardNormal()
-- float Random()
-- float Random(float min, float max)
 - float Random(float range)
-- int RandomInt(int range)
+- float Random(float min, float max)
+- float Random()
 - int RandomInt(int min, int max)
+- int RandomInt(int range)
 - float RandomNormal(float meanValue, float variance)
 - String RemoveTrailingSlash(const String pathName)
 - String ReplaceExtension(const String fullPath, const String newExtension)
@@ -7180,8 +7172,8 @@ Properties:
 - float Sign(float value)
 - float Sin(float angle)
 - float SmoothStep(float lhs, float rhs, float t)
-- void SubscribeToEvent(const String eventName, const String functionName)
 - void SubscribeToEvent(void* sender, const String eventName, const String functionName)
+- void SubscribeToEvent(const String eventName, const String functionName)
 - float Tan(float angle)
 - bool ToBool(const String source)
 - Color ToColor(const String source)

+ 88 - 2
Docs/Reference.dox

@@ -1749,7 +1749,7 @@ You can chose from animated sprites, 2D particle emitters and static sprites.
 
 \section Urho2D_Animated Animated sprites
 
-Workflow for creating animated sprites in Urho2D relies on Spriter (c). 
+Workflow for creating animated sprites in Urho2D relies on Spriter (c).
 Spriter is a crossplatform tool for creating 2D animations. It comes both as an almost fully featured free version and a more advanced 'pro' version. Free version is available at http://www.brashmonkey.com/spriter.htm. To get started, scml files from Bin/Data/Urho2D folder can be loaded in Spriter. Note that although currently Spriter doesn't support spritesheets/texture atlases, Urho2D does: you just have to use the same name for your scml file and your spritesheet's xml file (see details below on how to generate this file). Keep your individual image files as they are still required if you want to later edit your scml project in Spriter.
 A *.scml file is loaded using AnimationSet2D class (Resource) and rendered using AnimatedSprite2D class (Drawable component):
 
@@ -1779,7 +1779,7 @@ Both are rendered using StaticSprite2D class (Drawable component):
 - StaticSprite2D: used to display a Sprite2D. Equivalent to a 3D StaticModel.
 - Sprite2D: an image defined with texture, texture rectangle and hot spot.
 - SpriteSheet2D: a texture atlas image (that packs multiple Sprite2D images).
-Spritesheets can be created using tools like ShoeBox (http://renderhjs.net/shoebox/), darkFunction Editor (http://darkfunction.com/editor/), SpriteHelper (http://www.gamedevhelper.com/spritehelper/), TexturePacker (http://www.codeandweb.com/texturepacker), ...
+Spritesheets can be created using tools like ShoeBox (http://renderhjs.net/shoebox/), darkFunction Editor (http://darkfunction.com/editor/), SpriteHelper (http://www.gamedevhelper.com/spriteHelper2Info.php), TexturePacker (http://www.codeandweb.com/texturepacker), ...
 These tools will generate an image file and a xml file mapping coordinates and size for each individual image. Note that Urho2D uses same xml file format as Sparrow/Starling engines.
 
 You can assign a material to an image by creating a xml parameter file named as the image and located in the same folder.
@@ -1843,6 +1843,92 @@ You can use different layers in order to simulate perspective. In this case you
 
 Finally, note that you can easily mix both 2D and 3D resources. 3D assets' position need to be slightly offset on the Z axis (z=1 is enough), Camera's position needs to be slightly offset (on the Z axis) from 3D assets' max girth and a Light is required.
 
+\section Urho2D_TileMap Tile Maps
+
+Tile maps workflow relies on the tmx file format, which is the native format of Tiled, a free app available at http://www.mapeditor.org/. It is strongly recommended to only use the latest stable release (currently 0.9.1). Do not use daily builds or older revisions, otherwise results may be unpredictable.
+
+Check example 36_Urho2DTileMap for a basic demonstration.
+
+You can use tile maps for the design of the whole scene/level, or in adjunction to other 2D resources.
+
+\section Urho2D_LoadingTMX "Loading" a Tile Map file
+
+A tmx file is loaded using \ref TmxFile2D "TmxFile2D resource class" and rendered using \ref TileMap2D "TileMap2D component class".
+You just have to create a \ref TileMap2D "TileMap2D" component inside a node and then assign the tmx resource file to it.
+
+C++:
+\code
+SharedPtr<Node> tileMapNode(scene_->CreateChild("TileMap")); // Create a standard Urho3D node
+tileMapNode->SetPosition(Vector3(0.0f, 0.0f, -1.0f));
+TileMap2D* tileMap = tileMapNode->CreateComponent<TileMap2D>(); // Create the TileMap2D component
+tileMap->SetTmxFile(cache->GetResource<TmxFile2D>("Urho2D/isometric_grass_and_water.tmx")); // Assign tmx resource file to component
+\endcode
+
+AngelScript:
+\code
+Node@ tileMapNode = scene_.CreateChild("TileMap"); // Create a standard Urho3D node
+tileMapNode.position = Vector3(0.0f, 0.0f, -1.0f);
+TileMap2D@ tileMap = tileMapNode.CreateComponent("TileMap2D"); // Create the TileMap2D component
+tileMap.tmxFile = cache.GetResource("TmxFile2D", "Urho2D/isometric_grass_and_water.tmx"); // Assign the tmx resource file to component
+\endcode
+
+Lua:
+\code
+local tileMapNode = scene_:CreateChild("TileMap") -- Create a standard Urho3D node
+tileMapNode.position = Vector3(0, 0, -1)
+local tileMap = tileMapNode:CreateComponent("TileMap2D") -- Create the TileMap2D component
+tileMap.tmxFile = cache:GetResource("TmxFile2D", "Urho2D/isometric_grass_and_water.tmx") -- Assign tmx resource file to component
+\endcode
+
+Note that currently only XML Layer Format is supported (Base64 and CSV are not). In Tiled, go to Maps > Map Properties to set 'Layer Format' to 'XML'.
+
+\section Urho2D_TMX_maps Tile Maps
+
+Once a tmx file is loaded in Urho, use \ref TileMap2D::GetInfo "GetInfo()" to access the map properties through \ref TileMapInfo2D class.
+
+A map is defined by its:
+- orientation: Urho2D supports both orthogonal (flat) and isometric (strict iso 2.5D and staggered iso) tile maps. Orientation can be retrieved with \ref TileMapInfo2D::orientation_ "orientation_" attribute (returns 0 for ortho, 1 for iso and 2 for staggered).
+- width and height expressed as a number of tiles in the map:  use \ref TileMapInfo2D::width_ "width_" and \ref TileMapInfo2D::height_ "height_" attributes to access these values
+- width and height expressed in Urho2D space: use \ref TileMapInfo2D::GetMapWidth "GetMapWidth()" and \ref TileMapInfo2D::GetMapHeight "GetMapHeight()" to access these values which are useful to set the camera's position for example
+- tile width and tile height as the size in pixels of the tiles in the map (expressed a percentage): use \ref TileMapInfo2D::tileWidth_ "tileWidth_" and \ref TileMapInfo2D::tileHeight_ "tileHeight_" attributes to access these values
+
+Two convenient functions are provided to convert Tiled index to/from Urho2D space:
+- \ref TileMapInfo2D::TileIndexToPosition "TileIndexToPosition()" to convert tile index to Urho position
+- \ref TileMapInfo2D::PositionToTileIndex "PositionToTileIndex()" to convert Urho position to tile index (returns false if position is outside of the map) 
+
+\section Urho2D_TMX_layers Tile Map Layers
+
+A tile map is composed of a mix of ordered \ref TileMapLayer2D "layers".
+
+Accessing layers : from a \ref TileMap2D "TileMap2D component", layers are accessed by their index from bottom to top using \ref TileMap2D::GetLayer "GetLayer()" function.  \ref TileMap2D::GetNumLayers "GetNumLayers()" returns the number of layers contained in the tmx file. \ref TileMapLayer2D::GetLayerType "GetLayerType()" returns the type of layer (Tile, Object or Image).
+
+A layer is characterized by its:
+- name: currently not accessible
+- width and height expressed as a number of tiles: use \ref TileMapLayer2D::GetWidth "GetWidth()" and \ref TileMapLayer2D::GetHeight "GetHeight()" to access these values
+
+Layer visibility can be toggled using \ref TileMapLayer2D::SetVisible "SetVisible()"  (and visibility state can be accessed with \ref TileMapLayer2D::IsVisible "IsVisible()")
+
+\section Urho2D_TMX_Objects Tile Map Objects
+
+Tiled \ref TileMapObject2D "objects" are wire shapes (Rectangle, Ellipse, Polygon, Polyline) and sprites (Tile) that are freely positionable in the tile map.
+
+Accessing Tiled objects : from a \ref TileMapLayer2D "TileMapLayer2D layer", objects are accessed by their index using \ref TileMapLayer2D::GetObject "GetObject()". \ref TileMapLayer2D::GetNumObjects "GetNumObjects()" returns the number of objects contained in the object layer (tile and image layers will return 0 as they don't hold objects).
+
+Use \ref TileMapObject2D::GetObjectType "GetObjectType()" to get the nature (TileMapObjectType2D) of the selected object.
+
+Objects' properties (Name and Type) can be accessed using respectively \ref TileMapObject2D::GetName "GetName()" and \ref TileMapObject2D::GetType "GetType()". Type can be useful to flag categories of objects in Tiled.
+
+Except Tile, object layers are not visible. They can be used:
+- to easily design polygon sprites and Box2D shapes using the object's vertices: use \ref TileMapObject2D::GetNumPoints "GetNumPoints()" to get the number of vertices and \ref TileMapObject2D::GetPoint "GetPoint()" to iterate through the vertices
+- as placeholders to easily set the position and size of entities in the world, using \ref TileMapObject2D::GetPosition "GetPosition()" and \ref TileMapObject2D::GetSize "GetSize()"
+- to display Tile objects as sprites
+- to create a background from Tile sprites
+- ...
+
+Additionaly \ref Sprite2D "Sprite2D" resource from a Tile object is retrieved using \ref TileMapObject2D::GetTileSprite "GetTileSprite()"
+
+If need be you can access the grid id (relative to the tilesets used) of a Tile object using \ref TileMapObject2D::GetTileGid "GetTileGid()".
+
 \page Serialization Serialization
 
 Classes that derive from Serializable can perform automatic serialization to binary or XML format by defining \ref AttributeInfo "attributes". Attributes are stored to the Context per class. %Scene load/save and network replication are both implemented by having the Node and Component classes derive from Serializable.

+ 9 - 6
Docs/ScriptAPI.dox

@@ -2141,7 +2141,7 @@ namespace Urho3D
 <a href="#Class_TileMap2D"><b>TileMap2D</b></a>
 <a href="#Class_TileMapInfo2D"><b>TileMapInfo2D</b></a>
 <a href="#Class_TileMapLayer2D"><b>TileMapLayer2D</b></a>
-<a href="#Class_TileObject2D"><b>TileObject2D</b></a>
+<a href="#Class_TileMapObject2D"><b>TileMapObject2D</b></a>
 <a href="#Class_Time"><b>Time</b></a>
 <a href="#Class_Timer"><b>Timer</b></a>
 <a href="#Class_TmxFile2D"><b>TmxFile2D</b></a>
@@ -10890,12 +10890,11 @@ Methods:
 - WrapMode GetAttributeAnimationWrapMode(const String&) const
 - Variant GetAttributeDefault(const String&) const
 - TileMapLayer2D@ GetLayer(uint) const
-- Vector2 IndexToPosition(int, int) const
 - bool Load(File@, bool = false)
 - bool Load(VectorBuffer&, bool = false)
 - bool LoadXML(const XMLElement&, bool = false)
 - void MarkNetworkUpdate() const
-- bool PositionToIndex(int&, int&, const Vector2&) const
+- bool PositionToTileIndex(int&, int&, const Vector2&) const
 - void Remove()
 - void RemoveInstanceDefault()
 - void ResetToDefault()
@@ -10907,6 +10906,7 @@ Methods:
 - void SetAttributeAnimation(const String&, ValueAnimation@, WrapMode = WM_LOOP, float = 1.0f)
 - void SetAttributeAnimationSpeed(const String&, float)
 - void SetAttributeAnimationWrapMode(const String&, WrapMode)
+- Vector2 TileIndexToPosition(int, int) const
 
 Properties:
 
@@ -10958,7 +10958,7 @@ Methods:
 - float GetAttributeAnimationSpeed(const String&) const
 - WrapMode GetAttributeAnimationWrapMode(const String&) const
 - Variant GetAttributeDefault(const String&) const
-- TileObject2D@ GetObject(uint) const
+- TileMapObject2D@ GetObject(uint) const
 - Node@ GetObjectNode(uint) const
 - Tile2D@ GetTile(int, int) const
 - Node@ GetTileNode(int, int) const
@@ -11008,9 +11008,9 @@ Properties:
 - int weakRefs // readonly
 - int width // readonly
 
-<a name="Class_TileObject2D"></a>
+<a name="Class_TileMapObject2D"></a>
 
-### TileObject2D
+### TileMapObject2D
 
 Methods:
 
@@ -12460,6 +12460,7 @@ Properties:
 
 - O_ORTHOGONAL
 - O_ISOMETRIC
+- O_STAGGERED
 
 
 ### PassLightingMode
@@ -12680,7 +12681,9 @@ Properties:
 - float Clamp(float, float, float)
 - int Clamp(int, int, int)
 - void ClearDelayedExecute(const String& = String ( ))
+- VectorBuffer CompressVectorBuffer(VectorBuffer&)
 - float Cos(float)
+- VectorBuffer DecompressVectorBuffer(VectorBuffer&)
 - void DelayedExecute(float, bool, const String&)
 - void DelayedExecute(float, bool, const String&, const Variant[]@)
 - bool Equals(float, float)

+ 6 - 6
Docs/Urho3D.dox

@@ -2,9 +2,9 @@ namespace Urho3D
 {
 
 /**
-\mainpage Urho3D - cross-platform rendering and game engine
+\mainpage Urho3D - cross-platform 2D and 3D game engine
 
-Urho3D (http://urho3d.github.io/) is a lightweight, cross-platform rendering and game engine implemented in C++ and released under the MIT license. It utilizes either Direct3D9 or OpenGL for rendering (%Shader %Model 2 or OpenGL 2.0 required as minimum.)
+Urho3D (http://urho3d.github.io/) is a lightweight, cross-platform 2D and 3D game engine implemented in C++ and released under the MIT license. It utilizes either Direct3D9 or OpenGL for rendering (%Shader %Model 2 or OpenGL 2.0 required as minimum.)
 
 For getting started, see:
 
@@ -37,18 +37,18 @@ For further reference, see:
 \ref Serialization "Serialization" <br>
 \ref Network "Networking" <br>
 \ref Multithreading "Multithreading" <br>
-\ref AttributeAnimation "Attribute Animation" <br>
+\ref AttributeAnimation "Attribute animation" <br>
 \ref Tools "Tools" <br>
 \ref Unicode "Unicode support" <br>
 \ref FileFormats "Custom file formats" <br>
 \ref CodingConventions "Coding conventions" <br>
 \ref ContributionChecklist "Contribution checklist" <br>
 \ref ScriptAPI "Scripting API (generated)" <br>
-\ref LuaScriptAPI "Lua Scripting API (generated)" <br>
+\ref LuaScriptAPI "Lua scripting API (generated)" <br>
 \ref EventList "Event list (generated)" <br>
 \ref AttributeList "Attribute list (generated)" <br>
 
-For Urho3D related links and projects, see \ref ExternalLinks "External Links".
+For Urho3D related links and projects, see \ref ExternalLinks "External links".
 
 For credits, copyright and licensing information, see \ref Credits & \ref License.
 
@@ -313,7 +313,7 @@ V1.0
 
 - Original release.
 
-\page ExternalLinks External Links
+\page ExternalLinks External links
 
 Related projects:
 

+ 5 - 3
Rakefile

@@ -249,6 +249,8 @@ def makefile_travis_ci
     system 'MINGW_PREFIX= ./cmake_gcc.sh -DURHO3D_LIB_TYPE=$URHO3D_LIB_TYPE -DURHO3D_64BIT=$URHO3D_64BIT -DURHO3D_LUA=1 -DURHO3D_TOOLS=0' or abort 'Failed to configure native build for tolua++ target'
     system "cd Build/ThirdParty/toluapp/src/bin && make -j$NUMJOBS" or abort 'Failed to build tolua++ tool'
     ENV['SKIP_NATIVE'] = '1'
+    # Temporary workaround due to Travis-CI insufficient memory in MinGW/STATIC build configuration, always use Release configuration.
+    $configuration = 'Release'
   else
     jit = 'JIT'
     amalg = '-DURHO3D_LUAJIT_AMALG=1'
@@ -275,9 +277,9 @@ def makefile_travis_ci
   else
     platform_prefix = ''
   end
-  # Temporary workaround due to Travis-CI insufficient memory in 64-bit/MinGW/STATIC build configuration, build samples separately using single worker process
-  if ENV['CI'] and ENV['WINDOWS'] and ENV['URHO3D_64BIT'] and ENV['URHO3D_LIB_TYPE'] == 'STATIC'
-    system "cd #{platform_prefix}Build/Tools && make -j$NUMJOBS && cd .. && make" or abort 'Failed to build or test Urho3D library'
+  # Temporary workaround due to Travis-CI insufficient memory in MinGW/STATIC build configuration, build samples separately and retry build for 3 times from where it fails
+  if ENV['CI'] and ENV['WINDOWS'] and ENV['URHO3D_LIB_TYPE'] == 'STATIC'
+    system "cd #{platform_prefix}Build/Tools && make -j$NUMJOBS && cd .. && (make -j$NUMJOBS || make || make)" or abort 'Failed to build or test Urho3D library'
   else
     # Only 64-bit Linux environment with virtual framebuffer X server support and not MinGW build; or OSX build environment are capable to run tests
     if $testing == 1 and (ENV['URHO3D_64BIT'] and ENV['WINDOWS'].to_i != 1 or ENV['OSX'])

+ 2 - 0
Readme.txt

@@ -442,6 +442,8 @@ cmake_xxxx batch files or shell scripts.
 |URHO3D_LUAJIT        |0|Enable Lua scripting support using LuaJIT (check      |
 |                     | | LuaJIT's CMakeLists.txt for more options)            |
 |URHO3D_LUAJIT_AMALG  |0|Enable LuaJIT amalgamated build (LuaJIT only)         |
+|URHO3D_PHYSICS       |1|Enable Physics support                                |
+|URHO3D_NAVIGATION    |1|Enable Navigation support                             |
 |URHO3D_SAFE_LUA      |0|Enable Lua C++ wrapper safety checks (when Lua        |
 |                     | | scripting support is enabled only)                   |
 |URHO3D_SAMPLES       |0|Build sample applications                             |

+ 12 - 0
Source/CMake/Modules/Urho3D-CMake-common.cmake

@@ -42,6 +42,8 @@ option (URHO3D_64BIT "Enable 64-bit build")
 option (URHO3D_ANGELSCRIPT "Enable AngelScript scripting support" TRUE)
 option (URHO3D_LUA "Enable additional Lua scripting support")
 option (URHO3D_LUAJIT "Enable Lua scripting support using LuaJIT (check LuaJIT's CMakeLists.txt for more options)")
+option (URHO3D_NAVIGATION "Enable navigation support" TRUE)
+option (URHO3D_PHYSICS "Enable physics support" TRUE)
 option (URHO3D_SSE "Enable SSE instruction set" ${URHO3D_DEFAULT_SSE})
 if (CMAKE_PROJECT_NAME STREQUAL Urho3D)
     cmake_dependent_option (URHO3D_LUAJIT_AMALG "Enable LuaJIT amalgamated build (LuaJIT only)" FALSE "URHO3D_LUAJIT" FALSE)
@@ -178,6 +180,16 @@ if (URHO3D_LUA)
     add_definitions (-DURHO3D_LUA)
 endif ()
 
+# Add definition for Navigation
+if (URHO3D_NAVIGATION)
+    add_definitions (-DURHO3D_NAVIGATION)
+endif ()
+
+# Add definition for Physics
+if (URHO3D_PHYSICS)
+    add_definitions (-DURHO3D_PHYSICS)
+endif ()
+
 # Default library type is STATIC
 if (URHO3D_LIB_TYPE)
     string (TOUPPER ${URHO3D_LIB_TYPE} URHO3D_LIB_TYPE)

+ 33 - 21
Source/CMake/Toolchains/android.toolchain.cmake

@@ -1,5 +1,5 @@
 # Copyright (c) 2010-2011, Ethan Rublee
-# Copyright (c) 2011-2013, Andrey Kamaev
+# Copyright (c) 2011-2014, Andrey Kamaev
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -12,9 +12,9 @@
 #     this list of conditions and the following disclaimer in the documentation
 #     and/or other materials provided with the distribution.
 #
-# 3.  The name of the copyright holders may be used to endorse or promote
-#     products derived from this software without specific prior written
-#     permission.
+# 3.  Neither the name of the copyright holder 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
@@ -297,6 +297,12 @@
 #     [+] updated for NDK r9
 #   - November 2013
 #     [+] updated for NDK r9b
+#   - December 2013
+#     [+] updated for NDK r9c
+#   - January 2014
+#     [~] fix copying of shared STL
+#   - April 2014
+#     [+] updated for NDK r9d
 # ------------------------------------------------------------------------------
 
 # Modified by Lasse Oorni and Yao Wei Tjong for Urho3D
@@ -325,7 +331,8 @@ set( CMAKE_SYSTEM_VERSION 1 )
 # rpath makes low sence for Android
 set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." )
 
-set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" )
+# Urho3D: updated for NDK r10
+set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" )
 if(NOT DEFINED ANDROID_NDK_SEARCH_PATHS)
  if( CMAKE_HOST_WIN32 )
   file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS )
@@ -343,10 +350,10 @@ set( ANDROID_SUPPORTED_ABIS_arm "armeabi-v7a;armeabi;armeabi-v7a with NEON;armea
 set( ANDROID_SUPPORTED_ABIS_x86 "x86" )
 set( ANDROID_SUPPORTED_ABIS_mipsel "mips" )
 
-# Urho3D: default to API 9
-set( ANDROID_DEFAULT_NDK_API_LEVEL 9 )
-set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 9 )
-set( ANDROID_DEFAULT_NDK_API_LEVEL_mips 9 )
+# Urho3D: default to API 12
+set( ANDROID_DEFAULT_NDK_API_LEVEL 12 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 12 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_mips 12 )
 
 
 macro( __LIST_FILTER listvar regex )
@@ -472,7 +479,7 @@ endif()
 
 
 # detect current host platform
-if( NOT DEFINED ANDROID_NDK_HOST_X64 AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64")
+if( NOT DEFINED ANDROID_NDK_HOST_X64 AND (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64" OR CMAKE_HOST_APPLE) )
  set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" )
  mark_as_advanced( ANDROID_NDK_HOST_X64 )
 endif()
@@ -1138,15 +1145,7 @@ endif()
 # case of shared STL linkage
 if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl )
  string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" )
- if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" )
-  get_filename_component( __libstlname "${__libstl}" NAME )
-  execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess )
-  if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}")
-   message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" )
-  endif()
-  unset( __fileCopyProcess )
-  unset( __libstlname )
- endif()
+ # TODO: check if .so file exists before the renaming
 endif()
 
 
@@ -1512,7 +1511,8 @@ endif()
 
 # global includes and link directories
 include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} )
-link_directories( "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" )
+get_filename_component(__android_install_path "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ABSOLUTE) # avoid CMP0015 policy warning
+link_directories( "${__android_install_path}" )
 
 # detect if need link crtbegin_so.o explicitly
 if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK )
@@ -1565,6 +1565,18 @@ if(NOT _CMAKE_IN_TRY_COMPILE)
  set( ANDROID_LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "path for android libs" FORCE )
 endif()
 
+# copy shared stl library to build directory
+if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" )
+ get_filename_component( __libstlname "${__libstl}" NAME )
+ execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess )
+ if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}")
+  message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" )
+ endif()
+ unset( __fileCopyProcess )
+ unset( __libstlname )
+endif()
+
+
 # set these global flags for cmake client scripts to change behavior
 set( ANDROID True )
 set( BUILD_ANDROID True )
@@ -1740,7 +1752,7 @@ endif()
 #   BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used
 #   ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform
 #   ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86" or "mips" depending on ANDROID_ABI
-#   ANDROID_NDK_RELEASE : one of r5, r5b, r5c, r6, r6b, r7, r7b, r7c, r8, r8b, r8c, r8d, r8e, r9, r9b; set only for NDK
+#   ANDROID_NDK_RELEASE : one of r5, r5b, r5c, r6, r6b, r7, r7b, r7c, r8, r8b, r8c, r8d, r8e, r9, r9b, r9c, r9d, r10; set only for NDK
 #   ANDROID_ARCH_NAME : "arm" or "x86" or "mips" depending on ANDROID_ABI
 #   ANDROID_SYSROOT : path to the compiler sysroot
 #   TOOL_OS_SUFFIX : "" or ".exe" depending on host platform

+ 13 - 1
Source/CMakeLists.txt

@@ -145,17 +145,29 @@ if (NOT WIN32)
 endif ()
 
 # Add targets
-foreach (TARGET Box2D Bullet Civetweb Detour FreeType JO kNet LZ4 PugiXml Recast SDL StanHull STB)
+foreach (TARGET Box2D Civetweb FreeType JO kNet LZ4 PugiXml SDL StanHull STB)
     add_subdirectory (ThirdParty/${TARGET})
 endforeach ()
+
 if (URHO3D_ANGELSCRIPT)
     add_subdirectory (ThirdParty/AngelScript)
 endif ()
+
 if (URHO3D_LUA)
     add_subdirectory (Engine/LuaScript)
     add_subdirectory (ThirdParty/Lua${JIT})
     add_subdirectory (ThirdParty/toluapp/src/lib)
 endif ()
+
+if (URHO3D_NAVIGATION)
+    add_subdirectory (ThirdParty/Detour)
+    add_subdirectory (ThirdParty/Recast)
+endif ()
+
+if (URHO3D_PHYSICS)
+    add_subdirectory (ThirdParty/Bullet)
+endif ()
+
 if (NOT IOS AND NOT ANDROID AND NOT RASPI)
     if (URHO3D_OPENGL)
         add_subdirectory (ThirdParty/GLEW)

+ 1 - 1
Source/Engine/.soversion

@@ -1 +1 @@
-0.0.9
+0.0.13

+ 19 - 8
Source/Engine/CMakeLists.txt

@@ -62,10 +62,19 @@ if (MSVC AND URHO3D_LIB_TYPE STREQUAL SHARED)   # MSVC linker does not have forc
 endif ()
 
 # Define source files
-set (SOURCES Audio Container Core Engine Graphics Input IO Math Navigation Network Physics Resource Scene UI Urho2D)
+set (SOURCES Audio Container Core Engine Graphics Input IO Math Network Resource Scene UI Urho2D)
 if (URHO3D_ANGELSCRIPT)
     list (APPEND SOURCES Script)
 endif ()
+
+if (URHO3D_NAVIGATION)
+    list (APPEND SOURCES Navigation)
+endif ()
+
+if (URHO3D_PHYSICS)
+    list (APPEND SOURCES Physics)
+endif ()
+
 foreach (SOURCE ${SOURCES})
     add_subdirectory (${SOURCE})
     install (DIRECTORY ${SOURCE}/ DESTINATION ${DEST_INCLUDE_DIR} ${DEST_PERMISSIONS} FILES_MATCHING PATTERN *.h)    # Note: the trailing slash is significant
@@ -96,13 +105,15 @@ set_output_directories (${OUTPUT_PATH} ARCHIVE LIBRARY)
  
 # Setup target
 setup_library (${URHO3D_LIB_TYPE})
-file (READ .soversion SOVERSION)
-string (STRIP ${SOVERSION} SOVERSION)
-string (REGEX MATCH "([^.]+)\\.([^.]+)\\.(.+)" MATCHED ${SOVERSION})
-if (MATCHED)
-    set_target_properties (${TARGET_NAME} PROPERTIES VERSION ${MATCHED} SOVERSION ${CMAKE_MATCH_1})
-else ()
-    message (FATAL_ERROR "The .soversion file is corrupted. It should contain a version number with this format major(0xFFFF).minor(0xFF).patch-level(0xFF). e.g.: 0.1.2")
+if (NOT ANDROID)
+    file (READ .soversion SOVERSION)
+    string (STRIP ${SOVERSION} SOVERSION)
+    string (REGEX MATCH "([^.]+)\\.([^.]+)\\.(.+)" MATCHED ${SOVERSION})
+    if (MATCHED)
+        set_target_properties (${TARGET_NAME} PROPERTIES VERSION ${MATCHED} SOVERSION ${CMAKE_MATCH_1})
+    else ()
+        message (FATAL_ERROR "The .soversion file is corrupted. It should contain a version number with this format major(0xFFFF).minor(0xFF).patch-level(0xFF). e.g.: 0.1.2")
+    endif ()
 endif ()
 install (TARGETS ${TARGET_NAME} RUNTIME DESTINATION ${DEST_RUNTIME_DIR} LIBRARY DESTINATION ${DEST_LIBRARY_DIR} ARCHIVE DESTINATION ${DEST_LIBRARY_DIR})
 if (NOT GIT_EXIT_CODE EQUAL 0)

+ 10 - 0
Source/Engine/Engine/Engine.cpp

@@ -32,10 +32,14 @@
 #include "Input.h"
 #include "InputEvents.h"
 #include "Log.h"
+#ifdef URHO3D_NAVIGATION
 #include "NavigationMesh.h"
+#endif
 #include "Network.h"
 #include "PackageFile.h"
+#ifdef URHO3D_PHYSICS
 #include "PhysicsWorld.h"
+#endif
 #include "ProcessUtils.h"
 #include "Profiler.h"
 #include "Renderer.h"
@@ -115,8 +119,14 @@ Engine::Engine(Context* context) :
 
     // Register object factories for libraries which are not automatically registered along with subsystem creation
     RegisterSceneLibrary(context_);
+
+#ifdef URHO3D_PHYSICS
     RegisterPhysicsLibrary(context_);
+#endif
+    
+#ifdef URHO3D_NAVIGATION
     RegisterNavigationLibrary(context_);
+#endif
 
     SubscribeToEvent(E_EXITREQUESTED, HANDLER(Engine, HandleExitRequested));
 }

+ 11 - 6
Source/Engine/Graphics/AnimatedModel.cpp

@@ -77,6 +77,14 @@ AnimatedModel::AnimatedModel(Context* context) :
 
 AnimatedModel::~AnimatedModel()
 {
+    // When being destroyed, remove the bone hierarchy if appropriate (last AnimatedModel in the node)
+    Bone* rootBone = skeleton_.GetRootBone();
+    if (rootBone && rootBone->node_)
+    {
+        Node* parent = rootBone->node_->GetParent();
+        if (parent && !parent->GetComponent<AnimatedModel>())
+            RemoveRootBone();
+    }
 }
 
 void AnimatedModel::RegisterObject(Context* context)
@@ -858,12 +866,6 @@ void AnimatedModel::OnNodeSet(Node* node)
         // If this AnimatedModel is the first in the node, it is the master which controls animation & morphs
         isMaster_ = GetComponent<AnimatedModel>() == this;
     }
-    else
-    {
-        // When AnimatedModel parent node is cleared, we are being detached from the scene.
-        // Remove the bone hierarchy now
-        RemoveRootBone();
-    }
 }
 
 void AnimatedModel::OnMarkedDirty(Node* node)
@@ -887,6 +889,9 @@ void AnimatedModel::OnWorldBoundingBoxUpdate()
         // Non-master animated models get the bounding box from the master
         /// \todo If it's a skinned attachment that does not cover the whole body, it will have unnecessarily large bounds
         AnimatedModel* master = node_->GetComponent<AnimatedModel>();
+        // Check if we've become the new master model in case the original was deleted
+        if (master == this)
+            isMaster_ = true;
         if (master)
             worldBoundingBox_ = master->GetWorldBoundingBox();
     }

+ 124 - 0
Source/Engine/IO/Compression.cpp

@@ -0,0 +1,124 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// 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.
+//
+
+#include "Precompiled.h"
+#include "ArrayPtr.h"
+#include "Compression.h"
+#include "Deserializer.h"
+#include "Serializer.h"
+#include "VectorBuffer.h"
+
+#include <lz4.h>
+#include <lz4hc.h>
+
+namespace Urho3D
+{
+
+unsigned EstimateCompressBound(unsigned srcSize)
+{
+    return LZ4_compressBound(srcSize);
+}
+
+unsigned CompressData(void* dest, const void* src, unsigned srcSize)
+{
+    if (!dest || !src || !srcSize)
+        return 0;
+    else
+        return LZ4_compressHC((const char*)src, (char*)dest, srcSize);
+}
+
+unsigned DecompressData(void* dest, const void* src, unsigned destSize)
+{
+    if (!dest || !src || !destSize)
+        return 0;
+    else
+        return LZ4_decompress_fast((const char*)src, (char*)dest, destSize);
+}
+
+bool CompressStream(Serializer& dest, Deserializer& src)
+{
+    unsigned srcSize = src.GetSize() - src.GetPosition();
+    // Prepend the source and dest. data size in the stream so that we know to buffer & uncompress the right amount
+    if (!srcSize)
+    {
+        dest.WriteUInt(0);
+        dest.WriteUInt(0);
+        return true;
+    }
+    
+    unsigned maxDestSize = LZ4_compressBound(srcSize);
+    SharedArrayPtr<unsigned char> srcBuffer(new unsigned char[srcSize]);
+    SharedArrayPtr<unsigned char> destBuffer(new unsigned char[maxDestSize]);
+    
+    if (src.Read(srcBuffer, srcSize) != srcSize)
+        return false;
+    
+    unsigned destSize = LZ4_compressHC((const char*)srcBuffer.Get(), (char*)destBuffer.Get(), srcSize);
+    bool success = true;
+    success &= dest.WriteUInt(srcSize);
+    success &= dest.WriteUInt(destSize);
+    success &= dest.Write(destBuffer, destSize) == destSize;
+    return success;
+}
+
+bool DecompressStream(Serializer& dest, Deserializer& src)
+{
+    if (src.IsEof())
+        return false;
+    
+    unsigned destSize = src.ReadUInt();
+    unsigned srcSize = src.ReadUInt();
+    if (!srcSize || !destSize)
+        return true; // No data
+    
+    if (srcSize > src.GetSize())
+        return false; // Illegal source (packed data) size reported, possibly not valid data
+    
+    SharedArrayPtr<unsigned char> srcBuffer(new unsigned char[srcSize]);
+    SharedArrayPtr<unsigned char> destBuffer(new unsigned char[destSize]);
+    
+    if (src.Read(srcBuffer, srcSize) != srcSize)
+        return false;
+    
+    LZ4_decompress_fast((const char*)srcBuffer.Get(), (char*)destBuffer.Get(), destSize);
+    return dest.Write(destBuffer, destSize) == destSize;
+}
+
+VectorBuffer CompressVectorBuffer(VectorBuffer& src)
+{
+    VectorBuffer ret;
+    src.Seek(0);
+    CompressStream(ret, src);
+    ret.Seek(0);
+    return ret;
+}
+
+VectorBuffer DecompressVectorBuffer(VectorBuffer& src)
+{
+    VectorBuffer ret;
+    src.Seek(0);
+    DecompressStream(ret, src);
+    ret.Seek(0);
+    return ret;
+}
+
+}

+ 49 - 0
Source/Engine/IO/Compression.h

@@ -0,0 +1,49 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// 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.
+//
+
+#pragma once
+
+#include "Urho3D.h"
+
+namespace Urho3D
+{
+
+class Deserializer;
+class Serializer;
+class VectorBuffer;
+
+/// Estimate and return worst case LZ4 compressed output size in bytes for given input size.
+URHO3D_API unsigned EstimateCompressBound(unsigned srcSize);
+/// Compress data using the LZ4 algorithm and return the compressed data size. The needed destination buffer worst-case size is given by EstimateCompressBound().
+URHO3D_API unsigned CompressData(void* dest, const void* src, unsigned srcSize);
+/// Uncompress data using the LZ4 algorithm. The uncompressed data size must be known. Return the number of compressed data bytes consumed.
+URHO3D_API unsigned DecompressData(void* dest, const void* src, unsigned destSize);
+/// Compress a source stream (from current position to the end) to the destination stream using the LZ4 algorithm. Return true on success.
+URHO3D_API bool CompressStream(Serializer& dest, Deserializer& src);
+/// Decompress a compressed source stream produced using CompressStream() to the destination stream. Return true on success.
+URHO3D_API bool DecompressStream(Serializer& dest, Deserializer& src);
+/// Compress a VectorBuffer using the LZ4 algorithm and return the compressed result buffer.
+URHO3D_API VectorBuffer CompressVectorBuffer(VectorBuffer& src);
+/// Decompress a VectorBuffer produced using CompressVectorBuffer().
+URHO3D_API VectorBuffer DecompressVectorBuffer(VectorBuffer& src);
+
+}

+ 21 - 6
Source/Engine/IO/FileWatcher.cpp

@@ -49,6 +49,7 @@ static const unsigned BUFFERSIZE = 4096;
 FileWatcher::FileWatcher(Context* context) :
     Object(context),
     fileSystem_(GetSubsystem<FileSystem>()),
+    delay_(1.0f),
     watchSubDirs_(false)
 {
 #if defined(URHO3D_FILEWATCHER)
@@ -214,6 +215,11 @@ void FileWatcher::StopWatching()
     }
 }
 
+void FileWatcher::SetDelay(float interval)
+{
+    delay_ = Max(interval, 0.0f);
+}
+
 void FileWatcher::ThreadFunction()
 {
 #if defined(URHO3D_FILEWATCHER)
@@ -307,22 +313,31 @@ void FileWatcher::AddChange(const String& fileName)
 {
     MutexLock lock(changesMutex_);
     
-    // If we have 2 unprocessed modifies in a row into the same file, only record the first
-    if (changes_.Empty() || changes_.Back() != fileName)
-        changes_.Push(fileName);
+    // Reset the timer associated with the filename. Will be notified once timer exceeds the delay
+    changes_[fileName].Reset();
 }
 
 bool FileWatcher::GetNextChange(String& dest)
 {
     MutexLock lock(changesMutex_);
     
+    unsigned delayMsec = (unsigned)(delay_ * 1000.0f);
+    
     if (changes_.Empty())
         return false;
     else
     {
-        dest = changes_.Front();
-        changes_.Erase(changes_.Begin());
-        return true;
+        for (HashMap<String, Timer>::Iterator i = changes_.Begin(); i != changes_.End(); ++i)
+        {
+            if (i->second_.GetMSec(false) >= delayMsec)
+            {
+                dest = i->first_;
+                changes_.Erase(i);
+                return true;
+            }
+        }
+        
+        return false;
     }
 }
 

+ 9 - 2
Source/Engine/IO/FileWatcher.h

@@ -26,6 +26,7 @@
 #include "Mutex.h"
 #include "Object.h"
 #include "Thread.h"
+#include "Timer.h"
 
 namespace Urho3D
 {
@@ -50,6 +51,8 @@ public:
     bool StartWatching(const String& pathName, bool watchSubDirs);
     /// Stop watching the directory.
     void StopWatching();
+    /// Set the delay in seconds before file changes are notified. This (hopefully) avoids notifying when a file save is still in progress. Default 1 second.
+    void SetDelay(float interval);
     /// Add a file change into the changes queue.
     void AddChange(const String& fileName);
     /// Return a file change (true if was found, false if not.)
@@ -57,16 +60,20 @@ public:
     
     /// Return the path being watched, or empty if not watching.
     const String& GetPath() const { return path_; }
+    /// Return the delay in seconds for notifying file changes.
+    float GetDelay() const { return delay_;}
     
 private:
     /// Filesystem.
     SharedPtr<FileSystem> fileSystem_;
     /// The path being watched.
     String path_;
-    /// Buffered file changes.
-    List<String> changes_;
+    /// Pending changes. These will be returned and removed from the list when their timer has exceeded the delay.
+    HashMap<String, Timer> changes_;
     /// Mutex for the change buffer.
     Mutex changesMutex_;
+    /// Delay in seconds for notifying changes.
+    float delay_;
     /// Watch subdirectories flag.
     bool watchSubDirs_;
 

+ 21 - 2
Source/Engine/LuaScript/CMakeLists.txt

@@ -42,6 +42,17 @@ endif ()
 # Define generated source files
 file (MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/generated)
 file (GLOB API_PKG_FILES ${CMAKE_CURRENT_SOURCE_DIR}/pkgs/*.pkg)
+
+# Remove NavigationLuaAPI.pkg
+if (NOT URHO3D_NAVIGATION)
+    list (REMOVE_ITEM API_PKG_FILES ${CMAKE_CURRENT_SOURCE_DIR}/pkgs/NavigationLuaAPI.pkg)
+endif ()
+
+# Remove PhysicsLuaAPI.pkg
+if (NOT URHO3D_PHYSICS)
+    list (REMOVE_ITEM API_PKG_FILES ${CMAKE_CURRENT_SOURCE_DIR}/pkgs/PhysicsLuaAPI.pkg)
+endif ()
+
 foreach (API_PKG_FILE ${API_PKG_FILES})
     get_filename_component (NAME ${API_PKG_FILE} NAME)
     string (REGEX REPLACE LuaAPI\\.pkg$ "" API ${NAME})
@@ -62,8 +73,16 @@ install (FILES ${H_FILES} DESTINATION ${DEST_INCLUDE_DIR})
 # Define dependency libs
 set (LIBS ../../ThirdParty/Lua${JIT}/src)
 set (LINK_LIBS_ONLY toluapp)
-set (INCLUDE_DIRS_ONLY . .. ../Audio ../Container ../Core ../Engine ../Graphics ../Input ../IO ../Math ../Navigation ../Network ../Physics ../Resource ../Scene ../UI  ../Urho2D
-    ../../ThirdParty/Box2D ../../ThirdParty/Bullet/src ../../ThirdParty/kNet/include ../../ThirdParty/SDL/include ../../ThirdParty/toluapp/include ${CMAKE_BINARY_DIR}/Engine)
+set (INCLUDE_DIRS_ONLY . .. ../Audio ../Container ../Core ../Engine ../Graphics ../Input ../IO ../Math ../Navigation ../Network ../Resource ../Scene ../UI  ../Urho2D
+    ../../ThirdParty/Box2D ../../ThirdParty/kNet/include ../../ThirdParty/SDL/include ../../ThirdParty/toluapp/include ${CMAKE_BINARY_DIR}/Engine)
+
+if (URHO3D_NAVIGATION)
+    set (INCLUDE_DIRS_ONLY ${INCLUDE_DIRS_ONLY} ../Navigation)
+endif ()
+
+if (URHO3D_PHYSICS)
+    set (INCLUDE_DIRS_ONLY ${INCLUDE_DIRS_ONLY} ../Physics ../../ThirdParty/Bullet/src)
+endif ()
 
 # Setup target
 setup_library ()

+ 12 - 0
Source/Engine/LuaScript/LuaScript.cpp

@@ -52,9 +52,13 @@ extern int tolua_GraphicsLuaAPI_open(lua_State*);
 extern int tolua_InputLuaAPI_open(lua_State*);
 extern int tolua_IOLuaAPI_open(lua_State*);
 extern int tolua_MathLuaAPI_open(lua_State*);
+#ifdef URHO3D_NAVIGATION
 extern int tolua_NavigationLuaAPI_open(lua_State*);
+#endif
 extern int tolua_NetworkLuaAPI_open(lua_State*);
+#ifdef URHO3D_PHYSICS
 extern int tolua_PhysicsLuaAPI_open(lua_State*);
+#endif
 extern int tolua_ResourceLuaAPI_open(lua_State*);
 extern int tolua_SceneLuaAPI_open(lua_State*);
 extern int tolua_UILuaAPI_open(lua_State*);
@@ -95,9 +99,17 @@ LuaScript::LuaScript(Context* context) :
     tolua_EngineLuaAPI_open(luaState_);
     tolua_GraphicsLuaAPI_open(luaState_);
     tolua_InputLuaAPI_open(luaState_);
+
+#ifdef URHO3D_NAVIGATION
     tolua_NavigationLuaAPI_open(luaState_);
+#endif
+
     tolua_NetworkLuaAPI_open(luaState_);
+
+#ifdef URHO3D_PHYSICS
     tolua_PhysicsLuaAPI_open(luaState_);
+#endif
+
     tolua_UILuaAPI_open(luaState_);
     tolua_Urho2DLuaAPI_open(luaState_);
     tolua_LuaScriptLuaAPI_open(luaState_);

+ 12 - 3
Source/Engine/LuaScript/LuaScriptInstance.cpp

@@ -29,8 +29,10 @@
 #include "LuaScript.h"
 #include "LuaScriptInstance.h"
 #include "MemoryBuffer.h"
+#ifdef URHO3D_PHYSICS
 #include "PhysicsEvents.h"
 #include "PhysicsWorld.h"
+#endif
 #include "ResourceCache.h"
 #include "Scene.h"
 #include "SceneEvents.h"
@@ -594,7 +596,6 @@ void LuaScriptInstance::FindScriptObjectMethodRefs()
 void LuaScriptInstance::SubscribeToScriptMethodEvents()
 {
     Scene* scene = GetScene();
-    PhysicsWorld* physicsWorld = scene ? scene->GetComponent<PhysicsWorld>() : 0;
 
     if (scene && scriptObjectMethods_[LSOM_UPDATE])
         SubscribeToEvent(scene, E_SCENEUPDATE, HANDLER(LuaScriptInstance, HandleUpdate));
@@ -602,11 +603,15 @@ void LuaScriptInstance::SubscribeToScriptMethodEvents()
     if (scene && scriptObjectMethods_[LSOM_POSTUPDATE])
         SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(LuaScriptInstance, HandlePostUpdate));
 
+#ifdef URHO3D_PHYSICS
+    PhysicsWorld* physicsWorld = scene ? scene->GetComponent<PhysicsWorld>() : 0;
+
     if (physicsWorld && scriptObjectMethods_[LSOM_FIXEDUPDATE])
         SubscribeToEvent(physicsWorld, E_PHYSICSPRESTEP, HANDLER(LuaScriptInstance, HandleFixedUpdate));
 
     if (physicsWorld && scriptObjectMethods_[LSOM_FIXEDPOSTUPDATE])
         SubscribeToEvent(physicsWorld, E_PHYSICSPOSTSTEP, HANDLER(LuaScriptInstance, HandlePostFixedUpdate));
+#endif
 
     if (node_ && scriptObjectMethods_[LSOM_TRANSFORMCHANGED])
         node_->AddListener(this);
@@ -615,19 +620,21 @@ void LuaScriptInstance::SubscribeToScriptMethodEvents()
 void LuaScriptInstance::UnsubscribeFromScriptMethodEvents()
 {
     Scene* scene = GetScene();
-    PhysicsWorld* physicsWorld = scene ? scene->GetComponent<PhysicsWorld>() : 0;
-
     if (scene && scriptObjectMethods_[LSOM_UPDATE])
         UnsubscribeFromEvent(scene, E_SCENEUPDATE);
 
     if (scene && scriptObjectMethods_[LSOM_POSTUPDATE])
         UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
 
+#ifdef URHO3D_PHYSICS
+    PhysicsWorld* physicsWorld = scene ? scene->GetComponent<PhysicsWorld>() : 0;
+
     if (physicsWorld && scriptObjectMethods_[LSOM_FIXEDUPDATE])
         UnsubscribeFromEvent(physicsWorld, E_PHYSICSPRESTEP);
 
     if (physicsWorld && scriptObjectMethods_[LSOM_FIXEDPOSTUPDATE])
         UnsubscribeFromEvent(physicsWorld, E_PHYSICSPOSTSTEP);
+#endif
 
     if (node_ && scriptObjectMethods_[LSOM_TRANSFORMCHANGED])
         node_->RemoveListener(this);
@@ -659,6 +666,7 @@ void LuaScriptInstance::HandlePostUpdate(StringHash eventType, VariantMap& event
     }
 }
 
+#ifdef URHO3D_PHYSICS
 void LuaScriptInstance::HandleFixedUpdate(StringHash eventType, VariantMap& eventData)
 {
     using namespace PhysicsPreStep;
@@ -684,6 +692,7 @@ void LuaScriptInstance::HandlePostFixedUpdate(StringHash eventType, VariantMap&
         function->EndCall();
     }
 }
+#endif
 
 void LuaScriptInstance::HandleEvent(StringHash eventType, VariantMap& eventData)
 {

+ 2 - 0
Source/Engine/LuaScript/LuaScriptInstance.h

@@ -135,10 +135,12 @@ private:
     void HandleUpdate(StringHash eventType, VariantMap& eventData);
     /// Handle the logic post update event.
     void HandlePostUpdate(StringHash eventType, VariantMap& eventData);
+#ifdef URHO3D_PHYSICS
     /// Handle the physics update event.
     void HandleFixedUpdate(StringHash eventType, VariantMap& eventData);
     /// Handle the physics post update event.
     void HandlePostFixedUpdate(StringHash eventType, VariantMap& eventData);
+#endif
     /// Handle event.
     void HandleEvent(StringHash eventType, VariantMap& eventData);
     /// Handle a specific sender's event.

+ 4 - 0
Source/Engine/LuaScript/ToluaUtils.cpp

@@ -302,6 +302,7 @@ template<> int ToluaPushPODVector<UIElement*>(lua_State* L, void* data, const ch
     return 1;
 }
 
+#ifdef URHO3D_PHYSICS
 template<> int ToluaPushPODVector<RigidBody*>(lua_State* L, void* data, const char*)
 {
     const PODVector<RigidBody*>& vector = *((const PODVector<RigidBody*>*)data);
@@ -313,6 +314,7 @@ template<> int ToluaPushPODVector<RigidBody*>(lua_State* L, void* data, const ch
     }
     return 1;
 }
+#endif
 
 template<> int ToluaPushPODVector<RigidBody2D*>(lua_State* L, void* data, const char*)
 {
@@ -356,10 +358,12 @@ template<> int ToluaPushPODVector<OctreeQueryResult>(lua_State* L, void* data, c
     return tolua_pushurho3dpodvectorusertype(L, *((const PODVector<OctreeQueryResult>*)data), "OctreeQueryResult");
 }
 
+#ifdef URHO3D_PHYSICS
 template<> int ToluaPushPODVector<PhysicsRaycastResult>(lua_State* L, void* data, const char*)
 {
     return tolua_pushurho3dpodvectorusertype(L, *((const PODVector<PhysicsRaycastResult>*)data), "PhysicsRaycastResult");
 }
+#endif
 
 template<> int ToluaPushPODVector<PhysicsRaycastResult2D>(lua_State* L, void* data, const char*)
 {

+ 6 - 0
Source/Engine/LuaScript/ToluaUtils.h

@@ -24,7 +24,9 @@
 
 #include "Context.h"
 #include "OctreeQuery.h"
+#ifdef URHO3D_PHYSICS
 #include "PhysicsWorld.h"
+#endif
 #include "PhysicsWorld2D.h"
 #include "Vector2.h"
 #include "Vector3.h"
@@ -117,8 +119,10 @@ template<> int ToluaPushPODVector<unsigned>(lua_State* L, void* data, const char
 template<> int ToluaPushPODVector<SoundSource*>(lua_State* L, void* data, const char* type);
 /// Push PODVector<UIElement*> to Lua as a table.
 template<> int ToluaPushPODVector<UIElement*>(lua_State* L, void* data, const char* type);
+#ifdef URHO3D_PHYSICS
 /// Push PODVector<RigidBody*> to Lua as a table.
 template<> int ToluaPushPODVector<RigidBody*>(lua_State* L, void* data, const char* type);
+#endif
 /// Push PODVector<RigidBody2D*> to Lua as a table.
 template<> int ToluaPushPODVector<RigidBody2D*>(lua_State* L, void* data, const char* type);
 /// Push PODVector<Vector3> to Lua as a table.
@@ -127,8 +131,10 @@ template<> int ToluaPushPODVector<Vector3>(lua_State* L, void* data, const char*
 template<> int ToluaPushPODVector<IntVector2>(lua_State* L, void* data, const char* type);
 /// Push PODVector<OctreeQueryResult> to Lua as a table.
 template<> int ToluaPushPODVector<OctreeQueryResult>(lua_State* L, void* data, const char* type);
+#ifdef URHO3D_PHYSICS
 /// Push PODVector<PhysicsRaycastResult> to Lua as a table.
 template<> int ToluaPushPODVector<PhysicsRaycastResult>(lua_State* L, void* data, const char* type);
+#endif
 /// Push PODVector<PhysicsRaycastResult2D> to Lua as a table.
 template<> int ToluaPushPODVector<PhysicsRaycastResult2D>(lua_State* L, void* data, const char* type);
 /// Push PODVector<RayQueryResult> to Lua as a table.

+ 1 - 0
Source/Engine/LuaScript/pkgs/Core/Variant.pkg

@@ -1,4 +1,5 @@
 $#include "Variant.h"
+$#include "VectorBuffer.h"
 
 enum VariantType
 {

+ 4 - 0
Source/Engine/LuaScript/pkgs/IO/Compression.pkg

@@ -0,0 +1,4 @@
+$#include "Compression.h"
+
+VectorBuffer CompressVectorBuffer(VectorBuffer& src);
+VectorBuffer DecompressVectorBuffer(VectorBuffer& src);

+ 0 - 9
Source/Engine/LuaScript/pkgs/IO/FileWatcher.pkg

@@ -1,9 +0,0 @@
-$#include "FileWatcher.h"
-
-class FileWatcher : public Object
-{
-    bool StartWatching(const String pathName, bool watchSubDirs);
-    void StopWatching();
-    void AddChange(const String fileName);
-    const String GetPath() const;
-};

+ 1 - 1
Source/Engine/LuaScript/pkgs/IOLuaAPI.pkg

@@ -1,7 +1,7 @@
+$pfile "IO/Compression.pkg"
 $pfile "IO/Deserializer.pkg"
 $pfile "IO/File.pkg"
 $pfile "IO/FileSystem.pkg"
-$pfile "IO/FileWatcher.pkg"
 $pfile "IO/Log.pkg"
 $pfile "IO/PackageFile.pkg"
 $pfile "IO/Serializer.pkg"

+ 4 - 4
Source/Engine/LuaScript/pkgs/Urho2D/TileMap2D.pkg

@@ -7,8 +7,8 @@ class TileMap2D : Component
     const TileMapInfo2D& GetInfo() const;
     unsigned GetNumLayers() const;
     TileMapLayer2D* GetLayer(unsigned index) const;
-    Vector2 IndexToPosition(int x, int y) const;
-    tolua_outside bool TileMap2DPositionToIndex @ PositionToIndex(const Vector2& position, int* x = 0, int* y = 0) const;
+    Vector2 TileIndexToPosition(int x, int y) const;
+    tolua_outside bool TileMap2DPositionToTileIndex @ PositionToTileIndex(const Vector2& position, int* x = 0, int* y = 0) const;
 
     tolua_property__get_set TmxFile2D* tmxFile;
     tolua_readonly tolua_property__get_set TileMapInfo2D& info;
@@ -16,8 +16,8 @@ class TileMap2D : Component
 };
 
 ${
-static bool TileMap2DPositionToIndex(const TileMap2D* tileMap, const Vector2& position, int* x, int* y)
+static bool TileMap2DPositionToTileIndex(const TileMap2D* tileMap, const Vector2& position, int* x, int* y)
 {
-    return tileMap->PositionToIndex(*x, *y, position);
+    return tileMap->PositionToTileIndex(*x, *y, position);
 }
 $}

+ 6 - 5
Source/Engine/LuaScript/pkgs/Urho2D/TileMapDefs2D.pkg

@@ -3,7 +3,8 @@ $#include "TileMapDefs2D.h"
 enum Orientation2D
 {
     O_ORTHOGONAL,
-    O_ISOMETRIC
+    O_ISOMETRIC,
+    O_STAGGERED
 };
 
 struct TileMapInfo2D
@@ -29,7 +30,7 @@ enum TileMapLayerType2D
     LT_INVALID
 };
 
-enum TileObjectType2D
+enum TileMapObjectType2D
 {
     OT_RECTANGLE,
     OT_ELLIPSE,
@@ -56,9 +57,9 @@ class Tile2D
     tolua_readonly tolua_property__get_set Sprite2D* sprite;
 };
 
-class TileObject2D
+class TileMapObject2D
 {
-    TileObjectType2D GetObjectType() const;
+    TileMapObjectType2D GetObjectType() const;
     const String GetName() const;
     const String GetType() const;
     const Vector2& GetPosition() const;
@@ -70,7 +71,7 @@ class TileObject2D
     bool HasProperty(const String& name) const;
     const String& GetProperty(const String& name) const;
 
-    tolua_readonly tolua_property__get_set TileObjectType2D objectType;
+    tolua_readonly tolua_property__get_set TileMapObjectType2D objectType;
     tolua_readonly tolua_property__get_set String name;
     tolua_readonly tolua_property__get_set String type;
     tolua_readonly tolua_property__get_set Vector2 position;

+ 1 - 1
Source/Engine/LuaScript/pkgs/Urho2D/TileMapLayer2D.pkg

@@ -17,7 +17,7 @@ class TileMapLayer2D : Component
     Tile2D* GetTile(int x, int y) const;
     
     unsigned GetNumObjects() const;
-    TileObject2D* GetObject(unsigned index) const;
+    TileMapObject2D* GetObject(unsigned index) const;
     Node* GetObjectNode(unsigned index) const;
 
     Node* GetImageNode() const;

+ 10 - 5
Source/Engine/Math/Ray.cpp

@@ -229,11 +229,16 @@ float Ray::HitDistance(const Vector3& v0, const Vector3& v1, const Vector3& v2,
             float v = direction_.DotProduct(q);
             if (v >= 0.0f && u + v <= det)
             {
-                // There is an intersection, so calculate distance & optional normal
-                if (outNormal)
-                    *outNormal = edge1.CrossProduct(edge2);
-                
-                return edge2.DotProduct(q) / det;
+                float distance = edge2.DotProduct(q) / det;
+                // Discard hits behind the ray
+                if (distance >= 0.0f)
+                {
+                    // There is an intersection, so calculate distance & optional normal
+                    if (outNormal)
+                        *outNormal = edge1.CrossProduct(edge2);
+                    
+                    return distance;
+                }
             }
         }
     }

+ 8 - 3
Source/Engine/Navigation/NavigationMesh.cpp

@@ -21,7 +21,9 @@
 //
 
 #include "Precompiled.h"
+#ifdef URHO3D_PHYSICS
 #include "CollisionShape.h"
+#endif
 #include "Context.h"
 #include "DebugRenderer.h"
 #include "Drawable.h"
@@ -799,6 +801,7 @@ void NavigationMesh::CollectGeometries(Vector<NavigationGeometryInfo>& geometryL
     
     Matrix3x4 inverse = node_->GetWorldTransform().Inverse();
     
+#ifdef URHO3D_PHYSICS
     // Prefer compatible physics collision shapes (triangle mesh, convex hull, box) if found.
     // Then fallback to visible geometry
     PODVector<CollisionShape*> collisionShapes;
@@ -825,8 +828,8 @@ void NavigationMesh::CollectGeometries(Vector<NavigationGeometryInfo>& geometryL
             collisionShapeFound = true;
         }
     }
-    
     if (!collisionShapeFound)
+#endif
     {
         PODVector<Drawable*> drawables;
         node->GetDerivedComponents<Drawable>(drawables);
@@ -884,11 +887,13 @@ void NavigationMesh::GetTileGeometry(NavigationBuildData& build, Vector<Navigati
                 build.offMeshRadii_.Push(connection->GetRadius());
                 /// \todo Allow to define custom flags
                 build.offMeshFlags_.Push(0x1);
+
                 build.offMeshAreas_.Push(0);
                 build.offMeshDir_.Push(connection->IsBidirectional() ? DT_OFFMESH_CON_BIDIR : 0);
                 continue;
             }
-            
+
+#ifdef URHO3D_PHYSICS
             CollisionShape* shape = dynamic_cast<CollisionShape*>(geometryList[i].component_);
             if (shape)
             {
@@ -953,7 +958,7 @@ void NavigationMesh::GetTileGeometry(NavigationBuildData& build, Vector<Navigati
                 
                 continue;
             }
-            
+#endif
             Drawable* drawable = dynamic_cast<Drawable*>(geometryList[i].component_);
             if (drawable)
             {

+ 7 - 1
Source/Engine/Scene/LogicComponent.cpp

@@ -23,8 +23,10 @@
 #include "Precompiled.h"
 #include "Log.h"
 #include "LogicComponent.h"
+#ifdef URHO3D_PHYSICS
 #include "PhysicsEvents.h"
 #include "PhysicsWorld.h"
+#endif
 #include "Scene.h"
 #include "SceneEvents.h"
 
@@ -111,7 +113,8 @@ void LogicComponent::UpdateEventSubscription()
         UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
         currentEventMask_ &= ~USE_POSTUPDATE;
     }
-    
+
+#ifdef URHO3D_PHYSICS
     PhysicsWorld* world = scene->GetComponent<PhysicsWorld>();
     if (!world)
         return;
@@ -139,6 +142,7 @@ void LogicComponent::UpdateEventSubscription()
         UnsubscribeFromEvent(world, E_PHYSICSPOSTSTEP);
         currentEventMask_ &= ~USE_FIXEDPOSTUPDATE;
     }
+#endif 
 }
 
 void LogicComponent::HandleSceneUpdate(StringHash eventType, VariantMap& eventData)
@@ -172,6 +176,7 @@ void LogicComponent::HandleScenePostUpdate(StringHash eventType, VariantMap& eve
     PostUpdate(eventData[P_TIMESTEP].GetFloat());
 }
 
+#ifdef URHO3D_PHYSICS
 void LogicComponent::HandlePhysicsPreStep(StringHash eventType, VariantMap& eventData)
 {
     using namespace PhysicsPreStep;
@@ -187,5 +192,6 @@ void LogicComponent::HandlePhysicsPostStep(StringHash eventType, VariantMap& eve
     // Execute user-defined fixed post-update function
     FixedPostUpdate(eventData[P_TIMESTEP].GetFloat());
 }
+#endif
 
 }

+ 2 - 1
Source/Engine/Scene/LogicComponent.h

@@ -82,11 +82,12 @@ private:
     void HandleSceneUpdate(StringHash eventType, VariantMap& eventData);
     /// Handle scene post-update event.
     void HandleScenePostUpdate(StringHash eventType, VariantMap& eventData);
+#ifdef URHO3D_PHYSICS
     /// Handle physics pre-step event.
     void HandlePhysicsPreStep(StringHash eventType, VariantMap& eventData);
     /// Handle physics post-step event.
     void HandlePhysicsPostStep(StringHash eventType, VariantMap& eventData);
-    
+#endif
     /// Requested event subscription mask.
     unsigned char updateEventMask_;
     /// Current event subscription mask.

+ 5 - 2
Source/Engine/Script/CMakeLists.txt

@@ -24,5 +24,8 @@
 define_source_files (PARENT_SCOPE)
 
 # Define dependency libs
-set (ENGINE_INCLUDE_DIRS_ONLY ${ENGINE_INCLUDE_DIRS_ONLY} ../ThirdParty/AngelScript/include ../ThirdParty/Bullet/src ../ThirdParty/kNet/include PARENT_SCOPE)
-
+if (URHO3D_PHYSICS)
+    set (ENGINE_INCLUDE_DIRS_ONLY ${ENGINE_INCLUDE_DIRS_ONLY} ../ThirdParty/AngelScript/include ../ThirdParty/Bullet/src ../ThirdParty/kNet/include PARENT_SCOPE)
+else ()
+    set (ENGINE_INCLUDE_DIRS_ONLY ${ENGINE_INCLUDE_DIRS_ONLY} ../ThirdParty/AngelScript/include ../ThirdParty/kNet/include PARENT_SCOPE)
+endif ()

+ 5 - 0
Source/Engine/Script/IOAPI.cpp

@@ -22,6 +22,7 @@
 
 #include "Precompiled.h"
 #include "APITemplates.h"
+#include "Compression.h"
 #include "FileSystem.h"
 #include "Log.h"
 #include "PackageFile.h"
@@ -321,6 +322,10 @@ static void RegisterSerialization(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Variant", "Variant& opAssign(const VectorBuffer&in)", asFUNCTION(VariantAssignBuffer), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Variant", "VectorBuffer GetBuffer() const", asFUNCTION(VariantGetBuffer), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Variant", "bool opEquals(const VectorBuffer&in) const", asFUNCTION(VariantEqualsBuffer), asCALL_CDECL_OBJLAST);
+    
+    // Register VectorBuffer compression functions
+    engine->RegisterGlobalFunction("VectorBuffer CompressVectorBuffer(VectorBuffer&in)", asFUNCTION(CompressVectorBuffer), asCALL_CDECL);
+    engine->RegisterGlobalFunction("VectorBuffer DecompressVectorBuffer(VectorBuffer&in)", asFUNCTION(DecompressVectorBuffer), asCALL_CDECL);
 }
 
 void RegisterFileSystem(asIScriptEngine* engine)

+ 2 - 0
Source/Engine/Script/NavigationAPI.cpp

@@ -21,6 +21,7 @@
 //
 
 #include "Precompiled.h"
+#ifdef URHO3D_NAVIGATION
 #include "APITemplates.h"
 #include "Navigable.h"
 #include "NavigationMesh.h"
@@ -109,3 +110,4 @@ void RegisterNavigationAPI(asIScriptEngine* engine)
 }
 
 }
+#endif

+ 2 - 0
Source/Engine/Script/PhysicsAPI.cpp

@@ -21,6 +21,7 @@
 //
 
 #include "Precompiled.h"
+#ifdef URHO3D_PHYSICS
 #include "APITemplates.h"
 #include "CollisionShape.h"
 #include "Constraint.h"
@@ -325,3 +326,4 @@ void RegisterPhysicsAPI(asIScriptEngine* engine)
 }
 
 }
+#endif

+ 4 - 0
Source/Engine/Script/Script.cpp

@@ -82,8 +82,12 @@ Script::Script(Context* context) :
     RegisterAudioAPI(scriptEngine_);
     RegisterUIAPI(scriptEngine_);
     RegisterNetworkAPI(scriptEngine_);
+#ifdef URHO3D_PHYSICS
     RegisterPhysicsAPI(scriptEngine_);
+#endif
+#ifdef URHO3D_NAVIGATION
     RegisterNavigationAPI(scriptEngine_);
+#endif
     RegisterUrho2DAPI(scriptEngine_);
     RegisterScriptAPI(scriptEngine_);
     RegisterEngineAPI(scriptEngine_);

+ 4 - 0
Source/Engine/Script/ScriptAPI.h

@@ -49,10 +49,14 @@ void RegisterAudioAPI(asIScriptEngine* engine);
 void RegisterUIAPI(asIScriptEngine* engine);
 /// Register the Network library to script.
 void RegisterNetworkAPI(asIScriptEngine* engine);
+#ifdef URHO3D_PHYSICS
 /// Register the Physics library to script.
 void RegisterPhysicsAPI(asIScriptEngine* engine);
+#endif
+#ifdef URHO3D_NAVIGATION
 /// Register the Navigation library to script.
 void RegisterNavigationAPI(asIScriptEngine* engine);
+#endif
 /// Register the Urho2D library to script.
 void RegisterUrho2DAPI(asIScriptEngine* engine);
 /// Register the Script library to script.

+ 8 - 3
Source/Engine/Script/ScriptInstance.cpp

@@ -24,8 +24,10 @@
 #include "Context.h"
 #include "Log.h"
 #include "MemoryBuffer.h"
+#ifdef URHO3D_PHYSICS
 #include "PhysicsEvents.h"
 #include "PhysicsWorld.h"
+#endif
 #include "Profiler.h"
 #include "ResourceCache.h"
 #include "ResourceEvents.h"
@@ -634,6 +636,7 @@ void ScriptInstance::UpdateEventSubscription()
             if (methods_[METHOD_POSTUPDATE])
                 SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(ScriptInstance, HandleScenePostUpdate));
 
+#ifdef URHO3D_PHYSICS
             if (methods_[METHOD_FIXEDUPDATE] || methods_[METHOD_FIXEDPOSTUPDATE])
             {
                 PhysicsWorld* world = scene->GetOrCreateComponent<PhysicsWorld>();
@@ -647,7 +650,7 @@ void ScriptInstance::UpdateEventSubscription()
                 else
                     LOGERROR("No physics world, can not subscribe script object to fixed update events");
             }
-
+#endif
             subscribedPostFixed_ = true;
         }
 
@@ -665,13 +668,14 @@ void ScriptInstance::UpdateEventSubscription()
         if (subscribedPostFixed_)
         {
             UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
-
+#ifdef URHO3D_PHYSICS
             PhysicsWorld* world = scene->GetComponent<PhysicsWorld>();
             if (world)
             {
                 UnsubscribeFromEvent(world, E_PHYSICSPRESTEP);
                 UnsubscribeFromEvent(world, E_PHYSICSPOSTSTEP);
             }
+#endif
 
             subscribedPostFixed_ = false;
         }
@@ -740,6 +744,7 @@ void ScriptInstance::HandleScenePostUpdate(StringHash eventType, VariantMap& eve
     scriptFile_->Execute(scriptObject_, methods_[METHOD_POSTUPDATE], parameters);
 }
 
+#ifdef URHO3D_PHYSICS
 void ScriptInstance::HandlePhysicsPreStep(StringHash eventType, VariantMap& eventData)
 {
     if (!scriptObject_)
@@ -763,7 +768,7 @@ void ScriptInstance::HandlePhysicsPostStep(StringHash eventType, VariantMap& eve
     parameters.Push(eventData[P_TIMESTEP]);
     scriptFile_->Execute(scriptObject_, methods_[METHOD_FIXEDPOSTUPDATE], parameters);
 }
-
+#endif
 void ScriptInstance::HandleScriptEvent(StringHash eventType, VariantMap& eventData)
 {
     if (!IsEnabledEffective() || !scriptFile_ || !scriptObject_)

+ 2 - 0
Source/Engine/Script/ScriptInstance.h

@@ -158,10 +158,12 @@ private:
     void HandleSceneUpdate(StringHash eventType, VariantMap& eventData);
     /// Handle scene post-update event.
     void HandleScenePostUpdate(StringHash eventType, VariantMap& eventData);
+#ifdef URHO3D_PHYSICS
     /// Handle physics pre-step event.
     void HandlePhysicsPreStep(StringHash eventType, VariantMap& eventData);
     /// Handle physics post-step event.
     void HandlePhysicsPostStep(StringHash eventType, VariantMap& eventData);
+#endif
     /// Handle an event in script.
     void HandleScriptEvent(StringHash eventType, VariantMap& eventData);
     /// Handle script file reload start.

+ 16 - 15
Source/Engine/Script/Urho2DAPI.cpp

@@ -206,6 +206,7 @@ static void RegisterTileMapDefs2D(asIScriptEngine* engine)
     engine->RegisterEnum("Orientation2D");
     engine->RegisterEnumValue("Orientation2D", "O_ORTHOGONAL", O_ORTHOGONAL);
     engine->RegisterEnumValue("Orientation2D", "O_ISOMETRIC", O_ISOMETRIC);
+    engine->RegisterEnumValue("Orientation2D", "O_STAGGERED", O_STAGGERED);
 
     engine->RegisterObjectType("TileMapInfo2D", 0, asOBJ_REF);
     engine->RegisterObjectBehaviour("TileMapInfo2D", asBEHAVE_ADDREF, "void f()", asFUNCTION(FakeAddRef), asCALL_CDECL_OBJLAST);
@@ -242,18 +243,18 @@ static void RegisterTileMapDefs2D(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Tile2D", "bool HasProperty(const String&in) const", asMETHOD(Tile2D, HasProperty), asCALL_THISCALL);
     engine->RegisterObjectMethod("Tile2D", "const String& GetProperty(const String&in) const", asMETHOD(Tile2D, HasProperty), asCALL_THISCALL);
 
-    RegisterRefCounted<TileObject2D>(engine, "TileObject2D");
-    engine->RegisterObjectMethod("TileObject2D", "TileObjectType2D get_objectType() const", asMETHOD(TileObject2D, GetObjectType), asCALL_THISCALL);
-    engine->RegisterObjectMethod("TileObject2D", "const String& get_name() const", asMETHOD(TileObject2D, GetName), asCALL_THISCALL);
-    engine->RegisterObjectMethod("TileObject2D", "const String& get_type() const", asMETHOD(TileObject2D, GetType), asCALL_THISCALL);
-    engine->RegisterObjectMethod("TileObject2D", "const Vector2& get_position() const", asMETHOD(TileObject2D, GetPosition), asCALL_THISCALL);
-    engine->RegisterObjectMethod("TileObject2D", "const Vector2& get_size() const", asMETHOD(TileObject2D, GetSize), asCALL_THISCALL);
-    engine->RegisterObjectMethod("TileObject2D", "uint get_numPoints() const", asMETHOD(TileObject2D, GetNumPoints), asCALL_THISCALL);
-    engine->RegisterObjectMethod("TileObject2D", "const Vector2& GetPoint(uint) const", asMETHOD(TileObject2D, GetPoint), asCALL_THISCALL);
-    engine->RegisterObjectMethod("TileObject2D", "int get_tileGid() const", asMETHOD(TileObject2D, GetTileGid), asCALL_THISCALL);
-    engine->RegisterObjectMethod("TileObject2D", "Sprite2D@ get_tileSprite() const", asMETHOD(TileObject2D, GetTileSprite), asCALL_THISCALL);
-    engine->RegisterObjectMethod("TileObject2D", "bool HasProperty(const String&in) const", asMETHOD(TileObject2D, HasProperty), asCALL_THISCALL);
-    engine->RegisterObjectMethod("TileObject2D", "const String& GetProperty(const String&in) const", asMETHOD(TileObject2D, HasProperty), asCALL_THISCALL);
+    RegisterRefCounted<TileMapObject2D>(engine, "TileMapObject2D");
+    engine->RegisterObjectMethod("TileMapObject2D", "TileObjectType2D get_objectType() const", asMETHOD(TileMapObject2D, GetObjectType), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapObject2D", "const String& get_name() const", asMETHOD(TileMapObject2D, GetName), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapObject2D", "const String& get_type() const", asMETHOD(TileMapObject2D, GetType), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapObject2D", "const Vector2& get_position() const", asMETHOD(TileMapObject2D, GetPosition), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapObject2D", "const Vector2& get_size() const", asMETHOD(TileMapObject2D, GetSize), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapObject2D", "uint get_numPoints() const", asMETHOD(TileMapObject2D, GetNumPoints), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapObject2D", "const Vector2& GetPoint(uint) const", asMETHOD(TileMapObject2D, GetPoint), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapObject2D", "int get_tileGid() const", asMETHOD(TileMapObject2D, GetTileGid), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapObject2D", "Sprite2D@ get_tileSprite() const", asMETHOD(TileMapObject2D, GetTileSprite), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapObject2D", "bool HasProperty(const String&in) const", asMETHOD(TileMapObject2D, HasProperty), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapObject2D", "const String& GetProperty(const String&in) const", asMETHOD(TileMapObject2D, HasProperty), asCALL_THISCALL);
 }
 
 static void RegisterTmxFile2D(asIScriptEngine* engine)
@@ -281,7 +282,7 @@ static void RegisterTileMapLayer2D(asIScriptEngine* engine)
 
     // For object group only
     engine->RegisterObjectMethod("TileMapLayer2D", "uint get_numObjects() const", asMETHOD(TileMapLayer2D, GetNumObjects), asCALL_THISCALL);
-    engine->RegisterObjectMethod("TileMapLayer2D", "TileObject2D@ GetObject(uint) const", asMETHOD(TileMapLayer2D, GetObject), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMapLayer2D", "TileMapObject2D@ GetObject(uint) const", asMETHOD(TileMapLayer2D, GetObject), asCALL_THISCALL);
     engine->RegisterObjectMethod("TileMapLayer2D", "Node@ GetObjectNode(uint) const", asMETHOD(TileMapLayer2D, GetObjectNode), asCALL_THISCALL);
     
     // For image layer only
@@ -295,8 +296,8 @@ static void RegisterTileMap2D(asIScriptEngine* engine)
     engine->RegisterObjectMethod("TileMap2D", "TileMapInfo2D@ get_info() const", asMETHOD(TileMap2D, GetInfo), asCALL_THISCALL);
     engine->RegisterObjectMethod("TileMap2D", "uint get_numLayers() const", asMETHOD(TileMap2D, GetNumLayers), asCALL_THISCALL);
     engine->RegisterObjectMethod("TileMap2D", "TileMapLayer2D@ GetLayer(uint) const", asMETHOD(TileMap2D, GetLayer), asCALL_THISCALL);
-    engine->RegisterObjectMethod("TileMap2D", "Vector2 IndexToPosition(int, int) const", asMETHOD(TileMap2D, IndexToPosition), asCALL_THISCALL);
-    engine->RegisterObjectMethod("TileMap2D", "bool PositionToIndex(int&out x, int &out y, const Vector2&in) const", asMETHOD(TileMap2D, PositionToIndex), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMap2D", "Vector2 TileIndexToPosition(int, int) const", asMETHOD(TileMap2D, TileIndexToPosition), asCALL_THISCALL);
+    engine->RegisterObjectMethod("TileMap2D", "bool PositionToTileIndex(int&out x, int &out y, const Vector2&in) const", asMETHOD(TileMap2D, PositionToTileIndex), asCALL_THISCALL);
 }
 
 static void RegisterRigidBody2D(asIScriptEngine* engine)

+ 53 - 5
Source/Engine/Urho2D/TileMap2D.cpp

@@ -22,8 +22,10 @@
 
 #include "Precompiled.h"
 #include "Context.h"
+#include "DebugRenderer.h"
 #include "Node.h"
 #include "ResourceCache.h"
+#include "Scene.h"
 #include "TileMap2D.h"
 #include "TileMapLayer2D.h"
 #include "TmxFile2D.h"
@@ -48,10 +50,56 @@ TileMap2D::~TileMap2D()
 void TileMap2D::RegisterObject(Context* context)
 {
     context->RegisterFactory<TileMap2D>(URHO2D_CATEGORY);
-
     ACCESSOR_ATTRIBUTE(TileMap2D, VAR_RESOURCEREF, "Tmx File", GetTmxFileAttr, SetTmxFileAttr, ResourceRef, ResourceRef(TmxFile2D::GetTypeStatic()), AM_DEFAULT);
 }
 
+void TileMap2D::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
+{
+    const Color& color = Color::RED;
+    float mapW = info_.GetMapWidth();
+    float mapH = info_.GetMapHeight();
+
+    switch (info_.orientation_)
+    {
+    case O_ORTHOGONAL:
+        debug->AddLine(Vector2(0.0f, 0.0f), Vector2(mapW, 0.0f), color);
+        debug->AddLine(Vector2(mapW, 0.0f), Vector2(mapW, mapH), color);
+        debug->AddLine(Vector2(mapW, mapH), Vector2(0.0f, mapH), color);
+        debug->AddLine(Vector2(0.0f, mapH), Vector2(0.0f, 0.0f), color);
+        break;
+
+    case O_ISOMETRIC:
+        debug->AddLine(Vector2(0.0f, mapH * 0.5f), Vector2(mapW * 0.5f, 0.0f), color);
+        debug->AddLine(Vector2(mapW * 0.5f, 0.0f), Vector2(mapW, mapH * 0.5f), color);
+        debug->AddLine(Vector2(mapW, mapH * 0.5f), Vector2(mapW * 0.5f, mapH), color);
+        debug->AddLine(Vector2(mapW * 0.5f, mapH), Vector2(0.0f, mapH * 0.5f), color);
+        break;
+
+    case O_STAGGERED:
+        debug->AddLine(Vector2(0.0f, 0.0f), Vector2(mapW, 0.0f), color);
+        debug->AddLine(Vector2(mapW, 0.0f), Vector2(mapW, mapH), color);
+        debug->AddLine(Vector2(mapW, mapH), Vector2(0.0f, mapH), color);
+        debug->AddLine(Vector2(0.0f, mapH), Vector2(0.0f, 0.0f), color);
+        break;
+    }
+
+    for (unsigned i = 0; i < layers_.Size(); ++i)
+        layers_[i]->DrawDebugGeometry(debug, depthTest);
+}
+
+void TileMap2D::DrawDebugGeometry()
+{
+    Scene* scene = GetScene();
+    if (!scene)
+        return;
+
+    DebugRenderer* debug = scene->GetComponent<DebugRenderer>();
+    if (!debug)
+        return;
+
+    DrawDebugGeometry(debug, false);
+}
+
 void TileMap2D::SetTmxFile(TmxFile2D* tmxFile)
 {
     if (tmxFile == tmxFile_)
@@ -101,14 +149,14 @@ TileMapLayer2D* TileMap2D::GetLayer(unsigned index) const
     return layers_[index];
 }
 
-Vector2 TileMap2D::IndexToPosition(int x, int y) const
+Vector2 TileMap2D::TileIndexToPosition(int x, int y) const
 {
-    return IndexToPosition2D(x, y, info_);
+    return info_.TileIndexToPosition(x, y);
 }
 
-bool TileMap2D::PositionToIndex(int& x, int& y, const Vector2& position) const
+bool TileMap2D::PositionToTileIndex(int& x, int& y, const Vector2& position) const
 {
-    return PositionToIndex2D(x, y, position, info_);
+    return info_.PositionToTileIndex(x, y, position);
 }
 
 void TileMap2D::SetTmxFileAttr(ResourceRef value)

+ 9 - 4
Source/Engine/Urho2D/TileMap2D.h

@@ -44,8 +44,13 @@ public:
     /// Register object factory.
     static void RegisterObject(Context* context);
 
+    /// Visualize the component as debug geometry.
+    virtual void DrawDebugGeometry(DebugRenderer* debug, bool depthTest);
+
     /// Set tmx file.
     void SetTmxFile(TmxFile2D* tmxFile);
+    /// Add debug geometry to the debug renderer.
+    void DrawDebugGeometry();
 
     /// Return tmx file.
     TmxFile2D* GetTmxFile() const;
@@ -55,10 +60,10 @@ public:
     unsigned GetNumLayers() const { return layers_.Size(); }
     /// Return tile map layer at index.
     TileMapLayer2D* GetLayer(unsigned index) const;
-    /// Convert index to position.
-    Vector2 IndexToPosition(int x, int y) const;
-    /// Convert position to index, if out of map return false.
-    bool PositionToIndex(int& x, int& y, const Vector2& position) const;
+    /// Convert tile index to position.
+    Vector2 TileIndexToPosition(int x, int y) const;
+    /// Convert position to tile index, if out of map return false.
+    bool PositionToTileIndex(int& x, int& y, const Vector2& position) const;
 
     /// Set tile map file attribute.
     void SetTmxFileAttr(ResourceRef value);

+ 95 - 32
Source/Engine/Urho2D/TileMapDefs2D.cpp

@@ -28,6 +28,95 @@
 
 namespace Urho3D
 {
+extern URHO3D_API const float PIXEL_SIZE;
+
+float TileMapInfo2D::GetMapWidth() const
+{
+    return width_ * tileWidth_;
+}
+
+float TileMapInfo2D::GetMapHeight() const
+{
+    if (orientation_ == O_STAGGERED)
+        return (height_ + 1) * 0.5f * tileHeight_;
+    else
+        return height_ * tileHeight_;
+}
+
+Vector2 TileMapInfo2D::ConvertPosition(const Vector2& position) const
+{
+    switch (orientation_)
+    {
+    case O_ISOMETRIC:
+        {
+            Vector2 index = position * PIXEL_SIZE / tileHeight_;
+            return Vector2((width_ + index.x_ - index.y_) * tileWidth_ * 0.5f, (height_ * 2.0f - index.x_ - index.y_) * tileHeight_ * 0.5f);
+        }
+
+    case O_STAGGERED:
+        return Vector2(position.x_ * PIXEL_SIZE, GetMapHeight() - position.y_ * PIXEL_SIZE);
+
+    case O_ORTHOGONAL:
+    default:
+        return Vector2(position.x_ * PIXEL_SIZE, GetMapHeight() - position.y_ * PIXEL_SIZE);
+    }
+
+    return Vector2::ZERO;
+}
+
+Vector2 TileMapInfo2D::TileIndexToPosition(int x, int y) const
+{
+    switch (orientation_)
+    {
+    case O_ISOMETRIC:
+        return Vector2((width_ + x - y - 1) * tileWidth_ * 0.5f, (height_ * 2 - x - y - 2) * tileHeight_ * 0.5f);
+
+    case O_STAGGERED:
+        if (y % 2 == 0)
+            return Vector2(x * tileWidth_, (height_ - 1 - y) * 0.5f * tileHeight_);
+        else
+            return Vector2((x + 0.5f) * tileWidth_, (height_ - 1 - y)  * 0.5f * tileHeight_);
+
+    case O_ORTHOGONAL:
+    default:
+        return Vector2(x * tileWidth_, (height_ - 1 - y) * tileHeight_);
+    }
+
+    return Vector2::ZERO;
+}
+
+bool TileMapInfo2D::PositionToTileIndex(int& x, int& y, const Vector2& position) const
+{
+    switch (orientation_)
+    {
+    case O_ISOMETRIC:
+        {
+            int x_sub_y = (int)(position.x_ * 2.0f / tileWidth_ + 1 - width_);
+            int x_add_y = (int)(height_ * 2.0f - position.y_ * 2.0f / tileHeight_ - 2.0f);
+            x = (x_sub_y - x_add_y) / 2;
+            y = (x_sub_y - x_add_y) / 2;
+        }
+        break;
+
+    case O_STAGGERED:
+        y = (int)(height_ - 1 - position.y_ * 2.0f / tileHeight_);
+        if (y % 2 == 0)
+            x = (int)(position.x_ / tileWidth_);
+        else
+            x = (int)(position.x_ / tileWidth_ - 0.5f);
+
+        break;
+
+    case O_ORTHOGONAL:
+    default:
+        x = (int)(position.x_ / tileWidth_);
+        y = height_ - 1 - int(position.y_ / tileHeight_);
+        break;
+
+    }
+
+    return x >= 0 && x < width_ && y >= 0 && y < height_;
+}
 
 PropertySet2D::PropertySet2D()
 {
@@ -83,16 +172,16 @@ const String& Tile2D::GetProperty(const String& name) const
     return propertySet_->GetProperty(name);
 }
 
-TileObject2D::TileObject2D()
+TileMapObject2D::TileMapObject2D()
 {
 }
 
-unsigned TileObject2D::GetNumPoints() const
+unsigned TileMapObject2D::GetNumPoints() const
 {
     return points_.Size();
 }
 
-const Vector2& TileObject2D::GetPoint(unsigned index) const
+const Vector2& TileMapObject2D::GetPoint(unsigned index) const
 {
     if (index >= points_.Size())
         return Vector2::ZERO;
@@ -100,49 +189,23 @@ const Vector2& TileObject2D::GetPoint(unsigned index) const
     return points_[index];
 }
 
-Sprite2D* TileObject2D::GetTileSprite() const
+Sprite2D* TileMapObject2D::GetTileSprite() const
 {
     return sprite_;
 }
 
-bool TileObject2D::HasProperty(const String& name) const
+bool TileMapObject2D::HasProperty(const String& name) const
 {
     if (!propertySet_)
         return false;
     return propertySet_->HasProperty(name);
 }
 
-const String& TileObject2D::GetProperty(const String& name) const
+const String& TileMapObject2D::GetProperty(const String& name) const
 {
     if (!propertySet_)
         return String::EMPTY;
     return propertySet_->GetProperty(name);
 }
 
-Vector2 IndexToPosition2D(int x, int y, const TileMapInfo2D& tileMapInfo)
-{
-    if (tileMapInfo.orientation_ == O_ORTHOGONAL)
-        return Vector2((x + 0.5f) * tileMapInfo.tileWidth_, (y + 0.5f) * tileMapInfo.tileHeight_);
-    else
-        return Vector2(((x + y) + 0.5f) * tileMapInfo.tileWidth_ * 0.5f, (tileMapInfo.height_ - (x - y) + 0.5f) * tileMapInfo.tileHeight_ * 0.5f);
-}
-
-bool PositionToIndex2D(int& x, int& y, const Vector2& position, const TileMapInfo2D& tileMapInfo)
-{
-    if (tileMapInfo.orientation_ == O_ORTHOGONAL)
-    {
-        x = (int)(position.x_ / tileMapInfo.tileWidth_);
-        y = (int)(position.y_ / tileMapInfo.tileHeight_);
-    }
-    else
-    {
-        int sum = (int)(position.x_ * 2.0f / tileMapInfo.tileWidth_);
-        int dif = (int)(tileMapInfo.height_ - position.y_ * 2.0f / tileMapInfo.tileHeight_);
-        x = (sum + dif) / 2;
-        y = (sum - dif) / 2;
-    }
-
-    return x >= 0 && x < tileMapInfo.width_ && y >= 0 && y < tileMapInfo.height_;
-}
-
 }

+ 17 - 14
Source/Engine/Urho2D/TileMapDefs2D.h

@@ -36,7 +36,9 @@ enum Orientation2D
     /// Orthogonal.
     O_ORTHOGONAL = 0,
     /// Isometric.
-    O_ISOMETRIC
+    O_ISOMETRIC,
+    /// Staggered.
+    O_STAGGERED
 };
 
 /// Tile map infomation.
@@ -54,9 +56,15 @@ struct URHO3D_API TileMapInfo2D
     float tileHeight_;
 
     /// Return map width.
-    float GetMapWidth() const { return width_ * tileWidth_; }
+    float GetMapWidth() const;
     /// return map height.
-    float GetMapHeight() const { return height_ * tileHeight_;}
+    float GetMapHeight() const;
+    /// Convert tmx position to Urho position.
+    Vector2 ConvertPosition(const Vector2& position) const;
+    /// Convert tile index to position.
+    Vector2 TileIndexToPosition(int x, int y) const;
+    /// Convert position to tile index, if out of map return false.
+    bool PositionToTileIndex(int& x, int& y, const Vector2& positon) const;
 };
 
 /// Tile map layer type.
@@ -72,8 +80,8 @@ enum TileMapLayerType2D
     LT_INVALID = 0xffff
 };
 
-/// Tile object type.
-enum TileObjectType2D
+/// Tile map object type.
+enum TileMapObjectType2D
 {
     /// Rectangle.
     OT_RECTANGLE = 0,
@@ -136,13 +144,13 @@ private:
 };
 
 /// Tile map object.
-class URHO3D_API TileObject2D : public RefCounted
+class URHO3D_API TileMapObject2D : public RefCounted
 {
 public:
-    TileObject2D();
+    TileMapObject2D();
 
     /// Return type.
-    TileObjectType2D GetObjectType() const { return objectType_; }
+    TileMapObjectType2D GetObjectType() const { return objectType_; }
     /// Return name.
     const String& GetName() const { return name_; }
     /// Return type.
@@ -168,7 +176,7 @@ private:
     friend class TmxObjectGroup2D;
 
     /// Object type.
-    TileObjectType2D objectType_;
+    TileMapObjectType2D objectType_;
     /// Name.
     String name_;
     /// Type.
@@ -187,9 +195,4 @@ private:
     SharedPtr<PropertySet2D> propertySet_;
 };
 
-/// Convert index to position.
-URHO3D_API Vector2 IndexToPosition2D(int x, int y, const TileMapInfo2D& tileMapInfo);
-/// Convert position to index, if out of range return false.
-URHO3D_API bool PositionToIndex2D(int& x, int& y, const Vector2& position, const TileMapInfo2D& tileMapInfo);
-
 }

+ 74 - 9
Source/Engine/Urho2D/TileMapLayer2D.cpp

@@ -22,6 +22,7 @@
 
 #include "Precompiled.h"
 #include "Context.h"
+#include "DebugRenderer.h"
 #include "Node.h"
 #include "ResourceCache.h"
 #include "StaticSprite2D.h"
@@ -51,6 +52,63 @@ void TileMapLayer2D::RegisterObject(Context* context)
     context->RegisterFactory<TileMapLayer2D>();
 }
 
+void TileMapLayer2D::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
+{
+    if (!debug)
+        return;
+
+    if (objectGroup_)
+    {
+        for (unsigned i = 0; i < objectGroup_->GetNumObjects(); ++i)
+        {
+            TileMapObject2D* object = objectGroup_->GetObject(i);
+            const Color& color = Color::YELLOW;
+
+            switch (object->GetObjectType())
+            {
+            case OT_RECTANGLE:
+                {
+                    const Vector2& lb = object->GetPosition();
+                    const Vector2& rt = lb + object->GetSize();
+
+                    debug->AddLine(Vector2(lb.x_, lb.y_), Vector2(rt.x_, lb.y_), color, depthTest);
+                    debug->AddLine(Vector2(rt.x_, lb.y_), Vector2(rt.x_, rt.y_), color, depthTest);
+                    debug->AddLine(Vector2(rt.x_, rt.y_), Vector2(lb.x_, rt.y_), color, depthTest);
+                    debug->AddLine(Vector2(lb.x_, rt.y_), Vector2(lb.x_, lb.y_), color, depthTest);
+                }
+                break;
+
+            case OT_ELLIPSE:
+                {
+                    const Vector2 halfSize = object->GetSize() * 0.5f;
+                    const Vector2 center = object->GetPosition() + halfSize;
+                    for (unsigned i = 0; i < 360; i += 30)
+                    {
+                        unsigned j = i + 30;
+                        float x1 = halfSize.x_ * Cos((float)i);
+                        float y1 = halfSize.y_ * Sin((float)i);
+                        float x2 = halfSize.x_ * Cos((float)j);
+                        float y2 = halfSize.y_ * Sin((float)j);
+                        debug->AddLine(center + Vector2(x1, y1), center + Vector2(x2, y2), color, depthTest);
+                    }
+                }
+                break;
+
+            case OT_POLYGON:
+            case OT_POLYLINE:
+                {
+                    for (unsigned j = 0; j < object->GetNumPoints() - 1; ++j)
+                        debug->AddLine(object->GetPoint(j), object->GetPoint(j + 1), color, depthTest);
+
+                    if (object->GetObjectType() == OT_POLYGON)
+                        debug->AddLine(object->GetPoint(0), object->GetPoint(object->GetNumPoints() - 1), color, depthTest);
+                }
+                break;
+            }
+        }
+    }
+}
+
 void TileMapLayer2D::Initialize(TileMap2D* tileMap, const TmxLayer2D* tmxLayer)
 {
     if (tileMap == tileMap_ && tmxLayer == tmxLayer_)
@@ -70,10 +128,10 @@ void TileMapLayer2D::Initialize(TileMap2D* tileMap, const TmxLayer2D* tmxLayer)
     tileLayer_ = 0;
     objectGroup_ = 0;
     imageLayer_ = 0;
-    
+
     tileMap_ = tileMap;
     tmxLayer_ = tmxLayer;
-    
+
     if (!tmxLayer_)
         return;
 
@@ -177,10 +235,10 @@ Node* TileMapLayer2D::GetTileNode(int x, int y) const
 {
     if (!tileLayer_)
         return 0;
-    
+
     if (x < 0 || x >= tileLayer_->GetWidth() || y < 0 || y >= tileLayer_->GetHeight())
         return 0;
-    
+
     return nodes_[y * tileLayer_->GetWidth() + x];
 }
 
@@ -192,7 +250,7 @@ unsigned TileMapLayer2D::GetNumObjects() const
     return objectGroup_->GetNumObjects();
 }
 
-TileObject2D* TileMapLayer2D::GetObject(unsigned index) const
+TileMapObject2D* TileMapLayer2D::GetObject(unsigned index) const
 {
     if (!objectGroup_)
         return 0;
@@ -230,6 +288,7 @@ void TileMapLayer2D::SetTileLayer(const TmxTileLayer2D* tileLayer)
     int height = tileLayer->GetHeight();
     nodes_.Resize(width * height);
 
+    const TileMapInfo2D& info = tileMap_->GetInfo();
     for (int y = 0; y < height; ++y)
     {
         for (int x = 0; x < width; ++x)
@@ -240,12 +299,12 @@ void TileMapLayer2D::SetTileLayer(const TmxTileLayer2D* tileLayer)
 
             SharedPtr<Node> tileNode(GetNode()->CreateChild("Tile"));
             tileNode->SetTemporary(true);
-            tileNode->SetPosition(tileMap_->IndexToPosition(x, y));
+            tileNode->SetPosition(info.TileIndexToPosition(x, y));
 
             StaticSprite2D* staticSprite = tileNode->CreateComponent<StaticSprite2D>();
             staticSprite->SetSprite(tile->GetSprite());
             staticSprite->SetLayer(drawOrder_);
-            staticSprite->SetOrderInLayer((height - 1 - y) * width + x);
+            staticSprite->SetOrderInLayer(y * width + x);
 
             nodes_[y * width + x] = tileNode;
         }
@@ -261,7 +320,7 @@ void TileMapLayer2D::SetObjectGroup(const TmxObjectGroup2D* objectGroup)
 
     for (unsigned i = 0; i < objectGroup->GetNumObjects(); ++i)
     {
-        const TileObject2D* object = objectGroup->GetObject(i);
+        const TileMapObject2D* object = objectGroup->GetObject(i);
 
         // Create dummy node for all object
         SharedPtr<Node> objectNode(GetNode()->CreateChild("Object"));
@@ -275,6 +334,12 @@ void TileMapLayer2D::SetObjectGroup(const TmxObjectGroup2D* objectGroup)
             staticSprite->SetSprite(object->GetTileSprite());
             staticSprite->SetLayer(drawOrder_);
             staticSprite->SetOrderInLayer((int)((10.0f - object->GetPosition().y_) * 100));
+
+            if (tmxFile->GetInfo().orientation_ == O_ISOMETRIC)
+            {
+                staticSprite->SetUseHotSpot(true);
+                staticSprite->SetHotSpot(Vector2(0.5f, 0.0f));
+            }
         }
 
         nodes_[i] = objectNode;
@@ -293,7 +358,7 @@ void TileMapLayer2D::SetImageLayer(const TmxImageLayer2D* imageLayer)
 
     SharedPtr<Node> imageNode(GetNode()->CreateChild("Tile"));
     imageNode->SetTemporary(true);
-    imageNode->SetPosition(Vector3(0.0f, mapHeight, 0.0f));
+    imageNode->SetPosition(imageLayer->GetPosition());
 
     StaticSprite2D* staticSprite = imageNode->CreateComponent<StaticSprite2D>();
     staticSprite->SetSprite(imageLayer->GetSprite());

+ 8 - 4
Source/Engine/Urho2D/TileMapLayer2D.h

@@ -28,6 +28,7 @@
 namespace Urho3D
 {
 
+class DebugRenderer;
 class Node;
 class TileMap2D;
 class TmxImageLayer2D;
@@ -48,6 +49,9 @@ public:
     /// Register object factory.
     static void RegisterObject(Context* context);
 
+    /// Add debug geometry to the debug renderer.
+    virtual void DrawDebugGeometry(DebugRenderer* debug, bool depthTest);
+
     /// Initialize with tile map and tmx layer.
     void Initialize(TileMap2D* tileMap, const TmxLayer2D* tmxLayer);
     /// Set draw order
@@ -79,13 +83,13 @@ public:
     /// Return tile (for tile layer only).
     Tile2D* GetTile(int x, int y) const;
 
-    /// Return number of objects (for object group only).
+    /// Return number of tile map objects (for object group only).
     unsigned GetNumObjects() const;
-    /// Return object (for object group only).
-    TileObject2D* GetObject(unsigned index) const;
+    /// Return tile map object (for object group only).
+    TileMapObject2D* GetObject(unsigned index) const;
     /// Return object node (for object group only).
     Node* GetObjectNode(unsigned index) const;
-    
+
     /// Return image node (for image layer only).
     Node* GetImageNode() const;
 

+ 46 - 33
Source/Engine/Urho2D/TmxFile2D.cpp

@@ -89,7 +89,7 @@ TmxTileLayer2D::TmxTileLayer2D(TmxFile2D* tmxFile) :
 {
 }
 
-bool TmxTileLayer2D::Load(const XMLElement& element)
+bool TmxTileLayer2D::Load(const XMLElement& element, const TileMapInfo2D& info)
 {
     LoadInfo(element);
 
@@ -109,8 +109,7 @@ bool TmxTileLayer2D::Load(const XMLElement& element)
     XMLElement tileElem = dataElem.GetChild("tile");
     tiles_.Resize(width_ * height_);
 
-    // Flip y
-    for (int y = height_ - 1; y >= 0; --y)
+    for (int y = 0; y < height_; ++y)
     {
         for (int x = 0; x < width_; ++x)
         {
@@ -133,7 +132,7 @@ bool TmxTileLayer2D::Load(const XMLElement& element)
 
     if (element.HasChild("properties"))
         LoadPropertySet(element.GetChild("properties"));
-    
+
     return true;
 }
 
@@ -150,22 +149,21 @@ TmxObjectGroup2D::TmxObjectGroup2D(TmxFile2D* tmxFile) :
 {
 }
 
-bool TmxObjectGroup2D::Load(const XMLElement& element)
+bool TmxObjectGroup2D::Load(const XMLElement& element, const TileMapInfo2D& info)
 {
     LoadInfo(element);
-   
-    const float mapHeight = height_ * tmxFile_->GetInfo().tileHeight_;
 
     for (XMLElement objectElem = element.GetChild("object"); objectElem; objectElem = objectElem.GetNext("object"))
     {
-        SharedPtr<TileObject2D> object(new TileObject2D());
+        SharedPtr<TileMapObject2D> object(new TileMapObject2D());
 
         if (objectElem.HasAttribute("name"))
             object->name_ = objectElem.GetAttribute("name");
         if (objectElem.HasAttribute("type"))
             object->type_ = objectElem.GetAttribute("type");
-        
-        object->position_ = Vector2(objectElem.GetInt("x") * PIXEL_SIZE, mapHeight - objectElem.GetInt("y") * PIXEL_SIZE);
+
+        Vector2 position(objectElem.GetFloat("x"), objectElem.GetFloat("y"));
+
         if (objectElem.HasAttribute("width") || objectElem.HasAttribute("height"))
         {
             if (!objectElem.HasChild("ellipse"))
@@ -173,12 +171,15 @@ bool TmxObjectGroup2D::Load(const XMLElement& element)
             else
                 object->objectType_ = OT_ELLIPSE;
 
-            object->size_ = Vector2(objectElem.GetInt("width") * PIXEL_SIZE, objectElem.GetInt("height") * PIXEL_SIZE);
-            object->position_.y_ -= object->size_.y_;
+            Vector2 size(objectElem.GetFloat("width"), objectElem.GetFloat("height"));
+
+            object->position_ = info.ConvertPosition(Vector2(position.x_, position.y_ + size.y_));
+            object->size_ = Vector2(size.x_ * PIXEL_SIZE, size.y_ * PIXEL_SIZE);
         }
         else if (objectElem.HasAttribute("gid"))
         {
             object->objectType_ = OT_TILE;
+            object->position_ = info.ConvertPosition(position);
             object->gid_ = objectElem.GetInt("gid");
             object->sprite_ = tmxFile_->GetTileSprite(object->gid_);
         }
@@ -198,9 +199,8 @@ bool TmxObjectGroup2D::Load(const XMLElement& element)
             for (unsigned i = 0; i < points.Size(); ++i)
             {
                 points[i].Replace(',', ' ');
-                Vector2 point = ToVector2(points[i]) * PIXEL_SIZE;
-                point.y_ = mapHeight - point.y_;
-                object->points_[i] = point;
+                Vector2 point = position + ToVector2(points[i]);
+                object->points_[i] = info.ConvertPosition(point);
             }
         }
 
@@ -219,7 +219,7 @@ bool TmxObjectGroup2D::Load(const XMLElement& element)
     return true;
 }
 
-TileObject2D* TmxObjectGroup2D::GetObject(unsigned index) const
+TileMapObject2D* TmxObjectGroup2D::GetObject(unsigned index) const
 {
     if (index >= objects_.Size())
         return 0;
@@ -232,7 +232,7 @@ TmxImageLayer2D::TmxImageLayer2D(TmxFile2D* tmxFile) :
 {
 }
 
-bool TmxImageLayer2D::Load(const XMLElement& element)
+bool TmxImageLayer2D::Load(const XMLElement& element, const TileMapInfo2D& info)
 {
     LoadInfo(element);
 
@@ -240,8 +240,9 @@ bool TmxImageLayer2D::Load(const XMLElement& element)
     if (!imageElem)
         return false;
 
+    position_ = Vector2(0.0f, info.GetMapHeight());
     source_ = imageElem.GetAttribute("source");
-    String textureFilePath = GetParentPath(GetName()) + source_;
+    String textureFilePath = GetParentPath(tmxFile_->GetName()) + source_;
     ResourceCache* cache = tmxFile_->GetSubsystem<ResourceCache>();
     SharedPtr<Texture2D> texture(cache->GetResource<Texture2D>(textureFilePath));
     if (!texture)
@@ -253,7 +254,7 @@ bool TmxImageLayer2D::Load(const XMLElement& element)
     sprite_ = new Sprite2D(tmxFile_->GetContext());
     sprite_->SetTexture(texture);
     sprite_->SetRectangle(IntRect(0, 0, texture->GetWidth(), texture->GetHeight()));
-    // Left top
+    // Set image hot spot at left top
     sprite_->SetHotSpot(Vector2(0.0f, 1.0f));
 
     if (element.HasChild("properties"))
@@ -318,7 +319,7 @@ bool TmxFile2D::BeginLoad(Deserializer& source)
                     return false;
 
                 tsxXMLFiles_[source] = tsxXMLFile;
-                
+
                 String textureFilePath = GetParentPath(GetName()) + tsxXMLFile->GetRoot("tileset").GetChild("image").GetAttribute("source");
                 GetSubsystem<ResourceCache>()->BackgroundLoadResource<Texture2D>(textureFilePath, true, this);
             }
@@ -357,9 +358,11 @@ bool TmxFile2D::EndLoad()
         info_.orientation_ = O_ORTHOGONAL;
     else if (orientation == "isometric")
         info_.orientation_ = O_ISOMETRIC;
+    else if (orientation == "staggered")
+        info_.orientation_ = O_STAGGERED;
     else
     {
-        LOGERROR("Invalid orientation type " + orientation);
+        LOGERROR("Unsupported orientation type " + orientation);
         return false;
     }
 
@@ -381,22 +384,22 @@ bool TmxFile2D::EndLoad()
         else if (name == "layer")
         {
             TmxTileLayer2D* tileLayer = new TmxTileLayer2D(this);
-            ret = tileLayer->Load(childElement);
-            
+            ret = tileLayer->Load(childElement, info_);
+
             layers_.Push(tileLayer);
         }
         else if (name == "objectgroup")
         {
             TmxObjectGroup2D* objectGroup = new TmxObjectGroup2D(this);
-            ret = objectGroup->Load(childElement);
-            
+            ret = objectGroup->Load(childElement, info_);
+
             layers_.Push(objectGroup);
 
         }
         else if (name == "imagelayer")
         {
             TmxImageLayer2D* imageLayer = new TmxImageLayer2D(this);
-            ret = imageLayer->Load(childElement);
+            ret = imageLayer->Load(childElement, info_);
 
             layers_.Push(imageLayer);
         }
@@ -408,7 +411,7 @@ bool TmxFile2D::EndLoad()
             return false;
         }
     }
-   
+
     loadXMLFile_.Reset();
     tsxXMLFiles_.Clear();
     return true;
@@ -456,8 +459,8 @@ SharedPtr<XMLFile> TmxFile2D::LoadTSXFile(const String& source)
 
 bool TmxFile2D::LoadTileSet(const XMLElement& element)
 {
-    int firstgid = element.GetInt("firstgid"); 
-    
+    int firstgid = element.GetInt("firstgid");
+
     XMLElement tileSetElem;
     if (element.HasAttribute("source"))
     {
@@ -479,7 +482,7 @@ bool TmxFile2D::LoadTileSet(const XMLElement& element)
     }
     else
         tileSetElem = element;
-    
+
     XMLElement imageElem = tileSetElem.GetChild("image");
     String textureFilePath = GetParentPath(GetName()) + imageElem.GetAttribute("source");
     ResourceCache* cache = GetSubsystem<ResourceCache>();
@@ -499,15 +502,25 @@ bool TmxFile2D::LoadTileSet(const XMLElement& element)
     int imageWidth = imageElem.GetInt("width");
     int imageHeight = imageElem.GetInt("height");
 
+    // Set hot spot at left bottom
+    Vector2 hotSpot(0.0f, 0.0f);
+    if (tileSetElem.HasChild("tileoffset"))
+    {
+        XMLElement offsetElem = tileSetElem.GetChild("tileoffset");
+        hotSpot.x_ += offsetElem.GetFloat("x") / (float)tileWidth;
+        hotSpot.y_ += offsetElem.GetFloat("y") / (float)tileHeight;
+    }
+
     int gid = firstgid;
-    for (int y = margin; y < imageHeight - margin; y += tileHeight + spacing)
+    for (int y = margin; y + tileHeight <= imageHeight - margin; y += tileHeight + spacing)
     {
-        for (int x = margin; x < imageWidth - margin; x += tileWidth + spacing)
+        for (int x = margin; x + tileWidth <= imageWidth - margin; x += tileWidth + spacing)
         {
             SharedPtr<Sprite2D> sprite(new Sprite2D(context_));
             sprite->SetTexture(texture);
             sprite->SetRectangle(IntRect(x, y, x + tileWidth, y + tileHeight));
-            
+            sprite->SetHotSpot(hotSpot);
+
             gidToSpriteMapping_[gid++] = sprite;
         }
     }

+ 13 - 9
Source/Engine/Urho2D/TmxFile2D.h

@@ -88,7 +88,7 @@ public:
     TmxTileLayer2D(TmxFile2D* tmxFile);
 
     /// Load from XML element.
-    bool Load(const XMLElement& element);
+    bool Load(const XMLElement& element, const TileMapInfo2D& info);
     /// Return tile.
     Tile2D* GetTile(int x, int y) const;
 
@@ -104,15 +104,15 @@ public:
     TmxObjectGroup2D(TmxFile2D* tmxFile);
 
     /// Load from XML element.
-    bool Load(const XMLElement& element);
+    bool Load(const XMLElement& element, const TileMapInfo2D& info);
     /// Return number of objects.
     unsigned GetNumObjects() const { return objects_.Size(); }
-    /// Return object at index.
-    TileObject2D* GetObject(unsigned index) const;
+    /// Return tile map object at index.
+    TileMapObject2D* GetObject(unsigned index) const;
 
 private:
     /// Objects.
-    Vector<SharedPtr<TileObject2D> > objects_;
+    Vector<SharedPtr<TileMapObject2D> > objects_;
 };
 
 /// Tmx image layer.
@@ -122,13 +122,17 @@ public:
     TmxImageLayer2D(TmxFile2D* tmxFile);
 
     /// Load from XML element.
-    bool Load(const XMLElement& element);
+    bool Load(const XMLElement& element, const TileMapInfo2D& info);
+    /// Return position.
+    const Vector2& GetPosition() const { return position_; }
     /// Return source.
     const String& GetSource() const { return source_; }
     /// Return sprite.
     Sprite2D* GetSprite() const;
-    
+
 private:
+    /// Position.
+    Vector2 position_;
     /// Source.
     String source_;
     /// Sprite.
@@ -145,7 +149,7 @@ public:
     TmxFile2D(Context* context);
     /// Destruct.
     virtual ~TmxFile2D();
-    /// Register object factory. 
+    /// Register object factory.
     static void RegisterObject(Context* context);
 
     /// Load resource from stream. May be called from a worker thread. Return true if successful.
@@ -169,7 +173,7 @@ private:
     SharedPtr<XMLFile> LoadTSXFile(const String& source);
     /// Load tile set.
     bool LoadTileSet(const XMLElement& element);
-    
+
     /// XML file used during loading.
     SharedPtr<XMLFile> loadXMLFile_;
     /// TSX name to XML file mapping.

+ 10 - 4
Source/Samples/CMakeLists.txt

@@ -44,15 +44,21 @@ add_subdirectory (07_Billboards)
 add_subdirectory (08_Decals)
 add_subdirectory (09_MultipleViewports)
 add_subdirectory (10_RenderToTexture)
-add_subdirectory (11_Physics)
-add_subdirectory (12_PhysicsStressTest)
-add_subdirectory (13_Ragdolls)
+if (URHO3D_PHYSICS)
+    add_subdirectory (11_Physics)
+    add_subdirectory (12_PhysicsStressTest)
+    add_subdirectory (13_Ragdolls)
+endif ()
 add_subdirectory (14_SoundEffects)
-add_subdirectory (15_Navigation)
+if (URHO3D_NAVIGATION)
+    add_subdirectory (15_Navigation)
+endif ()
 add_subdirectory (16_Chat)
+if (URHO3D_PHYSICS)
 add_subdirectory (17_SceneReplication)
 add_subdirectory (18_CharacterDemo)
 add_subdirectory (19_VehicleDemo)
+endif ()
 add_subdirectory (20_HugeObjectCount)
 if (URHO3D_ANGELSCRIPT)
     add_subdirectory (21_AngelScriptIntegration)

+ 6 - 0
Source/Tools/AssetImporter/AssetImporter.cpp

@@ -33,7 +33,9 @@
 #include "Material.h"
 #include "Model.h"
 #include "Octree.h"
+#ifdef URHO3D_PHYSICS
 #include "PhysicsWorld.h"
+#endif
 #include "ProcessUtils.h"
 #include "Quaternion.h"
 #include "ResourceCache.h"
@@ -247,7 +249,9 @@ void Run(const Vector<String>& arguments)
     context_->RegisterSubsystem(new WorkQueue(context_));
     RegisterSceneLibrary(context_);
     RegisterGraphicsLibrary(context_);
+#ifdef URHO3D_PHYSICS
     RegisterPhysicsLibrary(context_);
+#endif
     
     String command = arguments[0].ToLower();
     String rootNodeName;
@@ -1309,8 +1313,10 @@ void BuildAndSaveScene(OutScene& scene, bool asPrefab)
     
     if (!asPrefab)
     {
+        #ifdef URHO3D_PHYSICS
         /// \todo Make the physics properties configurable
         outScene->CreateComponent<PhysicsWorld>();
+        #endif
     
         /// \todo Make the octree properties configurable, or detect from the scene contents
         outScene->CreateComponent<Octree>();