diff options
Diffstat (limited to 'tools/compile_assets/loaders.odin')
| -rw-r--r-- | tools/compile_assets/loaders.odin | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/tools/compile_assets/loaders.odin b/tools/compile_assets/loaders.odin new file mode 100644 index 0000000..136ba07 --- /dev/null +++ b/tools/compile_assets/loaders.odin @@ -0,0 +1,199 @@ +package assets_gen + +import os "core:os/os2" +import "core:fmt" +import "core:strings" +import "core:path/filepath" +import "core:image" +import "core:image/png" +import "core:image/qoi" + +import ase "aseprite" +import aseutil "aseprite/utils" + +load_map :: proc(path: string, _: ^os.File, _: ^os.File) { + line := fmt.aprintf("#load(\"%v\")", path) + maps[filepath.stem(path)] = line + paths_to_res_type[path] = "Map_Id" +} + +load_tileset :: proc(path: string, _: ^os.File, _: ^os.File) { + line := fmt.aprintf("#load(\"%v\")", path) + tilesets[filepath.stem(path)] = line + paths_to_res_type[path] = "Tileset_Id" +} + +load_qoi :: proc(path: string, qoi: ^os.File, output: ^os.File) { + line := fmt.aprintf("{{data = #load(%w)}}", path) + + images[filepath.stem(path)] = line + paths_to_res_type[path] = "Image_Id" +} + +load_png :: proc(path: string, png_file: ^os.File, output: ^os.File) { + // Convert all PNG files to QOI and store those + + png_bytes, read_err := os.read_entire_file(png_file, context.allocator) + if read_err != nil { + die("Could not read file (%v)", read_err) + } + defer delete(png_bytes) + + img, png_err := png.load_from_bytes(png_bytes) + if png_err != nil { + die("Could not parse file (%v)", png_err) + } + defer image.destroy(img) + + info, fi_err := os.fstat(png_file, allocator = context.temp_allocator) + if fi_err != nil { + die("Could not load file info (%v)", fi_err) + } + + compiled_path := strings.concatenate( + {COMPILED_DIR, filepath.stem(info.name), ".qoi"}, + allocator = context.temp_allocator, + ) + qoi_err := qoi.save_to_file(compiled_path, img) + + if qoi_err != nil { + die("Could not convert PNG to QOI (%v)", qoi_err) + } + + absolute_path, abs_ok := filepath.abs( + compiled_path, + allocator = context.temp_allocator, + ) + if !abs_ok { + die("Could not find absolute path to a compiled file (%v)", compiled_path) + } + + line := fmt.aprintf("{{data = #load(%w)}}", absolute_path) + + images[filepath.stem(path)] = line + paths_to_res_type[path] = "Image_Id" +} + +@(private="file") +load_sprite_sheet :: proc(path: string, doc: ^ase.Document) { + sprite_sheet, ss_err := aseutil.create_sprite_sheet(doc, { + size = {int(doc.header.width), int(doc.header.height)}, + count = int(doc.header.frames), + }) + if ss_err != nil { + die( + "Could not create sprite sheet from aseprite file %v (%v)", + path, + ss_err, + ) + } + defer aseutil.destroy(sprite_sheet) + + fmt.println("loaded ss") + + pixels := make( + []image.RGBA_Pixel, + sprite_sheet.width * sprite_sheet.height, + allocator = context.temp_allocator, + ) + + i := 0 + for i < sprite_sheet.width * sprite_sheet.height { + channel := i * 4 + pixels[i].r = sprite_sheet.data[channel + 0] + pixels[i].g = sprite_sheet.data[channel + 1] + pixels[i].b = sprite_sheet.data[channel + 2] + pixels[i].a = sprite_sheet.data[channel + 3] + i += 1 + } + + img, img_ok := image.pixels_to_image( + pixels, + sprite_sheet.width, + sprite_sheet.height, + ) + if !img_ok { + die("Could not create sprite sheet image %v", path) + } + + compiled_path := strings.concatenate( + {COMPILED_DIR, filepath.stem(path), "-sheet.qoi"}, + allocator = context.temp_allocator, + ) + qoi_err := qoi.save_to_file(compiled_path, &img) + + if qoi_err != nil { + die("Could not save spritesheet %v (%v)", path, qoi_err) + } + + absolute_path, abs_ok := filepath.abs( + compiled_path, + allocator = context.temp_allocator, + ) + if !abs_ok { + die("Could not find absolute path to a compiled file (%v)", compiled_path) + } + + line := fmt.aprintf("{{data = #load(%w)}}", absolute_path) + images[filepath.stem(path)] = line + paths_to_res_type[path] = "Image_Id" +} + +@(private="file") +load_animation :: proc(path: string, doc: ^ase.Document) { + tags: map[string]struct{ + from: i32, + to: i32, + } + defer delete(tags) + + for frame in doc.frames { + for chunk in frame.chunks { + bin_tags, is_tags := chunk.(ase.Tags_Chunk) + if !is_tags { + continue + } + + for bin_tag in bin_tags { + tags[bin_tag.name] = { + from = i32(bin_tag.from_frame), + to = i32(bin_tag.to_frame), + } + } + } + } + + frame_durations := make([]i32, doc.header.frames) + defer delete(frame_durations) + + i := 0 + for frame in doc.frames { + frame_durations[i] = i32(frame.header.duration) + i += 1 + } + + line := fmt.aprintf( + "{{frame_count = %w, frame_durations = %w, tags = %w}}", + len(frame_durations), + frame_durations[:], + tags, + ) + + animations[filepath.stem(path)] = line +} + +load_ase :: proc(path: string, ase_file: ^os.File, output: ^os.File) { + doc: ase.Document + defer ase.destroy_doc(&doc) + + unmarshal_err := ase.unmarshal(&doc, path, alloc = context.temp_allocator) + if unmarshal_err != nil { + die("Could not unmarshal aseprite file %v (%v)", path, unmarshal_err) + } + + // Load sprite sheet + load_sprite_sheet(path, &doc) + + // Load animation + load_animation(path, &doc) +} |
