From 0988ab832bfc7a1b1c851125b6172cf68c6d9cb9 Mon Sep 17 00:00:00 2001 From: Xander Swan <[hidden email]> Date: Wed, 7 Jan 2026 23:12:22 -0500 Subject: doesn't compile but i'm commiting anywya --- tools/compile_assets/main.odin | 328 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 tools/compile_assets/main.odin (limited to 'tools/compile_assets/main.odin') diff --git a/tools/compile_assets/main.odin b/tools/compile_assets/main.odin new file mode 100644 index 0000000..60c8a8c --- /dev/null +++ b/tools/compile_assets/main.odin @@ -0,0 +1,328 @@ +package assets_gen + +import os "core:os/os2" +import "core:fmt" +import "core:path/filepath" +import "core:strings" + +COMPILED_DIR :: ".compiled-res/" +HELP_STR :: `USAGE: %v [input dir] [output file].odin` + +Asset_Loader :: #type proc(string, ^os.File, ^os.File) + +file_content := +`#+feature dynamic-literals +package demonchime + +// DO NOT EDIT +// +// This file is autogenerated by tools/compile_assets +// All resource types are defined in 'src/resources.odin'. + +import rl "vendor:raylib" + +Image_Id :: enum { +} + +Animation_Id :: enum { +} + +Map_Id :: enum { +} + +Tileset_Id :: enum { +} + +Resource_Id :: union { + Image_Id, + Animation_Id, + Map_Id, + Tileset_Id, +} + +images: [Image_Id]Image_Resource +animations: [Animation_Id]Animation_Resource +maps: [Map_Id]Map_Resource +tilesets: [Tileset_Id]Tileset_Resource + +path_to_id: map[string]Resource_Id + +load_resources :: proc() { + load_images() + load_anims() + load_maps() + load_tilesets() + + // Allow conversion from paths to a resource id, since it's a better way to + // reference resources in other resources (JSON is a good example). +} + +@(private="file") +load_images :: proc() { +} + +@(private="file") +load_anims :: proc() { +} + +@(private="file") +load_maps :: proc() { +} + +@(private="file") +load_tilesets :: proc() { +} +` + +images: map[string]string +animations: map[string]string +maps: map[string]string +tilesets: map[string]string + +paths_to_res_type: map[string]string + +die :: proc(msg: string, args: ..any, exit_code := 1) { + fmt.eprintfln(msg, ..args) + os.exit(exit_code) +} + +print_help :: proc(exit_code := 1) { + die(HELP_STR, os.args[0], exit_code = exit_code) +} + +recursive_read_directory :: proc( + dir: string, + allocator := context.allocator, +) -> ([]os.File_Info, os.Error) { + context.allocator = allocator + + full_files: [dynamic]os.File_Info + + files, read_dir_err := os.read_all_directory_by_path( + dir, + allocator = allocator, + ) + if read_dir_err != nil { + return nil, read_dir_err + } + defer delete(files) + + for file in files { + fmt.printfln("Found %-15v '%v'", file.type, file.fullpath) + #partial switch file.type { + case .Directory: + subdir_files, sub_err := recursive_read_directory(file.fullpath) + if sub_err != nil { + delete(full_files) + return nil, sub_err + } + defer delete(subdir_files) + + append(&full_files, ..subdir_files) + + os.file_info_delete(file, allocator) + case .Regular: + append(&full_files, file) + case: + delete(full_files) + die("Invalid file type %v", file.type) + } + } + + return full_files[:], nil +} + +create_enum :: proc( + content: string, + replace: string, + elements: map[string]string +) -> string { + ids := "" + + for element in elements { + ids = strings.concatenate({ + ids, + " ", + strings.to_upper_snake_case(element, context.temp_allocator), + ",\n" + }, allocator = context.temp_allocator) + } + + replaced, _ := strings.replace_all( + content, + replace, + ids, + allocator = context.temp_allocator, + ) + + return replaced +} + +create_loads :: proc( + content: string, + map_name: string, + placeholder: string, + elements: map[string]string +) -> string { + load := "" + for element in elements { + load = strings.concatenate({ + load, + " ", + map_name, + "[.", + strings.to_upper_snake_case(element, context.temp_allocator), + "] = ", + elements[element], + "\n", + }, allocator = context.temp_allocator) + } + return set_placeholder(content, placeholder, load) +} + +set_placeholder :: proc( + content: string, + placeholder: string, + with: string +) -> string { + new_content, _ := strings.replace_all( + content, + placeholder, + with, + allocator = context.temp_allocator, + ) + return new_content +} + +main :: proc() { + if len(os.args) != 3 { + print_help() + } + + input_dir := os.args[1] + output_file_path := os.args[2] + + output_file, open_err := os.open(output_file_path, {.Write, .Create, .Trunc}) + if open_err != nil { + die("Could not create output file '%v' (%v)", output_file_path, open_err) + } + defer os.close(output_file) + + dir_info, stat_err := os.stat(input_dir, context.temp_allocator) + if stat_err != nil { + die("Error reading directory %v", stat_err) + } + + if dir_info.type != .Directory { + die("Expected directory (Got %v)", dir_info.type) + } + + files, dir_read_err := recursive_read_directory(input_dir) + if dir_read_err != nil { + die("Could not iterate directory %v", dir_read_err) + } + defer { + for file in files { + os.file_info_delete(file, context.allocator) + } + delete(files) + } + + free_all(context.temp_allocator) + + loaders: map[string]Asset_Loader + defer delete(loaders) + + loaders["tmj"] = load_map + // loaders["world"] = load_json + loaders["tsj"] = load_tileset + loaders["qoi"] = load_qoi + loaders["png"] = load_png + loaders["ase"] = load_ase + + os.make_directory_all(COMPILED_DIR) + + fmt.println("Generating assets file...") + for file in files { + ext := filepath.ext(file.fullpath)[1:] + loader, has := &loaders[ext] + if !has { + fmt.printfln( + "%-25v Skipped\tNo loader for '%v'", + file.name, + ext, + ) + continue + } + + f, open_err := os.open(file.fullpath) + if open_err != nil { + fmt.printfln("%-25v Skipped\tCould not load file", file.name) + continue + } + defer os.close(f) + + fmt.printfln("%-25v Loading...", file.name) + loader^(file.fullpath, f, output_file) + fmt.printfln("%-25v Loaded", file.name) + + free_all(context.temp_allocator) + } + + content := file_content + + images_to_enum: map[string]string + defer delete(images_to_enum) + + content = create_enum(content, "", images) + content = create_enum(content, "", animations) + content = create_enum(content, "", maps) + content = create_enum(content, "", tilesets) + + content = create_loads(content, "images", "", images) + content = create_loads(content, "animations", "", animations) + content = create_loads(content, "maps", "", maps) + content = create_loads(content, "tilesets", "", tilesets) + + res_paths := "" + cwd, _ := os.get_working_directory(context.temp_allocator) + + for file in files { + res_type, is_res := paths_to_res_type[file.fullpath] + if !is_res { + continue + } + + res_name := strings.to_upper_snake_case( + filepath.stem(file.fullpath), + context.temp_allocator, + ) + rel_path, _ := filepath.rel(cwd, file.fullpath, context.temp_allocator) + res_paths = strings.concatenate({ + res_paths, + " path_to_id[\"", + rel_path, + "\"] = ", + res_type, + ".", + res_name, + "\n", + }, allocator = context.temp_allocator) + } + content = set_placeholder(content, "", res_paths) + + os.write_string(output_file, content) + + for image in images { + delete(images[image]) + } + for anim in animations { + delete(animations[anim]) + } + for tmap in maps { + delete(maps[tmap]) + } + + free_all(context.temp_allocator) +} + -- cgit v1.3-2-g0d8e