Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8dd4313
[SM64] Animations Rewrite/Rework
Lilaa3 Sep 30, 2024
74398bc
[SM64] Animations Rewrite/Rework
Lilaa3 Sep 30, 2024
d482ea5
Remove animation docs from README until I write new ones in fast64_docs
Lilaa3 Sep 30, 2024
944d223
Merge branch 'animations_rework' of github.com:Lilaa3/fast64 into ani…
Lilaa3 Oct 1, 2024
acacef7
remove accidental exports
Lilaa3 Oct 1, 2024
501232a
merge conflicts?
Lilaa3 Oct 1, 2024
eec5516
Fix level export includes dups
Lilaa3 Oct 1, 2024
b97f0aa
Fixed comment adjust function
Lilaa3 Oct 2, 2024
5812e86
change table properties to only have elements
Lilaa3 Oct 5, 2024
c4f10d6
Update properties.py
Lilaa3 Oct 6, 2024
849efe1
Rename
Lilaa3 Oct 6, 2024
e509c6b
bounds check
Lilaa3 Oct 6, 2024
4094086
keep default action name consistent with blender
Lilaa3 Oct 6, 2024
aa99b67
as_posix fix and clean up
Lilaa3 Oct 11, 2024
08493f9
Merge remote-tracking branch 'upstream/main' into animations_rework
Lilaa3 Oct 14, 2024
55c9273
designated is include in repo settings, include in tooltip
Lilaa3 Oct 14, 2024
ff3ed4b
Fix empty text files
Lilaa3 Oct 28, 2024
e1e1149
fix peach's address
Lilaa3 Dec 13, 2024
4bc91af
Some attempts at tasteful comments
Lilaa3 Dec 29, 2024
fa39bfd
allow str, use path in f3d writer
Lilaa3 Dec 30, 2024
0fc5822
Merge remote-tracking branch 'upstream/main' into animations_rework
Lilaa3 Apr 15, 2025
1df6dd0
better valid filename func
Lilaa3 Apr 18, 2025
09aa244
Merge remote-tracking branch 'upstream/main' into animations_rework
Lilaa3 May 20, 2025
d204154
Merge remote-tracking branch 'upstream/main' into animations_rework
Lilaa3 May 30, 2025
a282c30
Merge remote-tracking branch 'upstream/main' into animations_rework
Lilaa3 Aug 15, 2025
a266582
Merge remote-tracking branch 'upstream/main' into animations_rework
Lilaa3 Aug 15, 2025
381ada7
Merge remote-tracking branch 'upstream/main' into animations_rework
Lilaa3 Aug 15, 2025
2ff4bc9
fix things!
Lilaa3 Aug 15, 2025
6fa0b72
Merge remote-tracking branch 'upstream/main' into animations_rework
Lilaa3 Aug 16, 2025
098c224
review and a personal nit
Lilaa3 Aug 18, 2025
a71b3c2
Add docs link
Lilaa3 Aug 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
repo_settings_operators_unregister,
)

from .fast64_internal.sm64 import sm64_register, sm64_unregister
from .fast64_internal.sm64 import sm64_register, sm64_unregister, SM64_ActionProperty
from .fast64_internal.sm64.sm64_constants import sm64_world_defaults
from .fast64_internal.sm64.settings.properties import SM64_Properties
from .fast64_internal.sm64.sm64_geolayout_bone import SM64_BoneProperties
Expand Down Expand Up @@ -246,6 +246,14 @@ class Fast64_Properties(bpy.types.PropertyGroup):
renderSettings: bpy.props.PointerProperty(type=Fast64RenderSettings_Properties, name="Fast64 Render Settings")


class Fast64_ActionProperties(bpy.types.PropertyGroup):
"""
Properties in Action.fast64.
"""

sm64: bpy.props.PointerProperty(type=SM64_ActionProperty, name="SM64 Properties")


class Fast64_BoneProperties(bpy.types.PropertyGroup):
"""
Properties in bone.fast64 (bpy.types.Bone)
Expand Down Expand Up @@ -315,6 +323,7 @@ def draw(self, context):
Fast64RenderSettings_Properties,
ManualUpdatePreviewOperator,
Fast64_Properties,
Fast64_ActionProperties,
Fast64_BoneProperties,
Fast64_ObjectProperties,
F3D_GlobalSettingsPanel,
Expand Down Expand Up @@ -464,7 +473,7 @@ def register():
bpy.types.Scene.fast64 = bpy.props.PointerProperty(type=Fast64_Properties, name="Fast64 Properties")
bpy.types.Bone.fast64 = bpy.props.PointerProperty(type=Fast64_BoneProperties, name="Fast64 Bone Properties")
bpy.types.Object.fast64 = bpy.props.PointerProperty(type=Fast64_ObjectProperties, name="Fast64 Object Properties")

bpy.types.Action.fast64 = bpy.props.PointerProperty(type=Fast64_ActionProperties, name="Fast64 Action Properties")
bpy.app.handlers.load_post.append(after_load)


Expand Down Expand Up @@ -492,6 +501,7 @@ def unregister():
del bpy.types.Scene.fast64
del bpy.types.Bone.fast64
del bpy.types.Object.fast64
del bpy.types.Action.fast64

repo_settings_operators_unregister()

Expand Down
64 changes: 59 additions & 5 deletions fast64_internal/operators.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
import bpy, mathutils, math
from bpy.types import Operator, Context, UILayout
from cProfile import Profile
from pstats import SortKey, Stats
from typing import Optional

import bpy, mathutils
from bpy.types import Operator, Context, UILayout, EnumProperty
from bpy.utils import register_class, unregister_class
from .utility import *
from .f3d.f3d_material import *

from .utility import (
cleanupTempMeshes,
get_mode_set_from_context_mode,
raisePluginError,
parentObject,
store_original_meshes,
store_original_mtx,
)
from .f3d.f3d_material import createF3DMat


def addMaterialByName(obj, matName, preset):
Expand All @@ -14,20 +26,29 @@ def addMaterialByName(obj, matName, preset):
material.name = matName


PROFILE_ENABLED = False


class OperatorBase(Operator):
"""Base class for operators, keeps track of context mode and sets it back after running
execute_operator() and catches exceptions for raisePluginError()"""

context_mode: str = ""
icon = "NONE"

@classmethod
def is_enabled(cls, context: Context, **op_values):
return True

@classmethod
def draw_props(cls, layout: UILayout, icon="", text: Optional[str] = None, **op_values):
"""Op args are passed to the operator via setattr()"""
icon = icon if icon else cls.icon
layout = layout.column()
op = layout.operator(cls.bl_idname, icon=icon, text=text)
for key, value in op_values.items():
setattr(op, key, value)
layout.enabled = cls.is_enabled(bpy.context, **op_values)
return op

def execute_operator(self, context: Context):
Expand All @@ -40,7 +61,12 @@ def execute(self, context: Context):
try:
if self.context_mode and self.context_mode != starting_mode_set:
bpy.ops.object.mode_set(mode=self.context_mode)
self.execute_operator(context)
if PROFILE_ENABLED:
with Profile() as profile:
self.execute_operator(context)
print(Stats(profile).strip_dirs().sort_stats(SortKey.CUMULATIVE).print_stats())
else:
self.execute_operator(context)
return {"FINISHED"}
except Exception as exc:
raisePluginError(self, exc)
Expand All @@ -53,6 +79,34 @@ def execute(self, context: Context):
bpy.ops.object.mode_set(mode=starting_mode_set)


class SearchEnumOperatorBase(OperatorBase):
bl_description = "Search Enum"
bl_label = "Search"
bl_property = None
bl_options = {"UNDO"}

@classmethod
def draw_props(cls, layout: UILayout, data, prop: str, name: str):
row = layout.row()
if name:
row.label(text=name)
row.prop(data, prop, text="")
row.operator(cls.bl_idname, icon="VIEWZOOM", text="")

def update_enum(self, context: Context):
raise NotImplementedError()

def execute_operator(self, context: Context):
assert self.bl_property
self.report({"INFO"}, f"Selected: {getattr(self, self.bl_property)}")
self.update_enum(context)
context.region.tag_redraw()

def invoke(self, context: Context, _):
context.window_manager.invoke_search_popup(self)
return {"RUNNING_MODAL"}


class AddWaterBox(OperatorBase):
bl_idname = "object.add_water_box"
bl_label = "Add Water Box"
Expand Down
35 changes: 3 additions & 32 deletions fast64_internal/sm64/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,38 +52,7 @@ For example, for Mario you would rotate the four limb joints around the Y-axis 1

Then after applying the rest pose and skinning, you would apply those operations in reverse order then apply rest pose again.

### Importing/Exporting Binary SM64 Animations (Not Mario)
- Note: SM64 animations only allow for rotations, and translation only on the root bone.

- Download Quad64, open the desired level, and go to Misc -> Script Dumps.
- Go to the objects header, find the object you want, and view the Behaviour Script tab.
- For most models with animation, you can will see a 27 command, and optionally a 28 command.

For importing:

- The last 4 bytes of the 27 command will be the animation list pointer.
- Make sure 'Is DMA Animation' is unchecked, 'Is Anim List' is checked, and 'Is Segmented Pointer' is checked.
- Set the animation importer start address as those 4 bytes.
- If a 28 command exists, then the second byte will be the anim list index.
- Otherwise, the anim list index is usually 0.

For exporting:

- Make sure 'Set Anim List Entry' is checked.
- Copy the addresses of the 27 command, which is the first number before the slash on that line.
- Optionally do the same for the 28 command, which may not exist.
- If a 28 command exists, then the second byte will be the anim list index.
- Otherwise, the anim list index is usually 0.

Select an armature for the animation, and press 'Import/Export animation'.

### Importing/Exporting Binary Mario Animations
Mario animations use a DMA table, which contains 8 byte entries of (offset from table start, animation size). Documentation about this table is here:
https://dudaw.webs.com/sm64docs/sm64_marios_animation_table.txt
Basically, Mario's DMA table starts at 0x4EC000. There is an 8 byte header, and then the animation entries afterward. Thus the 'climb up ledge' DMA entry is at 0x4EC008. The first 4 bytes at that address indicate the offset from 0x4EC000 at which the actual animation exists. Thus the 'climb up ledge' animation entry address is at 0x4EC690. Using this table you can find animations you want to overwrite. Make sure the 'Is DMA Animation' option is checked and 'Is Segmented Pointer' is unchecked when importing/exporting. Check "Overwrite DMA Entry", set the start address to 4EC000 (for Mario), and set the entry address to the DMA entry obtained previously.

### Animating Existing Geolayouts
Often times it is hard to rig an existing SM64 geolayout, as there are many intermediate non-deform bones and bones don't point to their children. To make this easier you can use the 'Create Animatable Metarig' operator in the SM64 Armature Tools header. This will generate a metarig which can be used with IK. The metarig bones will be placed on armature layers 3 and 4.
### [Animations](https://fast64.readthedocs.io/en/latest/sm64/animations/index.html)

## Decomp
To start, set your base decomp folder in SM64 General Settings. This allows the plugin to automatically add headers/includes to the correct locations. You can always choose to export to a custom location, although headers/includes won't be written.
Expand Down Expand Up @@ -165,6 +134,8 @@ Insertable Binary exporting will generate a binary file, with a header containin
1 = Geolayout
2 = Animation
3 = Collision
4 = Animation Table
5 = Animation DMA Table

0x04-0x08 : Data Size (size in bytes of Data Section)
0x08-0x0C : Start Address (start address of data, relative to start of Data Section)
Expand Down
33 changes: 24 additions & 9 deletions fast64_internal/sm64/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from bpy.types import PropertyGroup
from bpy.props import PointerProperty
from bpy.utils import register_class, unregister_class

from .settings import (
settings_props_register,
settings_props_unregister,
Expand Down Expand Up @@ -83,14 +87,23 @@
sm64_dl_writer_unregister,
)

from .sm64_anim import (
sm64_anim_panel_register,
sm64_anim_panel_unregister,
sm64_anim_register,
sm64_anim_unregister,
from .animation import (
anim_panel_register,
anim_panel_unregister,
anim_register,
anim_unregister,
SM64_ActionAnimProperty,
)


class SM64_ActionProperty(PropertyGroup):
"""
Properties in Action.fast64.sm64.
"""

animation: PointerProperty(type=SM64_ActionAnimProperty, name="SM64 Properties")


def sm64_panel_register():
settings_panels_register()
tools_panels_register()
Expand All @@ -103,7 +116,7 @@ def sm64_panel_register():
sm64_spline_panel_register()
sm64_dl_writer_panel_register()
sm64_dl_parser_panel_register()
sm64_anim_panel_register()
anim_panel_register()


def sm64_panel_unregister():
Expand All @@ -118,12 +131,13 @@ def sm64_panel_unregister():
sm64_spline_panel_unregister()
sm64_dl_writer_panel_unregister()
sm64_dl_parser_panel_unregister()
sm64_anim_panel_unregister()
anim_panel_unregister()


def sm64_register(register_panels: bool):
tools_operators_register()
tools_props_register()
anim_register()
sm64_col_register()
sm64_bone_register()
sm64_cam_register()
Expand All @@ -134,8 +148,8 @@ def sm64_register(register_panels: bool):
sm64_spline_register()
sm64_dl_writer_register()
sm64_dl_parser_register()
sm64_anim_register()
settings_props_register()
register_class(SM64_ActionProperty)

if register_panels:
sm64_panel_register()
Expand All @@ -144,6 +158,7 @@ def sm64_register(register_panels: bool):
def sm64_unregister(unregister_panels: bool):
tools_operators_unregister()
tools_props_unregister()
anim_unregister()
sm64_col_unregister()
sm64_bone_unregister()
sm64_cam_unregister()
Expand All @@ -154,8 +169,8 @@ def sm64_unregister(unregister_panels: bool):
sm64_spline_unregister()
sm64_dl_writer_unregister()
sm64_dl_parser_unregister()
sm64_anim_unregister()
settings_props_unregister()
unregister_class(SM64_ActionProperty)

if unregister_panels:
sm64_panel_unregister()
15 changes: 15 additions & 0 deletions fast64_internal/sm64/animation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from .operators import anim_ops_register, anim_ops_unregister
from .properties import anim_props_register, anim_props_unregister, SM64_ArmatureAnimProperties, SM64_ActionAnimProperty
from .panels import anim_panel_register, anim_panel_unregister
from .exporting import export_animation, export_animation_table
from .utility import get_anim_obj, is_obj_animatable


def anim_register():
anim_ops_register()
anim_props_register()


def anim_unregister():
anim_ops_unregister()
anim_props_unregister()
Loading