diff options
| author | iamcheeseman <[hidden email]> | 2026-01-12 20:51:28 -0500 |
|---|---|---|
| committer | iamcheeseman <[hidden email]> | 2026-01-12 20:51:28 -0500 |
| commit | 7fb83578b99aa224f7545f4118a46e84b58a9295 (patch) | |
| tree | 515e294ac7de167c4501cc0a8d375b13213faf36 /tools/compile_assets/tiled.odin | |
| parent | 2b3a3ea9f4bc902b1b357fd149952d4570b25bf3 (diff) | |
NEW ASSET SYSTEM WOOOOOOOOHOOOOOOOOOOOOOOOOOOOOOOOOO
Diffstat (limited to 'tools/compile_assets/tiled.odin')
| -rw-r--r-- | tools/compile_assets/tiled.odin | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/tools/compile_assets/tiled.odin b/tools/compile_assets/tiled.odin new file mode 100644 index 0000000..7752273 --- /dev/null +++ b/tools/compile_assets/tiled.odin @@ -0,0 +1,447 @@ +package assets_gen + +import os "core:os/os2" +import "core:fmt" +import "core:encoding/json" +import "core:path/filepath" +import "core:strings" + +Rect :: struct { + start: [2]f32, + size: [2]f32, +} + +Json_Map :: struct { + backgroundcolor: string, + class: string, + compressionlevel: i32, + width: i32, + height: i32, + infinite: bool, + layers: []Json_Layer, + nextlayerid: i32, + nextobjectid: i32, + orientation: string, + parallaxoriginx: f64, + parallaxoriginy: f64, + properties: []Json_Property, + renderorder: string, + staggeraxis: string, + staggerindex: string, + tilewidth: i32, + tileheight: i32, + tilesets: []Json_Tileset, +} + +Json_Layer :: struct { + class: string, + compression: string, + data: union { + []i32, + string, + }, + draworder: string, + encoding: string, + id: i32, + image: string, + image_width: i32, + image_height: i32, + layers: []Json_Layer, + // locked: bool, + name: string, + objects: []Json_Object, + offsetx: f64, + offsety: f64, + opacity: f32, + parallaxx: f64, + parallaxy: f64, + properties: []Json_Property, + repeatx: bool, + repeaty: bool, + tintcolor: string, + transparentcolor: string, + type: string, + visible: bool, + x: i32, + y: i32, + width: i32, + height: i32, +} + +Json_Object :: struct { + ellipse: bool, + gid: i32, + width: f64, + height: f64, + id: i32, + name: string, + point: bool, + polygon: []Json_Point, + polyline: []Json_Point, + properties: []Json_Property, + rotation: f64, + template: string, + text: Maybe(struct { + fontfamily: string, + color: string, + text: string, + halign: string, + valign: string, + pixelsize: i32, + wrap: bool, + underline: bool, + bold: bool, + italic: bool, + kerning: bool, + strikeout: bool, + }), + type: string, + visible: bool, + x: f64, + y: f64, +} + +Json_Tileset :: struct { + background_color: string, + class: string, + rows: i32, + columns: i32, + fillmode: string, + firstgid: i32, + grid: Maybe(Json_Grid), + image: string, + imagewidth: i32, + imageheight: i32, + margin: i32, + name: string, + objectalignment: string, + properties: []Json_Property, + source: string, + spacing: i32, + terrains: []Json_Terrain, + tilecount: i32, + tilewidth: i32, + tileheight: i32, + tileoffset: Json_Tile_Offset, + tilerendersize: string, + tiles: []Json_Tile, + transformations: Json_Transformations, + transparentcolor: string, + type: string, + wangsets: []Json_Wang_Set, +} + +Json_Grid :: struct { + width: i32, + height: i32, + orientation: string, +} + +Json_Tile_Offset :: struct { + x: i32, + y: i32, +} + +Json_Transformations :: struct { + hflip: bool, + vflip: bool, + rotate: bool, + preferuntransformed: bool, +} + +Json_Tile :: struct { + animation: []Json_Frame, + id: i32, + image: string, + imagewidth: i32, + imageheight: i32, + x: i32, + y: i32, + width: i32, + height: i32, + objectgroup: Json_Layer, + probability: f64, + properties: []Json_Property, + terrain: []i32, + type: string, +} + +Json_Frame :: struct { + duration: i32, + tileid: i32, +} + +Json_Terrain :: struct { + name: string, + properties: []Json_Property, + tile: i32, +} + +Json_Wang_Set :: struct { + class: string, + colors: []Json_Wang_Color, + name: string, + properties: []Json_Property, + tile: i32, + type: string, + wangtiles: []Json_Wang_Tile, +} + +Json_Wang_Color :: struct { + class: string, + color: string, + name: string, + probability: f64, + properties: []Json_Property, + tile: i32, +} + +Json_Wang_Tile :: struct { + tileid: i32, + wangid: []u8, +} + +Json_Object_Template :: struct { + tileset: Maybe(Json_Tileset), + object: Json_Object, +} + +Json_Property :: struct { + name: string, + type: string, + propertytype: string, + value: any, +} + +Json_Point :: struct { + x: f64, + y: f64, +} + +Json_World_Room :: struct { + file_name: string `json:"fileName"`, + x: i32, + y: i32, + width: i32, + height: i32, +} + +Json_World :: struct { + maps: []Json_World_Room, +} + +Gids :: struct { + first: u32, + last: u32, +} + +gids: map[string]Gids + +load_json_world :: proc(path: string) { + json_text, read_err := os.read_entire_file(path, context.temp_allocator) + if read_err != nil { + die("Could not load world %v (%v)", path, read_err) + } + + json_dat: Json_World + unmarshal_err := json.unmarshal( + json_text, + &json_dat, + allocator = context.temp_allocator, + ) + if unmarshal_err != nil { + die("Could not parse world %v (%v)", path, unmarshal_err) + } + + for room in json_dat.maps { + room_name := strings.to_screaming_snake_case( + filepath.stem(room.file_name), + allocator = context.temp_allocator, + ) + + line := fmt.aprintf( + "{{id=.%v, x=%w, y=%w, width=%w, height=%w}}", + room_name, + room.x, + room.y, + room.width, + room.height, + ) + append(&world, line) + } +} + +create_tile :: proc( + tileset_enum: string, + rect: Rect, + collisions: []Rect, +) -> string { + line := fmt.aprintf( + "{{tileset=.%v, rect=%w, id=%w, collisions=%w}}", + tileset_enum, + rect, + len(tiles), + collisions, + ) + append(&tiles, line) + return line +} + +load_json_tileset :: proc(path: string) { + json_text, read_err := os.read_entire_file(path, context.temp_allocator) + if read_err != nil { + die("Could not load tileset %v (%v)", path, read_err) + } + + json_dat: Json_Tileset + unmarshal_err := json.unmarshal( + json_text, + &json_dat, + allocator = context.temp_allocator, + ) + if unmarshal_err != nil { + die("Failed to parse tileset %v (%v)", path, unmarshal_err) + } + + tileset_enum := strings.to_screaming_snake_case( + filepath.stem(path), + allocator = context.temp_allocator, + ) + + image_enum := strings.to_screaming_snake_case( + filepath.stem(json_dat.image), + allocator = context.temp_allocator, + ) + + tiles_x := json_dat.imagewidth / json_dat.tilewidth + tiles_y := json_dat.imageheight / json_dat.tileheight + + local_tiles := make([dynamic]string, allocator = context.temp_allocator) + + tile_size: [2]f32 = {f32(json_dat.tilewidth), f32(json_dat.tileheight)} + + first_gid := u32(len(tiles)) + + gids[filepath.stem(path)] = { + first = first_gid, + last = u32(len(tiles) + int(json_dat.tilecount)), + } + + collisions := make([][dynamic]Rect, json_dat.tilecount) + defer { + for collision in collisions { + delete(collision) + } + delete(collisions) + } + + for tile in json_dat.tiles { + collision := &collisions[tile.id] + for object in tile.objectgroup.objects { + append( + collision, + Rect{ + start = {f32(object.x), f32(object.y)}, + size = {f32(object.width), f32(object.height)} + } + ) + } + } + + for y in 0..<tiles_y { + for x in 0..<tiles_x { + append(&local_tiles, create_tile( + tileset_enum, + Rect{ + start = {f32(x * json_dat.tilewidth), f32(y * json_dat.tileheight)}, + size = tile_size, + }, + collisions[y * tiles_x + x][:], + )) + } + } + + gids := make([]u32, len(local_tiles)) + for tile, i in local_tiles { + gids[i] = first_gid + u32(i) + } + + line := fmt.aprintf("{{tiles=%w, image=.%v}}", gids, image_enum) + tilesets[filepath.stem(path)] = line +} + +load_json_room :: proc(path: string, file: ^os.File) { + json_text, read_err := os.read_entire_file(file, context.temp_allocator) + if read_err != nil { + die("Could not load room %v (%v)", path, read_err) + } + + json_dat: Json_Map + unmarshal_err := json.unmarshal( + json_text, + &json_dat, + allocator = context.temp_allocator, + ) + if unmarshal_err != nil { + die("Failed to parse room %v (%v)", path, unmarshal_err) + } + + width := json_dat.width + height := json_dat.height + + tile_width := json_dat.tilewidth + tile_height := json_dat.tileheight + + tiled_to_real_gid: map[i32]u32 + defer delete(tiled_to_real_gid) + + // map tiled's map-based GIDs to my actually global GIDs + id: i32 = 1 + for tileset in json_dat.tilesets { + tileset_name := filepath.stem(tileset.source) + gid, exists := gids[tileset_name] + if !exists { + load_json_tileset(strings.concatenate({ + filepath.dir(path), + "/", + tileset.source, + })) + gid = gids[tileset_name] + } + + for i in gid.first..<gid.last { + tiled_to_real_gid[id] = i + id += 1 + } + } + + layers: [dynamic][]u32 + defer delete(layers) + + for layer in json_dat.layers { + if strings.compare(layer.type, "tilelayer") != 0 { + continue + } + + json_layer_dat, ok := layer.data.([]i32) + if !ok { + continue + } + + data := make([]u32, len(json_layer_dat), allocator = context.temp_allocator) + + for cell, i in json_layer_dat { + data[i] = tiled_to_real_gid[cell] + } + + append(&layers, data) + } + + line := fmt.aprintf( + "{{width=%v, height=%v, tile_width=%v, tile_height=%v, layers=%w, objects={{}}, background_image=nil}}", + width, height, + tile_width, tile_height, + layers[:], + ) + rooms[filepath.stem(path)] = line +} |
