mirror of
https://github.com/zeldaret/tww.git
synced 2026-08-04 09:08:39 -04:00
Add Model Extraction Script
- Support extraction of Vec/cXy/GXColor data
This commit is contained in:
@@ -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"])
|
||||
|
||||
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user