package main import "base:runtime" import "core:encoding/json" import "core:fmt" import "core:os" Map_File :: struct { compression_level: int `json:"compressionlevel"`, height: int `json:"height"`, infinite: bool `json:"infinite"`, layers: []Layer `json:"layers"`, next_layer_id: int `json:"nextlayerid"`, next_object_id: int `json:"nextobjectid"`, orientation: string `json:"orientation"`, render_order: string `json:"renderorder"`, tiled_version: string `json:"tiledversion"`, tile_height: int `json:"tileheight"`, tile_sets: []Tileset `json:"tilesets"`, tile_width: int `json:"tilewidth"`, type: string `json:"type"`, version: string `json:"version"`, width: int `json:"width"`, } Layer :: struct { data: []int `json:"data"`, height: int `json:"height"`, id: int `json:"id"`, name: string `json:"name"`, opacity: f32 `json:"opacity"`, type: string `json:"type"`, visible: bool `json:"visible"`, width: int `json:"width"`, x: int `json:"x"`, y: int `json:"y"`, } Tileset :: struct { first_gid: int `json:"firstgid"`, 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"`, tiled_version: string `json:"tiledversion"`, tile_height: int `json:"tileheight"`, tile_width: int `json:"tilewidth"`, type: string `json:"type"`, version: string `json:"version"`, } Tileset_Load_Error_Type :: enum { None, Err_Loading_File, Err_Unmarshal, } Tileset_Load_Error :: struct { type: Tileset_Load_Error_Type, msg: string, } Tileset_Data :: struct { name: string, image: string, tile_width: i32, tile_height: i32, columns: i32, rows: i32, margin: i32, spacing: i32, tile_count: i32, } Map_Load_Error_Type :: enum { None, Err_Loading_File, Err_Unmarshal, } Map_Load_Error :: struct { type: Map_Load_Error_Type, msg: string, } Map :: struct { width: i32, height: i32, layers: []Layer_Data, } Layer_Data :: struct { data: [][]i32, } load_map :: proc( path: string, allocator: runtime.Allocator, ) -> ( map_out: Map, err: Map_Load_Error, ) { context.allocator = allocator cfg_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)} } unm_map: Map_File unm_err := json.unmarshal(cfg_data, &unm_map) if unm_err != nil { return {}, Map_Load_Error{type = .Err_Unmarshal, msg = fmt.aprintf("Error unmarshalling file: %v (%v)\nOnly Tiled version 1.11.2 is supported", path, unm_err)} } assert(!unm_map.infinite, "Infinite maps are not supported") assert( unm_map.orientation == "orthogonal", "Only orthogonal maps are supported", ) assert( unm_map.render_order == "right-down", "Only right-down maps are supported", ) assert( unm_map.tile_height == 16 && unm_map.tile_width == 16, "Only 16x16 tiles are supported", ) if len(unm_map.layers) == 0 { return {}, Map_Load_Error{type = .Err_Unmarshal, msg = fmt.aprintf("No layers found in file: %v", path)} } if len(unm_map.tile_sets) == 0 { return {}, Map_Load_Error{type = .Err_Unmarshal, msg = fmt.aprintf("No tilesets found in file: %v", path)} } for layer in unm_map.layers { assert( layer.type == "tilelayer", "Only layers with type 'tilelayer' are supported", ) } map_out.width = i32(unm_map.width) map_out.height = i32(unm_map.height) map_out.layers = make([]Layer_Data, len(unm_map.layers)) for &out, li in map_out.layers { src := unm_map.layers[li] out.data = make([][]i32, src.height) for row in 0 ..< src.height { out.data[row] = make([]i32, src.width) for col in 0 ..< src.width { out.data[row][col] = i32(src.data[row * src.width + col]) } } } // for layer in unm_map.layers { // for tile, tile_id in layer.data { // map_out.data[tile_id / layer.width][tile_id % layer.width] = i32( // tile, // ) // } // } return } load_tileset :: proc( path: string, allocator: runtime.Allocator, ) -> ( tileset_out: Tileset_Data, err: Tileset_Load_Error, ) { context.allocator = allocator cfg_data, os_err := os.read_entire_file(path, context.allocator) if os_err != os.General_Error.None { return {}, Tileset_Load_Error{type = .Err_Loading_File, msg = fmt.aprintf("Error reading file: %v (%v)", path, os_err)} } unm: Tileset_File unm_err := json.unmarshal(cfg_data, &unm) if unm_err != nil { return {}, Tileset_Load_Error{type = .Err_Unmarshal, msg = fmt.aprintf("Error unmarshalling file: %v (%v)\nOnly Tiled version 1.11.2 is supported", path, unm_err)} } assert(unm.type == "tileset", "Only files with type 'tileset' are supported") assert( unm.tile_height > 0 && unm.tile_width > 0, "Only positive tile sizes are supported", ) assert(unm.columns > 0, "Tileset must have at least one column") tileset_out.name = unm.name tileset_out.image = unm.image tileset_out.tile_width = i32(unm.tile_width) tileset_out.tile_height = i32(unm.tile_height) tileset_out.columns = i32(unm.columns) tileset_out.rows = i32( (unm.image_height - 2 * unm.margin + unm.spacing) / (unm.tile_height + unm.spacing), ) tileset_out.margin = i32(unm.margin) tileset_out.spacing = i32(unm.spacing) tileset_out.tile_count = i32(unm.tile_count) return }