Tileson 1.4.0
A helpful json parser for Tiled maps
Loading...
Searching...
No Matches
tileson_forward.hpp
Go to the documentation of this file.
1//
2// Created by robin on 25.07.2020.
3//
4
5#ifndef TILESON_TILESON_FORWARD_HPP
6#define TILESON_TILESON_FORWARD_HPP
17// M a p . h p p
18// ----------------
19
21{
22 if(m_class == nullptr)
23 {
24 TiledClass* baseClass = (m_project != nullptr) ? m_project->getClass(m_classType) : nullptr;
25 if(baseClass != nullptr)
26 {
27 m_class = std::make_shared<TiledClass>(*baseClass);
28 m_class->update(m_properties);
29 }
30 }
31 return (m_class != nullptr) ? m_class.get() : nullptr;
32}
33
34// T i l e . h p p
35// ---------------------
36
43{
44 m_tileset = tileset;
45 m_map = map;
46
47 if(json.count("image") > 0) m_image = fs::path(json["image"].get<std::string>()); //Optional
48
49 bool allFound = parseId(json);
50
51 if(json.count("type") > 0) m_type = json["type"].get<std::string>(); //Optional
52 else if(json.count("class") > 0) m_type = json["class"].get<std::string>(); //Tiled v1.9 renamed 'type' to 'class'
53
54 if(json.count("objectgroup") > 0) m_objectgroup = tson::Layer(json["objectgroup"], m_map); //Optional
55
56 if(json.count("imagewidth") > 0 && json.count("imageheight") > 0)
57 m_imageSize = {json["imagewidth"].get<int>(), json["imageheight"].get<int>()}; //Optional
58
59 m_subRect = {0,0, m_imageSize.x, m_imageSize.y};
60 if(json.count("x") > 0) m_subRect.x = json["x"].get<int>(); //Optional
61 if(json.count("y") > 0) m_subRect.y = json["y"].get<int>(); //Optional
62 if(json.count("width") > 0) m_subRect.width = json["width"].get<int>(); //Optional
63 if(json.count("height") > 0) m_subRect.height = json["height"].get<int>(); //Optional
64
65 //More advanced data
66 if(json.count("animation") > 0 && json["animation"].isArray())
67 {
68 auto &animation = json.array("animation");
69 std::vector<tson::Frame> frames;
70 std::for_each(animation.begin(), animation.end(), [&](std::unique_ptr<IJson> &item) { frames.emplace_back(*item); });
71 if(frames.size() > 0)
72 {
73 m_animation.setFrames(frames);
74 }
75 }
76 if(json.count("terrain") > 0 && json["terrain"].isArray())
77 {
78 auto &terrain = json.array("terrain");
79 std::for_each(terrain.begin(), terrain.end(), [&](std::unique_ptr<IJson> &item) { m_terrain.emplace_back(item->get<int>()); });
80 }
81
82 if(json.count("properties") > 0 && json["properties"].isArray())
83 {
84 auto &properties = json.array("properties");
85 tson::Project *project = (m_map != nullptr) ? m_map->getProject() : nullptr;
86 std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item) { m_properties.add(*item, project); });
87 }
88
89 performDataCalculations();
90
91 return allFound;
92}
93
99{
100 if(m_map != nullptr)
101 return m_map->getTileSize();
102 else
103 return {0,0};
104}
105
107{
108 if(json.count("id") > 0)
109 {
110 m_id = json["id"].get<uint32_t>() + 1;
111 if (m_tileset != nullptr)
112 m_gid = m_tileset->getFirstgid() + m_id - 1;
113 else
114 m_gid = m_id;
115 manageFlipFlagsByIdThenRemoveFlags(m_gid);
116 return true;
117 }
118 return false;
119}
120
125void tson::Tile::performDataCalculations()
126{
127 if(m_tileset == nullptr || m_map == nullptr)
128 return;
129
130 int firstId = m_tileset->getFirstgid(); //First tile id of the tileset
131 int columns = m_tileset->getColumns();
132 int rows = m_tileset->getTileCount() / columns;
133 int lastId = (m_tileset->getFirstgid() + m_tileset->getTileCount()) - 1;
134
135 int const gid = static_cast<int>(getGid());
136 if (gid >= firstId && gid <= lastId)
137 {
138 int const baseTilePosition = (gid - firstId);
139
140 int const tileModX = (baseTilePosition % columns);
141 int const currentRow = (baseTilePosition / columns);
142 int const offsetX = (tileModX != 0) ? ((tileModX) * m_map->getTileSize().x) : (0 * m_map->getTileSize().x);
143 int const offsetY = (currentRow < rows-1) ? (currentRow * m_map->getTileSize().y) : ((rows-1) * m_map->getTileSize().y);
144
145 tson::Vector2i spacing = m_tileset->getMarginSpacingOffset({tileModX, currentRow});
146 m_drawingRect = { offsetX + spacing.x, offsetY + spacing.y, m_map->getTileSize().x, m_map->getTileSize().y };
147 }
148 else
149 m_drawingRect = {0, 0, 0, 0};
150}
151
156const tson::Vector2f tson::Tile::getPosition(const std::tuple<int, int> &tileDataPos)
157{
158 return {((float) std::get<0>(tileDataPos)) * m_drawingRect.width, ((float) std::get<1>(tileDataPos)) * m_drawingRect.height};
159}
160
167{
168 if(m_class == nullptr)
169 {
170 TiledClass* baseClass = (m_map != nullptr && m_map->getProject() != nullptr) ? m_map->getProject()->getClass(m_type) : nullptr;
171 if(baseClass != nullptr)
172 {
173 m_class = std::make_shared<TiledClass>(*baseClass);
174 m_class->update(m_properties);
175 }
176 }
177 return (m_class != nullptr) ? m_class.get() : nullptr;
178}
179
180// T i l e s e t . h p p
181// ------------------------
182
184{
185 if(m_class == nullptr)
186 {
187 TiledClass* baseClass = (m_map != nullptr && m_map->getProject() != nullptr) ? m_map->getProject()->getClass(m_classType) : nullptr;
188 if(baseClass != nullptr)
189 {
190 m_class = std::make_shared<TiledClass>(*baseClass);
191 m_class->update(m_properties);
192 }
193 }
194 return (m_class != nullptr) ? m_class.get() : nullptr;
195}
196
197// T i l e O b j e c t . h p p
198// ---------------------
199
206void tson::TileObject::initialize(const std::tuple<int, int> &posInTileUnits, tson::Tile *tile)
207{
208 m_tile = tile;
209 m_posInTileUnits = tile->getPositionInTileUnits(posInTileUnits);
210 m_position = tile->getPosition(posInTileUnits);
211}
212
214{
215 return m_tile->getDrawingRect();
216}
217
218// L a y e r . h p p
219// -------------------
220
224void tson::Layer::decompressData()
225{
226
227 tson::DecompressorContainer *container = m_map->getDecompressors();
228 if(container->empty())
229 return;
230
231 if(m_encoding.empty() && m_compression.empty())
232 return;
233
234 std::string data = m_base64Data;
235 bool hasBeenDecoded = false;
236 if(!m_encoding.empty() && container->contains(m_encoding))
237 {
238 data = container->get(m_encoding)->decompress(data);
239 hasBeenDecoded = true;
240 }
241
242 if(!m_compression.empty() && container->contains(m_compression))
243 {
244 data = container->get(m_compression)->decompress(data);
245 }
246
247 if(hasBeenDecoded)
248 {
249 std::vector<uint8_t> bytes = tson::Tools::Base64DecodedStringToBytes(data);
250 m_data = tson::Tools::BytesToUnsignedInts(bytes);
251 }
252}
253
260{
261 m_map = map;
262
263 bool allFound = true;
264 if(json.count("tintcolor") > 0) m_tintColor = tson::Colori(json["tintcolor"].get<std::string>()); //Optional
265 if(json.count("compression") > 0) m_compression = json["compression"].get<std::string>(); //Optional
266 if(json.count("draworder") > 0) m_drawOrder = json["draworder"].get<std::string>(); //Optional
267 if(json.count("encoding") > 0) m_encoding = json["encoding"].get<std::string>(); //Optional
268 if(json.count("id") > 0) m_id = json["id"].get<int>(); //Optional
269 if(json.count("image") > 0) m_image = json["image"].get<std::string>(); //Optional
270 if(json.count("name") > 0) m_name = json["name"].get<std::string>(); else allFound = false;
271 if(json.count("offsetx") > 0 && json.count("offsety") > 0)
272 m_offset = {json["offsetx"].get<float>(), json["offsety"].get<float>()}; //Optional
273 if(json.count("opacity") > 0) m_opacity = json["opacity"].get<float>(); else allFound = false;
274 if(json.count("width") > 0 && json.count("height") > 0)
275 m_size = {json["width"].get<int>(), json["height"].get<int>()}; //else allFound = false; - Not mandatory for all layers!
276 if(json.count("transparentcolor") > 0) m_transparentColor = tson::Colori(json["transparentcolor"].get<std::string>()); //Optional
277 if(json.count("type") > 0) m_typeStr = json["type"].get<std::string>(); else allFound = false;
278 if(json.count("class") > 0) m_classType = json["class"].get<std::string>(); //Optional
279 if(json.count("visible") > 0) m_visible = json["visible"].get<bool>(); else allFound = false;
280 if(json.count("x") > 0) m_x = json["x"].get<int>(); else allFound = false;
281 if(json.count("y") > 0) m_y = json["y"].get<int>(); else allFound = false;
282 if(json.count("repeatx") > 0) m_repeatX = json["repeatx"].get<bool>(); //Optional
283 if(json.count("repeaty") > 0) m_repeatY = json["repeaty"].get<bool>(); //Optional
284
285 tson::Vector2f parallax {1.f, 1.f};
286 if(json.count("parallaxx") > 0)
287 parallax.x = json["parallaxx"].get<float>();
288 if(json.count("parallaxy") > 0)
289 parallax.y = json["parallaxy"].get<float>();
290
291 m_parallax = parallax;
292
293 //Handle DATA (Optional)
294 if(json.count("data") > 0)
295 {
296 if(json["data"].isArray())
297 {
298 auto &array = json.array("data");
299 std::for_each(array.begin(), array.end(), [&](std::unique_ptr<IJson> &item) { m_data.push_back(item->get<uint32_t>()); });
300 }
301 else
302 {
303 m_base64Data = json["data"].get<std::string>();
304 decompressData();
305 }
306 }
307
308 //More advanced data
309 if(json.count("chunks") > 0 && json["chunks"].isArray())
310 {
311 auto &chunks = json.array("chunks");
312 std::for_each(chunks.begin(), chunks.end(), [&](std::unique_ptr<IJson> &item) { m_chunks.emplace_back(*item); });
313 }
314 if(json.count("layers") > 0 && json["layers"].isArray())
315 {
316 auto &layers = json.array("layers");
317 std::for_each(layers.begin(), layers.end(), [&](std::unique_ptr<IJson> &item) { m_layers.emplace_back(*item, m_map); });
318 }
319 if(json.count("objects") > 0 && json["objects"].isArray())
320 {
321 auto &objects = json.array("objects");
322 std::for_each(objects.begin(), objects.end(), [&](std::unique_ptr<IJson> &item) { m_objects.emplace_back(*item, m_map); });
323 }
324 if(json.count("properties") > 0 && json["properties"].isArray())
325 {
326 auto &properties = json.array("properties");
327 tson::Project *project = (m_map != nullptr) ? m_map->getProject() : nullptr;
328 std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item) { m_properties.add(*item, project); });
329 }
330
331 setTypeByString();
332
333 return allFound;
334}
335
337{
338 if(m_class == nullptr)
339 {
340 TiledClass* baseClass = (m_map != nullptr && m_map->getProject() != nullptr) ? m_map->getProject()->getClass(m_classType) : nullptr;
341 if(baseClass != nullptr)
342 {
343 m_class = std::make_shared<TiledClass>(*baseClass);
344 m_class->update(m_properties);
345 }
346 }
347 return (m_class != nullptr) ? m_class.get() : nullptr;
348}
349
350// O b j e c t . h p p
351// --------------------
352
353
361 tson::IJson* tson::readField(const std::string& fieldName, IJson& main, IJson* templ)
362{
363 if(main.count(fieldName) > 0)
364 {
365 return &main[fieldName];
366 } else if (templ && templ->count(fieldName) > 0)
367 {
368 return &(*templ)[fieldName];
369 }
370
371 return nullptr;
372}
373
374
382bool tson::readField(Text& field, const std::string& fieldName, IJson& main, IJson* templ)
383{
384 IJson* fieldJson = readField(fieldName, main, templ);
385 if(fieldJson){
386 field = tson::Text(*fieldJson);
387 return true;
388 }
389 return false;
390}
391
399bool tson::readField(std::vector<Vector2i>& field, const std::string& fieldName, IJson& main, IJson* templ)
400{
401 IJson* fieldJson = readField(fieldName, main, templ);
402 if(fieldJson && fieldJson->isArray())
403 {
404 auto polyline = fieldJson->array();
405 std::for_each(polyline.begin(), polyline.end(),[&field](std::unique_ptr<IJson> &item)
406 {
407 IJson &j = *item;
408 field.emplace_back(j["x"].get<int>(), j["y"].get<int>());
409 });
410 return true;
411 }
412 return false;
413}
414
424bool tson::readVector(Vector2i& field, const std::string& fieldNameX, const std::string& fieldNameY, IJson& main, IJson* templ)
425{
426 int x = 0, y = 0;
427 if(readField(x, fieldNameX, main, templ) && readField(y, fieldNameY, main, templ))
428 {
429 field = {x, y};
430 return true;
431 }
432 return false;
433}
434
442{
443 if(json.count("properties") > 0 && json["properties"].isArray())
444 {
445 auto &props = json.array("properties");
446 tson::Project *project = (map != nullptr) ? map->getProject() : nullptr;
447 std::for_each(props.begin(), props.end(), [&](std::unique_ptr<IJson> &item)
448 {
449 properties.add(*item, project);
450 });
451 }
452}
453
461void tson::readGid(uint32_t& gid, TileFlipFlags& flags, IJson& main, IJson* templ)
462{
463 uint32_t g;
464 if(readField(g, "gid", main, templ))
465 {
466 if (g & FLIPPED_HORIZONTALLY_FLAG) flags |= TileFlipFlags::Horizontally;
467 if (g & FLIPPED_VERTICALLY_FLAG) flags |= TileFlipFlags::Vertically;
468 if (g & FLIPPED_DIAGONALLY_FLAG) flags |= TileFlipFlags::Diagonally;
469
470 // Clear flags
471 g &= ~(FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG);
472
473 gid = g;
474 }
475}
476
477
485{
486 m_map = map;
487 bool allFound = true;
488 IJson* templateJson = nullptr;
489
490 if(readField(m_template, "template", json) && map != nullptr)
491 {
492 IJson* tobjJsonFile = map->parseLinkedFile(m_template);
493 if(tobjJsonFile)
494 templateJson = readField("object", *tobjJsonFile);
495 }
496
497 readField(m_ellipse, "ellipse", json, templateJson); //Optional
498 readField(m_point, "point", json, templateJson); // Optional
499 readField(m_text, "text", json, templateJson);
500 readGid(m_gid, m_flipFlags, json, templateJson);
501
502 allFound &= readField(m_id, "id", json, templateJson);
503 allFound &= readField(m_name, "name", json, templateJson);
504 allFound &= readField(m_rotation, "rotation", json, templateJson);
505 allFound &= readField(m_type, "type", json, templateJson) || readField(m_type, "class", json, templateJson); //Tiled v1.9 renamed 'type' to 'class'
506 allFound &= readField(m_visible, "visible", json, templateJson);
507 allFound &= readVector(m_size, "width", "height", json, templateJson);
508 allFound &= readVector(m_position, "x", "y", json, templateJson);
509
510 setObjectTypeByJson(json, templateJson);
511
512 if(m_objectType == ObjectType::Template)
513 allFound = true; //Just accept anything with this type
514
515 //More advanced data
516 readField(m_polygon, "polygon", json, templateJson);
517 readField(m_polyline, "polyline", json, templateJson);
518
519 // merge properties with template's.
520 if(templateJson) readProperties(m_properties, *templateJson, m_map);
521 readProperties(m_properties, json, m_map);
522
523 return allFound;
524}
525
526// W a n g s e t . h p p
527// ----------------------
529{
530 if(m_class == nullptr)
531 {
532 TiledClass* baseClass = (m_map != nullptr && m_map->getProject() != nullptr) ? m_map->getProject()->getClass(m_classType) : nullptr;
533 if(baseClass != nullptr)
534 {
535 m_class = std::make_shared<TiledClass>(*baseClass);
536 m_class->update(m_properties);
537 }
538 }
539 return (m_class != nullptr) ? m_class.get() : nullptr;
540}
541
542// W a n g c o l o r . h p p
543// ----------------------
545{
546 if(m_class == nullptr)
547 {
548 TiledClass* baseClass = (m_map != nullptr && m_map->getProject() != nullptr) ? m_map->getProject()->getClass(m_classType) : nullptr;
549 if(baseClass != nullptr)
550 {
551 m_class = std::make_shared<TiledClass>(*baseClass);
552 m_class->update(m_properties);
553 }
554 }
555 return (m_class != nullptr) ? m_class.get() : nullptr;
556}
557
564{
565 if(m_class == nullptr)
566 {
567 TiledClass* baseClass = (m_map != nullptr && m_map->getProject() != nullptr) ? m_map->getProject()->getClass(m_type) : nullptr;
568 if(baseClass != nullptr)
569 {
570 m_class = std::make_shared<TiledClass>(*baseClass);//, m_map->getProject());
571 m_class->update(m_properties);
572 }
573 }
574 return (m_class != nullptr) ? m_class.get() : nullptr;
575}
576
577// W o r l d . h p p
578// ------------------
579
587{
588 m_maps.clear();
589 std::for_each(m_mapData.begin(), m_mapData.end(), [&](const tson::WorldMapData &data)
590 {
591 if(fs::exists(data.path))
592 {
593 std::unique_ptr<tson::Map> map = parser->parse(data.path);
594 m_maps.push_back(std::move(map));
595 }
596 });
597
598 return m_maps.size();
599}
600
601// P r o p e r t y . h p p
602// ------------------
604{
605 switch(m_type)
606 {
607 case Type::Color:
608 m_value = Colori(json.get<std::string>());
609 break;
610
611 case Type::File:
612 m_value = fs::path(json.get<std::string>());
613 break;
614
615 case Type::Int:
616 if(!m_propertyType.empty())
617 {
618 m_type = Type::Enum;
619 tson::EnumDefinition *def = (m_project != nullptr) ? m_project->getEnumDefinition(m_propertyType) : nullptr;
620 if(def != nullptr)
621 {
622 uint32_t v = json.get<uint32_t>();
623 m_value = tson::EnumValue(v, def);
624 }
625 else
626 m_value = tson::EnumValue();
627 }
628 else
629 m_value = json.get<int>();
630
631 break;
632
633 case Type::Boolean:
634 m_value = json.get<bool>();
635 break;
636
637 case Type::Float:
638 m_value = json.get<float>();
639 break;
640
641 case Type::String:
642 if(!m_propertyType.empty())
643 {
644 m_type = Type::Enum;
645 tson::EnumDefinition *def = (m_project != nullptr) ? m_project->getEnumDefinition(m_propertyType) : nullptr;
646 if(def != nullptr)
647 {
648 std::string v = json.get<std::string>();
649 m_value = tson::EnumValue(v, def);
650 }
651 else
652 m_value = tson::EnumValue();
653 }
654 else
655 setStrValue(json.get<std::string>());
656
657 break;
658
659 case Type::Class:
660 {
661 tson::TiledClass *baseClass = (m_project != nullptr) ? m_project->getClass(m_propertyType) : nullptr;
662 if (baseClass != nullptr)
663 {
664 tson::TiledClass c = *baseClass;
665 c.update(json);
666 m_value = c;
667 }
668 }
669 break;
670
671 case Type::Object:
672 m_value = json.get<uint32_t>();
673 break;
674 default:
675 setStrValue(json.get<std::string>());
676 break;
677 }
678}
679
680
681#endif //TILESON_TILESON_FORWARD_HPP
Definition DecompressorContainer.hpp:16
bool contains(std::string_view name) const
Definition DecompressorContainer.hpp:44
bool empty() const
Definition DecompressorContainer.hpp:91
IDecompressor< std::string_view, std::string > * get(std::string_view name)
Definition DecompressorContainer.hpp:77
Definition TiledEnum.hpp:11
Definition TiledEnum.hpp:160
virtual TOut decompress(const TIn &input)=0
Definition IJson.hpp:11
T get(std::string_view key)
Definition IJson.hpp:82
virtual bool isArray() const =0
virtual size_t count(std::string_view key) const =0
virtual std::vector< std::unique_ptr< IJson > > array()=0
Definition Layer.hpp:26
bool parse(IJson &json, tson::Map *map)
Definition tileson_forward.hpp:259
tson::TiledClass * getClass()
Definition tileson_forward.hpp:336
Definition Map.hpp:29
tson::TiledClass * getClass()
Definition tileson_forward.hpp:20
Project * getProject()
Definition Map.hpp:590
bool parse(IJson &json, tson::Map *map)
Definition tileson_forward.hpp:484
tson::TiledClass * getClass()
Definition tileson_forward.hpp:563
Definition Project.hpp:20
tson::TiledClass * getClass(std::string_view name)
Definition Project.hpp:136
Definition PropertyCollection.hpp:15
void setValueByType(IJson &json)
Definition tileson_forward.hpp:603
Definition Rect.hpp:11
Definition Text.hpp:13
const tson::Rect & getDrawingRect() const
Definition tileson_forward.hpp:213
void initialize(const std::tuple< int, int > &posInTileUnits, tson::Tile *tile)
Definition tileson_forward.hpp:206
Definition Tile.hpp:23
const tson::Vector2f getPosition(const std::tuple< int, int > &tileDataPos)
Definition tileson_forward.hpp:156
const tson::Vector2i getTileSize() const
Definition tileson_forward.hpp:98
bool parseId(IJson &json)
Definition tileson_forward.hpp:106
bool parse(IJson &json, tson::Tileset *tileset, tson::Map *map)
Definition tileson_forward.hpp:42
const tson::Vector2i getPositionInTileUnits(const std::tuple< int, int > &tileDataPos)
Definition Tile.hpp:276
tson::TiledClass * getClass()
Definition tileson_forward.hpp:166
Definition TiledClass.hpp:11
void update(IJson &json)
Definition TiledClass.hpp:92
Definition Tileset.hpp:24
tson::TiledClass * getClass()
Definition tileson_forward.hpp:183
Definition tileson_parser.hpp:56
static std::vector< uint8_t > Base64DecodedStringToBytes(std::string_view str)
Definition Tools.hpp:44
static std::vector< uint32_t > BytesToUnsignedInts(const std::vector< uint8_t > &bytes)
Definition Tools.hpp:60
T y
Definition Vector2.hpp:22
T x
Definition Vector2.hpp:21
tson::TiledClass * getClass()
Definition tileson_forward.hpp:544
tson::TiledClass * getClass()
Definition tileson_forward.hpp:528
Definition WorldMapData.hpp:11
std::size_t loadMaps(tson::Tileson *parser)
Definition tileson_forward.hpp:586
bool readVector(Vector2i &field, const std::string &fieldNameX, const std::string &fieldNameY, IJson &main, IJson *templ=nullptr)
Definition tileson_forward.hpp:424
IJson * readField(const std::string &fieldName, IJson &main, IJson *templ=nullptr)
Definition tileson_forward.hpp:361
void readGid(uint32_t &gid, TileFlipFlags &flags, IJson &main, IJson *templ=nullptr)
Definition tileson_forward.hpp:461
TileFlipFlags
Definition Enums.hpp:77
Color< uint8_t > Colori
Definition Color.hpp:89
void readProperties(tson::PropertyCollection &properties, IJson &json, tson::Map *map)
Definition tileson_forward.hpp:441