Skip to content

Commit

Permalink
fixed auto frame range always being wrong
Browse files Browse the repository at this point in the history
  • Loading branch information
Lilaa3 committed Apr 19, 2024
1 parent a622a91 commit dac1166
Show file tree
Hide file tree
Showing 6 changed files with 605 additions and 288 deletions.
104 changes: 83 additions & 21 deletions fast64_internal/sm64/animation/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,10 @@ def to_props(self, action, header):
header.custom_name = self.reference
header.override_name = True

correctFrameRange = self.start_frame, self.loop_start, self.loop_end
header.start_frame, header.loop_start, header.loop_end = correctFrameRange
if correctFrameRange != header.get_frame_range(action): # If auto frame range is wrong
correct_frame_range = self.start_frame, self.loop_start, self.loop_end
header.start_frame, header.loop_start, header.loop_end = correct_frame_range
auto_frame_range = header.get_frame_range(action)
if correct_frame_range != auto_frame_range:
header.manual_frame_range = True

header.trans_divisor = self.trans_divisor
Expand Down Expand Up @@ -395,7 +396,7 @@ def to_props(self, action, remove_name_footer: bool = True):
action_props.custom_file_name = main_header.file_name
action_props.reference_tables = True

if action_props.get_anim_file_name(action) != action_props.custom_file_name:
if action_props.custom_file_name and action_props.get_anim_file_name(action) != action_props.custom_file_name:
action_props.override_file_name = True

for i in range(len(self.headers) - 1):
Expand All @@ -407,41 +408,82 @@ def to_props(self, action, remove_name_footer: bool = True):
action_props.update_header_variant_numbers()


@dataclasses.dataclass
class DMATableEntrie:
offset: int
size: int
address: int


@dataclasses.dataclass
class DMATable:
address_place_holder: int = 0
entries: list[DMATableEntrie] = dataclasses.field(default_factory=list)
data: bytes = dataclasses.field(default_factory=bytes)

def read_binary(self, rom_data: bytes, address: int):
dma_table_reader = RomReading(rom_data, address)
num_entries = dma_table_reader.read_value(4) # numEntries
self.address_place_holder = dma_table_reader.read_value(4) # addrPlaceholder

end_of_table = 0
for _ in range(num_entries):
offset = dma_table_reader.read_value(4)
size = dma_table_reader.read_value(4)
self.entries.append(DMATableEntrie(offset, size, address + offset))
end_of_entry = offset + size
if end_of_entry > end_of_table:
end_of_table = end_of_entry

self.data = rom_data[address : address + end_of_table]


@dataclasses.dataclass
class SM64_AnimTable:
name: str = ""
reference: str | int = None
values_reference: str = ""
elements: list[SM64_AnimHeader, SM64_AnimData] = dataclasses.field(default_factory=list)

def to_binary(self, is_dma: bool, start_address: int):
data: bytearray = bytearray()
ptrs: list[int] = []

anim_data_set = []
def get_sets(self):
# Remove duplicates of data and headers, keep order by using a list
data_set = []
headers_set = []
for anim_header, anim_data in self.elements:
if anim_data and not anim_data in anim_data_set:
anim_data_set.append(anim_data)
if anim_data and not anim_data in data_set:
data_set.append(anim_data)
if not anim_header in headers_set:
headers_set.append(anim_header)
value_table, indice_tables = create_tables(anim_data_set, "values")
return data_set, headers_set

def to_binary(self, is_dma: bool, start_address: int):
# TODO: Handle dma exports
data: bytearray = bytearray()
ptrs: list[int] = []

data_set, headers_set = self.get_sets()

# Calculate offsets and generate tables
table_offset = start_address
table_length = len(self.elements) * 4
headers_offset = table_offset + table_length
headers_length = len(headers_set) * HEADER_SIZE
indice_tables_offset = start_address + headers_length
indice_tables_length = sum([len(indice_table.data) for indice_table in indice_tables])
values_table_offset = indice_tables_length
if data_set:
value_table, indice_tables = create_tables(data_set, "values")
indice_tables_offset = start_address + headers_length
indice_tables_length = sum([len(indice_table.data) for indice_table in indice_tables])
values_table_offset = indice_tables_length

# Add the animation table
for anim_header, anim_data in self.elements:
ptrs.append(len(data))
header_offset = headers_offset + (headers_set.index(anim_header) * HEADER_SIZE)
data.extend(header_offset.to_bytes(4, byteorder="big", signed=False))

# Add all the headers
for anim_header, anim_data in self.elements:
if anim_data:
indice_offset = sum(
[len(indice_table.data) for indice_table in indice_tables[: anim_data_set.index(anim_data)]]
[len(indice_table.data) for indice_table in indice_tables[: data_set.index(anim_data)]]
)
data.extend(
anim_header.to_binary(
Expand All @@ -453,11 +495,31 @@ def to_binary(self, is_dma: bool, start_address: int):
ptrs.append(len(data))
data.extend(anim_header.to_binary())

for indice_table in indice_tables:
data.extend(indice_table.to_binary())
data.extend(value_table.to_binary())
if data_set:
for indice_table in indice_tables:
data.extend(indice_table.to_binary())
data.extend(value_table.to_binary())

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

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

# Add all the headers
for anim_header, anim_data in self.elements:
data.write(anim_header.to_c(is_dma_structure, refresh_version))
data.write("\n")

return data.getvalue()

def to_c(self, is_dma: bool, start_address: int):
def to_c(self, is_dma_structure: bool, refresh_version: str):
pass


Expand Down
39 changes: 22 additions & 17 deletions fast64_internal/sm64/animation/exporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,13 @@
from bpy.path import abspath

from ...utility import (
PluginError,
radians_to_s16,
writeIfNotFound,
writeInsertableFile,
)
from ..sm64_utility import SM64_ShortArray
from ..sm64_constants import MAX_U16, NULL

from .classes import SM64_Anim, SM64_AnimPair
from .utility import anim_name_to_enum, get_anim_pose_bones
from .utility import get_anim_pose_bones


def get_animation_pairs(
Expand Down Expand Up @@ -74,21 +71,25 @@ def get_animation_pairs(
return pairs


def update_includes(level_name: str, group_name: str, dir_name: str, dir_path: str, header_type: str):
def update_includes(
level_name: str, group_name: str, dir_name: str, dir_path: str, header_type: str, update_table: bool
):
if header_type == "Actor":
data_path = os.path.join(dir_path, f"{group_name}.c")
header_path = os.path.join(dir_path, f"{group_name}.h")

writeIfNotFound(data_path, f'\n#include "{dir_name}/anims/data.inc.c"', "")
writeIfNotFound(data_path, f'\n#include "{dir_name}/anims/table.inc.c"', "")
writeIfNotFound(header_path, f'\n#include "{dir_name}/anim_header.h"', "#endif")
if update_table:
writeIfNotFound(data_path, f'\n#include "{dir_name}/anims/table.inc.c"', "")
writeIfNotFound(header_path, f'\n#include "{dir_name}/anim_header.h"', "#endif")
elif header_type == "Level":
data_path = os.path.join(dir_path, "leveldata.c")
header_path = os.path.join(dir_path, "header.h")

writeIfNotFound(data_path, f'\n#include "levels/{level_name}/{dir_name}/anims/data.inc.c"', "")
writeIfNotFound(data_path, f'\n#include "levels/{level_name}/{dir_name}/anims/table.inc.c"', "")
writeIfNotFound(header_path, f'\n#include "levels/{level_name}/{dir_name}/anim_header.h"', "\n#endif")
if update_table:
writeIfNotFound(data_path, f'\n#include "levels/{level_name}/{dir_name}/anims/table.inc.c"', "")
writeIfNotFound(header_path, f'\n#include "levels/{level_name}/{dir_name}/anim_header.h"', "\n#endif")


def write_anim_header(
Expand All @@ -105,7 +106,7 @@ def write_anim_header(
def update_enum_file(
enum_path: str,
enum_list_name: str,
header_names: list[str],
enum_names: list[str],
override_files: bool,
):
if override_files or not os.path.exists(enum_path):
Expand All @@ -119,8 +120,7 @@ def update_enum_file(
text = f"enum {enum_list_name} {{\n}};\n\n" + text
enum_list_index = text.find(enum_list_name)

for header_name in header_names:
enum_name = anim_name_to_enum(header_name)
for enum_name in enum_names:
if text.find(enum_name, enum_list_index) == -1:
enum_list_end = text.find("}", enum_list_index)
text = text[:enum_list_end] + f"\t{enum_name},\n" + text[enum_list_end:]
Expand All @@ -131,7 +131,7 @@ def update_enum_file(

def update_table_file(
table_path: str,
header_names: list[str],
enum_and_header_names: list[tuple[str, str]],
table_name: str,
generate_enums: bool,
override_files: bool,
Expand All @@ -145,7 +145,12 @@ def update_table_file(
text = file.read()

if generate_enums:
update_enum_file(enum_path, enum_list_name, header_names, override_files)
update_enum_file(
enum_path,
enum_list_name,
[tup[0] for tup in enum_and_header_names],
override_files,
)
include_text = '#include "table_enum.h"\n'
include_index = text.find(include_text)
if include_index == -1: # If there is no table, add one and find again
Expand All @@ -158,9 +163,9 @@ def update_table_file(
text += f"const struct Animation *const {table_name}[] = {{\n\tNULL,\n}};\n"
table_index = text.find(table_name)

for header_name in header_names:
for enum_name, header_name in enum_and_header_names:
header_reference = f"&{header_name}"
header_by_enum_reference = f"[{anim_name_to_enum(header_name)}] = &{header_name}"
header_by_enum_reference = f"[{enum_name}] = &{header_name}"
if text.find(header_reference, table_index) != -1 and (
not generate_enums or text.find(header_by_enum_reference, table_index) != -1
):
Expand All @@ -171,7 +176,7 @@ def update_table_file(
table_end = text.find("}", table_index)

if generate_enums:
text = text[:table_end] + f"\t[{anim_name_to_enum(header_name)}] = {header_reference},\n" + text[table_end:]
text = text[:table_end] + f"\t[{enum_name}] = {header_reference},\n" + text[table_end:]
else:
text = text[:table_end] + f"\t{header_reference},\n" + text[table_end:]

Expand Down
55 changes: 18 additions & 37 deletions fast64_internal/sm64/animation/importing.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from ..sm64_constants import insertableBinaryTypes

from .utility import RomReading, get_anim_pose_bones, sm64_to_radian
from .classes import SM64_Anim, SM64_AnimData, SM64_AnimHeader, SM64_AnimPair, SM64_AnimTable
from .classes import DMATable, DMATableEntrie, SM64_Anim, SM64_AnimData, SM64_AnimHeader, SM64_AnimPair, SM64_AnimTable
from .c_parser import CParser, EnumIndexedValue, Initialization


Expand Down Expand Up @@ -95,7 +95,6 @@ def animation_data_to_blender(
pose_bone.rotation_mode = "QUATERNION"

action = bpy.data.actions.new("")
anim_import.to_props(action, remove_name_footer)

if armature_obj.animation_data is None:
armature_obj.animation_data_create()
Expand Down Expand Up @@ -139,6 +138,8 @@ def animation_data_to_blender(
for frame, rotation in enumerate(bone_data.rotation):
f_curve.keyframe_points.insert(frame, rotation[property_index])

anim_import.to_props(action, remove_name_footer)


def import_animation_from_c_header(
animations: dict[str, SM64_Anim], header_initialization: Initialization, c_parser: CParser
Expand Down Expand Up @@ -224,6 +225,7 @@ def import_binary_header(
animations: dict[str, SM64_Anim],
segment_data: Optional[dict[int, tuple[int, int]]] = None,
):
print(f"Reading binary header at address {address}")
header = SM64_AnimHeader()
header.read_binary(data, address, segment_data, is_dma)

Expand All @@ -245,48 +247,27 @@ def import_binary_header(
return header


@dataclasses.dataclass
class DMATableEntrie:
offset: int
size: int
address: int


def read_binary_dma_table_entries(rom_data: BufferedReader, address: int):
entries: list[DMATableEntrie] = []
dma_table_reader = RomReading(rom_data, address)

num_entries = dma_table_reader.read_value(4) # numEntries
dma_table_reader.read_value(4) # addrPlaceholder

for _ in range(num_entries):
offset = dma_table_reader.read_value(4)
size = dma_table_reader.read_value(4)
entries.append(DMATableEntrie(offset, size, address + offset))

return entries


def import_binary_dma_animation(
rom_data: BufferedReader,
address: int,
animations: dict[str, SM64_Anim],
table: SM64_AnimTable,
read_entire_table: bool,
table_index: Optional[int] = None,
):
entries: list[DMATableEntrie] = read_binary_dma_table_entries(rom_data, address)
if read_entire_table:
for entrie in entries:
header = import_binary_header(rom_data, entrie.address, True, animations, None)
table.elements.append(header)
else:
if not 0 <= table_index < len(entries):
raise PluginError("Entrie outside of defined table.")

entrie: DMATableEntrie = entries[table_index]
) -> Optional[SM64_AnimHeader]:
dma_table = DMATable()
dma_table.read_binary(rom_data, address)
if not table_index is None:
if table_index < 0 or table_index >= len(dma_table.entries):
raise PluginError(f"Index {table_index} outside of defined table ({len(dma_table.entries)} entries).")

entrie: DMATableEntrie = dma_table.entries[table_index]
header = import_binary_header(rom_data, entrie.address, True, animations, None)
table.elements.append(header)
return header
else:
for entrie in dma_table.entries:
header = import_binary_header(rom_data, entrie.address, True, animations, None)
table.elements.append(header)


def import_binary_table(
Expand Down Expand Up @@ -345,7 +326,7 @@ def import_binary_animations(
rom_data, address, segment_data, animations, read_entire_table, table_index, ignore_null, table
)
elif import_type == "DMA":
import_binary_dma_animation(rom_data, address, animations, table, read_entire_table, table_index)
import_binary_dma_animation(rom_data, address, animations, table, table_index if read_entire_table else None)
elif import_type == "Animation":
import_binary_header(rom_data, address, False, animations, segment_data)
else:
Expand Down
Loading

0 comments on commit dac1166

Please sign in to comment.