├── .editorconfig
├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── example
├── CMakeLists.txt
├── raylib-tmx-example.c
├── raylib-tmx-example.png
└── resources
│ ├── desert.tmx
│ └── tmw_desert_spacing.png
├── include
├── CMakeLists.txt
└── raylib-tmx.h
├── src
├── CMakeLists.txt
└── raylib-tmx.c
└── test
├── CMakeLists.txt
├── raylib-tmx-test.c
└── resources
├── desert.tmx
└── tmw_desert_spacing.png
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | charset = utf-8
6 | end_of_line = lf
7 | indent_size = 4
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | .vscode
3 | *.tiled-session
4 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.11)
2 | project(raylib-tmx
3 | VERSION 0.0.1
4 | DESCRIPTION "raylib-tmx"
5 | HOMEPAGE_URL "https://github.com/robloach/raylib-tmx"
6 | LANGUAGES C
7 | )
8 |
9 | # Include Directory
10 | add_subdirectory(include)
11 | add_subdirectory(src)
12 |
13 | # Examples
14 | option(RAYLIB_TMX_BUILD_EXAMPLE "Build Example" ON)
15 | if(RAYLIB_TMX_BUILD_EXAMPLE)
16 | add_subdirectory(example)
17 | endif()
18 |
19 | # Testing
20 | include(CTest)
21 | enable_testing()
22 | if(BUILD_TESTING AND RAYLIB_TMX_BUILD_EXAMPLE)
23 | set(CTEST_CUSTOM_TESTS_IGNORE
24 | pkg-config--static
25 | )
26 | add_subdirectory(test)
27 | endif()
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2021 Rob Loach (@RobLoach)
2 |
3 | This software is provided "as-is", without any express or implied warranty. In no event
4 | will the authors be held liable for any damages arising from the use of this software.
5 |
6 | Permission is granted to anyone to use this software for any purpose, including commercial
7 | applications, and to alter it and redistribute it freely, subject to the following restrictions:
8 |
9 | 1. The origin of this software must not be misrepresented; you must not claim that you
10 | wrote the original software. If you use this software in a product, an acknowledgment
11 | in the product documentation would be appreciated but is not required.
12 |
13 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented
14 | as being the original software.
15 |
16 | 3. This notice may not be removed or altered from any source distribution.
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # raylib-tmx
2 |
3 | Load [Tiled](https://www.mapeditor.org) `.tmx` files for tile maps in [raylib](https://www.raylib.com), with [TMX C Loader](https://github.com/baylej/tmx).
4 |
5 | 
6 |
7 | ## Usage
8 |
9 | This is a header-only library. To use it, define `RAYLIB_TMX_IMPLEMENTATION` in one *.c* source file before including *[raylib-tmx.h](include/raylib-tmx.h)*. You will also have to link its dependencies:
10 |
11 | - [raylib](https://www.raylib.com/)
12 | - [tmx](https://github.com/baylej/tmx) - With [tmx_load_buffer_path()](https://github.com/baylej/tmx/pull/58)
13 | - [libxml2](http://xmlsoft.org)
14 | - [zlib](http://zlib.net/) (optional)
15 |
16 | If you're using CMake, *libxml2* and *zlib* come packed in.
17 |
18 | ### Example
19 |
20 | ``` c
21 | #include "raylib.h"
22 |
23 | #define RAYLIB_TMX_IMPLEMENTATION
24 | #include "raylib-tmx.h"
25 |
26 | int main() {
27 | InitWindow(800, 450, "[raylib-tmx] example");
28 |
29 | tmx_map* map = LoadTMX("desert.tmx");
30 |
31 | while(!WindowShouldClose()) {
32 |
33 | BeginDrawing();
34 | {
35 | ClearBackground(RAYWHITE);
36 | DrawTMX(map, 0, 0, WHITE);
37 | }
38 | EndDrawing();
39 | }
40 |
41 | UnloadTMX(map);
42 |
43 | CloseWindow();
44 | return 0;
45 | }
46 | ```
47 |
48 | See the [example directory](example) for a demonstration of how to use *raylib-tmx*. Refer to the [libTMX documentation](http://libtmx.rtfd.io/) to see how to use the `tmx_map*` map object beyond rendering.
49 |
50 | ### API
51 |
52 | ``` c
53 | tmx_map* LoadTMX(const char* fileName);
54 | void UnloadTMX(tmx_map* map);
55 | Color ColorFromTMX(uint32_t color);
56 | void DrawTMX(tmx_map *map, int posX, int posY, Color tint);
57 | void DrawTMXLayer(tmx_map *map, tmx_layer *layers, int posX, int posY, Color tint);
58 | void DrawTMXTile(tmx_tile* tile, int posX, int posY, Color tint);
59 | ```
60 |
61 | ## Development
62 |
63 | To build the example locally, and run tests, use [cmake](https://cmake.org/).
64 |
65 | ``` bash
66 | git submodule update --init
67 | mkdir build
68 | cd build
69 | cmake ..
70 | make
71 | cd examples
72 | ./raylib-tmx-example
73 | ```
74 |
75 | ## Alternatives
76 |
77 | This is not the only attempt to get Tiled working in raylib...
78 |
79 | - [raylib-tileson](https://github.com/robloach/raylib-tileson)
80 | - [raylib-tiled](https://github.com/RobLoach/raylib-tiled)
81 |
82 | ## Credits
83 |
84 | This uses the [TMX C Loader](https://github.com/baylej/tmx), which is licensed under the [BSD 2-Clause "Simplified" License](https://github.com/baylej/tmx/blob/master/COPYING). Thank you to [Bayle Jonathan](https://github.com/baylej) for putting it together, and the [tmx example](https://github.com/baylej/tmx/blob/master/examples/raylib/raylib.c) this was inspired from.
85 |
86 | ## License
87 |
88 | *raylib-tmx* is licensed under an unmodified zlib/libpng license, which is an OSI-certified, BSD-like license that allows static linking with closed source software. Check [LICENSE](LICENSE) for further details.
89 |
--------------------------------------------------------------------------------
/example/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # raylib-tmx-example
2 | add_executable(raylib-tmx-example raylib-tmx-example.c)
3 | target_link_libraries(raylib-tmx-example PUBLIC
4 | raylib
5 | raylib-tmx
6 | )
7 |
8 | # Copy the resources
9 | file(GLOB resources resources/*)
10 | set(test_resources)
11 | list(APPEND test_resources ${resources})
12 | file(COPY ${test_resources} DESTINATION "resources/")
13 |
--------------------------------------------------------------------------------
/example/raylib-tmx-example.c:
--------------------------------------------------------------------------------
1 | /*******************************************************************************************
2 | *
3 | * [raylib-tmx] example - TMX Tiled Map editor loader for raylib.
4 | *
5 | * This example has been created using raylib 3.7 (www.raylib.com)
6 | * raylib-tmx is licensed under an unmodified zlib/libpng license (View raylib.h for details)
7 | *
8 | * Example by Rob Loach (@RobLoach)
9 | *
10 | * Copyright (c) 2021 Rob Loach (@RobLoach)
11 | *
12 | ********************************************************************************************/
13 |
14 | #include "raylib.h"
15 |
16 | #define RAYLIB_TMX_IMPLEMENTATION
17 | #include "raylib-tmx.h"
18 |
19 | int main(int argc, char *argv[]) {
20 | // Initialization
21 | //--------------------------------------------------------------------------------------
22 | // Make sure we're running in the correct directory.
23 | ChangeDirectory(GetDirectoryPath(argv[0]));
24 |
25 | const int screenWidth = 800;
26 | const int screenHeight = 450;
27 | InitWindow(screenWidth, screenHeight, "[raylib-tmx] example");
28 | SetTargetFPS(60);
29 |
30 | tmx_map* map = LoadTMX(argc > 1 ? argv[1] : "resources/desert.tmx");
31 | Vector2 position = {0, 0};
32 | //--------------------------------------------------------------------------------------
33 |
34 | while(!WindowShouldClose()) {
35 |
36 | // Update
37 | //----------------------------------------------------------------------------------
38 | if (IsKeyDown(KEY_LEFT)) {
39 | position.x += 2;
40 | }
41 | if (IsKeyDown(KEY_UP)) {
42 | position.y += 2;
43 | }
44 | if (IsKeyDown(KEY_RIGHT)) {
45 | position.x -= 2;
46 | }
47 | if (IsKeyDown(KEY_DOWN)) {
48 | position.y -= 2;
49 | }
50 | //----------------------------------------------------------------------------------
51 |
52 | // Draw
53 | //----------------------------------------------------------------------------------
54 | BeginDrawing();
55 | {
56 | ClearBackground(RAYWHITE);
57 | DrawTMX(map, position.x, position.y, WHITE);
58 | DrawFPS(10, 10);
59 | }
60 | EndDrawing();
61 | //----------------------------------------------------------------------------------
62 | }
63 |
64 | // De-Initialization
65 | //--------------------------------------------------------------------------------------
66 | UnloadTMX(map);
67 |
68 | CloseWindow();
69 | //--------------------------------------------------------------------------------------
70 |
71 | return 0;
72 | }
73 |
--------------------------------------------------------------------------------
/example/raylib-tmx-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobLoach/raylib-tmx/e8410d7cad1453c3a2d3c733a86f5d775ef4462b/example/raylib-tmx-example.png
--------------------------------------------------------------------------------
/example/resources/desert.tmx:
--------------------------------------------------------------------------------
1 |
2 |
178 |
--------------------------------------------------------------------------------
/example/resources/tmw_desert_spacing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobLoach/raylib-tmx/e8410d7cad1453c3a2d3c733a86f5d775ef4462b/example/resources/tmw_desert_spacing.png
--------------------------------------------------------------------------------
/include/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(raylib-tmx-h INTERFACE)
2 |
3 | # Include Directory
4 | target_include_directories(raylib-tmx-h INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/)
5 |
--------------------------------------------------------------------------------
/include/raylib-tmx.h:
--------------------------------------------------------------------------------
1 | /**********************************************************************************************
2 | *
3 | * raylib-tmx - Tiled TMX Loader for tile maps in raylib.
4 | *
5 | * Copyright 2021 Rob Loach (@RobLoach)
6 | *
7 | * DEPENDENCIES:
8 | * raylib https://www.raylib.com/
9 | * tmx https://github.com/baylej/tmx
10 | *
11 | * LICENSE: zlib/libpng
12 | *
13 | * raylib-tmx is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
14 | * BSD-like license that allows static linking with closed source software:
15 | *
16 | * This software is provided "as-is", without any express or implied warranty. In no event
17 | * will the authors be held liable for any damages arising from the use of this software.
18 | *
19 | * Permission is granted to anyone to use this software for any purpose, including commercial
20 | * applications, and to alter it and redistribute it freely, subject to the following restrictions:
21 | *
22 | * 1. The origin of this software must not be misrepresented; you must not claim that you
23 | * wrote the original software. If you use this software in a product, an acknowledgment
24 | * in the product documentation would be appreciated but is not required.
25 | *
26 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
27 | * as being the original software.
28 | *
29 | * 3. This notice may not be removed or altered from any source distribution.
30 | *
31 | **********************************************************************************************/
32 |
33 | #ifndef INCLUDE_RAYLIB_TMX_H_
34 | #define INCLUDE_RAYLIB_TMX_H_
35 |
36 | #include "raylib.h" // NOLINT
37 | #include "tmx.h" // NOLINT
38 |
39 | #ifdef __cplusplus
40 | extern "C" {
41 | #endif
42 |
43 | // TMX functions
44 | tmx_map* LoadTMX(const char* fileName); // Load a Tiled .tmx tile map
45 | void UnloadTMX(tmx_map* map); // Unload the given Tiled map
46 | Color ColorFromTMX(uint32_t color); // Convert a Tiled color number to a raylib Color
47 | void DrawTMX(tmx_map *map, int posX, int posY, Color tint); // Render the given Tiled map to the screen
48 | void DrawTMXLayers(tmx_map *map, tmx_layer *layers, int posX, int posY, Color tint); // Render all the given map layers to the screen
49 | void DrawTMXLayer(tmx_map *map, tmx_layer *layer, int posX, int posY, Color tint); // Render a single map layer on the screen
50 | void DrawTMXTile(tmx_tile* tile, int posX, int posY, Color tint); // Render the given tile to the screen
51 |
52 | #ifdef __cplusplus
53 | }
54 | #endif
55 |
56 | #endif // INCLUDE_RAYLIB_TMX_H_
57 |
58 | #ifdef RAYLIB_TMX_IMPLEMENTATION
59 | #ifndef RAYLIB_TMX_IMPLEMENTATION_ONCE
60 | #define RAYLIB_TMX_IMPLEMENTATION_ONCE
61 |
62 | #ifdef __cplusplus
63 | extern "C" {
64 | #endif
65 |
66 | /**
67 | * Convert the given Tiled ARGB color to a raylib Color.
68 | *
69 | * @param color The Tiled color number in ARGB form.
70 | *
71 | * @return The raylib Color representation.
72 | */
73 | Color ColorFromTMX(uint32_t color) {
74 | tmx_col_bytes res = tmx_col_to_bytes(color);
75 | return *((Color*)&res);
76 | }
77 |
78 | /**
79 | * Loads the provided path as a Texture for use with TMX.
80 | *
81 | * @param fileName The file path of the image to load.
82 | *
83 | * @return A void pointer representation of the Texture.
84 | *
85 | * @see UnloadTMXImage()
86 | *
87 | * @internal
88 | */
89 | void *LoadTMXImage(const char *fileName) {
90 | Texture2D *returnValue = MemAlloc(sizeof(Texture2D));
91 | *returnValue = LoadTexture(fileName);
92 | return returnValue;
93 | }
94 |
95 | /**
96 | * Unload the provided Texture pointer.
97 | *
98 | * @internal
99 | */
100 | void UnloadTMXImage(void *ptr) {
101 | if (ptr != NULL) {
102 | UnloadTexture(*((Texture2D *) ptr));
103 | MemFree(ptr);
104 | }
105 | }
106 |
107 | /**
108 | * Reallocate memory function callback for TMX.
109 | *
110 | * @internal
111 | */
112 | void* MemReallocTMX(void* address, size_t len) {
113 | return MemRealloc(address, (int)len);
114 | }
115 |
116 | /**
117 | * Loads given .tmx Tiled file.
118 | *
119 | * @param fileName The .tmx file to load.
120 | *
121 | * @return A TMX Tiled map object pointer.
122 | *
123 | * @see UnloadTMX()
124 | * @todo Add LoadTMXFromMemory() to allow loading through a buffer: https://github.com/baylej/tmx/pull/58
125 | */
126 | tmx_map* LoadTMX(const char* fileName) {
127 | // Register the TMX callbacks.
128 | tmx_alloc_func = MemReallocTMX;
129 | tmx_free_func = MemFree;
130 | tmx_img_load_func = LoadTMXImage;
131 | tmx_img_free_func = UnloadTMXImage;
132 |
133 | // Load the TMX file.
134 | tmx_map* map = tmx_load(fileName);
135 | if (!map) {
136 | TraceLog(LOG_ERROR, "TMX: Failed to load TMX file %s", fileName);
137 | return NULL;
138 | }
139 | TraceLog(LOG_INFO, "TMX: Loaded %ix%i map", map->width, map->height);
140 | return map;
141 |
142 | // TODO: Load using a buffer instead: https://github.com/baylej/tmx/pull/58
143 | // const char* fileText = LoadFileText(fileName);
144 | // tmx_map* map = tmx_load_buffer_path(fileText, TextLength(fileText), fileName);
145 | // if (!map) {
146 | // TraceLog(LOG_ERROR, "TMX: Failed to load TMX file %s", fileName);
147 | // return NULL;
148 | // }
149 | // TraceLog(LOG_INFO, "TMX: Loaded %ix%i map", map->width, map->height);
150 | // return map;
151 | }
152 |
153 | /**
154 | * Unloads the given TMX map.
155 | *
156 | * @param map The map to unload.
157 | */
158 | void UnloadTMX(tmx_map* map) {
159 | if (map) {
160 | tmx_map_free(map);
161 | TraceLog(LOG_INFO, "TMX: Unloaded map");
162 | }
163 | }
164 |
165 | #ifndef RAYLIB_TMX_LINE_THICKNESS
166 | #define RAYLIB_TMX_LINE_THICKNESS 3.0f
167 | #endif
168 |
169 | /**
170 | * @internal
171 | */
172 | void DrawTMXPolyline(double offset_x, double offset_y, double **points, int points_count, Color color) {
173 | for (int i = 1; i < points_count; i++) {
174 | DrawLineEx((Vector2){(float)(offset_x + points[i-1][0]), (float)(offset_y + points[i-1][1])},
175 | (Vector2){(float)(offset_x + points[i][0]), (float)(offset_y + points[i][1])},
176 | RAYLIB_TMX_LINE_THICKNESS, color);
177 | }
178 | }
179 |
180 | /**
181 | * @internal
182 | */
183 | void DrawTMXPolygon(double offset_x, double offset_y, double **points, int points_count, Color color) {
184 | DrawTMXPolyline(offset_x, offset_y, points, points_count, color);
185 | if (points_count > 2) {
186 | DrawLineEx((Vector2){(float)(offset_x + points[0][0]), (float)(offset_y + points[0][1])},
187 | (Vector2){(float)(offset_x + points[points_count-1][0]), (float)(offset_y + points[points_count-1][1])},
188 | RAYLIB_TMX_LINE_THICKNESS, color);
189 | }
190 | }
191 |
192 | /**
193 | * @internal
194 | */
195 | void DrawTMXText(tmx_text* text, Rectangle dest, Color tint) {
196 | float fontSize = (float)text->pixelsize;
197 | const char* message = text->text;
198 | Font font = GetFontDefault();
199 | // TODO: Figure out the correct spacing.
200 | float spacing = (float)text->kerning * fontSize / 12.0f;
201 | Vector2 position = {dest.x, dest.y};
202 |
203 | if (text->wrap == 0) {
204 | Vector2 textSize = MeasureTextEx(font, message, fontSize, spacing);
205 | if (text->halign == HA_CENTER) {
206 | position.x = dest.x + dest.width / 2.0f - textSize.x / 2.0f;
207 | }
208 | else if (text->halign == HA_RIGHT) {
209 | position.x = dest.x + dest.width - textSize.x;
210 | }
211 | if (text->valign == VA_CENTER) {
212 | position.y = dest.y + dest.height / 2.0f - textSize.y / 2.0f;
213 | }
214 | else if (text->valign == VA_BOTTOM) {
215 | position.y = dest.y + dest.height - textSize.y;
216 | }
217 | DrawTextEx(font, message, position, fontSize, spacing, tint);
218 | }
219 | else {
220 | Vector2 origin = {0.0f, 0.0f};
221 | DrawTextPro(font, message, position, origin, 0.0f, fontSize, spacing, tint);
222 | }
223 | }
224 |
225 | /**
226 | * @internal
227 | */
228 | void DrawTMXLayerObjects(tmx_map *map, tmx_object_group *objgr, int posX, int posY, Color tint) {
229 | tmx_object *head = objgr->head;
230 | Color color = ColorFromTMX(objgr->color);
231 | // TODO: Merge the tint
232 |
233 | while (head) {
234 | if (head->visible) {
235 | Rectangle dest = (Rectangle) {
236 | (float)posX + (float)head->x,
237 | (float)posY + (float)head->y,
238 | (float)head->width,
239 | (float)head->height
240 | };
241 | switch (head->obj_type) {
242 | case OT_SQUARE:
243 | DrawRectangleLinesEx(dest, (int)RAYLIB_TMX_LINE_THICKNESS, color);
244 | break;
245 | case OT_POLYGON:
246 | DrawTMXPolygon(dest.x, dest.y, head->content.shape->points, head->content.shape->points_len, color);
247 | break;
248 | case OT_POLYLINE:
249 | DrawTMXPolyline(dest.x, dest.y, head->content.shape->points, head->content.shape->points_len, color);
250 | break;
251 | case OT_ELLIPSE:
252 | DrawEllipseLines(dest.x + head->width / 2.0, dest.y + head->height / 2.0, head->width / 2.0f, head->height / 2.0f, color);
253 | break;
254 | case OT_TILE: {
255 | int gid = head->content.gid;
256 | if (map->tiles[gid] != NULL) {
257 | DrawTMXTile(map->tiles[gid], dest.x, dest.y - dest.height, tint);
258 | }
259 | } break;
260 | case OT_TEXT: {
261 | tmx_text* text = head->content.text;
262 | Color textColor = ColorFromTMX(text->color);
263 | // TODO: Fix application of the tint.
264 | textColor.a = tint.a;
265 | DrawTMXText(text, dest, textColor);
266 | } break;
267 | case OT_POINT:
268 | DrawCircle(dest.x + head->width / 2.0, dest.y + head->height / 2.0, 5, color);
269 | break;
270 | }
271 | }
272 | head = head->next;
273 | }
274 | }
275 |
276 | /**
277 | * @internal
278 | */
279 | void DrawTMXLayerImage(tmx_image *image, int posX, int posY, Color tint) {
280 | if (image->resource_image) {
281 | Texture2D *texture = (Texture2D*)image->resource_image;
282 | DrawTexture(*texture, posX, posY, tint);
283 | }
284 | }
285 |
286 | /**
287 | * Render a single TMX tile on the screen.
288 | *
289 | * @param tile Which tile to render on the screen.
290 | * @param posX The X position of the tile.
291 | * @param posY The Y position of the tile.
292 | * @param tint How to tint the tile when rendering.
293 | */
294 | void DrawTMXTile(tmx_tile* tile, int posX, int posY, Color tint) {
295 | Texture* image;
296 | Rectangle srcRect;
297 | Vector2 position;
298 | position.x = (float)posX;
299 | position.y = (float)posY;
300 |
301 | #ifdef RAYLIB_TMX_SUPPORT_ANIMATIONS
302 | // TODO: Process the animation https://github.com/baylej/tmx/pull/64
303 | if(tile->animation) {
304 | int tile_id = tile->animation[tile->current_animation_frame].tile_id;
305 | tile = &tile->tileset->tiles[tile_id];
306 | }
307 | #endif
308 |
309 | srcRect.x = tile->ul_x;
310 | srcRect.y = tile->ul_y;
311 | srcRect.width = tile->tileset->tile_width;
312 | srcRect.height = tile->tileset->tile_height;
313 |
314 | // Find the image
315 | tmx_image *im = tile->image;
316 |
317 | if (im && im->resource_image) {
318 | image = (Texture*)im->resource_image;
319 | }
320 | else if (tile->tileset->image->resource_image) {
321 | image = (Texture*)tile->tileset->image->resource_image;
322 | }
323 |
324 | if (image) {
325 | DrawTextureRec(*image, srcRect, position, tint);
326 | }
327 | }
328 |
329 | /**
330 | * @internal
331 | */
332 | void DrawTMXLayerTiles(tmx_map *map, tmx_layer *layer, int posX, int posY, Color tint) {
333 | unsigned int gid, baseGid; //, flags;
334 | tmx_tileset *ts;
335 | Color newTint = ColorAlpha(tint, (float)layer->opacity);
336 |
337 | switch (map->renderorder) {
338 | case R_NONE:
339 | case R_RIGHTDOWN:
340 | for (int y = 0; y < map->height; y++) {
341 | for (int x = 0; x < map->width; x++) {
342 | baseGid = layer->content.gids[(y * map->width) + x];
343 | gid = (baseGid) & TMX_FLIP_BITS_REMOVAL;
344 | // TODO: Add the flags of the tile to Draw.
345 | // flags = baseGid & ~TMX_FLIP_BITS_REMOVAL;
346 | if (map->tiles[gid] != NULL) {
347 | ts = map->tiles[gid]->tileset;
348 | DrawTMXTile(map->tiles[gid], posX + x * ts->tile_width, posY + y * ts->tile_height, newTint);
349 | }
350 | }
351 | }
352 | break;
353 | case R_RIGHTUP:
354 | for (int y = map->height - 1; y >= 0; y--) {
355 | for (int x = 0; x < map->width; x++) {
356 | baseGid = layer->content.gids[(y * map->width) + x];
357 | gid = (baseGid) & TMX_FLIP_BITS_REMOVAL;
358 | // TODO: Add the flags of the tile to Draw.
359 | // flags = baseGid & ~TMX_FLIP_BITS_REMOVAL;
360 | if (map->tiles[gid] != NULL) {
361 | ts = map->tiles[gid]->tileset;
362 | DrawTMXTile(map->tiles[gid], posX + x * ts->tile_width, posY + y * ts->tile_height, newTint);
363 | }
364 | }
365 | }
366 | break;
367 | case R_LEFTDOWN:
368 | for (int y = 0; y < map->height; y++) {
369 | for (int x = map->width - 1; x >= 0; x--) {
370 | baseGid = layer->content.gids[(y * map->width) + x];
371 | gid = (baseGid) & TMX_FLIP_BITS_REMOVAL;
372 | // TODO: Add the flags of the tile to Draw.
373 | // flags = baseGid & ~TMX_FLIP_BITS_REMOVAL;
374 | if (map->tiles[gid] != NULL) {
375 | ts = map->tiles[gid]->tileset;
376 | DrawTMXTile(map->tiles[gid], posX + x * ts->tile_width, posY + y * ts->tile_height, newTint);
377 | }
378 | }
379 | }
380 | break;
381 | case R_LEFTUP:
382 | for (int y = map->height - 1; y >= 0; y--) {
383 | for (int x = map->width - 1; x >= 0; x--) {
384 | baseGid = layer->content.gids[(y * map->width) + x];
385 | gid = (baseGid) & TMX_FLIP_BITS_REMOVAL;
386 | // TODO: Add the flags of the tile to Draw.
387 | // flags = baseGid & ~TMX_FLIP_BITS_REMOVAL;
388 | if (map->tiles[gid] != NULL) {
389 | ts = map->tiles[gid]->tileset;
390 | DrawTMXTile(map->tiles[gid], posX + x * ts->tile_width, posY + y * ts->tile_height, newTint);
391 | }
392 | }
393 | }
394 | break;
395 | }
396 |
397 | }
398 |
399 | /**
400 | * Render the given layer to the screen.
401 | *
402 | * @param map The TMX map that holds the layer.
403 | * @param layer The layer to render on the screen.
404 | * @param posX The X position of the screen.
405 | * @param posY The Y position of the screen.
406 | * @param tint How to tint the rendering of the layer.
407 | */
408 | void DrawTMXLayer(tmx_map *map, tmx_layer *layer, int posX, int posY, Color tint) {
409 | switch (layer->type) {
410 | case L_GROUP:
411 | DrawTMXLayers(map, layer->content.group_head, posX + layer->offsetx, posY + layer->offsety, tint); // recursive call
412 | break;
413 | case L_OBJGR:
414 | DrawTMXLayerObjects(map, layer->content.objgr, posX + layer->offsetx, posY + layer->offsety, tint);
415 | break;
416 | case L_IMAGE:
417 | DrawTMXLayerImage(layer->content.image, posX + layer->offsetx, posY + layer->offsety, tint);
418 | break;
419 | case L_LAYER:
420 | DrawTMXLayerTiles(map, layer, posX + layer->offsetx, posY + layer->offsety, tint);
421 | break;
422 | case L_NONE:
423 | // Nothing.
424 | break;
425 | }
426 | }
427 |
428 | /**
429 | * Draws all of the given TMX map layers to the screen.
430 | *
431 | * @param map The TMX map that holds the layer.
432 | * @param layers The layer to render on the screen.
433 | * @param posX The X position of the screen.
434 | * @param posY The Y position of the screen.
435 | * @param tint How to tint the rendering of the layer.
436 | */
437 | void DrawTMXLayers(tmx_map *map, tmx_layer *layers, int posX, int posY, Color tint) {
438 | while (layers) {
439 | if (layers->visible) {
440 | DrawTMXLayer(map, layers, posX, posY, tint);
441 | }
442 | layers = layers->next;
443 | }
444 | }
445 |
446 | /**
447 | * Render the given map to the screen.
448 | *
449 | * @param map The TMX map to render to the screen.
450 | * @param posX The X position of the screen.
451 | * @param posY The Y position of the screen.
452 | * @param tint How to tint the rendering of the layer.
453 | */
454 | void DrawTMX(tmx_map *map, int posX, int posY, Color tint) {
455 | Color background = ColorFromTMX(map->backgroundcolor);
456 | // TODO: Apply the tint to the background color.
457 | DrawRectangle(posX, posY, map->width, map->height, background);
458 | DrawTMXLayers(map, map->ly_head, posX, posY, tint);
459 | }
460 |
461 | #ifdef __cplusplus
462 | }
463 | #endif
464 |
465 | #endif // RAYLIB_TMX_IMPLEMENTATION_ONCE
466 | #endif // RAYLIB_TMX_IMPLEMENTATION
467 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # raylib
2 | find_package(raylib QUIET)
3 | if (NOT raylib_FOUND)
4 | include(FetchContent)
5 | FetchContent_Declare(
6 | raylib
7 | GIT_REPOSITORY https://github.com/raysan5/raylib.git
8 | GIT_TAG 5.0
9 | )
10 | FetchContent_GetProperties(raylib)
11 | if (NOT raylib_POPULATED) # Have we downloaded raylib yet?
12 | set(FETCHCONTENT_QUIET NO)
13 | FetchContent_Populate(raylib)
14 | set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
15 | set(BUILD_GAMES OFF CACHE BOOL "" FORCE)
16 | add_subdirectory(${raylib_SOURCE_DIR} ${raylib_BINARY_DIR})
17 | endif()
18 | endif()
19 |
20 | # tmx
21 | find_package(tmx QUIET)
22 | if (NOT tmx_FOUND)
23 | include(FetchContent)
24 | FetchContent_Declare(
25 | tmx
26 | GIT_REPOSITORY https://github.com/RobLoach/tmx.git
27 | GIT_TAG f88a433
28 | )
29 | FetchContent_GetProperties(tmx)
30 | if (NOT tmx_POPULATED)
31 | set(FETCHCONTENT_QUIET NO)
32 | FetchContent_Populate(tmx)
33 | add_subdirectory(${tmx_SOURCE_DIR} ${tmx_BINARY_DIR})
34 | endif()
35 | endif()
36 |
37 | option(RAYLIB_TMX "raylib-tmx" ON)
38 | option(RAYLIB_TMX_SHARED "raylib-tmx-shared" OFF)
39 |
40 | set(RAYLIB_TMX_DEPS raylib tmx)
41 | if(UNIX)
42 | list(APPEND RAYLIB_TMX_DEPS m)
43 | endif()
44 |
45 | if(RAYLIB_TMX)
46 | add_library(raylib-tmx STATIC raylib-tmx.c)
47 | target_include_directories(raylib-tmx PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include)
48 | target_link_libraries(raylib-tmx PUBLIC ${RAYLIB_TMX_DEPS})
49 | endif()
50 |
51 | if(RAYLIB_TMX_SHARED)
52 | add_library(raylib-tmx-shared SHARED raylib-tmx.c)
53 | target_include_directories(raylib-tmx-shared PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include)
54 | target_link_libraries(raylib-tmx-shared PUBLIC ${RAYLIB_TMX_DEPS})
55 | endif()
56 |
--------------------------------------------------------------------------------
/src/raylib-tmx.c:
--------------------------------------------------------------------------------
1 | /**
2 | * raylib-tmx - TMX Loader for raylib.
3 | *
4 | * This file is here to allow compiled individually. This allows linking
5 | * raylib-tmx without needing to compile it as part of your source files,
6 | * or defining RAYLIB_TMX_IMPLEMENTATION.
7 | */
8 |
9 | #define RAYLIB_TMX_IMPLEMENTATION
10 | #include "raylib-tmx.h"
11 |
--------------------------------------------------------------------------------
/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # raylib-tmx-test
2 | add_executable(raylib-tmx-test raylib-tmx-test.c)
3 | target_compile_options(raylib-tmx-test PRIVATE -Wall -Wextra -Wconversion -Wsign-conversion)
4 | target_link_libraries(raylib-tmx-test PUBLIC
5 | raylib
6 | raylib-tmx
7 | )
8 |
9 | # Copy the resources
10 | file(GLOB resources resources/*)
11 | set(test_resources)
12 | list(APPEND test_resources ${resources})
13 | file(COPY ${test_resources} DESTINATION "resources/")
14 |
15 | # Set up the test
16 | add_test(NAME raylib-tmx-test COMMAND raylib-tmx-test)
17 |
--------------------------------------------------------------------------------
/test/raylib-tmx-test.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "raylib.h"
4 |
5 | #define RAYLIB_TMX_IMPLEMENTATION
6 | #include "raylib-tmx.h"
7 |
8 | int main(int argc, char *argv[]) {
9 | // Initialization
10 | SetTraceLogLevel(LOG_ALL);
11 | TraceLog(LOG_INFO, "================================");
12 | TraceLog(LOG_INFO, "raylib-tmx-test");
13 | TraceLog(LOG_INFO, "================================");
14 |
15 | InitWindow(640, 480, "[raylib-tmx] tests");
16 | assert(IsWindowReady());
17 |
18 | // Make sure we're running in the correct directory.
19 | assert(argc > 0);
20 | const char* dir = GetDirectoryPath(argv[0]);
21 | assert(ChangeDirectory(dir));
22 |
23 | tmx_map* map = LoadTMX("resources/desert.tmx");
24 | assert(map != NULL);
25 |
26 | BeginDrawing();
27 | {
28 | ClearBackground(RAYWHITE);
29 | DrawTMX(map, 10, 10, WHITE);
30 |
31 | DrawTMXLayer(map, map->ly_head, 10, 10, WHITE);
32 | }
33 | EndDrawing();
34 |
35 | UnloadTMX(map);
36 |
37 | CloseWindow();
38 | TraceLog(LOG_INFO, "================================");
39 | TraceLog(LOG_INFO, "raylib-tmx tests succesful");
40 | TraceLog(LOG_INFO, "================================");
41 |
42 | return 0;
43 | }
44 |
--------------------------------------------------------------------------------
/test/resources/desert.tmx:
--------------------------------------------------------------------------------
1 |
2 |
118 |
--------------------------------------------------------------------------------
/test/resources/tmw_desert_spacing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobLoach/raylib-tmx/e8410d7cad1453c3a2d3c733a86f5d775ef4462b/test/resources/tmw_desert_spacing.png
--------------------------------------------------------------------------------