From 52364f28b907b463f55b66984d780209dd3d4ad8 Mon Sep 17 00:00:00 2001 From: Stefan Stefanov Date: Wed, 24 Apr 2024 21:08:36 +0300 Subject: [PATCH] working metdata output for json & odin in the aseprite_odin_generator tool --- .gitignore | 4 +- .../aseprite_odin_generator.odin | 4 +- src/aseprite_odin_generator/metadata.json | 2 +- src/generator.odin | 96 +++++++++++++++---- 4 files changed, 83 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 66483a8..91dc2bb 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,6 @@ ols.json libtinyfiledialogs.a libtinyfiledialogs.obj tinyfiledialogs.lib -tinyfiledialogs.obj \ No newline at end of file +tinyfiledialogs.obj + +.idea/ diff --git a/src/aseprite_odin_generator/aseprite_odin_generator.odin b/src/aseprite_odin_generator/aseprite_odin_generator.odin index 225578e..d095938 100644 --- a/src/aseprite_odin_generator/aseprite_odin_generator.odin +++ b/src/aseprite_odin_generator/aseprite_odin_generator.odin @@ -37,7 +37,9 @@ main :: proc() { json_bytes, jerr := json.marshal(metadata) os.write_entire_file("src/aseprite_odin_generator/metadata.json", json_bytes) - + sb := gen.generate_odin_enums_and_atlas_offsets_file_sb(metadata[:]) + odin_output_str := s.to_string(sb) + os.write_entire_file("src/aseprite_odin_generator/output.odino", transmute([]byte)odin_output_str ) rl.ExportImage(atlas, EXPORT_PATH) } diff --git a/src/aseprite_odin_generator/metadata.json b/src/aseprite_odin_generator/metadata.json index a07b92b..be61ff1 100644 --- a/src/aseprite_odin_generator/metadata.json +++ b/src/aseprite_odin_generator/metadata.json @@ -1 +1 @@ -[{"name":"Edinica","location":[95,10],"size":[58,57]},{"name":"Dvoika_0","location":[234,10],"size":[55,31]},{"name":"Troika","location":[10,10],"size":[75,75]},{"name":"Dvoika_1","location":[163,10],"size":[61,33]}] \ No newline at end of file +[{"name":"Edinica","location":[95,10],"size":[58,57]},{"name":"Dvoika_0","location":[234,10],"size":[55,31]},{"name":"Dvoika_1","location":[163,10],"size":[61,33]},{"name":"Troika","location":[10,10],"size":[75,75]}] \ No newline at end of file diff --git a/src/generator.odin b/src/generator.odin index 62483a8..6ad9ebe 100644 --- a/src/generator.odin +++ b/src/generator.odin @@ -1,11 +1,10 @@ package game import ase "./aseprite" -import "core:encoding/json" import "core:fmt" -import "core:mem" import "core:os" import fp "core:path/filepath" +import "core:slice" import "core:strings" import rl "vendor:raylib" import stbrp "vendor:stb/rect_pack" @@ -25,13 +24,6 @@ AtlasEntry :: struct { layer_cell_count: [dynamic]i32, } -SingleFrameSprite :: distinct rl.Rectangle - -AnimatedSprite :: struct { - x, y: i32, - width, height: i32, -} - SpriteAtlasMetadata :: struct { name: string, location: [2]i32, @@ -89,6 +81,13 @@ unmarshall_aseprite_files :: proc(file_paths: []string, atlas_entries: ^[dynamic atlas_entry_from_compressed_cells :: proc(document: ase.Document) -> (atlas_entry: AtlasEntry) { atlas_entry.frames = auto_cast len(document.frames) fmt.println("N Frames: ", len(document.frames)) + // note(stefan): Since the expected input for the program is multiple files containing a single sprite + // it's probably a safe assumption most of the files will be a single layer with 1 or more frames + // which means we can first prod the file for information about how many frames are there and + // allocate a slice that is going to be [Frames X Layers]CellData. + // which would allow us to gain an already sorted list of sprites if we iterate all frames of a single layer + // instead of iterating all layers for each frame + // might be even quicker to first get that information an allocate at once the amount of cells we need for frame, frameIdx in document.frames { fmt.printfln("Frame_{0} Chunks: ", frameIdx, len(frame.chunks)) for chunk in frame.chunks { @@ -109,14 +108,21 @@ atlas_entry_from_compressed_cells :: proc(document: ase.Document) -> (atlas_entr opacity = cel_chunk.opacity_level, layer_index = cel_chunk.layer_index, } + append(&atlas_entry.cells, cell) } + if layer_chunk, ok := chunk.(ase.Layer_Chunk); ok { fmt.println("Layer chunk: ", layer_chunk) append(&atlas_entry.layer_names, layer_chunk.name) } } } + + slice.sort_by(atlas_entry.cells[:], proc(i, j: CellData) -> bool { + return i.layer_index < j.layer_index + }) + return } @@ -210,17 +216,17 @@ pack_atlas_entries :: proc( entry := entry_and_cell.entry cell := entry_and_cell.cell_of_entry - cell_name : string - if entry.layer_cell_count[cell.layer_index] > 1 { - cell_name = fmt.aprintf( - "{0}_%d", - entry.layer_names[cell.layer_index], - cell.frame_index, - allocator, - ) - } else { - cell_name = entry.layer_names[cell.layer_index] - } + cell_name: string + if entry.layer_cell_count[cell.layer_index] > 1 { + cell_name = fmt.aprintf( + "{0}_%d", + entry.layer_names[cell.layer_index], + cell.frame_index, + allocator, + ) + } else { + cell_name = entry.layer_names[cell.layer_index] + } cell_metadata := SpriteAtlasMetadata { name = cell_name, location = { @@ -231,5 +237,55 @@ pack_atlas_entries :: proc( } append(&metadata, cell_metadata) } + return metadata } + +/* + Generates a barebones file with the package name "atlas_bindings", + the file contains an array of offsets, indexed by an enum. + The enum has unique names +*/ +generate_odin_enums_and_atlas_offsets_file_sb :: proc( + metadata: []SpriteAtlasMetadata, + alloc := context.allocator, +) -> strings.Builder { + sb := strings.builder_make(alloc) + strings.write_string(&sb, "package atlas_bindings\n\n") + + // Introduce the Rect type + strings.write_string(&sb, "AtlasRect :: struct { x, y, w, h: i32 }\n\n") + // start enum + strings.write_string(&sb, "AtlasSprite :: enum {\n") + { + for cell in metadata { + strings.write_string(&sb, fmt.aprintf("\t%s,\n", cell.name)) + } + } + // end enum + strings.write_string(&sb, "}\n\n") + + // start offsets array + // todo(stefan): the name of the array can be based on the output name? + strings.write_string(&sb, "ATLAS_SPRITES := []AtlasRect {\n") + { + entry: string + for cell in metadata { + entry = fmt.aprintf( + "\t.%v = {{ x = %v, y = %v, w = %v, h = %v }},\n", + cell.name, + cell.location.x, + cell.location.y, + cell.size.x, + cell.size.y, + ) + strings.write_string(&sb, entry) + } + } + // end offsets array + strings.write_string(&sb, "}\n\n") + + fmt.println("\n", strings.to_string(sb)) + + return sb +}