aboutsummaryrefslogtreecommitdiff
path: root/tools/compile_assets/tiled.odin
diff options
context:
space:
mode:
authoriamcheeseman <[hidden email]>2026-01-12 20:51:28 -0500
committeriamcheeseman <[hidden email]>2026-01-12 20:51:28 -0500
commit7fb83578b99aa224f7545f4118a46e84b58a9295 (patch)
tree515e294ac7de167c4501cc0a8d375b13213faf36 /tools/compile_assets/tiled.odin
parent2b3a3ea9f4bc902b1b357fd149952d4570b25bf3 (diff)
NEW ASSET SYSTEM WOOOOOOOOHOOOOOOOOOOOOOOOOOOOOOOOOO
Diffstat (limited to 'tools/compile_assets/tiled.odin')
-rw-r--r--tools/compile_assets/tiled.odin447
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
+}