diff options
| author | Xander Swan <[hidden email]> | 2026-01-07 23:12:22 -0500 |
|---|---|---|
| committer | Xander Swan <[hidden email]> | 2026-01-07 23:12:22 -0500 |
| commit | 0988ab832bfc7a1b1c851125b6172cf68c6d9cb9 (patch) | |
| tree | 460bc2d9f0bce463af273d6b2b2c20faa880ac29 /tools/compile_assets/aseprite/marshal.odin | |
| parent | ade0dc4d257d053b7064184f193f8168c496e308 (diff) | |
doesn't compile but i'm commiting anywya
Diffstat (limited to 'tools/compile_assets/aseprite/marshal.odin')
| -rw-r--r-- | tools/compile_assets/aseprite/marshal.odin | 549 |
1 files changed, 549 insertions, 0 deletions
diff --git a/tools/compile_assets/aseprite/marshal.odin b/tools/compile_assets/aseprite/marshal.odin new file mode 100644 index 0000000..1b56de1 --- /dev/null +++ b/tools/compile_assets/aseprite/marshal.odin @@ -0,0 +1,549 @@ +package aseprite_file_handler + +import "core:io" +import "core:os" +import "core:log" +import "core:bytes" +import "core:bufio" +import "vendor:zlib" + + +marshal_to_bytes_buff :: proc(doc: ^Document, b: ^bytes.Buffer, allocator := context.allocator)-> (file_size: int, err: Marshal_Error) { + w, ok := io.to_writer(bytes.buffer_to_stream(b)) + if !ok { + return file_size, .Unable_Make_Writer + } + return marshal(doc, w, allocator) +} + +marshal_to_handle :: proc(doc: ^Document, h: os.Handle, allocator := context.allocator)-> (file_size: int, err: Marshal_Error) { + w, ok := io.to_writer(os.stream_from_handle(h)) + if !ok { + return file_size, .Unable_Make_Writer + } + return marshal(doc, w, allocator) +} + +marshal_to_slice :: proc(doc: ^Document, b: []byte, allocator := context.allocator)-> (file_size: int, err: Marshal_Error) { + buf: bytes.Buffer + defer bytes.buffer_destroy(&buf) + file_size = marshal(doc, &buf, allocator) or_return + if len(b) < len(buf.buf[buf.off:]) { + return file_size, Marshal_Errors.Buffer_Not_Big_Enough + } + copy_slice(b[:], buf.buf[buf.off:]) + return +} + +marshal_to_dynamic :: proc(doc: ^Document, b: ^[dynamic]byte, allocator := context.allocator)-> (file_size: int, err: Marshal_Error) { + buf: bytes.Buffer + defer bytes.buffer_destroy(&buf) + file_size = marshal(doc, &buf, allocator) or_return + append(b, ..buf.buf[:]) + return +} + +marshal_to_bufio :: proc(doc: ^Document, w: ^bufio.Writer, allocator := context.allocator) -> (file_size: int, err: Marshal_Error) { + ww, ok := io.to_writer(bufio.writer_to_stream(w)) + if !ok { + return file_size, .Unable_Make_Writer + } + return marshal(doc, ww, allocator) +} + +marshal :: proc{ + marshal_to_bytes_buff, marshal_to_slice, marshal_to_handle, + marshal_to_dynamic, marshal_to_bufio, marshal_to_writer, +} + +marshal_to_writer :: proc(doc: ^Document, ww: io.Writer, allocator := context.allocator) -> (file_size: int, err: Marshal_Error) { + ud_map_warn: bool + s := &file_size + b: bytes.Buffer + defer bytes.buffer_destroy(&b) + + w, ok := io.to_writer(bytes.buffer_to_stream(&b)) + if !ok { + return file_size, .Unable_Make_Writer + } + + write(w, FILE_MAGIC_NUM, s) or_return + write(w, WORD(len(doc.frames)), s) or_return + write(w, doc.header.width, s) or_return + write(w, doc.header.height, s) or_return + write(w, WORD(doc.header.color_depth), s) or_return + write(w, transmute(DWORD)doc.header.flags, s) or_return + write(w, doc.header.speed, s) or_return + write_skip(w, 8, s) or_return + write(w, doc.header.transparent_index, s) or_return + write_skip(w, 3, s) or_return + write(w, doc.header.num_of_colors, s) or_return + write(w, doc.header.ratio_width, s) or_return + write(w, doc.header.ratio_height, s) or_return + write(w, doc.header.x, s) or_return + write(w, doc.header.y, s) or_return + write(w, doc.header.grid_width, s) or_return + write(w, doc.header.grid_height, s) or_return + write_skip(w, 84, s) or_return + + for frame in doc.frames { + fb: bytes.Buffer + defer bytes.buffer_destroy(&fb) + + fw, ok2 := io.to_writer(bytes.buffer_to_stream(&fb)) + if !ok2 { + return file_size, .Unable_Make_Writer + } + + frame_size: int + fs := &frame_size + + write(fw, FRAME_MAGIC_NUM, fs) or_return + write(fw, frame.header.old_num_of_chunks, fs) or_return + write(fw, frame.header.duration, fs) or_return + write_skip(fw, 2, fs) or_return + write(fw, frame.header.num_of_chunks, fs) or_return + + for chunk in frame.chunks { + cb: bytes.Buffer + defer bytes.buffer_destroy(&cb) + + cw, ok3 := io.to_writer(bytes.buffer_to_stream(&cb)) + if !ok3 { + return file_size, .Unable_Make_Writer + } + + chunk_size: int + cs := &chunk_size + + chunk_type := get_chunk_type(chunk) or_return + write(cw, chunk_type, cs) or_return + + switch val in chunk { + case Old_Palette_256_Chunk: + write(cw, WORD(len(val)), cs) or_return + + for p in val { + write(cw, p.entries_to_skip, cs) or_return + if len(p.colors) > 256 { + return file_size, .Invalid_Old_Palette + + } else if len(p.colors) == 256 { + write_byte(cw, 0, cs) or_return + + } else { + write(cw, p.num_colors, cs) or_return + } + + for c in p.colors { + write(cw, c[2], cs) or_return + write(cw, c[1], cs) or_return + write(cw, c[0], cs) or_return + } + } + + case Old_Palette_64_Chunk: + write(cw, WORD(len(val)), cs) or_return + + for p in val { + write(cw, p.entries_to_skip, cs) or_return + + if len(p.colors) > 256 { + return file_size, .Invalid_Old_Palette + + } else if len(p.colors) == 256 { + write_byte(cw, 0, cs) or_return + + } else { + write(cw, p.num_colors, cs) or_return + } + + for c in p.colors { + write(cw, c[2], cs) or_return + write(cw, c[1], cs) or_return + write(cw, c[0], cs) or_return + } + } + case Layer_Chunk: + write(cw, transmute(WORD)val.flags, cs) or_return + write(cw, WORD(val.type), cs) or_return + write(cw, val.child_level, cs) or_return + write(cw, val.default_width, cs) or_return + write(cw, val.default_height, cs) or_return + write(cw, WORD(val.blend_mode), cs) or_return + write(cw, val.opacity, cs) or_return + write_skip(cw, 3, cs) or_return + write(cw, val.name, cs) or_return + + if val.type == .Tilemap { + write(cw, val.tileset_index, cs) or_return + } + + case Cel_Chunk: + write(cw, val.layer_index, cs) or_return + write(cw, val.x, cs) or_return + write(cw, val.y, cs) or_return + write(cw, val.opacity_level, cs) or_return + + cel_type := get_cel_type(val.cel) or_return + write(cw, cel_type, cs) or_return + write(cw, val.z_index, cs) or_return + write_skip(cw, 5, cs) or_return + + switch cel in val.cel { + case Raw_Cel: + write(cw, cel.width, cs) or_return + write(cw, cel.height, cs) or_return + write(cw, cel.pixels[:], cs) or_return + + case Linked_Cel: + write(cw, WORD(cel), cs) or_return + + case Com_Image_Cel: + write(cw, cel.width, cs) or_return + write(cw, cel.height, cs) or_return + + com_buf := make([]byte, len(cel.pixels)+64, allocator) or_return + defer delete(com_buf) + + data_rd: [^]u8 = raw_data(cel.pixels[:]) + com_buf_rd: [^]u8 = raw_data(com_buf[:]) + + config := zlib.z_stream { + avail_in=zlib.uInt(len(cel.pixels)), + next_in=&data_rd[0], + avail_out=zlib.uInt(len(com_buf)), + next_out=&com_buf_rd[0], + } + + en := zlib.deflateInit(&config, zlib.DEFAULT_COMPRESSION) + if en < zlib.OK { + return file_size, ZLIB_Errors(en) + } + + en = zlib.deflate(&config, zlib.FINISH) + if en < zlib.OK { + return file_size, ZLIB_Errors(en) + } + + en = zlib.deflateEnd(&config) + if en < zlib.OK { + return file_size, ZLIB_Errors(en) + } + + write(cw, com_buf[:int(config.total_out)], cs) or_return + + case Com_Tilemap_Cel: + write(cw, cel.width, cs) or_return + write(cw, cel.height, cs) or_return + write(cw, cel.bits_per_tile, cs) or_return + write(cw, DWORD(cel.bitmask_id), cs) or_return + write(cw, cel.bitmask_x, cs) or_return + write(cw, cel.bitmask_y, cs) or_return + write(cw, cel.bitmask_diagonal, cs) or_return + write_skip(cw, 10, cs) or_return + + buf := make([]u8, len(cel.tiles)*4, allocator) or_return + defer delete(buf) + + n := tiles_to_u8(cel.tiles[:], buf[:]) or_return + com_buf := make([]byte, n+64, allocator) or_return + defer delete(com_buf) + + data_rd: [^]u8 = raw_data(buf[:n]) + com_buf_rd: [^]u8 = raw_data(com_buf[:]) + + config := zlib.z_stream { + avail_in=zlib.uInt(n), + next_in=&data_rd[0], + avail_out=zlib.uInt(len(com_buf)), + next_out=&com_buf_rd[0], + } + + en := zlib.deflateInit(&config, zlib.DEFAULT_COMPRESSION) + if en < zlib.OK { + return file_size, ZLIB_Errors(en) + } + + en = zlib.deflate(&config, zlib.FINISH) + if en < zlib.OK { + return file_size, ZLIB_Errors(en) + } + + en = zlib.deflateEnd(&config) + if en < zlib.OK { + return file_size, ZLIB_Errors(en) + } + + write(cw, com_buf[:int(config.total_out)], cs) or_return + + case: + return file_size, .Invalid_Cel_Type + } + + case Cel_Extra_Chunk: + write(cw, transmute(WORD)val.flags, cs) or_return + write(cw, val.x, cs) or_return + write(cw, val.y, cs) or_return + write(cw, val.width, cs) or_return + write(cw, val.width, cs) or_return + write_skip(cw, 16, cs) or_return + + case Color_Profile_Chunk: + if val.icc != nil { + write(cw, WORD(Color_Profile_Type.ICC), cs) or_return + } else { + write(cw, WORD(val.type), cs) or_return + } + + write(cw, transmute(WORD)val.flags, cs) or_return + write(cw, val.fixed_gamma, cs) or_return + write_skip(cw, 8, cs) or_return + + #partial switch v in val.icc { + case ICC_Profile: + write(cw, DWORD(len(v)), cs) or_return + write(cw, cast([]u8)v[:], cs) or_return + } + + case External_Files_Chunk: + write(cw, DWORD(len(val)), cs) or_return + write_skip(cw, 8, cs) or_return + + for file in val { + write(cw, file.id, cs) or_return + write(cw, BYTE(file.type), cs) or_return + write_skip(cw, 7, cs) or_return + write(cw, file.file_name_or_id, cs) or_return + } + + case Mask_Chunk: + write(cw, val.x, cs) or_return + write(cw, val.y, cs) or_return + write(cw, val.width, cs) or_return + write(cw, val.height, cs) or_return + write_skip(cw, 8, cs) or_return + write(cw, val.name, cs) or_return + write(cw, val.bit_map_data[:], cs) or_return + + case Path_Chunk: + + case Tags_Chunk: + write(cw, WORD(len(val)), cs) or_return + write_skip(cw, 8, cs) or_return + + for tag in val { + write(cw, tag.from_frame, cs) or_return + write(cw, tag.to_frame, cs) or_return + write(cw, BYTE(tag.loop_direction), cs) or_return + write(cw, tag.repeat, cs) or_return + write_skip(cw, 6, cs) or_return + write(cw, tag.tag_color[2], cs) or_return + write(cw, tag.tag_color[1], cs) or_return + write(cw, tag.tag_color[0], cs) or_return + write(cw, BYTE(0), cs) or_return + write(cw, tag.name, cs) or_return + } + + case Palette_Chunk: + write(cw, DWORD(len(val.entries)), cs) or_return + write(cw, val.first_index, cs) or_return + write(cw, val.last_index, cs) or_return + write_skip(cw, 8, cs) or_return + + for entry in val.entries { + if entry.name != nil { + write(cw, WORD(1), cs) or_return + } else { + write(cw, WORD(0), cs) or_return + } + + write(cw, entry.color[3], cs) or_return + write(cw, entry.color[2], cs) or_return + write(cw, entry.color[1], cs) or_return + write(cw, entry.color[0], cs) or_return + + #partial switch v in entry.name { + case string: + write(cw, v, cs) or_return + } + } + + case User_Data_Chunk: + flags: UD_Flags + if val.text != nil { flags += {.Text} } + if val.color != nil { flags += {.Color} } + if val.maps != nil { flags += {.Properties} } + + write(cw, transmute(DWORD)flags, cs) or_return + + switch v in val.text { + case string: + write(cw, v, cs) or_return + } + + switch v in val.color { + case Color_RGBA: + write(cw, v[3], cs) or_return + write(cw, v[2], cs) or_return + write(cw, v[1], cs) or_return + write(cw, v[0], cs) or_return + } + + switch m in val.maps { + case Properties_Map: + if !ud_map_warn { + log.warn("Writing User Data Maps may still have bugs.") + ud_map_warn = true + } + + mb: bytes.Buffer + defer bytes.buffer_destroy(&mb) + mw, ok4 := io.to_writer(bytes.buffer_to_stream(&mb)) + if !ok4 { + return file_size, .Unable_Make_Writer + } + map_size: int + ms := &map_size + write(mw, DWORD(len(m)), ms) or_return + + for key, val in m { + write(mw, key, ms) or_return + val := val.(Properties) + write(mw, DWORD(len(val)), ms) + for name, type in val { + _, err = write(mw, name, ms) + if err != nil { + log.error("Failed to write key", key) + return + } + write(mw, get_property_type(type) or_return, ms) + write(mw, type, ms) or_return + } + } + + map_size += 4 + write(cw, DWORD(map_size), cs) or_return + write(cw, mb.buf[:map_size-4], cs) or_return + } + + case Slice_Chunk: + write(cw, DWORD(len(val.keys)), cs) or_return + + flags := val.flags + if len(val.keys) != 0 { + key := val.keys[0] + if key.center != nil { + flags += {.Patched_slice} + } + if key.pivot != nil { + flags += {.Pivot_Information} + } + } + write(cw, transmute(DWORD)flags, cs) or_return + + write(cw, DWORD(0), cs) or_return + write(cw, val.name, cs) or_return + + for key in val.keys { + write(cw, key.frame_num, cs) or_return + write(cw, key.x, cs) or_return + write(cw, key.y, cs) or_return + write(cw, key.width, cs) or_return + write(cw, key.height, cs) or_return + + #partial switch v in key.center { + case Slice_Center: + write(cw, v.x, cs) or_return + write(cw, v.y, cs) or_return + write(cw, v.width, cs) or_return + write(cw, v.height, cs) or_return + } + + #partial switch v in key.pivot { + case Slice_Pivot: + write(cw, v.x, cs) or_return + write(cw, v.y, cs) or_return + } + } + + case Tileset_Chunk: + write(cw, val.id, cs) or_return + + flags := val.flags + if val.compressed != nil { + flags += {.Include_Tiles_Inside_This_File} + } + if val.external != nil { + flags += {.Include_Link_To_External_File} + } + write(cw, transmute(DWORD)flags, cs) or_return + + write(cw, val.num_of_tiles, cs) or_return + write(cw, val.width, cs) or_return + write(cw, val.height, cs) or_return + write(cw, val.base_index, cs) or_return + write_skip(cw, 14, cs) or_return + write(cw, val.name, cs) or_return + + #partial switch v in val.external { + case Tileset_External: + write(cw, v.file_id, cs) or_return + write(cw, v.tileset_id, cs) or_return + } + + #partial switch v in val.compressed { + case Tileset_Compressed: + com_buf := make([]byte, len(v), allocator) or_return + defer delete(com_buf) + data_rd: [^]u8 = raw_data(v[:]) + com_buf_rd: [^]u8 = raw_data(com_buf[:]) + + config := zlib.z_stream { + avail_in = zlib.uInt(len(v)), + next_in = &data_rd[0], + avail_out = zlib.uInt(len(v)), + next_out = &com_buf_rd[0], + } + + en := zlib.deflateInit(&config, zlib.DEFAULT_COMPRESSION) + if en < zlib.OK { + return file_size, ZLIB_Errors(en) + } + + en = zlib.deflate(&config, zlib.FINISH) + if en < zlib.OK { + return file_size, ZLIB_Errors(en) + } + + en = zlib.deflateEnd(&config) + if en < zlib.OK { + return file_size, ZLIB_Errors(en) + } + + write(cw, DWORD(config.total_out), cs) or_return + write(cw, com_buf[:int(config.total_out)], cs) or_return + } + + case: + return file_size, .Invalid_Chunk_Type + } + + write(fw, DWORD(chunk_size + 4), fs) or_return + write(fw, cb.buf[:chunk_size], fs) or_return + } + + write(w, DWORD(frame_size + 4), s) or_return + write(w, fb.buf[:frame_size], s) or_return + } + + written: int + file_size += 4 + write(ww, DWORD(file_size), &written) or_return + write(ww, b.buf[:file_size-4], &written) or_return + + if written != file_size { + return file_size, Marshal_Errors.Wrong_Write_Size + } + return +}
\ No newline at end of file |
