======== Geometry Layout Commands ========
The geometry layout commands define how geometric shapes are drawn. Some geo layouts are contained after the Level data blocks and some are loaded with [[super_mario_64:level_commands#17: Load ROM to Segment|Level Command 0x17]] The first byte of the geo layout command is the command type. Unlike the level commands, there is no length byte specified in the command. Most geo layout commands are constant length, however, some depend on the values set.
Once geo layouts are loaded, they are processed into a graph node system. Graph nodes are a linked list that setup the rendering properties of display lists inside.
===== Drawing Layers =====
^ Layer ^ Description ^
| 00 | Opaque no AA |
| 01 | Opaque has AA (Blending disabled). |
| 02 | Decals or triangles that draw on top of geometry near the same depth (Lessened depth-range). Blending disabled. **Only** renders when //very close or on other polygons// on real hardware. |
| 03 | Intersecting Polygons (computes AA along the edge of intersection, otherwise opaque) |
| 04 | Transparent pixels, no blending (OpenGL's equivalent is Alphatest). Allows perfect layering with other transparencies around it. |
| 05 | Blending (translucency) enabled. Layering must be handled with the order of drawn faces. |
| 06 | Blending (translucency) enabled. Layering must be handled with the order of drawn faces. Decal mode like layer 2. Lessened depth-range. |
| 07 | Blending enabled. Layering must be handled with the order of drawn faces. Intersecting mode like layer 3. |
===== Graph Nodes =====
==== Graph Node Header ====
Every graph node has the same header. Depending on the geo layout cmd, the subsequent bytes will be different. Like geo layouts, graph nodes have no length byte.
^ value ^ type ^ description ^
| *0x00* | s16 type; | structure type |
| *0x02* | s16 flags; | hi = drawing layer, lo = graph render flags |
| *0x04* | struct GraphNode | previous node |
| *0x08* | struct GraphNode | next node |
| *0x0C* | struct GraphNode | parent node |
| *0x10* | struct GraphNode | child nodes |
==== GraphNode Render Flags ====
^ value ^ description ^
| 0x0001 | Render Active |
| 0x0002 | Render Children First |
| 0x0004 | Render Billboard |
| 0x0008 | Render Z Buffer |
| 0x0010 | Render Invisible |
| 0x0020 | Render Has Animation |
==== GraphNode Types ====
Types of graph nodes. This value goes inside the first byte of the graph node header once the geo layout is loaded.
^ value ^ description ^
| 0x01 | root |
| 0x02 | ortho projection |
| 0x03 | perspective |
| 0x04 | master list |
| 0x0A | start |
| 0x0B | level of detail |
| 0x0c | switch case |
| 0x14 | camera |
| 0x15 | translation rotation |
| 0x16 | translation |
| 0x17 | rotation |
| 0x18 | object |
| 0x19 | animated part |
| 0x1A | billboard |
| 0x1B | display list |
| 0x1C | scale |
| 0x28 | shadow |
| 0x29 | object parent |
| 0x2A | generated list |
| 0x2C | background |
| 0x2E | held object|
| 0x2F | culling radius |
===== Geometry Layout Commands =====
==== 00: Branch and Store ====
Branches to segmented address and stores 2 return addresses.
''00 00 00 00 [SS SS SS SS]''
| S | Segmented address to branch to |
/* Geo Layout 0x00 Rough translation. */
// 0x8038BD80 = Pointer to current Geo layout command
// 0x8038BCB8 = Pointer to array/table to where branch return pointers are stored.
// 0x8038BD7A = Branch depth value.
*(0x8038BCB8 + (0x8038BD7A * 4)) = *0x8038BD80 + 8; // Stores the pointer to the next geo command
*0x8038BD7A += 1; // Increment branch value
*(0x8038BCB8 + (0x8038BD7A * 4)) = (*0x8038BD78 << 16) + *0x8038BD7E; // Store another address
*0x8038BD7A += 1; // Increment branch value
*0x8038BD7E = *0x8038BD7A;
0x8038BD80 = SegmentedToVirtual(0x8038BD80 + 4); // Go to the segmented address.
Length: 8
----
==== 01: Terminate Geometry Layout ====
The ending command to close.
''01 00 00 00''
Length: 4
----
==== 02: Branch Geometry Layout ====
Branches the current geo layout to another area within a RAM bank.
''02 [AA] 00 00 [SS SS SS SS]''
| A | 0 = Jump, 1 = Jump and store return address |
| S | Segmented address to branch to |
Length: 8
----
==== 03: Return From Branch ====
Ends the current geometry layout branch and returns to the area following the 0x02 command.
''03 00 00 00''
Length: 4
----
==== 04: Open Node ====
If you don't understand nodes, this is basically like a sub-folder.
''04 00 00 00''
Length: 4
----
==== 05: Close Node ====
Used at the end of the data within the opened node.
''05 00 00 00''
Length: 4
----
==== 06: Store Current Node Pointer To Table (Unused) ====
''06 00 [XX XX]''
Stores the pointer of the last node into the table at address (*0x8038BCAC). This table is usually empty except for the first entry (index 0), which holds the pointer to the node created by the geo layout 0x0F command. The size of the table is defined by the geo layout 0x08 command.
| X | Index in table to store pointer |
Example in a geometry layout:
0A 01 002D 0064 4E20 8029AA3C // Set camera frustum (FOV = 45, Near = 100, Far = 20000)
06 00 00 01 // Store pointer of the 0x0A command node to address ((*0x8038BCAC) + 4)
----
==== 07: Set/OR/AND Node Flags (Unused) ====
''06 [OP] [VV VV]''
Does an operation on the flags of the current node. (Flags are at offset 0x02 of the GraphNode structure)
| OP | Operation (0 = Set flags to value, 1 = OR flags with value, 2 = AND flags with value) |
| V | Value |
Example in a geometry layout:
0A 01 002D 0064 4E20 8029AA3C // Set camera frustum (FOV = 45, Near = 100, Far = 20000)
07 00 00 01 // Set Node flags of 0x0A command to be 0x0001
07 01 01 00 // OR Node flags with 0x0100
07 02 00 01 // AND Node flags with 0x0001
----
==== 08: Set Screen Render Area ====
Only used in geo layout of levels.
Sets graph node type 0x0001
''08 00 00 [AA] [XX XX] [YY YY] [WW WW] [HH HH]''
| A | Number of entries (minus 2) to allocate in pointer table at address (*0x8038BCAC). Usually set to 0x0A for levels, and 0 for mario face. Used with the geometry layout 0x06 command. |
| X | X position |
| Y | Y position |
| W | Width of screen |
| H | Height of screen |
struct GraphNodeRoot
{
/*0x00*/ struct GraphNode node;
/*0x14*/ u8 areaIndex;
/*0x15*/ s8 unk15; // ?
/*0x16*/ s16 x;
/*0x18*/ s16 y;
/*0x1A*/ s16 width; // half width, 160
/*0x1C*/ s16 height; // half height
/*0x1E*/ s16 numViews; // number of entries in mystery array
/*0x20*/ struct GraphNode **views;
};
Length: C
----
==== 09: Create Ortho Matrix ====
Sets ortho matrix for level backgrounds.
It is unknown if this command is actually necessary or not. You can remove this command from a level's geometry layout and it won't affect the background, and changing the scale value has no visible effect either.
''09 00 [AA AA]''
| A | Scale of near plane, usually set to 0x64. Gets converted to a float and then divided by 100.0f |
Length: 4
struct GraphNodeOrthoProjection
{
/*0x00*/ struct GraphNode node;
/*0x14*/ f32 scale;
};
----
==== 0A: Set Camera Frustum ====
Set camera frustum properties. Only used in geo layout of levels.
GraphNode type 0x03
''0A [AA] [BB BB] [NN NN] [FF FF] {EE EE EE EE}''
| A | Use ASM code defined by E |
| B | Camera FOV (0x2D = 45) |
| N | Camera Near |
| F | Camera Far |
| E | optional ASM function if A is non-zero (always 8029AA3C) |
struct GraphNodePerspective
{
/*0x00*/ struct FnGraphNode fnNode;
/*0x14*/ void *Function
/*0x18*/ s32 unused;
/*0x1C*/ f32 fov; // horizontal field of view in degrees
/*0x20*/ s16 near; // near clipping plane
/*0x22*/ s16 far; // far clipping plane
};
Length: 8-C (variable)
----
==== 0B: Start Geo Layout ====
Starts geometry layout with no parameters whatsoever. Seems to use a pre-set render area.
''0B 00 00 00''
struct GraphNodeStart
{
/*0x00*/ struct GraphNode node;
};
Length: 4
----
==== 0C: Enable/Disable Z-Buffer ====
This command is used in level geometry layouts. Z-Buffering is disabled when rendering the skybox, and re-enabled when rendering level geometry.
GraphNode type 0x04
''0C [AA] 00 00''
| A | 0x00 = Disable Z-buffer, 0x01 = Enable Z-buffer |
''[ 0C 01 00 00 ]'' will add the following Fast3D data to the following node:
E7 00 00 00 00 00 00 00
B7 00 00 00 00 00 00 01
// Node's Fast3D commands
E7 00 00 00 00 00 00 00
B6 00 00 00 00 00 00 01
Length: 4
----
==== 0D: Set Render Range ====
Used in WF, CCM, TTM, SSL levels and some geo layouts. This command will make the following node only render in a certain distance range away from the camera.
GraphNode type 0x0B
''0D 00 00 00 [AA AA] [BB BB]''
| A | (s16) Minimum distance value |
| B | (s16) Maximum distance value |
Example from "Grassy Level Part" in Whomp's fortress:
0049E3A8 / 0E000958 [ 20 00 07 D0 ]
0049E3AC / 0E00095C [ 04 00 00 00 ]
0049E3B0 / 0E000960 [ 0D 00 00 00 F8 30 1F 40 ]
0049E3B8 / 0E000968 [ 04 00 00 00 ]
0049E3BC / 0E00096C [ 15 01 00 00 07 00 AB A0 ] // Real geometry (Camera is nearby)
0049E3C4 / 0E000974 [ 15 06 00 00 07 00 AF B8 ]
0049E3CC / 0E00097C [ 05 00 00 00 ]
0049E3D0 / 0E000980 [ 0D 00 00 00 1F 40 4E 20 ]
0049E3D8 / 0E000988 [ 04 00 00 00 ]
0049E3DC / 0E00098C [ 15 01 00 00 07 00 AE C8 ] // Fake geometry (Camera is far away)
0049E3E4 / 0E000994 [ 05 00 00 00 ]
0049E3E8 / 0E000998 [ 05 00 00 00 ]
0049E3EC / 0E00099C [ 01 00 00 00 ]
struct GraphNodeLevelOfDetail
{
/*0x00*/ struct GraphNode node;
/*0x14*/ s16 minDistance;
/*0x16*/ s16 maxDistance;
};
Length: 8
----
==== 0E: Switch Case ====
Loads ASM in RAM that switches between the receding display lists within the node.
GraphNode type 0x0C
''0E 00 00 [NN] [AA AA AA AA]''
| N | Number of cases/display lists, starting at 01 |
| A | ASM Function |
struct GraphNodeSwitchCase
{
/*0x00*/ struct FnGraphNode fnNode;
/*0x14*/ void *Function
/*0x18*/ s32 unused;
/*0x1C*/ s16 numCases;
/*0x1E*/ s16 selectedCase;
};
Length: 8
----
==== 0F: Create Camera Graph Node ====
GraphNode type 0x14.
''0F 00 [TT TT] [XX XX] [YY YY] [ZZ ZZ] [UU UU] [VV VV] [WW WW] [AA AA AA AA]''
| T | cam type |
| X | x location (s16) |
| Y | y location (s16) |
| Z | z location (s16) |
| U | x focus (s16) |
| V | y focus (s16) |
| W | z focuz (s16) |
| A | ASM function. Always 80287D30 (levels) or 00 (menus) |
struct GraphNodeCamera
{
/*0x00*/ struct FnGraphNode fnNode;
/*0x18*/ union {
s32 preset;
struct LevelCamera *levelCamera;
} config;
/*0x1C*/ Vec3f from;
/*0x28*/ Vec3f to;
/*0x34*/ void *matrixPtr; // pointer to look-at matrix of this camera as a Mat4
/*0x38*/ s16 roll; // roll in look at matrix. Doesn't account for light direction unlike rollScreen.
/*0x3A*/ s16 rollScreen; // rolls screen while keeping the light direction consistent
};
Length: 0x14
----
==== 10: Translate and Rotate ====
Applies translation & rotation to the following node.
GraphNode type 0x15
''10 [AA] [BB BB] [XX XX] [YY YY] [ZZ ZZ] [RX RX] [RY RY] [RZ RZ]''
| A | Branching flag |
| B | Used if A != 0 |
| X | X translation offset (s16) |
| Y | Y translation offset (s16) |
| Z | Z translation offset (s16) |
| RX | X rotation (s16) |
| RY | Y rotation (s16) |
| RZ | Z rotation (s16) |
struct GraphNodeTranslationRotation
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
/*0x18*/ Vec3s translation;
/*0x1E*/ Vec3s rotation;
};
Length: 0x10
----
==== 11: Translate Node (and Load Display List or Start Geo Layout) ====
Applies translation to the child nodes, and a display list if one is specified. You can start a geometry layout with this command to set the offset for the entire model. You cannot start a geometry layout and load a display list at the same time, as it will cause the game to freeze (white-screen).
GraphNode type 0x16
''11 [B][L] [XX XX] [YY YY] [ZZ ZZ] {AA AA AA AA}''
| B | Include last 4 bytes if set to 8 (command will be C bytes long instead of 8) |
| L | Drawing layer if B is set, otherwise will always be zero |
| X | X translation offset (s16) |
| Y | Y translation offset (s16) |
| Z | Z translation offset (s16) |
| A | Segmented address with display list if B is set. \\ Also creates a joint of some kind? (Does not work with animations?) |
struct GraphNodeTranslation
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
/*0x18*/ Vec3s translation;
u8 pad1E[2];
};
Length: 8-C (variable)
Note: You can't just use the 8-byte version of 0x11 command just anywhere. It seems like the command needs a joint in it's parent node(s) for it to work properly (created from geo layout commands 0x11, 0x12, and 0x13).
0B000000
04000000
11 00 0000 0100 0000 // This will cause a crash
04000000
15 01 00 00 0700A290
05000000
05000000
01000000
0B000000
04000000
11 80 0000 0100 0000 00000000 // This will work, since it creates a joint.
04000000
15 01 00 00 0700A290
05000000
05000000
01000000
11 00 0000 0100 0000 // This will also work, since it is starting the geo layout.
04000000
15 01 00 00 0700A290
05000000
01000000
0B000000
04000000
13 01 0000 0000 0000 00000000
04000000
11 00 0000 0100 0000 // This will also work, since there is a joint above it.
04000000
15 01 00 00 0700A290
05000000
05000000
05000000
01000000
----
==== 12: Rotate Node (and Load Display List or Start Geo Layout) ====
Applies rotation to the child nodes, and a display list if one is specified. You can start a geometry layout with this command to set the rotation for the entire model. You cannot start a geometry layout and load a display list at the same time, as it will cause the game to freeze (white-screen).
GraphNode type 0x17
''12 [B][L] [RX RX] [RY RY] [RZ RZ] {AA AA AA AA}''
| B | Include last 4 bytes if set to 8 (command will be C bytes long instead of 8) |
| L | Drawing layer if B is set, otherwise will always be zero |
| RX | X rotation (s16) |
| RY | Y rotation (s16) |
| RZ | Z rotation (s16) |
| A | Segmented address with display list if B is set.\\ Also creates a joint of some kind? (Does not work with animations?) |
struct GraphNodeRotation
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
/*0x18*/ Vec3s rotation;
u8 pad1E[2];
};
Length: 8-C (variable)
Note: You can't just use the 8-byte version of 0x12 command just anywhere. It seems like the command needs a joint in it's parent node(s) for it to work properly (created from geo layout commands 0x11, 0x12, and 0x13).
(see geo layout command 0x11 for examples)
----
==== 13: Load Display List With Offset ====
Loads display list with drawing layer and offsets the model and the node's children on X/Y/Z axis.
GraphNode type 0x19
''13 [LL] [XX XX] [YY YY] [ZZ ZZ] [AA AA AA AA]''
| L | Drawing layer |
| X | Offset on X axis (s16) |
| Y | Offset on Y axis (s16) |
| Z | Offset on Z axis (s16) |
| A | Segmented address with display list \\ If 0x00000000, an invisible rotation joint is created |
struct GraphNodeAnimatedPart
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
/*0x18*/ Vec3s translation;
};
* GraphNode part that transforms itself and its children based on animation data. This animation data is not stored in the node itself but in global variables that are set when object nodes are processed if the object has animation. Used for Mario, enemies and anything else with animation data. The display list can be null, in which case it won't draw anything itself.
Length: C
----
==== 14: Billboard Model and Translate (and Load Display List or Start Geo Layout) ====
Almost identical with the geometry layout 0x11 command, except that it will billboard the node and it's children without needing the use of 0x21 in the behavior script. You can start a geometry layout with this command to billboard and set the offset for the entire model. You cannot start a geometry layout and load a display list at the same time, as it will cause the game to freeze (white-screen).
GraphNode type 0x1A
''14 [B][L] [XX XX] [YY YY] [ZZ ZZ] {AA AA AA AA}''
| B | Include last 4 bytes if set to 8 (command will be C bytes long instead of 8) |
| L | Drawing layer if B is set, otherwise will always be zero |
| X | X translation offset (s16) |
| Y | Y translation offset (s16) |
| Z | Z translation offset (s16) |
| A | Segmented address with display list if B is set. \\ Also creates a joint of some kind? (Does not work with animations?) |
struct GraphNodeBillboard
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
/*0x18*/ Vec3s translation;
};
Length: 8-C (variable)
----
==== 15: Load Display List ====
Loads display list with drawing layer and no other properties.
GraphNode type 0x1B
''15 [LL] 00 00 [AA AA AA AA]''
| L | Drawing layer |
| A | Segmented address with display list |
struct GraphNodeDisplayList
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
};
Length: 8
----
==== 16: Start Geo Layout with Shadow ====
Used at start of the geo layout, with shadow type, solidity, and size.
GraphNode type 0x28
''16 00 00 [AA] 00 [BB] [CC CC]''
| A | Shadow type |
| B | Shadow solidity (00=invisible, FF=black) |
| C | Shadow scale |
struct GraphNodeShadow
{
/*0x00*/ struct GraphNode node;
/*0x14*/ s16 shadowScale; // diameter (when a circle) or side (when a square) of shadow
/*0x16*/ u8 shadowSolidity; // opacity of shadow, 255 = opaque
/*0x17*/ u8 shadowType; // see ShadowType enum in shadow.h
};
enum ShadowType
{
SHADOW_CIRCLE_9_VERTS = 0,
SHADOW_CIRCLE_4_VERTS = 1,
SHADOW_CIRCLE_4_VERTS_FLAT_UNUSED = 2,
SHADOW_SQUARE_PERMANENT = 10,
SHADOW_SQUARE_SCALABLE = 11,
SHADOW_SQUARE_TOGGLABLE = 12,
/**
* This defines an offset after which rectangular shadows with custom
* widths and heights can be defined.
*/
SHADOW_RECTANGLE_HARDCODED_OFFSET = 50,
SHADOW_CIRCLE_PLAYER = 99
};
Length: 8
----
==== 17: Create Object List ====
Sets up rendering for 3D Objects. Without it, 0x24 objects placed in level do not render.
GraphNode type 0x29
''17 00 00 00''
Length: 4
----
==== 18: Load Polygons ASM ====
Used in some original objects to point to ASM in RAM, for misc. effects such as vertex rippling.
GraphNode type 0x2A
The 3rd and 4th bytes are parameters passed into the asm function. Argument register a1 is a pointer to the node data, and the parameters are stored as a word at offset 0x18.
''18 00 [XX XX] [AA AA AA AA]''
| X | Parameter(s) passed into asm function. **a1->0x18** |
| A | ASM RAM Address |
struct GraphNodeGenerated
{
/*0x00*/ struct FnGraphNode fnNode;
/*0x18*/ u32 parameter; // extra context for the function
};
Length: 8
----
==== 19: Set Background ====
Set background image or color.
GraphNode type 0x2C
''19 00 [TT TT] [AA AA AA AA]''
| T | If A == 0, RGBA color, else background ID |
| A | ASM function to set the background image, always 0x802763D4 |
struct GraphNodeBackground
{
/*0x00*/ struct FnGraphNode fnNode;
/*0x18*/ s32 unused;
/*0x1C*/ s32 background; // background ID, or rgba5551 color if fnNode.func is null
};
Length: 8
Examples:
[ 19 00 00 00 80 27 63 D4 ] # Bob-Omb's Battlefield
[ 19 00 00 01 80 27 63 D4 ] # Lethal Lava Land
[ 19 00 00 02 80 27 63 D4 ] # Wet Dry World
[ 19 00 00 03 80 27 63 D4 ] # Rainbow Ride
[ 19 00 00 04 80 27 63 D4 ] # Cool Cool Mountain
[ 19 00 00 05 80 27 63 D4 ] # Shifting Sand Land
[ 19 00 00 06 80 27 63 D4 ] # Big Boo's Haunt
[ 19 00 00 07 80 27 63 D4 ] # Bowser 1 Course
[ 19 00 00 08 80 27 63 D4 ] # Jolly Roger Bay
[ 19 00 00 09 80 27 63 D4 ] # Bowser 3 Course
[ 19 00 00 01 00 00 00 00 ] # Secret Slide, pure black background
----
==== 1A: No Operation ====
Doesn't do anything, nop. This command is never used in any of the scripts.
Length: 8
----
==== 1D: Scale Model ====
Scales the receding data uniformly.
GraphNode type 0x1c
''1D [A][B] 00 00 [SS SS SS SS] {DD DD DD DD}''
| A | If MSbit is set, load B and ?? |
| B | If MSbit of A is set, use for A2 to 8037B940 |
| S | Scale percentage (0x10000 = 100%) |
| DD | optional word used if the MSbit of A is set |
struct GraphNodeScale
{
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
/*0x18*/ f32 scale;
};
Length: 8-C (variable)
----
==== 1E: No Operation ====
Doesn't do anything, nop. This command is never used in any of the scripts.
Length: 8
----
==== 1F: No Operation ====
Doesn't do anything, nop. This command is never used in any of the scripts.
Length: 0x10
----
==== 20: Start Geo Layout with Render Area ====
Starts the geometry layout with no shadow and a render area.
GraphNode type 0x2F. If not set, a default of 300 is used.
''20 00 [AA AA]''
| A | Render distance? |
struct GraphNodeCullingRadius
{
/*0x00*/ struct GraphNode node;
/*0x14*/ s16 cullingRadius; // specifies the 'sphere radius' for purposes of frustrum culling
u8 pad1E[2];
};
Length: 4
===== See Also =====
[[super_mario_64:level_commands]]
===== References =====
* https://github.com/n64decomp/sm64/blob/master/
* http://origami64.net/showthread.php?tid=9
* http://www.smwcentral.net/?p=viewthread&t=74776
* https://sites.google.com/site/kazemario64/geo-layout-polygon-commands
* http://qubedstudios.rustedlogic.net/Mario64_HackingDoc1.5.txt