Skip to content

[SM64] Add SM64 C Geo Layout & Level Importer#198

Open
jesusyoshi54 wants to merge 38 commits intoFast-64:mainfrom
jesusyoshi54:importers
Open

[SM64] Add SM64 C Geo Layout & Level Importer#198
jesusyoshi54 wants to merge 38 commits intoFast-64:mainfrom
jesusyoshi54:importers

Conversation

@jesusyoshi54
Copy link
Collaborator

This code adds a fully functional geo layout, and level importer for sm64 decomp code.

All models imported with the operators provided have close to 100% material accuracy (some odd modes are still not supported), and the geo layouts should also be fully imported.

This code can import full level models with objects, collision and graphics all in the correct hierarchy, or each one individually. It can also import actor geo layouts or level object geo layouts.

Currently the code needs further integration into the SM64 codebase, as it currently exists in a rather stand alone manner.

@Reonu
Copy link
Contributor

Reonu commented Aug 3, 2024

Tested this on both blender 4.2 and 4.1 Only BoB seems to import without errors (though the UVs are broken), TTC throws a bunch of errors and it imports only the collision. Everything else errors out and either nothing gets imported or only the actors get imported. Inside Castle which is what I'm trying to import doesn't work at all.

@Lilaa3 Lilaa3 mentioned this pull request Oct 14, 2024
1 task
@avereyishere
Copy link
Contributor

avereyishere commented Mar 3, 2025

Python: Traceback (most recent call last):
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 2141, in execute
geo_layout = find_actor_models_from_geo(
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1996, in find_actor_models_from_geo
geo_layout.parse_level_geo(layout_name, scene)
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1395, in parse_level_geo
self.parse_stream_from_start(geo_layout, start, 0)
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\utility_importer.py", line 58, in parse_stream_from_start
self.parse_stream(dat_stream, entry_id, *args, **kwargs)
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\utility_importer.py", line 70, in parse_stream
flow_status = func(cur_macro, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1492, in GEO_OPEN_NODE
GeoChild.parse_stream(self.geo_layouts.get(self.stream), self.stream, depth + 1)
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\utility_importer.py", line 70, in parse_stream
flow_status = func(cur_macro, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1492, in GEO_OPEN_NODE
GeoChild.parse_stream(self.geo_layouts.get(self.stream), self.stream, depth + 1)
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\utility_importer.py", line 70, in parse_stream
flow_status = func(cur_macro, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1492, in GEO_OPEN_NODE
GeoChild.parse_stream(self.geo_layouts.get(self.stream), self.stream, depth + 1)
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\utility_importer.py", line 70, in parse_stream
flow_status = func(cur_macro, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1492, in GEO_OPEN_NODE
GeoChild.parse_stream(self.geo_layouts.get(self.stream), self.stream, depth + 1)
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\utility_importer.py", line 70, in parse_stream
flow_status = func(cur_macro, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1492, in GEO_OPEN_NODE
GeoChild.parse_stream(self.geo_layouts.get(self.stream), self.stream, depth + 1)
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\utility_importer.py", line 70, in parse_stream
flow_status = func(cur_macro, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1492, in GEO_OPEN_NODE
GeoChild.parse_stream(self.geo_layouts.get(self.stream), self.stream, depth + 1)
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\utility_importer.py", line 70, in parse_stream
flow_status = func(cur_macro, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1492, in GEO_OPEN_NODE
GeoChild.parse_stream(self.geo_layouts.get(self.stream), self.stream, depth + 1)
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\utility_importer.py", line 70, in parse_stream
flow_status = func(cur_macro, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1492, in GEO_OPEN_NODE
GeoChild.parse_stream(self.geo_layouts.get(self.stream), self.stream, depth + 1)
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\utility_importer.py", line 70, in parse_stream
flow_status = func(cur_macro, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1492, in GEO_OPEN_NODE
GeoChild.parse_stream(self.geo_layouts.get(self.stream), self.stream, depth + 1)
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\utility_importer.py", line 70, in parse_stream
flow_status = func(cur_macro, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1114, in GEO_ROTATION_NODE
geo_obj = self.GEO_ROTATE(macro, depth)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1122, in GEO_ROTATE
return self.setup_geo_obj("rotate", self.translate_rotate, macro.args[0])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1361, in setup_geo_obj
self.set_geo_type(geo_obj, geo_cmd)
File "C:\Users\wowiz\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\fast64-KCS-importers\fast64_internal\sm64\sm64_level_importer.py", line 1343, in set_geo_type
geo_obj.sm64_obj_type = geo_cmd
^^^^^^^^^^^^^^^^^^^^^
TypeError: bpy_struct: item.attr = val: enum "Geo Translate/Rotat" not found in ('None', 'Level Root', 'Area Root', 'Object', 'Macro', 'Special', 'Mario Start', 'Whirlpool', 'Water Box', 'Camera Volume', 'Switch', 'Puppycam Volume', 'Geo ASM', 'Geo Branch', 'Geo Translate/Rotate', 'Geo Translate Node', 'Geo Rotation Node', 'Geo Billboard', 'Geo Scale', 'Geo Displaylist', 'Custom Geo Command')

@jesusyoshi54
Copy link
Collaborator Author

yeah I'm aware armatures don't work currently. this is still WIP

@Lilaa3 Lilaa3 linked an issue May 7, 2025 that may be closed by this pull request
@Reonu
Copy link
Contributor

Reonu commented Nov 22, 2025

@jesusyoshi54 not sure if you're still working on this, but I tried to import Castle Grounds (from a HackerSM64 3.0 repo in order to avoid macro objects) and it didn't work at all:

Info: Success!
Info: Success!
Info: Deleted 3 object(s)
Traceback (most recent call last):
  File "/home/reonu/.config/blender/4.5/scripts/addons/fast64-main/fast64_internal/sm64/sm64_level_importer.py", line 2394, in execute
    lvl = parse_level_script(
          ^^^^^^^^^^^^^^^^^^^
  File "/home/reonu/.config/blender/4.5/scripts/addons/fast64-main/fast64_internal/sm64/sm64_level_importer.py", line 1870, in parse_level_script
    lvl.parse_level_script(entry, col=col)
  File "/home/reonu/.config/blender/4.5/scripts/addons/fast64-main/fast64_internal/sm64/sm64_level_importer.py", line 317, in parse_level_script
    self.parse_stream_from_start(script_stream, entry, col)
  File "/home/reonu/.config/blender/4.5/scripts/addons/fast64-main/fast64_internal/utility_importer.py", line 57, in parse_stream_from_start
    self.parse_stream(dat_stream, entry_id, *args, **kwargs)
  File "/home/reonu/.config/blender/4.5/scripts/addons/fast64-main/fast64_internal/utility_importer.py", line 67, in parse_stream
    raise Exception(f"Macro {cur_macro} not found in parser function")
Exception: Macro Macro(cmd='#include "levels/castle_grounds/areas/script_vanilla_load.inc.c"    ALLOC_LEVEL_POOL', args=['']) not found in parser function
Error: Python: Traceback (most recent call last):
  File "/home/reonu/.config/blender/4.5/scripts/addons/fast64-main/fast64_internal/sm64/sm64_level_importer.py", line 2394, in execute
    lvl = parse_level_script(
          ^^^^^^^^^^^^^^^^^^^
  File "/home/reonu/.config/blender/4.5/scripts/addons/fast64-main/fast64_internal/sm64/sm64_level_importer.py", line 1870, in parse_level_script
    lvl.parse_level_script(entry, col=col)
  File "/home/reonu/.config/blender/4.5/scripts/addons/fast64-main/fast64_internal/sm64/sm64_level_importer.py", line 317, in parse_level_script
    self.parse_stream_from_start(script_stream, entry, col)
  File "/home/reonu/.config/blender/4.5/scripts/addons/fast64-main/fast64_internal/utility_importer.py", line 57, in parse_stream_from_start
    self.parse_stream(dat_stream, entry_id, *args, **kwargs)
  File "/home/reonu/.config/blender/4.5/scripts/addons/fast64-main/fast64_internal/utility_importer.py", line 67, in parse_stream
    raise Exception(f"Macro {cur_macro} not found in parser function")
Exception: Macro Macro(cmd='#include "levels/castle_grounds/areas/script_vanilla_load.inc.c"    ALLOC_LEVEL_POOL', args=['']) not found in parser function

I'm on blender 4.5.4

@Reonu
Copy link
Contributor

Reonu commented Nov 22, 2025

Importing from ultrasm64 does work though

scut added 2 commits January 25, 2026 22:29
scut and others added 6 commits January 29, 2026 20:51
… parsing, fixed certain vanilla level oddities
…en using Lights_t or other structs, fixed texture imports when DLs use numbers instead of macros, fixed default color combiner not being shaded solid, fixed texture set being from for base f3d mode, fixed some var names that caused errors, started working on binary and byte stream texture IO
…LC_DXT in load blocks, added texture importing from string arrays in model files
@kdehl16-web
Copy link

re-run this

scut and others added 9 commits February 9, 2026 19:27
… reworked parsing and level importing modules to be cleaner
…, made actor importing use animations PR actor presets
…layout importing bone offsets and naming issues and various other geo issues
…, fixed actors that had common group models not having proper context
…se level functions, changed tile property parsing, added actor collision importing
@jesusyoshi54 jesusyoshi54 marked this pull request as ready for review February 23, 2026 22:07
@jesusyoshi54
Copy link
Collaborator Author

jesusyoshi54 commented Feb 23, 2026

Summary of changes:
This PR adds in new data parsing functionality for use in importing from either C or binary code. Currently supports importing Geo Layouts, Collision, Objects and Models from SM64 levels or objects.

Features:

  • Imports full levels from decomp repos or binary roms
  • Imports actor armatures from decomp or binary (try with animation importer!~)
  • Custom imports for objects and levels given entry point (seg ptr name)
  • Imports all actor models used in model while importing model
  • Removes old SM64 Binary geo layout and DL importers

Description of code:
The new import code is split into 4 major files.
Utility_importer contains data parsing base classes and C preprocessing utility functions.
f3d_import contains f3d data data parsing for DL and associated f3d data containers (materials, textures, tiles etc.)
sm64_level_importer contains the data parsers for sm64 data (geo layouts, level scripts) as well as the appropriate functions and properties for importing data.
bin_png module is used to convert binary data streams into png textures (I'm up to renaming it)

The theory of operation is basically that you use importer properties and assumptions about the import target to gather the appropriate C files with get_all_aggregates and then gather the necessary data types within those files with get_data_types_from_file (unnecessary in binary importing). After that you add the appropriate data to the data parser class (Level, Collision, DL etc.) and then run a parsing function, which is essentially a generator. The generator yields one Macro which maps to a single function call in the data parser subclass which parses the arguments. After parsing, data within the class can be used to write the appropriate output to blender.

edits to the function map were just to reformat it to deal with multiple keys, the data inside hasn't changed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement sm64 C importing?

4 participants