diff options
author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2021-02-02 13:01:35 -0500 |
---|---|---|
committer | Kelly Rauchenberger <fefferburbia@gmail.com> | 2021-02-02 13:01:35 -0500 |
commit | 7166c9b831f9c6a50ba42272682b776d01e5703e (patch) | |
tree | b27c4b695a8cd5f64c680e358bb919e86ef7cd74 /vendor | |
parent | 362c332000a65acc060660dcb6bb0ec6f99cbafe (diff) | |
download | tanetane-7166c9b831f9c6a50ba42272682b776d01e5703e.tar.gz tanetane-7166c9b831f9c6a50ba42272682b776d01e5703e.tar.bz2 tanetane-7166c9b831f9c6a50ba42272682b776d01e5703e.zip |
Map rendering Works but I don't want to use Tileson so I'm gonna change that
Mainly bc Tileson requires std::filesystem, which my clang is too old for apparently, and while I can use gcc instead I just want to not, I suppose. Also Tileson's API is very weird RE const correctness? Idk. And also being able to parse the tmx files rather than exporting to json would be preferable.
Diffstat (limited to 'vendor')
-rw-r--r-- | vendor/tileson.hpp | 7391 |
1 files changed, 7391 insertions, 0 deletions
diff --git a/vendor/tileson.hpp b/vendor/tileson.hpp new file mode 100644 index 0000000..f8545ed --- /dev/null +++ b/vendor/tileson.hpp | |||
@@ -0,0 +1,7391 @@ | |||
1 | /// | ||
2 | /// T I L E S O N V E R S I O N 1 . 3 . 0 | ||
3 | /// ------------------------------------------------ | ||
4 | /// BSD 2-Clause License | ||
5 | /// | ||
6 | /// Copyright (c) 2020, Robin Berg Pettersen | ||
7 | /// All rights reserved. | ||
8 | /// | ||
9 | /// Redistribution and use in source and binary forms, with or without | ||
10 | /// modification, are permitted provided that the following conditions are met: | ||
11 | /// | ||
12 | /// 1. Redistributions of source code must retain the above copyright notice, this | ||
13 | /// list of conditions and the following disclaimer. | ||
14 | /// | ||
15 | /// 2. Redistributions in binary form must reproduce the above copyright notice, | ||
16 | /// this list of conditions and the following disclaimer in the documentation | ||
17 | /// and/or other materials provided with the distribution. | ||
18 | /// | ||
19 | /// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
20 | /// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | /// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
22 | /// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
23 | /// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | /// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
25 | /// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
26 | /// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
27 | /// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
28 | /// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
29 | |||
30 | #ifndef TILESON_TILESON_H | ||
31 | #define TILESON_TILESON_H | ||
32 | |||
33 | |||
34 | /*** Start of inlined file: json11.hpp ***/ | ||
35 | /*** Start of inlined file: json11.cpp ***/ | ||
36 | |||
37 | /*** Start of inlined file: json11.hpp ***/ | ||
38 | /* Copyright (c) 2013 Dropbox, Inc. | ||
39 | * | ||
40 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
41 | * of this software and associated documentation files (the "Software"), to deal | ||
42 | * in the Software without restriction, including without limitation the rights | ||
43 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
44 | * copies of the Software, and to permit persons to whom the Software is | ||
45 | * furnished to do so, subject to the following conditions: | ||
46 | * | ||
47 | * The above copyright notice and this permission notice shall be included in | ||
48 | * all copies or substantial portions of the Software. | ||
49 | * | ||
50 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
51 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
52 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
53 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
54 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
55 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
56 | * THE SOFTWARE. | ||
57 | */ | ||
58 | |||
59 | #pragma once | ||
60 | |||
61 | #include <string> | ||
62 | #include <vector> | ||
63 | #include <map> | ||
64 | #include <memory> | ||
65 | #include <initializer_list> | ||
66 | |||
67 | #define JSON11_IS_DEFINED | ||
68 | |||
69 | #ifdef _MSC_VER | ||
70 | #if _MSC_VER <= 1800 // VS 2013 | ||
71 | #ifndef noexcept | ||
72 | #define noexcept throw() | ||
73 | #endif | ||
74 | |||
75 | #ifndef snprintf | ||
76 | #define snprintf _snprintf_s | ||
77 | #endif | ||
78 | #endif | ||
79 | #endif | ||
80 | |||
81 | namespace json11 { | ||
82 | |||
83 | enum JsonParse { | ||
84 | STANDARD, COMMENTS | ||
85 | }; | ||
86 | |||
87 | class JsonValue; | ||
88 | |||
89 | class Json final { | ||
90 | public: | ||
91 | // Types | ||
92 | enum Type { | ||
93 | NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT | ||
94 | }; | ||
95 | |||
96 | // Array and object typedefs | ||
97 | typedef std::vector<Json> array; | ||
98 | typedef std::map<std::string, Json> object; | ||
99 | |||
100 | // Constructors for the various types of JSON value. | ||
101 | inline Json() noexcept; // NUL | ||
102 | inline Json(std::nullptr_t) noexcept; // NUL | ||
103 | inline Json(double value); // NUMBER | ||
104 | inline Json(int value); // NUMBER | ||
105 | inline Json(bool value); // BOOL | ||
106 | inline Json(const std::string &value); // STRING | ||
107 | inline Json(std::string &&value); // STRING | ||
108 | inline Json(const char * value); // STRING | ||
109 | inline Json(const array &values); // ARRAY | ||
110 | inline Json(array &&values); // ARRAY | ||
111 | inline Json(const object &values); // OBJECT | ||
112 | inline Json(object &&values); // OBJECT | ||
113 | |||
114 | // Implicit constructor: anything with a to_json() function. | ||
115 | template <class T, class = decltype(&T::to_json)> | ||
116 | inline Json(const T & t) : Json(t.to_json()) {} | ||
117 | |||
118 | // Implicit constructor: map-like objects (std::map, std::unordered_map, etc) | ||
119 | template <class M, typename std::enable_if< | ||
120 | std::is_constructible<std::string, decltype(std::declval<M>().begin()->first)>::value | ||
121 | && std::is_constructible<Json, decltype(std::declval<M>().begin()->second)>::value, | ||
122 | int>::type = 0> | ||
123 | inline Json(const M & m) : Json(object(m.begin(), m.end())) {} | ||
124 | |||
125 | // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc) | ||
126 | template <class V, typename std::enable_if< | ||
127 | std::is_constructible<Json, decltype(*std::declval<V>().begin())>::value, | ||
128 | int>::type = 0> | ||
129 | inline Json(const V & v) : Json(array(v.begin(), v.end())) {} | ||
130 | |||
131 | // This prevents Json(some_pointer) from accidentally producing a bool. Use | ||
132 | // Json(bool(some_pointer)) if that behavior is desired. | ||
133 | Json(void *) = delete; | ||
134 | |||
135 | // Accessors | ||
136 | inline Type type() const; | ||
137 | |||
138 | inline bool is_null() const { return type() == NUL; } | ||
139 | inline bool is_number() const { return type() == NUMBER; } | ||
140 | inline bool is_bool() const { return type() == BOOL; } | ||
141 | inline bool is_string() const { return type() == STRING; } | ||
142 | inline bool is_array() const { return type() == ARRAY; } | ||
143 | inline bool is_object() const { return type() == OBJECT; } | ||
144 | |||
145 | // Return the enclosed value if this is a number, 0 otherwise. Note that json11 does not | ||
146 | // distinguish between integer and non-integer numbers - number_value() and int_value() | ||
147 | // can both be applied to a NUMBER-typed object. | ||
148 | inline double number_value() const; | ||
149 | inline int int_value() const; | ||
150 | |||
151 | // Return the enclosed value if this is a boolean, false otherwise. | ||
152 | inline bool bool_value() const; | ||
153 | // Return the enclosed string if this is a string, "" otherwise. | ||
154 | inline const std::string &string_value() const; | ||
155 | // Return the enclosed std::vector if this is an array, or an empty vector otherwise. | ||
156 | inline const array &array_items() const; | ||
157 | // Return the enclosed std::map if this is an object, or an empty map otherwise. | ||
158 | inline const object &object_items() const; | ||
159 | |||
160 | // Return a reference to arr[i] if this is an array, Json() otherwise. | ||
161 | inline const Json & operator[](size_t i) const; | ||
162 | // Return a reference to obj[key] if this is an object, Json() otherwise. | ||
163 | inline const Json & operator[](const std::string &key) const; | ||
164 | |||
165 | // Serialize. | ||
166 | inline void dump(std::string &out) const; | ||
167 | inline std::string dump() const { | ||
168 | std::string out; | ||
169 | dump(out); | ||
170 | return out; | ||
171 | } | ||
172 | |||
173 | // Parse. If parse fails, return Json() and assign an error message to err. | ||
174 | static inline Json parse(const std::string & in, | ||
175 | std::string & err, | ||
176 | JsonParse strategy = JsonParse::STANDARD); | ||
177 | static inline Json parse(const char * in, | ||
178 | std::string & err, | ||
179 | JsonParse strategy = JsonParse::STANDARD) { | ||
180 | if (in) { | ||
181 | return parse(std::string(in), err, strategy); | ||
182 | } else { | ||
183 | err = "null input"; | ||
184 | return nullptr; | ||
185 | } | ||
186 | } | ||
187 | // Parse multiple objects, concatenated or separated by whitespace | ||
188 | static inline std::vector<Json> parse_multi( | ||
189 | const std::string & in, | ||
190 | std::string::size_type & parser_stop_pos, | ||
191 | std::string & err, | ||
192 | JsonParse strategy = JsonParse::STANDARD); | ||
193 | |||
194 | static inline std::vector<Json> parse_multi( | ||
195 | const std::string & in, | ||
196 | std::string & err, | ||
197 | JsonParse strategy = JsonParse::STANDARD) { | ||
198 | std::string::size_type parser_stop_pos; | ||
199 | return parse_multi(in, parser_stop_pos, err, strategy); | ||
200 | } | ||
201 | |||
202 | inline bool operator== (const Json &rhs) const; | ||
203 | inline bool operator< (const Json &rhs) const; | ||
204 | inline bool operator!= (const Json &rhs) const { return !(*this == rhs); } | ||
205 | inline bool operator<= (const Json &rhs) const { return !(rhs < *this); } | ||
206 | inline bool operator> (const Json &rhs) const { return (rhs < *this); } | ||
207 | inline bool operator>= (const Json &rhs) const { return !(*this < rhs); } | ||
208 | |||
209 | /* has_shape(types, err) | ||
210 | * | ||
211 | * Return true if this is a JSON object and, for each item in types, has a field of | ||
212 | * the given type. If not, return false and set err to a descriptive message. | ||
213 | */ | ||
214 | typedef std::initializer_list<std::pair<std::string, Type>> shape; | ||
215 | inline bool has_shape(const shape & types, std::string & err) const; | ||
216 | |||
217 | private: | ||
218 | std::shared_ptr<JsonValue> m_ptr; | ||
219 | }; | ||
220 | |||
221 | // Internal class hierarchy - JsonValue objects are not exposed to users of this API. | ||
222 | class JsonValue { | ||
223 | protected: | ||
224 | friend class Json; | ||
225 | friend class JsonInt; | ||
226 | friend class JsonDouble; | ||
227 | virtual Json::Type type() const = 0; | ||
228 | virtual bool equals(const JsonValue * other) const = 0; | ||
229 | virtual bool less(const JsonValue * other) const = 0; | ||
230 | virtual void dump(std::string &out) const = 0; | ||
231 | virtual double number_value() const; | ||
232 | virtual int int_value() const; | ||
233 | virtual bool bool_value() const; | ||
234 | virtual const std::string &string_value() const; | ||
235 | virtual const Json::array &array_items() const; | ||
236 | virtual const Json &operator[](size_t i) const; | ||
237 | virtual const Json::object &object_items() const; | ||
238 | virtual const Json &operator[](const std::string &key) const; | ||
239 | virtual ~JsonValue() {} | ||
240 | }; | ||
241 | |||
242 | } // namespace json11 | ||
243 | |||
244 | /*** End of inlined file: json11.hpp ***/ | ||
245 | |||
246 | #include <cassert> | ||
247 | #include <cmath> | ||
248 | #include <cstdlib> | ||
249 | #include <cstdio> | ||
250 | #include <limits> | ||
251 | |||
252 | namespace json11 { | ||
253 | |||
254 | static const int max_depth = 200; | ||
255 | |||
256 | using std::string; | ||
257 | using std::vector; | ||
258 | using std::map; | ||
259 | using std::make_shared; | ||
260 | using std::initializer_list; | ||
261 | using std::move; | ||
262 | |||
263 | /* Helper for representing null - just a do-nothing struct, plus comparison | ||
264 | * operators so the helpers in JsonValue work. We can't use nullptr_t because | ||
265 | * it may not be orderable. | ||
266 | */ | ||
267 | struct NullStruct { | ||
268 | bool operator==(NullStruct) const { return true; } | ||
269 | bool operator<(NullStruct) const { return false; } | ||
270 | }; | ||
271 | |||
272 | /* * * * * * * * * * * * * * * * * * * * | ||
273 | * Serialization | ||
274 | */ | ||
275 | |||
276 | static void dump(NullStruct, string &out) { | ||
277 | out += "null"; | ||
278 | } | ||
279 | |||
280 | static void dump(double value, string &out) { | ||
281 | if (std::isfinite(value)) { | ||
282 | char buf[32]; | ||
283 | snprintf(buf, sizeof buf, "%.17g", value); | ||
284 | out += buf; | ||
285 | } else { | ||
286 | out += "null"; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | static void dump(int value, string &out) { | ||
291 | char buf[32]; | ||
292 | snprintf(buf, sizeof buf, "%d", value); | ||
293 | out += buf; | ||
294 | } | ||
295 | |||
296 | static void dump(bool value, string &out) { | ||
297 | out += value ? "true" : "false"; | ||
298 | } | ||
299 | |||
300 | static void dump(const string &value, string &out) { | ||
301 | out += '"'; | ||
302 | for (size_t i = 0; i < value.length(); i++) { | ||
303 | const char ch = value[i]; | ||
304 | if (ch == '\\') { | ||
305 | out += "\\\\"; | ||
306 | } else if (ch == '"') { | ||
307 | out += "\\\""; | ||
308 | } else if (ch == '\b') { | ||
309 | out += "\\b"; | ||
310 | } else if (ch == '\f') { | ||
311 | out += "\\f"; | ||
312 | } else if (ch == '\n') { | ||
313 | out += "\\n"; | ||
314 | } else if (ch == '\r') { | ||
315 | out += "\\r"; | ||
316 | } else if (ch == '\t') { | ||
317 | out += "\\t"; | ||
318 | } else if (static_cast<uint8_t>(ch) <= 0x1f) { | ||
319 | char buf[8]; | ||
320 | snprintf(buf, sizeof buf, "\\u%04x", ch); | ||
321 | out += buf; | ||
322 | } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80 | ||
323 | && static_cast<uint8_t>(value[i+2]) == 0xa8) { | ||
324 | out += "\\u2028"; | ||
325 | i += 2; | ||
326 | } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80 | ||
327 | && static_cast<uint8_t>(value[i+2]) == 0xa9) { | ||
328 | out += "\\u2029"; | ||
329 | i += 2; | ||
330 | } else { | ||
331 | out += ch; | ||
332 | } | ||
333 | } | ||
334 | out += '"'; | ||
335 | } | ||
336 | |||
337 | static void dump(const Json::array &values, string &out) { | ||
338 | bool first = true; | ||
339 | out += "["; | ||
340 | for (const auto &value : values) { | ||
341 | if (!first) | ||
342 | out += ", "; | ||
343 | value.dump(out); | ||
344 | first = false; | ||
345 | } | ||
346 | out += "]"; | ||
347 | } | ||
348 | |||
349 | static void dump(const Json::object &values, string &out) { | ||
350 | bool first = true; | ||
351 | out += "{"; | ||
352 | for (const auto &kv : values) { | ||
353 | if (!first) | ||
354 | out += ", "; | ||
355 | dump(kv.first, out); | ||
356 | out += ": "; | ||
357 | kv.second.dump(out); | ||
358 | first = false; | ||
359 | } | ||
360 | out += "}"; | ||
361 | } | ||
362 | |||
363 | void Json::dump(string &out) const { | ||
364 | m_ptr->dump(out); | ||
365 | } | ||
366 | |||
367 | /* * * * * * * * * * * * * * * * * * * * | ||
368 | * Value wrappers | ||
369 | */ | ||
370 | |||
371 | template <Json::Type tag, typename T> | ||
372 | class Value : public JsonValue { | ||
373 | protected: | ||
374 | |||
375 | // Constructors | ||
376 | explicit Value(const T &value) : m_value(value) {} | ||
377 | explicit Value(T &&value) : m_value(move(value)) {} | ||
378 | |||
379 | // Get type tag | ||
380 | Json::Type type() const override { | ||
381 | return tag; | ||
382 | } | ||
383 | |||
384 | // Comparisons | ||
385 | bool equals(const JsonValue * other) const override { | ||
386 | return m_value == static_cast<const Value<tag, T> *>(other)->m_value; | ||
387 | } | ||
388 | bool less(const JsonValue * other) const override { | ||
389 | return m_value < static_cast<const Value<tag, T> *>(other)->m_value; | ||
390 | } | ||
391 | |||
392 | const T m_value; | ||
393 | void dump(string &out) const override { json11::dump(m_value, out); } | ||
394 | }; | ||
395 | |||
396 | class JsonDouble final : public Value<Json::NUMBER, double> { | ||
397 | double number_value() const override { return m_value; } | ||
398 | int int_value() const override { return static_cast<int>(m_value); } | ||
399 | bool equals(const JsonValue * other) const override { return m_value == other->number_value(); } | ||
400 | bool less(const JsonValue * other) const override { return m_value < other->number_value(); } | ||
401 | public: | ||
402 | explicit JsonDouble(double value) : Value(value) {} | ||
403 | }; | ||
404 | |||
405 | class JsonInt final : public Value<Json::NUMBER, int> { | ||
406 | double number_value() const override { return m_value; } | ||
407 | int int_value() const override { return m_value; } | ||
408 | bool equals(const JsonValue * other) const override { return m_value == other->number_value(); } | ||
409 | bool less(const JsonValue * other) const override { return m_value < other->number_value(); } | ||
410 | public: | ||
411 | explicit JsonInt(int value) : Value(value) {} | ||
412 | }; | ||
413 | |||
414 | class JsonBoolean final : public Value<Json::BOOL, bool> { | ||
415 | bool bool_value() const override { return m_value; } | ||
416 | public: | ||
417 | explicit JsonBoolean(bool value) : Value(value) {} | ||
418 | }; | ||
419 | |||
420 | class JsonString final : public Value<Json::STRING, string> { | ||
421 | const string &string_value() const override { return m_value; } | ||
422 | public: | ||
423 | explicit JsonString(const string &value) : Value(value) {} | ||
424 | explicit JsonString(string &&value) : Value(move(value)) {} | ||
425 | }; | ||
426 | |||
427 | class JsonArray final : public Value<Json::ARRAY, Json::array> { | ||
428 | const Json::array &array_items() const override { return m_value; } | ||
429 | const Json & operator[](size_t i) const override; | ||
430 | public: | ||
431 | explicit JsonArray(const Json::array &value) : Value(value) {} | ||
432 | explicit JsonArray(Json::array &&value) : Value(move(value)) {} | ||
433 | }; | ||
434 | |||
435 | class JsonObject final : public Value<Json::OBJECT, Json::object> { | ||
436 | const Json::object &object_items() const override { return m_value; } | ||
437 | const Json & operator[](const string &key) const override; | ||
438 | public: | ||
439 | explicit JsonObject(const Json::object &value) : Value(value) {} | ||
440 | explicit JsonObject(Json::object &&value) : Value(move(value)) {} | ||
441 | }; | ||
442 | |||
443 | class JsonNull final : public Value<Json::NUL, NullStruct> { | ||
444 | public: | ||
445 | JsonNull() : Value({}) {} | ||
446 | }; | ||
447 | |||
448 | /* * * * * * * * * * * * * * * * * * * * | ||
449 | * Static globals - static-init-safe | ||
450 | */ | ||
451 | struct Statics { | ||
452 | const std::shared_ptr<JsonValue> null = make_shared<JsonNull>(); | ||
453 | const std::shared_ptr<JsonValue> t = make_shared<JsonBoolean>(true); | ||
454 | const std::shared_ptr<JsonValue> f = make_shared<JsonBoolean>(false); | ||
455 | const string empty_string; | ||
456 | const vector<Json> empty_vector; | ||
457 | const map<string, Json> empty_map; | ||
458 | Statics() {} | ||
459 | }; | ||
460 | |||
461 | static const Statics & statics() { | ||
462 | static const Statics s {}; | ||
463 | return s; | ||
464 | } | ||
465 | |||
466 | static const Json & static_null() { | ||
467 | // This has to be separate, not in Statics, because Json() accesses statics().null. | ||
468 | static const Json json_null; | ||
469 | return json_null; | ||
470 | } | ||
471 | |||
472 | /* * * * * * * * * * * * * * * * * * * * | ||
473 | * Constructors | ||
474 | */ | ||
475 | |||
476 | Json::Json() noexcept : m_ptr(statics().null) {} | ||
477 | Json::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {} | ||
478 | Json::Json(double value) : m_ptr(make_shared<JsonDouble>(value)) {} | ||
479 | Json::Json(int value) : m_ptr(make_shared<JsonInt>(value)) {} | ||
480 | Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {} | ||
481 | Json::Json(const string &value) : m_ptr(make_shared<JsonString>(value)) {} | ||
482 | Json::Json(string &&value) : m_ptr(make_shared<JsonString>(move(value))) {} | ||
483 | Json::Json(const char * value) : m_ptr(make_shared<JsonString>(value)) {} | ||
484 | Json::Json(const Json::array &values) : m_ptr(make_shared<JsonArray>(values)) {} | ||
485 | Json::Json(Json::array &&values) : m_ptr(make_shared<JsonArray>(move(values))) {} | ||
486 | Json::Json(const Json::object &values) : m_ptr(make_shared<JsonObject>(values)) {} | ||
487 | Json::Json(Json::object &&values) : m_ptr(make_shared<JsonObject>(move(values))) {} | ||
488 | |||
489 | /* * * * * * * * * * * * * * * * * * * * | ||
490 | * Accessors | ||
491 | */ | ||
492 | |||
493 | inline Json::Type Json::type() const { return m_ptr->type(); } | ||
494 | inline double Json::number_value() const { return m_ptr->number_value(); } | ||
495 | inline int Json::int_value() const { return m_ptr->int_value(); } | ||
496 | inline bool Json::bool_value() const { return m_ptr->bool_value(); } | ||
497 | inline const string & Json::string_value() const { return m_ptr->string_value(); } | ||
498 | inline const vector<Json> & Json::array_items() const { return m_ptr->array_items(); } | ||
499 | inline const map<string, Json> & Json::object_items() const { return m_ptr->object_items(); } | ||
500 | inline const Json & Json::operator[] (size_t i) const { return (*m_ptr)[i]; } | ||
501 | inline const Json & Json::operator[] (const string &key) const { return (*m_ptr)[key]; } | ||
502 | |||
503 | inline double JsonValue::number_value() const { return 0; } | ||
504 | inline int JsonValue::int_value() const { return 0; } | ||
505 | inline bool JsonValue::bool_value() const { return false; } | ||
506 | inline const string & JsonValue::string_value() const { return statics().empty_string; } | ||
507 | inline const vector<Json> & JsonValue::array_items() const { return statics().empty_vector; } | ||
508 | inline const map<string, Json> & JsonValue::object_items() const { return statics().empty_map; } | ||
509 | inline const Json & JsonValue::operator[] (size_t) const { return static_null(); } | ||
510 | inline const Json & JsonValue::operator[] (const string &) const { return static_null(); } | ||
511 | |||
512 | inline const Json & JsonObject::operator[] (const string &key) const { | ||
513 | auto iter = m_value.find(key); | ||
514 | return (iter == m_value.end()) ? static_null() : iter->second; | ||
515 | } | ||
516 | inline const Json & JsonArray::operator[] (size_t i) const { | ||
517 | if (i >= m_value.size()) return static_null(); | ||
518 | else return m_value[i]; | ||
519 | } | ||
520 | |||
521 | /* * * * * * * * * * * * * * * * * * * * | ||
522 | * Comparison | ||
523 | */ | ||
524 | |||
525 | bool Json::operator== (const Json &other) const { | ||
526 | if (m_ptr == other.m_ptr) | ||
527 | return true; | ||
528 | if (m_ptr->type() != other.m_ptr->type()) | ||
529 | return false; | ||
530 | |||
531 | return m_ptr->equals(other.m_ptr.get()); | ||
532 | } | ||
533 | |||
534 | bool Json::operator< (const Json &other) const { | ||
535 | if (m_ptr == other.m_ptr) | ||
536 | return false; | ||
537 | if (m_ptr->type() != other.m_ptr->type()) | ||
538 | return m_ptr->type() < other.m_ptr->type(); | ||
539 | |||
540 | return m_ptr->less(other.m_ptr.get()); | ||
541 | } | ||
542 | |||
543 | /* * * * * * * * * * * * * * * * * * * * | ||
544 | * Parsing | ||
545 | */ | ||
546 | |||
547 | /* esc(c) | ||
548 | * | ||
549 | * Format char c suitable for printing in an error message. | ||
550 | */ | ||
551 | static inline string esc(char c) { | ||
552 | char buf[12]; | ||
553 | if (static_cast<uint8_t>(c) >= 0x20 && static_cast<uint8_t>(c) <= 0x7f) { | ||
554 | snprintf(buf, sizeof buf, "'%c' (%d)", c, c); | ||
555 | } else { | ||
556 | snprintf(buf, sizeof buf, "(%d)", c); | ||
557 | } | ||
558 | return string(buf); | ||
559 | } | ||
560 | |||
561 | static inline bool in_range(long x, long lower, long upper) { | ||
562 | return (x >= lower && x <= upper); | ||
563 | } | ||
564 | |||
565 | namespace { | ||
566 | /* JsonParser | ||
567 | * | ||
568 | * Object that tracks all state of an in-progress parse. | ||
569 | */ | ||
570 | struct JsonParser final { | ||
571 | |||
572 | /* State | ||
573 | */ | ||
574 | const string &str; | ||
575 | size_t i; | ||
576 | string &err; | ||
577 | bool failed; | ||
578 | const JsonParse strategy; | ||
579 | |||
580 | /* fail(msg, err_ret = Json()) | ||
581 | * | ||
582 | * Mark this parse as failed. | ||
583 | */ | ||
584 | Json fail(string &&msg) { | ||
585 | return fail(move(msg), Json()); | ||
586 | } | ||
587 | |||
588 | template <typename T> | ||
589 | T fail(string &&msg, const T err_ret) { | ||
590 | if (!failed) | ||
591 | err = std::move(msg); | ||
592 | failed = true; | ||
593 | return err_ret; | ||
594 | } | ||
595 | |||
596 | /* consume_whitespace() | ||
597 | * | ||
598 | * Advance until the current character is non-whitespace. | ||
599 | */ | ||
600 | void consume_whitespace() { | ||
601 | while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t') | ||
602 | i++; | ||
603 | } | ||
604 | |||
605 | /* consume_comment() | ||
606 | * | ||
607 | * Advance comments (c-style inline and multiline). | ||
608 | */ | ||
609 | bool consume_comment() { | ||
610 | bool comment_found = false; | ||
611 | if (str[i] == '/') { | ||
612 | i++; | ||
613 | if (i == str.size()) | ||
614 | return fail("unexpected end of input after start of comment", false); | ||
615 | if (str[i] == '/') { // inline comment | ||
616 | i++; | ||
617 | // advance until next line, or end of input | ||
618 | while (i < str.size() && str[i] != '\n') { | ||
619 | i++; | ||
620 | } | ||
621 | comment_found = true; | ||
622 | } | ||
623 | else if (str[i] == '*') { // multiline comment | ||
624 | i++; | ||
625 | if (i > str.size()-2) | ||
626 | return fail("unexpected end of input inside multi-line comment", false); | ||
627 | // advance until closing tokens | ||
628 | while (!(str[i] == '*' && str[i+1] == '/')) { | ||
629 | i++; | ||
630 | if (i > str.size()-2) | ||
631 | return fail( | ||
632 | "unexpected end of input inside multi-line comment", false); | ||
633 | } | ||
634 | i += 2; | ||
635 | comment_found = true; | ||
636 | } | ||
637 | else | ||
638 | return fail("malformed comment", false); | ||
639 | } | ||
640 | return comment_found; | ||
641 | } | ||
642 | |||
643 | /* consume_garbage() | ||
644 | * | ||
645 | * Advance until the current character is non-whitespace and non-comment. | ||
646 | */ | ||
647 | void consume_garbage() { | ||
648 | consume_whitespace(); | ||
649 | if(strategy == JsonParse::COMMENTS) { | ||
650 | bool comment_found = false; | ||
651 | do { | ||
652 | comment_found = consume_comment(); | ||
653 | if (failed) return; | ||
654 | consume_whitespace(); | ||
655 | } | ||
656 | while(comment_found); | ||
657 | } | ||
658 | } | ||
659 | |||
660 | /* get_next_token() | ||
661 | * | ||
662 | * Return the next non-whitespace character. If the end of the input is reached, | ||
663 | * flag an error and return 0. | ||
664 | */ | ||
665 | char get_next_token() { | ||
666 | consume_garbage(); | ||
667 | if (failed) return static_cast<char>(0); | ||
668 | if (i == str.size()) | ||
669 | return fail("unexpected end of input", static_cast<char>(0)); | ||
670 | |||
671 | return str[i++]; | ||
672 | } | ||
673 | |||
674 | /* encode_utf8(pt, out) | ||
675 | * | ||
676 | * Encode pt as UTF-8 and add it to out. | ||
677 | */ | ||
678 | void encode_utf8(long pt, string & out) { | ||
679 | if (pt < 0) | ||
680 | return; | ||
681 | |||
682 | if (pt < 0x80) { | ||
683 | out += static_cast<char>(pt); | ||
684 | } else if (pt < 0x800) { | ||
685 | out += static_cast<char>((pt >> 6) | 0xC0); | ||
686 | out += static_cast<char>((pt & 0x3F) | 0x80); | ||
687 | } else if (pt < 0x10000) { | ||
688 | out += static_cast<char>((pt >> 12) | 0xE0); | ||
689 | out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80); | ||
690 | out += static_cast<char>((pt & 0x3F) | 0x80); | ||
691 | } else { | ||
692 | out += static_cast<char>((pt >> 18) | 0xF0); | ||
693 | out += static_cast<char>(((pt >> 12) & 0x3F) | 0x80); | ||
694 | out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80); | ||
695 | out += static_cast<char>((pt & 0x3F) | 0x80); | ||
696 | } | ||
697 | } | ||
698 | |||
699 | /* parse_string() | ||
700 | * | ||
701 | * Parse a string, starting at the current position. | ||
702 | */ | ||
703 | string parse_string() { | ||
704 | string out; | ||
705 | long last_escaped_codepoint = -1; | ||
706 | while (true) { | ||
707 | if (i == str.size()) | ||
708 | return fail("unexpected end of input in string", ""); | ||
709 | |||
710 | char ch = str[i++]; | ||
711 | |||
712 | if (ch == '"') { | ||
713 | encode_utf8(last_escaped_codepoint, out); | ||
714 | return out; | ||
715 | } | ||
716 | |||
717 | if (in_range(ch, 0, 0x1f)) | ||
718 | return fail("unescaped " + esc(ch) + " in string", ""); | ||
719 | |||
720 | // The usual case: non-escaped characters | ||
721 | if (ch != '\\') { | ||
722 | encode_utf8(last_escaped_codepoint, out); | ||
723 | last_escaped_codepoint = -1; | ||
724 | out += ch; | ||
725 | continue; | ||
726 | } | ||
727 | |||
728 | // Handle escapes | ||
729 | if (i == str.size()) | ||
730 | return fail("unexpected end of input in string", ""); | ||
731 | |||
732 | ch = str[i++]; | ||
733 | |||
734 | if (ch == 'u') { | ||
735 | // Extract 4-byte escape sequence | ||
736 | string esc = str.substr(i, 4); | ||
737 | // Explicitly check length of the substring. The following loop | ||
738 | // relies on std::string returning the terminating NUL when | ||
739 | // accessing str[length]. Checking here reduces brittleness. | ||
740 | if (esc.length() < 4) { | ||
741 | return fail("bad \\u escape: " + esc, ""); | ||
742 | } | ||
743 | for (size_t j = 0; j < 4; j++) { | ||
744 | if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') | ||
745 | && !in_range(esc[j], '0', '9')) | ||
746 | return fail("bad \\u escape: " + esc, ""); | ||
747 | } | ||
748 | |||
749 | long codepoint = strtol(esc.data(), nullptr, 16); | ||
750 | |||
751 | // JSON specifies that characters outside the BMP shall be encoded as a pair | ||
752 | // of 4-hex-digit \u escapes encoding their surrogate pair components. Check | ||
753 | // whether we're in the middle of such a beast: the previous codepoint was an | ||
754 | // escaped lead (high) surrogate, and this is a trail (low) surrogate. | ||
755 | if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) | ||
756 | && in_range(codepoint, 0xDC00, 0xDFFF)) { | ||
757 | // Reassemble the two surrogate pairs into one astral-plane character, per | ||
758 | // the UTF-16 algorithm. | ||
759 | encode_utf8((((last_escaped_codepoint - 0xD800) << 10) | ||
760 | | (codepoint - 0xDC00)) + 0x10000, out); | ||
761 | last_escaped_codepoint = -1; | ||
762 | } else { | ||
763 | encode_utf8(last_escaped_codepoint, out); | ||
764 | last_escaped_codepoint = codepoint; | ||
765 | } | ||
766 | |||
767 | i += 4; | ||
768 | continue; | ||
769 | } | ||
770 | |||
771 | encode_utf8(last_escaped_codepoint, out); | ||
772 | last_escaped_codepoint = -1; | ||
773 | |||
774 | if (ch == 'b') { | ||
775 | out += '\b'; | ||
776 | } else if (ch == 'f') { | ||
777 | out += '\f'; | ||
778 | } else if (ch == 'n') { | ||
779 | out += '\n'; | ||
780 | } else if (ch == 'r') { | ||
781 | out += '\r'; | ||
782 | } else if (ch == 't') { | ||
783 | out += '\t'; | ||
784 | } else if (ch == '"' || ch == '\\' || ch == '/') { | ||
785 | out += ch; | ||
786 | } else { | ||
787 | return fail("invalid escape character " + esc(ch), ""); | ||
788 | } | ||
789 | } | ||
790 | } | ||
791 | |||
792 | /* parse_number() | ||
793 | * | ||
794 | * Parse a double. | ||
795 | */ | ||
796 | Json parse_number() { | ||
797 | size_t start_pos = i; | ||
798 | |||
799 | if (str[i] == '-') | ||
800 | i++; | ||
801 | |||
802 | // Integer part | ||
803 | if (str[i] == '0') { | ||
804 | i++; | ||
805 | if (in_range(str[i], '0', '9')) | ||
806 | return fail("leading 0s not permitted in numbers"); | ||
807 | } else if (in_range(str[i], '1', '9')) { | ||
808 | i++; | ||
809 | while (in_range(str[i], '0', '9')) | ||
810 | i++; | ||
811 | } else { | ||
812 | return fail("invalid " + esc(str[i]) + " in number"); | ||
813 | } | ||
814 | |||
815 | if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' | ||
816 | && (i - start_pos) <= static_cast<size_t>(std::numeric_limits<int>::digits10)) { | ||
817 | return std::atoi(str.c_str() + start_pos); | ||
818 | } | ||
819 | |||
820 | // Decimal part | ||
821 | if (str[i] == '.') { | ||
822 | i++; | ||
823 | if (!in_range(str[i], '0', '9')) | ||
824 | return fail("at least one digit required in fractional part"); | ||
825 | |||
826 | while (in_range(str[i], '0', '9')) | ||
827 | i++; | ||
828 | } | ||
829 | |||
830 | // Exponent part | ||
831 | if (str[i] == 'e' || str[i] == 'E') { | ||
832 | i++; | ||
833 | |||
834 | if (str[i] == '+' || str[i] == '-') | ||
835 | i++; | ||
836 | |||
837 | if (!in_range(str[i], '0', '9')) | ||
838 | return fail("at least one digit required in exponent"); | ||
839 | |||
840 | while (in_range(str[i], '0', '9')) | ||
841 | i++; | ||
842 | } | ||
843 | |||
844 | return std::strtod(str.c_str() + start_pos, nullptr); | ||
845 | } | ||
846 | |||
847 | /* expect(str, res) | ||
848 | * | ||
849 | * Expect that 'str' starts at the character that was just read. If it does, advance | ||
850 | * the input and return res. If not, flag an error. | ||
851 | */ | ||
852 | Json expect(const string &expected, Json res) { | ||
853 | assert(i != 0); | ||
854 | i--; | ||
855 | if (str.compare(i, expected.length(), expected) == 0) { | ||
856 | i += expected.length(); | ||
857 | return res; | ||
858 | } else { | ||
859 | return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length())); | ||
860 | } | ||
861 | } | ||
862 | |||
863 | /* parse_json() | ||
864 | * | ||
865 | * Parse a JSON object. | ||
866 | */ | ||
867 | Json parse_json(int depth) { | ||
868 | if (depth > max_depth) { | ||
869 | return fail("exceeded maximum nesting depth"); | ||
870 | } | ||
871 | |||
872 | char ch = get_next_token(); | ||
873 | if (failed) | ||
874 | return Json(); | ||
875 | |||
876 | if (ch == '-' || (ch >= '0' && ch <= '9')) { | ||
877 | i--; | ||
878 | return parse_number(); | ||
879 | } | ||
880 | |||
881 | if (ch == 't') | ||
882 | return expect("true", true); | ||
883 | |||
884 | if (ch == 'f') | ||
885 | return expect("false", false); | ||
886 | |||
887 | if (ch == 'n') | ||
888 | return expect("null", Json()); | ||
889 | |||
890 | if (ch == '"') | ||
891 | return parse_string(); | ||
892 | |||
893 | if (ch == '{') { | ||
894 | map<string, Json> data; | ||
895 | ch = get_next_token(); | ||
896 | if (ch == '}') | ||
897 | return data; | ||
898 | |||
899 | while (1) { | ||
900 | if (ch != '"') | ||
901 | return fail("expected '\"' in object, got " + esc(ch)); | ||
902 | |||
903 | string key = parse_string(); | ||
904 | if (failed) | ||
905 | return Json(); | ||
906 | |||
907 | ch = get_next_token(); | ||
908 | if (ch != ':') | ||
909 | return fail("expected ':' in object, got " + esc(ch)); | ||
910 | |||
911 | data[std::move(key)] = parse_json(depth + 1); | ||
912 | if (failed) | ||
913 | return Json(); | ||
914 | |||
915 | ch = get_next_token(); | ||
916 | if (ch == '}') | ||
917 | break; | ||
918 | if (ch != ',') | ||
919 | return fail("expected ',' in object, got " + esc(ch)); | ||
920 | |||
921 | ch = get_next_token(); | ||
922 | } | ||
923 | return data; | ||
924 | } | ||
925 | |||
926 | if (ch == '[') { | ||
927 | vector<Json> data; | ||
928 | ch = get_next_token(); | ||
929 | if (ch == ']') | ||
930 | return data; | ||
931 | |||
932 | while (1) { | ||
933 | i--; | ||
934 | data.push_back(parse_json(depth + 1)); | ||
935 | if (failed) | ||
936 | return Json(); | ||
937 | |||
938 | ch = get_next_token(); | ||
939 | if (ch == ']') | ||
940 | break; | ||
941 | if (ch != ',') | ||
942 | return fail("expected ',' in list, got " + esc(ch)); | ||
943 | |||
944 | ch = get_next_token(); | ||
945 | (void)ch; | ||
946 | } | ||
947 | return data; | ||
948 | } | ||
949 | |||
950 | return fail("expected value, got " + esc(ch)); | ||
951 | } | ||
952 | }; | ||
953 | }//namespace { | ||
954 | |||
955 | Json Json::parse(const string &in, string &err, JsonParse strategy) { | ||
956 | JsonParser parser { in, 0, err, false, strategy }; | ||
957 | Json result = parser.parse_json(0); | ||
958 | |||
959 | // Check for any trailing garbage | ||
960 | parser.consume_garbage(); | ||
961 | if (parser.failed) | ||
962 | return Json(); | ||
963 | if (parser.i != in.size() && | ||
964 | ((parser.i + 1) != in.size() && in[parser.i] != 0)) //RBP: If there is only 1 character diff, it is probably just a terminating zero from a memory read. | ||
965 | { | ||
966 | return parser.fail("unexpected trailing " + esc(in[parser.i])); | ||
967 | } | ||
968 | return result; | ||
969 | } | ||
970 | |||
971 | // Documented in json11.hpp | ||
972 | vector<Json> Json::parse_multi(const string &in, | ||
973 | std::string::size_type &parser_stop_pos, | ||
974 | string &err, | ||
975 | JsonParse strategy) { | ||
976 | JsonParser parser { in, 0, err, false, strategy }; | ||
977 | parser_stop_pos = 0; | ||
978 | vector<Json> json_vec; | ||
979 | while (parser.i != in.size() && !parser.failed) { | ||
980 | json_vec.push_back(parser.parse_json(0)); | ||
981 | if (parser.failed) | ||
982 | break; | ||
983 | |||
984 | // Check for another object | ||
985 | parser.consume_garbage(); | ||
986 | if (parser.failed) | ||
987 | break; | ||
988 | parser_stop_pos = parser.i; | ||
989 | } | ||
990 | return json_vec; | ||
991 | } | ||
992 | |||
993 | /* * * * * * * * * * * * * * * * * * * * | ||
994 | * Shape-checking | ||
995 | */ | ||
996 | |||
997 | bool Json::has_shape(const shape & types, string & err) const { | ||
998 | if (!is_object()) { | ||
999 | err = "expected JSON object, got " + dump(); | ||
1000 | return false; | ||
1001 | } | ||
1002 | |||
1003 | const auto& obj_items = object_items(); | ||
1004 | for (auto & item : types) { | ||
1005 | const auto it = obj_items.find(item.first); | ||
1006 | if (it == obj_items.cend() || it->second.type() != item.second) { | ||
1007 | err = "bad type for " + item.first + " in " + dump(); | ||
1008 | return false; | ||
1009 | } | ||
1010 | } | ||
1011 | |||
1012 | return true; | ||
1013 | } | ||
1014 | |||
1015 | } // namespace json11 | ||
1016 | |||
1017 | /*** End of inlined file: json11.cpp ***/ | ||
1018 | |||
1019 | /*** End of inlined file: json11.hpp ***/ | ||
1020 | |||
1021 | |||
1022 | /*** Start of inlined file: tileson_parser.hpp ***/ | ||
1023 | // | ||
1024 | // Created by robin on 22.03.2020. | ||
1025 | // | ||
1026 | |||
1027 | #ifndef TILESON_TILESON_PARSER_HPP | ||
1028 | #define TILESON_TILESON_PARSER_HPP | ||
1029 | |||
1030 | //RBP: FS-namespace is defined in tileson_parser now! | ||
1031 | #if _MSC_VER && !__INTEL_COMPILER | ||
1032 | #include <filesystem> | ||
1033 | namespace fs = std::filesystem; | ||
1034 | #elif __MINGW64__ | ||
1035 | #if __MINGW64_VERSION_MAJOR > 6 | ||
1036 | #include <filesystem> | ||
1037 | namespace fs = std::filesystem; | ||
1038 | #else | ||
1039 | #include <experimental/filesystem> | ||
1040 | namespace fs = std::experimental::filesystem; | ||
1041 | #endif | ||
1042 | #elif __clang__ | ||
1043 | #if __clang_major__ < 8 | ||
1044 | #include <experimental/filesystem> | ||
1045 | namespace fs = std::experimental::filesystem; | ||
1046 | #else | ||
1047 | #include <filesystem> | ||
1048 | namespace fs = std::filesystem; | ||
1049 | #endif | ||
1050 | #else //Linux | ||
1051 | #if __GNUC__ < 8 //GCC major version less than 8 | ||
1052 | #include <experimental/filesystem> | ||
1053 | namespace fs = std::experimental::filesystem; | ||
1054 | #else | ||
1055 | #include <filesystem> | ||
1056 | namespace fs = std::filesystem; | ||
1057 | #endif | ||
1058 | #endif | ||
1059 | |||
1060 | #include <fstream> | ||
1061 | #include <sstream> | ||
1062 | #include <memory> | ||
1063 | |||
1064 | |||
1065 | /*** Start of inlined file: Tools.hpp ***/ | ||
1066 | // | ||
1067 | // Created by robin on 31.07.2020. | ||
1068 | // | ||
1069 | |||
1070 | #ifndef TILESON_TOOLS_HPP | ||
1071 | #define TILESON_TOOLS_HPP | ||
1072 | |||
1073 | #include <cstdint> | ||
1074 | #include <vector> | ||
1075 | #include <string_view> | ||
1076 | namespace tson | ||
1077 | { | ||
1078 | class Tools | ||
1079 | { | ||
1080 | |||
1081 | public: | ||
1082 | Tools() = delete; | ||
1083 | ~Tools() = delete; | ||
1084 | inline static std::vector<uint8_t> Base64DecodedStringToBytes(std::string_view str); | ||
1085 | inline static std::vector<uint32_t> BytesToUnsignedInts(const std::vector<uint8_t> &bytes); | ||
1086 | //inline static std::vector<int> BytesToInts(const std::vector<uint8_t> &bytes); | ||
1087 | }; | ||
1088 | |||
1089 | /*! | ||
1090 | * When you have decoded a Base64 string, you'll get a string representing bytes. This function turns them into actual bytes. | ||
1091 | * @param str | ||
1092 | * @return | ||
1093 | */ | ||
1094 | std::vector<uint8_t> Tools::Base64DecodedStringToBytes(std::string_view str) | ||
1095 | { | ||
1096 | std::vector<uint8_t> bytes; | ||
1097 | for(size_t i = 0; i < str.size(); ++i) | ||
1098 | { | ||
1099 | uint8_t u8 = static_cast<uint8_t>(str[i]); | ||
1100 | bytes.push_back(u8); | ||
1101 | } | ||
1102 | return bytes; | ||
1103 | } | ||
1104 | |||
1105 | /*! | ||
1106 | * Converts bytes into unsigned int values. The bytes are converted in the Little Endian byte order to fit Tiled's specs. | ||
1107 | * @param bytes A vector of bytes. | ||
1108 | * @return Bytes converted to unsigned ints | ||
1109 | */ | ||
1110 | std::vector<uint32_t> Tools::BytesToUnsignedInts(const std::vector<uint8_t> &bytes) | ||
1111 | { | ||
1112 | std::vector<uint32_t> uints; | ||
1113 | std::vector<uint8_t> toConvert; | ||
1114 | //uint32_t size8 = (compressed[55] << 24) | (compressed[56] << 16) | (compressed[57] << 8) | compressed[58]; //Should be 66000 | ||
1115 | |||
1116 | for(size_t i = 0; i < bytes.size(); ++i) | ||
1117 | { | ||
1118 | toConvert.push_back(bytes[i]); | ||
1119 | if(toConvert.size() == 4) | ||
1120 | { | ||
1121 | uint32_t u32 = (toConvert[3] << 24) | (toConvert[2] << 16) | (toConvert[1] << 8) | toConvert[0]; | ||
1122 | uints.push_back(u32); | ||
1123 | toConvert.clear(); | ||
1124 | } | ||
1125 | } | ||
1126 | |||
1127 | return uints; | ||
1128 | } | ||
1129 | |||
1130 | /*! | ||
1131 | * While the Tiled specification uses unsigned ints for their tiles, Tileson uses regular ints. | ||
1132 | * This may be changed in the future, but should in reality never really become an issue. | ||
1133 | * | ||
1134 | * Update 2020-11-09: This will cause problems when tiles has flip flags! | ||
1135 | * | ||
1136 | * int differences: | ||
1137 | * int max: 2147483647 | ||
1138 | * uint max: 4294967295 | ||
1139 | * | ||
1140 | * @param bytes A vector of bytes. | ||
1141 | * @return Bytes converted to ints | ||
1142 | */ | ||
1143 | /*std::vector<int> Tools::BytesToInts(const std::vector<uint8_t> &bytes) | ||
1144 | { | ||
1145 | std::vector<int> ints; | ||
1146 | std::vector<uint8_t> toConvert; | ||
1147 | //uint32_t size8 = (compressed[55] << 24) | (compressed[56] << 16) | (compressed[57] << 8) | compressed[58]; //Should be 66000 | ||
1148 | |||
1149 | for(size_t i = 0; i < bytes.size(); ++i) | ||
1150 | { | ||
1151 | toConvert.push_back(bytes[i]); | ||
1152 | if(toConvert.size() == 4) | ||
1153 | { | ||
1154 | uint32_t u32 = (toConvert[3] << 24) | (toConvert[2] << 16) | (toConvert[1] << 8) | toConvert[0]; | ||
1155 | ints.push_back(u32); | ||
1156 | toConvert.clear(); | ||
1157 | } | ||
1158 | } | ||
1159 | |||
1160 | return ints; | ||
1161 | }*/ | ||
1162 | } | ||
1163 | |||
1164 | #endif //TILESON_TOOLS_HPP | ||
1165 | |||
1166 | /*** End of inlined file: Tools.hpp ***/ | ||
1167 | |||
1168 | |||
1169 | /*** Start of inlined file: Base64Decompressor.hpp ***/ | ||
1170 | // | ||
1171 | // Created by robin on 29.07.2020. | ||
1172 | // The Base64 decoding logic is heavily based on: https://github.com/ReneNyffenegger/cpp-base64 | ||
1173 | // | ||
1174 | |||
1175 | #ifndef TILESON_BASE64DECOMPRESSOR_HPP | ||
1176 | #define TILESON_BASE64DECOMPRESSOR_HPP | ||
1177 | |||
1178 | |||
1179 | /*** Start of inlined file: IDecompressor.hpp ***/ | ||
1180 | // | ||
1181 | // Created by robin on 29.07.2020. | ||
1182 | // | ||
1183 | |||
1184 | #ifndef TILESON_IDECOMPRESSOR_HPP | ||
1185 | #define TILESON_IDECOMPRESSOR_HPP | ||
1186 | |||
1187 | #include <string_view> | ||
1188 | |||
1189 | namespace tson | ||
1190 | { | ||
1191 | template <class TIn, class TOut> | ||
1192 | class IDecompressor | ||
1193 | { | ||
1194 | public: | ||
1195 | /*! | ||
1196 | * If the name matches with 'compression' or 'encoding' the decompress() function will | ||
1197 | * be called automatically for the actual Layer. Encoding-related matching is handled first! | ||
1198 | * | ||
1199 | * Known values: | ||
1200 | * | ||
1201 | * compression: zlib, gzip, zstd (since Tiled 1.3) or empty (default) (tilelayer only). | ||
1202 | * encoding: csv (default) or base64 (tilelayer only). | ||
1203 | * | ||
1204 | * @return | ||
1205 | */ | ||
1206 | [[nodiscard]] virtual const std::string &name() const = 0; | ||
1207 | |||
1208 | /*! | ||
1209 | * Used primarily for Tiled related decompression. | ||
1210 | * @param input Input data | ||
1211 | * @return Decompressed data | ||
1212 | */ | ||
1213 | virtual TOut decompress(const TIn &input) = 0; | ||
1214 | |||
1215 | /*! | ||
1216 | * Used for whole file decompression. Not related to Tiled | ||
1217 | * @param path | ||
1218 | * @return | ||
1219 | */ | ||
1220 | virtual TOut decompressFile(const fs::path &path) = 0; | ||
1221 | |||
1222 | /*! | ||
1223 | * Used for whole file decompression. Not related to Tiled | ||
1224 | * @param path | ||
1225 | * @return | ||
1226 | */ | ||
1227 | virtual TOut decompress(const void *data, size_t size) = 0; | ||
1228 | }; | ||
1229 | } | ||
1230 | |||
1231 | #endif //TILESON_IDECOMPRESSOR_HPP | ||
1232 | |||
1233 | /*** End of inlined file: IDecompressor.hpp ***/ | ||
1234 | |||
1235 | #include <string> | ||
1236 | |||
1237 | namespace tson | ||
1238 | { | ||
1239 | class Base64Decompressor : public IDecompressor<std::string_view, std::string> | ||
1240 | { | ||
1241 | public: | ||
1242 | [[nodiscard]] inline const std::string &name() const override; | ||
1243 | |||
1244 | inline std::string decompress(const std::string_view &s) override; | ||
1245 | |||
1246 | inline std::string decompressFile(const fs::path &path) override; | ||
1247 | inline std::string decompress(const void *data, size_t size) override; | ||
1248 | |||
1249 | private: | ||
1250 | inline unsigned int pos_of_char(const unsigned char chr); | ||
1251 | inline static const std::string NAME = "base64"; | ||
1252 | }; | ||
1253 | |||
1254 | const std::string &Base64Decompressor::name() const | ||
1255 | { | ||
1256 | return NAME; | ||
1257 | } | ||
1258 | |||
1259 | std::string Base64Decompressor::decompress(const std::string_view &s) | ||
1260 | { | ||
1261 | |||
1262 | size_t length_of_string = s.length(); | ||
1263 | if (!length_of_string) return std::string(""); | ||
1264 | |||
1265 | size_t in_len = length_of_string; | ||
1266 | size_t pos = 0; | ||
1267 | |||
1268 | // | ||
1269 | // The approximate length (bytes) of the decoded string might be one ore | ||
1270 | // two bytes smaller, depending on the amount of trailing equal signs | ||
1271 | // in the encoded string. This approximation is needed to reserve | ||
1272 | // enough space in the string to be returned. | ||
1273 | // | ||
1274 | size_t approx_length_of_decoded_string = length_of_string / 4 * 3; | ||
1275 | std::string ret; | ||
1276 | ret.reserve(approx_length_of_decoded_string); | ||
1277 | |||
1278 | while (pos < in_len) { | ||
1279 | |||
1280 | unsigned int pos_of_char_1 = pos_of_char(s[pos+1] ); | ||
1281 | |||
1282 | ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char(s[pos+0]) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4))); | ||
1283 | |||
1284 | if (s[pos+2] != '=' && s[pos+2] != '.') { // accept URL-safe base 64 strings, too, so check for '.' also. | ||
1285 | |||
1286 | unsigned int pos_of_char_2 = pos_of_char(s[pos+2] ); | ||
1287 | ret.push_back(static_cast<std::string::value_type>( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2))); | ||
1288 | |||
1289 | if (s[pos+3] != '=' && s[pos+3] != '.') { | ||
1290 | ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(s[pos+3]) )); | ||
1291 | } | ||
1292 | } | ||
1293 | |||
1294 | pos += 4; | ||
1295 | } | ||
1296 | |||
1297 | return ret; | ||
1298 | } | ||
1299 | |||
1300 | unsigned int Base64Decompressor::pos_of_char(const unsigned char chr) | ||
1301 | { | ||
1302 | // | ||
1303 | // Return the position of chr within base64_encode() | ||
1304 | // | ||
1305 | |||
1306 | if (chr >= 'A' && chr <= 'Z') return chr - 'A'; | ||
1307 | else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1; | ||
1308 | else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2; | ||
1309 | else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters ( | ||
1310 | else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_' | ||
1311 | |||
1312 | throw "If input is correct, this line should never be reached."; | ||
1313 | } | ||
1314 | |||
1315 | /*! | ||
1316 | * UNUSED! Does nothing | ||
1317 | * @param path | ||
1318 | * @return | ||
1319 | */ | ||
1320 | std::string Base64Decompressor::decompressFile(const fs::path &path) | ||
1321 | { | ||
1322 | return std::string(); | ||
1323 | } | ||
1324 | |||
1325 | /*! | ||
1326 | * UNUSED! Does nothing | ||
1327 | * @param path | ||
1328 | * @return | ||
1329 | */ | ||
1330 | std::string Base64Decompressor::decompress(const void *data, size_t size) | ||
1331 | { | ||
1332 | return std::string(); | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | #endif //TILESON_BASE64DECOMPRESSOR_HPP | ||
1337 | |||
1338 | /*** End of inlined file: Base64Decompressor.hpp ***/ | ||
1339 | |||
1340 | |||
1341 | /*** Start of inlined file: Lzma.hpp ***/ | ||
1342 | // | ||
1343 | // Created by robin on 16.01.2021. | ||
1344 | // | ||
1345 | //#include "../../extras/pocketlzma.hpp" | ||
1346 | #ifdef POCKETLZMA_POCKETLZMA_H | ||
1347 | |||
1348 | #ifndef TILESON_LZMA_HPP | ||
1349 | #define TILESON_LZMA_HPP | ||
1350 | |||
1351 | namespace tson | ||
1352 | { | ||
1353 | class Lzma : public IDecompressor<std::vector<uint8_t>, std::vector<uint8_t>> | ||
1354 | { | ||
1355 | public: | ||
1356 | inline const std::string &name() const override | ||
1357 | { | ||
1358 | return NAME; | ||
1359 | } | ||
1360 | |||
1361 | inline std::vector<uint8_t> decompress(const std::vector<uint8_t> &input) override | ||
1362 | { | ||
1363 | std::vector<uint8_t> out; | ||
1364 | |||
1365 | plz::PocketLzma p; | ||
1366 | plz::StatusCode status = p.decompress(input, out); | ||
1367 | |||
1368 | if(status != plz::StatusCode::Ok) | ||
1369 | return std::vector<uint8_t>(); | ||
1370 | |||
1371 | return out; | ||
1372 | } | ||
1373 | |||
1374 | inline std::vector<uint8_t> decompressFile(const fs::path &path) override | ||
1375 | { | ||
1376 | std::vector<uint8_t> in; | ||
1377 | std::vector<uint8_t> out; | ||
1378 | |||
1379 | plz::PocketLzma p; | ||
1380 | plz::FileStatus fileStatus = plz::File::FromFile(path.u8string(), in); | ||
1381 | if(fileStatus.status() != plz::FileStatus::Code::Ok) | ||
1382 | return std::vector<uint8_t>(); | ||
1383 | |||
1384 | plz::StatusCode status = p.decompress(in, out); | ||
1385 | |||
1386 | if(status != plz::StatusCode::Ok) | ||
1387 | return std::vector<uint8_t>(); | ||
1388 | |||
1389 | return out; | ||
1390 | } | ||
1391 | |||
1392 | inline std::vector<uint8_t> decompress(const void *data, size_t size) override | ||
1393 | { | ||
1394 | std::vector<uint8_t> out; | ||
1395 | |||
1396 | plz::PocketLzma p; | ||
1397 | plz::StatusCode status = p.decompress((uint8_t*) data, size, out); | ||
1398 | |||
1399 | if(status != plz::StatusCode::Ok) | ||
1400 | return std::vector<uint8_t>(); | ||
1401 | |||
1402 | return out; | ||
1403 | } | ||
1404 | |||
1405 | private: | ||
1406 | inline static const std::string NAME {"lzma"}; | ||
1407 | }; | ||
1408 | } | ||
1409 | |||
1410 | #endif //TILESON_LZMA_HPP | ||
1411 | |||
1412 | #endif | ||
1413 | /*** End of inlined file: Lzma.hpp ***/ | ||
1414 | |||
1415 | |||
1416 | /*** Start of inlined file: DecompressorContainer.hpp ***/ | ||
1417 | // | ||
1418 | // Created by robin on 30.07.2020. | ||
1419 | // | ||
1420 | |||
1421 | #ifndef TILESON_DECOMPRESSORCONTAINER_HPP | ||
1422 | #define TILESON_DECOMPRESSORCONTAINER_HPP | ||
1423 | |||
1424 | #include <memory> | ||
1425 | #include <vector> | ||
1426 | #include <string_view> | ||
1427 | #include <functional> | ||
1428 | namespace tson | ||
1429 | { | ||
1430 | class DecompressorContainer | ||
1431 | { | ||
1432 | public: | ||
1433 | inline DecompressorContainer() = default; | ||
1434 | template <typename T, typename... Args> | ||
1435 | inline void add(Args &&... args); | ||
1436 | inline void remove(std::string_view name); | ||
1437 | inline bool contains(std::string_view name) const; | ||
1438 | inline bool empty() const; | ||
1439 | inline size_t size() const; | ||
1440 | inline void clear(); | ||
1441 | |||
1442 | inline IDecompressor<std::string_view, std::string> *get(std::string_view name); | ||
1443 | private: | ||
1444 | //Key: name, | ||
1445 | std::vector<std::unique_ptr<IDecompressor<std::string_view, std::string>>> m_decompressors; | ||
1446 | }; | ||
1447 | |||
1448 | template<typename T, typename... Args> | ||
1449 | void DecompressorContainer::add(Args &&... args) | ||
1450 | { | ||
1451 | m_decompressors.emplace_back(new T(args...)); | ||
1452 | } | ||
1453 | |||
1454 | /*! | ||
1455 | * | ||
1456 | * @param name The name of the decompressor to check whether exists. | ||
1457 | * @return Whether a decompressor with the given name exists or not. | ||
1458 | */ | ||
1459 | bool DecompressorContainer::contains(std::string_view name) const | ||
1460 | { | ||
1461 | auto iter = std::find_if(m_decompressors.begin(), m_decompressors.end(), [&](const auto &item) | ||
1462 | { | ||
1463 | return item->name() == name; | ||
1464 | }); | ||
1465 | |||
1466 | return iter != m_decompressors.end(); | ||
1467 | } | ||
1468 | |||
1469 | /*! | ||
1470 | * Removed an element with the given name. | ||
1471 | * @param name The name of the decompressor | ||
1472 | */ | ||
1473 | void DecompressorContainer::remove(std::string_view name) | ||
1474 | { | ||
1475 | auto iter = std::remove_if(m_decompressors.begin(), m_decompressors.end(), [&](const auto &item) | ||
1476 | { | ||
1477 | return item->name() == name; | ||
1478 | }); | ||
1479 | m_decompressors.erase(iter); | ||
1480 | } | ||
1481 | |||
1482 | size_t DecompressorContainer::size() const | ||
1483 | { | ||
1484 | return m_decompressors.size(); | ||
1485 | } | ||
1486 | |||
1487 | /*! | ||
1488 | * | ||
1489 | * @param name The name of the container | ||
1490 | * @return An ICompressor pointer if it exists. nullptr otherwise. | ||
1491 | */ | ||
1492 | IDecompressor<std::string_view, std::string> *DecompressorContainer::get(std::string_view name) | ||
1493 | { | ||
1494 | auto iter = std::find_if(m_decompressors.begin(), m_decompressors.end(), [&](const auto &item) | ||
1495 | { | ||
1496 | return item->name() == name; | ||
1497 | }); | ||
1498 | |||
1499 | return (iter != m_decompressors.end()) ? iter->get() : nullptr; | ||
1500 | } | ||
1501 | |||
1502 | /*! | ||
1503 | * Check if container is empty | ||
1504 | * @return Whether or not the container is empty | ||
1505 | */ | ||
1506 | bool DecompressorContainer::empty() const | ||
1507 | { | ||
1508 | return m_decompressors.empty(); | ||
1509 | } | ||
1510 | |||
1511 | /*! | ||
1512 | * Clears all IDecompressor elements in the container | ||
1513 | */ | ||
1514 | void DecompressorContainer::clear() | ||
1515 | { | ||
1516 | m_decompressors.clear(); | ||
1517 | } | ||
1518 | } | ||
1519 | #endif //TILESON_DECOMPRESSORCONTAINER_HPP | ||
1520 | |||
1521 | /*** End of inlined file: DecompressorContainer.hpp ***/ | ||
1522 | |||
1523 | |||
1524 | /*** Start of inlined file: MemoryStream.hpp ***/ | ||
1525 | // | ||
1526 | // Created by robin on 22.03.2020. | ||
1527 | // | ||
1528 | |||
1529 | #ifndef TILESON_MEMORYSTREAM_HPP | ||
1530 | #define TILESON_MEMORYSTREAM_HPP | ||
1531 | |||
1532 | |||
1533 | /*** Start of inlined file: MemoryBuffer.hpp ***/ | ||
1534 | // | ||
1535 | // Created by robin on 22.03.2020. | ||
1536 | // | ||
1537 | |||
1538 | #ifndef TILESON_MEMORYBUFFER_HPP | ||
1539 | #define TILESON_MEMORYBUFFER_HPP | ||
1540 | |||
1541 | #include <iostream> | ||
1542 | |||
1543 | namespace tson | ||
1544 | { | ||
1545 | class MemoryBuffer : public std::basic_streambuf<char> { | ||
1546 | public: | ||
1547 | MemoryBuffer(const uint8_t *p, size_t l) { | ||
1548 | setg((char*)p, (char*)p, (char*)p + l); | ||
1549 | } | ||
1550 | }; | ||
1551 | } | ||
1552 | |||
1553 | #endif //TILESON_MEMORYBUFFER_HPP | ||
1554 | |||
1555 | /*** End of inlined file: MemoryBuffer.hpp ***/ | ||
1556 | |||
1557 | namespace tson | ||
1558 | { | ||
1559 | class MemoryStream : public std::istream { | ||
1560 | public: | ||
1561 | MemoryStream(const uint8_t *p, size_t l) : | ||
1562 | std::istream(&m_buffer), | ||
1563 | m_buffer(p, l) { | ||
1564 | rdbuf(&m_buffer); | ||
1565 | } | ||
1566 | |||
1567 | private: | ||
1568 | MemoryBuffer m_buffer; | ||
1569 | }; | ||
1570 | } | ||
1571 | |||
1572 | #endif //TILESON_MEMORYSTREAM_HPP | ||
1573 | |||
1574 | /*** End of inlined file: MemoryStream.hpp ***/ | ||
1575 | |||
1576 | |||
1577 | /*** Start of inlined file: Map.hpp ***/ | ||
1578 | // | ||
1579 | // Created by robin on 22.03.2020. | ||
1580 | // | ||
1581 | |||
1582 | #ifndef TILESON_MAP_HPP | ||
1583 | #define TILESON_MAP_HPP | ||
1584 | |||
1585 | |||
1586 | /*** Start of inlined file: Color.hpp ***/ | ||
1587 | // | ||
1588 | // Created by robin on 09.08.2019. | ||
1589 | // | ||
1590 | |||
1591 | #ifndef TILESON_COLOR_HPP | ||
1592 | #define TILESON_COLOR_HPP | ||
1593 | |||
1594 | #include <type_traits> | ||
1595 | #include <cstdint> | ||
1596 | #include <string> | ||
1597 | |||
1598 | namespace tson | ||
1599 | { | ||
1600 | |||
1601 | template<typename T> | ||
1602 | class Color | ||
1603 | { | ||
1604 | |||
1605 | public: | ||
1606 | /*! | ||
1607 | * Parses color from Tiled's own color format, which is #aarrggbb in hex format or optionally #rrggbb. | ||
1608 | * @param color Color in "#rrggbbaa" hex format. | ||
1609 | * @example "#ffaa07ff" and "#aa07ff". In cases where alpha is not a value, it is set to 255. | ||
1610 | */ | ||
1611 | inline explicit Color(const std::string &color) | ||
1612 | { | ||
1613 | parseHexString(color); | ||
1614 | } | ||
1615 | inline Color(T red, T green, T blue, T alpha); | ||
1616 | inline Color() { r = g = b = 0; a = 255; } | ||
1617 | |||
1618 | inline bool operator==(const Color &rhs) const; | ||
1619 | inline bool operator==(const std::string &rhs) const; | ||
1620 | inline bool operator!=(const Color &rhs) const; | ||
1621 | |||
1622 | inline Color<float> asFloat(); | ||
1623 | inline Color<uint8_t> asInt(); | ||
1624 | |||
1625 | /*! Red */ | ||
1626 | T r; | ||
1627 | /*! Green */ | ||
1628 | T g; | ||
1629 | /*! Blue */ | ||
1630 | T b; | ||
1631 | /*! Alpha */ | ||
1632 | T a; | ||
1633 | |||
1634 | private: | ||
1635 | void parseHexString(const std::string &color) | ||
1636 | { | ||
1637 | if constexpr (std::is_same<T, float>::value) | ||
1638 | { | ||
1639 | if (color.size() == 9) | ||
1640 | { | ||
1641 | a = (float) std::stoi(color.substr(1, 2), nullptr, 16) / 255; | ||
1642 | r = (float) std::stoi(color.substr(3, 2), nullptr, 16) / 255; | ||
1643 | g = (float) std::stoi(color.substr(5, 2), nullptr, 16) / 255; | ||
1644 | b = (float) std::stoi(color.substr(7, 2), nullptr, 16) / 255; | ||
1645 | } | ||
1646 | else if (color.size() == 7) | ||
1647 | { | ||
1648 | r = (float) std::stoi(color.substr(1, 2), nullptr, 16) / 255; | ||
1649 | g = (float) std::stoi(color.substr(3, 2), nullptr, 16) / 255; | ||
1650 | b = (float) std::stoi(color.substr(5, 2), nullptr, 16) / 255; | ||
1651 | a = 1.f; | ||
1652 | } | ||
1653 | } | ||
1654 | else | ||
1655 | { | ||
1656 | if (color.size() == 9) | ||
1657 | { | ||
1658 | a = std::stoi(color.substr(1, 2), nullptr, 16); | ||
1659 | r = std::stoi(color.substr(3, 2), nullptr, 16); | ||
1660 | g = std::stoi(color.substr(5, 2), nullptr, 16); | ||
1661 | b = std::stoi(color.substr(7, 2), nullptr, 16); | ||
1662 | } | ||
1663 | else if (color.size() == 7) | ||
1664 | { | ||
1665 | r = std::stoi(color.substr(1, 2), nullptr, 16); | ||
1666 | g = std::stoi(color.substr(3, 2), nullptr, 16); | ||
1667 | b = std::stoi(color.substr(5, 2), nullptr, 16); | ||
1668 | a = 255; | ||
1669 | } | ||
1670 | } | ||
1671 | } | ||
1672 | |||
1673 | }; | ||
1674 | |||
1675 | typedef Color<uint8_t> Colori; | ||
1676 | typedef Color<float> Colorf; | ||
1677 | |||
1678 | /*! | ||
1679 | * Gets the Color as a float. Only useful if the template related to the current color is NOT float | ||
1680 | * @tparam T The template type | ||
1681 | * @return If the T type is float, the value will be returned as a copy of itself. Else: All values will be divided by 255 | ||
1682 | * before returning. | ||
1683 | */ | ||
1684 | template<typename T> | ||
1685 | tson::Colorf Color<T>::asFloat() | ||
1686 | { | ||
1687 | if constexpr (std::is_same<T, float>::value) | ||
1688 | *this; | ||
1689 | else | ||
1690 | return tson::Colorf((float) r / 255, (float) g / 255, (float) b / 255, (float) a / 255); | ||
1691 | } | ||
1692 | |||
1693 | /*! | ||
1694 | * Gets the Color as an 32-bit variable, where each channel is 8-bit. | ||
1695 | * Only useful if the template related to the current color is NOT already 8-bit int | ||
1696 | * @tparam T The template type | ||
1697 | * @return If the T type is float, the value of each channel will be multiplied by 255. Else: The value will be returned as a copy of itself. | ||
1698 | */ | ||
1699 | template<typename T> | ||
1700 | tson::Colori Color<T>::asInt() | ||
1701 | { | ||
1702 | if constexpr (std::is_same<T, float>::value) | ||
1703 | return tson::Colori((float) r * 255, (float) g * 255, (float) b * 255, (float) a * 255); | ||
1704 | else | ||
1705 | *this; | ||
1706 | } | ||
1707 | |||
1708 | /*! | ||
1709 | * Create a new color in rgba (red, green, blue, alpha) format | ||
1710 | * @tparam T the template type for each channel. Usually uint8_t (8-bit int) or float. | ||
1711 | * @param red Red channel | ||
1712 | * @param green Green channel | ||
1713 | * @param blue Blue channel | ||
1714 | * @param alpha Alpha channel | ||
1715 | */ | ||
1716 | template<typename T> | ||
1717 | Color<T>::Color(T red, T green, T blue, T alpha) | ||
1718 | { | ||
1719 | r = red; | ||
1720 | g = green; | ||
1721 | b = blue; | ||
1722 | a = alpha; | ||
1723 | } | ||
1724 | |||
1725 | template<typename T> | ||
1726 | bool Color<T>::operator==(const std::string &rhs) const { | ||
1727 | Color other {rhs}; | ||
1728 | return *this == other; | ||
1729 | } | ||
1730 | |||
1731 | template<typename T> | ||
1732 | bool Color<T>::operator==(const Color &rhs) const | ||
1733 | { | ||
1734 | return r == rhs.r && | ||
1735 | g == rhs.g && | ||
1736 | b == rhs.b && | ||
1737 | a == rhs.a; | ||
1738 | } | ||
1739 | |||
1740 | template<typename T> | ||
1741 | bool Color<T>::operator!=(const Color &rhs) const | ||
1742 | { | ||
1743 | return !(rhs == *this); | ||
1744 | } | ||
1745 | |||
1746 | } | ||
1747 | |||
1748 | #endif //TILESON_COLOR_HPP | ||
1749 | |||
1750 | /*** End of inlined file: Color.hpp ***/ | ||
1751 | |||
1752 | |||
1753 | /*** Start of inlined file: Vector2.hpp ***/ | ||
1754 | // | ||
1755 | // Created by robin on 31.07.2019. | ||
1756 | // | ||
1757 | |||
1758 | #ifndef TILESON_VECTOR2_HPP | ||
1759 | #define TILESON_VECTOR2_HPP | ||
1760 | |||
1761 | namespace tson | ||
1762 | { | ||
1763 | template<typename T> | ||
1764 | class Vector2 | ||
1765 | { | ||
1766 | |||
1767 | public: | ||
1768 | inline Vector2(T xPos, T yPos); | ||
1769 | inline Vector2() { x = y = 0; } | ||
1770 | |||
1771 | inline bool operator==(const Vector2 &rhs) const; | ||
1772 | inline bool operator!=(const Vector2 &rhs) const; | ||
1773 | |||
1774 | T x; | ||
1775 | T y; | ||
1776 | }; | ||
1777 | |||
1778 | /*! | ||
1779 | * | ||
1780 | * @tparam T template type | ||
1781 | * @param xPos x-position | ||
1782 | * @param yPos y-position | ||
1783 | */ | ||
1784 | template<typename T> | ||
1785 | Vector2<T>::Vector2(T xPos, T yPos) | ||
1786 | { | ||
1787 | x = xPos; | ||
1788 | y = yPos; | ||
1789 | } | ||
1790 | |||
1791 | template<typename T> | ||
1792 | bool Vector2<T>::operator==(const Vector2 &rhs) const | ||
1793 | { | ||
1794 | return x == rhs.x && | ||
1795 | y == rhs.y; | ||
1796 | } | ||
1797 | |||
1798 | template<typename T> | ||
1799 | bool Vector2<T>::operator!=(const Vector2 &rhs) const | ||
1800 | { | ||
1801 | return !(rhs == *this); | ||
1802 | } | ||
1803 | |||
1804 | typedef Vector2<int> Vector2i; | ||
1805 | typedef Vector2<float> Vector2f; | ||
1806 | } | ||
1807 | |||
1808 | #endif //TILESON_VECTOR2_HPP | ||
1809 | |||
1810 | /*** End of inlined file: Vector2.hpp ***/ | ||
1811 | |||
1812 | //#include "../external/json.hpp" | ||
1813 | |||
1814 | /*** Start of inlined file: IJson.hpp ***/ | ||
1815 | // | ||
1816 | // Created by robin on 06.01.2021. | ||
1817 | // | ||
1818 | |||
1819 | #ifndef TILESON_IJSON_HPP | ||
1820 | #define TILESON_IJSON_HPP | ||
1821 | |||
1822 | namespace tson | ||
1823 | { | ||
1824 | class IJson | ||
1825 | { | ||
1826 | public: | ||
1827 | |||
1828 | virtual IJson& operator[](std::string_view key) = 0; | ||
1829 | virtual IJson &at(std::string_view key) = 0; | ||
1830 | virtual IJson &at(size_t pos) = 0; | ||
1831 | /*! | ||
1832 | * If current json object is an array, this will get all elements of it! | ||
1833 | * @return An array | ||
1834 | */ | ||
1835 | [[nodiscard]] virtual std::vector<std::unique_ptr<IJson>> array() = 0; | ||
1836 | [[nodiscard]] virtual std::vector<std::unique_ptr<IJson>> &array(std::string_view key) = 0; | ||
1837 | /*! | ||
1838 | * Get the size of an object. This will be equal to the number of | ||
1839 | * variables an object contains. | ||
1840 | * @return | ||
1841 | */ | ||
1842 | [[nodiscard]] virtual size_t size() const = 0; | ||
1843 | [[nodiscard]] virtual bool parse(const fs::path &path) = 0; | ||
1844 | [[nodiscard]] virtual bool parse(const void *data, size_t size) = 0; | ||
1845 | |||
1846 | template <typename T> | ||
1847 | [[nodiscard]] T get(std::string_view key); | ||
1848 | template <typename T> | ||
1849 | [[nodiscard]] T get(); | ||
1850 | [[nodiscard]] virtual size_t count(std::string_view key) const = 0; | ||
1851 | [[nodiscard]] virtual bool any(std::string_view key) const = 0; | ||
1852 | [[nodiscard]] virtual bool isArray() const = 0; | ||
1853 | [[nodiscard]] virtual bool isObject() const = 0; | ||
1854 | [[nodiscard]] virtual bool isNull() const = 0; | ||
1855 | |||
1856 | protected: | ||
1857 | [[nodiscard]] virtual int32_t getInt32(std::string_view key) = 0; | ||
1858 | [[nodiscard]] virtual uint32_t getUInt32(std::string_view key) = 0; | ||
1859 | [[nodiscard]] virtual int64_t getInt64(std::string_view key) = 0; | ||
1860 | [[nodiscard]] virtual uint64_t getUInt64(std::string_view key) = 0; | ||
1861 | [[nodiscard]] virtual double getDouble(std::string_view key) = 0; | ||
1862 | [[nodiscard]] virtual float getFloat(std::string_view key) = 0; | ||
1863 | [[nodiscard]] virtual std::string getString(std::string_view key) = 0; | ||
1864 | [[nodiscard]] virtual bool getBool(std::string_view key) = 0; | ||
1865 | |||
1866 | [[nodiscard]] virtual int32_t getInt32() = 0; | ||
1867 | [[nodiscard]] virtual uint32_t getUInt32() = 0; | ||
1868 | [[nodiscard]] virtual int64_t getInt64() = 0; | ||
1869 | [[nodiscard]] virtual uint64_t getUInt64() = 0; | ||
1870 | [[nodiscard]] virtual double getDouble() = 0; | ||
1871 | [[nodiscard]] virtual float getFloat() = 0; | ||
1872 | [[nodiscard]] virtual std::string getString() = 0; | ||
1873 | [[nodiscard]] virtual bool getBool() = 0; | ||
1874 | }; | ||
1875 | |||
1876 | template<typename T> | ||
1877 | T IJson::get(std::string_view key) | ||
1878 | { | ||
1879 | if constexpr (std::is_same<T, double>::value) | ||
1880 | return getDouble(key); | ||
1881 | if constexpr (std::is_same<T, float>::value) | ||
1882 | return getFloat(key); | ||
1883 | else if constexpr (std::is_same<T, int32_t>::value) | ||
1884 | return getInt32(key); | ||
1885 | else if constexpr (std::is_same<T, uint32_t>::value) | ||
1886 | return getUInt32(key); | ||
1887 | else if constexpr (std::is_same<T, int64_t>::value) | ||
1888 | return getInt64(key); | ||
1889 | else if constexpr (std::is_same<T, uint64_t>::value) | ||
1890 | return getUInt64(key); | ||
1891 | else if constexpr (std::is_same<T, std::string>::value) | ||
1892 | return getString(key); | ||
1893 | else if constexpr (std::is_same<T, bool>::value) | ||
1894 | return getBool(key); | ||
1895 | else | ||
1896 | return nullptr; | ||
1897 | } | ||
1898 | |||
1899 | template<typename T> | ||
1900 | T IJson::get() | ||
1901 | { | ||
1902 | if constexpr (std::is_same<T, double>::value) | ||
1903 | return getDouble(); | ||
1904 | if constexpr (std::is_same<T, float>::value) | ||
1905 | return getFloat(); | ||
1906 | else if constexpr (std::is_same<T, int32_t>::value) | ||
1907 | return getInt32(); | ||
1908 | else if constexpr (std::is_same<T, uint32_t>::value) | ||
1909 | return getUInt32(); | ||
1910 | else if constexpr (std::is_same<T, int64_t>::value) | ||
1911 | return getInt64(); | ||
1912 | else if constexpr (std::is_same<T, uint64_t>::value) | ||
1913 | return getUInt64(); | ||
1914 | else if constexpr (std::is_same<T, std::string>::value) | ||
1915 | return getString(); | ||
1916 | else if constexpr (std::is_same<T, bool>::value) | ||
1917 | return getBool(); | ||
1918 | else | ||
1919 | return nullptr; | ||
1920 | } | ||
1921 | |||
1922 | } | ||
1923 | |||
1924 | #endif //TILESON_IJSON_HPP | ||
1925 | |||
1926 | /*** End of inlined file: IJson.hpp ***/ | ||
1927 | |||
1928 | |||
1929 | |||
1930 | /*** Start of inlined file: NlohmannJson.hpp ***/ | ||
1931 | // | ||
1932 | // Created by robin on 08.01.2021. | ||
1933 | // | ||
1934 | |||
1935 | #ifdef INCLUDE_NLOHMANN_JSON_HPP_ | ||
1936 | |||
1937 | #ifndef TILESON_NLOHMANNJSON_HPP | ||
1938 | #define TILESON_NLOHMANNJSON_HPP | ||
1939 | |||
1940 | namespace tson | ||
1941 | { | ||
1942 | class NlohmannJson : public tson::IJson | ||
1943 | { | ||
1944 | public: | ||
1945 | inline NlohmannJson() = default; | ||
1946 | |||
1947 | IJson &operator[](std::string_view key) override | ||
1948 | { | ||
1949 | if(m_arrayCache.count(key.data()) == 0) | ||
1950 | m_arrayCache[key.data()] = std::make_unique<NlohmannJson>(&m_json->operator[](key.data()));//.front()); | ||
1951 | |||
1952 | return *m_arrayCache[key.data()].get(); | ||
1953 | } | ||
1954 | |||
1955 | inline explicit NlohmannJson(nlohmann::json *json) : m_json {json} | ||
1956 | { | ||
1957 | |||
1958 | } | ||
1959 | |||
1960 | inline IJson& at(std::string_view key) override | ||
1961 | { | ||
1962 | if(m_arrayCache.count(key.data()) == 0) | ||
1963 | m_arrayCache[key.data()] = std::make_unique<NlohmannJson>(&m_json->operator[](key.data()));//.front()); | ||
1964 | |||
1965 | return *m_arrayCache[key.data()].get(); | ||
1966 | } | ||
1967 | |||
1968 | inline IJson& at(size_t pos) override | ||
1969 | { | ||
1970 | if(m_arrayPosCache.count(pos) == 0) | ||
1971 | m_arrayPosCache[pos] = std::make_unique<NlohmannJson>(&m_json->at(pos)); | ||
1972 | |||
1973 | return *m_arrayPosCache[pos]; | ||
1974 | } | ||
1975 | |||
1976 | std::vector<std::unique_ptr<IJson>> array() override | ||
1977 | { | ||
1978 | std::vector<std::unique_ptr<IJson>> vec; | ||
1979 | for(auto &item : *m_json) | ||
1980 | { | ||
1981 | nlohmann::json *ptr = &item; | ||
1982 | vec.emplace_back(std::make_unique<NlohmannJson>(ptr)); | ||
1983 | } | ||
1984 | |||
1985 | return vec; | ||
1986 | } | ||
1987 | |||
1988 | inline std::vector<std::unique_ptr<IJson>> &array(std::string_view key) override | ||
1989 | { | ||
1990 | if(m_arrayListDataCache.count(key.data()) == 0) | ||
1991 | { | ||
1992 | if (m_json->count(key.data()) > 0 && m_json->operator[](key.data()).is_array()) | ||
1993 | { | ||
1994 | std::for_each(m_json->operator[](key.data()).begin(), m_json->operator[](key.data()).end(), [&](nlohmann::json &item) | ||
1995 | { | ||
1996 | nlohmann::json *ptr = &item; | ||
1997 | m_arrayListDataCache[key.data()].emplace_back(std::make_unique<NlohmannJson>(ptr)); | ||
1998 | }); | ||
1999 | } | ||
2000 | } | ||
2001 | |||
2002 | return m_arrayListDataCache[key.data()]; | ||
2003 | } | ||
2004 | |||
2005 | [[nodiscard]] inline size_t size() const override | ||
2006 | { | ||
2007 | return m_json->size(); | ||
2008 | } | ||
2009 | |||
2010 | inline bool parse(const fs::path &path) override | ||
2011 | { | ||
2012 | clearCache(); | ||
2013 | m_data = nullptr; | ||
2014 | m_json = nullptr; | ||
2015 | if (fs::exists(path) && fs::is_regular_file(path)) | ||
2016 | { | ||
2017 | m_data = std::make_unique<nlohmann::json>(); | ||
2018 | std::ifstream i(path.u8string()); | ||
2019 | try | ||
2020 | { | ||
2021 | i >> *m_data; | ||
2022 | m_json = m_data.get(); | ||
2023 | } | ||
2024 | catch (const nlohmann::json::parse_error &error) | ||
2025 | { | ||
2026 | std::string message = "Parse error: "; | ||
2027 | message += std::string(error.what()); | ||
2028 | message += std::string("\n"); | ||
2029 | std::cerr << message; | ||
2030 | return false; | ||
2031 | } | ||
2032 | return true; | ||
2033 | } | ||
2034 | return false; | ||
2035 | } | ||
2036 | |||
2037 | inline bool parse(const void *data, size_t size) override | ||
2038 | { | ||
2039 | clearCache(); | ||
2040 | m_json = nullptr; | ||
2041 | m_data = std::make_unique<nlohmann::json>(); | ||
2042 | tson::MemoryStream mem{(uint8_t *) data, size}; | ||
2043 | try | ||
2044 | { | ||
2045 | mem >> *m_data; | ||
2046 | m_json = m_data.get(); | ||
2047 | } | ||
2048 | catch (const nlohmann::json::parse_error &error) | ||
2049 | { | ||
2050 | std::string message = "Parse error: "; | ||
2051 | message += std::string(error.what()); | ||
2052 | message += std::string("\n"); | ||
2053 | std::cerr << message; | ||
2054 | return false; | ||
2055 | } | ||
2056 | return true; | ||
2057 | } | ||
2058 | |||
2059 | [[nodiscard]] inline size_t count(std::string_view key) const override | ||
2060 | { | ||
2061 | return m_json->count(key); | ||
2062 | } | ||
2063 | |||
2064 | [[nodiscard]] inline bool any(std::string_view key) const override | ||
2065 | { | ||
2066 | return count(key) > 0; | ||
2067 | } | ||
2068 | |||
2069 | [[nodiscard]] inline bool isArray() const override | ||
2070 | { | ||
2071 | return m_json->is_array(); | ||
2072 | } | ||
2073 | |||
2074 | [[nodiscard]] inline bool isObject() const override | ||
2075 | { | ||
2076 | return m_json->is_object(); | ||
2077 | } | ||
2078 | |||
2079 | [[nodiscard]] inline bool isNull() const override | ||
2080 | { | ||
2081 | return m_json->is_null(); | ||
2082 | } | ||
2083 | |||
2084 | protected: | ||
2085 | [[nodiscard]] inline int32_t getInt32(std::string_view key) override | ||
2086 | { | ||
2087 | return m_json->operator[](key.data()).get<int32_t>(); | ||
2088 | } | ||
2089 | |||
2090 | [[nodiscard]] inline uint32_t getUInt32(std::string_view key) override | ||
2091 | { | ||
2092 | return m_json->operator[](key.data()).get<uint32_t>(); | ||
2093 | } | ||
2094 | |||
2095 | [[nodiscard]] inline int64_t getInt64(std::string_view key) override | ||
2096 | { | ||
2097 | return m_json->operator[](key.data()).get<int64_t>(); | ||
2098 | } | ||
2099 | |||
2100 | [[nodiscard]] inline uint64_t getUInt64(std::string_view key) override | ||
2101 | { | ||
2102 | return m_json->operator[](key.data()).get<uint64_t>(); | ||
2103 | } | ||
2104 | |||
2105 | [[nodiscard]] inline double getDouble(std::string_view key) override | ||
2106 | { | ||
2107 | return m_json->operator[](key.data()).get<double>(); | ||
2108 | } | ||
2109 | |||
2110 | [[nodiscard]] inline std::string getString(std::string_view key) override | ||
2111 | { | ||
2112 | return m_json->operator[](key.data()).get<std::string>(); | ||
2113 | } | ||
2114 | |||
2115 | [[nodiscard]] inline bool getBool(std::string_view key) override | ||
2116 | { | ||
2117 | return m_json->operator[](key.data()).get<bool>(); | ||
2118 | } | ||
2119 | |||
2120 | [[nodiscard]] float getFloat(std::string_view key) override | ||
2121 | { | ||
2122 | return m_json->operator[](key.data()).get<float>(); | ||
2123 | } | ||
2124 | |||
2125 | [[nodiscard]] inline int32_t getInt32() override | ||
2126 | { | ||
2127 | return m_json->get<int32_t>(); | ||
2128 | } | ||
2129 | |||
2130 | [[nodiscard]] inline uint32_t getUInt32() override | ||
2131 | { | ||
2132 | return m_json->get<uint32_t>(); | ||
2133 | } | ||
2134 | |||
2135 | [[nodiscard]] inline int64_t getInt64() override | ||
2136 | { | ||
2137 | return m_json->get<int64_t>(); | ||
2138 | } | ||
2139 | |||
2140 | [[nodiscard]] inline uint64_t getUInt64() override | ||
2141 | { | ||
2142 | return m_json->get<uint64_t>(); | ||
2143 | } | ||
2144 | |||
2145 | [[nodiscard]] inline double getDouble() override | ||
2146 | { | ||
2147 | return m_json->get<double>(); | ||
2148 | } | ||
2149 | |||
2150 | [[nodiscard]] inline std::string getString() override | ||
2151 | { | ||
2152 | return m_json->get<std::string>(); | ||
2153 | } | ||
2154 | |||
2155 | [[nodiscard]] inline bool getBool() override | ||
2156 | { | ||
2157 | return m_json->get<bool>(); | ||
2158 | } | ||
2159 | |||
2160 | [[nodiscard]] float getFloat() override | ||
2161 | { | ||
2162 | return m_json->get<float>(); | ||
2163 | } | ||
2164 | |||
2165 | private: | ||
2166 | inline void clearCache() | ||
2167 | { | ||
2168 | m_arrayCache.clear(); | ||
2169 | m_arrayPosCache.clear(); | ||
2170 | m_arrayListDataCache.clear(); | ||
2171 | } | ||
2172 | |||
2173 | nlohmann::json *m_json = nullptr; | ||
2174 | std::unique_ptr<nlohmann::json> m_data = nullptr; //Only used if this is the owner json! | ||
2175 | |||
2176 | //Cache! | ||
2177 | std::map<std::string, std::unique_ptr<IJson>> m_arrayCache; | ||
2178 | std::map<size_t, std::unique_ptr<IJson>> m_arrayPosCache; | ||
2179 | std::map<std::string, std::vector<std::unique_ptr<IJson>>> m_arrayListDataCache; | ||
2180 | |||
2181 | }; | ||
2182 | } | ||
2183 | #endif //TILESON_NLOHMANNJSON_HPP | ||
2184 | |||
2185 | #endif //INCLUDE_NLOHMANN_JSON_HPP_ | ||
2186 | /*** End of inlined file: NlohmannJson.hpp ***/ | ||
2187 | |||
2188 | |||
2189 | /*** Start of inlined file: PicoJson.hpp ***/ | ||
2190 | // | ||
2191 | // Created by robin on 11.01.2021. | ||
2192 | // | ||
2193 | |||
2194 | #ifdef picojson_h | ||
2195 | #ifndef TILESON_PICOJSON_HPP | ||
2196 | #define TILESON_PICOJSON_HPP | ||
2197 | |||
2198 | namespace tson | ||
2199 | { | ||
2200 | class PicoJson : public tson::IJson | ||
2201 | { | ||
2202 | public: | ||
2203 | inline PicoJson() = default; | ||
2204 | |||
2205 | IJson &operator[](std::string_view key) override | ||
2206 | { | ||
2207 | if(m_arrayCache.count(key.data()) == 0) | ||
2208 | { | ||
2209 | if(m_json->is<picojson::object>()) | ||
2210 | { | ||
2211 | picojson::object &o = m_json->get<picojson::object>(); | ||
2212 | m_arrayCache[key.data()] = std::make_unique<PicoJson>(&o[key.data()]); | ||
2213 | } | ||
2214 | } | ||
2215 | |||
2216 | return *m_arrayCache[key.data()].get(); | ||
2217 | } | ||
2218 | |||
2219 | inline explicit PicoJson(picojson::value *json) : m_json {json} | ||
2220 | { | ||
2221 | |||
2222 | } | ||
2223 | |||
2224 | inline IJson& at(std::string_view key) override | ||
2225 | { | ||
2226 | if(m_arrayCache.count(key.data()) == 0) | ||
2227 | { | ||
2228 | if(m_json->is<picojson::object>()) | ||
2229 | { | ||
2230 | picojson::object &o = m_json->get<picojson::object>(); | ||
2231 | m_arrayCache[key.data()] = std::make_unique<PicoJson>(&o[key.data()]); | ||
2232 | } | ||
2233 | } | ||
2234 | return *m_arrayCache[key.data()].get(); | ||
2235 | } | ||
2236 | |||
2237 | inline IJson& at(size_t pos) override | ||
2238 | { | ||
2239 | if(m_arrayPosCache.count(pos) == 0) | ||
2240 | { | ||
2241 | picojson::array &a = m_json->get<picojson::array>(); | ||
2242 | m_arrayPosCache[pos] = std::make_unique<PicoJson>(&a.at(pos)); | ||
2243 | } | ||
2244 | |||
2245 | return *m_arrayPosCache[pos]; | ||
2246 | } | ||
2247 | |||
2248 | std::vector<std::unique_ptr<IJson>> array() override | ||
2249 | { | ||
2250 | std::vector<std::unique_ptr<IJson>> vec; | ||
2251 | if(m_json->is<picojson::array>()) | ||
2252 | { | ||
2253 | picojson::array &a = m_json->get<picojson::array>(); | ||
2254 | for (auto &item : a) | ||
2255 | { | ||
2256 | picojson::value *ptr = &item; | ||
2257 | vec.emplace_back(std::make_unique<PicoJson>(ptr)); | ||
2258 | } | ||
2259 | } | ||
2260 | |||
2261 | return vec; | ||
2262 | } | ||
2263 | |||
2264 | inline std::vector<std::unique_ptr<IJson>> &array(std::string_view key) override | ||
2265 | { | ||
2266 | if(m_arrayListDataCache.count(key.data()) == 0) | ||
2267 | { | ||
2268 | if(count(key.data()) > 0) | ||
2269 | { | ||
2270 | if (isObject()) | ||
2271 | { | ||
2272 | picojson::object &obj = m_json->get<picojson::object>(); | ||
2273 | picojson::value &v = obj.at(key.data()); | ||
2274 | bool isArray = v.is<picojson::array>(); | ||
2275 | if (isArray) | ||
2276 | { | ||
2277 | picojson::array &a = v.get<picojson::array>(); | ||
2278 | |||
2279 | std::for_each(a.begin(), a.end(), [&](picojson::value &item) | ||
2280 | { | ||
2281 | picojson::value *ptr = &item; | ||
2282 | m_arrayListDataCache[key.data()].emplace_back(std::make_unique<PicoJson>(ptr)); | ||
2283 | }); | ||
2284 | } | ||
2285 | } | ||
2286 | } | ||
2287 | } | ||
2288 | |||
2289 | return m_arrayListDataCache[key.data()]; | ||
2290 | } | ||
2291 | |||
2292 | [[nodiscard]] inline size_t size() const override | ||
2293 | { | ||
2294 | if (m_json->is<picojson::object>()) | ||
2295 | { | ||
2296 | picojson::object obj = m_json->get<picojson::object>(); | ||
2297 | return obj.size(); | ||
2298 | } | ||
2299 | return 0; | ||
2300 | } | ||
2301 | |||
2302 | inline bool parse(const fs::path &path) override | ||
2303 | { | ||
2304 | clearCache(); | ||
2305 | m_data = nullptr; | ||
2306 | m_json = nullptr; | ||
2307 | if (fs::exists(path) && fs::is_regular_file(path)) | ||
2308 | { | ||
2309 | m_data = std::make_unique<picojson::value>(); | ||
2310 | std::ifstream i(path.u8string()); | ||
2311 | try | ||
2312 | { | ||
2313 | std::string error = picojson::parse(*m_data, i); | ||
2314 | if(!error.empty()) | ||
2315 | { | ||
2316 | std::cerr << "PicoJson parse error: " << error << "\n"; | ||
2317 | return false; | ||
2318 | } | ||
2319 | //i >> *m_data; | ||
2320 | m_json = m_data.get(); | ||
2321 | } | ||
2322 | catch (const std::exception &error) | ||
2323 | { | ||
2324 | std::string message = "Parse error: "; | ||
2325 | message += std::string(error.what()); | ||
2326 | message += std::string("\n"); | ||
2327 | std::cerr << message; | ||
2328 | return false; | ||
2329 | } | ||
2330 | return true; | ||
2331 | } | ||
2332 | return false; | ||
2333 | } | ||
2334 | |||
2335 | inline bool parse(const void *data, size_t size) override | ||
2336 | { | ||
2337 | clearCache(); | ||
2338 | m_json = nullptr; | ||
2339 | m_data = std::make_unique<picojson::value>(); | ||
2340 | tson::MemoryStream mem{(uint8_t *) data, size}; | ||
2341 | try | ||
2342 | { | ||
2343 | std::string error = picojson::parse(*m_data, mem); | ||
2344 | if(!error.empty()) | ||
2345 | { | ||
2346 | std::cerr << "PicoJson parse error: " << error << "\n"; | ||
2347 | return false; | ||
2348 | } | ||
2349 | //mem >> *m_data; | ||
2350 | m_json = m_data.get(); | ||
2351 | } | ||
2352 | catch (const std::exception &error) | ||
2353 | { | ||
2354 | std::string message = "Parse error: "; | ||
2355 | message += std::string(error.what()); | ||
2356 | message += std::string("\n"); | ||
2357 | std::cerr << message; | ||
2358 | return false; | ||
2359 | } | ||
2360 | return true; | ||
2361 | } | ||
2362 | |||
2363 | [[nodiscard]] inline size_t count(std::string_view key) const override | ||
2364 | { | ||
2365 | if (isObject()) | ||
2366 | { | ||
2367 | picojson::object obj = m_json->get<picojson::object>(); | ||
2368 | return obj.count(key.data()); | ||
2369 | } | ||
2370 | |||
2371 | return m_json->contains(key.data()) ? 1 : 0; | ||
2372 | } | ||
2373 | |||
2374 | [[nodiscard]] inline bool any(std::string_view key) const override | ||
2375 | { | ||
2376 | return count(key) > 0; | ||
2377 | } | ||
2378 | |||
2379 | [[nodiscard]] inline bool isArray() const override | ||
2380 | { | ||
2381 | return m_json->is<picojson::array>(); | ||
2382 | } | ||
2383 | |||
2384 | [[nodiscard]] inline bool isObject() const override | ||
2385 | { | ||
2386 | return m_json->is<picojson::object>(); | ||
2387 | } | ||
2388 | |||
2389 | [[nodiscard]] inline bool isNull() const override | ||
2390 | { | ||
2391 | return m_json->is<picojson::null>(); | ||
2392 | } | ||
2393 | |||
2394 | protected: | ||
2395 | [[nodiscard]] inline int32_t getInt32(std::string_view key) override | ||
2396 | { | ||
2397 | picojson::object obj = m_json->get<picojson::object>(); | ||
2398 | return static_cast<int32_t>(getDouble(key)); | ||
2399 | } | ||
2400 | |||
2401 | [[nodiscard]] inline uint32_t getUInt32(std::string_view key) override | ||
2402 | { | ||
2403 | picojson::object obj = m_json->get<picojson::object>(); | ||
2404 | return static_cast<uint32_t>(getDouble(key)); | ||
2405 | } | ||
2406 | |||
2407 | [[nodiscard]] inline int64_t getInt64(std::string_view key) override | ||
2408 | { | ||
2409 | picojson::object obj = m_json->get<picojson::object>(); | ||
2410 | return static_cast<int64_t>(getDouble(key)); | ||
2411 | } | ||
2412 | |||
2413 | [[nodiscard]] inline uint64_t getUInt64(std::string_view key) override | ||
2414 | { | ||
2415 | picojson::object obj = m_json->get<picojson::object>(); | ||
2416 | return static_cast<uint64_t>(getDouble(key)); | ||
2417 | } | ||
2418 | |||
2419 | [[nodiscard]] inline double getDouble(std::string_view key) override | ||
2420 | { | ||
2421 | picojson::object obj = m_json->get<picojson::object>(); | ||
2422 | return obj[key.data()].get<double>(); | ||
2423 | } | ||
2424 | |||
2425 | [[nodiscard]] inline std::string getString(std::string_view key) override | ||
2426 | { | ||
2427 | picojson::object obj = m_json->get<picojson::object>(); | ||
2428 | return obj[key.data()].get<std::string>(); | ||
2429 | } | ||
2430 | |||
2431 | [[nodiscard]] inline bool getBool(std::string_view key) override | ||
2432 | { | ||
2433 | picojson::object obj = m_json->get<picojson::object>(); | ||
2434 | return obj[key.data()].get<bool>(); | ||
2435 | } | ||
2436 | |||
2437 | [[nodiscard]] float getFloat(std::string_view key) override | ||
2438 | { | ||
2439 | picojson::object obj = m_json->get<picojson::object>(); | ||
2440 | return static_cast<float>(getDouble(key)); | ||
2441 | } | ||
2442 | |||
2443 | [[nodiscard]] inline int32_t getInt32() override | ||
2444 | { | ||
2445 | return static_cast<int32_t>(getDouble()); | ||
2446 | } | ||
2447 | |||
2448 | [[nodiscard]] inline uint32_t getUInt32() override | ||
2449 | { | ||
2450 | return static_cast<uint32_t>(getDouble()); | ||
2451 | } | ||
2452 | |||
2453 | [[nodiscard]] inline int64_t getInt64() override | ||
2454 | { | ||
2455 | return static_cast<int64_t>(getDouble()); | ||
2456 | } | ||
2457 | |||
2458 | [[nodiscard]] inline uint64_t getUInt64() override | ||
2459 | { | ||
2460 | return static_cast<uint64_t>(getDouble()); | ||
2461 | } | ||
2462 | |||
2463 | [[nodiscard]] inline double getDouble() override | ||
2464 | { | ||
2465 | return m_json->get<double>(); | ||
2466 | } | ||
2467 | |||
2468 | [[nodiscard]] inline std::string getString() override | ||
2469 | { | ||
2470 | return m_json->get<std::string>(); | ||
2471 | } | ||
2472 | |||
2473 | [[nodiscard]] inline bool getBool() override | ||
2474 | { | ||
2475 | return m_json->get<bool>(); | ||
2476 | } | ||
2477 | |||
2478 | [[nodiscard]] float getFloat() override | ||
2479 | { | ||
2480 | return static_cast<float>(getDouble()); | ||
2481 | } | ||
2482 | |||
2483 | private: | ||
2484 | inline void clearCache() | ||
2485 | { | ||
2486 | m_arrayCache.clear(); | ||
2487 | m_arrayPosCache.clear(); | ||
2488 | m_arrayListDataCache.clear(); | ||
2489 | } | ||
2490 | |||
2491 | picojson::value *m_json = nullptr; | ||
2492 | std::unique_ptr<picojson::value> m_data = nullptr; //Only used if this is the owner json! | ||
2493 | |||
2494 | //Cache! | ||
2495 | std::map<std::string, std::unique_ptr<IJson>> m_arrayCache; | ||
2496 | std::map<size_t, std::unique_ptr<IJson>> m_arrayPosCache; | ||
2497 | std::map<std::string, std::vector<std::unique_ptr<IJson>>> m_arrayListDataCache; | ||
2498 | |||
2499 | }; | ||
2500 | } | ||
2501 | #endif //TILESON_PICOJSON_HPP | ||
2502 | #endif | ||
2503 | |||
2504 | /*** End of inlined file: PicoJson.hpp ***/ | ||
2505 | |||
2506 | //#include "../json/Gason.hpp" //Unsupported | ||
2507 | |||
2508 | /*** Start of inlined file: Json11.hpp ***/ | ||
2509 | // | ||
2510 | // Created by robin on 16.01.2021. | ||
2511 | // | ||
2512 | |||
2513 | #ifndef TILESON_JSON11_HPP | ||
2514 | #define TILESON_JSON11_HPP | ||
2515 | |||
2516 | namespace tson | ||
2517 | { | ||
2518 | class Json11 : public tson::IJson | ||
2519 | { | ||
2520 | public: | ||
2521 | inline Json11() = default; | ||
2522 | |||
2523 | IJson &operator[](std::string_view key) override | ||
2524 | { | ||
2525 | if(m_arrayCache.count(key.data()) == 0) | ||
2526 | { | ||
2527 | if(m_json->is_object()) | ||
2528 | { | ||
2529 | m_arrayCache[key.data()] = std::make_unique<Json11>(m_json->operator[](key.data())); | ||
2530 | } | ||
2531 | } | ||
2532 | |||
2533 | return *m_arrayCache[key.data()].get(); | ||
2534 | } | ||
2535 | |||
2536 | inline explicit Json11(const json11::Json &json) : m_json {&json} | ||
2537 | { | ||
2538 | |||
2539 | } | ||
2540 | |||
2541 | inline IJson& at(std::string_view key) override | ||
2542 | { | ||
2543 | if(m_arrayCache.count(key.data()) == 0) | ||
2544 | { | ||
2545 | if(m_json->is_object()) | ||
2546 | { | ||
2547 | m_arrayCache[key.data()] = std::make_unique<Json11>(m_json->operator[](key.data())); | ||
2548 | } | ||
2549 | } | ||
2550 | return *m_arrayCache[key.data()].get(); | ||
2551 | } | ||
2552 | |||
2553 | inline IJson& at(size_t pos) override | ||
2554 | { | ||
2555 | if(m_arrayPosCache.count(pos) == 0) | ||
2556 | { | ||
2557 | const std::vector<json11::Json> &a = m_json->array_items(); | ||
2558 | m_arrayPosCache[pos] = std::make_unique<Json11>(a.at(pos)); | ||
2559 | } | ||
2560 | |||
2561 | return *m_arrayPosCache[pos]; | ||
2562 | } | ||
2563 | |||
2564 | std::vector<std::unique_ptr<IJson>> array() override | ||
2565 | { | ||
2566 | std::vector<std::unique_ptr<IJson>> vec; | ||
2567 | if(m_json->is_array()) | ||
2568 | { | ||
2569 | for (const json11::Json &item : m_json->array_items()) | ||
2570 | { | ||
2571 | vec.emplace_back(std::make_unique<Json11>(item)); | ||
2572 | } | ||
2573 | } | ||
2574 | |||
2575 | return vec; | ||
2576 | } | ||
2577 | |||
2578 | inline std::vector<std::unique_ptr<IJson>> &array(std::string_view key) override | ||
2579 | { | ||
2580 | if(m_arrayListDataCache.count(key.data()) == 0) | ||
2581 | { | ||
2582 | if(count(key.data()) > 0) | ||
2583 | { | ||
2584 | if(isObject()) | ||
2585 | { | ||
2586 | const json11::Json &v = m_json->operator[](key.data()); | ||
2587 | if(v.is_array()) | ||
2588 | { | ||
2589 | for (const json11::Json &item : v.array_items()) | ||
2590 | { | ||
2591 | m_arrayListDataCache[key.data()].emplace_back(std::make_unique<Json11>(item)); | ||
2592 | } | ||
2593 | } | ||
2594 | } | ||
2595 | } | ||
2596 | } | ||
2597 | |||
2598 | return m_arrayListDataCache[key.data()]; | ||
2599 | } | ||
2600 | |||
2601 | [[nodiscard]] inline size_t size() const override | ||
2602 | { | ||
2603 | if(m_json->is_object()) | ||
2604 | return m_json->object_items().size(); | ||
2605 | else if(m_json->is_array()) | ||
2606 | return m_json->array_items().size(); | ||
2607 | |||
2608 | return 0; | ||
2609 | } | ||
2610 | |||
2611 | inline bool parse(const fs::path &path) override | ||
2612 | { | ||
2613 | clearCache(); | ||
2614 | m_data = nullptr; | ||
2615 | m_json = nullptr; | ||
2616 | if (fs::exists(path) && fs::is_regular_file(path)) | ||
2617 | { | ||
2618 | std::ifstream file(path.u8string()); | ||
2619 | std::string str; | ||
2620 | |||
2621 | file.seekg(0, std::ios::end); | ||
2622 | str.reserve(file.tellg()); | ||
2623 | file.seekg(0, std::ios::beg); | ||
2624 | |||
2625 | str.assign((std::istreambuf_iterator<char>(file)), | ||
2626 | std::istreambuf_iterator<char>()); | ||
2627 | |||
2628 | m_data = std::make_unique<json11::Json>(); | ||
2629 | |||
2630 | try | ||
2631 | { | ||
2632 | std::string strError; | ||
2633 | *m_data = json11::Json::parse(str, strError); | ||
2634 | if(!strError.empty()) | ||
2635 | { | ||
2636 | std::cerr << strError << "\n"; | ||
2637 | return false; | ||
2638 | } | ||
2639 | m_json = m_data.get(); | ||
2640 | } | ||
2641 | catch (const std::exception &error) | ||
2642 | { | ||
2643 | std::string message = "Json11 parse error: "; | ||
2644 | message += std::string(error.what()); | ||
2645 | message += std::string("\n"); | ||
2646 | std::cerr << message; | ||
2647 | return false; | ||
2648 | } | ||
2649 | return true; | ||
2650 | } | ||
2651 | return false; | ||
2652 | } | ||
2653 | |||
2654 | inline bool parse(const void *data, size_t size) override | ||
2655 | { | ||
2656 | clearCache(); | ||
2657 | m_json = nullptr; | ||
2658 | std::string str; | ||
2659 | |||
2660 | str.reserve(size); | ||
2661 | |||
2662 | tson::MemoryStream mem{(uint8_t *) data, size}; | ||
2663 | |||
2664 | str.assign((std::istreambuf_iterator<char>(mem)), | ||
2665 | std::istreambuf_iterator<char>()); | ||
2666 | |||
2667 | m_data = std::make_unique<json11::Json>(); | ||
2668 | |||
2669 | try | ||
2670 | { | ||
2671 | std::string strError; | ||
2672 | |||
2673 | *m_data = json11::Json::parse(str, strError); | ||
2674 | if(!strError.empty()) | ||
2675 | { | ||
2676 | std::cout << strError << "\n"; | ||
2677 | return false; | ||
2678 | } | ||
2679 | m_json = m_data.get(); | ||
2680 | } | ||
2681 | catch (const std::exception &error) | ||
2682 | { | ||
2683 | std::string message = "Json11 parse error: "; | ||
2684 | message += std::string(error.what()); | ||
2685 | message += std::string("\n"); | ||
2686 | std::cerr << message; | ||
2687 | return false; | ||
2688 | } | ||
2689 | return true; | ||
2690 | } | ||
2691 | |||
2692 | [[nodiscard]] inline size_t count(std::string_view key) const override | ||
2693 | { | ||
2694 | if (isObject()) | ||
2695 | { | ||
2696 | //const json11::Json &j = m_json->operator[](key.data()); | ||
2697 | //size_t s1 = j.object_items().size(); | ||
2698 | return m_json->object_items().count(key.data()); | ||
2699 | } | ||
2700 | |||
2701 | return 0; | ||
2702 | } | ||
2703 | |||
2704 | [[nodiscard]] inline bool any(std::string_view key) const override | ||
2705 | { | ||
2706 | return count(key) > 0; | ||
2707 | } | ||
2708 | |||
2709 | [[nodiscard]] inline bool isArray() const override | ||
2710 | { | ||
2711 | return m_json->is_array(); | ||
2712 | } | ||
2713 | |||
2714 | [[nodiscard]] inline bool isObject() const override | ||
2715 | { | ||
2716 | return m_json->is_object(); | ||
2717 | } | ||
2718 | |||
2719 | [[nodiscard]] inline bool isNull() const override | ||
2720 | { | ||
2721 | return m_json->is_null(); | ||
2722 | } | ||
2723 | |||
2724 | protected: | ||
2725 | [[nodiscard]] inline int32_t getInt32(std::string_view key) override | ||
2726 | { | ||
2727 | return static_cast<int32_t>(getDouble(key)); | ||
2728 | } | ||
2729 | |||
2730 | [[nodiscard]] inline uint32_t getUInt32(std::string_view key) override | ||
2731 | { | ||
2732 | return static_cast<uint32_t>(getDouble(key)); | ||
2733 | } | ||
2734 | |||
2735 | [[nodiscard]] inline int64_t getInt64(std::string_view key) override | ||
2736 | { | ||
2737 | return static_cast<int64_t>(getDouble(key)); | ||
2738 | } | ||
2739 | |||
2740 | [[nodiscard]] inline uint64_t getUInt64(std::string_view key) override | ||
2741 | { | ||
2742 | return static_cast<uint64_t>(getDouble(key)); | ||
2743 | } | ||
2744 | |||
2745 | [[nodiscard]] inline double getDouble(std::string_view key) override | ||
2746 | { | ||
2747 | return m_json->operator[](key.data()).number_value(); | ||
2748 | } | ||
2749 | |||
2750 | [[nodiscard]] inline std::string getString(std::string_view key) override | ||
2751 | { | ||
2752 | return m_json->operator[](key.data()).string_value(); // .get<std::string>(); | ||
2753 | } | ||
2754 | |||
2755 | [[nodiscard]] inline bool getBool(std::string_view key) override | ||
2756 | { | ||
2757 | return m_json->operator[](key.data()).bool_value(); | ||
2758 | } | ||
2759 | |||
2760 | [[nodiscard]] float getFloat(std::string_view key) override | ||
2761 | { | ||
2762 | return static_cast<float>(getDouble(key)); | ||
2763 | } | ||
2764 | |||
2765 | [[nodiscard]] inline int32_t getInt32() override | ||
2766 | { | ||
2767 | return static_cast<int32_t>(getDouble()); | ||
2768 | } | ||
2769 | |||
2770 | [[nodiscard]] inline uint32_t getUInt32() override | ||
2771 | { | ||
2772 | return static_cast<uint32_t>(getDouble()); | ||
2773 | } | ||
2774 | |||
2775 | [[nodiscard]] inline int64_t getInt64() override | ||
2776 | { | ||
2777 | return static_cast<int64_t>(getDouble()); | ||
2778 | } | ||
2779 | |||
2780 | [[nodiscard]] inline uint64_t getUInt64() override | ||
2781 | { | ||
2782 | return static_cast<uint64_t>(getDouble()); | ||
2783 | } | ||
2784 | |||
2785 | [[nodiscard]] inline double getDouble() override | ||
2786 | { | ||
2787 | return m_json->number_value(); | ||
2788 | } | ||
2789 | |||
2790 | [[nodiscard]] inline std::string getString() override | ||
2791 | { | ||
2792 | return m_json->string_value(); | ||
2793 | } | ||
2794 | |||
2795 | [[nodiscard]] inline bool getBool() override | ||
2796 | { | ||
2797 | return m_json->bool_value(); | ||
2798 | } | ||
2799 | |||
2800 | [[nodiscard]] float getFloat() override | ||
2801 | { | ||
2802 | return static_cast<float>(getDouble()); | ||
2803 | } | ||
2804 | |||
2805 | private: | ||
2806 | |||
2807 | inline void clearCache() | ||
2808 | { | ||
2809 | m_arrayCache.clear(); | ||
2810 | m_arrayPosCache.clear(); | ||
2811 | m_arrayListDataCache.clear(); | ||
2812 | } | ||
2813 | |||
2814 | //Owner values | ||
2815 | char *m_endptr; | ||
2816 | std::unique_ptr<json11::Json> m_data = nullptr; //Only used if this is the owner json! | ||
2817 | |||
2818 | const json11::Json *m_json = nullptr; | ||
2819 | |||
2820 | //Cache! | ||
2821 | std::map<std::string, std::unique_ptr<IJson>> m_arrayCache; | ||
2822 | std::map<size_t, std::unique_ptr<IJson>> m_arrayPosCache; | ||
2823 | std::map<std::string, std::vector<std::unique_ptr<IJson>>> m_arrayListDataCache; | ||
2824 | |||
2825 | }; | ||
2826 | } | ||
2827 | |||
2828 | #endif //TILESON_JSON11_HPP | ||
2829 | |||
2830 | /*** End of inlined file: Json11.hpp ***/ | ||
2831 | |||
2832 | |||
2833 | |||
2834 | /*** Start of inlined file: Layer.hpp ***/ | ||
2835 | // | ||
2836 | // Created by robin on 22.03.2020. | ||
2837 | // | ||
2838 | |||
2839 | #ifndef TILESON_LAYER_HPP | ||
2840 | #define TILESON_LAYER_HPP | ||
2841 | |||
2842 | #include <set> | ||
2843 | //#include "../external/json.hpp" | ||
2844 | |||
2845 | |||
2846 | /*** Start of inlined file: Chunk.hpp ***/ | ||
2847 | // | ||
2848 | // Created by robin on 22.03.2020. | ||
2849 | // | ||
2850 | |||
2851 | #ifndef TILESON_CHUNK_HPP | ||
2852 | #define TILESON_CHUNK_HPP | ||
2853 | |||
2854 | //#include "../external/json.hpp" | ||
2855 | |||
2856 | namespace tson | ||
2857 | { | ||
2858 | class Chunk | ||
2859 | { | ||
2860 | public: | ||
2861 | inline Chunk() = default; | ||
2862 | inline explicit Chunk(IJson &json); | ||
2863 | inline bool parse(IJson &json); | ||
2864 | |||
2865 | [[nodiscard]] inline const std::vector<int> &getData() const; | ||
2866 | [[nodiscard]] inline const std::string &getBase64Data() const; | ||
2867 | [[nodiscard]] inline const Vector2i &getSize() const; | ||
2868 | [[nodiscard]] inline const Vector2i &getPosition() const; | ||
2869 | |||
2870 | private: | ||
2871 | std::vector<int> m_data; /*! 'data' (when uint array): Array of unsigned int (GIDs) or base64-encoded data. tilelayer only. */ | ||
2872 | std::string m_base64Data; /*! 'data' (when string): Array of unsigned int (GIDs) or base64-encoded data. */ | ||
2873 | tson::Vector2i m_size; /*! x='width' (in tiles) and y='height' (in tiles): */ | ||
2874 | tson::Vector2i m_position; /*! 'x' and 'y' position in tiles */ | ||
2875 | }; | ||
2876 | } | ||
2877 | |||
2878 | #endif //TILESON_CHUNK_HPP | ||
2879 | |||
2880 | /*! | ||
2881 | * Parses 'chunk' data from Tiled json and stores the values in this class | ||
2882 | * @param json json-data | ||
2883 | */ | ||
2884 | tson::Chunk::Chunk(IJson &json) | ||
2885 | { | ||
2886 | parse(json); | ||
2887 | } | ||
2888 | |||
2889 | /*! | ||
2890 | * Parses 'chunk' data from Tiled json and stores the values in this class | ||
2891 | * @param json json-data | ||
2892 | * @return true if all mandatory fields was found. false otherwise. | ||
2893 | */ | ||
2894 | bool tson::Chunk::parse(IJson &json) | ||
2895 | { | ||
2896 | bool allFound = true; | ||
2897 | |||
2898 | if(json.count("width") > 0 && json.count("height") > 0) | ||
2899 | m_size = {json["width"].get<int>(), json["height"].get<int>()}; else allFound = false; | ||
2900 | if(json.count("x") > 0 && json.count("y") > 0) | ||
2901 | m_position = {json["x"].get<int>(), json["y"].get<int>()}; else allFound = false; | ||
2902 | |||
2903 | //Handle DATA (Optional) | ||
2904 | if(json.count("data") > 0) | ||
2905 | { | ||
2906 | if(json["data"].isArray()) | ||
2907 | { | ||
2908 | auto &data = json.array("data"); | ||
2909 | std::for_each(data.begin(), data.end(), [&](std::unique_ptr<IJson> &item) { m_data.push_back(item->get<int>()); }); | ||
2910 | } | ||
2911 | else | ||
2912 | m_base64Data = json["data"].get<std::string>(); | ||
2913 | } | ||
2914 | |||
2915 | return allFound; | ||
2916 | } | ||
2917 | |||
2918 | /*! | ||
2919 | * 'data' (when uint array): Array of unsigned int (GIDs) or base64-encoded data. tilelayer only. | ||
2920 | * @return list of tile ids | ||
2921 | */ | ||
2922 | const std::vector<int> &tson::Chunk::getData() const | ||
2923 | { | ||
2924 | return m_data; | ||
2925 | } | ||
2926 | |||
2927 | /*! | ||
2928 | * 'data' (when string): Array of unsigned int (GIDs) or base64-encoded data. | ||
2929 | * @return base64 string | ||
2930 | */ | ||
2931 | const std::string &tson::Chunk::getBase64Data() const | ||
2932 | { | ||
2933 | return m_base64Data; | ||
2934 | } | ||
2935 | |||
2936 | /*! | ||
2937 | * x='width' (in tiles) and y='height' (in tiles). | ||
2938 | * @return Size (x and y), containing the values from the fields 'width' and 'height' in Tiled | ||
2939 | */ | ||
2940 | const tson::Vector2i &tson::Chunk::getSize() const | ||
2941 | { | ||
2942 | return m_size; | ||
2943 | } | ||
2944 | |||
2945 | /*! | ||
2946 | * 'x' and 'y' position in tiles | ||
2947 | * @return Position in int | ||
2948 | */ | ||
2949 | const tson::Vector2i &tson::Chunk::getPosition() const | ||
2950 | { | ||
2951 | return m_position; | ||
2952 | } | ||
2953 | /*** End of inlined file: Chunk.hpp ***/ | ||
2954 | |||
2955 | |||
2956 | /*** Start of inlined file: Object.hpp ***/ | ||
2957 | // | ||
2958 | // Created by robin on 22.03.2020. | ||
2959 | // | ||
2960 | |||
2961 | #ifndef TILESON_OBJECT_HPP | ||
2962 | #define TILESON_OBJECT_HPP | ||
2963 | |||
2964 | //#include "../external/json.hpp" | ||
2965 | |||
2966 | |||
2967 | /*** Start of inlined file: PropertyCollection.hpp ***/ | ||
2968 | // | ||
2969 | // Created by robin on 22.03.2020. | ||
2970 | // | ||
2971 | |||
2972 | #ifndef TILESON_PROPERTYCOLLECTION_HPP | ||
2973 | #define TILESON_PROPERTYCOLLECTION_HPP | ||
2974 | |||
2975 | |||
2976 | /*** Start of inlined file: Property.hpp ***/ | ||
2977 | // | ||
2978 | // Created by robin on 22.03.2020. | ||
2979 | // | ||
2980 | |||
2981 | #ifndef TILESON_PROPERTY_HPP | ||
2982 | #define TILESON_PROPERTY_HPP | ||
2983 | |||
2984 | //#include "../../TilesonConfig.h" | ||
2985 | |||
2986 | //#if USE_CPP17_FILESYSTEM | ||
2987 | |||
2988 | #include <any> | ||
2989 | #include <string> | ||
2990 | |||
2991 | /*** Start of inlined file: Enums.hpp ***/ | ||
2992 | // | ||
2993 | // Created by robin on 22.03.2020. | ||
2994 | // | ||
2995 | |||
2996 | #ifndef TILESON_ENUMS_HPP | ||
2997 | #define TILESON_ENUMS_HPP | ||
2998 | #include <cstdint> | ||
2999 | |||
3000 | /*** Start of inlined file: EnumBitflags.hpp ***/ | ||
3001 | // | ||
3002 | // Created by robin on 08.11.2020. | ||
3003 | // | ||
3004 | |||
3005 | #ifndef TILESON_ENUMBITFLAGS_HPP | ||
3006 | #define TILESON_ENUMBITFLAGS_HPP | ||
3007 | |||
3008 | #include <type_traits> | ||
3009 | #include <iostream> | ||
3010 | |||
3011 | namespace tson | ||
3012 | { | ||
3013 | #define ENABLE_BITMASK_OPERATORS(x) \ | ||
3014 | template<> \ | ||
3015 | struct EnableBitMaskOperators<x> \ | ||
3016 | { \ | ||
3017 | static const bool enable = true; \ | ||
3018 | }; | ||
3019 | |||
3020 | template<typename Enum> | ||
3021 | struct EnableBitMaskOperators | ||
3022 | { | ||
3023 | static const bool enable = false; | ||
3024 | }; | ||
3025 | |||
3026 | template<typename Enum> | ||
3027 | typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type | ||
3028 | operator |(Enum lhs, Enum rhs) | ||
3029 | { | ||
3030 | static_assert(std::is_enum<Enum>::value, | ||
3031 | "template parameter is not an enum type"); | ||
3032 | |||
3033 | using underlying = typename std::underlying_type<Enum>::type; | ||
3034 | |||
3035 | return static_cast<Enum> ( | ||
3036 | static_cast<underlying>(lhs) | | ||
3037 | static_cast<underlying>(rhs) | ||
3038 | ); | ||
3039 | } | ||
3040 | |||
3041 | //Permissions operator &(Permissions lhs, Permissions rhs) | ||
3042 | template<typename Enum> | ||
3043 | typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type | ||
3044 | operator &(Enum lhs, Enum rhs) | ||
3045 | { | ||
3046 | static_assert(std::is_enum<Enum>::value, | ||
3047 | "template parameter is not an enum type"); | ||
3048 | |||
3049 | using underlying = typename std::underlying_type<Enum>::type; | ||
3050 | |||
3051 | return static_cast<Enum> ( | ||
3052 | static_cast<underlying>(lhs) & | ||
3053 | static_cast<underlying>(rhs) | ||
3054 | ); | ||
3055 | } | ||
3056 | |||
3057 | //Permissions operator ^(Permissions lhs, Permissions rhs) | ||
3058 | template<typename Enum> | ||
3059 | typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type | ||
3060 | operator ^(Enum lhs, Enum rhs) | ||
3061 | { | ||
3062 | static_assert(std::is_enum<Enum>::value, | ||
3063 | "template parameter is not an enum type"); | ||
3064 | |||
3065 | using underlying = typename std::underlying_type<Enum>::type; | ||
3066 | |||
3067 | return static_cast<Enum> ( | ||
3068 | static_cast<underlying>(lhs) ^ | ||
3069 | static_cast<underlying>(rhs) | ||
3070 | ); | ||
3071 | } | ||
3072 | |||
3073 | //Permissions operator ~(Permissions rhs) | ||
3074 | template<typename Enum> | ||
3075 | typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type | ||
3076 | operator ~(Enum rhs) | ||
3077 | { | ||
3078 | static_assert(std::is_enum<Enum>::value, | ||
3079 | "template parameter is not an enum type"); | ||
3080 | |||
3081 | using underlying = typename std::underlying_type<Enum>::type; | ||
3082 | |||
3083 | return static_cast<Enum> ( | ||
3084 | ~static_cast<underlying>(rhs) | ||
3085 | ); | ||
3086 | } | ||
3087 | |||
3088 | //Permissions& operator |=(Permissions &lhs, Permissions rhs) | ||
3089 | template<typename Enum> | ||
3090 | typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type | ||
3091 | &operator |=(Enum &lhs, Enum rhs) | ||
3092 | { | ||
3093 | static_assert(std::is_enum<Enum>::value, | ||
3094 | "template parameter is not an enum type"); | ||
3095 | |||
3096 | using underlying = typename std::underlying_type<Enum>::type; | ||
3097 | |||
3098 | lhs = static_cast<Enum> ( | ||
3099 | static_cast<underlying>(lhs) | | ||
3100 | static_cast<underlying>(rhs) | ||
3101 | ); | ||
3102 | |||
3103 | return lhs; | ||
3104 | } | ||
3105 | |||
3106 | //Permissions& operator &=(Permissions &lhs, Permissions rhs) | ||
3107 | template<typename Enum> | ||
3108 | typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type | ||
3109 | &operator &=(Enum &lhs, Enum rhs) | ||
3110 | { | ||
3111 | static_assert(std::is_enum<Enum>::value, | ||
3112 | "template parameter is not an enum type"); | ||
3113 | |||
3114 | using underlying = typename std::underlying_type<Enum>::type; | ||
3115 | |||
3116 | lhs = static_cast<Enum> ( | ||
3117 | static_cast<underlying>(lhs) & | ||
3118 | static_cast<underlying>(rhs) | ||
3119 | ); | ||
3120 | |||
3121 | return lhs; | ||
3122 | } | ||
3123 | |||
3124 | //Permissions& operator ^=(Permissions &lhs, Permissions rhs) | ||
3125 | template<typename Enum> | ||
3126 | typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type | ||
3127 | &operator ^=(Enum &lhs, Enum rhs) | ||
3128 | { | ||
3129 | static_assert(std::is_enum<Enum>::value, | ||
3130 | "template parameter is not an enum type"); | ||
3131 | |||
3132 | using underlying = typename std::underlying_type<Enum>::type; | ||
3133 | |||
3134 | lhs = static_cast<Enum> ( | ||
3135 | static_cast<underlying>(lhs) ^ | ||
3136 | static_cast<underlying>(rhs) | ||
3137 | ); | ||
3138 | |||
3139 | return lhs; | ||
3140 | } | ||
3141 | } | ||
3142 | |||
3143 | #endif //TILESON_ENUMBITFLAGS_HPP | ||
3144 | |||
3145 | /*** End of inlined file: EnumBitflags.hpp ***/ | ||
3146 | |||
3147 | |||
3148 | namespace tson | ||
3149 | { | ||
3150 | /*! | ||
3151 | * Type used in Property.hpp | ||
3152 | */ | ||
3153 | enum class Type : uint8_t | ||
3154 | { | ||
3155 | Undefined = 0, | ||
3156 | Color = 1, /*! color */ | ||
3157 | File = 2, /*! file */ | ||
3158 | Int = 3, /*! int */ | ||
3159 | Boolean = 4, /*! bool */ | ||
3160 | Float = 5, /*! float */ | ||
3161 | String = 6 /*! string */ | ||
3162 | }; | ||
3163 | |||
3164 | /*! | ||
3165 | * Layer.hpp - LayerType | ||
3166 | * //'type': tilelayer, objectgroup, imagelayer or group | ||
3167 | */ | ||
3168 | enum class LayerType : uint8_t | ||
3169 | { | ||
3170 | Undefined = 0, | ||
3171 | TileLayer = 1, | ||
3172 | ObjectGroup = 2, | ||
3173 | ImageLayer = 3, | ||
3174 | Group = 4 | ||
3175 | }; | ||
3176 | |||
3177 | /*! | ||
3178 | * Map.hpp - ParseStatus | ||
3179 | */ | ||
3180 | enum class ParseStatus : uint8_t | ||
3181 | { | ||
3182 | OK = 0, //OK unless otherwise stated | ||
3183 | FileNotFound = 1, | ||
3184 | ParseError = 2, | ||
3185 | MissingData = 3, | ||
3186 | DecompressionError = 4 | ||
3187 | }; | ||
3188 | |||
3189 | /*! | ||
3190 | * Object.hpp - ObjectType | ||
3191 | */ | ||
3192 | enum class ObjectType : uint8_t | ||
3193 | { | ||
3194 | Undefined = 0, | ||
3195 | Object = 1, | ||
3196 | Ellipse = 2, | ||
3197 | Rectangle = 3, | ||
3198 | Point = 4, | ||
3199 | Polygon = 5, | ||
3200 | Polyline = 6, | ||
3201 | Text = 7, | ||
3202 | Template = 8 | ||
3203 | }; | ||
3204 | |||
3205 | static constexpr uint32_t FLIPPED_HORIZONTALLY_FLAG = 0x80000000; | ||
3206 | static constexpr uint32_t FLIPPED_VERTICALLY_FLAG = 0x40000000; | ||
3207 | static constexpr uint32_t FLIPPED_DIAGONALLY_FLAG = 0x20000000; | ||
3208 | /*! | ||
3209 | * Object.hpp - ObjectFlipFlags | ||
3210 | */ | ||
3211 | enum class TileFlipFlags : uint32_t | ||
3212 | { | ||
3213 | None = 0, | ||
3214 | Diagonally = FLIPPED_DIAGONALLY_FLAG, | ||
3215 | Vertically = FLIPPED_VERTICALLY_FLAG, | ||
3216 | Horizontally = FLIPPED_HORIZONTALLY_FLAG | ||
3217 | }; | ||
3218 | |||
3219 | /*! | ||
3220 | * Tileset.hpp - ObjectAlignment | ||
3221 | */ | ||
3222 | enum class ObjectAlignment : uint8_t | ||
3223 | { | ||
3224 | Unspecified = 0, //unspecified | ||
3225 | TopLeft = 1, //topleft | ||
3226 | Top = 2, //top | ||
3227 | TopRight = 3, //topright | ||
3228 | Left = 4, //left | ||
3229 | Center = 5, //center | ||
3230 | Right = 6, //right | ||
3231 | BottomLeft = 7, //bottomleft | ||
3232 | Bottom = 8, //bottom | ||
3233 | BottomRight = 9 //bottomright | ||
3234 | }; | ||
3235 | |||
3236 | ENABLE_BITMASK_OPERATORS(TileFlipFlags) | ||
3237 | } | ||
3238 | |||
3239 | #endif //TILESON_ENUMS_HPP | ||
3240 | |||
3241 | /*** End of inlined file: Enums.hpp ***/ | ||
3242 | |||
3243 | |||
3244 | //#include "../external/json.hpp" | ||
3245 | |||
3246 | namespace tson | ||
3247 | { | ||
3248 | class Property | ||
3249 | { | ||
3250 | public: | ||
3251 | |||
3252 | //enum class Type : uint8_t | ||
3253 | //{ | ||
3254 | // Undefined = 0, | ||
3255 | // Color = 1, /*! color */ | ||
3256 | // File = 2, /*! file */ | ||
3257 | // Int = 3, /*! int */ | ||
3258 | // Boolean = 4, /*! bool */ | ||
3259 | // Float = 5, /*! float */ | ||
3260 | // String = 6 /*! string */ | ||
3261 | //}; | ||
3262 | |||
3263 | inline Property(); | ||
3264 | inline Property(IJson &json); | ||
3265 | inline Property(std::string name, std::any value, Type type); | ||
3266 | |||
3267 | inline void setValue(const std::any &value); | ||
3268 | inline void setStrValue(const std::string &value); | ||
3269 | inline void setName(const std::string &name); | ||
3270 | |||
3271 | [[nodiscard]] inline const std::type_info& getValueType() const; | ||
3272 | inline std::string getValueTypeInfo(); | ||
3273 | [[nodiscard]]inline const std::any &getValue() const; | ||
3274 | template <typename T> | ||
3275 | inline T getValue() const; | ||
3276 | [[nodiscard]] inline const std::string &getName() const; | ||
3277 | [[nodiscard]] inline Type getType() const; | ||
3278 | |||
3279 | protected: | ||
3280 | inline void setTypeByString(const std::string &str); | ||
3281 | inline void setValueByType(IJson &json); | ||
3282 | |||
3283 | Type m_type = Type::Undefined; | ||
3284 | std::string m_name; | ||
3285 | std::any m_value; //Using std::any to assign any type | ||
3286 | }; | ||
3287 | |||
3288 | template<typename T> | ||
3289 | T Property::getValue() const | ||
3290 | { | ||
3291 | bool isCorrectType = (m_value.type() == typeid(T)); | ||
3292 | |||
3293 | if(isCorrectType) | ||
3294 | { | ||
3295 | T value = std::any_cast<T>(m_value); | ||
3296 | return value; | ||
3297 | } | ||
3298 | else | ||
3299 | { | ||
3300 | static T defaultValue; | ||
3301 | return defaultValue; | ||
3302 | } | ||
3303 | } | ||
3304 | } | ||
3305 | |||
3306 | tson::Property::Property() : m_name {"unnamed"} | ||
3307 | { | ||
3308 | |||
3309 | } | ||
3310 | |||
3311 | tson::Property::Property(IJson &json) | ||
3312 | { | ||
3313 | setTypeByString(json["type"].get<std::string>()); | ||
3314 | setValueByType(json["value"]); | ||
3315 | m_name = json["name"].get<std::string>(); | ||
3316 | } | ||
3317 | |||
3318 | tson::Property::Property(std::string name, std::any value, Type type) : m_name { move(name) }, m_value { move(value) }, m_type {type} | ||
3319 | { | ||
3320 | |||
3321 | } | ||
3322 | |||
3323 | void tson::Property::setValue(const std::any &value) | ||
3324 | { | ||
3325 | m_value = value; | ||
3326 | } | ||
3327 | |||
3328 | /*! | ||
3329 | * Sets the value specifically as string. | ||
3330 | * When not specified as std::string, the default is that the value will be set as char * when adding a value like "test" | ||
3331 | * This function is to make sure the value is added as string. | ||
3332 | * @param value | ||
3333 | */ | ||
3334 | void tson::Property::setStrValue(const std::string &value) | ||
3335 | { | ||
3336 | m_value = value; | ||
3337 | } | ||
3338 | |||
3339 | const std::any &tson::Property::getValue() const | ||
3340 | { | ||
3341 | return m_value; | ||
3342 | } | ||
3343 | |||
3344 | void tson::Property::setName(const std::string &name) | ||
3345 | { | ||
3346 | m_name = name; | ||
3347 | } | ||
3348 | |||
3349 | const std::string &tson::Property::getName() const | ||
3350 | { | ||
3351 | return m_name; | ||
3352 | } | ||
3353 | |||
3354 | /*! | ||
3355 | * Gets the value type as std::value_info. | ||
3356 | * This can easily be compared to types like this: | ||
3357 | * Check if int: getValueType() == typeid(int) | ||
3358 | * @return | ||
3359 | */ | ||
3360 | |||
3361 | const std::type_info &tson::Property::getValueType() const | ||
3362 | { | ||
3363 | return m_value.type(); | ||
3364 | } | ||
3365 | |||
3366 | /*! | ||
3367 | * Gets the value type as std::string | ||
3368 | * Examples of known types: | ||
3369 | * "i" = int | ||
3370 | * "f" = float | ||
3371 | * "b" = bool | ||
3372 | * @return | ||
3373 | */ | ||
3374 | std::string tson::Property::getValueTypeInfo() | ||
3375 | { | ||
3376 | return m_value.type().name(); | ||
3377 | } | ||
3378 | |||
3379 | tson::Type tson::Property::getType() const | ||
3380 | { | ||
3381 | return m_type; | ||
3382 | } | ||
3383 | |||
3384 | void tson::Property::setTypeByString(const std::string &str) | ||
3385 | { | ||
3386 | if(str == "color") | ||
3387 | m_type = tson::Type::Color; | ||
3388 | else if(str == "file") | ||
3389 | m_type = tson::Type::File; | ||
3390 | else if(str == "int") | ||
3391 | m_type = tson::Type::Int; | ||
3392 | else if(str == "bool") | ||
3393 | m_type = tson::Type::Boolean; | ||
3394 | else if(str == "float") | ||
3395 | m_type = tson::Type::Float; | ||
3396 | else if(str == "string") | ||
3397 | m_type = tson::Type::String; | ||
3398 | else | ||
3399 | m_type = tson::Type::Undefined; | ||
3400 | } | ||
3401 | |||
3402 | void tson::Property::setValueByType(IJson &json) | ||
3403 | { | ||
3404 | switch(m_type) | ||
3405 | { | ||
3406 | case Type::Color: | ||
3407 | m_value = Colori(json.get<std::string>()); | ||
3408 | break; | ||
3409 | |||
3410 | case Type::File: | ||
3411 | m_value = fs::path(json.get<std::string>()); | ||
3412 | break; | ||
3413 | |||
3414 | case Type::Int: | ||
3415 | m_value = json.get<int>(); | ||
3416 | break; | ||
3417 | |||
3418 | case Type::Boolean: | ||
3419 | m_value = json.get<bool>(); | ||
3420 | break; | ||
3421 | |||
3422 | case Type::Float: | ||
3423 | m_value = json.get<float>(); | ||
3424 | break; | ||
3425 | |||
3426 | case Type::String: | ||
3427 | setStrValue(json.get<std::string>()); | ||
3428 | break; | ||
3429 | |||
3430 | default: | ||
3431 | setStrValue(json.get<std::string>()); | ||
3432 | break; | ||
3433 | |||
3434 | } | ||
3435 | } | ||
3436 | |||
3437 | #endif //TILESON_PROPERTY_HPP | ||
3438 | |||
3439 | /*** End of inlined file: Property.hpp ***/ | ||
3440 | |||
3441 | //#include "../external/json.hpp" | ||
3442 | #include <map> | ||
3443 | |||
3444 | namespace tson | ||
3445 | { | ||
3446 | class PropertyCollection | ||
3447 | { | ||
3448 | public: | ||
3449 | inline PropertyCollection() = default; | ||
3450 | |||
3451 | inline explicit PropertyCollection(std::string id); | ||
3452 | |||
3453 | inline tson::Property * add(const tson::Property &property); | ||
3454 | inline tson::Property * add(IJson &json); | ||
3455 | inline tson::Property * add(const std::string &name, const std::any &value, tson::Type type); | ||
3456 | |||
3457 | inline void remove(const std::string &name); | ||
3458 | |||
3459 | inline void setValue(const std::string &name, const std::any &value); | ||
3460 | inline void setId(const std::string &id); | ||
3461 | |||
3462 | inline bool hasProperty(const std::string &name); | ||
3463 | inline tson::Property * getProperty(const std::string &name); | ||
3464 | inline std::map<std::string, Property> &getProperties(); | ||
3465 | inline std::vector<Property*> get(); | ||
3466 | template <typename T> | ||
3467 | inline T getValue(const std::string &name); | ||
3468 | [[nodiscard]] inline const std::string &getId() const; | ||
3469 | [[nodiscard]] inline size_t getSize() const; | ||
3470 | |||
3471 | protected: | ||
3472 | std::string m_id; | ||
3473 | std::map<std::string, tson::Property> m_properties; | ||
3474 | }; | ||
3475 | } | ||
3476 | |||
3477 | template<typename T> | ||
3478 | T tson::PropertyCollection::getValue(const std::string &name) | ||
3479 | { | ||
3480 | static T defaultT; | ||
3481 | return (m_properties.count(name) > 0) ? m_properties[name].getValue<T>() : defaultT; | ||
3482 | } | ||
3483 | |||
3484 | tson::PropertyCollection::PropertyCollection(std::string id) : m_id {std::move(id)} | ||
3485 | { | ||
3486 | |||
3487 | } | ||
3488 | |||
3489 | tson::Property *tson::PropertyCollection::add(const tson::Property &property) | ||
3490 | { | ||
3491 | m_properties[property.getName()] = property; | ||
3492 | return &m_properties[property.getName()]; | ||
3493 | } | ||
3494 | |||
3495 | tson::Property *tson::PropertyCollection::add(IJson &json) | ||
3496 | { | ||
3497 | tson::Property property = tson::Property(json); | ||
3498 | std::string name = property.getName(); | ||
3499 | m_properties[name] = std::move(property); | ||
3500 | return &m_properties[name]; | ||
3501 | } | ||
3502 | |||
3503 | tson::Property *tson::PropertyCollection::add(const std::string &name, const std::any &value, tson::Type type) | ||
3504 | { | ||
3505 | m_properties[name] = {name, value, type}; | ||
3506 | return &m_properties[name]; | ||
3507 | } | ||
3508 | |||
3509 | void tson::PropertyCollection::remove(const std::string &name) | ||
3510 | { | ||
3511 | m_properties.erase(name); | ||
3512 | } | ||
3513 | |||
3514 | /*! | ||
3515 | * Sets a value IF the property already exists. Does nothing otherwise. | ||
3516 | * See add() for adding new properties | ||
3517 | * @param name | ||
3518 | * @param value | ||
3519 | */ | ||
3520 | void tson::PropertyCollection::setValue(const std::string &name, const std::any &value) | ||
3521 | { | ||
3522 | if(m_properties.count(name) > 0) | ||
3523 | m_properties[name].setValue(value); | ||
3524 | } | ||
3525 | |||
3526 | void tson::PropertyCollection::setId(const std::string &id) | ||
3527 | { | ||
3528 | m_id = id; | ||
3529 | } | ||
3530 | |||
3531 | bool tson::PropertyCollection::hasProperty(const std::string &name) | ||
3532 | { | ||
3533 | return m_properties.count(name) > 0; | ||
3534 | } | ||
3535 | |||
3536 | tson::Property *tson::PropertyCollection::getProperty(const std::string &name) | ||
3537 | { | ||
3538 | return (m_properties.count(name) > 0) ? &m_properties[name] : nullptr; | ||
3539 | } | ||
3540 | |||
3541 | std::map<std::string, tson::Property> &tson::PropertyCollection::getProperties() | ||
3542 | { | ||
3543 | return m_properties; | ||
3544 | } | ||
3545 | |||
3546 | /*! | ||
3547 | * Gets vector of pointers to all the existing properties | ||
3548 | * @return | ||
3549 | */ | ||
3550 | std::vector<tson::Property *> tson::PropertyCollection::get() | ||
3551 | { | ||
3552 | std::vector<tson::Property *> props; | ||
3553 | for(auto &i : m_properties) | ||
3554 | props.emplace_back(&i.second); | ||
3555 | |||
3556 | return props; | ||
3557 | } | ||
3558 | |||
3559 | const std::string &tson::PropertyCollection::getId() const | ||
3560 | { | ||
3561 | return m_id; | ||
3562 | } | ||
3563 | |||
3564 | size_t tson::PropertyCollection::getSize() const | ||
3565 | { | ||
3566 | return m_properties.size(); | ||
3567 | } | ||
3568 | |||
3569 | #endif //TILESON_PROPERTYCOLLECTION_HPP | ||
3570 | |||
3571 | /*** End of inlined file: PropertyCollection.hpp ***/ | ||
3572 | |||
3573 | |||
3574 | /*** Start of inlined file: Text.hpp ***/ | ||
3575 | // | ||
3576 | // Created by robin on 05.08.2019. | ||
3577 | // | ||
3578 | |||
3579 | #ifndef TILESON_TEXT_HPP | ||
3580 | #define TILESON_TEXT_HPP | ||
3581 | |||
3582 | #include <string> | ||
3583 | |||
3584 | namespace tson | ||
3585 | { | ||
3586 | class Text | ||
3587 | { | ||
3588 | public: | ||
3589 | inline Text() = default; | ||
3590 | /*! | ||
3591 | * | ||
3592 | * @param _text Text | ||
3593 | * @param _wrap If the text is marked as wrapped | ||
3594 | */ | ||
3595 | inline Text(std::string _text, bool _wrap, tson::Colori _color) : text {std::move(_text)}, wrap {_wrap}, color {_color} {}; | ||
3596 | //Just make it simple | ||
3597 | std::string text; | ||
3598 | tson::Colori color; | ||
3599 | bool wrap{}; | ||
3600 | }; | ||
3601 | } | ||
3602 | |||
3603 | #endif //TILESON_TEXT_HPP | ||
3604 | |||
3605 | /*** End of inlined file: Text.hpp ***/ | ||
3606 | |||
3607 | namespace tson | ||
3608 | { | ||
3609 | class Object | ||
3610 | { | ||
3611 | public: | ||
3612 | //enum class Type : uint8_t | ||
3613 | //{ | ||
3614 | // Undefined = 0, | ||
3615 | // Object = 1, | ||
3616 | // Ellipse = 2, | ||
3617 | // Rectangle = 3, | ||
3618 | // Point = 4, | ||
3619 | // Polygon = 5, | ||
3620 | // Polyline = 6, | ||
3621 | // Text = 7, | ||
3622 | // Template = 8 | ||
3623 | //}; | ||
3624 | |||
3625 | inline Object() = default; | ||
3626 | inline explicit Object(IJson &json); | ||
3627 | inline bool parse(IJson &json); | ||
3628 | |||
3629 | [[nodiscard]] inline ObjectType getObjectType() const; | ||
3630 | [[nodiscard]] inline bool isEllipse() const; | ||
3631 | [[nodiscard]] inline uint32_t getGid() const; | ||
3632 | [[nodiscard]] inline const Vector2i &getSize() const; | ||
3633 | [[nodiscard]] inline int getId() const; | ||
3634 | [[nodiscard]] inline const std::string &getName() const; | ||
3635 | [[nodiscard]] inline bool isPoint() const; | ||
3636 | [[nodiscard]] inline float getRotation() const; | ||
3637 | [[nodiscard]] inline const std::string &getTemplate() const; | ||
3638 | [[nodiscard]] inline const std::string &getType() const; | ||
3639 | [[nodiscard]] inline bool isVisible() const; | ||
3640 | [[nodiscard]] inline const Vector2i &getPosition() const; | ||
3641 | |||
3642 | [[nodiscard]] inline const std::vector<tson::Vector2i> &getPolygons() const; | ||
3643 | [[nodiscard]] inline const std::vector<tson::Vector2i> &getPolylines() const; | ||
3644 | [[nodiscard]] inline PropertyCollection &getProperties(); | ||
3645 | [[nodiscard]] inline const Text &getText() const; | ||
3646 | |||
3647 | template <typename T> | ||
3648 | inline T get(const std::string &name); | ||
3649 | inline tson::Property * getProp(const std::string &name); | ||
3650 | |||
3651 | //v1.2.0-stuff | ||
3652 | [[nodiscard]] inline TileFlipFlags getFlipFlags() const; | ||
3653 | inline bool hasFlipFlags(TileFlipFlags flags); | ||
3654 | |||
3655 | private: | ||
3656 | inline void setObjectTypeByJson(IJson &json); | ||
3657 | |||
3658 | ObjectType m_objectType = ObjectType::Undefined; /*! Says with object type this is */ | ||
3659 | bool m_ellipse {}; /*! 'ellipse': Used to mark an object as an ellipse */ | ||
3660 | uint32_t m_gid {}; /*! 'gid': GID, only if object comes from a Tilemap */ | ||
3661 | tson::Vector2i m_size; /*! x = 'width' (Width in pixels), y = 'height' (Height in pixels). Ignored if using a gid.)*/ | ||
3662 | int m_id{}; /*! 'id': Incremental id - unique across all objects */ | ||
3663 | std::string m_name; /*! 'name': String assigned to name field in editor*/ | ||
3664 | bool m_point {}; /*! 'point': Used to mark an object as a point */ | ||
3665 | std::vector<tson::Vector2i> m_polygon; /*! 'polygon': A list of x,y coordinates in pixels */ | ||
3666 | std::vector<tson::Vector2i> m_polyline; /*! 'polyline': A list of x,y coordinates in pixels */ | ||
3667 | tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */ | ||
3668 | float m_rotation {}; /*! 'rotation': Angle in degrees clockwise */ | ||
3669 | std::string m_template; /*! 'template': Reference to a template file, in case object is a template instance */ | ||
3670 | tson::Text m_text; /*! first: 'text' second: 'wrap' */ | ||
3671 | std::string m_type; /*! 'type': String assigned to type field in editor */ | ||
3672 | bool m_visible {}; /*! 'visible': Whether object is shown in editor. */ | ||
3673 | tson::Vector2i m_position; /*! 'x' and 'y': coordinate in pixels */ | ||
3674 | |||
3675 | //v1.2.0-stuff | ||
3676 | tson::TileFlipFlags m_flipFlags = TileFlipFlags::None; /*! Resolved using bit 32, 31 and 30 from gid */ | ||
3677 | }; | ||
3678 | |||
3679 | /*! | ||
3680 | * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>") | ||
3681 | * @tparam T The template value | ||
3682 | * @param name Name of the property | ||
3683 | * @return The actual value, if it exists. Otherwise: The default value of the type. | ||
3684 | */ | ||
3685 | template<typename T> | ||
3686 | T tson::Object::get(const std::string &name) | ||
3687 | { | ||
3688 | return m_properties.getValue<T>(name); | ||
3689 | } | ||
3690 | } | ||
3691 | |||
3692 | /*! | ||
3693 | * Parses a json Tiled object | ||
3694 | * @param json | ||
3695 | */ | ||
3696 | tson::Object::Object(IJson &json) | ||
3697 | { | ||
3698 | parse(json); | ||
3699 | } | ||
3700 | |||
3701 | /*! | ||
3702 | * Parses a json Tiled object and autoamtically determines the object type based on the data presented. | ||
3703 | * Call getObjectType() to see what object type it is. | ||
3704 | * @param json | ||
3705 | * @return true if all mandatory fields was found. false otherwise. | ||
3706 | */ | ||
3707 | bool tson::Object::parse(IJson &json) | ||
3708 | { | ||
3709 | bool allFound = true; | ||
3710 | |||
3711 | if(json.count("ellipse") > 0) m_ellipse = json["ellipse"].get<bool>(); //Optional | ||
3712 | if(json.count("gid") > 0) | ||
3713 | { | ||
3714 | uint32_t gid = json["gid"].get<uint32_t>(); //Optional | ||
3715 | if (gid & FLIPPED_HORIZONTALLY_FLAG) m_flipFlags |= TileFlipFlags::Horizontally; | ||
3716 | if (gid & FLIPPED_VERTICALLY_FLAG) m_flipFlags |= TileFlipFlags::Vertically; | ||
3717 | if (gid & FLIPPED_DIAGONALLY_FLAG) m_flipFlags |= TileFlipFlags::Diagonally; | ||
3718 | |||
3719 | // Clear flags | ||
3720 | gid &= ~(FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG); | ||
3721 | |||
3722 | m_gid = gid; | ||
3723 | } | ||
3724 | if(json.count("id") > 0) m_id = json["id"].get<int>(); else allFound = false; | ||
3725 | if(json.count("name") > 0) m_name = json["name"].get<std::string>(); else allFound = false; | ||
3726 | if(json.count("point") > 0) m_point = json["point"].get<bool>(); //Optional | ||
3727 | if(json.count("rotation") > 0) m_rotation = json["rotation"].get<float>(); else allFound = false; | ||
3728 | if(json.count("template") > 0) m_template = json["template"].get<std::string>(); //Optional | ||
3729 | if(json.count("type") > 0) m_type = json["type"].get<std::string>(); else allFound = false; | ||
3730 | if(json.count("visible") > 0) m_visible = json["visible"].get<bool>(); else allFound = false; | ||
3731 | |||
3732 | if(json.count("width") > 0 && json.count("height") > 0) | ||
3733 | m_size = {json["width"].get<int>(), json["height"].get<int>()}; else allFound = false; | ||
3734 | if(json.count("x") > 0 && json.count("y") > 0) | ||
3735 | m_position = {json["x"].get<int>(), json["y"].get<int>()}; else allFound = false; | ||
3736 | |||
3737 | if(json.count("text") > 0) | ||
3738 | { | ||
3739 | bool hasColor = json["text"].count("color") > 0; | ||
3740 | tson::Color c = (hasColor) ? tson::Colori(json["text"]["color"].get<std::string>()) : tson::Colori(); | ||
3741 | m_text = {json["text"]["text"].get<std::string>(), json["text"]["wrap"].get<bool>(), c}; //Optional | ||
3742 | } | ||
3743 | |||
3744 | setObjectTypeByJson(json); | ||
3745 | |||
3746 | if(m_objectType == ObjectType::Template) | ||
3747 | allFound = true; //Just accept anything with this type | ||
3748 | |||
3749 | //More advanced data | ||
3750 | if(json.count("polygon") > 0 && json["polygon"].isArray()) | ||
3751 | { | ||
3752 | auto &polygon = json.array("polygon"); | ||
3753 | std::for_each(polygon.begin(), polygon.end(),[&](std::unique_ptr<IJson> &item) | ||
3754 | { | ||
3755 | IJson &j = *item; | ||
3756 | m_polygon.emplace_back(j["x"].get<int>(), j["y"].get<int>()); | ||
3757 | }); | ||
3758 | |||
3759 | } | ||
3760 | |||
3761 | if(json.count("polyline") > 0 && json["polyline"].isArray()) | ||
3762 | { | ||
3763 | auto &polyline = json.array("polyline"); | ||
3764 | std::for_each(polyline.begin(), polyline.end(),[&](std::unique_ptr<IJson> &item) | ||
3765 | { | ||
3766 | IJson &j = *item; | ||
3767 | m_polyline.emplace_back(j["x"].get<int>(), j["y"].get<int>()); | ||
3768 | }); | ||
3769 | } | ||
3770 | |||
3771 | if(json.count("properties") > 0 && json["properties"].isArray()) | ||
3772 | { | ||
3773 | auto &properties = json.array("properties"); | ||
3774 | std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item) | ||
3775 | { | ||
3776 | m_properties.add(*item); | ||
3777 | }); | ||
3778 | } | ||
3779 | |||
3780 | return allFound; | ||
3781 | } | ||
3782 | |||
3783 | /*! | ||
3784 | * Sets an object type based on json data. | ||
3785 | * @param json | ||
3786 | */ | ||
3787 | void tson::Object::setObjectTypeByJson(IJson &json) | ||
3788 | { | ||
3789 | m_objectType = ObjectType::Undefined; | ||
3790 | if(m_ellipse) | ||
3791 | m_objectType = ObjectType::Ellipse; | ||
3792 | else if(m_point) | ||
3793 | m_objectType = ObjectType::Point; | ||
3794 | else if(json.count("polygon") > 0) | ||
3795 | m_objectType = ObjectType::Polygon; | ||
3796 | else if(json.count("polyline") > 0) | ||
3797 | m_objectType = ObjectType::Polyline; | ||
3798 | else if(json.count("text") > 0) | ||
3799 | m_objectType = ObjectType::Text; | ||
3800 | else if(json.count("gid") > 0) | ||
3801 | m_objectType = ObjectType::Object; | ||
3802 | else if(json.count("template") > 0) | ||
3803 | m_objectType = ObjectType::Template; | ||
3804 | else | ||
3805 | m_objectType = ObjectType::Rectangle; | ||
3806 | } | ||
3807 | |||
3808 | /*! | ||
3809 | * Gets what type of object this is. | ||
3810 | * @return | ||
3811 | */ | ||
3812 | |||
3813 | tson::ObjectType tson::Object::getObjectType() const | ||
3814 | { | ||
3815 | return m_objectType; | ||
3816 | } | ||
3817 | |||
3818 | /*! | ||
3819 | * 'ellipse': Used to mark an object as an ellipse | ||
3820 | * @return | ||
3821 | */ | ||
3822 | bool tson::Object::isEllipse() const | ||
3823 | { | ||
3824 | return m_ellipse; | ||
3825 | } | ||
3826 | |||
3827 | /*! | ||
3828 | * 'gid': GID, only if object comes from a Tilemap | ||
3829 | * @return | ||
3830 | */ | ||
3831 | uint32_t tson::Object::getGid() const | ||
3832 | { | ||
3833 | return m_gid; | ||
3834 | } | ||
3835 | |||
3836 | /*! | ||
3837 | * x = 'width' (Width in pixels), y = 'height' (Height in pixels). Ignored if using a gid.) | ||
3838 | * @return | ||
3839 | */ | ||
3840 | const tson::Vector2i &tson::Object::getSize() const | ||
3841 | { | ||
3842 | return m_size; | ||
3843 | } | ||
3844 | |||
3845 | /*! | ||
3846 | * 'id': Incremental id - unique across all objects | ||
3847 | * @return | ||
3848 | */ | ||
3849 | int tson::Object::getId() const | ||
3850 | { | ||
3851 | return m_id; | ||
3852 | } | ||
3853 | |||
3854 | /*! | ||
3855 | * 'name': String assigned to name field in editor | ||
3856 | * @return | ||
3857 | */ | ||
3858 | const std::string &tson::Object::getName() const | ||
3859 | { | ||
3860 | return m_name; | ||
3861 | } | ||
3862 | |||
3863 | /*! | ||
3864 | * 'point': Used to mark an object as a point | ||
3865 | * @return true if the object is of type point | ||
3866 | */ | ||
3867 | bool tson::Object::isPoint() const | ||
3868 | { | ||
3869 | return m_point; | ||
3870 | } | ||
3871 | |||
3872 | /*! | ||
3873 | * 'rotation': Angle in degrees clockwise | ||
3874 | * @return | ||
3875 | */ | ||
3876 | float tson::Object::getRotation() const | ||
3877 | { | ||
3878 | return m_rotation; | ||
3879 | } | ||
3880 | |||
3881 | /*! | ||
3882 | * 'template': Reference to a template file, in case object is a template instance | ||
3883 | * @return | ||
3884 | */ | ||
3885 | const std::string &tson::Object::getTemplate() const | ||
3886 | { | ||
3887 | return m_template; | ||
3888 | } | ||
3889 | |||
3890 | /*! | ||
3891 | * 'type': String assigned to type field in editor | ||
3892 | * @return | ||
3893 | */ | ||
3894 | const std::string &tson::Object::getType() const | ||
3895 | { | ||
3896 | return m_type; | ||
3897 | } | ||
3898 | |||
3899 | /*! | ||
3900 | * 'visible': Whether object is shown in editor. | ||
3901 | * @return | ||
3902 | */ | ||
3903 | bool tson::Object::isVisible() const | ||
3904 | { | ||
3905 | return m_visible; | ||
3906 | } | ||
3907 | |||
3908 | /*! | ||
3909 | * 'x' and 'y': coordinate in pixels | ||
3910 | * @return | ||
3911 | */ | ||
3912 | const tson::Vector2i &tson::Object::getPosition() const | ||
3913 | { | ||
3914 | return m_position; | ||
3915 | } | ||
3916 | |||
3917 | /*! | ||
3918 | * 'polygon': A list of x,y coordinates in pixels. | ||
3919 | * If this is a Polygon type, this function will return the points used to create it | ||
3920 | * @return | ||
3921 | */ | ||
3922 | const std::vector<tson::Vector2i> &tson::Object::getPolygons() const | ||
3923 | { | ||
3924 | return m_polygon; | ||
3925 | } | ||
3926 | |||
3927 | /*! | ||
3928 | * 'polyline': A list of x,y coordinates in pixels | ||
3929 | * If this is a Polyline type, this function will return the points used to create it | ||
3930 | * @return | ||
3931 | */ | ||
3932 | const std::vector<tson::Vector2i> &tson::Object::getPolylines() const | ||
3933 | { | ||
3934 | return m_polyline; | ||
3935 | } | ||
3936 | |||
3937 | /*! | ||
3938 | * 'properties': A list of properties (name, value, type). | ||
3939 | * @return | ||
3940 | */ | ||
3941 | tson::PropertyCollection &tson::Object::getProperties() | ||
3942 | { | ||
3943 | return m_properties; | ||
3944 | } | ||
3945 | |||
3946 | /*! | ||
3947 | * 'type': String assigned to type field in editor | ||
3948 | * @return | ||
3949 | */ | ||
3950 | const tson::Text &tson::Object::getText() const | ||
3951 | { | ||
3952 | return m_text; | ||
3953 | } | ||
3954 | |||
3955 | /*! | ||
3956 | * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>"); | ||
3957 | * @param name Name of the property | ||
3958 | * @return | ||
3959 | */ | ||
3960 | tson::Property *tson::Object::getProp(const std::string &name) | ||
3961 | { | ||
3962 | if(m_properties.hasProperty(name)) | ||
3963 | return m_properties.getProperty(name); | ||
3964 | return nullptr; | ||
3965 | } | ||
3966 | |||
3967 | /*! | ||
3968 | * Get all flip flags | ||
3969 | * @return | ||
3970 | */ | ||
3971 | tson::TileFlipFlags tson::Object::getFlipFlags() const | ||
3972 | { | ||
3973 | return m_flipFlags; | ||
3974 | } | ||
3975 | |||
3976 | /*! | ||
3977 | * | ||
3978 | * @param flags Which flags to check for. Several flags can be checked at once using the bitwise or operator. | ||
3979 | * Example: | ||
3980 | * hasFlipFlags(TileFlipFlags::Vertically | TileFlipFlags::Horizontally) | ||
3981 | * | ||
3982 | * @return true if the flag(s) specified are set | ||
3983 | */ | ||
3984 | bool tson::Object::hasFlipFlags(TileFlipFlags flags) | ||
3985 | { | ||
3986 | return ((m_flipFlags & flags) == flags) ? true : false; | ||
3987 | } | ||
3988 | |||
3989 | #endif //TILESON_OBJECT_HPP | ||
3990 | |||
3991 | /*** End of inlined file: Object.hpp ***/ | ||
3992 | |||
3993 | |||
3994 | /*** Start of inlined file: TileObject.hpp ***/ | ||
3995 | // | ||
3996 | // Created by robin on 26.07.2020. | ||
3997 | // | ||
3998 | |||
3999 | #ifndef TILESON_TILEOBJECT_HPP | ||
4000 | #define TILESON_TILEOBJECT_HPP | ||
4001 | |||
4002 | |||
4003 | /*** Start of inlined file: Rect.hpp ***/ | ||
4004 | // | ||
4005 | // Created by robin on 24.07.2020. | ||
4006 | // | ||
4007 | |||
4008 | #ifndef TILESON_RECT_HPP | ||
4009 | #define TILESON_RECT_HPP | ||
4010 | |||
4011 | namespace tson | ||
4012 | { | ||
4013 | class Rect | ||
4014 | { | ||
4015 | public: | ||
4016 | |||
4017 | inline Rect(); | ||
4018 | inline Rect(int x_, int y_, int width_, int height_); | ||
4019 | |||
4020 | inline bool operator==(const Rect &rhs) const; | ||
4021 | inline bool operator!=(const Rect &rhs) const; | ||
4022 | |||
4023 | int x; | ||
4024 | int y; | ||
4025 | int width; | ||
4026 | int height; | ||
4027 | }; | ||
4028 | |||
4029 | Rect::Rect() | ||
4030 | { | ||
4031 | |||
4032 | } | ||
4033 | |||
4034 | Rect::Rect(int x_, int y_, int width_, int height_) | ||
4035 | { | ||
4036 | x = x_; | ||
4037 | y = y_; | ||
4038 | width = width_; | ||
4039 | height = height_; | ||
4040 | } | ||
4041 | |||
4042 | bool Rect::operator==(const Rect &rhs) const | ||
4043 | { | ||
4044 | return x == rhs.x && | ||
4045 | y == rhs.y && | ||
4046 | width == rhs.width && | ||
4047 | height == rhs.height; | ||
4048 | } | ||
4049 | |||
4050 | bool Rect::operator!=(const Rect &rhs) const | ||
4051 | { | ||
4052 | return !(rhs == *this); | ||
4053 | } | ||
4054 | } | ||
4055 | |||
4056 | #endif //TILESON_RECT_HPP | ||
4057 | |||
4058 | /*** End of inlined file: Rect.hpp ***/ | ||
4059 | |||
4060 | namespace tson | ||
4061 | { | ||
4062 | class Tile; | ||
4063 | class TileObject | ||
4064 | { | ||
4065 | public: | ||
4066 | inline TileObject() = default; | ||
4067 | inline TileObject(const std::tuple<int, int> &posInTileUnits, tson::Tile *tile); | ||
4068 | |||
4069 | inline void initialize(const std::tuple<int, int> &posInTileUnits, tson::Tile *tile); //Defined in tileson_forward.hpp | ||
4070 | |||
4071 | inline Tile *getTile() const; | ||
4072 | inline const Vector2i &getPositionInTileUnits() const; | ||
4073 | inline const Vector2f &getPosition() const; | ||
4074 | inline const tson::Rect &getDrawingRect() const; //Defined in tileson_forward.hpp | ||
4075 | |||
4076 | private: | ||
4077 | tson::Tile *m_tile; | ||
4078 | tson::Vector2i m_posInTileUnits; | ||
4079 | tson::Vector2f m_position; | ||
4080 | |||
4081 | }; | ||
4082 | |||
4083 | TileObject::TileObject(const std::tuple<int, int> &posInTileUnits, tson::Tile *tile) | ||
4084 | { | ||
4085 | initialize(posInTileUnits, tile); | ||
4086 | } | ||
4087 | |||
4088 | /*! | ||
4089 | * Get a pointer to the related tile | ||
4090 | * @return | ||
4091 | */ | ||
4092 | Tile *TileObject::getTile() const | ||
4093 | { | ||
4094 | return m_tile; | ||
4095 | } | ||
4096 | |||
4097 | /*! | ||
4098 | * Gets the position of the tile in tile units | ||
4099 | * @return | ||
4100 | */ | ||
4101 | const Vector2i &TileObject::getPositionInTileUnits() const | ||
4102 | { | ||
4103 | return m_posInTileUnits; | ||
4104 | } | ||
4105 | |||
4106 | /*! | ||
4107 | * Gets the position of the tile in pixels. | ||
4108 | * @return | ||
4109 | */ | ||
4110 | const Vector2f &TileObject::getPosition() const | ||
4111 | { | ||
4112 | return m_position; | ||
4113 | } | ||
4114 | } | ||
4115 | |||
4116 | #endif //TILESON_TILEOBJECT_HPP | ||
4117 | |||
4118 | /*** End of inlined file: TileObject.hpp ***/ | ||
4119 | |||
4120 | |||
4121 | /*** Start of inlined file: FlaggedTile.hpp ***/ | ||
4122 | // | ||
4123 | // Created by robin on 13.11.2020. | ||
4124 | // | ||
4125 | |||
4126 | #ifndef TILESON_FLAGGEDTILE_HPP | ||
4127 | #define TILESON_FLAGGEDTILE_HPP | ||
4128 | |||
4129 | namespace tson | ||
4130 | { | ||
4131 | class FlaggedTile | ||
4132 | { | ||
4133 | |||
4134 | public: | ||
4135 | FlaggedTile(size_t x_, size_t y_, uint32_t id_, uint32_t tileId_) : x {x_}, y {y_}, id {id_}, tileId {tileId_} | ||
4136 | { | ||
4137 | |||
4138 | } | ||
4139 | size_t x; | ||
4140 | size_t y; | ||
4141 | /*! Full ID, including flag */ | ||
4142 | uint32_t id; | ||
4143 | /*! ID of the flagged tile */ | ||
4144 | uint32_t tileId; | ||
4145 | }; | ||
4146 | } | ||
4147 | #endif //TILESON_FLAGGEDTILE_HPP | ||
4148 | |||
4149 | /*** End of inlined file: FlaggedTile.hpp ***/ | ||
4150 | |||
4151 | namespace tson | ||
4152 | { | ||
4153 | class Tile; | ||
4154 | class Map; | ||
4155 | |||
4156 | class Layer | ||
4157 | { | ||
4158 | public: | ||
4159 | inline Layer() = default; | ||
4160 | inline Layer(IJson &json, tson::Map *map); | ||
4161 | inline bool parse(IJson &json, tson::Map *map); | ||
4162 | |||
4163 | [[nodiscard]] inline const std::string &getCompression() const; | ||
4164 | [[nodiscard]] inline const std::vector<uint32_t> &getData() const; | ||
4165 | [[nodiscard]] inline const std::string &getBase64Data() const; | ||
4166 | [[nodiscard]] inline const std::string &getDrawOrder() const; | ||
4167 | [[nodiscard]] inline const std::string &getEncoding() const; | ||
4168 | [[nodiscard]] inline int getId() const; | ||
4169 | [[nodiscard]] inline const std::string &getImage() const; | ||
4170 | [[nodiscard]] inline const std::string &getName() const; | ||
4171 | [[nodiscard]] inline const Vector2f &getOffset() const; | ||
4172 | [[nodiscard]] inline float getOpacity() const; | ||
4173 | [[nodiscard]] inline const Vector2i &getSize() const; | ||
4174 | [[nodiscard]] inline const Colori &getTransparentcolor() const; | ||
4175 | |||
4176 | [[nodiscard]] inline LayerType getType() const; | ||
4177 | |||
4178 | [[nodiscard]] inline const std::string &getTypeStr() const; | ||
4179 | [[nodiscard]] inline bool isVisible() const; | ||
4180 | [[nodiscard]] inline int getX() const; | ||
4181 | [[nodiscard]] inline int getY() const; | ||
4182 | |||
4183 | [[nodiscard]] inline std::vector<tson::Chunk> &getChunks(); | ||
4184 | [[nodiscard]] inline std::vector<tson::Layer> &getLayers(); | ||
4185 | [[nodiscard]] inline std::vector<tson::Object> &getObjects(); | ||
4186 | [[nodiscard]] inline PropertyCollection &getProperties(); | ||
4187 | |||
4188 | inline tson::Object *getObj(int id); | ||
4189 | inline tson::Object *firstObj(const std::string &name); | ||
4190 | inline std::vector<tson::Object> getObjectsByName(const std::string &name); | ||
4191 | inline std::vector<tson::Object> getObjectsByType(tson::ObjectType type); | ||
4192 | |||
4193 | template <typename T> | ||
4194 | inline T get(const std::string &name); | ||
4195 | inline tson::Property * getProp(const std::string &name); | ||
4196 | |||
4197 | inline void assignTileMap(std::map<uint32_t, tson::Tile*> *tileMap); | ||
4198 | inline void createTileData(const Vector2i &mapSize, bool isInfiniteMap); | ||
4199 | |||
4200 | [[nodiscard]] inline const std::map<std::tuple<int, int>, tson::Tile *> &getTileData() const; | ||
4201 | inline tson::Tile * getTileData(int x, int y); | ||
4202 | |||
4203 | //v1.2.0-stuff | ||
4204 | [[nodiscard]] inline const Colori &getTintColor() const; | ||
4205 | [[nodiscard]] inline tson::Map *getMap() const; | ||
4206 | |||
4207 | [[nodiscard]] inline const std::map<std::tuple<int, int>, tson::TileObject> &getTileObjects() const; | ||
4208 | inline tson::TileObject * getTileObject(int x, int y); | ||
4209 | [[nodiscard]] inline const std::set<uint32_t> &getUniqueFlaggedTiles() const; | ||
4210 | inline void resolveFlaggedTiles(); | ||
4211 | |||
4212 | private: | ||
4213 | inline void setTypeByString(); | ||
4214 | |||
4215 | std::vector<tson::Chunk> m_chunks; /*! 'chunks': Array of chunks (optional). tilelayer only. */ | ||
4216 | std::string m_compression; /*! 'compression': zlib, gzip or empty (default). tilelayer only. */ | ||
4217 | std::vector<uint32_t> m_data; /*! 'data' (when uint array): Array of unsigned int (GIDs) or base64-encoded | ||
4218 | * data. tilelayer only. */ | ||
4219 | std::string m_base64Data; /*! 'data' (when string): Array of unsigned int (GIDs) or base64-encoded | ||
4220 | * data. tilelayer only. */ | ||
4221 | std::string m_drawOrder; /*! 'draworder': topdown (default) or index. objectgroup only. */ | ||
4222 | std::string m_encoding; /*! 'encoding': csv (default) or base64. tilelayer only. */ | ||
4223 | int m_id{}; /*! 'id': Incremental id - unique across all layers */ | ||
4224 | std::string m_image; /*! 'image': Image used by this layer. imagelayer only. */ | ||
4225 | std::vector<tson::Layer> m_layers; /*! 'layers': Array of layers. group on */ | ||
4226 | std::string m_name; /*! 'name': Name assigned to this layer */ | ||
4227 | std::vector<tson::Object> m_objects; /*! 'objects': Array of objects. objectgroup only. */ | ||
4228 | tson::Vector2f m_offset; /*! 'offsetx' and 'offsety': Horizontal and Vertical layer offset in pixels | ||
4229 | * (default: {0, 0}) */ | ||
4230 | float m_opacity{}; /*! 'opacity': Value between 0 and 1 */ | ||
4231 | tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */ | ||
4232 | tson::Vector2i m_size; /*! x = 'width': (Column count. Same as map width for fixed-size maps.) | ||
4233 | y = 'height': Row count. Same as map height for fixed-size maps. */ | ||
4234 | tson::Colori m_transparentcolor; /*! 'transparentcolor': Hex-formatted color (#RRGGBB) (optional, imagelayer only */ | ||
4235 | std::string m_typeStr; /*! 'type': tilelayer, objectgroup, imagelayer or group */ | ||
4236 | LayerType m_type {LayerType::Undefined}; /*! Layer type as enum*/ | ||
4237 | bool m_visible{}; /*! 'visible': Whether layer is shown or hidden in editor */ | ||
4238 | int m_x{}; /*! 'x': Horizontal layer offset in tiles. Always 0. */ | ||
4239 | int m_y{}; /*! 'y': Vertical layer offset in tiles. Always 0. */ | ||
4240 | |||
4241 | std::map<uint32_t, tson::Tile*> *m_tileMap; | ||
4242 | std::map<std::tuple<int, int>, tson::Tile*> m_tileData; /*! Key: Tuple of x and y pos in tile units. */ | ||
4243 | |||
4244 | //v1.2.0-stuff | ||
4245 | tson::Colori m_tintcolor; /*! 'tintcolor': Hex-formatted color (#RRGGBB or #AARRGGBB) that is multiplied with | ||
4246 | * any graphics drawn by this layer or any child layers (optional). */ | ||
4247 | inline void decompressData(); /*! Defined in tileson_forward.hpp */ | ||
4248 | inline void queueFlaggedTile(size_t x, size_t y, uint32_t id); /*! Queue a flagged tile */ | ||
4249 | |||
4250 | tson::Map * m_map; /*! The map who owns this layer */ | ||
4251 | std::map<std::tuple<int, int>, tson::TileObject> m_tileObjects; | ||
4252 | std::set<uint32_t> m_uniqueFlaggedTiles; | ||
4253 | std::vector<tson::FlaggedTile> m_flaggedTiles; | ||
4254 | |||
4255 | }; | ||
4256 | |||
4257 | /*! | ||
4258 | * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>") | ||
4259 | * @tparam T The template value | ||
4260 | * @param name Name of the property | ||
4261 | * @return The actual value, if it exists. Otherwise: The default value of the type. | ||
4262 | */ | ||
4263 | template<typename T> | ||
4264 | T Layer::get(const std::string &name) | ||
4265 | { | ||
4266 | return m_properties.getValue<T>(name); | ||
4267 | } | ||
4268 | } | ||
4269 | |||
4270 | /*! | ||
4271 | * Parses a Tiled layer from json | ||
4272 | * @param json | ||
4273 | */ | ||
4274 | tson::Layer::Layer(IJson &json, tson::Map *map) | ||
4275 | { | ||
4276 | parse(json, map); | ||
4277 | } | ||
4278 | |||
4279 | void tson::Layer::queueFlaggedTile(size_t x, size_t y, uint32_t id) | ||
4280 | { | ||
4281 | uint32_t tileId = id; | ||
4282 | tileId &= ~(FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG); | ||
4283 | m_uniqueFlaggedTiles.insert(id); | ||
4284 | m_flaggedTiles.emplace_back(x, y, id, tileId); | ||
4285 | } | ||
4286 | |||
4287 | /*! | ||
4288 | * Parses a Tiled layer from json | ||
4289 | * @param json | ||
4290 | * @return true if all mandatory fields was found. false otherwise. | ||
4291 | */ | ||
4292 | bool tson::Layer::parse(IJson &json, tson::Map *map) | ||
4293 | { | ||
4294 | m_map = map; | ||
4295 | |||
4296 | bool allFound = true; | ||
4297 | if(json.count("tintcolor") > 0) m_tintcolor = tson::Colori(json["tintcolor"].get<std::string>()); //Optional | ||
4298 | if(json.count("compression") > 0) m_compression = json["compression"].get<std::string>(); //Optional | ||
4299 | if(json.count("draworder") > 0) m_drawOrder = json["draworder"].get<std::string>(); //Optional | ||
4300 | if(json.count("encoding") > 0) m_encoding = json["encoding"].get<std::string>(); //Optional | ||
4301 | if(json.count("id") > 0) m_id = json["id"].get<int>(); //Optional | ||
4302 | if(json.count("image") > 0) m_image = json["image"].get<std::string>(); //Optional | ||
4303 | if(json.count("name") > 0) m_name = json["name"].get<std::string>(); else allFound = false; | ||
4304 | if(json.count("offsetx") > 0 && json.count("offsety") > 0) | ||
4305 | m_offset = {json["offsetx"].get<float>(), json["offsety"].get<float>()}; //Optional | ||
4306 | if(json.count("opacity") > 0) m_opacity = json["opacity"].get<float>(); else allFound = false; | ||
4307 | if(json.count("width") > 0 && json.count("height") > 0) | ||
4308 | m_size = {json["width"].get<int>(), json["height"].get<int>()}; //else allFound = false; - Not mandatory for all layers! | ||
4309 | if(json.count("transparentcolor") > 0) m_transparentcolor = tson::Colori(json["transparentcolor"].get<std::string>()); //Optional | ||
4310 | if(json.count("type") > 0) m_typeStr = json["type"].get<std::string>(); else allFound = false; | ||
4311 | if(json.count("visible") > 0) m_visible = json["visible"].get<bool>(); else allFound = false; | ||
4312 | if(json.count("x") > 0) m_x = json["x"].get<int>(); else allFound = false; | ||
4313 | if(json.count("y") > 0) m_y = json["y"].get<int>(); else allFound = false; | ||
4314 | |||
4315 | //Handle DATA (Optional) | ||
4316 | if(json.count("data") > 0) | ||
4317 | { | ||
4318 | if(json["data"].isArray()) | ||
4319 | { | ||
4320 | auto &array = json.array("data"); | ||
4321 | std::for_each(array.begin(), array.end(), [&](std::unique_ptr<IJson> &item) { m_data.push_back(item->get<uint32_t>()); }); | ||
4322 | } | ||
4323 | else | ||
4324 | { | ||
4325 | m_base64Data = json["data"].get<std::string>(); | ||
4326 | decompressData(); | ||
4327 | } | ||
4328 | } | ||
4329 | |||
4330 | //More advanced data | ||
4331 | if(json.count("chunks") > 0 && json["chunks"].isArray()) | ||
4332 | { | ||
4333 | auto &chunks = json.array("chunks"); | ||
4334 | std::for_each(chunks.begin(), chunks.end(), [&](std::unique_ptr<IJson> &item) { m_chunks.emplace_back(*item); }); | ||
4335 | } | ||
4336 | if(json.count("layers") > 0 && json["layers"].isArray()) | ||
4337 | { | ||
4338 | auto &layers = json.array("layers"); | ||
4339 | std::for_each(layers.begin(), layers.end(), [&](std::unique_ptr<IJson> &item) { m_layers.emplace_back(*item, m_map); }); | ||
4340 | } | ||
4341 | if(json.count("objects") > 0 && json["objects"].isArray()) | ||
4342 | { | ||
4343 | auto &objects = json.array("objects"); | ||
4344 | std::for_each(objects.begin(), objects.end(), [&](std::unique_ptr<IJson> &item) { m_objects.emplace_back(*item); }); | ||
4345 | } | ||
4346 | if(json.count("properties") > 0 && json["properties"].isArray()) | ||
4347 | { | ||
4348 | auto &properties = json.array("properties"); | ||
4349 | std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item) { m_properties.add(*item); }); | ||
4350 | } | ||
4351 | |||
4352 | setTypeByString(); | ||
4353 | |||
4354 | return allFound; | ||
4355 | } | ||
4356 | |||
4357 | /*! | ||
4358 | * Copies all objects with a name that equals the parameter | ||
4359 | * @param name Name of the objects to return | ||
4360 | * @return All objects with a matching name | ||
4361 | */ | ||
4362 | std::vector<tson::Object> tson::Layer::getObjectsByName(const std::string &name) | ||
4363 | { | ||
4364 | std::vector<tson::Object> found; | ||
4365 | |||
4366 | std::copy_if(m_objects.begin(), m_objects.end(), std::back_inserter(found), [&](const tson::Object &item) | ||
4367 | { | ||
4368 | return item.getName() == name; | ||
4369 | }); | ||
4370 | |||
4371 | return found; | ||
4372 | } | ||
4373 | |||
4374 | /*! | ||
4375 | * Copies all objects with a type that equals the parameter | ||
4376 | * @param type LayerType of the objects to return | ||
4377 | * @return All objects with a matching type | ||
4378 | */ | ||
4379 | std::vector<tson::Object> tson::Layer::getObjectsByType(tson::ObjectType type) | ||
4380 | { | ||
4381 | std::vector<tson::Object> found; | ||
4382 | |||
4383 | std::copy_if(m_objects.begin(), m_objects.end(), std::back_inserter(found), [&](const tson::Object &item) | ||
4384 | { | ||
4385 | return item.getObjectType() == type; | ||
4386 | }); | ||
4387 | |||
4388 | return found; | ||
4389 | } | ||
4390 | |||
4391 | /*! | ||
4392 | * Returns the first object with the given name | ||
4393 | * @param name Name of the object to find. | ||
4394 | * @return A pointer to the object if found. nullptr otherwise. | ||
4395 | */ | ||
4396 | tson::Object *tson::Layer::firstObj(const std::string &name) | ||
4397 | { | ||
4398 | auto result = std::find_if(m_objects.begin(), m_objects.end(), [&](const tson::Object &obj){return obj.getName() == name; }); | ||
4399 | if(result == m_objects.end()) | ||
4400 | return nullptr; | ||
4401 | |||
4402 | return &result.operator*(); | ||
4403 | } | ||
4404 | |||
4405 | /*! | ||
4406 | * Get an object by ID | ||
4407 | * @param id Unique ID of the object | ||
4408 | * @return A pointer to the object if found. nullptr otherwise. | ||
4409 | */ | ||
4410 | tson::Object *tson::Layer::getObj(int id) | ||
4411 | { | ||
4412 | auto result = std::find_if(m_objects.begin(), m_objects.end(), [&](const tson::Object &obj){return obj.getId() == id; }); | ||
4413 | if(result == m_objects.end()) | ||
4414 | return nullptr; | ||
4415 | |||
4416 | return &result.operator*(); | ||
4417 | } | ||
4418 | |||
4419 | /*! | ||
4420 | * Set type by string | ||
4421 | * tilelayer, objectgroup, imagelayer or group | ||
4422 | */ | ||
4423 | void tson::Layer::setTypeByString() | ||
4424 | { | ||
4425 | if(m_typeStr == "tilelayer") m_type = LayerType::TileLayer; | ||
4426 | else if(m_typeStr == "objectgroup") m_type = LayerType::ObjectGroup; | ||
4427 | else if(m_typeStr == "imagelayer") m_type = LayerType::ImageLayer; | ||
4428 | else if(m_typeStr == "group") m_type = LayerType::Group; | ||
4429 | else m_type = LayerType::Undefined; | ||
4430 | } | ||
4431 | |||
4432 | /*! | ||
4433 | * 'compression': zlib, gzip or empty (default). tilelayer only. | ||
4434 | * @return | ||
4435 | */ | ||
4436 | const std::string &tson::Layer::getCompression() const | ||
4437 | { | ||
4438 | return m_compression; | ||
4439 | } | ||
4440 | |||
4441 | /*! | ||
4442 | * 'data' (when uint array): Array of unsigned int (GIDs) or base64-encoded data. tilelayer only. | ||
4443 | * @return | ||
4444 | */ | ||
4445 | const std::vector<uint32_t> &tson::Layer::getData() const | ||
4446 | { | ||
4447 | return m_data; | ||
4448 | } | ||
4449 | |||
4450 | /*! | ||
4451 | * 'data' (when string): Array of unsigned int (GIDs) or base64-encoded data. tilelayer only. | ||
4452 | * @return | ||
4453 | */ | ||
4454 | const std::string &tson::Layer::getBase64Data() const | ||
4455 | { | ||
4456 | return m_base64Data; | ||
4457 | } | ||
4458 | |||
4459 | /*! | ||
4460 | * 'draworder': topdown (default) or index. objectgroup only. | ||
4461 | * @return | ||
4462 | */ | ||
4463 | const std::string &tson::Layer::getDrawOrder() const | ||
4464 | { | ||
4465 | return m_drawOrder; | ||
4466 | } | ||
4467 | |||
4468 | /*! | ||
4469 | * 'encoding': csv (default) or base64. tilelayer only. | ||
4470 | * @return | ||
4471 | */ | ||
4472 | const std::string &tson::Layer::getEncoding() const | ||
4473 | { | ||
4474 | return m_encoding; | ||
4475 | } | ||
4476 | |||
4477 | /*! | ||
4478 | * 'id': Incremental id - unique across all layers | ||
4479 | * @return | ||
4480 | */ | ||
4481 | int tson::Layer::getId() const | ||
4482 | { | ||
4483 | return m_id; | ||
4484 | } | ||
4485 | |||
4486 | /*! | ||
4487 | * 'image': Image used by this layer. imagelayer only. | ||
4488 | * @return | ||
4489 | */ | ||
4490 | const std::string &tson::Layer::getImage() const | ||
4491 | { | ||
4492 | return m_image; | ||
4493 | } | ||
4494 | |||
4495 | /*! | ||
4496 | * 'name': Name assigned to this layer | ||
4497 | * @return | ||
4498 | */ | ||
4499 | const std::string &tson::Layer::getName() const | ||
4500 | { | ||
4501 | return m_name; | ||
4502 | } | ||
4503 | |||
4504 | /*! | ||
4505 | * 'offsetx' and 'offsety': Horizontal and Vertical layer offset in pixels (default: {0, 0}) | ||
4506 | * @return | ||
4507 | */ | ||
4508 | const tson::Vector2f &tson::Layer::getOffset() const | ||
4509 | { | ||
4510 | return m_offset; | ||
4511 | } | ||
4512 | |||
4513 | /*! | ||
4514 | * 'opacity': Value between 0 and 1 | ||
4515 | * @return | ||
4516 | */ | ||
4517 | float tson::Layer::getOpacity() const | ||
4518 | { | ||
4519 | return m_opacity; | ||
4520 | } | ||
4521 | |||
4522 | /*! | ||
4523 | * x = 'width': (Column count. Same as map width for fixed-size maps.) | ||
4524 | * y = 'height': Row count. Same as map height for fixed-size maps. | ||
4525 | * @return width and height as a single size | ||
4526 | */ | ||
4527 | const tson::Vector2i &tson::Layer::getSize() const | ||
4528 | { | ||
4529 | return m_size; | ||
4530 | } | ||
4531 | |||
4532 | /*! | ||
4533 | * 'transparentcolor': Color created from a hex color (#RRGGBB) (optional, imagelayer only) | ||
4534 | * @return color as color object with rgba channel. | ||
4535 | */ | ||
4536 | const tson::Colori &tson::Layer::getTransparentcolor() const | ||
4537 | { | ||
4538 | return m_transparentcolor; | ||
4539 | } | ||
4540 | |||
4541 | /*! | ||
4542 | * 'type': tilelayer, objectgroup, imagelayer or group | ||
4543 | * @return string with the object type | ||
4544 | */ | ||
4545 | const std::string &tson::Layer::getTypeStr() const | ||
4546 | { | ||
4547 | return m_typeStr; | ||
4548 | } | ||
4549 | |||
4550 | /*! | ||
4551 | * 'visible': Whether layer is shown or hidden in editor | ||
4552 | * @return | ||
4553 | */ | ||
4554 | bool tson::Layer::isVisible() const | ||
4555 | { | ||
4556 | return m_visible; | ||
4557 | } | ||
4558 | |||
4559 | /*! | ||
4560 | * 'x': Horizontal layer offset in tiles. Always 0. | ||
4561 | * @return x value (always 0 for layer) | ||
4562 | */ | ||
4563 | int tson::Layer::getX() const | ||
4564 | { | ||
4565 | return m_x; | ||
4566 | } | ||
4567 | |||
4568 | /*! | ||
4569 | * 'y': Horizontal layer offset in tiles. Always 0. | ||
4570 | * @return y value (always 0 for layer) | ||
4571 | */ | ||
4572 | int tson::Layer::getY() const | ||
4573 | { | ||
4574 | return m_y; | ||
4575 | } | ||
4576 | |||
4577 | /*! | ||
4578 | * 'chunks': Array of chunks (optional). tilelayer only. | ||
4579 | * @return | ||
4580 | */ | ||
4581 | std::vector<tson::Chunk> &tson::Layer::getChunks() | ||
4582 | { | ||
4583 | return m_chunks; | ||
4584 | } | ||
4585 | |||
4586 | /*! | ||
4587 | * 'layers': Array of layers. group on | ||
4588 | * @return | ||
4589 | */ | ||
4590 | std::vector<tson::Layer> &tson::Layer::getLayers() | ||
4591 | { | ||
4592 | return m_layers; | ||
4593 | } | ||
4594 | |||
4595 | /*! | ||
4596 | * 'objects': Array of objects. objectgroup only. | ||
4597 | * @return | ||
4598 | */ | ||
4599 | std::vector<tson::Object> &tson::Layer::getObjects() | ||
4600 | { | ||
4601 | return m_objects; | ||
4602 | } | ||
4603 | |||
4604 | /*! | ||
4605 | * 'properties': A list of properties (name, value, type). | ||
4606 | * @return | ||
4607 | */ | ||
4608 | tson::PropertyCollection &tson::Layer::getProperties() | ||
4609 | { | ||
4610 | return m_properties; | ||
4611 | } | ||
4612 | |||
4613 | /*! | ||
4614 | * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>"); | ||
4615 | * @param name Name of the property | ||
4616 | * @return | ||
4617 | */ | ||
4618 | tson::Property *tson::Layer::getProp(const std::string &name) | ||
4619 | { | ||
4620 | if(m_properties.hasProperty(name)) | ||
4621 | return m_properties.getProperty(name); | ||
4622 | return nullptr; | ||
4623 | } | ||
4624 | |||
4625 | /*! | ||
4626 | * Get layer type | ||
4627 | * @return Layer type as enum | ||
4628 | */ | ||
4629 | tson::LayerType tson::Layer::getType() const | ||
4630 | { | ||
4631 | return m_type; | ||
4632 | } | ||
4633 | |||
4634 | /*! | ||
4635 | * Assigns a tilemap of pointers to existing tiles. | ||
4636 | * @param tileMap The tilemap. key: tile id, value: pointer to Tile. | ||
4637 | */ | ||
4638 | void tson::Layer::assignTileMap(std::map<uint32_t, tson::Tile *> *tileMap) | ||
4639 | { | ||
4640 | m_tileMap = tileMap; | ||
4641 | } | ||
4642 | |||
4643 | /*! | ||
4644 | * Get tile data as some kind of map with x and y position with pointers to existing tiles. | ||
4645 | * Map only contains tiles that are not empty. x and y position is in tile units. | ||
4646 | * | ||
4647 | * Example of getting tile from the returned map: | ||
4648 | * | ||
4649 | * Tile *tile = tileData[{0, 4}]; | ||
4650 | * | ||
4651 | * @return A map that represents the data returned from getData() in a 2D map with Tile pointers. | ||
4652 | */ | ||
4653 | const std::map<std::tuple<int, int>, tson::Tile *> &tson::Layer::getTileData() const | ||
4654 | { | ||
4655 | return m_tileData; | ||
4656 | } | ||
4657 | |||
4658 | /*! | ||
4659 | * A safe way to get tile data | ||
4660 | * Get tile data as some kind of map with x and y position with pointers to existing tiles. | ||
4661 | * Map only contains tiles that are not empty. x and y position is in tile units. | ||
4662 | * | ||
4663 | * Example of getting tile: | ||
4664 | * Tile *tile = layer->getTileData(0, 4) | ||
4665 | * | ||
4666 | * @param x X position in tile units | ||
4667 | * @param y Y position in tile units | ||
4668 | * @return pointer to tile, if it exists. nullptr otherwise. | ||
4669 | */ | ||
4670 | tson::Tile *tson::Layer::getTileData(int x, int y) | ||
4671 | { | ||
4672 | return (m_tileData.count({x, y}) > 0) ? m_tileData[{x,y}] : nullptr; | ||
4673 | } | ||
4674 | |||
4675 | /*! | ||
4676 | * Used for getting the tson::Map who is the parent of this Layer. | ||
4677 | * @return a pointer to the tson::Map where this layer is contained. | ||
4678 | */ | ||
4679 | tson::Map *tson::Layer::getMap() const | ||
4680 | { | ||
4681 | return m_map; | ||
4682 | } | ||
4683 | |||
4684 | /*! | ||
4685 | * | ||
4686 | * This is only supported for non-infinite maps! | ||
4687 | * | ||
4688 | * @param mapSize The size of the map | ||
4689 | * @param isInfiniteMap Whether or not the current map is infinte. | ||
4690 | */ | ||
4691 | void tson::Layer::createTileData(const Vector2i &mapSize, bool isInfiniteMap) | ||
4692 | { | ||
4693 | size_t x = 0; | ||
4694 | size_t y = 0; | ||
4695 | if(!isInfiniteMap) | ||
4696 | { | ||
4697 | std::for_each(m_data.begin(), m_data.end(), [&](uint32_t tileId) | ||
4698 | { | ||
4699 | if (x == mapSize.x) | ||
4700 | { | ||
4701 | ++y; | ||
4702 | x = 0; | ||
4703 | } | ||
4704 | |||
4705 | if (tileId > 0 && m_tileMap->count(tileId) > 0) | ||
4706 | { | ||
4707 | m_tileData[{x, y}] = m_tileMap->at(tileId); | ||
4708 | m_tileObjects[{x, y}] = {{x, y}, m_tileData[{x, y}]}; | ||
4709 | } | ||
4710 | else if(tileId > 0 && m_tileMap->count(tileId) == 0) //Tile with flip flags! | ||
4711 | { | ||
4712 | queueFlaggedTile(x, y, tileId); | ||
4713 | } | ||
4714 | x++; | ||
4715 | }); | ||
4716 | |||
4717 | } | ||
4718 | } | ||
4719 | |||
4720 | const std::map<std::tuple<int, int>, tson::TileObject> &tson::Layer::getTileObjects() const | ||
4721 | { | ||
4722 | return m_tileObjects; | ||
4723 | } | ||
4724 | |||
4725 | tson::TileObject *tson::Layer::getTileObject(int x, int y) | ||
4726 | { | ||
4727 | return (m_tileObjects.count({x, y}) > 0) ? &m_tileObjects[{x,y}] : nullptr; | ||
4728 | } | ||
4729 | |||
4730 | const std::set<uint32_t> &tson::Layer::getUniqueFlaggedTiles() const | ||
4731 | { | ||
4732 | return m_uniqueFlaggedTiles; | ||
4733 | } | ||
4734 | |||
4735 | void tson::Layer::resolveFlaggedTiles() | ||
4736 | { | ||
4737 | std::for_each(m_flaggedTiles.begin(), m_flaggedTiles.end(), [&](const tson::FlaggedTile &tile) | ||
4738 | { | ||
4739 | if (tile.id > 0 && m_tileMap->count(tile.id) > 0) | ||
4740 | { | ||
4741 | m_tileData[{tile.x, tile.y}] = m_tileMap->at(tile.id); | ||
4742 | m_tileObjects[{tile.x, tile.y}] = {{tile.x, tile.y}, m_tileData[{tile.x, tile.y}]}; | ||
4743 | } | ||
4744 | }); | ||
4745 | } | ||
4746 | |||
4747 | /*! | ||
4748 | * 'tintcolor': Hex-formatted color (#RRGGBB or #AARRGGBB) that is multiplied with any graphics drawn by this layer or any child layers (optional). | ||
4749 | * | ||
4750 | * @return tintcolor | ||
4751 | */ | ||
4752 | const tson::Colori &tson::Layer::getTintColor() const | ||
4753 | { | ||
4754 | return m_tintcolor; | ||
4755 | } | ||
4756 | |||
4757 | #endif //TILESON_LAYER_HPP | ||
4758 | |||
4759 | /*** End of inlined file: Layer.hpp ***/ | ||
4760 | |||
4761 | |||
4762 | /*** Start of inlined file: Tileset.hpp ***/ | ||
4763 | // | ||
4764 | // Created by robin on 22.03.2020. | ||
4765 | // | ||
4766 | |||
4767 | #ifndef TILESON_TILESET_HPP | ||
4768 | #define TILESON_TILESET_HPP | ||
4769 | |||
4770 | //#include "../external/json.hpp" | ||
4771 | |||
4772 | |||
4773 | /*** Start of inlined file: WangSet.hpp ***/ | ||
4774 | // | ||
4775 | // Created by robin on 22.03.2020. | ||
4776 | // | ||
4777 | |||
4778 | #ifndef TILESON_WANGSET_HPP | ||
4779 | #define TILESON_WANGSET_HPP | ||
4780 | |||
4781 | //#include "../external/json.hpp" | ||
4782 | |||
4783 | /*** Start of inlined file: WangColor.hpp ***/ | ||
4784 | // | ||
4785 | // Created by robin on 22.03.2020. | ||
4786 | // | ||
4787 | |||
4788 | #ifndef TILESON_WANGCOLOR_HPP | ||
4789 | #define TILESON_WANGCOLOR_HPP | ||
4790 | |||
4791 | //#include "../external/json.hpp" | ||
4792 | |||
4793 | namespace tson | ||
4794 | { | ||
4795 | class WangColor | ||
4796 | { | ||
4797 | public: | ||
4798 | inline WangColor() = default; | ||
4799 | inline explicit WangColor(IJson &json); | ||
4800 | inline bool parse(IJson &json); | ||
4801 | |||
4802 | [[nodiscard]] inline const Colori &getColor() const; | ||
4803 | [[nodiscard]] inline const std::string &getName() const; | ||
4804 | [[nodiscard]] inline float getProbability() const; | ||
4805 | [[nodiscard]] inline int getTile() const; | ||
4806 | |||
4807 | private: | ||
4808 | tson::Colori m_color; /*! 'color': Hex-formatted color (#RRGGBB or #AARRGGBB) */ | ||
4809 | std::string m_name; /*! 'name': Name of the Wang color */ | ||
4810 | float m_probability{}; /*! 'probability': Probability used when randomizing */ | ||
4811 | int m_tile{}; /*! 'tile': Local ID of tile representing the Wang color */ | ||
4812 | }; | ||
4813 | } | ||
4814 | |||
4815 | tson::WangColor::WangColor(IJson &json) | ||
4816 | { | ||
4817 | parse(json); | ||
4818 | } | ||
4819 | |||
4820 | bool tson::WangColor::parse(IJson &json) | ||
4821 | { | ||
4822 | bool allFound = true; | ||
4823 | |||
4824 | if(json.count("color") > 0) m_color = tson::Colori(json["color"].get<std::string>()); else allFound = false; | ||
4825 | if(json.count("name") > 0) m_name = json["name"].get<std::string>(); else allFound = false; | ||
4826 | if(json.count("probability") > 0) m_probability = json["probability"].get<float>(); else allFound = false; | ||
4827 | if(json.count("tile") > 0) m_tile = json["tile"].get<int>(); else allFound = false; | ||
4828 | |||
4829 | return allFound; | ||
4830 | } | ||
4831 | |||
4832 | /*! | ||
4833 | * 'color': Color object created from hex-formatted string (#RRGGBB or #AARRGGBB) | ||
4834 | * @return | ||
4835 | */ | ||
4836 | const tson::Colori &tson::WangColor::getColor() const | ||
4837 | { | ||
4838 | return m_color; | ||
4839 | } | ||
4840 | |||
4841 | /*! | ||
4842 | * 'name': Name of the Wang color | ||
4843 | * @return | ||
4844 | */ | ||
4845 | const std::string &tson::WangColor::getName() const | ||
4846 | { | ||
4847 | return m_name; | ||
4848 | } | ||
4849 | |||
4850 | /*! | ||
4851 | * 'probability': Probability used when randomizing | ||
4852 | * @return | ||
4853 | */ | ||
4854 | float tson::WangColor::getProbability() const | ||
4855 | { | ||
4856 | return m_probability; | ||
4857 | } | ||
4858 | |||
4859 | /*! | ||
4860 | * 'tile': Local ID of tile representing the Wang color | ||
4861 | * @return | ||
4862 | */ | ||
4863 | int tson::WangColor::getTile() const | ||
4864 | { | ||
4865 | return m_tile; | ||
4866 | } | ||
4867 | |||
4868 | #endif //TILESON_WANGCOLOR_HPP | ||
4869 | |||
4870 | /*** End of inlined file: WangColor.hpp ***/ | ||
4871 | |||
4872 | |||
4873 | |||
4874 | /*** Start of inlined file: WangTile.hpp ***/ | ||
4875 | // | ||
4876 | // Created by robin on 22.03.2020. | ||
4877 | // | ||
4878 | |||
4879 | #ifndef TILESON_WANGTILE_HPP | ||
4880 | #define TILESON_WANGTILE_HPP | ||
4881 | |||
4882 | //#include "../external/json.hpp" | ||
4883 | |||
4884 | namespace tson | ||
4885 | { | ||
4886 | class WangTile | ||
4887 | { | ||
4888 | public: | ||
4889 | inline WangTile() = default; | ||
4890 | inline explicit WangTile(IJson &json); | ||
4891 | inline bool parse(IJson &json); | ||
4892 | |||
4893 | [[nodiscard]] inline bool hasDFlip() const; | ||
4894 | [[nodiscard]] inline bool hasHFlip() const; | ||
4895 | [[nodiscard]] inline int getTileid() const; | ||
4896 | [[nodiscard]] inline bool hasVFlip() const; | ||
4897 | |||
4898 | [[nodiscard]] inline const std::vector<int> &getWangIds() const; | ||
4899 | |||
4900 | private: | ||
4901 | bool m_dflip{}; /*! 'dflip': Tile is flipped diagonally */ | ||
4902 | bool m_hflip{}; /*! 'hflip': Tile is flipped horizontally */ | ||
4903 | int m_tileid{}; /*! 'tileid': Local ID of tile */ | ||
4904 | bool m_vflip{}; /*! 'vflip': Tile is flipped vertically */ | ||
4905 | std::vector<int> m_wangId; /*! 'wangid': Array of Wang color indexes (uchar[8])*/ | ||
4906 | }; | ||
4907 | } | ||
4908 | |||
4909 | tson::WangTile::WangTile(IJson &json) | ||
4910 | { | ||
4911 | parse(json); | ||
4912 | } | ||
4913 | |||
4914 | /*! | ||
4915 | * Parses a wang tile from Tiled json. | ||
4916 | * @param json A Tiled json file | ||
4917 | * @return true if all mandatory fields were found. False otherwise. | ||
4918 | */ | ||
4919 | bool tson::WangTile::parse(IJson &json) | ||
4920 | { | ||
4921 | bool allFound = true; | ||
4922 | |||
4923 | if(json.count("dflip") > 0) m_dflip = json["dflip"].get<bool>(); else allFound = false; | ||
4924 | if(json.count("hflip") > 0) m_hflip = json["hflip"].get<bool>(); else allFound = false; | ||
4925 | if(json.count("vflip") > 0) m_vflip = json["vflip"].get<bool>(); else allFound = false; | ||
4926 | if(json.count("tileid") > 0) m_tileid = json["tileid"].get<int>(); else allFound = false; | ||
4927 | |||
4928 | if(json.count("wangid") > 0 && json["wangid"].isArray()) | ||
4929 | { | ||
4930 | auto &wangid = json.array("wangid"); | ||
4931 | std::for_each(wangid.begin(), wangid.end(), [&](std::unique_ptr<IJson> &item) { m_wangId.emplace_back(item->get<int>()); }); | ||
4932 | } | ||
4933 | |||
4934 | return allFound; | ||
4935 | } | ||
4936 | |||
4937 | /*! | ||
4938 | * 'dflip': Tile is flipped diagonally | ||
4939 | * @return | ||
4940 | */ | ||
4941 | bool tson::WangTile::hasDFlip() const | ||
4942 | { | ||
4943 | return m_dflip; | ||
4944 | } | ||
4945 | |||
4946 | /*! | ||
4947 | * 'hflip': Tile is flipped horizontally | ||
4948 | * @return | ||
4949 | */ | ||
4950 | bool tson::WangTile::hasHFlip() const | ||
4951 | { | ||
4952 | return m_hflip; | ||
4953 | } | ||
4954 | |||
4955 | /*! | ||
4956 | * 'tileid': Local ID of tile | ||
4957 | * @return | ||
4958 | */ | ||
4959 | int tson::WangTile::getTileid() const | ||
4960 | { | ||
4961 | return m_tileid; | ||
4962 | } | ||
4963 | |||
4964 | /*! | ||
4965 | * 'vflip': Tile is flipped vertically | ||
4966 | * @return | ||
4967 | */ | ||
4968 | bool tson::WangTile::hasVFlip() const | ||
4969 | { | ||
4970 | return m_vflip; | ||
4971 | } | ||
4972 | |||
4973 | /*! | ||
4974 | * 'wangid': Array of Wang color indexes (uchar[8]) | ||
4975 | * @return | ||
4976 | */ | ||
4977 | const std::vector<int> &tson::WangTile::getWangIds() const | ||
4978 | { | ||
4979 | return m_wangId; | ||
4980 | } | ||
4981 | |||
4982 | #endif //TILESON_WANGTILE_HPP | ||
4983 | |||
4984 | /*** End of inlined file: WangTile.hpp ***/ | ||
4985 | |||
4986 | namespace tson | ||
4987 | { | ||
4988 | class WangSet | ||
4989 | { | ||
4990 | public: | ||
4991 | inline WangSet() = default; | ||
4992 | inline explicit WangSet(IJson &json); | ||
4993 | inline bool parse(IJson &json); | ||
4994 | |||
4995 | [[nodiscard]] inline const std::string &getName() const; | ||
4996 | [[nodiscard]] inline int getTile() const; | ||
4997 | |||
4998 | [[nodiscard]] inline const std::vector<tson::WangTile> &getWangTiles() const; | ||
4999 | [[nodiscard]] inline const std::vector<tson::WangColor> &getCornerColors() const; | ||
5000 | [[nodiscard]] inline const std::vector<tson::WangColor> &getEdgeColors() const; | ||
5001 | |||
5002 | inline PropertyCollection &getProperties(); | ||
5003 | |||
5004 | template <typename T> | ||
5005 | inline T get(const std::string &name); | ||
5006 | inline tson::Property * getProp(const std::string &name); | ||
5007 | |||
5008 | private: | ||
5009 | std::string m_name; /*! 'name': Name of the Wang set */ | ||
5010 | int m_tile{}; /*! 'tile': Local ID of tile representing the Wang set */ | ||
5011 | std::vector<tson::WangTile> m_wangTiles; /*! 'wangtiles': Array of Wang tiles */ | ||
5012 | std::vector<tson::WangColor> m_cornerColors; /*! 'cornercolors': Array of Wang colors */ | ||
5013 | std::vector<tson::WangColor> m_edgeColors; /*! 'edgecolors': Array of Wang colors */ | ||
5014 | tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */ | ||
5015 | |||
5016 | }; | ||
5017 | |||
5018 | /*! | ||
5019 | * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>") | ||
5020 | * @tparam T The template value | ||
5021 | * @param name Name of the property | ||
5022 | * @return The actual value, if it exists. Otherwise: The default value of the type. | ||
5023 | */ | ||
5024 | template<typename T> | ||
5025 | T tson::WangSet::get(const std::string &name) | ||
5026 | { | ||
5027 | return m_properties.getValue<T>(name); | ||
5028 | } | ||
5029 | } | ||
5030 | |||
5031 | tson::WangSet::WangSet(IJson &json) | ||
5032 | { | ||
5033 | parse(json); | ||
5034 | } | ||
5035 | |||
5036 | bool tson::WangSet::parse(IJson &json) | ||
5037 | { | ||
5038 | bool allFound = true; | ||
5039 | |||
5040 | if(json.count("tile") > 0) m_tile = json["tile"].get<int>(); else allFound = false; | ||
5041 | if(json.count("name") > 0) m_name = json["name"].get<std::string>(); else allFound = false; | ||
5042 | |||
5043 | //More advanced data | ||
5044 | if(json.count("wangtiles") > 0 && json["wangtiles"].isArray()) | ||
5045 | { | ||
5046 | auto &wangtiles = json.array("wangtiles"); | ||
5047 | std::for_each(wangtiles.begin(), wangtiles.end(), [&](std::unique_ptr<IJson> &item) { m_wangTiles.emplace_back(*item); }); | ||
5048 | } | ||
5049 | if(json.count("cornercolors") > 0 && json["cornercolors"].isArray()) | ||
5050 | { | ||
5051 | auto &cornercolors = json.array("cornercolors"); | ||
5052 | std::for_each(cornercolors.begin(), cornercolors.end(), [&](std::unique_ptr<IJson> &item) { m_cornerColors.emplace_back(*item); }); | ||
5053 | } | ||
5054 | if(json.count("edgecolors") > 0 && json["edgecolors"].isArray()) | ||
5055 | { | ||
5056 | auto &edgecolors = json.array("edgecolors"); | ||
5057 | std::for_each(edgecolors.begin(), edgecolors.end(), [&](std::unique_ptr<IJson> &item) { m_edgeColors.emplace_back(*item); }); | ||
5058 | } | ||
5059 | if(json.count("properties") > 0 && json["properties"].isArray()) | ||
5060 | { | ||
5061 | auto &properties = json.array("properties"); | ||
5062 | std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item) { m_properties.add(*item); }); | ||
5063 | } | ||
5064 | |||
5065 | return allFound; | ||
5066 | } | ||
5067 | |||
5068 | /*! | ||
5069 | * 'name': Name of the Wang set | ||
5070 | * @return | ||
5071 | */ | ||
5072 | const std::string &tson::WangSet::getName() const | ||
5073 | { | ||
5074 | return m_name; | ||
5075 | } | ||
5076 | |||
5077 | /*! | ||
5078 | * 'tile': Local ID of tile representing the Wang set | ||
5079 | * @return | ||
5080 | */ | ||
5081 | int tson::WangSet::getTile() const | ||
5082 | { | ||
5083 | return m_tile; | ||
5084 | } | ||
5085 | |||
5086 | /*! | ||
5087 | * 'wangtiles': Array of Wang tiles | ||
5088 | * @return | ||
5089 | */ | ||
5090 | const std::vector<tson::WangTile> &tson::WangSet::getWangTiles() const | ||
5091 | { | ||
5092 | return m_wangTiles; | ||
5093 | } | ||
5094 | |||
5095 | /*! | ||
5096 | * 'cornercolors': Array of Wang colors | ||
5097 | * @return | ||
5098 | */ | ||
5099 | const std::vector<tson::WangColor> &tson::WangSet::getCornerColors() const | ||
5100 | { | ||
5101 | return m_cornerColors; | ||
5102 | } | ||
5103 | |||
5104 | /*! | ||
5105 | * 'edgecolors': Array of Wang colors | ||
5106 | * @return | ||
5107 | */ | ||
5108 | const std::vector<tson::WangColor> &tson::WangSet::getEdgeColors() const | ||
5109 | { | ||
5110 | return m_edgeColors; | ||
5111 | } | ||
5112 | |||
5113 | /*! | ||
5114 | * 'properties': A list of properties (name, value, type). | ||
5115 | * @return | ||
5116 | */ | ||
5117 | tson::PropertyCollection &tson::WangSet::getProperties() | ||
5118 | { | ||
5119 | return m_properties; | ||
5120 | } | ||
5121 | |||
5122 | /*! | ||
5123 | * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>"); | ||
5124 | * @param name Name of the property | ||
5125 | * @return | ||
5126 | */ | ||
5127 | tson::Property *tson::WangSet::getProp(const std::string &name) | ||
5128 | { | ||
5129 | if(m_properties.hasProperty(name)) | ||
5130 | return m_properties.getProperty(name); | ||
5131 | |||
5132 | return nullptr; | ||
5133 | } | ||
5134 | |||
5135 | #endif //TILESON_WANGSET_HPP | ||
5136 | |||
5137 | /*** End of inlined file: WangSet.hpp ***/ | ||
5138 | |||
5139 | |||
5140 | /*** Start of inlined file: Tile.hpp ***/ | ||
5141 | // | ||
5142 | // Created by robin on 22.03.2020. | ||
5143 | // | ||
5144 | |||
5145 | #ifndef TILESON_TILE_HPP | ||
5146 | #define TILESON_TILE_HPP | ||
5147 | |||
5148 | //#include "../external/json.hpp" | ||
5149 | |||
5150 | |||
5151 | /*** Start of inlined file: Frame.hpp ***/ | ||
5152 | // | ||
5153 | // Created by robin on 22.03.2020. | ||
5154 | // | ||
5155 | |||
5156 | #ifndef TILESON_FRAME_HPP | ||
5157 | #define TILESON_FRAME_HPP | ||
5158 | |||
5159 | //#include "../external/json.hpp" | ||
5160 | |||
5161 | namespace tson | ||
5162 | { | ||
5163 | class Frame | ||
5164 | { | ||
5165 | public: | ||
5166 | inline Frame() = default; | ||
5167 | inline Frame(int duration, int tileId); | ||
5168 | inline explicit Frame(IJson &json); | ||
5169 | |||
5170 | inline bool parse(IJson &json); | ||
5171 | |||
5172 | [[nodiscard]] inline int getDuration() const; | ||
5173 | [[nodiscard]] inline int getTileId() const; | ||
5174 | |||
5175 | private: | ||
5176 | int m_duration {}; /*! 'duration': Frame duration in milliseconds */ | ||
5177 | int m_tileId {}; /*! 'tileid': Local tile ID representing this frame */ | ||
5178 | }; | ||
5179 | } | ||
5180 | |||
5181 | /*! | ||
5182 | * | ||
5183 | * @param duration duration in milliseconds | ||
5184 | * @param tileId TileId | ||
5185 | */ | ||
5186 | tson::Frame::Frame(int duration, int tileId) : m_duration {duration}, m_tileId {tileId} | ||
5187 | { | ||
5188 | |||
5189 | } | ||
5190 | |||
5191 | /*! | ||
5192 | * Parses frame data from json | ||
5193 | * @param json | ||
5194 | */ | ||
5195 | tson::Frame::Frame(IJson &json) | ||
5196 | { | ||
5197 | parse(json); | ||
5198 | } | ||
5199 | |||
5200 | /*! | ||
5201 | * Parses frame data from json | ||
5202 | * @param json | ||
5203 | * @return true if all mandatory fields was found. false otherwise. | ||
5204 | */ | ||
5205 | bool tson::Frame::parse(IJson &json) | ||
5206 | { | ||
5207 | bool allFound = true; | ||
5208 | |||
5209 | if(json.count("duration") > 0) m_duration = json["duration"].get<int>(); else allFound = false; | ||
5210 | if(json.count("tileid") > 0) m_tileId = json["tileid"].get<int>(); else allFound = false; | ||
5211 | |||
5212 | return allFound; | ||
5213 | } | ||
5214 | |||
5215 | /*! | ||
5216 | * 'duration': Frame duration in milliseconds | ||
5217 | * @return Duration in milliseconds | ||
5218 | */ | ||
5219 | int tson::Frame::getDuration() const | ||
5220 | { | ||
5221 | return m_duration; | ||
5222 | } | ||
5223 | |||
5224 | /*! | ||
5225 | * 'tileid': Local tile ID representing this frame | ||
5226 | * @return tile id | ||
5227 | */ | ||
5228 | int tson::Frame::getTileId() const | ||
5229 | { | ||
5230 | return m_tileId; | ||
5231 | } | ||
5232 | |||
5233 | #endif //TILESON_FRAME_HPP | ||
5234 | |||
5235 | /*** End of inlined file: Frame.hpp ***/ | ||
5236 | |||
5237 | namespace tson | ||
5238 | { | ||
5239 | class Tileset; | ||
5240 | |||
5241 | class Tile | ||
5242 | { | ||
5243 | public: | ||
5244 | inline Tile() = default; | ||
5245 | inline Tile(IJson &json, tson::Tileset *tileset, tson::Map *map); | ||
5246 | inline Tile(uint32_t id, tson::Tileset *tileset, tson::Map *map); | ||
5247 | inline Tile(uint32_t id, tson::Map *map); //v1.2.0 | ||
5248 | inline bool parse(IJson &json, tson::Tileset *tileset, tson::Map *map); | ||
5249 | inline bool parseId(IJson &json); | ||
5250 | |||
5251 | [[nodiscard]] inline uint32_t getId() const; | ||
5252 | |||
5253 | [[nodiscard]] inline const fs::path &getImage() const; | ||
5254 | |||
5255 | [[nodiscard]] inline const Vector2i &getImageSize() const; | ||
5256 | [[nodiscard]] inline const std::string &getType() const; | ||
5257 | |||
5258 | [[nodiscard]] inline const std::vector<tson::Frame> &getAnimation() const; | ||
5259 | [[nodiscard]] inline const Layer &getObjectgroup() const; | ||
5260 | [[nodiscard]] inline PropertyCollection &getProperties(); | ||
5261 | [[nodiscard]] inline const std::vector<int> &getTerrain() const; | ||
5262 | |||
5263 | template <typename T> | ||
5264 | inline T get(const std::string &name); | ||
5265 | inline tson::Property * getProp(const std::string &name); | ||
5266 | |||
5267 | //v1.2.0-stuff | ||
5268 | inline void setProperties(const tson::PropertyCollection &properties); | ||
5269 | |||
5270 | inline tson::Tileset * getTileset() const; | ||
5271 | inline tson::Map * getMap() const; | ||
5272 | inline const tson::Rect &getDrawingRect() const; | ||
5273 | inline const tson::Vector2f getPosition(const std::tuple<int, int> &tileDataPos); | ||
5274 | inline const tson::Vector2i getPositionInTileUnits(const std::tuple<int, int> &tileDataPos); | ||
5275 | inline const tson::Vector2i getTileSize() const; /*! Declared in tileson_forward.hpp */ | ||
5276 | |||
5277 | [[nodiscard]] inline TileFlipFlags getFlipFlags() const; | ||
5278 | inline bool hasFlipFlags(TileFlipFlags flags); | ||
5279 | [[nodiscard]] inline uint32_t getGid() const; | ||
5280 | |||
5281 | inline void addTilesetAndPerformCalculations(tson::Tileset *tileset); //v1.2.0 | ||
5282 | |||
5283 | private: | ||
5284 | std::vector<tson::Frame> m_animation; /*! 'animation': Array of Frames */ | ||
5285 | uint32_t m_id {}; /*! 'id': Local ID of the tile */ | ||
5286 | |||
5287 | fs::path m_image; /*! 'image': Image representing this tile (optional)*/ | ||
5288 | |||
5289 | tson::Vector2i m_imageSize; /*! x = 'imagewidth' and y = 'imageheight': in pixels */ | ||
5290 | tson::Layer m_objectgroup; /*! 'objectgroup': Layer with type objectgroup (optional) */ | ||
5291 | tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */ | ||
5292 | std::vector<int> m_terrain; /*! 'terrain': Index of terrain for each corner of tile */ | ||
5293 | std::string m_type; /*! 'type': The type of the tile (optional) */ | ||
5294 | |||
5295 | //v1.2.0-stuff | ||
5296 | uint32_t m_gid {}; /*! id without flip flags */ | ||
5297 | tson::Tileset * m_tileset; /*! A pointer to the tileset where this Tile comes from */ | ||
5298 | tson::Map * m_map; /*! A pointer to the map where this tile is contained */ | ||
5299 | tson::Rect m_drawingRect; /*! A rect that shows which part of the tileset that is used for this tile */ | ||
5300 | tson::TileFlipFlags m_flipFlags = TileFlipFlags::None; /*! Resolved using bit 32, 31 and 30 from gid */ | ||
5301 | inline void performDataCalculations(); /*! Declared in tileson_forward.hpp - Calculate all the values used in the tile class. */ | ||
5302 | inline void manageFlipFlagsByIdThenRemoveFlags(uint32_t &id); | ||
5303 | friend class Layer; | ||
5304 | }; | ||
5305 | |||
5306 | /*! | ||
5307 | * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>") | ||
5308 | * @tparam T The template value | ||
5309 | * @param name Name of the property | ||
5310 | * @return The actual value, if it exists. Otherwise: The default value of the type. | ||
5311 | */ | ||
5312 | template<typename T> | ||
5313 | T tson::Tile::get(const std::string &name) | ||
5314 | { | ||
5315 | return m_properties.getValue<T>(name); | ||
5316 | } | ||
5317 | } | ||
5318 | |||
5319 | tson::Tile::Tile(IJson &json, tson::Tileset *tileset, tson::Map *map) | ||
5320 | { | ||
5321 | parse(json, tileset, map); | ||
5322 | } | ||
5323 | |||
5324 | /*! | ||
5325 | * Used in cases where you have a tile without any property | ||
5326 | * @param id | ||
5327 | */ | ||
5328 | tson::Tile::Tile(uint32_t id, tson::Tileset *tileset, tson::Map *map) : m_id {id}, m_gid {id} | ||
5329 | { | ||
5330 | m_tileset = tileset; | ||
5331 | m_map = map; | ||
5332 | manageFlipFlagsByIdThenRemoveFlags(m_gid); | ||
5333 | performDataCalculations(); | ||
5334 | } | ||
5335 | |||
5336 | /*! | ||
5337 | * Used in cases where you have a FLIP FLAGGED tile | ||
5338 | * @param id | ||
5339 | */ | ||
5340 | tson::Tile::Tile(uint32_t id, tson::Map *map) : m_id {id}, m_gid {id} | ||
5341 | { | ||
5342 | m_map = map; | ||
5343 | manageFlipFlagsByIdThenRemoveFlags(m_gid); | ||
5344 | } | ||
5345 | |||
5346 | /*! | ||
5347 | * For flip flagged tiles, tilesets must be resolved later. | ||
5348 | * @param tileset | ||
5349 | */ | ||
5350 | void tson::Tile::addTilesetAndPerformCalculations(tson::Tileset *tileset) | ||
5351 | { | ||
5352 | m_tileset = tileset; | ||
5353 | performDataCalculations(); | ||
5354 | } | ||
5355 | |||
5356 | /*! | ||
5357 | * Parses a tile from a Tiled json. id on tile is store as id + 1 to match the references in data containers. | ||
5358 | * @param json | ||
5359 | * @return | ||
5360 | */ | ||
5361 | bool tson::Tile::parse(IJson &json, tson::Tileset *tileset, tson::Map *map) | ||
5362 | { | ||
5363 | m_tileset = tileset; | ||
5364 | m_map = map; | ||
5365 | |||
5366 | if(json.count("image") > 0) m_image = fs::path(json["image"].get<std::string>()); //Optional | ||
5367 | |||
5368 | bool allFound = parseId(json); | ||
5369 | |||
5370 | if(json.count("type") > 0) m_type = json["type"].get<std::string>(); //Optional | ||
5371 | if(json.count("objectgroup") > 0) m_objectgroup = tson::Layer(json["objectgroup"], m_map); //Optional | ||
5372 | |||
5373 | if(json.count("imagewidth") > 0 && json.count("imageheight") > 0) | ||
5374 | m_imageSize = {json["imagewidth"].get<int>(), json["imageheight"].get<int>()}; //Optional | ||
5375 | |||
5376 | //More advanced data | ||
5377 | if(json.count("animation") > 0 && json["animation"].isArray()) | ||
5378 | { | ||
5379 | auto &animation = json.array("animation"); | ||
5380 | std::for_each(animation.begin(), animation.end(), [&](std::unique_ptr<IJson> &item) { m_animation.emplace_back(*item); }); | ||
5381 | } | ||
5382 | if(json.count("terrain") > 0 && json["terrain"].isArray()) | ||
5383 | { | ||
5384 | auto &terrain = json.array("terrain"); | ||
5385 | std::for_each(terrain.begin(), terrain.end(), [&](std::unique_ptr<IJson> &item) { m_terrain.emplace_back(item->get<int>()); }); | ||
5386 | } | ||
5387 | |||
5388 | if(json.count("properties") > 0 && json["properties"].isArray()) | ||
5389 | { | ||
5390 | auto &properties = json.array("properties"); | ||
5391 | std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item) { m_properties.add(*item); }); | ||
5392 | } | ||
5393 | |||
5394 | performDataCalculations(); | ||
5395 | |||
5396 | return allFound; | ||
5397 | } | ||
5398 | |||
5399 | /*! | ||
5400 | * 'id': Local ID of the tile | ||
5401 | * @return | ||
5402 | */ | ||
5403 | uint32_t tson::Tile::getId() const | ||
5404 | { | ||
5405 | return m_id; | ||
5406 | } | ||
5407 | |||
5408 | /*! | ||
5409 | * 'image': Image representing this tile (optional) | ||
5410 | * @return | ||
5411 | */ | ||
5412 | |||
5413 | const fs::path &tson::Tile::getImage() const { return m_image; } | ||
5414 | |||
5415 | /*! | ||
5416 | * x = 'imagewidth' and y = 'imageheight': in pixels | ||
5417 | * @return | ||
5418 | */ | ||
5419 | const tson::Vector2i &tson::Tile::getImageSize() const | ||
5420 | { | ||
5421 | return m_imageSize; | ||
5422 | } | ||
5423 | |||
5424 | /*! | ||
5425 | * 'type': The type of the tile (optional) | ||
5426 | * @return | ||
5427 | */ | ||
5428 | const std::string &tson::Tile::getType() const | ||
5429 | { | ||
5430 | return m_type; | ||
5431 | } | ||
5432 | |||
5433 | /*! | ||
5434 | * 'animation': Array of Frames | ||
5435 | * @return | ||
5436 | */ | ||
5437 | const std::vector<tson::Frame> &tson::Tile::getAnimation() const | ||
5438 | { | ||
5439 | return m_animation; | ||
5440 | } | ||
5441 | |||
5442 | /*! | ||
5443 | * 'objectgroup': Layer with type objectgroup (optional) | ||
5444 | * @return | ||
5445 | */ | ||
5446 | const tson::Layer &tson::Tile::getObjectgroup() const | ||
5447 | { | ||
5448 | return m_objectgroup; | ||
5449 | } | ||
5450 | |||
5451 | /*! | ||
5452 | * 'properties': A list of properties (name, value, type). | ||
5453 | * @return | ||
5454 | */ | ||
5455 | tson::PropertyCollection &tson::Tile::getProperties() | ||
5456 | { | ||
5457 | return m_properties; | ||
5458 | } | ||
5459 | |||
5460 | /*! | ||
5461 | * 'terrain': Index of terrain for each corner of tile | ||
5462 | * @return | ||
5463 | */ | ||
5464 | const std::vector<int> &tson::Tile::getTerrain() const | ||
5465 | { | ||
5466 | return m_terrain; | ||
5467 | } | ||
5468 | |||
5469 | /*! | ||
5470 | * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>"); | ||
5471 | * @param name Name of the property | ||
5472 | * @return | ||
5473 | */ | ||
5474 | tson::Property *tson::Tile::getProp(const std::string &name) | ||
5475 | { | ||
5476 | if(m_properties.hasProperty(name)) | ||
5477 | return m_properties.getProperty(name); | ||
5478 | |||
5479 | return nullptr; | ||
5480 | } | ||
5481 | |||
5482 | /*! | ||
5483 | * Used for getting the tson::Tileset who is the parent of this Tile. | ||
5484 | * @return a pointer to the tson::Tileset where this tile is contained. | ||
5485 | */ | ||
5486 | tson::Tileset *tson::Tile::getTileset() const | ||
5487 | { | ||
5488 | return m_tileset; | ||
5489 | } | ||
5490 | |||
5491 | /*! | ||
5492 | * Used for getting the tson::Map who is the parent of this Tile. | ||
5493 | * @return a pointer to the tson::Map where this tile is contained. | ||
5494 | */ | ||
5495 | tson::Map *tson::Tile::getMap() const | ||
5496 | { | ||
5497 | return m_map; | ||
5498 | } | ||
5499 | |||
5500 | /*! | ||
5501 | * Get the information needed to draw the Tile based on its current tileset | ||
5502 | * @return a tson::Rect containing the information needed to draw the tile. | ||
5503 | */ | ||
5504 | const tson::Rect &tson::Tile::getDrawingRect() const | ||
5505 | { | ||
5506 | return m_drawingRect; | ||
5507 | } | ||
5508 | |||
5509 | /*! | ||
5510 | * Helper function. | ||
5511 | * | ||
5512 | * Get the position of the tile in tile units. | ||
5513 | * The size of each unit is determined by the tile size property of the map. | ||
5514 | * Example: If the tile size is 16x16 in the map, a tile unit of [2, 4] would be [32, 64] in pixels. | ||
5515 | * If you want the position in pixels: use getPosition() instead. | ||
5516 | * | ||
5517 | * @return Position of tile in tile units. | ||
5518 | */ | ||
5519 | const tson::Vector2i tson::Tile::getPositionInTileUnits(const std::tuple<int, int> &tileDataPos) | ||
5520 | { | ||
5521 | return {std::get<0>(tileDataPos), std::get<1>(tileDataPos)}; | ||
5522 | } | ||
5523 | |||
5524 | void tson::Tile::manageFlipFlagsByIdThenRemoveFlags(uint32_t &id) | ||
5525 | { | ||
5526 | if (id & FLIPPED_HORIZONTALLY_FLAG) m_flipFlags |= TileFlipFlags::Horizontally; | ||
5527 | if (id & FLIPPED_VERTICALLY_FLAG) m_flipFlags |= TileFlipFlags::Vertically; | ||
5528 | if (id & FLIPPED_DIAGONALLY_FLAG) m_flipFlags |= TileFlipFlags::Diagonally; | ||
5529 | |||
5530 | id &= ~(FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG); | ||
5531 | } | ||
5532 | |||
5533 | tson::TileFlipFlags tson::Tile::getFlipFlags() const | ||
5534 | { | ||
5535 | return m_flipFlags; | ||
5536 | } | ||
5537 | |||
5538 | /*! | ||
5539 | * | ||
5540 | * @param flags Which flags to check for. Several flags can be checked at once using the bitwise or operator. | ||
5541 | * Example: | ||
5542 | * hasFlipFlags(TileFlipFlags::Vertically | TileFlipFlags::Horizontally) | ||
5543 | * | ||
5544 | * @return true if the flag(s) specified are set | ||
5545 | */ | ||
5546 | bool tson::Tile::hasFlipFlags(tson::TileFlipFlags flags) | ||
5547 | { | ||
5548 | return ((m_flipFlags & flags) == flags) ? true : false; | ||
5549 | } | ||
5550 | |||
5551 | uint32_t tson::Tile::getGid() const | ||
5552 | { | ||
5553 | return m_gid; | ||
5554 | } | ||
5555 | |||
5556 | void tson::Tile::setProperties(const tson::PropertyCollection &properties) | ||
5557 | { | ||
5558 | m_properties = properties; | ||
5559 | } | ||
5560 | |||
5561 | #endif //TILESON_TILE_HPP | ||
5562 | |||
5563 | /*** End of inlined file: Tile.hpp ***/ | ||
5564 | |||
5565 | |||
5566 | /*** Start of inlined file: Terrain.hpp ***/ | ||
5567 | // | ||
5568 | // Created by robin on 22.03.2020. | ||
5569 | // | ||
5570 | |||
5571 | #ifndef TILESON_TERRAIN_HPP | ||
5572 | #define TILESON_TERRAIN_HPP | ||
5573 | |||
5574 | //#include "../external/json.hpp" | ||
5575 | |||
5576 | namespace tson | ||
5577 | { | ||
5578 | class Terrain | ||
5579 | { | ||
5580 | public: | ||
5581 | inline Terrain() = default; | ||
5582 | inline Terrain(std::string name, int tile); | ||
5583 | inline explicit Terrain(IJson &json); | ||
5584 | |||
5585 | inline bool parse(IJson &json); | ||
5586 | |||
5587 | [[nodiscard]] inline const std::string &getName() const; | ||
5588 | [[nodiscard]] inline int getTile() const; | ||
5589 | [[nodiscard]] inline PropertyCollection &getProperties(); | ||
5590 | |||
5591 | template <typename T> | ||
5592 | inline T get(const std::string &name); | ||
5593 | inline tson::Property * getProp(const std::string &name); | ||
5594 | |||
5595 | private: | ||
5596 | std::string m_name; /*! 'name': Name of terrain */ | ||
5597 | int m_tile {}; /*! 'tile': Local ID of tile representing terrain */ | ||
5598 | tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */ | ||
5599 | }; | ||
5600 | |||
5601 | /*! | ||
5602 | * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>") | ||
5603 | * @tparam T The template value | ||
5604 | * @param name Name of the property | ||
5605 | * @return The actual value, if it exists. Otherwise: The default value of the type. | ||
5606 | */ | ||
5607 | template<typename T> | ||
5608 | T tson::Terrain::get(const std::string &name) | ||
5609 | { | ||
5610 | return m_properties.getValue<T>(name); | ||
5611 | } | ||
5612 | } | ||
5613 | |||
5614 | tson::Terrain::Terrain(std::string name, int tile) : m_name {std::move(name)}, m_tile {tile} | ||
5615 | { | ||
5616 | |||
5617 | } | ||
5618 | |||
5619 | tson::Terrain::Terrain(IJson &json) | ||
5620 | { | ||
5621 | parse(json); | ||
5622 | } | ||
5623 | |||
5624 | bool tson::Terrain::parse(IJson &json) | ||
5625 | { | ||
5626 | bool allFound = true; | ||
5627 | |||
5628 | if(json.count("name") > 0) m_name = json["name"].get<std::string>(); else allFound = false; | ||
5629 | if(json.count("tile") > 0) m_tile = json["tile"].get<int>(); else allFound = false; | ||
5630 | |||
5631 | if(json.count("properties") > 0 && json["properties"].isArray()) | ||
5632 | { | ||
5633 | auto &properties = json.array("properties"); | ||
5634 | std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item) { m_properties.add(*item); }); | ||
5635 | } | ||
5636 | |||
5637 | return allFound; | ||
5638 | } | ||
5639 | |||
5640 | /*! | ||
5641 | * 'name': Name of terrain | ||
5642 | * @return | ||
5643 | */ | ||
5644 | const std::string &tson::Terrain::getName() const | ||
5645 | { | ||
5646 | return m_name; | ||
5647 | } | ||
5648 | |||
5649 | /*! | ||
5650 | * 'tile': Local ID of tile representing terrain | ||
5651 | * @return | ||
5652 | */ | ||
5653 | int tson::Terrain::getTile() const | ||
5654 | { | ||
5655 | return m_tile; | ||
5656 | } | ||
5657 | |||
5658 | /*! | ||
5659 | * 'properties': A list of properties (name, value, type). *Missing from the official Tiled documentation...* | ||
5660 | * @return | ||
5661 | */ | ||
5662 | tson::PropertyCollection &tson::Terrain::getProperties() | ||
5663 | { | ||
5664 | return m_properties; | ||
5665 | } | ||
5666 | |||
5667 | /*! | ||
5668 | * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>"); | ||
5669 | * @param name Name of the property | ||
5670 | * @return | ||
5671 | */ | ||
5672 | tson::Property *tson::Terrain::getProp(const std::string &name) | ||
5673 | { | ||
5674 | if(m_properties.hasProperty(name)) | ||
5675 | return m_properties.getProperty(name); | ||
5676 | return nullptr; | ||
5677 | } | ||
5678 | |||
5679 | #endif //TILESON_TERRAIN_HPP | ||
5680 | |||
5681 | /*** End of inlined file: Terrain.hpp ***/ | ||
5682 | |||
5683 | |||
5684 | /*** Start of inlined file: Grid.hpp ***/ | ||
5685 | // | ||
5686 | // Created by robin on 22.03.2020. | ||
5687 | // | ||
5688 | |||
5689 | #ifndef TILESON_GRID_HPP | ||
5690 | #define TILESON_GRID_HPP | ||
5691 | |||
5692 | #include <string> | ||
5693 | //#include "../external/json.hpp" | ||
5694 | |||
5695 | namespace tson | ||
5696 | { | ||
5697 | class Grid | ||
5698 | { | ||
5699 | public: | ||
5700 | inline Grid() = default; | ||
5701 | inline explicit Grid(IJson &json); | ||
5702 | |||
5703 | inline bool parse(IJson &json); | ||
5704 | |||
5705 | [[nodiscard]] inline const std::string &getOrientation() const; | ||
5706 | [[nodiscard]] inline const Vector2i &getSize() const; | ||
5707 | |||
5708 | private: | ||
5709 | std::string m_orientation; /*! 'orientation': Orientation of the grid for the tiles in this tileset (orthogonal or isometric) */ | ||
5710 | tson::Vector2i m_size; /*! 'width' and 'height': Size. */ | ||
5711 | }; | ||
5712 | } | ||
5713 | |||
5714 | /*! | ||
5715 | * Parses Tiled grid data from json | ||
5716 | * @param json | ||
5717 | */ | ||
5718 | tson::Grid::Grid(IJson &json) | ||
5719 | { | ||
5720 | parse(json); | ||
5721 | } | ||
5722 | |||
5723 | /*! | ||
5724 | * Parses Tiled grid data from json | ||
5725 | * @param json | ||
5726 | * @return true if all mandatory fields was found. false otherwise. | ||
5727 | */ | ||
5728 | bool tson::Grid::parse(IJson &json) | ||
5729 | { | ||
5730 | bool allFound = true; | ||
5731 | |||
5732 | if(json.count("orientation") > 0) m_orientation = json["orientation"].get<std::string>(); //Optional | ||
5733 | |||
5734 | if(json.count("width") > 0 && json.count("height") > 0) | ||
5735 | m_size = {json["width"].get<int>(), json["height"].get<int>()}; else allFound = false; | ||
5736 | |||
5737 | return allFound; | ||
5738 | } | ||
5739 | |||
5740 | /*! | ||
5741 | * 'orientation': Orientation of the grid for the tiles in this tileset (orthogonal or isometric) | ||
5742 | * @return orientation as string | ||
5743 | */ | ||
5744 | const std::string &tson::Grid::getOrientation() const | ||
5745 | { | ||
5746 | return m_orientation; | ||
5747 | } | ||
5748 | |||
5749 | /*! | ||
5750 | * 'width' and 'height': Size. | ||
5751 | * @return size as int | ||
5752 | */ | ||
5753 | const tson::Vector2i &tson::Grid::getSize() const | ||
5754 | { | ||
5755 | return m_size; | ||
5756 | } | ||
5757 | |||
5758 | #endif //TILESON_GRID_HPP | ||
5759 | |||
5760 | /*** End of inlined file: Grid.hpp ***/ | ||
5761 | |||
5762 | #include <functional> | ||
5763 | |||
5764 | namespace tson | ||
5765 | { | ||
5766 | class Map; | ||
5767 | class Tileset | ||
5768 | { | ||
5769 | public: | ||
5770 | inline Tileset() = default; | ||
5771 | inline explicit Tileset(IJson &json, tson::Map *map); | ||
5772 | inline bool parse(IJson &json, tson::Map *map); | ||
5773 | |||
5774 | [[nodiscard]] inline int getColumns() const; | ||
5775 | [[nodiscard]] inline int getFirstgid() const; | ||
5776 | |||
5777 | [[nodiscard]] inline const fs::path &getImagePath() const; | ||
5778 | [[nodiscard]] inline const fs::path &getImage() const; | ||
5779 | |||
5780 | [[nodiscard]] inline const Vector2i &getImageSize() const; | ||
5781 | [[nodiscard]] inline int getMargin() const; | ||
5782 | [[nodiscard]] inline const std::string &getName() const; | ||
5783 | [[nodiscard]] inline int getSpacing() const; | ||
5784 | [[nodiscard]] inline int getTileCount() const; | ||
5785 | [[nodiscard]] inline const Vector2i &getTileSize() const; | ||
5786 | [[nodiscard]] inline const Colori &getTransparentColor() const; | ||
5787 | |||
5788 | [[nodiscard]] inline const std::string &getType() const; | ||
5789 | [[nodiscard]] inline std::vector<tson::Tile> &getTiles(); | ||
5790 | [[nodiscard]] inline const std::vector<tson::WangSet> &getWangsets() const; | ||
5791 | [[nodiscard]] inline PropertyCollection &getProperties(); | ||
5792 | [[nodiscard]] inline const std::vector<tson::Terrain> &getTerrains() const; | ||
5793 | [[nodiscard]] inline const Vector2i &getTileOffset() const; | ||
5794 | [[nodiscard]] inline const Grid &getGrid() const; | ||
5795 | |||
5796 | inline tson::Tile * getTile(int id); | ||
5797 | inline tson::Terrain * getTerrain(const std::string &name); | ||
5798 | |||
5799 | template <typename T> | ||
5800 | inline T get(const std::string &name); | ||
5801 | inline tson::Property * getProp(const std::string &name); | ||
5802 | |||
5803 | //v1.2.0-stuff | ||
5804 | [[nodiscard]] inline tson::Map *getMap() const; | ||
5805 | [[nodiscard]] inline ObjectAlignment getObjectAlignment() const; | ||
5806 | |||
5807 | inline static tson::ObjectAlignment StringToAlignment(std::string_view str); | ||
5808 | |||
5809 | private: | ||
5810 | inline void generateMissingTiles(); | ||
5811 | |||
5812 | int m_columns {}; /*! 'columns': The number of tile columns in the tileset */ | ||
5813 | int m_firstgid {}; /*! 'firstgid': GID corresponding to the first tile in the set */ | ||
5814 | |||
5815 | fs::path m_image; /*! 'image': Image used for tiles in this set */ | ||
5816 | |||
5817 | tson::Vector2i m_imageSize; /*! x = 'imagewidth' and y = 'imageheight': in pixels */ | ||
5818 | int m_margin {}; /*! 'margin': Buffer between image edge and first tile (pixels)*/ | ||
5819 | std::string m_name; /*! 'name': Name given to this tileset */ | ||
5820 | int m_spacing {}; /*! 'spacing': Spacing between adjacent tiles in image (pixels)*/ | ||
5821 | int m_tileCount {}; /*! 'tilecount': The number of tiles in this tileset */ | ||
5822 | tson::Vector2i m_tileSize; /*! x = 'tilewidth' and y = 'tileheight': Maximum size of tiles in this set */ | ||
5823 | tson::Colori m_transparentColor; /*! 'transparentcolor': Hex-formatted color (#RRGGBB) (optional) */ | ||
5824 | std::string m_type; /*! 'type': tileset (for tileset files, since 1.0) */ | ||
5825 | |||
5826 | std::vector<tson::Tile> m_tiles; /*! 'tiles': Array of Tiles (optional) */ | ||
5827 | std::vector<tson::WangSet> m_wangsets; /*! 'wangsets':Array of Wang sets (since 1.1.5) */ | ||
5828 | tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */ | ||
5829 | |||
5830 | std::vector<tson::Terrain> m_terrains; /*! 'terrains': Array of Terrains (optional) */ | ||
5831 | tson::Vector2i m_tileOffset; /*! 'x' and 'y': See <tileoffset> (optional) */ | ||
5832 | tson::Grid m_grid; /*! 'grid': This element is only used in case of isometric orientation, and determines | ||
5833 | how tile overlays for terrain and collision information are rendered. */ | ||
5834 | |||
5835 | //v1.2.0-stuff | ||
5836 | tson::ObjectAlignment m_objectAlignment{tson::ObjectAlignment::Unspecified}; /*! 'objectalignment': Alignment to use for tile objects. Tiled 1.4.*/ | ||
5837 | tson::Map * m_map; /*! The map who owns this tileset */ | ||
5838 | }; | ||
5839 | |||
5840 | /*! | ||
5841 | * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>") | ||
5842 | * @tparam T The template value | ||
5843 | * @param name Name of the property | ||
5844 | * @return The actual value, if it exists. Otherwise: The default value of the type. | ||
5845 | */ | ||
5846 | template<typename T> | ||
5847 | T tson::Tileset::get(const std::string &name) | ||
5848 | { | ||
5849 | return m_properties.getValue<T>(name); | ||
5850 | } | ||
5851 | } | ||
5852 | |||
5853 | tson::Tileset::Tileset(IJson &json, tson::Map *map) | ||
5854 | { | ||
5855 | parse(json, map); | ||
5856 | } | ||
5857 | |||
5858 | bool tson::Tileset::parse(IJson &json, tson::Map *map) | ||
5859 | { | ||
5860 | m_map = map; | ||
5861 | bool allFound = true; | ||
5862 | |||
5863 | if(json.count("columns") > 0) m_columns = json["columns"].get<int>(); else allFound = false; | ||
5864 | if(json.count("firstgid") > 0) m_firstgid = json["firstgid"].get<int>(); else allFound = false; | ||
5865 | |||
5866 | if(json.count("image") > 0) m_image = fs::path(json["image"].get<std::string>()); else allFound = false; | ||
5867 | |||
5868 | if(json.count("margin") > 0) m_margin = json["margin"].get<int>(); else allFound = false; | ||
5869 | if(json.count("name") > 0) m_name = json["name"].get<std::string>(); else allFound = false; | ||
5870 | if(json.count("spacing") > 0) m_spacing = json["spacing"].get<int>(); else allFound = false; | ||
5871 | if(json.count("tilecount") > 0) m_tileCount = json["tilecount"].get<int>(); else allFound = false; | ||
5872 | if(json.count("transparentcolor") > 0) m_transparentColor = tson::Colori(json["transparentcolor"].get<std::string>()); //Optional | ||
5873 | if(json.count("type") > 0) m_type = json["type"].get<std::string>(); | ||
5874 | if(json.count("grid") > 0) m_grid = tson::Grid(json["grid"]); | ||
5875 | |||
5876 | if(json.count("imagewidth") > 0 && json.count("imageheight") > 0) | ||
5877 | m_imageSize = {json["imagewidth"].get<int>(), json["imageheight"].get<int>()}; else allFound = false; | ||
5878 | if(json.count("tilewidth") > 0 && json.count("tileheight") > 0) | ||
5879 | m_tileSize = {json["tilewidth"].get<int>(), json["tileheight"].get<int>()}; else allFound = false; | ||
5880 | if(json.count("tileoffset") > 0) | ||
5881 | m_tileOffset = {json["tileoffset"]["x"].get<int>(), json["tileoffset"]["y"].get<int>()}; | ||
5882 | |||
5883 | //More advanced data | ||
5884 | if(json.count("wangsets") > 0 && json["wangsets"].isArray()) | ||
5885 | { | ||
5886 | auto &wangsets = json.array("wangsets"); | ||
5887 | std::for_each(wangsets.begin(), wangsets.end(), [&](std::unique_ptr<IJson> &item) { m_wangsets.emplace_back(*item); }); | ||
5888 | } | ||
5889 | if(json.count("tiles") > 0 && json["tiles"].isArray()) | ||
5890 | { | ||
5891 | auto &tiles = json.array("tiles"); | ||
5892 | std::for_each(tiles.begin(), tiles.end(), [&](std::unique_ptr<IJson> &item) { m_tiles.emplace_back(*item, this, m_map); }); | ||
5893 | } | ||
5894 | if(json.count("terrains") > 0 && json["terrains"].isArray()) | ||
5895 | { | ||
5896 | auto &terrains = json.array("terrains"); | ||
5897 | std::for_each(terrains.begin(), terrains.end(), [&](std::unique_ptr<IJson> &item) { m_terrains.emplace_back(*item); }); | ||
5898 | } | ||
5899 | |||
5900 | if(json.count("properties") > 0 && json["properties"].isArray()) | ||
5901 | { | ||
5902 | auto &properties = json.array("properties"); | ||
5903 | std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item) { m_properties.add(*item); }); | ||
5904 | } | ||
5905 | |||
5906 | if(json.count("objectalignment") > 0) | ||
5907 | { | ||
5908 | std::string alignment = json["objectalignment"].get<std::string>(); | ||
5909 | m_objectAlignment = StringToAlignment(alignment); | ||
5910 | } | ||
5911 | |||
5912 | generateMissingTiles(); | ||
5913 | |||
5914 | return allFound; | ||
5915 | } | ||
5916 | |||
5917 | /*! | ||
5918 | * 'columns': The number of tile columns in the tileset | ||
5919 | * @return | ||
5920 | */ | ||
5921 | int tson::Tileset::getColumns() const | ||
5922 | { | ||
5923 | return m_columns; | ||
5924 | } | ||
5925 | |||
5926 | /*! | ||
5927 | * 'firstgid': GID corresponding to the first tile in the set | ||
5928 | * @return | ||
5929 | */ | ||
5930 | int tson::Tileset::getFirstgid() const | ||
5931 | { | ||
5932 | return m_firstgid; | ||
5933 | } | ||
5934 | |||
5935 | /*! | ||
5936 | * 'image': Image used for tiles in this set | ||
5937 | * @return | ||
5938 | */ | ||
5939 | |||
5940 | const fs::path &tson::Tileset::getImagePath() const { return m_image; } | ||
5941 | |||
5942 | /*! | ||
5943 | * x = 'imagewidth' and y = 'imageheight': in pixels | ||
5944 | * @return | ||
5945 | */ | ||
5946 | const tson::Vector2i &tson::Tileset::getImageSize() const | ||
5947 | { | ||
5948 | return m_imageSize; | ||
5949 | } | ||
5950 | |||
5951 | /*! | ||
5952 | * 'margin': Buffer between image edge and first tile (pixels) | ||
5953 | * @return | ||
5954 | */ | ||
5955 | int tson::Tileset::getMargin() const | ||
5956 | { | ||
5957 | return m_margin; | ||
5958 | } | ||
5959 | |||
5960 | /*! | ||
5961 | * 'name': Name given to this tileset | ||
5962 | * @return | ||
5963 | */ | ||
5964 | const std::string &tson::Tileset::getName() const | ||
5965 | { | ||
5966 | return m_name; | ||
5967 | } | ||
5968 | |||
5969 | /*! | ||
5970 | * 'spacing': Spacing between adjacent tiles in image (pixels) | ||
5971 | * @return | ||
5972 | */ | ||
5973 | int tson::Tileset::getSpacing() const | ||
5974 | { | ||
5975 | return m_spacing; | ||
5976 | } | ||
5977 | |||
5978 | /*! | ||
5979 | * 'tilecount': The number of tiles in this tileset | ||
5980 | * @return | ||
5981 | */ | ||
5982 | int tson::Tileset::getTileCount() const | ||
5983 | { | ||
5984 | return m_tileCount; | ||
5985 | } | ||
5986 | |||
5987 | /*! | ||
5988 | * x = 'tilewidth' and y = 'tileheight': Maximum size of tiles in this set | ||
5989 | * @return | ||
5990 | */ | ||
5991 | const tson::Vector2i &tson::Tileset::getTileSize() const | ||
5992 | { | ||
5993 | return m_tileSize; | ||
5994 | } | ||
5995 | |||
5996 | /*! | ||
5997 | * 'transparentcolor': Color object created by hex-formatted color (#RRGGBB) (optional) | ||
5998 | * @return | ||
5999 | */ | ||
6000 | const tson::Colori &tson::Tileset::getTransparentColor() const | ||
6001 | { | ||
6002 | return m_transparentColor; | ||
6003 | } | ||
6004 | |||
6005 | /*! | ||
6006 | * 'type': tileset (for tileset files, since 1.0) | ||
6007 | * @return | ||
6008 | */ | ||
6009 | const std::string &tson::Tileset::getType() const | ||
6010 | { | ||
6011 | return m_type; | ||
6012 | } | ||
6013 | |||
6014 | /*! | ||
6015 | * 'image': Image used for tiles in this set | ||
6016 | * @return | ||
6017 | */ | ||
6018 | |||
6019 | const fs::path &tson::Tileset::getImage() const { return m_image; } | ||
6020 | |||
6021 | /*! | ||
6022 | * 'tiles': Array of Tiles (optional) | ||
6023 | * @return | ||
6024 | */ | ||
6025 | std::vector<tson::Tile> &tson::Tileset::getTiles() | ||
6026 | { | ||
6027 | return m_tiles; | ||
6028 | } | ||
6029 | |||
6030 | /*! | ||
6031 | * 'wangsets':Array of Wang sets (since Tiled 1.1.5) | ||
6032 | * @return | ||
6033 | */ | ||
6034 | const std::vector<tson::WangSet> &tson::Tileset::getWangsets() const | ||
6035 | { | ||
6036 | return m_wangsets; | ||
6037 | } | ||
6038 | |||
6039 | /*! | ||
6040 | * 'properties': A list of properties (name, value, type). | ||
6041 | * @return | ||
6042 | */ | ||
6043 | tson::PropertyCollection &tson::Tileset::getProperties() | ||
6044 | { | ||
6045 | return m_properties; | ||
6046 | } | ||
6047 | |||
6048 | /*! | ||
6049 | * 'terrains': Array of Terrains (optional) | ||
6050 | * @return | ||
6051 | */ | ||
6052 | const std::vector<tson::Terrain> &tson::Tileset::getTerrains() const | ||
6053 | { | ||
6054 | return m_terrains; | ||
6055 | } | ||
6056 | |||
6057 | /*! | ||
6058 | * 'x' and 'y': See <tileoffset> (optional) | ||
6059 | * @return | ||
6060 | */ | ||
6061 | const tson::Vector2i &tson::Tileset::getTileOffset() const | ||
6062 | { | ||
6063 | return m_tileOffset; | ||
6064 | } | ||
6065 | |||
6066 | /*! | ||
6067 | * 'grid': This element is only used in case of isometric orientation, and determines | ||
6068 | * how tile overlays for terrain and collision information are rendered. | ||
6069 | * @return | ||
6070 | */ | ||
6071 | const tson::Grid &tson::Tileset::getGrid() const | ||
6072 | { | ||
6073 | return m_grid; | ||
6074 | } | ||
6075 | |||
6076 | /*! | ||
6077 | * Gets a tile by ID (Tiled ID + 1) | ||
6078 | * @param id The ID of the tile stored in Tiled map + 1. Example: If ID was stored in Tiled map as 0, the corresponding value in Tileson is 1. | ||
6079 | * This is to make sure the IDs of tiles matches their references in containers. | ||
6080 | * @return A pointer to the Tile if found. nullptr otherwise. | ||
6081 | */ | ||
6082 | tson::Tile *tson::Tileset::getTile(int id) | ||
6083 | { | ||
6084 | auto result = std::find_if(m_tiles.begin(), m_tiles.end(), [&](const tson::Tile & item) { return item.getId() == id;}); | ||
6085 | if(result == m_tiles.end()) | ||
6086 | return nullptr; | ||
6087 | |||
6088 | return &result.operator*(); | ||
6089 | } | ||
6090 | |||
6091 | /*! | ||
6092 | * Get an existing Terrain object by name | ||
6093 | * @param name | ||
6094 | * @return A pointer to the Terrain if found. nullptr otherwise. | ||
6095 | */ | ||
6096 | tson::Terrain *tson::Tileset::getTerrain(const std::string &name) | ||
6097 | { | ||
6098 | auto result = std::find_if(m_terrains.begin(), m_terrains.end(), [&](const tson::Terrain & item) { return item.getName() == name;}); | ||
6099 | if(result == m_terrains.end()) | ||
6100 | return nullptr; | ||
6101 | |||
6102 | return &result.operator*(); | ||
6103 | } | ||
6104 | |||
6105 | /*! | ||
6106 | * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>"); | ||
6107 | * @param name Name of the property | ||
6108 | * @return | ||
6109 | */ | ||
6110 | tson::Property *tson::Tileset::getProp(const std::string &name) | ||
6111 | { | ||
6112 | if(m_properties.hasProperty(name)) | ||
6113 | return m_properties.getProperty(name); | ||
6114 | |||
6115 | return nullptr; | ||
6116 | } | ||
6117 | |||
6118 | /*! | ||
6119 | * Tiled only has tiles with a property stored in the map. This function makes sure even the ones with no properties will exist. | ||
6120 | */ | ||
6121 | void tson::Tileset::generateMissingTiles() | ||
6122 | { | ||
6123 | std::vector<uint32_t> tileIds; | ||
6124 | for(auto &tile : m_tiles) | ||
6125 | tileIds.push_back(tile.getId()); | ||
6126 | |||
6127 | for(uint32_t i = m_firstgid; i < m_firstgid + m_tileCount; ++i) | ||
6128 | { | ||
6129 | if(std::count(tileIds.begin(), tileIds.end(), i) == 0) | ||
6130 | { | ||
6131 | m_tiles.emplace_back(Tile(i, this, m_map)); | ||
6132 | } | ||
6133 | } | ||
6134 | } | ||
6135 | |||
6136 | /*! | ||
6137 | * Used for getting the tson::Map who is the parent of this Tileset. | ||
6138 | * @return a pointer to the tson::Map where this tileset is contained. | ||
6139 | */ | ||
6140 | tson::Map *tson::Tileset::getMap() const | ||
6141 | { | ||
6142 | return m_map; | ||
6143 | } | ||
6144 | |||
6145 | /*! | ||
6146 | * | ||
6147 | * @param str The string you want to convert | ||
6148 | * @return Alignment enum based on the string from the input. | ||
6149 | */ | ||
6150 | tson::ObjectAlignment tson::Tileset::StringToAlignment(std::string_view str) | ||
6151 | { | ||
6152 | if(str == "unspecified") return tson::ObjectAlignment::Unspecified; | ||
6153 | else if(str == "topleft") return tson::ObjectAlignment::TopLeft; | ||
6154 | else if(str == "top") return tson::ObjectAlignment::Top; | ||
6155 | else if(str == "topright") return tson::ObjectAlignment::TopRight; | ||
6156 | else if(str == "left") return tson::ObjectAlignment::Left; | ||
6157 | else if(str == "center") return tson::ObjectAlignment::Center; | ||
6158 | else if(str == "right") return tson::ObjectAlignment::Right; | ||
6159 | else if(str == "bottomleft") return tson::ObjectAlignment::BottomLeft; | ||
6160 | else if(str == "bottom") return tson::ObjectAlignment::Bottom; | ||
6161 | else if(str == "bottomright") return tson::ObjectAlignment::BottomRight; | ||
6162 | else | ||
6163 | return tson::ObjectAlignment::Unspecified; | ||
6164 | } | ||
6165 | |||
6166 | tson::ObjectAlignment tson::Tileset::getObjectAlignment() const | ||
6167 | { | ||
6168 | return m_objectAlignment; | ||
6169 | } | ||
6170 | |||
6171 | #endif //TILESON_TILESET_HPP | ||
6172 | /*** End of inlined file: Tileset.hpp ***/ | ||
6173 | |||
6174 | namespace tson | ||
6175 | { | ||
6176 | class Map | ||
6177 | { | ||
6178 | public: | ||
6179 | inline Map() = default; | ||
6180 | inline Map(ParseStatus status, std::string description); | ||
6181 | inline explicit Map(IJson &json, tson::DecompressorContainer *decompressors); | ||
6182 | inline bool parse(IJson &json, tson::DecompressorContainer *decompressors); | ||
6183 | |||
6184 | [[nodiscard]] inline const Colori &getBackgroundColor() const; | ||
6185 | [[nodiscard]] inline const Vector2i &getSize() const; | ||
6186 | [[nodiscard]] inline int getHexsideLength() const; | ||
6187 | [[nodiscard]] inline bool isInfinite() const; | ||
6188 | [[nodiscard]] inline int getNextLayerId() const; | ||
6189 | [[nodiscard]] inline int getNextObjectId() const; | ||
6190 | [[nodiscard]] inline const std::string &getOrientation() const; | ||
6191 | [[nodiscard]] inline const std::string &getRenderOrder() const; | ||
6192 | [[nodiscard]] inline const std::string &getStaggerAxis() const; | ||
6193 | [[nodiscard]] inline const std::string &getStaggerIndex() const; | ||
6194 | [[nodiscard]] inline const std::string &getTiledVersion() const; | ||
6195 | [[nodiscard]] inline const Vector2i &getTileSize() const; | ||
6196 | [[nodiscard]] inline const std::string &getType() const; | ||
6197 | [[nodiscard]] inline int getVersion() const; | ||
6198 | |||
6199 | [[nodiscard]] inline std::vector<tson::Layer> &getLayers(); | ||
6200 | [[nodiscard]] inline PropertyCollection &getProperties(); | ||
6201 | [[nodiscard]] inline std::vector<tson::Tileset> &getTilesets(); | ||
6202 | |||
6203 | [[nodiscard]] inline ParseStatus getStatus() const; | ||
6204 | [[nodiscard]] inline const std::string &getStatusMessage() const; | ||
6205 | [[nodiscard]] inline const std::map<uint32_t, tson::Tile *> &getTileMap() const; | ||
6206 | |||
6207 | inline Layer * getLayer(const std::string &name); | ||
6208 | inline Tileset * getTileset(const std::string &name); | ||
6209 | |||
6210 | template <typename T> | ||
6211 | inline T get(const std::string &name); | ||
6212 | inline tson::Property * getProp(const std::string &name); | ||
6213 | |||
6214 | //v1.2.0 | ||
6215 | [[nodiscard]] inline int getCompressionLevel() const; | ||
6216 | inline DecompressorContainer *getDecompressors(); | ||
6217 | inline Tileset * getTilesetByGid(uint32_t gid); | ||
6218 | |||
6219 | private: | ||
6220 | inline void createTilesetData(IJson &json); | ||
6221 | inline void processData(); | ||
6222 | |||
6223 | Colori m_backgroundColor; /*! 'backgroundcolor': Hex-formatted color (#RRGGBB or #AARRGGBB) (optional)*/; | ||
6224 | Vector2i m_size; /*! 'width' and 'height' of a Tiled map */ | ||
6225 | int m_hexsideLength {}; /*! 'hexsidelength': Length of the side of a hex tile in pixels */ | ||
6226 | bool m_isInfinite {}; /*! 'infinite': Whether the map has infinite dimensions*/ | ||
6227 | std::vector<tson::Layer> m_layers; /*! 'layers': Array of layers. group on */ | ||
6228 | int m_nextLayerId {}; /*! 'nextlayerid': Auto-increments for each layer */ | ||
6229 | int m_nextObjectId {}; /*! 'nextobjectid': Auto-increments for each placed object */ | ||
6230 | std::string m_orientation; /*! 'orientation': orthogonal, isometric, staggered or hexagonal */ | ||
6231 | tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */ | ||
6232 | std::string m_renderOrder; /*! 'renderorder': Rendering direction (orthogonal maps only) */ | ||
6233 | std::string m_staggerAxis; /*! 'staggeraxis': x or y (staggered / hexagonal maps only) */ | ||
6234 | std::string m_staggerIndex; /*! 'staggerindex': odd or even (staggered / hexagonal maps only) */ | ||
6235 | std::string m_tiledVersion; /*! 'tiledversion': The Tiled version used to save the file */ | ||
6236 | Vector2i m_tileSize; /*! 'tilewidth': and 'tileheight' of a map */ | ||
6237 | std::vector<tson::Tileset> m_tilesets; /*! 'tilesets': Array of Tilesets */ | ||
6238 | std::string m_type; /*! 'type': map (since 1.0) */ | ||
6239 | int m_version{}; /*! 'version': The JSON format version*/ | ||
6240 | |||
6241 | ParseStatus m_status {ParseStatus::OK}; | ||
6242 | std::string m_statusMessage {"OK"}; | ||
6243 | |||
6244 | std::map<uint32_t, tson::Tile*> m_tileMap; /*! key: Tile ID. Value: Pointer to Tile*/ | ||
6245 | |||
6246 | //v1.2.0 | ||
6247 | int m_compressionLevel {-1}; /*! 'compressionlevel': The compression level to use for tile layer | ||
6248 | * data (defaults to -1, which means to use the algorithm default) | ||
6249 | * Introduced in Tiled 1.3*/ | ||
6250 | tson::DecompressorContainer * m_decompressors; | ||
6251 | std::map<uint32_t, tson::Tile> m_flaggedTileMap; /*! key: Tile ID. Value: Tile*/ | ||
6252 | }; | ||
6253 | |||
6254 | /*! | ||
6255 | * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>") | ||
6256 | * @tparam T The template value | ||
6257 | * @param name Name of the property | ||
6258 | * @return The actual value, if it exists. Otherwise: The default value of the type. | ||
6259 | */ | ||
6260 | template<typename T> | ||
6261 | T tson::Map::get(const std::string &name) | ||
6262 | { | ||
6263 | return m_properties.getValue<T>(name); | ||
6264 | } | ||
6265 | } | ||
6266 | |||
6267 | /*! | ||
6268 | * When errors have happened before the map starts parsing, just keep the statuses | ||
6269 | * @param status The status | ||
6270 | * @param description Description of the status | ||
6271 | */ | ||
6272 | tson::Map::Map(tson::ParseStatus status, std::string description) : m_status {status}, m_statusMessage { std::move(description) } | ||
6273 | { | ||
6274 | |||
6275 | } | ||
6276 | |||
6277 | /*! | ||
6278 | * Parses a json of a Tiled map. | ||
6279 | * @param json A json object with the format of Map | ||
6280 | * @return true if all mandatory fields was found. false otherwise. | ||
6281 | */ | ||
6282 | tson::Map::Map(IJson &json, tson::DecompressorContainer *decompressors) | ||
6283 | { | ||
6284 | parse(json, decompressors); | ||
6285 | } | ||
6286 | |||
6287 | /*! | ||
6288 | * Parses a json of a Tiled map. | ||
6289 | * @param json A json object with the format of Map | ||
6290 | * @return true if all mandatory fields was found. false otherwise. | ||
6291 | */ | ||
6292 | bool tson::Map::parse(IJson &json, tson::DecompressorContainer *decompressors) | ||
6293 | { | ||
6294 | m_decompressors = decompressors; | ||
6295 | |||
6296 | bool allFound = true; | ||
6297 | if(json.count("compressionlevel") > 0) | ||
6298 | m_compressionLevel = json["compressionlevel"].get<int>(); //Tiled 1.3 - Optional | ||
6299 | |||
6300 | if(json.count("backgroundcolor") > 0) m_backgroundColor = Colori(json["backgroundcolor"].get<std::string>()); //Optional | ||
6301 | if(json.count("width") > 0 && json.count("height") > 0 ) | ||
6302 | m_size = {json["width"].get<int>(), json["height"].get<int>()}; else allFound = false; | ||
6303 | if(json.count("hexsidelength") > 0) m_hexsideLength = json["hexsidelength"].get<int>(); //Optional | ||
6304 | if(json.count("infinite") > 0) m_isInfinite = json["infinite"].get<bool>(); //Optional | ||
6305 | if(json.count("nextlayerid") > 0) m_nextLayerId = json["nextlayerid"].get<int>(); //Optional | ||
6306 | if(json.count("nextobjectid") > 0) m_nextObjectId = json["nextobjectid"].get<int>(); else allFound = false; | ||
6307 | if(json.count("orientation") > 0) m_orientation = json["orientation"].get<std::string>(); else allFound = false; | ||
6308 | if(json.count("renderorder") > 0) m_renderOrder = json["renderorder"].get<std::string>(); //Optional | ||
6309 | if(json.count("staggeraxis") > 0) m_staggerAxis = json["staggeraxis"].get<std::string>(); //Optional | ||
6310 | if(json.count("staggerindex") > 0) m_staggerIndex = json["staggerindex"].get<std::string>(); //Optional | ||
6311 | if(json.count("tiledversion") > 0) m_tiledVersion = json["tiledversion"].get<std::string>(); else allFound = false; | ||
6312 | if(json.count("tilewidth") > 0 && json.count("tileheight") > 0 ) | ||
6313 | m_tileSize = {json["tilewidth"].get<int>(), json["tileheight"].get<int>()}; else allFound = false; | ||
6314 | if(json.count("type") > 0) m_type = json["type"].get<std::string>(); //Optional | ||
6315 | if(json.count("version") > 0) m_version = json["version"].get<int>(); else allFound = false; | ||
6316 | |||
6317 | //More advanced data | ||
6318 | if(json.count("layers") > 0 && json["layers"].isArray()) | ||
6319 | { | ||
6320 | auto &array = json.array("layers"); | ||
6321 | std::for_each(array.begin(), array.end(), [&](std::unique_ptr<IJson> &item) | ||
6322 | { | ||
6323 | m_layers.emplace_back(*item, this); | ||
6324 | }); | ||
6325 | } | ||
6326 | |||
6327 | if(json.count("properties") > 0 && json["properties"].isArray()) | ||
6328 | { | ||
6329 | auto &array = json.array("properties"); | ||
6330 | std::for_each(array.begin(), array.end(), [&](std::unique_ptr<IJson> &item) | ||
6331 | { | ||
6332 | m_properties.add(*item); | ||
6333 | }); | ||
6334 | } | ||
6335 | createTilesetData(json); | ||
6336 | processData(); | ||
6337 | |||
6338 | return allFound; | ||
6339 | } | ||
6340 | |||
6341 | /*! | ||
6342 | * Tileset data must be created in two steps to prevent malformed tson::Tileset pointers inside tson::Tile | ||
6343 | */ | ||
6344 | void tson::Map::createTilesetData(IJson &json) | ||
6345 | { | ||
6346 | if(json.count("tilesets") > 0 && json["tilesets"].isArray()) | ||
6347 | { | ||
6348 | //First created tileset objects | ||
6349 | auto &tilesets = json.array("tilesets"); | ||
6350 | std::for_each(tilesets.begin(), tilesets.end(), [&](std::unique_ptr<IJson> &item) | ||
6351 | { | ||
6352 | m_tilesets.emplace_back(); | ||
6353 | }); | ||
6354 | |||
6355 | int i = 0; | ||
6356 | //Then do the parsing | ||
6357 | std::for_each(tilesets.begin(), tilesets.end(), [&](std::unique_ptr<IJson> &item) | ||
6358 | { | ||
6359 | m_tilesets[i].parse(*item, this); | ||
6360 | ++i; | ||
6361 | }); | ||
6362 | } | ||
6363 | } | ||
6364 | |||
6365 | /*! | ||
6366 | * Processes the parsed data and uses the data to create helpful objects, like tile maps. | ||
6367 | */ | ||
6368 | void tson::Map::processData() | ||
6369 | { | ||
6370 | m_tileMap.clear(); | ||
6371 | for(auto &tileset : m_tilesets) | ||
6372 | { | ||
6373 | std::for_each(tileset.getTiles().begin(), tileset.getTiles().end(), [&](tson::Tile &tile) { m_tileMap[tile.getGid()] = &tile; }); | ||
6374 | } | ||
6375 | std::for_each(m_layers.begin(), m_layers.end(), [&](tson::Layer &layer) | ||
6376 | { | ||
6377 | layer.assignTileMap(&m_tileMap); | ||
6378 | layer.createTileData(m_size, m_isInfinite); | ||
6379 | const std::set<uint32_t> &flaggedTiles = layer.getUniqueFlaggedTiles(); | ||
6380 | for(uint32_t ftile : flaggedTiles) | ||
6381 | { | ||
6382 | tson::Tile tile {ftile, layer.getMap()}; | ||
6383 | if(m_tileMap.count(tile.getGid())) | ||
6384 | { | ||
6385 | tson::Tile *originalTile = m_tileMap[tile.getGid()]; | ||
6386 | tile.addTilesetAndPerformCalculations(originalTile->getTileset()); | ||
6387 | tile.setProperties(originalTile->getProperties()); | ||
6388 | m_flaggedTileMap[ftile] = tile; | ||
6389 | m_tileMap[ftile] = &m_flaggedTileMap[ftile]; | ||
6390 | } | ||
6391 | } | ||
6392 | layer.resolveFlaggedTiles(); | ||
6393 | }); | ||
6394 | } | ||
6395 | |||
6396 | /*! | ||
6397 | * 'backgroundcolor': Color created from a hex-formatted color string (#RRGGBB or #AARRGGBB) (optional) | ||
6398 | * @return string as color | ||
6399 | */ | ||
6400 | const tson::Colori &tson::Map::getBackgroundColor() const | ||
6401 | { | ||
6402 | return m_backgroundColor; | ||
6403 | } | ||
6404 | |||
6405 | /*! | ||
6406 | * 'width' and 'height' of a Tiled map | ||
6407 | * @return | ||
6408 | */ | ||
6409 | const tson::Vector2<int> &tson::Map::getSize() const | ||
6410 | { | ||
6411 | return m_size; | ||
6412 | } | ||
6413 | |||
6414 | /*! | ||
6415 | * 'hexsidelength': Length of the side of a hex tile in pixels | ||
6416 | * @return | ||
6417 | */ | ||
6418 | int tson::Map::getHexsideLength() const | ||
6419 | { | ||
6420 | return m_hexsideLength; | ||
6421 | } | ||
6422 | |||
6423 | /*! | ||
6424 | * 'infinite': Whether the map has infinite dimensions | ||
6425 | * @return | ||
6426 | */ | ||
6427 | bool tson::Map::isInfinite() const | ||
6428 | { | ||
6429 | return m_isInfinite; | ||
6430 | } | ||
6431 | |||
6432 | /*! | ||
6433 | * 'nextlayerid': Auto-increments for each layer | ||
6434 | * @return | ||
6435 | */ | ||
6436 | int tson::Map::getNextLayerId() const | ||
6437 | { | ||
6438 | return m_nextLayerId; | ||
6439 | } | ||
6440 | |||
6441 | /*! | ||
6442 | * 'nextobjectid': Auto-increments for each placed object | ||
6443 | * @return | ||
6444 | */ | ||
6445 | int tson::Map::getNextObjectId() const | ||
6446 | { | ||
6447 | return m_nextObjectId; | ||
6448 | } | ||
6449 | |||
6450 | /*! | ||
6451 | * 'orientation': orthogonal, isometric, staggered or hexagonal | ||
6452 | * @return | ||
6453 | */ | ||
6454 | const std::string &tson::Map::getOrientation() const | ||
6455 | { | ||
6456 | return m_orientation; | ||
6457 | } | ||
6458 | |||
6459 | /*! | ||
6460 | * 'renderorder': Rendering direction (orthogonal maps only) | ||
6461 | * @return | ||
6462 | */ | ||
6463 | const std::string &tson::Map::getRenderOrder() const | ||
6464 | { | ||
6465 | return m_renderOrder; | ||
6466 | } | ||
6467 | |||
6468 | /*! | ||
6469 | * 'staggeraxis': x or y (staggered / hexagonal maps only) | ||
6470 | * @return | ||
6471 | */ | ||
6472 | const std::string &tson::Map::getStaggerAxis() const | ||
6473 | { | ||
6474 | return m_staggerAxis; | ||
6475 | } | ||
6476 | |||
6477 | /*! | ||
6478 | * 'staggerindex': odd or even (staggered / hexagonal maps only) | ||
6479 | * @return | ||
6480 | */ | ||
6481 | const std::string &tson::Map::getStaggerIndex() const | ||
6482 | { | ||
6483 | return m_staggerIndex; | ||
6484 | } | ||
6485 | |||
6486 | /*! | ||
6487 | * 'tiledversion': The Tiled version used to save the file | ||
6488 | * @return | ||
6489 | */ | ||
6490 | const std::string &tson::Map::getTiledVersion() const | ||
6491 | { | ||
6492 | return m_tiledVersion; | ||
6493 | } | ||
6494 | |||
6495 | /*! | ||
6496 | * 'tilewidth': and 'tileheight' of a map | ||
6497 | * @return | ||
6498 | */ | ||
6499 | const tson::Vector2<int> &tson::Map::getTileSize() const | ||
6500 | { | ||
6501 | return m_tileSize; | ||
6502 | } | ||
6503 | |||
6504 | /*! | ||
6505 | * 'type': map (since 1.0) | ||
6506 | * @return | ||
6507 | */ | ||
6508 | const std::string &tson::Map::getType() const | ||
6509 | { | ||
6510 | return m_type; | ||
6511 | } | ||
6512 | |||
6513 | /*! | ||
6514 | * 'version': The JSON format version | ||
6515 | * @return | ||
6516 | */ | ||
6517 | int tson::Map::getVersion() const | ||
6518 | { | ||
6519 | return m_version; | ||
6520 | } | ||
6521 | |||
6522 | /*! | ||
6523 | * 'layers': Array of layers. group on | ||
6524 | * @return | ||
6525 | */ | ||
6526 | std::vector<tson::Layer> &tson::Map::getLayers() | ||
6527 | { | ||
6528 | return m_layers; | ||
6529 | } | ||
6530 | |||
6531 | /*! | ||
6532 | * 'properties': A list of properties (name, value, type). | ||
6533 | * @return | ||
6534 | */ | ||
6535 | tson::PropertyCollection &tson::Map::getProperties() | ||
6536 | { | ||
6537 | return m_properties; | ||
6538 | } | ||
6539 | |||
6540 | /*! | ||
6541 | * 'tilesets': Array of Tilesets | ||
6542 | * @return | ||
6543 | */ | ||
6544 | std::vector<tson::Tileset> &tson::Map::getTilesets() | ||
6545 | { | ||
6546 | return m_tilesets; | ||
6547 | } | ||
6548 | |||
6549 | tson::Layer *tson::Map::getLayer(const std::string &name) | ||
6550 | { | ||
6551 | auto result = std::find_if(m_layers.begin(), m_layers.end(), [&](const tson::Layer &item) { return item.getName() == name; }); | ||
6552 | if(result == m_layers.end()) | ||
6553 | return nullptr; | ||
6554 | |||
6555 | return &result.operator*(); | ||
6556 | } | ||
6557 | |||
6558 | /*! | ||
6559 | * Gets a tileset by name | ||
6560 | * | ||
6561 | * @param name Name of the tileset | ||
6562 | * @return tileset with the matching name | ||
6563 | */ | ||
6564 | tson::Tileset *tson::Map::getTileset(const std::string &name) | ||
6565 | { | ||
6566 | auto result = std::find_if(m_tilesets.begin(), m_tilesets.end(), [&](const tson::Tileset &item) {return item.getName() == name; }); | ||
6567 | if(result == m_tilesets.end()) | ||
6568 | return nullptr; | ||
6569 | |||
6570 | return &result.operator*(); | ||
6571 | } | ||
6572 | |||
6573 | /*! | ||
6574 | * Gets a tileset by gid (graphical ID of a tile). These are always unique, no matter how many tilesets you have | ||
6575 | * | ||
6576 | * @param gid Graphical ID of a tile | ||
6577 | * @return tileset related to the actual gid | ||
6578 | */ | ||
6579 | tson::Tileset *tson::Map::getTilesetByGid(uint32_t gid) | ||
6580 | { | ||
6581 | auto result = std::find_if(m_tilesets.begin(), m_tilesets.end(), [&](const tson::Tileset &tileset) | ||
6582 | { | ||
6583 | int firstId = tileset.getFirstgid(); //First tile id of the tileset | ||
6584 | int lastId = (firstId + tileset.getTileCount()) - 1; | ||
6585 | |||
6586 | return (gid >= firstId && gid <= lastId); | ||
6587 | }); | ||
6588 | if(result == m_tilesets.end()) | ||
6589 | return nullptr; | ||
6590 | |||
6591 | return &result.operator*(); | ||
6592 | } | ||
6593 | |||
6594 | /*! | ||
6595 | * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>"); | ||
6596 | * @param name Name of the property | ||
6597 | * @return | ||
6598 | */ | ||
6599 | tson::Property *tson::Map::getProp(const std::string &name) | ||
6600 | { | ||
6601 | if(m_properties.hasProperty(name)) | ||
6602 | return m_properties.getProperty(name); | ||
6603 | return nullptr; | ||
6604 | } | ||
6605 | |||
6606 | tson::ParseStatus tson::Map::getStatus() const | ||
6607 | { | ||
6608 | return m_status; | ||
6609 | } | ||
6610 | |||
6611 | const std::string &tson::Map::getStatusMessage() const | ||
6612 | { | ||
6613 | return m_statusMessage; | ||
6614 | } | ||
6615 | |||
6616 | /*! | ||
6617 | * Get a tile map with pointers to every existing tile. | ||
6618 | * @return | ||
6619 | */ | ||
6620 | const std::map<uint32_t, tson::Tile *> &tson::Map::getTileMap() const | ||
6621 | { | ||
6622 | return m_tileMap; | ||
6623 | } | ||
6624 | |||
6625 | tson::DecompressorContainer *tson::Map::getDecompressors() | ||
6626 | { | ||
6627 | return m_decompressors; | ||
6628 | } | ||
6629 | |||
6630 | /*! | ||
6631 | * 'compressionlevel': The compression level to use for tile layer data (defaults to -1, which means to use the algorithm default) | ||
6632 | * | ||
6633 | * @return The compression level | ||
6634 | */ | ||
6635 | int tson::Map::getCompressionLevel() const | ||
6636 | { | ||
6637 | return m_compressionLevel; | ||
6638 | } | ||
6639 | |||
6640 | #endif //TILESON_MAP_HPP | ||
6641 | |||
6642 | /*** End of inlined file: Map.hpp ***/ | ||
6643 | |||
6644 | |||
6645 | /*** Start of inlined file: Project.hpp ***/ | ||
6646 | // | ||
6647 | // Created by robin on 01.08.2020. | ||
6648 | // | ||
6649 | |||
6650 | #ifndef TILESON_PROJECT_HPP | ||
6651 | #define TILESON_PROJECT_HPP | ||
6652 | |||
6653 | #include <fstream> | ||
6654 | #include <sstream> | ||
6655 | #include <memory> | ||
6656 | |||
6657 | /*** Start of inlined file: World.hpp ***/ | ||
6658 | // | ||
6659 | // Created by robin on 01.08.2020. | ||
6660 | // | ||
6661 | |||
6662 | #ifndef TILESON_WORLD_HPP | ||
6663 | #define TILESON_WORLD_HPP | ||
6664 | |||
6665 | |||
6666 | /*** Start of inlined file: WorldMapData.hpp ***/ | ||
6667 | // | ||
6668 | // Created by robin on 01.08.2020. | ||
6669 | // | ||
6670 | |||
6671 | #ifndef TILESON_WORLDMAPDATA_HPP | ||
6672 | #define TILESON_WORLDMAPDATA_HPP | ||
6673 | |||
6674 | namespace tson | ||
6675 | { | ||
6676 | class WorldMapData | ||
6677 | { | ||
6678 | public: | ||
6679 | inline WorldMapData(const fs::path &folder_, IJson &json); | ||
6680 | inline void parse(const fs::path &folder_, IJson &json); | ||
6681 | //inline WorldMapData(fs::path folder_, std::string fileName_) : folder {std::move(folder_)}, fileName {fileName_} | ||
6682 | //{ | ||
6683 | // path = folder / fileName; | ||
6684 | //} | ||
6685 | |||
6686 | fs::path folder; | ||
6687 | fs::path path; | ||
6688 | std::string fileName; | ||
6689 | tson::Vector2i size; | ||
6690 | tson::Vector2i position; | ||
6691 | }; | ||
6692 | |||
6693 | WorldMapData::WorldMapData(const fs::path &folder_, IJson &json) | ||
6694 | { | ||
6695 | parse(folder_, json); | ||
6696 | } | ||
6697 | |||
6698 | void WorldMapData::parse(const fs::path &folder_, IJson &json) | ||
6699 | { | ||
6700 | folder = folder_; | ||
6701 | if(json.count("fileName") > 0) fileName = json["fileName"].get<std::string>(); | ||
6702 | if(json.count("height") > 0) size = {json["width"].get<int>(), json["height"].get<int>()}; | ||
6703 | if(json.count("x") > 0) position = {json["x"].get<int>(), json["y"].get<int>()}; | ||
6704 | |||
6705 | path = (!fileName.empty()) ? folder / fileName : folder; | ||
6706 | } | ||
6707 | } | ||
6708 | |||
6709 | #endif //TILESON_WORLDMAPDATA_HPP | ||
6710 | /*** End of inlined file: WorldMapData.hpp ***/ | ||
6711 | |||
6712 | #include <memory> | ||
6713 | namespace tson | ||
6714 | { | ||
6715 | class Tileson; | ||
6716 | class World | ||
6717 | { | ||
6718 | public: | ||
6719 | #ifdef JSON11_IS_DEFINED | ||
6720 | inline explicit World(std::unique_ptr<tson::IJson> jsonParser = std::make_unique<tson::Json11>()) : m_json {std::move(jsonParser)} | ||
6721 | { | ||
6722 | } | ||
6723 | |||
6724 | inline explicit World(const fs::path &path, std::unique_ptr<tson::IJson> jsonParser = std::make_unique<tson::Json11>()); | ||
6725 | #else | ||
6726 | inline explicit World(std::unique_ptr<tson::IJson> jsonParser) : m_json {std::move(jsonParser)} | ||
6727 | { | ||
6728 | } | ||
6729 | |||
6730 | inline explicit World(const fs::path &path, std::unique_ptr<tson::IJson> jsonParser); | ||
6731 | #endif | ||
6732 | inline bool parse(const fs::path &path); | ||
6733 | inline int loadMaps(tson::Tileson *parser); //tileson_forward.hpp | ||
6734 | inline bool contains(std::string_view filename); | ||
6735 | inline const WorldMapData *get(std::string_view filename) const; | ||
6736 | |||
6737 | [[nodiscard]] inline const fs::path &getPath() const; | ||
6738 | [[nodiscard]] inline const fs::path &getFolder() const; | ||
6739 | [[nodiscard]] inline const std::vector<WorldMapData> &getMapData() const; | ||
6740 | [[nodiscard]] inline bool onlyShowAdjacentMaps() const; | ||
6741 | [[nodiscard]] inline const std::string &getType() const; | ||
6742 | [[nodiscard]] inline const std::vector<std::unique_ptr<tson::Map>> &getMaps() const; | ||
6743 | |||
6744 | private: | ||
6745 | inline void parseJson(IJson &json); | ||
6746 | |||
6747 | std::unique_ptr<IJson> m_json = nullptr; | ||
6748 | fs::path m_path; | ||
6749 | fs::path m_folder; | ||
6750 | std::vector<WorldMapData> m_mapData; | ||
6751 | std::vector<std::unique_ptr<tson::Map>> m_maps; | ||
6752 | bool m_onlyShowAdjacentMaps; | ||
6753 | std::string m_type; | ||
6754 | }; | ||
6755 | |||
6756 | World::World(const fs::path &path, std::unique_ptr<tson::IJson> jsonParser) : m_json {std::move(jsonParser)} | ||
6757 | { | ||
6758 | parse(path); | ||
6759 | } | ||
6760 | |||
6761 | bool World::parse(const fs::path &path) | ||
6762 | { | ||
6763 | m_path = path; | ||
6764 | m_folder = m_path.parent_path(); | ||
6765 | |||
6766 | if(!m_json->parse(path)) | ||
6767 | return false; | ||
6768 | |||
6769 | parseJson(*m_json); | ||
6770 | return true; | ||
6771 | } | ||
6772 | |||
6773 | const fs::path &World::getPath() const | ||
6774 | { | ||
6775 | return m_path; | ||
6776 | } | ||
6777 | |||
6778 | const std::vector<WorldMapData> &World::getMapData() const | ||
6779 | { | ||
6780 | return m_mapData; | ||
6781 | } | ||
6782 | |||
6783 | bool World::onlyShowAdjacentMaps() const | ||
6784 | { | ||
6785 | return m_onlyShowAdjacentMaps; | ||
6786 | } | ||
6787 | |||
6788 | const std::string &World::getType() const | ||
6789 | { | ||
6790 | return m_type; | ||
6791 | } | ||
6792 | |||
6793 | void World::parseJson(IJson &json) | ||
6794 | { | ||
6795 | if(json.count("onlyShowAdjacentMaps") > 0) m_onlyShowAdjacentMaps = json["onlyShowAdjacentMaps"].get<bool>(); | ||
6796 | if(json.count("type") > 0) m_type = json["type"].get<std::string>(); | ||
6797 | |||
6798 | if(json["maps"].isArray()) | ||
6799 | { | ||
6800 | auto &maps = json.array("maps"); | ||
6801 | std::for_each(maps.begin(), maps.end(), [&](std::unique_ptr<IJson> &item) { m_mapData.emplace_back(m_folder, *item); }); | ||
6802 | } | ||
6803 | } | ||
6804 | |||
6805 | const fs::path &World::getFolder() const | ||
6806 | { | ||
6807 | return m_folder; | ||
6808 | } | ||
6809 | |||
6810 | /*! | ||
6811 | * Check if there is WorldMapData in the world that contains the current filename. | ||
6812 | * Filename = <file>.<extension> | ||
6813 | * @param filename | ||
6814 | * @return | ||
6815 | */ | ||
6816 | bool World::contains(std::string_view filename) | ||
6817 | { | ||
6818 | //Note: might be moved to std::ranges from C++20. | ||
6819 | return std::any_of(m_mapData.begin(), m_mapData.end(), [&](const auto &item) { return item.fileName == filename; }); | ||
6820 | } | ||
6821 | |||
6822 | /*! | ||
6823 | * Get a map by its filename | ||
6824 | * @param filename Filename (including extension) - (example: file.json) | ||
6825 | * @return pointer to WorldMapData or nullptr if not exists | ||
6826 | */ | ||
6827 | const WorldMapData * World::get(std::string_view filename) const | ||
6828 | { | ||
6829 | auto iter = std::find_if(m_mapData.begin(), m_mapData.end(), [&](const auto &item) { return item.fileName == filename; }); | ||
6830 | return (iter == m_mapData.end()) ? nullptr : iter.operator->(); | ||
6831 | } | ||
6832 | |||
6833 | /*! | ||
6834 | * Get all maps that have been loaded by loadMaps(). | ||
6835 | * NOTE: This is untested, and was a last second addition to Tileson 1.2.0, as I had forgot about the loadMaps() functionality (also untested) | ||
6836 | * If you find anything malfunctioning - please report. | ||
6837 | * @return All maps loaded by loadMaps() | ||
6838 | */ | ||
6839 | const std::vector<std::unique_ptr<tson::Map>> &World::getMaps() const | ||
6840 | { | ||
6841 | return m_maps; | ||
6842 | } | ||
6843 | |||
6844 | } | ||
6845 | |||
6846 | #endif //TILESON_WORLD_HPP | ||
6847 | /*** End of inlined file: World.hpp ***/ | ||
6848 | |||
6849 | |||
6850 | |||
6851 | /*** Start of inlined file: ProjectFolder.hpp ***/ | ||
6852 | // | ||
6853 | // Created by robin on 01.08.2020. | ||
6854 | // | ||
6855 | |||
6856 | #ifndef TILESON_PROJECTFOLDER_HPP | ||
6857 | #define TILESON_PROJECTFOLDER_HPP | ||
6858 | |||
6859 | namespace tson | ||
6860 | { | ||
6861 | class ProjectFolder | ||
6862 | { | ||
6863 | public: | ||
6864 | inline ProjectFolder(const fs::path &path); | ||
6865 | |||
6866 | inline const fs::path &getPath() const; | ||
6867 | inline bool hasWorldFile() const; | ||
6868 | inline const std::vector<ProjectFolder> &getSubFolders() const; | ||
6869 | inline const std::vector<fs::path> &getFiles() const; | ||
6870 | inline const World &getWorld() const; | ||
6871 | |||
6872 | private: | ||
6873 | inline void loadData(); | ||
6874 | fs::path m_path; | ||
6875 | bool m_hasWorldFile; | ||
6876 | tson::World m_world; | ||
6877 | std::vector<ProjectFolder> m_subFolders; | ||
6878 | std::vector<fs::path> m_files; | ||
6879 | |||
6880 | }; | ||
6881 | |||
6882 | ProjectFolder::ProjectFolder(const fs::path &path) : m_path {path} | ||
6883 | { | ||
6884 | loadData(); | ||
6885 | } | ||
6886 | |||
6887 | void ProjectFolder::loadData() | ||
6888 | { | ||
6889 | m_hasWorldFile = false; | ||
6890 | m_subFolders.clear(); | ||
6891 | m_files.clear(); | ||
6892 | //Search and see if there is a World file .world file | ||
6893 | fs::path worldPath; | ||
6894 | for (const auto & entry : fs::directory_iterator(m_path)) | ||
6895 | { | ||
6896 | if(fs::is_regular_file(entry.path())) | ||
6897 | { | ||
6898 | if(entry.path().extension() == ".world") | ||
6899 | { | ||
6900 | m_hasWorldFile = true; | ||
6901 | worldPath = entry.path(); | ||
6902 | } | ||
6903 | } | ||
6904 | } | ||
6905 | |||
6906 | if(m_hasWorldFile) | ||
6907 | m_world.parse(worldPath); | ||
6908 | |||
6909 | for (const auto & entry : fs::directory_iterator(m_path)) | ||
6910 | { | ||
6911 | if (fs::is_directory(entry.path())) | ||
6912 | m_subFolders.emplace_back(entry.path());//.loadData(); - loadData() is called in the constructor, so don't call again. | ||
6913 | else if (fs::is_regular_file(entry.path())) | ||
6914 | { | ||
6915 | if(m_hasWorldFile && m_world.contains(entry.path().filename().u8string())) | ||
6916 | m_files.emplace_back(entry.path()); | ||
6917 | else if(!m_hasWorldFile) | ||
6918 | m_files.emplace_back(entry.path()); | ||
6919 | } | ||
6920 | } | ||
6921 | |||
6922 | } | ||
6923 | |||
6924 | const fs::path &ProjectFolder::getPath() const | ||
6925 | { | ||
6926 | return m_path; | ||
6927 | } | ||
6928 | |||
6929 | bool ProjectFolder::hasWorldFile() const | ||
6930 | { | ||
6931 | return m_hasWorldFile; | ||
6932 | } | ||
6933 | |||
6934 | const std::vector<ProjectFolder> &ProjectFolder::getSubFolders() const | ||
6935 | { | ||
6936 | return m_subFolders; | ||
6937 | } | ||
6938 | |||
6939 | const std::vector<fs::path> &ProjectFolder::getFiles() const | ||
6940 | { | ||
6941 | return m_files; | ||
6942 | } | ||
6943 | |||
6944 | /*! | ||
6945 | * Only gives useful data if hasWorldFile() is true! | ||
6946 | * @return | ||
6947 | */ | ||
6948 | const World &ProjectFolder::getWorld() const | ||
6949 | { | ||
6950 | return m_world; | ||
6951 | } | ||
6952 | } | ||
6953 | |||
6954 | #endif //TILESON_PROJECTFOLDER_HPP | ||
6955 | /*** End of inlined file: ProjectFolder.hpp ***/ | ||
6956 | |||
6957 | |||
6958 | /*** Start of inlined file: ProjectData.hpp ***/ | ||
6959 | // | ||
6960 | // Created by robin on 01.08.2020. | ||
6961 | // | ||
6962 | |||
6963 | #ifndef TILESON_PROJECTDATA_HPP | ||
6964 | #define TILESON_PROJECTDATA_HPP | ||
6965 | |||
6966 | namespace tson | ||
6967 | { | ||
6968 | class ProjectData | ||
6969 | { | ||
6970 | public: | ||
6971 | ProjectData() = default; | ||
6972 | std::string automappingRulesFile; | ||
6973 | std::vector<std::string> commands; | ||
6974 | std::string extensionsPath; | ||
6975 | std::vector<std::string> folders; | ||
6976 | std::string objectTypesFile; | ||
6977 | |||
6978 | //Tileson specific | ||
6979 | fs::path basePath; | ||
6980 | std::vector<tson::ProjectFolder> folderPaths; | ||
6981 | }; | ||
6982 | } | ||
6983 | |||
6984 | #endif //TILESON_PROJECTDATA_HPP | ||
6985 | /*** End of inlined file: ProjectData.hpp ***/ | ||
6986 | |||
6987 | namespace tson | ||
6988 | { | ||
6989 | class Project | ||
6990 | { | ||
6991 | public: | ||
6992 | #ifdef JSON11_IS_DEFINED | ||
6993 | inline explicit Project(std::unique_ptr<tson::IJson> jsonParser = std::make_unique<tson::Json11>()) : m_json {std::move(jsonParser)} | ||
6994 | { | ||
6995 | |||
6996 | } | ||
6997 | inline explicit Project(const fs::path &path, std::unique_ptr<tson::IJson> jsonParser = std::make_unique<tson::Json11>()); | ||
6998 | #else | ||
6999 | inline explicit Project(std::unique_ptr<tson::IJson> jsonParser) : m_json {std::move(jsonParser)} | ||
7000 | { | ||
7001 | |||
7002 | } | ||
7003 | inline explicit Project(const fs::path &path, std::unique_ptr<tson::IJson> jsonParser); | ||
7004 | #endif | ||
7005 | inline bool parse(const fs::path &path); | ||
7006 | |||
7007 | [[nodiscard]] inline const ProjectData &getData() const; | ||
7008 | [[nodiscard]] inline const fs::path &getPath() const; | ||
7009 | [[nodiscard]] inline const std::vector<ProjectFolder> &getFolders() const; | ||
7010 | |||
7011 | private: | ||
7012 | inline void parseJson(IJson &json); | ||
7013 | fs::path m_path; | ||
7014 | std::vector<ProjectFolder> m_folders; | ||
7015 | ProjectData m_data; | ||
7016 | std::unique_ptr<IJson> m_json = nullptr; | ||
7017 | }; | ||
7018 | |||
7019 | Project::Project(const fs::path &path, std::unique_ptr<tson::IJson> jsonParser) : m_json {std::move(jsonParser)} | ||
7020 | { | ||
7021 | parse(path); | ||
7022 | } | ||
7023 | |||
7024 | bool Project::parse(const fs::path &path) | ||
7025 | { | ||
7026 | m_path = path; | ||
7027 | std::ifstream i(m_path.u8string()); | ||
7028 | |||
7029 | try | ||
7030 | { | ||
7031 | if(!m_json->parse(path)) | ||
7032 | return false; | ||
7033 | } | ||
7034 | catch(const std::exception &error) | ||
7035 | { | ||
7036 | std::string message = "Parse error: "; | ||
7037 | message += std::string(error.what()); | ||
7038 | message += std::string("\n"); | ||
7039 | return false; | ||
7040 | } | ||
7041 | parseJson(*m_json); | ||
7042 | return true; | ||
7043 | } | ||
7044 | |||
7045 | const ProjectData &Project::getData() const | ||
7046 | { | ||
7047 | return m_data; | ||
7048 | } | ||
7049 | |||
7050 | void Project::parseJson(IJson &json) | ||
7051 | { | ||
7052 | m_data.basePath = m_path.parent_path(); //The directory of the project file | ||
7053 | |||
7054 | if(json.count("automappingRulesFile") > 0) m_data.automappingRulesFile = json["automappingRulesFile"].get<std::string>(); | ||
7055 | if(json.count("commands") > 0) | ||
7056 | { | ||
7057 | m_data.commands.clear(); | ||
7058 | auto &commands = json.array("commands"); | ||
7059 | std::for_each(commands.begin(), commands.end(), [&](std::unique_ptr<IJson> &item) | ||
7060 | { | ||
7061 | m_data.commands.emplace_back(item->get<std::string>()); | ||
7062 | }); | ||
7063 | } | ||
7064 | if(json.count("extensionsPath") > 0) m_data.extensionsPath = json["extensionsPath"].get<std::string>(); | ||
7065 | if(json.count("folders") > 0) | ||
7066 | { | ||
7067 | m_data.folders.clear(); | ||
7068 | m_data.folderPaths.clear(); | ||
7069 | auto &folders = json.array("folders"); | ||
7070 | std::for_each(folders.begin(), folders.end(), [&](std::unique_ptr<IJson> &item) | ||
7071 | { | ||
7072 | std::string folder = item->get<std::string>(); | ||
7073 | m_data.folders.emplace_back(folder); | ||
7074 | m_data.folderPaths.emplace_back(m_data.basePath / folder); | ||
7075 | m_folders.emplace_back(m_data.basePath / folder); | ||
7076 | }); | ||
7077 | } | ||
7078 | if(json.count("objectTypesFile") > 0) m_data.objectTypesFile = json["objectTypesFile"].get<std::string>(); | ||
7079 | |||
7080 | } | ||
7081 | |||
7082 | const fs::path &Project::getPath() const | ||
7083 | { | ||
7084 | return m_path; | ||
7085 | } | ||
7086 | |||
7087 | const std::vector<ProjectFolder> &Project::getFolders() const | ||
7088 | { | ||
7089 | return m_folders; | ||
7090 | } | ||
7091 | |||
7092 | } | ||
7093 | |||
7094 | #endif //TILESON_PROJECT_HPP | ||
7095 | |||
7096 | /*** End of inlined file: Project.hpp ***/ | ||
7097 | |||
7098 | namespace tson | ||
7099 | { | ||
7100 | class Tileson | ||
7101 | { | ||
7102 | public: | ||
7103 | #ifdef JSON11_IS_DEFINED | ||
7104 | inline explicit Tileson(std::unique_ptr<tson::IJson> jsonParser = std::make_unique<tson::Json11>(), bool includeBase64Decoder = true); | ||
7105 | #else | ||
7106 | inline explicit Tileson(std::unique_ptr<tson::IJson> jsonParser, bool includeBase64Decoder = true); | ||
7107 | #endif | ||
7108 | |||
7109 | inline std::unique_ptr<tson::Map> parse(const fs::path &path, std::unique_ptr<IDecompressor<std::vector<uint8_t>, std::vector<uint8_t>>> decompressor = nullptr); | ||
7110 | inline std::unique_ptr<tson::Map> parse(const void * data, size_t size, std::unique_ptr<IDecompressor<std::vector<uint8_t>, std::vector<uint8_t>>> decompressor = nullptr); | ||
7111 | inline tson::DecompressorContainer *decompressors(); | ||
7112 | |||
7113 | private: | ||
7114 | inline std::unique_ptr<tson::Map> parseJson(); | ||
7115 | std::unique_ptr<tson::IJson> m_json; | ||
7116 | tson::DecompressorContainer m_decompressors; | ||
7117 | }; | ||
7118 | } | ||
7119 | |||
7120 | /*! | ||
7121 | * | ||
7122 | * @param includeBase64Decoder Includes the base64-decoder from "Base64Decompressor.hpp" if true. | ||
7123 | * Otherwise no other decompressors/decoders than whatever the user itself have added will be used. | ||
7124 | */ | ||
7125 | tson::Tileson::Tileson(std::unique_ptr<tson::IJson> jsonParser, bool includeBase64Decoder) : m_json {std::move(jsonParser)} | ||
7126 | { | ||
7127 | if(includeBase64Decoder) | ||
7128 | m_decompressors.add<Base64Decompressor>(); | ||
7129 | } | ||
7130 | |||
7131 | /*! | ||
7132 | * Parses Tiled json map data by file | ||
7133 | * @param path path to file | ||
7134 | * @return parsed data as Map | ||
7135 | */ | ||
7136 | std::unique_ptr<tson::Map> tson::Tileson::parse(const fs::path &path, std::unique_ptr<IDecompressor<std::vector<uint8_t>, std::vector<uint8_t>>> decompressor) | ||
7137 | { | ||
7138 | |||
7139 | bool result = false; | ||
7140 | |||
7141 | if(decompressor != nullptr) | ||
7142 | { | ||
7143 | std::vector<uint8_t> decompressed = decompressor->decompressFile(path); | ||
7144 | result = (decompressed.empty()) ? false : true; | ||
7145 | if(!result) | ||
7146 | return std::make_unique<tson::Map>(tson::ParseStatus::DecompressionError, "Error during decompression"); | ||
7147 | result = m_json->parse(&decompressed[0], decompressed.size()); | ||
7148 | if(result) | ||
7149 | return std::move(parseJson()); | ||
7150 | } | ||
7151 | else if(m_json->parse(path)) | ||
7152 | { | ||
7153 | return std::move(parseJson()); | ||
7154 | } | ||
7155 | |||
7156 | std::string msg = "File not found: "; | ||
7157 | msg += std::string(path.u8string()); | ||
7158 | return std::make_unique<tson::Map>(tson::ParseStatus::FileNotFound, msg); | ||
7159 | } | ||
7160 | |||
7161 | /*! | ||
7162 | * Parses Tiled json map data by memory | ||
7163 | * @param data The data to parse | ||
7164 | * @param size The size of the data to parse | ||
7165 | * @return parsed data as Map | ||
7166 | */ | ||
7167 | std::unique_ptr<tson::Map> tson::Tileson::parse(const void *data, size_t size, std::unique_ptr<IDecompressor<std::vector<uint8_t>, std::vector<uint8_t>>> decompressor) | ||
7168 | { | ||
7169 | bool result = false; | ||
7170 | |||
7171 | if(decompressor != nullptr) | ||
7172 | { | ||
7173 | std::vector<uint8_t> decompressed = decompressor->decompress(data, size); | ||
7174 | result = (decompressed.empty()) ? false : true; | ||
7175 | if(!result) | ||
7176 | return std::make_unique<tson::Map>(tson::ParseStatus::DecompressionError, "Error during decompression"); | ||
7177 | result = m_json->parse(&decompressed[0], decompressed.size()); | ||
7178 | } | ||
7179 | else | ||
7180 | result = m_json->parse(data, size); | ||
7181 | |||
7182 | if(!result) | ||
7183 | return std::make_unique<tson::Map>(tson::ParseStatus::ParseError, "Memory error"); | ||
7184 | |||
7185 | return std::move(parseJson()); | ||
7186 | } | ||
7187 | |||
7188 | /*! | ||
7189 | * Common parsing functionality for doing the json parsing | ||
7190 | * @param json Tiled json to parse | ||
7191 | * @return parsed data as Map | ||
7192 | */ | ||
7193 | std::unique_ptr<tson::Map> tson::Tileson::parseJson() | ||
7194 | { | ||
7195 | std::unique_ptr<tson::Map> map = std::make_unique<tson::Map>(); | ||
7196 | |||
7197 | if(map->parse(*m_json, &m_decompressors)) | ||
7198 | return std::move(map); | ||
7199 | |||
7200 | return std::make_unique<tson::Map> (tson::ParseStatus::MissingData, "Missing map data..."); | ||
7201 | } | ||
7202 | |||
7203 | /*! | ||
7204 | * Gets the decompressor container used when something is either encoded or compressed (regardless: IDecompressor is used as base). | ||
7205 | * These are used specifically for tile layers, and are connected by checking the name of the IDecompressor. If the name of a decompressor | ||
7206 | * matches with an encoding or a compression, its decompress() function will be used. | ||
7207 | * | ||
7208 | * @return The container including all decompressors. | ||
7209 | */ | ||
7210 | tson::DecompressorContainer *tson::Tileson::decompressors() | ||
7211 | { | ||
7212 | return &m_decompressors; | ||
7213 | } | ||
7214 | |||
7215 | #endif //TILESON_TILESON_PARSER_HPP | ||
7216 | |||
7217 | /*** End of inlined file: tileson_parser.hpp ***/ | ||
7218 | |||
7219 | |||
7220 | /*** Start of inlined file: tileson_forward.hpp ***/ | ||
7221 | // | ||
7222 | // Created by robin on 25.07.2020. | ||
7223 | // | ||
7224 | |||
7225 | #ifndef TILESON_TILESON_FORWARD_HPP | ||
7226 | #define TILESON_TILESON_FORWARD_HPP | ||
7227 | /*! | ||
7228 | * T I L E S O N F O R W A R D D E C L A R A T I O N S | ||
7229 | * ------------------------------------------------------- | ||
7230 | * | ||
7231 | * Due to cross-references we have forward declarations that cannot be resolved during the | ||
7232 | * implementation, thus the implementations must be done later when the class definition itself is known. | ||
7233 | * | ||
7234 | * All those forward declarations can be found below. | ||
7235 | */ | ||
7236 | |||
7237 | // T i l e . h p p | ||
7238 | // --------------------- | ||
7239 | |||
7240 | /*! | ||
7241 | * Really just a shortcut to retrieve the tile size from the map. | ||
7242 | * @return TileSize based on the map property for tile size. | ||
7243 | */ | ||
7244 | const tson::Vector2i tson::Tile::getTileSize() const | ||
7245 | { | ||
7246 | if(m_map != nullptr) | ||
7247 | return m_map->getTileSize(); | ||
7248 | else | ||
7249 | return {0,0}; | ||
7250 | } | ||
7251 | |||
7252 | bool tson::Tile::parseId(IJson &json) | ||
7253 | { | ||
7254 | if(json.count("id") > 0) | ||
7255 | { | ||
7256 | m_id = json["id"].get<uint32_t>() + 1; | ||
7257 | if (m_tileset != nullptr) | ||
7258 | m_gid = m_tileset->getFirstgid() + m_id - 1; | ||
7259 | else | ||
7260 | m_gid = m_id; | ||
7261 | manageFlipFlagsByIdThenRemoveFlags(m_gid); | ||
7262 | return true; | ||
7263 | } | ||
7264 | return false; | ||
7265 | } | ||
7266 | |||
7267 | /*! | ||
7268 | * Uses tson::Tileset and tson::Map data to calculate related values for tson::Tile. | ||
7269 | * Added in v1.2.0 | ||
7270 | */ | ||
7271 | void tson::Tile::performDataCalculations() | ||
7272 | { | ||
7273 | if(m_tileset == nullptr || m_map == nullptr) | ||
7274 | return; | ||
7275 | |||
7276 | int firstId = m_tileset->getFirstgid(); //First tile id of the tileset | ||
7277 | int columns = m_tileset->getColumns(); | ||
7278 | int rows = m_tileset->getTileCount() / columns; | ||
7279 | int lastId = (m_tileset->getFirstgid() + m_tileset->getTileCount()) - 1; | ||
7280 | |||
7281 | if (getGid() >= firstId && getGid() <= lastId) | ||
7282 | { | ||
7283 | int baseTilePosition = ((int)getGid() - firstId); | ||
7284 | |||
7285 | int tileModX = (baseTilePosition % columns); | ||
7286 | int currentRow = (baseTilePosition / columns); | ||
7287 | int offsetX = (tileModX != 0) ? ((tileModX) * m_map->getTileSize().x) : (0 * m_map->getTileSize().x); | ||
7288 | int offsetY = (currentRow < rows-1) ? (currentRow * m_map->getTileSize().y) : ((rows-1) * m_map->getTileSize().y); | ||
7289 | |||
7290 | m_drawingRect = { offsetX, offsetY, m_map->getTileSize().x, m_map->getTileSize().y }; | ||
7291 | } | ||
7292 | else | ||
7293 | m_drawingRect = {0, 0, 0, 0}; | ||
7294 | } | ||
7295 | |||
7296 | /*! | ||
7297 | * Get the position of the tile in pixels based on the tile data position from the current layer. | ||
7298 | * @return The position of the tile in Pixels | ||
7299 | */ | ||
7300 | const tson::Vector2f tson::Tile::getPosition(const std::tuple<int, int> &tileDataPos) | ||
7301 | { | ||
7302 | return {((float) std::get<0>(tileDataPos)) * m_drawingRect.width, ((float) std::get<1>(tileDataPos)) * m_drawingRect.height}; | ||
7303 | } | ||
7304 | |||
7305 | // T i l e O b j e c t . h p p | ||
7306 | // --------------------- | ||
7307 | |||
7308 | /*! | ||
7309 | * In cases where the empty constructor is called, this must be called manually | ||
7310 | * for this class to make sense | ||
7311 | * @param posInTileUnits | ||
7312 | * @param tile | ||
7313 | */ | ||
7314 | void tson::TileObject::initialize(const std::tuple<int, int> &posInTileUnits, tson::Tile *tile) | ||
7315 | { | ||
7316 | m_tile = tile; | ||
7317 | m_posInTileUnits = tile->getPositionInTileUnits(posInTileUnits); | ||
7318 | m_position = tile->getPosition(posInTileUnits); | ||
7319 | } | ||
7320 | |||
7321 | const tson::Rect &tson::TileObject::getDrawingRect() const | ||
7322 | { | ||
7323 | return m_tile->getDrawingRect(); | ||
7324 | } | ||
7325 | |||
7326 | // L a y e r . h p p | ||
7327 | // ------------------- | ||
7328 | |||
7329 | /*! | ||
7330 | * Decompresses data if there are matching decompressors | ||
7331 | */ | ||
7332 | void tson::Layer::decompressData() | ||
7333 | { | ||
7334 | |||
7335 | tson::DecompressorContainer *container = m_map->getDecompressors(); | ||
7336 | if(container->empty()) | ||
7337 | return; | ||
7338 | |||
7339 | if(m_encoding.empty() && m_compression.empty()) | ||
7340 | return; | ||
7341 | |||
7342 | std::string data = m_base64Data; | ||
7343 | bool hasBeenDecoded = false; | ||
7344 | if(!m_encoding.empty() && container->contains(m_encoding)) | ||
7345 | { | ||
7346 | data = container->get(m_encoding)->decompress(data); | ||
7347 | hasBeenDecoded = true; | ||
7348 | } | ||
7349 | |||
7350 | if(!m_compression.empty() && container->contains(m_compression)) | ||
7351 | { | ||
7352 | data = container->get(m_compression)->decompress(data); | ||
7353 | } | ||
7354 | |||
7355 | if(hasBeenDecoded) | ||
7356 | { | ||
7357 | std::vector<uint8_t> bytes = tson::Tools::Base64DecodedStringToBytes(data); | ||
7358 | m_data = tson::Tools::BytesToUnsignedInts(bytes); | ||
7359 | } | ||
7360 | } | ||
7361 | |||
7362 | // W o r l d . h p p | ||
7363 | // ------------------ | ||
7364 | |||
7365 | /*! | ||
7366 | * Loads the actual maps based on the world data. | ||
7367 | * @param parser A Tileson object used for parsing the maps of the world. | ||
7368 | * @return How many maps who were parsed. Remember to call getStatus() for the actual map to find out if everything went okay. | ||
7369 | */ | ||
7370 | |||
7371 | int tson::World::loadMaps(tson::Tileson *parser) | ||
7372 | { | ||
7373 | m_maps.clear(); | ||
7374 | std::for_each(m_mapData.begin(), m_mapData.end(), [&](const tson::WorldMapData &data) | ||
7375 | { | ||
7376 | if(fs::exists(data.path)) | ||
7377 | { | ||
7378 | std::unique_ptr<tson::Map> map = parser->parse(data.path); | ||
7379 | m_maps.push_back(std::move(map)); | ||
7380 | } | ||
7381 | }); | ||
7382 | |||
7383 | return m_maps.size(); | ||
7384 | } | ||
7385 | |||
7386 | #endif //TILESON_TILESON_FORWARD_HPP | ||
7387 | |||
7388 | /*** End of inlined file: tileson_forward.hpp ***/ | ||
7389 | |||
7390 | #endif //TILESON_TILESON_H | ||
7391 | |||