summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt3
-rw-r--r--res/map1.json53
-rw-r--r--src/game.h9
-rw-r--r--src/main.cpp2
-rw-r--r--src/renderer.cpp65
-rw-r--r--src/renderer.h6
-rw-r--r--tools/sprite_dumper/tileset_dumper.cpp44
-rw-r--r--vendor/tileson.hpp7391
8 files changed, 7548 insertions, 25 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bbc297..443fe86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -2,6 +2,8 @@ cmake_minimum_required (VERSION 3.1)
2project (tanetane) 2project (tanetane)
3 3
4set(CMAKE_BUILD_TYPE Debug) 4set(CMAKE_BUILD_TYPE Debug)
5set(CMAKE_C_COMPILER /usr/local/bin/gcc-10)
6set(CMAKE_CXX_COMPILER /usr/local/bin/g++-10)
5 7
6# Set directory to look for package helpers. 8# Set directory to look for package helpers.
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${tanetane_SOURCE_DIR}/cmake") 9set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${tanetane_SOURCE_DIR}/cmake")
@@ -19,6 +21,7 @@ include_directories(
19 ${SDL2_INCLUDE_DIR} 21 ${SDL2_INCLUDE_DIR}
20 ${SDL2_IMAGE_INCLUDE_DIRS} 22 ${SDL2_IMAGE_INCLUDE_DIRS}
21 src 23 src
24 vendor
22) 25)
23 26
24link_directories( 27link_directories(
diff --git a/res/map1.json b/res/map1.json new file mode 100644 index 0000000..b5b3d1a --- /dev/null +++ b/res/map1.json
@@ -0,0 +1,53 @@
1{ "compressionlevel":-1,
2 "height":32,
3 "infinite":false,
4 "layers":[
5 {
6 "data":[55, 55, 55, 55, 55, 55, 56, 57, 58, 58, 2147483704, 2147483703, 2147483707, 2147483708, 2147483709, 2147483703, 55, 55, 55, 55, 55, 55, 55, 62, 63, 2147483711, 2147483710, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 56, 58, 58, 2147483712, 55, 55, 55, 55, 55, 61, 60, 59, 55, 55, 65, 66, 58, 58, 58, 2147483714, 2147483715, 2147483716, 2147483717, 2147483718, 71, 2147483712, 55, 61, 60, 59, 55, 55, 56, 57, 2147483705, 2147483704, 55, 55, 55, 55, 55, 55, 61, 60, 59, 55, 55, 65, 66, 58, 58, 58, 72, 2147483719, 55, 55, 55, 70, 69, 68, 67, 73, 58, 74, 58, 58, 58, 58, 2147483706, 2147483723, 2147483724, 2147483725, 2147483706, 2147483705, 2147483719, 70, 69, 68, 67, 73, 66, 58, 58, 58, 2147483713, 55, 55, 65, 73, 2147483713, 70, 69, 68, 67, 73, 58, 58, 58, 58, 58, 58, 58, 2147483712, 65, 73, 77, 76, 75, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 77, 76, 75, 58, 58, 58, 58, 58, 58, 58, 2147483719, 2147483724, 58, 58, 58, 77, 76, 75, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 80, 81, 82, 83, 84, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 85, 86, 2147483735, 2147483735, 2147483735, 2147483735, 2147483734, 2147483733, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 88, 89, 90, 91, 92, 79, 79, 2147483732, 2147483731, 2147483730, 2147483729, 2147483728, 79, 79, 79, 79, 79, 79, 79, 85, 86, 2147483735, 2147483735, 2147483735, 2147483735, 2147483735, 2147483735, 2147483735, 2147483735, 93, 94, 2147483743, 2147483743, 2147483743, 2147483743, 2147483742, 2147483741, 2147483735, 87, 2147483734, 2147483733, 79, 79, 79, 2147483735, 2147483735, 2147483744, 2147483733, 97, 98, 99, 100, 101, 101, 79, 2147483740, 2147483739, 2147483738, 2147483737, 2147483736, 79, 79, 79, 85, 86, 87, 87, 93, 94, 2147483743, 2147483743, 2147483743, 102, 103, 104, 105, 106, 106, 107, 106, 108, 2147483757, 2147483756, 2147483755, 2147483758, 2147483743, 95, 2147483742, 2147483741, 2147483735, 2147483735, 2147483735, 2147483743, 2147483743, 2147483759, 2147483741, 2147483760, 2147483761, 2147483727, 2147483727, 79, 79, 79, 2147483749, 2147483748, 2147483747, 2147483746, 2147483745, 79, 85, 112, 93, 94, 95, 95, 95, 106, 106, 106, 106, 114, 114, 114, 114, 106, 106, 108, 109, 115, 116, 2147483763, 2147483757, 109, 109, 2147483756, 2147483755, 2147483758, 2147483743, 2147483743, 2147483743, 2147483765, 2147483765, 118, 2147483758, 2147483767, 2147483768, 2147483735, 2147483734, 2147483733, 2147483769, 2147483770, 123, 122, 121, 85, 86, 2147483735, 93, 94, 95, 107, 106, 106, 106, 106, 106, 106, 106, 106, 2147483772, 2147483772, 106, 108, 109, 115, 116, 116, 116, 116, 116, 116, 116, 2147483763, 2147483756, 106, 106, 106, 106, 2147483765, 118, 2147483754, 2147483754, 2147483754, 2147483773, 126, 2147483742, 2147483741, 2147483775, 2147483776, 129, 128, 127, 93, 130, 130, 95, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 131, 132, 109, 115, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 2147483763, 2147483756, 106, 106, 106, 133, 130, 118, 134, 106, 106, 106, 2147483755, 2147483758, 2147483783, 136, 2147483784, 2147483784, 135, 110, 107, 118, 106, 106, 106, 106, 106, 108, 2147483757, 109, 2147483757, 109, 2147483757, 109, 115, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 2147483763, 109, 137, 137, 138, 2147483756, 106, 106, 106, 2147483754, 108, 2147483756, 106, 106, 2147483784, 2147483784, 2147483784, 2147483784, 133, 130, 118, 134, 106, 106, 106, 108, 115, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 139, 140, 2147483756, 106, 108, 115, 2147483763, 137, 2147483756, 2147483784, 2147483784, 2147483784, 2147483784, 108, 2147483757, 109, 138, 141, 142, 109, 115, 116, 116, 116, 116, 116, 116, 116, 2147483764, 2147483764, 2147483764, 116, 116, 116, 116, 116, 116, 116, 116, 2147483791, 2147483792, 143, 116, 145, 138, 141, 142, 138, 116, 146, 139, 140, 147, 116, 116, 148, 2147483763, 2147483756, 106, 106, 108, 115, 116, 116, 116, 139, 138, 141, 142, 116, 2147483764, 2147483764, 2147483764, 2147483764, 2147483764, 2147483764, 2147483764, 2147483764, 2147483764, 2147483764, 2147483764, 146, 139, 140, 142, 2147483791, 2147483792, 2147483797, 150, 149, 151, 152, 2147483764, 116, 151, 116, 138, 141, 116, 116, 116, 116, 116, 116, 116, 2147483763, 2147483757, 109, 115, 116, 148, 146, 139, 140, 147, 2147483764, 2147483764, 2147483764, 2147483764, 102, 103, 104, 105, 2147483764, 2147483764, 2147483764, 2147483764, 146, 139, 140, 142, 2147483791, 151, 152, 150, 150, 151, 152, 150, 149, 143, 116, 151, 138, 138, 141, 116, 116, 138, 141, 141, 141, 116, 153, 154, 116, 116, 155, 116, 116, 2147483791, 143, 138, 141, 142, 102, 103, 104, 156, 157, 103, 104, 105, 146, 139, 140, 142, 148, 2147483791, 2147483792, 150, 158, 159, 160, 161, 158, 151, 152, 161, 143, 151, 116, 138, 141, 138, 141, 138, 141, 162, 162, 162, 143, 116, 153, 154, 163, 2147483791, 144, 2147483797, 149, 2147483792, 145, 138, 141, 142, 1073741988, 3221225637, 3221225638, 167, 143, 139, 140, 2147483764, 2147483791, 144, 2147483792, 2147483797, 2147483816, 151, 152, 169, 170, 151, 152, 150, 150, 151, 152, 151, 116, 116, 116, 138, 141, 2147483797, 158, 151, 152, 161, 149, 143, 116, 116, 2147483791, 2147483797, 150, 150, 158, 151, 152, 161, 158, 151, 152, 161, 3221225640, 1073741988, 149, 139, 140, 2147483792, 2147483797, 150, 150, 2147483816, 2147483814, 167, 167, 167, 167, 167, 167, 150, 150, 151, 151, 151, 116, 116, 2147483791, 2147483792, 2147483797, 151, 152, 150, 150, 150, 171, 172, 2147483792, 144, 2147483820, 2147483819, 150, 173, 174, 175, 158, 151, 152, 161, 150, 150, 176, 177, 178, 159, 160, 179, 180, 181, 2147483816, 2147483814, 102, 103, 104, 105, 102, 103, 104, 103, 152, 151, 152, 151, 116, 2147483791, 2147483797, 151, 152, 139, 150, 151, 152, 182, 150, 150, 150, 150, 150, 150, 150, 183, 184, 185, 150, 150, 150, 150, 150, 150, 150, 150, 186, 169, 170, 187, 150, 150, 2147483814, 167, 167, 188, 102, 103, 104, 105, 102, 103, 152, 150, 158, 151, 2147483792, 2147483797, 150, 150, 158, 151, 152, 161, 152, 189, 190, 150, 189, 190, 150, 150, 150, 191, 192, 193, 150, 150, 150, 189, 190, 150, 150, 150, 150, 1073741995, 1073741996, 194, 194, 151, 152, 167, 1073742019, 1073742019, 3221225638, 188, 167, 167, 167, 167, 158, 151, 152, 161, 150, 150, 158, 151, 152, 161, 158, 151, 152, 161, 189, 190, 150, 196, 1073741995, 1073741996, 194, 2147483842, 3221225644, 3221225643, 2147483816, 2147483845, 197, 168, 150, 2147483816, 2147483845, 150, 150, 150, 198, 3221225671, 1073742024, 3221225672, 151, 151, 152, 150, 3221225640, 1073742019, 1073741988, 1073742019, 158, 151, 152, 161, 201, 202, 150, 151, 152, 164, 195, 195, 203, 196, 150, 2147483816, 204, 195, 168, 150, 205, 198, 153, 154, 2147483846, 2147483853, 205, 194, 167, 166, 195, 2147483814, 1073741990, 151, 152, 103, 104, 3221225678, 207, 151, 152, 151, 152, 150, 189, 190, 158, 151, 152, 161, 150, 150, 2147483856, 209, 151, 167, 167, 103, 104, 167, 204, 195, 204, 2147483814, 167, 210, 211, 168, 198, 2147483802, 2147483801, 2147483860, 2147483860, 2147483846, 138, 141, 142, 167, 3221225638, 188, 167, 151, 152, 103, 104, 103, 104, 103, 104, 151, 152, 161, 150, 150, 150, 150, 150, 2147483816, 195, 195, 2147483861, 214, 150, 151, 152, 167, 167, 103, 104, 215, 157, 103, 104, 105, 167, 167, 2147483860, 2147483860, 148, 2147483860, 2147483860, 2147483860, 2147483860, 2147483860, 2147483860, 2147483860, 2147483848, 2147483854, 166, 167, 167, 103, 104, 103, 104, 151, 152, 161, 150, 2147483798, 2147483798, 2147483864, 2147483865, 2147483798, 2147483816, 2147483814, 167, 167, 218, 214, 150, 150, 158, 151, 152, 103, 104, 1073741988, 3221225637, 3221225638, 1073741991, 167, 167, 139, 140, 1073742024, 1073742023, 146, 139, 219, 220, 221, 222, 140, 147, 2147483847, 102, 103, 104, 105, 158, 151, 152, 103, 104, 138, 138, 2147483798, 2147483871, 2147483872, 2147483873, 2147483874, 3221225640, 3221225638, 151, 152, 151, 152, 150, 151, 152, 161, 150, 138, 141, 3221225622, 3221225622, 3221225640, 3221225638, 139, 140, 151, 152, 207, 1073742030, 1073742023, 2147483860, 227, 228, 229, 230, 163, 3221225671, 103, 167, 167, 102, 103, 104, 105, 146, 139, 140, 138, 104, 138, 104, 150, 150, 150, 150, 3221225640, 138, 151, 152, 2147483860, 151, 139, 140, 150, 3221225622, 3221225622, 3221225622, 103, 104, 3221225622, 3221225640, 151, 152, 139, 207, 103, 104, 1073742030, 3221225670, 2147483792, 144, 143, 3221225671, 1073742055, 3221225678, 103, 104, 103, 167, 167, 167, 138, 141, 1073742023, 116, 138, 141, 103, 104, 151, 152, 150, 150, 151, 152, 150, 150, 151, 150, 151, 152, 139, 140, 138, 141, 139, 140, 103, 104, 3221225622, 139, 151, 152, 139, 140, 103, 104, 168, 2147483816, 103, 104, 167, 167, 138, 141, 138, 141, 167, 116, 116, 116, 116, 116, 103, 104, 138, 141, 2147483853, 150, 151, 152, 150, 150, 151, 152, 150, 150, 150, 205, 138, 141, 116, 116, 138, 141, 139, 140, 138, 141, 2147483853, 150, 151, 141, 139, 139, 166, 2147483814, 103, 104, 103, 104, 138, 141, 138, 141, 138, 141, 138, 141, 103, 104, 138, 141, 116, 116, 2147483846, 232, 232, 2147483853, 151, 152, 150, 150, 150, 150, 205, 198, 116, 116, 116, 116, 116, 116, 138, 141, 116, 116, 2147483846, 194, 198, 116, 138, 141, 200, 231, 138, 141, 138, 141, 138, 141, 116, 116, 138, 141, 116, 116, 138, 141, 116, 116, 116, 116, 116, 116, 116, 2147483846, 2147483853, 150, 150, 150, 150],
7 "height":32,
8 "id":1,
9 "name":"Layer 1",
10 "opacity":1,
11 "type":"tilelayer",
12 "visible":true,
13 "width":48,
14 "x":0,
15 "y":0
16 },
17 {
18 "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 6, 7, 8, 9, 4, 5, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 10, 7, 11, 9, 4, 5, 2, 3, 6, 7, 8, 12, 6, 7, 8, 9, 4, 5, 2, 3, 6, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 1, 1, 13, 14, 15, 12, 6, 7, 15, 9, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 9, 6, 7, 8, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 10, 7, 8, 9, 4, 5, 16, 17, 6, 7, 11, 18, 19, 20, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 21, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 6, 7, 8, 12, 6, 7, 8, 9, 10, 7, 8, 12, 6, 23, 24, 17, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 8, 9, 4, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 14, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 9, 25, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 6, 7, 11, 26, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 17, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 8, 18, 27, 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 14, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 6, 23, 2, 29, 21, 22, 1, 1, 1, 1, 1, 1, 1, 1, 30, 31, 19, 20, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 8, 9, 25, 32, 8, 9, 4, 5, 1, 1, 1, 1, 1, 1, 1, 1, 24, 17, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 18, 19, 14, 6, 7, 11, 18, 19, 14, 11, 26, 1, 1, 1, 1, 1, 1, 1, 1, 13, 20, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 33, 18, 19, 14, 8, 12, 6, 7, 8, 12, 6, 23, 24, 17, 8, 12, 6, 23, 24, 17, 6, 34, 1, 1, 1, 1, 1, 1, 1, 1, 30, 31, 19, 20, 8, 12, 6, 7, 33, 18, 19, 20, 8, 12, 6, 7, 33, 18, 27, 28, 24, 17, 6, 7, 8, 12, 6, 7, 8, 9, 25, 32, 6, 7, 8, 9, 25, 32, 8, 9, 4, 5, 1, 1, 1, 1, 1, 1, 1, 1, 24, 17, 6, 7, 8, 12, 6, 23, 30, 31, 19, 20, 33, 18, 27, 28, 1, 1, 13, 20, 33, 18, 19, 14, 33, 18, 19, 14, 8, 12, 8, 12, 6, 7, 8, 12, 6, 7, 11, 26, 1, 1, 1, 1, 1, 1, 1, 1, 13, 20, 8, 12, 6, 7, 33, 35, 1, 29, 36, 37, 38, 39, 4, 5, 1, 1, 16, 17, 6, 23, 24, 17, 6, 23, 24, 17, 6, 7, 6, 7, 8, 12, 6, 7, 11, 18, 27, 28, 1, 1, 1, 1, 1, 1, 1, 1, 30, 31, 19, 20, 33, 18, 27, 28, 40, 41, 19, 20, 33, 18, 42, 35, 1, 1, 13, 20, 8, 9, 25, 32, 8, 9, 25, 32, 8, 12, 8, 12, 6, 7, 8, 12, 6, 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 30, 31, 27, 28, 1, 1, 30, 31, 43, 31, 27, 44, 27, 28, 1, 1, 30, 31, 19, 20, 33, 18, 19, 20, 8, 12, 6, 32, 6, 7, 8, 12, 6, 7, 8, 9, 4, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 30, 31, 27, 28, 24, 17, 6, 32, 33, 18, 8, 12, 6, 7, 11, 18, 19, 14, 11, 26, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 1, 1, 1, 1, 1, 29, 6, 32, 33, 18, 27, 28, 6, 7, 11, 18, 27, 28, 45, 31, 27, 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 29, 4, 5, 1, 1, 1, 1, 29, 4, 5, 1, 1, 13, 14, 15, 9, 4, 5, 1, 1, 40, 46, 33, 18, 27, 28, 1, 1, 8, 12, 6, 23, 1, 1, 1, 1, 1, 29, 21, 22, 1, 1, 1, 1, 1, 1, 1, 40, 46, 11, 26, 1, 1, 1, 40, 46, 8, 9, 4, 5, 16, 17, 6, 7, 11, 26, 1, 1, 30, 31, 27, 28, 1, 1, 1, 1, 6, 7, 8, 9, 4, 22, 1, 1, 40, 46, 47, 35, 1, 1, 1, 1, 1, 1, 29, 36, 37, 38, 39, 4, 22, 1, 16, 17, 6, 7, 8, 9, 10, 7, 11, 18, 27, 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 12, 6, 7, 8, 9, 4, 5, 45, 48, 49, 50, 2, 3, 4, 5, 1, 40, 46, 19, 20, 33, 18, 42, 35, 1, 13, 14, 8, 12, 6, 7, 8, 12, 6, 23, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 11, 18, 19, 14, 11, 26, 1, 1, 2, 3, 25, 7, 42, 26, 1, 30, 31, 43, 31, 27, 44, 27, 28, 1, 30, 31, 19, 14, 8, 12, 6, 7, 8, 9, 4, 5, 1, 1, 2147483699, 1, 2, 3, 6, 7, 8, 52, 8, 12, 6, 23, 24, 17, 6, 34, 1, 1, 13, 14, 8, 12, 6, 34, 1, 53, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 30, 31, 19, 14, 11, 18, 19, 14, 15, 9, 4, 5, 2147483702, 1, 13, 14, 8, 12, 6, 7, 6, 7, 8, 9, 25, 32, 8, 9, 4, 5, 16, 17, 6, 7, 8, 9, 4, 5, 1, 1, 1, 1, 1, 1, 13, 14, 8, 9, 4, 5, 16, 17, 6, 23, 24, 17, 6, 7, 15, 9, 4, 5, 16, 17, 6, 7, 8, 12, 8, 12, 6, 7, 8, 12, 6, 7, 8, 9, 10, 7, 8, 12, 6, 7, 8, 9, 4, 5, 2, 3, 4, 5, 16, 17, 6, 7, 8, 9, 10, 32, 8, 9, 25, 7, 15, 12, 6, 7, 15, 9, 25, 32, 8, 12, 6, 7, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 42, 26, 13, 14, 8, 9, 25, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 34, 16, 17, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 9, 25, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12, 6, 7, 8, 12],
19 "height":32,
20 "id":1,
21 "name":"Layer 0",
22 "opacity":1,
23 "type":"tilelayer",
24 "visible":true,
25 "width":48,
26 "x":0,
27 "y":0
28 }],
29 "nextlayerid":2,
30 "nextobjectid":1,
31 "orientation":"orthogonal",
32 "renderorder":"right-down",
33 "tiledversion":"1.4.3",
34 "tileheight":16,
35 "tilesets":[
36 {
37 "columns":10,
38 "firstgid":1,
39 "image":"..\/tools\/sprite_dumper\/build\/tiles.png",
40 "imageheight":384,
41 "imagewidth":160,
42 "margin":0,
43 "name":"fromRom",
44 "spacing":0,
45 "tilecount":240,
46 "tileheight":16,
47 "tilewidth":16
48 }],
49 "tilewidth":16,
50 "type":"map",
51 "version":1.4,
52 "width":48
53} \ No newline at end of file
diff --git a/src/game.h b/src/game.h index 274ef2e..e5976b1 100644 --- a/src/game.h +++ b/src/game.h
@@ -4,6 +4,7 @@
4#include <set> 4#include <set>
5#include <range/v3/all.hpp> 5#include <range/v3/all.hpp>
6#include <vector> 6#include <vector>
7#include <tileson.hpp>
7#include "sprite.h" 8#include "sprite.h"
8 9
9struct Input { 10struct Input {
@@ -54,10 +55,18 @@ public:
54 } 55 }
55 } 56 }
56 57
58 void loadMapFromFile(std::string_view filename) {
59 tson::Tileson t;
60 map_ = t.parse(fs::path(filename));
61 }
62
63 tson::Map* getMap() const { return map_.get(); }
64
57private: 65private:
58 66
59 std::vector<Sprite> sprites_; 67 std::vector<Sprite> sprites_;
60 std::set<std::tuple<int, int>> spritesByY_; 68 std::set<std::tuple<int, int>> spritesByY_;
69 std::unique_ptr<tson::Map> map_;
61}; 70};
62 71
63#endif /* end of include guard: GAME_H_E6F1396E */ 72#endif /* end of include guard: GAME_H_E6F1396E */
diff --git a/src/main.cpp b/src/main.cpp index ea8d8f4..df0bfff 100644 --- a/src/main.cpp +++ b/src/main.cpp
@@ -8,6 +8,8 @@ void loop(Renderer& renderer) {
8 Game game; 8 Game game;
9 Input keystate; 9 Input keystate;
10 10
11 game.loadMapFromFile("../res/map1.json");
12
11 int lucasSprite = game.addSprite(Sprite("../res/lucas_anim.txt", renderer)); 13 int lucasSprite = game.addSprite(Sprite("../res/lucas_anim.txt", renderer));
12 int kumaSprite = game.addSprite(Sprite("../res/kuma_anim.txt", renderer)); 14 int kumaSprite = game.addSprite(Sprite("../res/kuma_anim.txt", renderer));
13 int dusterSprite = game.addSprite(Sprite("../res/duster_anim.txt", renderer)); 15 int dusterSprite = game.addSprite(Sprite("../res/duster_anim.txt", renderer));
diff --git a/src/renderer.cpp b/src/renderer.cpp index 931e699..45b9045 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp
@@ -29,7 +29,56 @@ Renderer::Renderer() {
29 } 29 }
30} 30}
31 31
32texture_ptr Renderer::renderMapLayer(const tson::Layer& layer) {
33 texture_ptr canvas(
34 SDL_CreateTexture(
35 ren_.get(),
36 SDL_PIXELFORMAT_RGBA8888,
37 SDL_TEXTUREACCESS_TARGET,
38 layer.getMap()->getSize().x * layer.getMap()->getTileSize().x,
39 layer.getMap()->getSize().y * layer.getMap()->getTileSize().y));
40
41 SDL_SetTextureBlendMode(canvas.get(), SDL_BLENDMODE_BLEND);
42
43 SDL_SetRenderTarget(ren_.get(), canvas.get());
44 SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_BLEND);
45 SDL_SetRenderDrawColor(ren_.get(), 255, 255, 255, 0);
46 SDL_RenderClear(ren_.get());
47
48 for (auto& [pos, tileObject] : layer.getTileObjects()) {
49 int x = tileObject.getPosition().x;
50 int y = tileObject.getPosition().y;
51 tson::Rect tileDestRect = tileObject.getDrawingRect();
52 SDL_Rect srcRect { tileDestRect.x, tileDestRect.y, tileDestRect.width, tileDestRect.height };
53 SDL_Rect destRect {
54 x, y, tileObject.getTile()->getTileSize().x, tileObject.getTile()->getTileSize().y };
55
56 SDL_RendererFlip flip = SDL_FLIP_NONE;
57 if (tileObject.getTile()->hasFlipFlags(tson::TileFlipFlags::Horizontally | tson::TileFlipFlags::Vertically)) {
58 flip = static_cast<SDL_RendererFlip>(SDL_FLIP_HORIZONTAL | SDL_FLIP_VERTICAL);
59 } else if (tileObject.getTile()->hasFlipFlags(tson::TileFlipFlags::Horizontally)) {
60 flip = SDL_FLIP_HORIZONTAL;
61 } else if (tileObject.getTile()->hasFlipFlags(tson::TileFlipFlags::Vertically)) {
62 flip = SDL_FLIP_VERTICAL;
63 }
64 SDL_RenderCopyEx(ren_.get(), textures_[tilesetTexId_].get(), &srcRect, &destRect, 0, nullptr, flip);
65 }
66
67 return canvas;
68}
69
32void Renderer::render(Game& game) { 70void Renderer::render(Game& game) {
71 if (tilesetTexId_ == -1) {
72 tilesetTexId_ = loadImageFromFile(game.getMap()->getTileset("fromRom")->getImage().c_str());
73 }
74
75 if (!renLay1_) {
76 renLay1_ = renderMapLayer(*game.getMap()->getLayer("Layer 1"));
77 }
78 if (!renLay0_) {
79 renLay0_ = renderMapLayer(*game.getMap()->getLayer("Layer 0"));
80 }
81
33 texture_ptr canvas( 82 texture_ptr canvas(
34 SDL_CreateTexture( 83 SDL_CreateTexture(
35 ren_.get(), 84 ren_.get(),
@@ -38,16 +87,22 @@ void Renderer::render(Game& game) {
38 CANVAS_WIDTH, 87 CANVAS_WIDTH,
39 CANVAS_HEIGHT)); 88 CANVAS_HEIGHT));
40 89
41 if (!canvas) 90 if (!canvas) {
42 {
43 throw sdl_error(); 91 throw sdl_error();
44 } 92 }
45 93
94
95
46 SDL_SetRenderTarget(ren_.get(), canvas.get()); 96 SDL_SetRenderTarget(ren_.get(), canvas.get());
47 SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_NONE); 97 SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_NONE);
48 SDL_SetRenderDrawColor(ren_.get(), 255, 255, 255, 255); 98 SDL_SetRenderDrawColor(ren_.get(), 255, 255, 255, 255);
49 SDL_RenderClear(ren_.get()); 99 SDL_RenderClear(ren_.get());
50 100
101 {
102 SDL_Rect dest { -80, -80, game.getMap()->getSize().x * game.getMap()->getTileSize().x, game.getMap()->getSize().y * game.getMap()->getTileSize().y };
103 SDL_RenderCopy(ren_.get(), renLay1_.get(), nullptr, &dest);
104 }
105
51 for (const Sprite& sprite : game.getSpritesByY() | game.spriteView()) { 106 for (const Sprite& sprite : game.getSpritesByY() | game.spriteView()) {
52 const SpriteFrame& frame = sprite.getFrame(); 107 const SpriteFrame& frame = sprite.getFrame();
53 const SDL_Rect& src = frame.srcRect; 108 const SDL_Rect& src = frame.srcRect;
@@ -55,6 +110,11 @@ void Renderer::render(Game& game) {
55 SDL_RenderCopy(ren_.get(), textures_.at(sprite.getTextureId()).get(), &src, &dest); 110 SDL_RenderCopy(ren_.get(), textures_.at(sprite.getTextureId()).get(), &src, &dest);
56 } 111 }
57 112
113 {
114 SDL_Rect dest { -80, -80, game.getMap()->getSize().x * game.getMap()->getTileSize().x, game.getMap()->getSize().y * game.getMap()->getTileSize().y };
115 SDL_RenderCopy(ren_.get(), renLay0_.get(), nullptr, &dest);
116 }
117
58 SDL_SetRenderTarget(ren_.get(), nullptr); 118 SDL_SetRenderTarget(ren_.get(), nullptr);
59 SDL_RenderCopy(ren_.get(), canvas.get(), nullptr, nullptr); 119 SDL_RenderCopy(ren_.get(), canvas.get(), nullptr, nullptr);
60 SDL_RenderPresent(ren_.get()); 120 SDL_RenderPresent(ren_.get());
@@ -68,6 +128,7 @@ int Renderer::loadImageFromFile(std::string_view filename) {
68 } 128 }
69 129
70 texture_ptr tex = texture_ptr(SDL_CreateTextureFromSurface(ren_.get(), pfs.get())); 130 texture_ptr tex = texture_ptr(SDL_CreateTextureFromSurface(ren_.get(), pfs.get()));
131 //SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND);
71 132
72 int texId = textures_.size(); 133 int texId = textures_.size();
73 textures_.push_back(std::move(tex)); 134 textures_.push_back(std::move(tex));
diff --git a/src/renderer.h b/src/renderer.h index abedb62..9573d8c 100644 --- a/src/renderer.h +++ b/src/renderer.h
@@ -7,6 +7,7 @@
7#include <memory> 7#include <memory>
8#include <string_view> 8#include <string_view>
9#include <vector> 9#include <vector>
10#include <tileson.hpp>
10 11
11class Game; 12class Game;
12 13
@@ -121,12 +122,17 @@ public:
121 122
122private: 123private:
123 124
125 texture_ptr renderMapLayer(const tson::Layer& layer);
126
124 sdl_wrapper sdl_; 127 sdl_wrapper sdl_;
125 img_wrapper img_; 128 img_wrapper img_;
126 window_ptr win_; 129 window_ptr win_;
127 renderer_ptr ren_; 130 renderer_ptr ren_;
128 131
129 std::vector<texture_ptr> textures_; 132 std::vector<texture_ptr> textures_;
133 int tilesetTexId_ = -1;
134 texture_ptr renLay0_;
135 texture_ptr renLay1_;
130}; 136};
131 137
132#endif /* end of include guard: RENDERER_H_6A58EC30 */ 138#endif /* end of include guard: RENDERER_H_6A58EC30 */
diff --git a/tools/sprite_dumper/tileset_dumper.cpp b/tools/sprite_dumper/tileset_dumper.cpp index d8997a5..f09fbd9 100644 --- a/tools/sprite_dumper/tileset_dumper.cpp +++ b/tools/sprite_dumper/tileset_dumper.cpp
@@ -264,15 +264,32 @@ int main(int argc, char** argv) {
264 itemised.push_back(std::move(newLayer)); 264 itemised.push_back(std::move(newLayer));
265 } 265 }
266 266
267 constexpr int TILES_PER_ROW = 10;
268 int sheetWidth;
269 int sheetHeight;
267 270
271 if (metatiles.size() < TILES_PER_ROW) {
272 sheetWidth = metatiles.size() * 16;
273 sheetHeight = 16;
274 } else {
275 sheetWidth = TILES_PER_ROW * 16;
276 sheetHeight = (metatiles.size() / TILES_PER_ROW + 1) * 16;
277 }
268 278
279 // Generate map datafile.
269 std::ofstream mapfile("out.tmx"); 280 std::ofstream mapfile("out.tmx");
270 mapfile << R"(<map version="1.0" orientation="orthogonal" renderorder="right-down" width=")"; 281 mapfile << R"(<map version="1.0" orientation="orthogonal" renderorder="right-down" width=")";
271 mapfile << width; 282 mapfile << width;
272 mapfile << R"(" height=")"; 283 mapfile << R"(" height=")";
273 mapfile << height; 284 mapfile << height;
274 mapfile << R"(" tilewidth="16" tileheight="16">)" << std::endl; 285 mapfile << R"(" tilewidth="16" tileheight="16">)" << std::endl;
275 mapfile << R"( <tileset firstgid="0" source="out.tsx" />)" << std::endl; 286 mapfile << R"( <tileset firstgid="1" name="fromRom" tilewidth="16" tileheight="16" tilecount=")";
287 mapfile << metatiles.size();
288 mapfile << R"(" columns=")";
289 mapfile << TILES_PER_ROW;
290 mapfile << R"(">)" << std::endl;
291 mapfile << R"( <image source="tiles.png" />)" << std::endl;
292 mapfile << R"( </tileset>)" << std::endl;
276 293
277 for (int layer=itemised.size()-1; layer>=0; layer--) { 294 for (int layer=itemised.size()-1; layer>=0; layer--) {
278 mapfile << R"( <layer id=")"; 295 mapfile << R"( <layer id=")";
@@ -294,7 +311,7 @@ int main(int argc, char** argv) {
294 mapfile << ","; 311 mapfile << ",";
295 } 312 }
296 313
297 unsigned int outChar = tu.id; 314 unsigned int outChar = tu.id + 1;
298 if (tu.tflipx) outChar |= 0x80000000; 315 if (tu.tflipx) outChar |= 0x80000000;
299 if (tu.tflipy) outChar |= 0x40000000; 316 if (tu.tflipy) outChar |= 0x40000000;
300 mapfile << outChar; 317 mapfile << outChar;
@@ -306,6 +323,7 @@ int main(int argc, char** argv) {
306 323
307 mapfile << R"(</map>)" << std::endl; 324 mapfile << R"(</map>)" << std::endl;
308 325
326 // Render map to image.
309 for (int layer=itemised.size()-1; layer>=0; layer--) { 327 for (int layer=itemised.size()-1; layer>=0; layer--) {
310 for (int mapy = 0; mapy < height; mapy++) { 328 for (int mapy = 0; mapy < height; mapy++) {
311 for (int mapx = 0; mapx < width; mapx++) { 329 for (int mapx = 0; mapx < width; mapx++) {
@@ -319,27 +337,7 @@ int main(int argc, char** argv) {
319 image.magick("png"); 337 image.magick("png");
320 image.write("out.png"); 338 image.write("out.png");
321 339
322 constexpr int TILES_PER_ROW = 10; 340 // Render tileset image.
323 int sheetWidth;
324 int sheetHeight;
325
326 if (metatiles.size() < TILES_PER_ROW) {
327 sheetWidth = metatiles.size() * 16;
328 sheetHeight = 16;
329 } else {
330 sheetWidth = TILES_PER_ROW * 16;
331 sheetHeight = (metatiles.size() / TILES_PER_ROW + 1) * 16;
332 }
333
334 std::ofstream tilesetfile("out.tsx");
335 tilesetfile << R"(<tileset name="fromRom" tilewidth="16" tileheight="16" tilecount=")";
336 tilesetfile << metatiles.size();
337 tilesetfile << R"(" columns=")";
338 tilesetfile << TILES_PER_ROW;
339 tilesetfile << R"(">)" << std::endl;
340 tilesetfile << R"( <image source="tiles.png" />)" << std::endl;
341 tilesetfile << R"(</tileset>)" << std::endl;
342
343 Magick::Image tilesetImage(Magick::Geometry(sheetWidth, sheetHeight), "transparent"); 341 Magick::Image tilesetImage(Magick::Geometry(sheetWidth, sheetHeight), "transparent");
344 for (int i=0; i<metatiles.size(); i++) { 342 for (int i=0; i<metatiles.size(); i++) {
345 Magick::Image tileRender = renderTile(metatiles.get(i), false, false, palettes, mapTiles, tilesets); 343 Magick::Image tileRender = renderTile(metatiles.get(i), false, false, palettes, mapTiles, tilesets);
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
81namespace 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
252namespace 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>
1076namespace 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
1189namespace 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
1237namespace 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
1351namespace 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>
1428namespace 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
1543namespace 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
1557namespace 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
1598namespace 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
1761namespace 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
1822namespace 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
1940namespace 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
2198namespace 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
2516namespace 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
2856namespace 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 */
2884tson::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 */
2894bool 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 */
2922const 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 */
2931const 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 */
2940const 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 */
2949const 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
3011namespace 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
3148namespace 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
3246namespace 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
3306tson::Property::Property() : m_name {"unnamed"}
3307{
3308
3309}
3310
3311tson::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
3318tson::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
3323void 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 */
3334void tson::Property::setStrValue(const std::string &value)
3335{
3336 m_value = value;
3337}
3338
3339const std::any &tson::Property::getValue() const
3340{
3341 return m_value;
3342}
3343
3344void tson::Property::setName(const std::string &name)
3345{
3346 m_name = name;
3347}
3348
3349const 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
3361const 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 */
3374std::string tson::Property::getValueTypeInfo()
3375{
3376 return m_value.type().name();
3377}
3378
3379tson::Type tson::Property::getType() const
3380{
3381 return m_type;
3382}
3383
3384void 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
3402void 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
3444namespace 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
3477template<typename T>
3478T 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
3484tson::PropertyCollection::PropertyCollection(std::string id) : m_id {std::move(id)}
3485{
3486
3487}
3488
3489tson::Property *tson::PropertyCollection::add(const tson::Property &property)
3490{
3491 m_properties[property.getName()] = property;
3492 return &m_properties[property.getName()];
3493}
3494
3495tson::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
3503tson::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
3509void 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 */
3520void 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
3526void tson::PropertyCollection::setId(const std::string &id)
3527{
3528 m_id = id;
3529}
3530
3531bool tson::PropertyCollection::hasProperty(const std::string &name)
3532{
3533 return m_properties.count(name) > 0;
3534}
3535
3536tson::Property *tson::PropertyCollection::getProperty(const std::string &name)
3537{
3538 return (m_properties.count(name) > 0) ? &m_properties[name] : nullptr;
3539}
3540
3541std::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 */
3550std::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
3559const std::string &tson::PropertyCollection::getId() const
3560{
3561 return m_id;
3562}
3563
3564size_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
3584namespace 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
3607namespace 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 */
3696tson::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 */
3707bool 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 */
3787void 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
3813tson::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 */
3822bool 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 */
3831uint32_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 */
3840const 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 */
3849int tson::Object::getId() const
3850{
3851 return m_id;
3852}
3853
3854/*!
3855 * 'name': String assigned to name field in editor
3856 * @return
3857 */
3858const 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 */
3867bool tson::Object::isPoint() const
3868{
3869 return m_point;
3870}
3871
3872/*!
3873 * 'rotation': Angle in degrees clockwise
3874 * @return
3875 */
3876float 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 */
3885const 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 */
3894const 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 */
3903bool tson::Object::isVisible() const
3904{
3905 return m_visible;
3906}
3907
3908/*!
3909 * 'x' and 'y': coordinate in pixels
3910 * @return
3911 */
3912const 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 */
3922const 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 */
3932const 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 */
3941tson::PropertyCollection &tson::Object::getProperties()
3942{
3943 return m_properties;
3944}
3945
3946/*!
3947 * 'type': String assigned to type field in editor
3948 * @return
3949 */
3950const 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 */
3960tson::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 */
3971tson::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 */
3984bool 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
4011namespace 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
4060namespace 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
4129namespace 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
4151namespace 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 */
4274tson::Layer::Layer(IJson &json, tson::Map *map)
4275{
4276 parse(json, map);
4277}
4278
4279void 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 */
4292bool 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 */
4362std::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 */
4379std::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 */
4396tson::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 */
4410tson::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 */
4423void 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 */
4436const 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 */
4445const 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 */
4454const 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 */
4463const 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 */
4472const 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 */
4481int tson::Layer::getId() const
4482{
4483 return m_id;
4484}
4485
4486/*!
4487 * 'image': Image used by this layer. imagelayer only.
4488 * @return
4489 */
4490const std::string &tson::Layer::getImage() const
4491{
4492 return m_image;
4493}
4494
4495/*!
4496 * 'name': Name assigned to this layer
4497 * @return
4498 */
4499const 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 */
4508const tson::Vector2f &tson::Layer::getOffset() const
4509{
4510 return m_offset;
4511}
4512
4513/*!
4514 * 'opacity': Value between 0 and 1
4515 * @return
4516 */
4517float 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 */
4527const 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 */
4536const 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 */
4545const 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 */
4554bool 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 */
4563int 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 */
4572int tson::Layer::getY() const
4573{
4574 return m_y;
4575}
4576
4577/*!
4578 * 'chunks': Array of chunks (optional). tilelayer only.
4579 * @return
4580 */
4581std::vector<tson::Chunk> &tson::Layer::getChunks()
4582{
4583 return m_chunks;
4584}
4585
4586/*!
4587 * 'layers': Array of layers. group on
4588 * @return
4589 */
4590std::vector<tson::Layer> &tson::Layer::getLayers()
4591{
4592 return m_layers;
4593}
4594
4595/*!
4596 * 'objects': Array of objects. objectgroup only.
4597 * @return
4598 */
4599std::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 */
4608tson::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 */
4618tson::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 */
4629tson::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 */
4638void 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 */
4653const 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 */
4670tson::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 */
4679tson::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 */
4691void 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
4720const std::map<std::tuple<int, int>, tson::TileObject> &tson::Layer::getTileObjects() const
4721{
4722 return m_tileObjects;
4723}
4724
4725tson::TileObject *tson::Layer::getTileObject(int x, int y)
4726{
4727 return (m_tileObjects.count({x, y}) > 0) ? &m_tileObjects[{x,y}] : nullptr;
4728}
4729
4730const std::set<uint32_t> &tson::Layer::getUniqueFlaggedTiles() const
4731{
4732 return m_uniqueFlaggedTiles;
4733}
4734
4735void 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 */
4752const 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
4793namespace 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
4815tson::WangColor::WangColor(IJson &json)
4816{
4817 parse(json);
4818}
4819
4820bool 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 */
4836const tson::Colori &tson::WangColor::getColor() const
4837{
4838 return m_color;
4839}
4840
4841/*!
4842 * 'name': Name of the Wang color
4843 * @return
4844 */
4845const std::string &tson::WangColor::getName() const
4846{
4847 return m_name;
4848}
4849
4850/*!
4851 * 'probability': Probability used when randomizing
4852 * @return
4853 */
4854float 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 */
4863int 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
4884namespace 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
4909tson::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 */
4919bool 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 */
4941bool tson::WangTile::hasDFlip() const
4942{
4943 return m_dflip;
4944}
4945
4946/*!
4947 * 'hflip': Tile is flipped horizontally
4948 * @return
4949 */
4950bool tson::WangTile::hasHFlip() const
4951{
4952 return m_hflip;
4953}
4954
4955/*!
4956 * 'tileid': Local ID of tile
4957 * @return
4958 */
4959int tson::WangTile::getTileid() const
4960{
4961 return m_tileid;
4962}
4963
4964/*!
4965 * 'vflip': Tile is flipped vertically
4966 * @return
4967 */
4968bool tson::WangTile::hasVFlip() const
4969{
4970 return m_vflip;
4971}
4972
4973/*!
4974 * 'wangid': Array of Wang color indexes (uchar[8])
4975 * @return
4976 */
4977const 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
4986namespace 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
5031tson::WangSet::WangSet(IJson &json)
5032{
5033 parse(json);
5034}
5035
5036bool 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 */
5072const 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 */
5081int tson::WangSet::getTile() const
5082{
5083 return m_tile;
5084}
5085
5086/*!
5087 * 'wangtiles': Array of Wang tiles
5088 * @return
5089 */
5090const 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 */
5099const 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 */
5108const 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 */
5117tson::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 */
5127tson::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
5161namespace 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 */
5186tson::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 */
5195tson::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 */
5205bool 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 */
5219int 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 */
5228int 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
5237namespace 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
5319tson::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 */
5328tson::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 */
5340tson::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 */
5350void 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 */
5361bool 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 */
5403uint32_t tson::Tile::getId() const
5404{
5405 return m_id;
5406}
5407
5408/*!
5409 * 'image': Image representing this tile (optional)
5410 * @return
5411 */
5412
5413const fs::path &tson::Tile::getImage() const { return m_image; }
5414
5415/*!
5416 * x = 'imagewidth' and y = 'imageheight': in pixels
5417 * @return
5418 */
5419const 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 */
5428const std::string &tson::Tile::getType() const
5429{
5430 return m_type;
5431}
5432
5433/*!
5434 * 'animation': Array of Frames
5435 * @return
5436 */
5437const 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 */
5446const 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 */
5455tson::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 */
5464const 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 */
5474tson::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 */
5486tson::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 */
5495tson::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 */
5504const 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 */
5519const tson::Vector2i tson::Tile::getPositionInTileUnits(const std::tuple<int, int> &tileDataPos)
5520{
5521 return {std::get<0>(tileDataPos), std::get<1>(tileDataPos)};
5522}
5523
5524void 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
5533tson::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 */
5546bool tson::Tile::hasFlipFlags(tson::TileFlipFlags flags)
5547{
5548 return ((m_flipFlags & flags) == flags) ? true : false;
5549}
5550
5551uint32_t tson::Tile::getGid() const
5552{
5553 return m_gid;
5554}
5555
5556void 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
5576namespace 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
5614tson::Terrain::Terrain(std::string name, int tile) : m_name {std::move(name)}, m_tile {tile}
5615{
5616
5617}
5618
5619tson::Terrain::Terrain(IJson &json)
5620{
5621 parse(json);
5622}
5623
5624bool 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 */
5644const 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 */
5653int 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 */
5662tson::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 */
5672tson::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
5695namespace 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 */
5718tson::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 */
5728bool 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 */
5744const 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 */
5753const 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
5764namespace 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
5853tson::Tileset::Tileset(IJson &json, tson::Map *map)
5854{
5855 parse(json, map);
5856}
5857
5858bool 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 */
5921int 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 */
5930int 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
5940const fs::path &tson::Tileset::getImagePath() const { return m_image; }
5941
5942/*!
5943 * x = 'imagewidth' and y = 'imageheight': in pixels
5944 * @return
5945 */
5946const 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 */
5955int tson::Tileset::getMargin() const
5956{
5957 return m_margin;
5958}
5959
5960/*!
5961 * 'name': Name given to this tileset
5962 * @return
5963 */
5964const 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 */
5973int tson::Tileset::getSpacing() const
5974{
5975 return m_spacing;
5976}
5977
5978/*!
5979 * 'tilecount': The number of tiles in this tileset
5980 * @return
5981 */
5982int 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 */
5991const 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 */
6000const 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 */
6009const 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
6019const fs::path &tson::Tileset::getImage() const { return m_image; }
6020
6021/*!
6022 * 'tiles': Array of Tiles (optional)
6023 * @return
6024 */
6025std::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 */
6034const 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 */
6043tson::PropertyCollection &tson::Tileset::getProperties()
6044{
6045 return m_properties;
6046}
6047
6048/*!
6049 * 'terrains': Array of Terrains (optional)
6050 * @return
6051 */
6052const 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 */
6061const 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 */
6071const 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 */
6082tson::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 */
6096tson::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 */
6110tson::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 */
6121void 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 */
6140tson::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 */
6150tson::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
6166tson::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
6174namespace 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 */
6272tson::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 */
6282tson::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 */
6292bool 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 */
6344void 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 */
6368void 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 */
6400const 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 */
6409const 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 */
6418int tson::Map::getHexsideLength() const
6419{
6420 return m_hexsideLength;
6421}
6422
6423/*!
6424 * 'infinite': Whether the map has infinite dimensions
6425 * @return
6426 */
6427bool tson::Map::isInfinite() const
6428{
6429 return m_isInfinite;
6430}
6431
6432/*!
6433 * 'nextlayerid': Auto-increments for each layer
6434 * @return
6435 */
6436int tson::Map::getNextLayerId() const
6437{
6438 return m_nextLayerId;
6439}
6440
6441/*!
6442 * 'nextobjectid': Auto-increments for each placed object
6443 * @return
6444 */
6445int tson::Map::getNextObjectId() const
6446{
6447 return m_nextObjectId;
6448}
6449
6450/*!
6451 * 'orientation': orthogonal, isometric, staggered or hexagonal
6452 * @return
6453 */
6454const std::string &tson::Map::getOrientation() const
6455{
6456 return m_orientation;
6457}
6458
6459/*!
6460 * 'renderorder': Rendering direction (orthogonal maps only)
6461 * @return
6462 */
6463const 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 */
6472const 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 */
6481const 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 */
6490const std::string &tson::Map::getTiledVersion() const
6491{
6492 return m_tiledVersion;
6493}
6494
6495/*!
6496 * 'tilewidth': and 'tileheight' of a map
6497 * @return
6498 */
6499const tson::Vector2<int> &tson::Map::getTileSize() const
6500{
6501 return m_tileSize;
6502}
6503
6504/*!
6505 * 'type': map (since 1.0)
6506 * @return
6507 */
6508const std::string &tson::Map::getType() const
6509{
6510 return m_type;
6511}
6512
6513/*!
6514 * 'version': The JSON format version
6515 * @return
6516 */
6517int tson::Map::getVersion() const
6518{
6519 return m_version;
6520}
6521
6522/*!
6523 * 'layers': Array of layers. group on
6524 * @return
6525 */
6526std::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 */
6535tson::PropertyCollection &tson::Map::getProperties()
6536{
6537 return m_properties;
6538}
6539
6540/*!
6541 * 'tilesets': Array of Tilesets
6542 * @return
6543 */
6544std::vector<tson::Tileset> &tson::Map::getTilesets()
6545{
6546 return m_tilesets;
6547}
6548
6549tson::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 */
6564tson::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 */
6579tson::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 */
6599tson::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
6606tson::ParseStatus tson::Map::getStatus() const
6607{
6608 return m_status;
6609}
6610
6611const 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 */
6620const std::map<uint32_t, tson::Tile *> &tson::Map::getTileMap() const
6621{
6622 return m_tileMap;
6623}
6624
6625tson::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 */
6635int 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
6674namespace 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>
6713namespace 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
6859namespace 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
6966namespace 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
6987namespace 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
7098namespace 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 */
7125tson::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 */
7136std::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 */
7167std::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 */
7193std::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 */
7210tson::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 */
7244const 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
7252bool 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 */
7271void 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 */
7300const 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 */
7314void 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
7321const 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 */
7332void 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
7371int 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