Skip to content

Commit

Permalink
Quick read (missing ui)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lilaa3 committed Apr 19, 2024
1 parent d68f843 commit 2b79e7f
Show file tree
Hide file tree
Showing 6 changed files with 363 additions and 176 deletions.
237 changes: 150 additions & 87 deletions fast64_internal/sm64/animation/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,21 @@ class SM64_AnimData:
values_file_name: str = ""

def to_c(self, is_dma_structure: bool):
data = StringIO()
text_data = StringIO()

value_table, indice_tables = create_tables([self])
indice_table = indice_tables[0]

if is_dma_structure:
data.write(indice_table.to_c())
data.write("\n\n")
data.write(value_table.to_c())
text_data.write(indice_table.to_c())
text_data.write("\n\n")
text_data.write(value_table.to_c())
else:
data.write(value_table.to_c())
data.write("\n\n")
data.write(indice_table.to_c())
text_data.write(value_table.to_c())
text_data.write("\n\n")
text_data.write(indice_table.to_c())

return data.getvalue()
return text_data.getvalue()

def to_binary(self, start_address: int) -> bytearray:
data: bytearray = bytearray()
Expand Down Expand Up @@ -183,41 +183,57 @@ def get_binary_flags(self):
return eval_num_from_str(self.custom_flags)
return self.flags

def to_c(self, is_dma_structure: bool, refresh_version: str) -> str:
def get_values_reference(self, override: Optional[str | int] = None):
if override:
return override
elif self.values_reference:
return self.values_reference
elif self.data and self.data.values_reference:
return self.data.values_reference

def get_indice_reference(self, override: Optional[str | int] = None):
if override:
return override
elif self.indice_reference:
return self.indice_reference
elif self.data and self.data.indice_reference:
return self.data.indice_reference

def to_c(
self,
values_override: Optional[str | int] = None,
indice_override: Optional[str | int] = None,
is_dma_structure: bool = False,
refresh_version: str = "Refresh 13",
):
return (
f"static const struct Animation {self.reference}{'[]' if is_dma_structure else ''} = {{\n"
f"\t{self.get_c_flags(is_dma_structure, refresh_version)}, // flags\n"
f"\t{self.trans_divisor}, // animYTransDivisor\n"
f"\t{self.start_frame}, // startFrame\n"
f"\t{self.loop_start}, // loopStart\n"
f"\t{self.loop_end}, // loopEnd\n"
f"\tANIMINDEX_NUMPARTS({self.indice_reference}), // unusedBoneCount\n"
f"\t{self.values_reference}, // values\n"
f"\t{self.indice_reference}, // index\n"
f"\tANIMINDEX_NUMPARTS({self.get_indice_reference(indice_override)}), // unusedBoneCount\n"
f"\t{self.get_values_reference(values_override)}, // values\n"
f"\t{self.get_indice_reference(indice_override)}, // index\n"
"\t0\n"
"};\n"
)

def to_binary(self, values_reference: int | None = None, indice_reference: int | None = None):
def to_binary(
self,
values_override: Optional[str | int] = None,
indice_override: Optional[str | int] = None,
):
data = bytearray()
data.extend(self.flags.to_bytes(2, byteorder="big", signed=False)) # 0x00
data.extend(self.trans_divisor.to_bytes(2, byteorder="big", signed=True)) # 0x02
data.extend(self.start_frame.to_bytes(2, byteorder="big", signed=True)) # 0x04
data.extend(self.loop_start.to_bytes(2, byteorder="big", signed=True)) # 0x06
data.extend(self.loop_end.to_bytes(2, byteorder="big", signed=True)) # 0x08
data.extend(self.bone_count.to_bytes(2, byteorder="big", signed=True)) # 0x0A

if not values_reference:
values_reference = self.values_reference
if not indice_reference:
indice_reference = self.indice_reference
if isinstance(values_reference, str):
values_reference = eval_num_from_str(values_reference)
if isinstance(indice_reference, str):
indice_reference = eval_num_from_str(indice_reference)

data.extend(values_reference.to_bytes(4, byteorder="big", signed=False)) # 0x0C
data.extend(indice_reference.to_bytes(4, byteorder="big", signed=False)) # 0x10
data.extend(self.get_values_reference(values_override).to_bytes(4, byteorder="big", signed=False)) # 0x0C
data.extend(self.get_indice_reference(indice_override).to_bytes(4, byteorder="big", signed=False)) # 0x10
data.extend(bytearray([0x00] * 4)) # 0x14 # Unused with no porpuse
# 0x18
return data
Expand Down Expand Up @@ -271,7 +287,7 @@ def read_c(self, value: Initialization):
),
)

def to_props(self, action, header):
def to_props(self, action, header, actor_name: str, use_custom_name: bool = True):
flagsToProps = { # TODO: Fix this whole thing its so cringe help me oh god help me
"ANIM_FLAG_NOLOOP": "no_loop",
"ANIM_FLAG_BACKWARD": "backwards",
Expand All @@ -284,8 +300,12 @@ def to_props(self, action, header):

header.action = action

if isinstance(self.reference, str):
header.custom_name = self.reference
header.custom_name = self.reference
if (
isinstance(self.reference, str)
and self.reference != header.get_anim_name(actor_name, action)
and use_custom_name
):
header.override_name = True

correct_frame_range = self.start_frame, self.loop_start, self.loop_end
Expand Down Expand Up @@ -342,45 +362,41 @@ def to_binary(self, is_dma: bool, start_address: int) -> bytearray:
return data, ptrs

def headers_to_c(self, is_dma_structure: bool, refresh_version: str) -> str:
data = StringIO()
text_data = StringIO()
for header in self.headers:
data.write(header.to_c(is_dma_structure, refresh_version))
data.write("\n")
return data.getvalue()
text_data.write(header.to_c(is_dma_structure=is_dma_structure, refresh_version=refresh_version))
text_data.write("\n")
return text_data.getvalue()

def to_c(self, is_dma_structure: bool, refresh_version: str):
data = StringIO()
text_data = StringIO()

table_data = None
if self.data:
table_data = self.data.to_c(is_dma_structure)

c_headers = self.headers_to_c(is_dma_structure, refresh_version)
if is_dma_structure:
data.write(c_headers)
text_data.write(c_headers)
if table_data:
data.write("\n")
data.write(table_data)
text_data.write("\n")
text_data.write(table_data)
else:
if table_data:
data.write(table_data)
data.write("\n")
data.write(c_headers)
text_data.write(table_data)
text_data.write("\n")
text_data.write(c_headers)

return data.getvalue()
return text_data.getvalue()

# Importing
def to_props(self, action, remove_name_footer: bool = True):
def to_props(self, action, actor_name: str, remove_name_footer: bool = True, use_custom_name: bool = True):
action_props = action.fast64.sm64

main_header = self.headers[0]

if not self.action_name:
if main_header.reference:
if remove_name_footer and main_header.reference.startswith("anim_"):
self.action_name = main_header.reference.replace("anim_", "", 1)
else:
self.action_name = main_header.reference
if not self.action_name and main_header.reference and remove_name_footer:
self.action_name = main_header.reference.lstrip("anim_")
if self.action_name:
action.name = self.action_name

Expand All @@ -407,7 +423,7 @@ def to_props(self, action, remove_name_footer: bool = True):
action_props.header_variants.add()

for header, header_props in zip(self.headers, action_props.headers):
header.to_props(action, header_props)
header.to_props(action, header_props, actor_name, use_custom_name)

action_props.update_header_variant_numbers()

Expand Down Expand Up @@ -442,6 +458,11 @@ def read_binary(self, rom_data: bytes, address: int):
self.data = rom_data[address : address + end_of_table]


def num_to_padded_hex(num: int):
hex_str = hex(num)[2:].upper() # remove the '0x' prefix
return hex_str.zfill(2)


@dataclasses.dataclass
class SM64_AnimTable:
reference: str | int = None
Expand Down Expand Up @@ -508,12 +529,54 @@ def to_binary(self, is_dma: bool, start_address: int):

return data

def data_and_headers_to_c(self, is_dma_structure: bool, refresh_version: str) -> list[os.PathLike, str]:
def to_c_dma(self) -> list[os.PathLike, str]:
files_data: dict[str, str] = {}

text_data = StringIO()
header_nums = []
included_headers = []
for i, anim_header in enumerate(self.elements):
header_nums.append(i)
included_headers.append(anim_header)
anim_header.reference = f"anim_{num_to_padded_hex(i)}"
# If at the end of the list, or the next element has different data
if (i >= len(self.elements) - 1) or self.elements[i + 1].data != anim_header.data:
# Create appropriate file name, store the final text and reset the data
name = "anim"
for num in header_nums:
name += f"_{num_to_padded_hex(num)}"
file_name = f"{name}.inc.c"

# While normal names are possible (order goes by line and file)
# That would break convention, require extra code for duplicates, warnings, etc
anim_header.data.indice_reference = f"{name}_indices"
anim_header.data.values_reference = f"{name}_values"

for included_header in included_headers:
text_data.write(included_header.to_c(is_dma_structure=True))
text_data.write("\n")

value_table, indice_tables = create_tables([anim_header.data])
text_data.write(indice_tables[0].to_c())
text_data.write("\n")
text_data.write(value_table.to_c())
text_data.write("\n")

files_data[file_name] = text_data.getvalue()

text_data = StringIO()
header_nums.clear()
included_headers.clear()

return files_data

def data_and_headers_to_c(self, refresh_version: str) -> list[os.PathLike, str]:
files_data: dict[str, str] = {}

headers_set = self.get_sets()[0]
text_data = StringIO()
for anim_header in headers_set:
data = StringIO()
text_data.truncate(0)
same_reference_headers = [anim_header]
for other_header in headers_set:
if (
Expand All @@ -527,79 +590,79 @@ def data_and_headers_to_c(self, is_dma_structure: bool, refresh_version: str) ->
for same_reference_header in same_reference_headers:
if same_reference_header.data:
value_table, indice_tables = create_tables([same_reference_header.data])
data.write(value_table.to_c())
data.write("\n")
for indice_table in indice_tables:
data.write(indice_table.to_c())
data.write("\n")
text_data.write(value_table.to_c())
text_data.write("\n")
text_data.write(indice_tables[0].to_c())
text_data.write("\n")
break

for same_reference_header in same_reference_headers:
data.write(same_reference_header.to_c(is_dma_structure, refresh_version))
data.write("\n")
text_data.write(same_reference_header.to_c(False, refresh_version))
text_data.write("\n")

files_data[anim_header.file_name] = data.getvalue()
files_data[anim_header.file_name] = text_data.getvalue()

return files_data

def combined_data_and_headers_to_c(self, is_dma_structure: bool, refresh_version: str):
data = StringIO()
def combined_data_and_headers_to_c(self, refresh_version: str):
text_data = StringIO()

headers_set, data_set = self.get_sets()
if data_set:
value_table, indice_tables = create_tables(data_set, self.values_reference)
data.write(value_table.to_c())
data.write("\n")
text_data.write(value_table.to_c())
text_data.write("\n")
for indice_table in indice_tables:
data.write(indice_table.to_c())
data.write("\n")
text_data.write(indice_table.to_c())
text_data.write("\n")

for anim_header in headers_set:
data.write(anim_header.to_c(is_dma_structure, refresh_version))
data.write("\n")
text_data.write(anim_header.to_c(False, refresh_version))
text_data.write("\n")

return data.getvalue()
return text_data.getvalue()

def enum_list_to_c(self):
data = StringIO()
text_data = StringIO()

data.write(f"enum {self.enum_list_reference} {{\n")
text_data.write(f"enum {self.enum_list_reference} {{\n")
for anim_header in self.elements:
data.write(f"\t{anim_header.enum_reference},\n")
data.write("};\n")
text_data.write(f"\t{anim_header.enum_reference},\n")
text_data.write("};\n")

return data.getvalue()

def table_to_c(self, generate_enums: bool):
data = StringIO()
text_data = StringIO()

if generate_enums:
data.write(f'#include "table_enum.h"\n')
text_data.write(f'#include "table_enum.h"\n')

data.write(f"const struct Animation *const {self.reference}[] = {{\n")
text_data.write(f"const struct Animation *const {self.reference}[] = {{\n")
for anim_header in self.elements:
if generate_enums:
data.write(f"\t[{anim_header.enum_reference}] = &{anim_header.reference},\n")
text_data.write(f"\t[{anim_header.enum_reference}] = &{anim_header.reference},\n")
else:
data.write(f"\t&{anim_header.reference},\n")
data.write("\tNULL,\n};\n")
text_data.write(f"\t&{anim_header.reference},\n")
text_data.write("\tNULL,\n};\n")

return data.getvalue()
return text_data.getvalue()


def create_tables(anims_data: list[SM64_AnimData], values_name: str = None):
"""Can generate multiple indices table with only one value table, which improves compression"""
"""This feature is used in table exports"""

def index_sub_seq_in_seq(sub_seq, seq):
i, seq_length, sub_length = -1, len(seq), len(seq)
try:
while True:
i = seq.index(sub_seq[0], i + 1, seq_length - sub_length + 1)
if sub_seq == seq[i : i + sub_length]:
return i
except ValueError:
return -1
def index_sub_seq_in_seq(sub_seq: list[int], seq: list[int]):
i, sub_length = -1, len(sub_seq)
while True:
trunc_seq = seq[i + 1 :]
if sub_seq[0] not in trunc_seq:
return -1
i = seq.index(sub_seq[0], i + 1)
if sub_seq == seq[i:sub_length]:
return i
return -1

value_table = SM64_ShortArray(values_name if values_name else anims_data[0].values_reference, True)

Expand Down
Loading

0 comments on commit 2b79e7f

Please sign in to comment.