diff --git a/map.odin b/map.odin index 685ccca..2d8ecf3 100644 --- a/map.odin +++ b/map.odin @@ -1,6 +1,8 @@ package main import "core:fmt" +import os "core:os" +import "core:strings" import rl "vendor:raylib" @@ -23,8 +25,14 @@ Tile :: struct { load_atlas :: proc() -> Atlas { at: Atlas - at.tex = rl.LoadTexture("./assets/3rdparty/tileset/Tiles/Tileset.png") - at.tile_size = rl.Vector2{16, 16} + ts, err := load_tileset("./Tiled/tiles.json", context.allocator) + if err.type != .None { + fmt.println(err.msg) + os.exit(1) + } + + at.tex = rl.LoadTexture(strings.clone_to_cstring(ts.texture_path)) + at.tile_size = rl.Vector2{f32(ts.tile_width), f32(ts.tile_height)} at.rows = at.tex.height / (i32(at.tile_size.y)) at.cols = at.tex.width / i32(at.tile_size.x) at.frames = at.cols * at.rows diff --git a/test.odin b/test.odin index 06ab7d0..d449e8a 100644 --- a/test.odin +++ b/test.odin @@ -1 +1,16 @@ package main + +import "core:fmt" +import "core:strings" +import "core:testing" + +@(test) +test_load_tileset :: proc(t: ^testing.T) { + ts, err := load_tileset("./Tiled/tiles.json", context.allocator) + assert(err.type == .None, err.msg) + assert(ts.tile_width == 16 && ts.tile_height == 16, "tile size") + assert(ts.columns == 8, "columns") + assert(ts.columns * ts.tile_width == 128, "cols * tile == image width") + assert(strings.has_suffix(ts.texture_path, "assets/3rdparty/tileset/Tiles/Tileset.png"), ts.texture_path) + fmt.println("test_load_tileset: ok") +} diff --git a/tiled_parser.odin b/tiled_parser.odin index 5710ded..b0834da 100644 --- a/tiled_parser.odin +++ b/tiled_parser.odin @@ -4,6 +4,7 @@ import "base:runtime" import "core:encoding/json" import "core:fmt" import "core:os" +import "core:path/filepath" Map_File :: struct { compression_level: int `json:"compressionlevel"`, @@ -41,6 +42,60 @@ Tileset :: struct { source: string `json:"source"`, } +Tileset_File :: struct { + columns: int `json:"columns"`, + image: string `json:"image"`, + image_height: int `json:"imageheight"`, + image_width: int `json:"imagewidth"`, + margin: int `json:"margin"`, + name: string `json:"name"`, + spacing: int `json:"spacing"`, + tile_count: int `json:"tilecount"`, + tile_height: int `json:"tileheight"`, + tile_width: int `json:"tilewidth"`, +} + +Tileset_Info :: struct { + texture_path: string, + tile_width: i32, + tile_height: i32, + columns: i32, +} + +load_tileset :: proc( + path: string, + allocator: runtime.Allocator, +) -> ( + out: Tileset_Info, + err: Map_Load_Error, +) { + context.allocator = allocator + + data, os_err := os.read_entire_file(path, context.allocator) + if os_err != os.General_Error.None { + return {}, Map_Load_Error{type = .Err_Loading_File, msg = fmt.aprintf("Error reading file: %v (%v)", path, os_err)} + } + + ts: Tileset_File + unm_err := json.unmarshal(data, &ts) + free(raw_data(data), context.allocator) + if unm_err != nil { + return {}, Map_Load_Error{type = .Err_Unmarshal, msg = fmt.aprintf("Error unmarshalling tileset: %v (%v)", path, unm_err)} + } + + assert(ts.margin == 0 && ts.spacing == 0, "Tilesets with margin/spacing are not supported") + assert(ts.tile_width == 16 && ts.tile_height == 16, "Only 16x16 tiles are supported") + + // image path in tiles.json is relative to the tileset file itself + elem := [2]string{filepath.dir(path), ts.image} + out.texture_path, _ = filepath.join(elem[:], context.allocator) + out.tile_width = i32(ts.tile_width) + out.tile_height = i32(ts.tile_height) + out.columns = i32(ts.columns) + + return +} + Map_Load_Error_Type :: enum { None, Err_Loading_File,