Skip to content

Commit

Permalink
64 is the nice number i have ants on my ears
Browse files Browse the repository at this point in the history
  • Loading branch information
Lilaa3 committed Jan 21, 2024
1 parent 553ee1c commit 65adda8
Show file tree
Hide file tree
Showing 6 changed files with 1,859 additions and 4,111 deletions.
125 changes: 66 additions & 59 deletions fast64_internal/sm64/animation/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from ..sm64_constants import MAX_U16

from .utility import RomReading
from .utility import RomReading, eval_num_from_str
from ...utility import PluginError, decodeSegmentedAddr, is_bit_active


Expand All @@ -28,22 +28,22 @@ def clean_frames(self):

last_value = self.values[-1]

for i, value in enumerate(reversed(self.values)):
for i, value in enumerate(reversed(self.values[:-1])):
if value != last_value:
break
self.values = self.values[:-i]
self.values = self.values[: len(self.values) - i]
return

def get_frame(self, frame: int):
return self.values[frame] if frame < len(self.values) else self.values[-1]

# Importing
def read_binary(self, indicesReader: RomReading, data: bytes, valuesAdress: int):
maxFrame = indicesReader.read_value(2, signed=False)
valueOffset = indicesReader.read_value(2, signed=False) * 2
def read_binary(self, indices_reader: RomReading, data: bytes, valuesAddress: int):
max_frame = indices_reader.read_value(2, signed=False)
value_offset = indices_reader.read_value(2, signed=False) * 2

valueReader = RomReading(data, valuesAdress + valueOffset)
for _ in range(maxFrame):
value = valueReader.read_value(2, signed=True)
value_reader = RomReading(data, valuesAddress + value_offset)
for _ in range(max_frame):
value = value_reader.read_value(2, signed=True)
self.values.append(value)

def read_c(self, maxFrame, offset, values: list[int]):
Expand Down Expand Up @@ -109,31 +109,36 @@ def get_c_flags(self, is_dma_structure: bool, refresh_version: str):
return flags
return 0

def to_c(self, is_dma_structure: bool, refresh_version: str) -> str:
def get_binary_flags(self):
if self.custom_flags:
return eval_num_from_str(self.custom_flags)
return self.flags

def to_c(self, indices_reference: str, values_reference: str, is_dma_structure: bool, refresh_version: str) -> str:
return (
f"static const struct Animation {self.name}{'[]' 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.data.indicesReference}), // unusedBoneCount\n"
f"\t{self.data.valuesReference}, // values\n"
f"\t{self.data.indicesReference}, // index\n"
f"\tANIMINDEX_NUMPARTS({indices_reference}), // unusedBoneCount\n"
f"\t{values_reference}, // values\n"
f"\t{indices_reference}, // index\n"
"\t0\n"
"};\n"
)

def toBinary(self, indicesReference, valuesReference):
def to_binary(self, indices_reference: str, values_reference: str, bone_count: int):
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
data.extend(valuesReference.to_bytes(4, byteorder="big", signed=False)) # 0x0C
data.extend(indicesReference.to_bytes(4, byteorder="big", signed=False)) # 0x10
data.extend(bone_count.to_bytes(2, byteorder="big", signed=True)) # 0x0A
data.extend(values_reference.to_bytes(4, byteorder="big", signed=False)) # 0x0C
data.extend(indices_reference.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 @@ -228,8 +233,8 @@ def read_c(self, value: Initialization):

@dataclasses.dataclass
class SM64_Anim:
indicesReference: str = ""
valuesReference: str = ""
indices_reference: str = ""
values_reference: str = ""
reference: bool = False
headers: list[SM64_AnimHeader] = dataclasses.field(default_factory=list)
pairs: list[SM64_AnimPair] = dataclasses.field(default_factory=list)
Expand All @@ -240,8 +245,8 @@ def create_tables(self):
def find_offset(added_pairs: list[SM64_AnimPair], pair: SM64_AnimPair):
offset = None
for added_pair in added_pairs:
for i, j in zip(pair.values[0 : len(added_pair.values)], added_pair.values[0 : len(pair.values)]):
offset = pair.offset
for i, j in zip(pair.values[: len(pair.values)], added_pair.values[: len(pair.values)]):
offset = added_pair.offset
if abs(i - j) > 1:
offset = None
break
Expand All @@ -250,8 +255,8 @@ def find_offset(added_pairs: list[SM64_AnimPair], pair: SM64_AnimPair):
print("Merging values and creating tables.")

value_table, indices_table, added_pairs = (
SM64_ShortArray(self.valuesReference, True),
SM64_ShortArray(self.indicesReference, False),
SM64_ShortArray(self.values_reference, True),
SM64_ShortArray(self.indices_reference, False),
[],
)

Expand All @@ -263,51 +268,53 @@ def find_offset(added_pairs: list[SM64_AnimPair], pair: SM64_AnimPair):
pair.clean_frames()
existing_offset = find_offset(added_pairs, pair)
if existing_offset is None:
offset: int = len(value_table.data)
offset = len(value_table.data)
pair.offset = offset
value_table.data.extend(pair.values)
added_pairs.append(pair)
else:
offset: int = existing_offset
offset = existing_offset

if offset > MAX_U16:
raise PluginError("Value table is too big to fit in the index offset.")

indices_table.data.extend([len(pair.values), offset])

return value_table, indices_table

def toBinary(self, mergeValues: bool, isDMA: bool, startAddress: int) -> bytearray:
def to_binary(self, is_dma: bool, start_address: int) -> bytearray:
data: bytearray = bytearray()
ptrs: list[int] = []

if self.reference:
for header in self.headers:
headerData = header.toBinary(self.indicesReference, self.valuesReference)
data.extend(headerData)
return data, []

valueTable, indicesTable = self.createTables(mergeValues)

indicesOffset = headerSize * len(self.headers)
valuesOffset = indicesOffset + (len(indicesTable) * 2)
indicesReference, valuesReference = startAddress + indicesOffset, startAddress + valuesOffset
indices_reference, values_reference = self.indices_reference, self.values_reference
bone_count = 0
else:
values_table, indices_table = self.create_tables()
indices_offset = headerSize * len(self.headers)
indices_size = len(indices_table.data) * 2
values_offset = indices_offset + indices_size
bone_count = (len(self.pairs) // 3) - 1
indices_reference, values_reference = start_address + indices_offset, start_address + values_offset

for header in self.headers:
ptrs.extend([startAddress + len(data) + 12, startAddress + len(data) + 16])
headerData = header.toBinary(indicesReference, valuesReference)
data.extend(headerData)
ptrs.extend([start_address + len(data) + 12, start_address + len(data) + 16])
header_data = header.to_binary(indices_reference, values_reference, bone_count)
data.extend(header_data)

for value in indicesTable:
data.extend(value.to_bytes(2, byteorder="big", signed=False))
for value in valueTable:
data.extend(value.to_bytes(2, byteorder="big", signed=True))
if not self.reference:
data.extend(indices_table.to_binary())
data.extend(values_table.to_binary())

if isDMA:
if is_dma or self.reference:
return data, []
return data, ptrs
else:
return data, ptrs

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

Expand Down Expand Up @@ -366,8 +373,8 @@ def to_action(self, action, remove_name_footer: bool = True):
if action_props.get_anim_file_name(action) != self.fileName:
action_props.override_file_name = True

action_props.indices_table, action_props.indices_address = self.indicesReference, self.indicesReference
action_props.values_table, action_props.values_address = self.valuesReference, self.valuesReference
action_props.indices_table, action_props.indices_address = self.indices_reference, self.indices_reference
action_props.values_table, action_props.values_address = self.values_reference, self.values_reference

self.reference_tables = self.reference

Expand All @@ -382,23 +389,23 @@ def to_action(self, action, remove_name_footer: bool = True):
action_props.update_header_variant_numbers()

def read_binary(self, data: bytes, header: SM64_AnimHeader):
self.indicesReference = hex(header.indices)
self.valuesReference = hex(header.values)
self.indices_reference = hex(header.indices)
self.values_reference = hex(header.values)

indicesReader = RomReading(data, header.indices)
indices_reader = RomReading(data, header.indices)
for _ in range((header.bone_count + 1) * 3):
pair = SM64_AnimPair()
pair.read_binary(indicesReader, data, header.values)
pair.read_binary(indices_reader, data, header.values)
pair.clean_frames()
self.pairs.append(pair)

def read_c(self, header: SM64_AnimHeader, c_parser: CParser):
self.indicesReference = header.indices
self.valuesReference = header.values
self.indices_reference = header.indices
self.values_reference = header.values

if self.indicesReference in c_parser.values_by_name and self.valuesReference in c_parser.values_by_name:
indicesArray = c_parser.values_by_name[self.indicesReference]
valuesArray = c_parser.values_by_name[self.valuesReference]
if self.indices_reference in c_parser.values_by_name and self.values_reference in c_parser.values_by_name:
indicesArray = c_parser.values_by_name[self.indices_reference]
valuesArray = c_parser.values_by_name[self.values_reference]
self.fileName = os.path.basename(indicesArray.origin_path)
else:
self.fileName = os.path.basename(header.origin_path)
Expand All @@ -424,7 +431,7 @@ class SM64_AnimTable:
enum_list: set[str] = dataclasses.field(default_factory=set)
enum_indexed_elements: list[tuple[str, SM64_AnimHeader]] = dataclasses.field(default_factory=list)

def toBinary(self):
def to_binary(self):
pass

def enum_list_to_c(self):
Expand Down
28 changes: 1 addition & 27 deletions fast64_internal/sm64/animation/exporting.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import os
import re

import bpy
from bpy.types import Object, Action
Expand All @@ -15,8 +14,7 @@
from ...utility_anim import stashActionInArmature
from ..sm64_constants import NULL

from .classes import SM64_AnimHeader, SM64_Anim, SM64_AnimPair, SM64_AnimTable
from .c_parser import CParser
from .classes import SM64_Anim, SM64_AnimPair


def get_animation_pairs(
Expand Down Expand Up @@ -147,30 +145,6 @@ def updateDataFile(data_file_path, animFileName):
writeIfNotFound(data_file_path, f'#include "{animFileName}"\n', "")


def get_animation_data(
armature_obj: Object,
action: Action,
blender_to_sm64_scale: float,
actor_name: str = "",
):
action_props = action.fast64.sm64

stashActionInArmature(armature_obj, action)

animation = action_props.to_animation_class(action, actor_name)

if action_props.reference_tables:
animation.reference = True
if sm64Props.is_binary_export():
animation.valuesReference, animation.indicesReference = int(action_props.valuesAddress, 16), int(
action_props.indicesAddress, 16
)
else:
animation.pairs = get_animation_pairs(blender_to_sm64_scale, action, armature_obj)

return animation


def exportAnimTableInsertableBinary(
armature_obj: bpy.types.Object,
scene: bpy.types.Scene,
Expand Down
Loading

0 comments on commit 65adda8

Please sign in to comment.