package assets_gen import os "core:os/os2" import "core:fmt" import "core:encoding/json" import "core:path/filepath" import "core:strings" import "core:math/bits" import "core:strconv" 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: u32, 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: union{ bool, int, string, f32, }, } 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, } tileset_gids: map[string]Gids load_json_color :: proc(hex_str: string) -> [4]f32 { if len(hex_str) == 0 { return {0, 0, 0, 1} } hex, hex_ok := strconv.parse_u64(hex_str[1:], 16) if !hex_ok { return {0, 0, 0, 1} } a := u8((hex >> 24) & 0xFF) r := u8((hex >> 16) & 0xFF) g := u8((hex >> 8) & 0xFF) b := u8(hex & 0xFF) if len(hex_str[1:]) == 2*3 { // If there wasn't an alpha channel included, assume max a = bits.U8_MAX } return { f32(r) / bits.U8_MAX, f32(g) / bits.U8_MAX, f32(b) / bits.U8_MAX, f32(a) / bits.U8_MAX, } } 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_ada_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( image_enum: string, rect: Rect, collisions: []Rect, ) -> string { line := fmt.aprintf( "{{image=.%v, rect=%w, id=%w, collisions=%w}}", image_enum, rect, len(tiles), collisions, ) append(&tiles, line) return line } load_json_imageset :: proc(path: string, json_dat: Json_Tileset) { last_id: i32 = 0 for tile in json_dat.tiles { image_enum := strings.to_ada_case( filepath.stem(tile.image), context.temp_allocator, ) collisions := make([dynamic]Rect, context.temp_allocator) for object in tile.objectgroup.objects { append( &collisions, Rect{ start = {f32(object.x), f32(object.y)}, size = {f32(object.width), f32(object.height)} }, ) } // Fill in any gaps with dummy tiles // TODO: Find a solution that doesn't involve filling my exe with zeroed // data for i in 1..<(tile.id - last_id) { append(&tiles, "") } create_tile( image_enum, Rect{ start = {0, 0}, size = {f32(tile.imagewidth), f32(tile.imageheight)}, }, collisions[:], ) last_id = tile.id } } load_json_tileset :: proc(path: string) { if filepath.stem(path) in loaded_tilesets { return } loaded_tilesets[filepath.stem(path)] = {} 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) } first_gid := u32(len(tiles)) tileset_gids[filepath.stem(path)] = { first = first_gid, last = u32(len(tiles) + int(json_dat.tilecount)), } // No image found; this is a image set if json_dat.imagewidth == 0 && json_dat.imageheight == 0 && json_dat.image == "" { load_json_imageset(path, json_dat) gids := &tileset_gids[filepath.stem(path)] gids.last = u32(len(tiles)) return } image_enum := strings.to_ada_case( filepath.stem(json_dat.image), allocator = context.temp_allocator, ) 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)} } ) } } tiles_x := json_dat.imagewidth / json_dat.tilewidth tiles_y := json_dat.imageheight / json_dat.tileheight tile_size := [2]f32{f32(json_dat.tilewidth), f32(json_dat.tileheight)} for y in 0..> 28 if flip_flags & 0b1000 != 0 { size.x *= -1 } if flip_flags & 0b0100 != 0 { size.y *= -1 } tiled_id := (obj.gid << 4) >> 4 fmt.printfln("%032b %v %v %032b %x", obj.gid, obj.gid, tiled_id, flip_flags, flip_flags) tile_id = tiled_to_real_gid[i32(tiled_id)] // tile_id = u32(obj.gid) } line := fmt.tprintf( "{{type = .%v, tile_id = %v, pos = %w, size = %w, parallax = %w, properties = %w}}", type_name, tile_id, pos, size, parallax, properties, ) append(&objects, line) } case: fmt.eprintfln("WARNING: Unsupported tile layer type '%v'", layer.type) } } objects_arr_str := "" for obj in objects { objects_arr_str = strings.concatenate({ objects_arr_str, obj, ", " }, allocator = context.temp_allocator) } line := fmt.aprintf( "{{width=%v, height=%v, tile_width=%v, tile_height=%v, layers=%w, objects={{%v}}, background_color=Color%w, background_images={{}} }}", width, height, tile_width, tile_height, layers[:], objects_arr_str, color, ) rooms[filepath.stem(path)] = line }