TmxFile2D.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. //
  2. // Copyright (c) 2008-2014 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Animation2D.h"
  24. #include "Context.h"
  25. #include "FileSystem.h"
  26. #include "Log.h"
  27. #include "ResourceCache.h"
  28. #include "Sprite2D.h"
  29. #include "Texture2D.h"
  30. #include "TmxFile2D.h"
  31. #include "XMLFile.h"
  32. #include "DebugNew.h"
  33. namespace Urho3D
  34. {
  35. extern const float PIXEL_SIZE;
  36. TmxFile2D::TmxFile2D(Context* context) :
  37. Resource(context),
  38. width_(0),
  39. height_(0),
  40. tileWidth_(0.0f),
  41. tileHeight_(0.0f)
  42. {
  43. }
  44. TmxFile2D::~TmxFile2D()
  45. {
  46. for (unsigned i = 0; i < layers_.Size(); ++i)
  47. delete layers_[i];
  48. }
  49. void TmxFile2D::RegisterObject(Context* context)
  50. {
  51. context->RegisterFactory<TmxFile2D>();
  52. }
  53. bool TmxFile2D::BeginLoad(Deserializer& source)
  54. {
  55. loadXMLFile_ = new XMLFile(context_);
  56. if (!loadXMLFile_->Load(source))
  57. {
  58. LOGERROR("Load XML failed " + source.GetName());
  59. loadXMLFile_.Reset();
  60. return false;
  61. }
  62. XMLElement rootElem = loadXMLFile_->GetRoot("map");
  63. if (!rootElem)
  64. {
  65. LOGERROR("Invalid tmx file " + source.GetName());
  66. loadXMLFile_.Reset();
  67. return false;
  68. }
  69. // If we're async loading, request the texture now. Finish during EndLoad().
  70. if (GetAsyncLoadState() == ASYNC_LOADING)
  71. {
  72. for (XMLElement tileSetElem = rootElem.GetChild("tileset"); tileSetElem; tileSetElem = tileSetElem.GetNext("tileset"))
  73. {
  74. String textureFilePath = GetParentPath(GetName()) + tileSetElem.GetChild("image").GetAttribute("source");
  75. GetSubsystem<ResourceCache>()->BackgroundLoadResource<Texture2D>(textureFilePath, true, this);
  76. }
  77. for (XMLElement imageLayerElem = rootElem.GetChild("imagelayer"); imageLayerElem; imageLayerElem = imageLayerElem.GetNext("imagelayer"))
  78. {
  79. String textureFilePath = GetParentPath(GetName()) + imageLayerElem.GetChild("image").GetAttribute("source");
  80. GetSubsystem<ResourceCache>()->BackgroundLoadResource<Texture2D>(textureFilePath, true, this);
  81. }
  82. }
  83. return true;
  84. }
  85. bool TmxFile2D::EndLoad()
  86. {
  87. if (!loadXMLFile_)
  88. return false;
  89. XMLElement rootElem = loadXMLFile_->GetRoot("map");
  90. String version = rootElem.GetAttribute("version");
  91. if (version != "1.0")
  92. {
  93. LOGERROR("Invalid version");
  94. return false;
  95. }
  96. String orientation = rootElem.GetAttribute("orientation");
  97. if (orientation != "orthogonal")
  98. {
  99. LOGERROR("Unsupported orientation now");
  100. return false;
  101. }
  102. width_ = rootElem.GetInt("width");
  103. height_ = rootElem.GetInt("height");
  104. tileWidth_ = rootElem.GetFloat("tilewidth") * PIXEL_SIZE;
  105. tileHeight_ = rootElem.GetFloat("tileheight") * PIXEL_SIZE;
  106. for (unsigned i = 0; i < layers_.Size(); ++i)
  107. delete layers_[i];
  108. layers_.Clear();
  109. for (XMLElement childElement = rootElem.GetChild(); childElement; childElement = childElement.GetNext())
  110. {
  111. bool ret = true;
  112. String name = childElement.GetName();
  113. if (name == "tileset")
  114. ret = LoadTileSet(childElement);
  115. else if (name == "layer")
  116. ret = LoadLayer(childElement);
  117. else if (name == "objectgroup")
  118. ret = LoadObjectGroup(childElement);
  119. else if (name == "imagelayer")
  120. ret = LoadImageLayer(childElement);
  121. if (!ret)
  122. {
  123. loadXMLFile_.Reset();
  124. return false;
  125. }
  126. }
  127. loadXMLFile_.Reset();
  128. return true;
  129. }
  130. const TmxLayer2D* TmxFile2D::GetLayer(unsigned index) const
  131. {
  132. if (index >= layers_.Size())
  133. return 0;
  134. return layers_[index];
  135. }
  136. Sprite2D* TmxFile2D::GetTileSprite(int gid) const
  137. {
  138. HashMap<int, SharedPtr<Sprite2D> >::ConstIterator i = tileSprites_.Find(gid);
  139. if (i == tileSprites_.End())
  140. return 0;
  141. return i->second_;
  142. }
  143. bool TmxFile2D::LoadTileSet(const XMLElement& element)
  144. {
  145. XMLElement imageElem = element.GetChild("image");
  146. String textureFilePath = GetParentPath(GetName()) + imageElem.GetAttribute("source");
  147. ResourceCache* cache = GetSubsystem<ResourceCache>();
  148. SharedPtr<Texture2D> texture(cache->GetResource<Texture2D>(textureFilePath));
  149. if (!texture)
  150. {
  151. LOGERROR("Could not load texture " + textureFilePath);
  152. return false;
  153. }
  154. tileSetTextures_.Push(texture);
  155. int gid = element.GetInt("firstgid");
  156. int tileWidth = element.GetInt("tilewidth");
  157. int tileHeight = element.GetInt("tileheight");
  158. int spacing = element.GetInt("spacing");
  159. int margin = element.GetInt("margin");
  160. int imageWidth = imageElem.GetInt("width");
  161. int imageHeight = imageElem.GetInt("height");
  162. for (int y = margin; y < imageHeight - margin; y += tileHeight + spacing)
  163. {
  164. for (int x = margin; x < imageWidth - margin; x += tileWidth + spacing)
  165. {
  166. SharedPtr<Sprite2D> sprite(new Sprite2D(context_));
  167. sprite->SetTexture(texture);
  168. sprite->SetRectangle(IntRect(x, y, x + tileWidth, y + tileHeight));
  169. // Set hot spot at left bottom
  170. sprite->SetHotSpot(Vector2(0.0f, 0.0f));
  171. tileSprites_[gid++] = sprite;
  172. }
  173. }
  174. return true;
  175. }
  176. bool TmxFile2D::LoadLayer(const XMLElement& element)
  177. {
  178. TmxTileLayer2D* tileLayer = new TmxTileLayer2D(this);
  179. layers_.Push(tileLayer);
  180. tileLayer->name_ = element.GetAttribute("name");
  181. tileLayer->width_ = element.GetInt("width");
  182. tileLayer->height_ = element.GetInt("height");
  183. XMLElement dataElem = element.GetChild("data");
  184. if (!dataElem)
  185. {
  186. LOGERROR("Could not find data in layer");
  187. return false;
  188. }
  189. if (dataElem.HasAttribute("encoding") && dataElem.GetAttribute("encoding") != "xml")
  190. {
  191. LOGERROR("Encoding not support now");
  192. return false;
  193. }
  194. XMLElement tileElem = dataElem.GetChild("tile");
  195. tileLayer->tileGids_.Resize(tileLayer->width_ * tileLayer->height_);
  196. // Flip y
  197. for (int y = tileLayer->height_ - 1; y >= 0; --y)
  198. {
  199. for (int x = 0; x < tileLayer->width_; ++x)
  200. {
  201. if (!tileElem)
  202. return false;
  203. int gid = tileElem.GetInt("gid");
  204. tileElem = tileElem.GetNext("tile");
  205. tileLayer->tileGids_[y * tileLayer->width_ + x] = gid;
  206. }
  207. }
  208. if (element.HasChild("properties"))
  209. LoadProperties(element.GetChild("properties"), tileLayer->properties_);
  210. return true;
  211. }
  212. bool TmxFile2D::LoadObjectGroup(const XMLElement& element)
  213. {
  214. TmxObjectGroup2D* objectGroup = new TmxObjectGroup2D(this);
  215. layers_.Push(objectGroup);
  216. objectGroup->name_ = element.GetAttribute("name");
  217. objectGroup->width_ = element.GetInt("width");
  218. objectGroup->height_ = element.GetInt("height");
  219. const float mapHeight = height_ * tileHeight_;
  220. for (XMLElement objectElem = element.GetChild("object"); objectElem; objectElem = objectElem.GetNext("object"))
  221. {
  222. objectGroup->objects_.Push(TmxObject());
  223. TmxObject& object = objectGroup->objects_.Back();
  224. object.x_ = objectElem.GetInt("x") * PIXEL_SIZE;
  225. // Flip y
  226. object.y_ = mapHeight - objectElem.GetInt("y") * PIXEL_SIZE;
  227. if (objectElem.HasAttribute("width") || objectElem.HasAttribute("height"))
  228. {
  229. if (!objectElem.HasChild("ellipse"))
  230. object.type_ = OT_RECTANGLE;
  231. else
  232. object.type_ = OT_ELLIPSE;
  233. object.width_ = objectElem.GetInt("width") * PIXEL_SIZE;
  234. object.height_ = objectElem.GetInt("height") * PIXEL_SIZE;
  235. object.y_ -= object.height_;
  236. }
  237. else if (objectElem.HasAttribute("gid"))
  238. {
  239. object.type_ = OT_TILE;
  240. object.gid_ = objectElem.GetInt("gid");
  241. }
  242. else
  243. {
  244. XMLElement childElem = objectElem.GetChild();
  245. if (childElem.GetName() == "polygon")
  246. object.type_ = OT_POLYGON;
  247. else if (childElem.GetName() == "polyline")
  248. object.type_ = OT_POLYLINE;
  249. else
  250. return false;
  251. Vector<String> points = childElem.GetAttribute("points").Split(' ');
  252. object.points_.Resize(points.Size());
  253. for (unsigned i = 0; i < points.Size(); ++i)
  254. {
  255. points[i].Replace(',', ' ');
  256. Vector2 point = ToVector2(points[i]) * PIXEL_SIZE;
  257. point.y_ = mapHeight - point.y_;
  258. object.points_[i] = point;
  259. }
  260. }
  261. if (objectElem.HasChild("properties"))
  262. LoadProperties(objectElem.GetChild("properties"), object.properties_);
  263. }
  264. if (element.HasChild("properties"))
  265. LoadProperties(element.GetChild("properties"), objectGroup->properties_);
  266. return true;
  267. }
  268. bool TmxFile2D::LoadImageLayer(const XMLElement& element)
  269. {
  270. TmxImageLayer2D* imageLayer = new TmxImageLayer2D(this);
  271. layers_.Push(imageLayer);
  272. imageLayer->name_ = element.GetAttribute("name");
  273. imageLayer->width_ = element.GetInt("width");
  274. imageLayer->height_ = element.GetInt("height");
  275. XMLElement imageElem = element.GetChild("image");
  276. if (!imageElem)
  277. return false;
  278. String textureFilePath = GetParentPath(GetName()) + imageElem.GetAttribute("source");
  279. ResourceCache* cache = GetSubsystem<ResourceCache>();
  280. SharedPtr<Texture2D> texture(cache->GetResource<Texture2D>(textureFilePath));
  281. if (!texture)
  282. {
  283. LOGERROR("Could not load texture " + textureFilePath);
  284. return false;
  285. }
  286. SharedPtr<Sprite2D> sprite(new Sprite2D(context_));
  287. sprite->SetTexture(texture);
  288. sprite->SetRectangle(IntRect(0, 0, texture->GetWidth(), texture->GetHeight()));
  289. // Left top
  290. sprite->SetHotSpot(Vector2(0.0f, 1.0f));
  291. imageLayer->sprite_ = sprite;
  292. if (element.HasChild("properties"))
  293. LoadProperties(element.GetChild("properties"), imageLayer->properties_);
  294. return true;
  295. }
  296. void TmxFile2D::LoadProperties(const XMLElement& element, HashMap<String, String>& peoperties)
  297. {
  298. for (XMLElement propertyElem = element.GetChild("property"); propertyElem; propertyElem = propertyElem.GetNext("property"))
  299. peoperties[propertyElem.GetAttribute("name")] = propertyElem.GetAttribute("value");
  300. }
  301. }