summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSuperDude88 <82904174+SuperDude88@users.noreply.github.com>2026-07-13 15:22:49 -0400
committerSuperDude88 <82904174+SuperDude88@users.noreply.github.com>2026-07-13 17:09:42 -0400
commit99f93ebe98d144f48e4e494724a163b026fe9d91 (patch)
tree03494240d0cc04dfafdec31fb8e57c1b062cd8c6
parent5319b0e006c365d16f509daa0e627baa8e5156c5 (diff)
Add Model Extraction Script
- Support extraction of Vec/cXy/GXColor data
-rwxr-xr-xconfigure.py20
-rw-r--r--tools/converters/extract_model_data.py145
2 files changed, 165 insertions, 0 deletions
diff --git a/configure.py b/configure.py
index a6bcd75d..9e25d2ae 100755
--- a/configure.py
+++ b/configure.py
@@ -1838,6 +1838,11 @@ config.custom_build_rules = [
"command": "$python tools/converters/matDL_dis.py $in $out --symbol $symbol --scope $scope",
"description": "CONVERT $symbol",
},
+ {
+ "name": "convert_embedded_model_data",
+ "command": "$python tools/converters/extract_model_data.py $in $out --type $type --symbol $symbol --scope $scope",
+ "description": "CONVERT $symbol",
+ },
]
config.custom_build_steps = {}
@@ -1870,6 +1875,21 @@ def emit_build_rule(asset):
}
)
+ case "Vec" | "cXy" | "GXColor":
+ steps.append(
+ {
+ "rule": "convert_embedded_model_data",
+ "inputs": out_dir / "bin" / asset["binary"],
+ "outputs": out_dir / "include" / asset["header"],
+ "variables": {
+ "type": asset.get("custom_type"),
+ "symbol": asset.get("rename") or asset["symbol"],
+ "scope": custom_data.get("scope", "local")
+ },
+ "implicit": Path("tools/converters/extract_model_data.py"),
+ }
+ )
+
case _:
print("Unknown asset type: " + asset["custom_type"])
diff --git a/tools/converters/extract_model_data.py b/tools/converters/extract_model_data.py
new file mode 100644
index 00000000..bd05e7a3
--- /dev/null
+++ b/tools/converters/extract_model_data.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python3
+
+from argparse import ArgumentParser
+import struct
+import os
+from enum import Enum
+from binary_funcs import read_f32, read_u8
+
+def write_array_declaration(c_file, symbol_name: str, scope: str, type: str):
+ if scope == "local":
+ var_def_prefix = "static "
+ else:
+ var_def_prefix = ""
+
+ c_file.write(f"{var_def_prefix}{type} {symbol_name}[] = {{\n")
+
+def format_float_array(elements: list[tuple[float, ...]]) -> str:
+ if len(elements) == 0:
+ return ""
+
+ num_components: int = len(elements[0])
+
+ # Get the longest float for each component
+ longest_components: list[int] = [0] * num_components
+ for element in elements:
+ for i, component in enumerate(element):
+ length = len(f"{component:f}".rstrip('0'))
+ if f"{component:f}".rstrip('0').endswith('.'):
+ length += 1
+ longest_components[i] = max(length, longest_components[i])
+
+ result: str = ""
+ for element in elements:
+ # Open each array element
+ result += " {"
+ for i, component in enumerate(element):
+ # Remove all the trailing 0s (unless the value would end with the decimal point)
+ value = f'{component:f}'.rstrip('0')
+ if value.endswith('.'):
+ value += '0'
+
+ # Only add the comma + minimum 1 space if this isn't the last element
+ if i != len(element) - 1:
+ result += f"{f'{value}f, ':<{longest_components[i] + 3}}"
+ else:
+ result += f"{f'{value}f':<{longest_components[i] + 1}}"
+
+ result += "},\n"
+
+ return result
+
+def convert_binary_to_Vec_c_source(src_path: str, dest_path: str, symbol_name: str, scope: str):
+ # Load data
+ with open(src_path, "rb") as binary_file, open(dest_path, "w") as c_file:
+
+ write_array_declaration(c_file, symbol_name, scope, "Vec")
+
+ elements: list[tuple[float, ...]] = []
+ while True:
+ try:
+ x, y, z = read_f32(binary_file), read_f32(binary_file), read_f32(binary_file)
+ except EOFError:
+ break
+
+ elements.append((x, y, z))
+
+ lines = format_float_array(elements)
+ c_file.write(lines)
+
+ c_file.write("};\n")
+
+def convert_binary_to_cXy_c_source(src_path: str, dest_path: str, symbol_name: str, scope: str):
+ # Load data
+ with open(src_path, "rb") as binary_file, open(dest_path, "w") as c_file:
+
+ write_array_declaration(c_file, symbol_name, scope, "cXy")
+
+ elements: list[tuple[float, ...]] = []
+ while True:
+ try:
+ x, y = read_f32(binary_file), read_f32(binary_file)
+ except EOFError:
+ break
+
+ elements.append((x, y))
+
+ lines = format_float_array(elements)
+ c_file.write(lines)
+
+ c_file.write("};\n")
+
+def convert_binary_to_GXColor_c_source(src_path: str, dest_path: str, symbol_name: str, scope: str):
+ # Load data
+ with open(src_path, "rb") as binary_file, open(dest_path, "w") as c_file:
+
+ write_array_declaration(c_file, symbol_name, scope, "GXColor")
+
+ while True:
+ try:
+ r, g, b, a = read_u8(binary_file), read_u8(binary_file), read_u8(binary_file), read_u8(binary_file)
+ except EOFError:
+ break
+
+ c_file.write(" " + f"{{0x{r:02X}, 0x{g:02X}, 0x{b:02X}, 0x{a:02X}}}" + ",\n")
+
+ c_file.write("};\n")
+
+
+def main():
+ parser = ArgumentParser(
+ description="Converts a binary file containing vertex data to an array of the specified type"
+ )
+ parser.add_argument("src_path", type=str, help="Binary source file path")
+ parser.add_argument("dest_path", type=str, help="Destination C include file path")
+ parser.add_argument(
+ "--type",
+ type=str,
+ help="Data type",
+ )
+ parser.add_argument(
+ "--symbol",
+ type=str,
+ help="Symbol name",
+ )
+ parser.add_argument(
+ "--scope",
+ choices=["global", "local"],
+ default="local",
+ help="The scope of the symbol",
+ )
+
+ args = parser.parse_args()
+
+ if args.type == "Vec":
+ convert_binary_to_Vec_c_source(args.src_path, args.dest_path, args.symbol, args.scope)
+ elif args.type == "cXy":
+ convert_binary_to_cXy_c_source(args.src_path, args.dest_path, args.symbol, args.scope)
+ elif args.type == "GXColor":
+ convert_binary_to_GXColor_c_source(args.src_path, args.dest_path, args.symbol, args.scope)
+ else:
+ raise Exception(f"Unknown data type: {args.type}")
+
+
+if __name__ == "__main__":
+ main()