TmxFile2D.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  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. const HashMap<String, String>* TmxFile2D::GetTileProperties(int gid) const
  144. {
  145. HashMap<int, HashMap<String, String> >::ConstIterator i = tileProperties_.Find(gid);
  146. if (i == tileProperties_.End())
  147. return 0;
  148. return &(i->second_);
  149. }
  150. bool TmxFile2D::LoadTileSet(const XMLElement& element)
  151. {
  152. XMLElement imageElem = element.GetChild("image");
  153. String textureFilePath = GetParentPath(GetName()) + imageElem.GetAttribute("source");
  154. ResourceCache* cache = GetSubsystem<ResourceCache>();
  155. SharedPtr<Texture2D> texture(cache->GetResource<Texture2D>(textureFilePath));
  156. if (!texture)
  157. {
  158. LOGERROR("Could not load texture " + textureFilePath);
  159. return false;
  160. }
  161. tileSetTextures_.Push(texture);
  162. int firstgid = element.GetInt("firstgid");
  163. int tileWidth = element.GetInt("tilewidth");
  164. int tileHeight = element.GetInt("tileheight");
  165. int spacing = element.GetInt("spacing");
  166. int margin = element.GetInt("margin");
  167. int imageWidth = imageElem.GetInt("width");
  168. int imageHeight = imageElem.GetInt("height");
  169. int gid = firstgid;
  170. for (int y = margin; y < imageHeight - margin; y += tileHeight + spacing)
  171. {
  172. for (int x = margin; x < imageWidth - margin; x += tileWidth + spacing)
  173. {
  174. SharedPtr<Sprite2D> sprite(new Sprite2D(context_));
  175. sprite->SetTexture(texture);
  176. sprite->SetRectangle(IntRect(x, y, x + tileWidth, y + tileHeight));
  177. // Set hot spot at left bottom
  178. sprite->SetHotSpot(Vector2(0.0f, 0.0f));
  179. tileSprites_[gid++] = sprite;
  180. }
  181. }
  182. for (XMLElement tileElem = element.GetChild("tile"); tileElem; tileElem = tileElem.GetNext("tile"))
  183. {
  184. if (tileElem.HasChild("properties"))
  185. {
  186. HashMap<String, String> properties;
  187. LoadProperties(tileElem.GetChild("properties"), properties);
  188. tileProperties_[firstgid + tileElem.GetInt("id")] = properties;
  189. }
  190. }
  191. return true;
  192. }
  193. bool TmxFile2D::LoadLayer(const XMLElement& element)
  194. {
  195. TmxTileLayer2D* tileLayer = new TmxTileLayer2D(this);
  196. layers_.Push(tileLayer);
  197. tileLayer->name_ = element.GetAttribute("name");
  198. tileLayer->width_ = element.GetInt("width");
  199. tileLayer->height_ = element.GetInt("height");
  200. XMLElement dataElem = element.GetChild("data");
  201. if (!dataElem)
  202. {
  203. LOGERROR("Could not find data in layer");
  204. return false;
  205. }
  206. if (dataElem.HasAttribute("encoding") && dataElem.GetAttribute("encoding") != "xml")
  207. {
  208. LOGERROR("Encoding not support now");
  209. return false;
  210. }
  211. XMLElement tileElem = dataElem.GetChild("tile");
  212. tileLayer->tileGids_.Resize(tileLayer->width_ * tileLayer->height_);
  213. // Flip y
  214. for (int y = tileLayer->height_ - 1; y >= 0; --y)
  215. {
  216. for (int x = 0; x < tileLayer->width_; ++x)
  217. {
  218. if (!tileElem)
  219. return false;
  220. int gid = tileElem.GetInt("gid");
  221. tileElem = tileElem.GetNext("tile");
  222. tileLayer->tileGids_[y * tileLayer->width_ + x] = gid;
  223. }
  224. }
  225. if (element.HasChild("properties"))
  226. LoadProperties(element.GetChild("properties"), tileLayer->properties_);
  227. return true;
  228. }
  229. bool TmxFile2D::LoadObjectGroup(const XMLElement& element)
  230. {
  231. TmxObjectGroup2D* objectGroup = new TmxObjectGroup2D(this);
  232. layers_.Push(objectGroup);
  233. objectGroup->name_ = element.GetAttribute("name");
  234. objectGroup->width_ = element.GetInt("width");
  235. objectGroup->height_ = element.GetInt("height");
  236. const float mapHeight = height_ * tileHeight_;
  237. for (XMLElement objectElem = element.GetChild("object"); objectElem; objectElem = objectElem.GetNext("object"))
  238. {
  239. objectGroup->objects_.Push(TmxObject());
  240. TmxObject& object = objectGroup->objects_.Back();
  241. object.x_ = objectElem.GetInt("x") * PIXEL_SIZE;
  242. // Flip y
  243. object.y_ = mapHeight - objectElem.GetInt("y") * PIXEL_SIZE;
  244. if (objectElem.HasAttribute("width") || objectElem.HasAttribute("height"))
  245. {
  246. if (!objectElem.HasChild("ellipse"))
  247. object.type_ = OT_RECTANGLE;
  248. else
  249. object.type_ = OT_ELLIPSE;
  250. object.width_ = objectElem.GetInt("width") * PIXEL_SIZE;
  251. object.height_ = objectElem.GetInt("height") * PIXEL_SIZE;
  252. object.y_ -= object.height_;
  253. }
  254. else if (objectElem.HasAttribute("gid"))
  255. {
  256. object.type_ = OT_TILE;
  257. object.gid_ = objectElem.GetInt("gid");
  258. }
  259. else
  260. {
  261. XMLElement childElem = objectElem.GetChild();
  262. if (childElem.GetName() == "polygon")
  263. object.type_ = OT_POLYGON;
  264. else if (childElem.GetName() == "polyline")
  265. object.type_ = OT_POLYLINE;
  266. else
  267. return false;
  268. Vector<String> points = childElem.GetAttribute("points").Split(' ');
  269. object.points_.Resize(points.Size());
  270. for (unsigned i = 0; i < points.Size(); ++i)
  271. {
  272. points[i].Replace(',', ' ');
  273. Vector2 point = ToVector2(points[i]) * PIXEL_SIZE;
  274. point.y_ = mapHeight - point.y_;
  275. object.points_[i] = point;
  276. }
  277. }
  278. if (objectElem.HasChild("properties"))
  279. LoadProperties(objectElem.GetChild("properties"), object.properties_);
  280. }
  281. if (element.HasChild("properties"))
  282. LoadProperties(element.GetChild("properties"), objectGroup->properties_);
  283. return true;
  284. }
  285. bool TmxFile2D::LoadImageLayer(const XMLElement& element)
  286. {
  287. TmxImageLayer2D* imageLayer = new TmxImageLayer2D(this);
  288. layers_.Push(imageLayer);
  289. imageLayer->name_ = element.GetAttribute("name");
  290. imageLayer->width_ = element.GetInt("width");
  291. imageLayer->height_ = element.GetInt("height");
  292. XMLElement imageElem = element.GetChild("image");
  293. if (!imageElem)
  294. return false;
  295. String textureFilePath = GetParentPath(GetName()) + imageElem.GetAttribute("source");
  296. ResourceCache* cache = GetSubsystem<ResourceCache>();
  297. SharedPtr<Texture2D> texture(cache->GetResource<Texture2D>(textureFilePath));
  298. if (!texture)
  299. {
  300. LOGERROR("Could not load texture " + textureFilePath);
  301. return false;
  302. }
  303. SharedPtr<Sprite2D> sprite(new Sprite2D(context_));
  304. sprite->SetTexture(texture);
  305. sprite->SetRectangle(IntRect(0, 0, texture->GetWidth(), texture->GetHeight()));
  306. // Left top
  307. sprite->SetHotSpot(Vector2(0.0f, 1.0f));
  308. imageLayer->sprite_ = sprite;
  309. if (element.HasChild("properties"))
  310. LoadProperties(element.GetChild("properties"), imageLayer->properties_);
  311. return true;
  312. }
  313. void TmxFile2D::LoadProperties(const XMLElement& element, HashMap<String, String>& peoperties)
  314. {
  315. for (XMLElement propertyElem = element.GetChild("property"); propertyElem; propertyElem = propertyElem.GetNext("property"))
  316. peoperties[propertyElem.GetAttribute("name")] = propertyElem.GetAttribute("value");
  317. }
  318. }