aboutsummaryrefslogtreecommitdiff
path: root/src/tiled/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 /src/tiled/tiled.odin
parent2b3a3ea9f4bc902b1b357fd149952d4570b25bf3 (diff)
NEW ASSET SYSTEM WOOOOOOOOHOOOOOOOOOOOOOOOOOOOOOOOOO
Diffstat (limited to 'src/tiled/tiled.odin')
-rw-r--r--src/tiled/tiled.odin628
1 files changed, 0 insertions, 628 deletions
diff --git a/src/tiled/tiled.odin b/src/tiled/tiled.odin
deleted file mode 100644
index d84c296..0000000
--- a/src/tiled/tiled.odin
+++ /dev/null
@@ -1,628 +0,0 @@
-package tiled
-
-import os "core:os/os2"
-import mem "core:mem"
-import strings "core:strings"
-import "core:path/filepath"
-import "core:log"
-import "core:encoding/json"
-
-import rl "vendor:raylib"
-
-Color :: [4]f32
-
-Error :: enum {
- NONE = 0,
- COULD_NOT_LOAD,
- NON_ORTHOGONAL_NOT_SUPPORTED,
- INFINITE_NOT_SUPPORTED,
- ELLIPSE_OBJ_NOT_SUPPORTED,
- POLYGON_OBJ_NOT_SUPPORTED,
- POLYLINE_OBJ_NOT_SUPPORTED,
- TEXT_OBJ_NOT_SUPPORTED,
-}
-
-Axis :: enum {
- X,
- Y,
-}
-
-Properties :: map[string]any
-
-Map :: struct {
- // Currently, only orthogonal maps are allowed. Any non-orthogonal maps
- // throw an error.
- // Infinite maps will also throw an error for now.
-
- background_color: Color,
- class: string,
-
- width: i32,
- height: i32,
-
- layers: []Layer,
-
- next_layer_id: i32,
- next_object_id: i32,
-
- parallax_origin_x: f64,
- parallax_origin_y: f64,
-
- properties: Properties,
-
- // stagger_axis: Axis,
- // stagger_offset: i32, // To replace stagger index.
-
- tile_width: i32,
- tile_height: i32,
-
- tile_sets: []Tile_Set,
-
- tiles: [dynamic]Tile,
-}
-
-Layer :: struct {
- // Layers that aren't visible are entirely ignored.
- name: string,
- properties: Properties,
-
- parallax_x: f64,
- parallax_y: f64,
-
- tint: Color,
- id: i32,
-
- layer: union #no_nil {
- Tile_Layer,
- Image_Layer,
- Object_Layer,
- }
-}
-
-Tile_Layer :: struct {
- // Data will automatically become uncompressed.
- width: i32,
- height: i32,
- data: []i32,
-}
-
-Image_Layer :: struct {
- texture: rl.Texture2D,
- transparent_color: Color,
- repeat_x: bool,
- repeat_y: bool,
-}
-
-Object_Layer :: []Object
-
-Object_Type :: enum {
- POINT,
- TILE,
- RECT,
-}
-
-Object :: struct {
- // For now, anything that *isn't* one of these is ignored and
- // a warning is thrown:
- // - Point
- // - Tile
- // - Rectangle
- //
- // Objects that aren't visible will be ignored entirely.
-
- type: Object_Type,
- name: string,
- class: string,
- properties: Properties,
- position: [2]f32,
- size: [2]f32,
- tile_id: i32,
-}
-
-Tile_Set :: struct {
- // For now, any autotiling information is ignored.
-
- properties: Properties,
-
- rows: i32,
- columns: i32,
-
- first_gid: i32,
-
- texture: rl.Texture2D,
- margin: i32,
- spacing: i32,
-
- tile_count: i32,
- tile_width: i32,
- tile_height: i32,
- tile_offset: [2]i32, // in pixels
-
- tiles: []i32, // array of GIDs
-}
-
-Tile :: struct {
- // For now, animations are ignored. Support in the future is somewhat likely.
- // And similar to above, autotiling information is ignored.
-
- is_image_collection: bool,
-
- tile_set: i32, // index for the tile set in Map
-
- id: i32,
- gid: i32,
-
- texture: Maybe(rl.Texture2D), // If the tile is part of an image collection.
-
- // Where on the texture is this tile
- src_start: [2]i32,
- src_size: [2]i32,
-
- object_group: Layer, // Object layer for collisions.
-
- properties: Properties,
-}
-
-load_map :: proc(path: string) -> (Map, Error) {
- defer free_all(context.temp_allocator)
-
- jmap_text, read_err := os.read_entire_file(path, context.temp_allocator)
- if read_err != nil {
- log.errorf("Failed to read file %v (%v)", path, read_err)
- return {}, .COULD_NOT_LOAD
- }
-
- jmap: Json_Map
- unmarshal_err := json.unmarshal(
- jmap_text,
- &jmap,
- allocator = context.temp_allocator,
- )
- if unmarshal_err != nil {
- log.errorf("Failed to unmarshal file %v (%v)", path, unmarshal_err)
- return {}, .COULD_NOT_LOAD
- }
-
- // log.debug(jmap)
-
- tmap: Map
- err := convert_json_map(jmap, &tmap, path)
- if err != .NONE {
- return {}, err
- }
- return tmap, .NONE
-}
-
-delete_map :: proc(tmap: Map) {
- delete(tmap.class)
- delete(tmap.properties)
-
- for layer in tmap.layers {
- delete_layer(layer)
- }
- delete(tmap.layers)
-
- for tile_set in tmap.tile_sets {
- delete(tile_set.properties)
- delete(tile_set.tiles) // all tiles are deleted later
- rl.UnloadTexture(tile_set.texture)
- }
- delete(tmap.tile_sets)
-
- for tile in tmap.tiles {
- delete(tile.properties)
-
- if tile.texture != nil {
- rl.UnloadTexture(tile.texture.(rl.Texture2D))
- }
-
- delete_layer(tile.object_group)
- }
- delete(tmap.tiles)
-}
-
-@(private)
-delete_layer :: proc(layer: Layer) {
- delete(layer.name)
- delete(layer.properties)
-
- switch l in layer.layer {
- case Tile_Layer:
- delete(l.data)
- case Image_Layer:
- rl.UnloadTexture(l.texture)
- case Object_Layer:
- for obj in l {
- delete(obj.name)
- delete(obj.class)
- delete(obj.properties)
- }
- delete(l)
- }
-}
-
-@(private)
-convert_json_color :: proc(jcolor: string) -> Color {
- return Color{1, 1, 1, 1}
-}
-
-@(private)
-convert_json_properties :: proc(jprops: []Json_Property) -> Properties {
- props := make(Properties)
-
- for jprop in jprops {
- props[jprop.name] = jprop.value
- }
-
- return props
-}
-
-@(private)
-convert_json_map :: proc(jmap: Json_Map, tmap: ^Map, path: string) -> Error {
- // ensure the map is orthogonal
- if strings.compare(jmap.orientation, "orthogonal") != 0 {
- return .NON_ORTHOGONAL_NOT_SUPPORTED
- }
-
- // ensure the map is not infinite
- if jmap.infinite {
- return .INFINITE_NOT_SUPPORTED
- }
-
- tmap.background_color = convert_json_color(jmap.backgroundcolor)
- tmap.class = strings.clone(jmap.class)
-
- tmap.width = jmap.width
- tmap.height = jmap.height
-
- tmap.tile_width = jmap.tilewidth
- tmap.tile_height = jmap.tileheight
-
- tmap.next_layer_id = jmap.nextlayerid
- tmap.next_object_id = jmap.nextobjectid
-
- tmap.parallax_origin_x = jmap.parallaxoriginx
- tmap.parallax_origin_y = jmap.parallaxoriginy
-
- tmap.properties = convert_json_properties(jmap.properties)
-
- // TODO: flatten groups
- layer_count := len(jmap.layers)
- for jlayer in jmap.layers {
- layer_count += len(jlayer.layers) // take into consideration groups
- }
-
- tmap.layers = make([]Layer, layer_count)
- current_index := 0
-
- for jlayer in jmap.layers {
- if !jlayer.visible {
- continue // ignore hidden layers
- }
-
- // FIXME: Some duplicated code down here
- if strings.compare(jlayer.type, "group") == 0 {
- for jlayer2 in jlayer.layers {
- if !jlayer2.visible {
- continue // ignore hidden layers
- }
-
- layer, err := convert_json_layer(jlayer2)
- if err != .NONE {
- return err
- }
- tmap.layers[current_index] = layer
- current_index += 1
- }
- continue
- }
-
- layer, err := convert_json_layer(jlayer)
- if err != .NONE {
- return err
- }
- tmap.layers[current_index] = layer
- current_index += 1
- }
-
- tmap.tile_sets = make([]Tile_Set, len(jmap.tilesets))
-
- res_dir := filepath.dir(path, allocator = context.temp_allocator)
-
- for jtile_set, i in jmap.tilesets {
- tile_set, err := convert_json_tile_set(tmap, res_dir, jtile_set)
- if err != .NONE {
- return err
- }
- tmap.tile_sets[i] = tile_set
-
- for j in 0..<len(tmap.tiles) {
- tmap.tiles[int(tile_set.first_gid) + j].tile_set = i32(i)
- }
- }
-
- return .NONE
-}
-
-Map_Iterate_Callback :: proc(i32, i32, Tile, Tile_Set)
-
-iterate_map_tiles :: proc(tmap: Map, callback: Map_Iterate_Callback) {
- for layer in tmap.layers {
- tile_layer, ok := layer.layer.(Tile_Layer)
- if !ok {
- continue
- }
-
- x: i32 = 0
- y: i32 = 0
-
- for cell, i in tile_layer.data {
- if cell > 0 {
- tile := tmap.tiles[cell - 1]
- tile_set := tmap.tile_sets[tile.tile_set]
- callback(x, y, tile, tile_set)
- }
-
- x += tmap.tile_width
- if x > (tmap.width - 1) * tmap.tile_width {
- x = 0
- y += tmap.tile_height
- }
- }
- }
-}
-
-test_cells :: proc(tmap: Map) {
- for layer in tmap.layers {
- tile_layer, ok := layer.layer.(Tile_Layer)
- if !ok {
- continue
- }
-
- x: i32 = 0
- y: i32 = 0
-
- for cell, i in tile_layer.data {
- if cell > 0 {
- log.debug(i, [2]i32{x, y}, cell)
- }
-
- x += tmap.tile_width
- if x > (tmap.width - 1) * tmap.tile_width {
- x = 0
- y += tmap.tile_height
- }
- }
- }
-}
-
-draw_map :: proc(tmap: Map) {
- draw_tile :: proc(x: i32, y: i32, tile: Tile, tile_set: Tile_Set) {
- rl.DrawTexturePro(
- tile_set.texture,
- rl.Rectangle{
- x = f32(tile.src_start.x),
- y = f32(tile.src_start.y),
- width = f32(tile.src_size.x),
- height = f32(tile.src_size.y),
- },
- rl.Rectangle{
- x = f32(x),
- y = f32(y),
- width = f32(tile.src_size.x),
- height = f32(tile.src_size.y),
- },
- {0, 0},
- 0,
- rl.WHITE,
- )
- }
-
- iterate_map_tiles(tmap, draw_tile)
-}
-
-@(private)
-load_image :: proc(filename: string, res_dir: string) -> rl.Texture2D {
- path := strings.concatenate({res_dir, "/", filename})
- defer delete(path)
-
- byte_path := make([]u8, len(path) + 1, context.temp_allocator)
- copy(byte_path, path)
- byte_path[len(path)] = 0
- return rl.LoadTexture(transmute(cstring)&byte_path[0])
-}
-
-@(private)
-convert_json_layer :: proc(jlayer: Json_Layer) -> (Layer, Error) {
- // TODO: uncompress tile data
-
- layer: Layer
-
- layer.name = strings.clone(jlayer.name)
-
- layer.parallax_x = jlayer.parallaxx
- layer.parallax_y = jlayer.parallaxy
-
- layer.id = jlayer.id
-
- layer.tint = convert_json_color(jlayer.tintcolor)
-
- layer.properties = convert_json_properties(jlayer.properties)
-
- switch jlayer.type {
- case "tilelayer":
- tile_layer := Tile_Layer{
- width = jlayer.width,
- height = jlayer.height,
- }
-
- data := jlayer.data.([]i32)
- tile_layer.data = make([]i32, len(data))
- copy(tile_layer.data, data)
-
- layer.layer = tile_layer
-
- case "objectgroup":
- obj_layer := make(Object_Layer, len(jlayer.objects))
-
- for jobj, i in jlayer.objects {
- if !jobj.visible {
- continue // ignore hidden objects
- }
-
- obj, err := convert_json_object(jobj)
- if err != .NONE {
- return {}, err
- }
- obj_layer[i] = obj
- }
-
- layer.layer = obj_layer
-
- case "imagelayer":
- image_layer := Image_Layer{
- texture = load_image(jlayer.image, "res"),
- transparent_color = convert_json_color(jlayer.transparentcolor),
- repeat_x = jlayer.repeatx,
- repeat_y = jlayer.repeaty,
- }
-
- layer.layer = image_layer
-
- case "group":
- // groups are handled elsewhere
- }
-
- return layer, .NONE
-}
-
-@(private)
-convert_json_object :: proc(jobj: Json_Object) -> (Object, Error) {
- obj: Object
-
- if jobj.ellipse {
- return {}, .ELLIPSE_OBJ_NOT_SUPPORTED
- }
- if jobj.polygon != nil {
- return {}, .POLYGON_OBJ_NOT_SUPPORTED
- }
- if jobj.polyline != nil {
- return {}, .POLYLINE_OBJ_NOT_SUPPORTED
- }
- if jobj.text != nil {
- return {}, .TEXT_OBJ_NOT_SUPPORTED
- }
-
- obj.position = {
- f32(jobj.x),
- f32(jobj.y),
- }
- obj.size = {
- f32(jobj.width),
- f32(jobj.height),
- }
- obj.tile_id = jobj.gid
-
- obj.name = strings.clone(jobj.name)
- obj.class = strings.clone(jobj.type)
- obj.properties = convert_json_properties(jobj.properties)
-
- return obj, .NONE
-}
-
-@(private)
-convert_json_tile_set :: proc(
- tmap: ^Map,
- res_dir: string,
- jtile_set: Json_Tile_Set,
-) -> (Tile_Set, Error) {
- if len(jtile_set.source) > 0 {
- // Tileset links somewhere else
- path := strings.concatenate({res_dir, "/", jtile_set.source})
- defer delete(path)
-
- data, err := os.read_entire_file(path, allocator = context.temp_allocator)
- if err != nil {
- log.errorf("Could not load external tile set '%v'", path)
- return {}, .COULD_NOT_LOAD
- }
-
- new_jtile_set: Json_Tile_Set
- marshal_err := json.unmarshal(
- data,
- &new_jtile_set,
- allocator = context.temp_allocator,
- )
- if marshal_err != nil {
- log.errorf("Could not unmarshal external tile set '%v'", path)
- return {}, .COULD_NOT_LOAD
- }
-
- return convert_json_tile_set(tmap, res_dir, new_jtile_set)
- }
-
- tile_set: Tile_Set
-
- tile_set.rows = jtile_set.rows
- tile_set.columns = jtile_set.columns
-
- tile_set.first_gid = jtile_set.firstgid
-
- tile_set.texture = load_image(jtile_set.image, res_dir)
- tile_set.margin = jtile_set.margin
- tile_set.spacing = jtile_set.spacing
-
- tile_set.tile_count = jtile_set.tilecount
- tile_set.tile_width = jtile_set.tilewidth
- tile_set.tile_height = jtile_set.tileheight
- tile_set.tile_offset = {
- jtile_set.tileoffset.x,
- jtile_set.tileoffset.y,
- }
-
- tile_set.properties = convert_json_properties(jtile_set.properties)
-
- tile_set.tiles = make([]i32, jtile_set.tilecount)
-
- // Ignore margin and spacing for now
- // TODO: account for margin and spacing
- tile_x := tile_set.texture.width / tile_set.tile_width
- tile_y := tile_set.texture.height / tile_set.tile_height
-
- current_index := 0
- for y in 0..<tile_y {
- for x in 0..<tile_x {
- tile: Tile
-
- tile.id = i32(current_index)
-
- tile.src_start = {
- x * tile_set.tile_width,
- y * tile_set.tile_height,
- }
- tile.src_size = {
- tile_set.tile_width,
- tile_set.tile_height,
- }
-
- current_index += 1
-
- tile.gid = i32(len(tmap.tiles))
- append(&tmap.tiles, tile)
-
- tile_set.tiles[current_index - 1] = tile.gid
- }
- }
-
- for jtile in jtile_set.tiles {
- ttile := &tmap.tiles[tile_set.tiles[jtile.id]]
- object_group, err := convert_json_layer(jtile.objectgroup)
- if err != .NONE {
- return {}, err
- }
- ttile.object_group = object_group
- ttile.properties = convert_json_properties(jtile.properties)
- }
-
- return tile_set, .NONE
-}