mirror of
				https://github.com/coop-deluxe/sm64coopdx.git
				synced 2025-10-30 08:01:01 +00:00 
			
		
		
		
	Fix graph node interpolation (#917)
	
		
			
	
		
	
	
		
	
		
			Some checks are pending
		
		
	
	
		
			
				
	
				Build coop / build-linux (push) Waiting to run
				
			
		
			
				
	
				Build coop / build-steamos (push) Waiting to run
				
			
		
			
				
	
				Build coop / build-windows-opengl (push) Waiting to run
				
			
		
			
				
	
				Build coop / build-windows-directx (push) Waiting to run
				
			
		
			
				
	
				Build coop / build-macos-arm (push) Waiting to run
				
			
		
			
				
	
				Build coop / build-macos-intel (push) Waiting to run
				
			
		
		
	
	
				
					
				
			
		
			Some checks are pending
		
		
	
	Build coop / build-linux (push) Waiting to run
				
			Build coop / build-steamos (push) Waiting to run
				
			Build coop / build-windows-opengl (push) Waiting to run
				
			Build coop / build-windows-directx (push) Waiting to run
				
			Build coop / build-macos-arm (push) Waiting to run
				
			Build coop / build-macos-intel (push) Waiting to run
				
			Shared graph nodes were incorrectly interpolated, only the first object with a shared graph node was interpolated properly. Thanks to @Cooliokid956 for noticing that most of node types were **never** interpolated. - Use a double hashmap to store interpolated data for each graph node and object. All translations, rotations and scales are now interpolated correctly. - Add `GraphNodeScaleXYZ` type to scale to all 3 dimensions; Add `GEO_SCALE_XYZ` command. gMtxTbl was also reaching it's limit, so dynamic allocation was added.
This commit is contained in:
		
							parent
							
								
									b671458f81
								
							
						
					
					
						commit
						6e4373adc9
					
				
					 26 changed files with 428 additions and 144 deletions
				
			
		| 
						 | 
					@ -3050,6 +3050,9 @@ GRAPH_NODE_TYPE_DISPLAY_LIST = 0x01B
 | 
				
			||||||
--- @type integer
 | 
					--- @type integer
 | 
				
			||||||
GRAPH_NODE_TYPE_SCALE = 0x01C
 | 
					GRAPH_NODE_TYPE_SCALE = 0x01C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--- @type integer
 | 
				
			||||||
 | 
					GRAPH_NODE_TYPE_SCALE_XYZ = 0x01D
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--- @type integer
 | 
					--- @type integer
 | 
				
			||||||
GRAPH_NODE_TYPE_SHADOW = 0x028
 | 
					GRAPH_NODE_TYPE_SHADOW = 0x028
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -969,16 +969,18 @@
 | 
				
			||||||
--- @class GraphNodeRotation
 | 
					--- @class GraphNodeRotation
 | 
				
			||||||
--- @field public displayList Pointer_Gfx
 | 
					--- @field public displayList Pointer_Gfx
 | 
				
			||||||
--- @field public node GraphNode
 | 
					--- @field public node GraphNode
 | 
				
			||||||
--- @field public prevRotation Vec3s
 | 
					 | 
				
			||||||
--- @field public prevTimestamp integer
 | 
					 | 
				
			||||||
--- @field public rotation Vec3s
 | 
					--- @field public rotation Vec3s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--- @class GraphNodeScale
 | 
					--- @class GraphNodeScale
 | 
				
			||||||
--- @field public displayList Pointer_Gfx
 | 
					--- @field public displayList Pointer_Gfx
 | 
				
			||||||
--- @field public node GraphNode
 | 
					--- @field public node GraphNode
 | 
				
			||||||
--- @field public prevScale number
 | 
					 | 
				
			||||||
--- @field public scale number
 | 
					--- @field public scale number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--- @class GraphNodeScaleXYZ
 | 
				
			||||||
 | 
					--- @field public displayList Pointer_Gfx
 | 
				
			||||||
 | 
					--- @field public node GraphNode
 | 
				
			||||||
 | 
					--- @field public scale Vec3f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--- @class GraphNodeShadow
 | 
					--- @class GraphNodeShadow
 | 
				
			||||||
--- @field public node GraphNode
 | 
					--- @field public node GraphNode
 | 
				
			||||||
--- @field public shadowScale integer
 | 
					--- @field public shadowScale integer
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -317,6 +317,8 @@ static void ParseGeoSymbol(GfxData* aGfxData, DataNode<GeoLayout>* aNode, GeoLay
 | 
				
			||||||
    geo_symbol_5(GEO_HELD_OBJECT, 2);
 | 
					    geo_symbol_5(GEO_HELD_OBJECT, 2);
 | 
				
			||||||
    geo_symbol_2(GEO_SCALE, 0);
 | 
					    geo_symbol_2(GEO_SCALE, 0);
 | 
				
			||||||
    geo_symbol_3(GEO_SCALE_WITH_DL, 2);
 | 
					    geo_symbol_3(GEO_SCALE_WITH_DL, 2);
 | 
				
			||||||
 | 
					    geo_symbol_4(GEO_SCALE_XYZ, 0);
 | 
				
			||||||
 | 
					    geo_symbol_5(GEO_SCALE_XYZ_WITH_DL, 4);
 | 
				
			||||||
    geo_symbol_0(GEO_NOP_1E);
 | 
					    geo_symbol_0(GEO_NOP_1E);
 | 
				
			||||||
    geo_symbol_0(GEO_NOP_1F);
 | 
					    geo_symbol_0(GEO_NOP_1F);
 | 
				
			||||||
    geo_symbol_1(GEO_CULLING_RADIUS, 0);
 | 
					    geo_symbol_1(GEO_CULLING_RADIUS, 0);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,8 +135,8 @@ private:
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern "C" {
 | 
					extern "C" {
 | 
				
			||||||
void* hmap_create(MapType type) {
 | 
					void* hmap_create(bool useUnordered) {
 | 
				
			||||||
    return new HMap(type);
 | 
					    return new HMap(useUnordered ? MapType::Unordered : MapType::Ordered);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void* hmap_get(void* map, int64_t key) {
 | 
					void* hmap_get(void* map, int64_t key) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -257,6 +257,7 @@ static std::unordered_map<s16, size_t> sGraphNodeSizeMap = {
 | 
				
			||||||
    { GRAPH_NODE_TYPE_TRANSLATION,          sizeof(GraphNodeTranslation) },
 | 
					    { GRAPH_NODE_TYPE_TRANSLATION,          sizeof(GraphNodeTranslation) },
 | 
				
			||||||
    { GRAPH_NODE_TYPE_ROTATION,             sizeof(GraphNodeRotation) },
 | 
					    { GRAPH_NODE_TYPE_ROTATION,             sizeof(GraphNodeRotation) },
 | 
				
			||||||
    { GRAPH_NODE_TYPE_SCALE,                sizeof(GraphNodeScale) },
 | 
					    { GRAPH_NODE_TYPE_SCALE,                sizeof(GraphNodeScale) },
 | 
				
			||||||
 | 
					    { GRAPH_NODE_TYPE_SCALE_XYZ,            sizeof(GraphNodeScaleXYZ) },
 | 
				
			||||||
    { GRAPH_NODE_TYPE_OBJECT,               sizeof(GraphNodeObject) },
 | 
					    { GRAPH_NODE_TYPE_OBJECT,               sizeof(GraphNodeObject) },
 | 
				
			||||||
    { GRAPH_NODE_TYPE_CULLING_RADIUS,       sizeof(GraphNodeCullingRadius) },
 | 
					    { GRAPH_NODE_TYPE_CULLING_RADIUS,       sizeof(GraphNodeCullingRadius) },
 | 
				
			||||||
    { GRAPH_NODE_TYPE_ANIMATED_PART,        sizeof(GraphNodeAnimatedPart) },
 | 
					    { GRAPH_NODE_TYPE_ANIMATED_PART,        sizeof(GraphNodeAnimatedPart) },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1352,6 +1352,7 @@
 | 
				
			||||||
- GRAPH_NODE_TYPE_BILLBOARD
 | 
					- GRAPH_NODE_TYPE_BILLBOARD
 | 
				
			||||||
- GRAPH_NODE_TYPE_DISPLAY_LIST
 | 
					- GRAPH_NODE_TYPE_DISPLAY_LIST
 | 
				
			||||||
- GRAPH_NODE_TYPE_SCALE
 | 
					- GRAPH_NODE_TYPE_SCALE
 | 
				
			||||||
 | 
					- GRAPH_NODE_TYPE_SCALE_XYZ
 | 
				
			||||||
- GRAPH_NODE_TYPE_SHADOW
 | 
					- GRAPH_NODE_TYPE_SHADOW
 | 
				
			||||||
- GRAPH_NODE_TYPE_OBJECT_PARENT
 | 
					- GRAPH_NODE_TYPE_OBJECT_PARENT
 | 
				
			||||||
- GRAPH_NODE_TYPE_GENERATED_LIST
 | 
					- GRAPH_NODE_TYPE_GENERATED_LIST
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,6 +56,7 @@
 | 
				
			||||||
- [GraphNodeRoot](#GraphNodeRoot)
 | 
					- [GraphNodeRoot](#GraphNodeRoot)
 | 
				
			||||||
- [GraphNodeRotation](#GraphNodeRotation)
 | 
					- [GraphNodeRotation](#GraphNodeRotation)
 | 
				
			||||||
- [GraphNodeScale](#GraphNodeScale)
 | 
					- [GraphNodeScale](#GraphNodeScale)
 | 
				
			||||||
 | 
					- [GraphNodeScaleXYZ](#GraphNodeScaleXYZ)
 | 
				
			||||||
- [GraphNodeShadow](#GraphNodeShadow)
 | 
					- [GraphNodeShadow](#GraphNodeShadow)
 | 
				
			||||||
- [GraphNodeStart](#GraphNodeStart)
 | 
					- [GraphNodeStart](#GraphNodeStart)
 | 
				
			||||||
- [GraphNodeSwitchCase](#GraphNodeSwitchCase)
 | 
					- [GraphNodeSwitchCase](#GraphNodeSwitchCase)
 | 
				
			||||||
| 
						 | 
					@ -1477,8 +1478,6 @@
 | 
				
			||||||
| ----- | ---- | ------ |
 | 
					| ----- | ---- | ------ |
 | 
				
			||||||
| displayList | `Pointer` <`Gfx`> |  |
 | 
					| displayList | `Pointer` <`Gfx`> |  |
 | 
				
			||||||
| node | [GraphNode](structs.md#GraphNode) | read-only |
 | 
					| node | [GraphNode](structs.md#GraphNode) | read-only |
 | 
				
			||||||
| prevRotation | [Vec3s](structs.md#Vec3s) | read-only |
 | 
					 | 
				
			||||||
| prevTimestamp | `integer` |  |
 | 
					 | 
				
			||||||
| rotation | [Vec3s](structs.md#Vec3s) | read-only |
 | 
					| rotation | [Vec3s](structs.md#Vec3s) | read-only |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[:arrow_up_small:](#)
 | 
					[:arrow_up_small:](#)
 | 
				
			||||||
| 
						 | 
					@ -1491,13 +1490,24 @@
 | 
				
			||||||
| ----- | ---- | ------ |
 | 
					| ----- | ---- | ------ |
 | 
				
			||||||
| displayList | `Pointer` <`Gfx`> |  |
 | 
					| displayList | `Pointer` <`Gfx`> |  |
 | 
				
			||||||
| node | [GraphNode](structs.md#GraphNode) | read-only |
 | 
					| node | [GraphNode](structs.md#GraphNode) | read-only |
 | 
				
			||||||
| prevScale | `number` |  |
 | 
					 | 
				
			||||||
| scale | `number` |  |
 | 
					| scale | `number` |  |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[:arrow_up_small:](#)
 | 
					[:arrow_up_small:](#)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<br />
 | 
					<br />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [GraphNodeScaleXYZ](#GraphNodeScaleXYZ)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| Field | Type | Access |
 | 
				
			||||||
 | 
					| ----- | ---- | ------ |
 | 
				
			||||||
 | 
					| displayList | `Pointer` <`Gfx`> |  |
 | 
				
			||||||
 | 
					| node | [GraphNode](structs.md#GraphNode) | read-only |
 | 
				
			||||||
 | 
					| scale | [Vec3f](structs.md#Vec3f) | read-only |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[:arrow_up_small:](#)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<br />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## [GraphNodeShadow](#GraphNodeShadow)
 | 
					## [GraphNodeShadow](#GraphNodeShadow)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Field | Type | Access |
 | 
					| Field | Type | Access |
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -407,6 +407,30 @@ enum SkyBackgroundParams {
 | 
				
			||||||
    CMD_W(scale), \
 | 
					    CMD_W(scale), \
 | 
				
			||||||
    CMD_PTR(displayList)
 | 
					    CMD_PTR(displayList)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 0x1D: Create scale scene graph node with optional display list
 | 
				
			||||||
 | 
					 *   0x01: u8 params
 | 
				
			||||||
 | 
					 *     0b1000_0000: if set, enable displayList field and drawingLayer
 | 
				
			||||||
 | 
					 *     0b0100_0000: if set, enable scale XYZ
 | 
				
			||||||
 | 
					 *     0b0000_1111: drawingLayer
 | 
				
			||||||
 | 
					 *   0x02-0x03: unused
 | 
				
			||||||
 | 
					 *   0x04: u32 scale X (0x10000 = 1.0)
 | 
				
			||||||
 | 
					 *   0x08: u32 scale Y (0x10000 = 1.0)
 | 
				
			||||||
 | 
					 *   0x0C: u32 scale Z (0x10000 = 1.0)
 | 
				
			||||||
 | 
					 *   0x10: [u32 displayList: if MSbit bit of params is set, display list segment address]
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define GEO_SCALE_XYZ(layer, sx, sy, sz) \
 | 
				
			||||||
 | 
					    CMD_BBH(0x1D, (layer | 0x40), 0x0000), \
 | 
				
			||||||
 | 
					    CMD_W(sx), \
 | 
				
			||||||
 | 
					    CMD_W(sy), \
 | 
				
			||||||
 | 
					    CMD_W(sz)
 | 
				
			||||||
 | 
					#define GEO_SCALE_XYZ_WITH_DL(layer, sx, sy, sz, displayList) \
 | 
				
			||||||
 | 
					    CMD_BBH(0x1D, (layer | 0xC0), 0x0000), \
 | 
				
			||||||
 | 
					    CMD_W(sx), \
 | 
				
			||||||
 | 
					    CMD_W(sy), \
 | 
				
			||||||
 | 
					    CMD_W(sz), \
 | 
				
			||||||
 | 
					    CMD_PTR(displayList)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 0x1E: No operation
 | 
					 * 0x1E: No operation
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -535,29 +535,45 @@ void geo_layout_cmd_node_rotation(void) {
 | 
				
			||||||
  0x1D: Create scale scene graph node with optional display list
 | 
					  0x1D: Create scale scene graph node with optional display list
 | 
				
			||||||
   cmd+0x01: u8 params
 | 
					   cmd+0x01: u8 params
 | 
				
			||||||
     (params & 0x80): if set, enable displayList field and drawingLayer
 | 
					     (params & 0x80): if set, enable displayList field and drawingLayer
 | 
				
			||||||
 | 
					     (params & 0x40): if set, enable scale XYZ
 | 
				
			||||||
     (params & 0x0F): drawingLayer
 | 
					     (params & 0x0F): drawingLayer
 | 
				
			||||||
   cmd+0x04: u32 scale (0x10000 = 1.0)
 | 
					   cmd+0x04: u32 scale (0x10000 = 1.0)
 | 
				
			||||||
  [cmd+0x08: void *displayList]
 | 
					     or
 | 
				
			||||||
 | 
					   cmd+0x04: u32 scale X (0x10000 = 1.0)
 | 
				
			||||||
 | 
					   cmd+0x08: u32 scale Y (0x10000 = 1.0)
 | 
				
			||||||
 | 
					   cmd+0x0C: u32 scale Z (0x10000 = 1.0)
 | 
				
			||||||
 | 
					  [cmd+0x08/0x10: void *displayList]
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
void geo_layout_cmd_node_scale(void) {
 | 
					void geo_layout_cmd_node_scale(void) {
 | 
				
			||||||
    struct GraphNodeScale *graphNode;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    s16 drawingLayer = 0;
 | 
					    s16 drawingLayer = 0;
 | 
				
			||||||
    s16 params = cur_geo_cmd_u8(0x01);
 | 
					    s16 params = cur_geo_cmd_u8(0x01);
 | 
				
			||||||
    f32 scale = cur_geo_cmd_u32(0x04) / 65536.0f;
 | 
					    Vec3f scale;
 | 
				
			||||||
    void *displayList = NULL;
 | 
					    void *displayList = NULL;
 | 
				
			||||||
 | 
					    bool isScaleXYZ = (params & 0x40) != 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (params & 0x80) {
 | 
					    if (isScaleXYZ) {
 | 
				
			||||||
        displayList = cur_geo_cmd_ptr(0x08);
 | 
					        scale[0] = cur_geo_cmd_u32(0x04) / 65536.0f;
 | 
				
			||||||
        drawingLayer = params & 0x0F;
 | 
					        scale[1] = cur_geo_cmd_u32(0x08) / 65536.0f;
 | 
				
			||||||
        gGeoLayoutCommand += 4 << CMD_SIZE_SHIFT;
 | 
					        scale[2] = cur_geo_cmd_u32(0x0C) / 65536.0f;
 | 
				
			||||||
 | 
					        gGeoLayoutCommand += 0x10 << CMD_SIZE_SHIFT;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        scale[0] = cur_geo_cmd_u32(0x04) / 65536.0f;
 | 
				
			||||||
 | 
					        gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    graphNode = init_graph_node_scale(gGraphNodePool, NULL, drawingLayer, displayList, scale);
 | 
					    if (params & 0x80) {
 | 
				
			||||||
 | 
					        displayList = cur_geo_cmd_ptr(0x00);
 | 
				
			||||||
 | 
					        drawingLayer = params & 0x0F;
 | 
				
			||||||
 | 
					        gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    register_scene_graph_node(&graphNode->node);
 | 
					    struct GraphNode *graphNode = (
 | 
				
			||||||
 | 
					        isScaleXYZ ?
 | 
				
			||||||
 | 
					        (struct GraphNode *) init_graph_node_scale_xyz(gGraphNodePool, NULL, drawingLayer, displayList, scale) :
 | 
				
			||||||
 | 
					        (struct GraphNode *) init_graph_node_scale(gGraphNodePool, NULL, drawingLayer, displayList, scale[0])
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
 | 
					    register_scene_graph_node(graphNode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 0x1E: No operation
 | 
					// 0x1E: No operation
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -291,7 +291,26 @@ struct GraphNodeScale *init_graph_node_scale(struct DynamicPool *pool,
 | 
				
			||||||
        init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_SCALE);
 | 
					        init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_SCALE);
 | 
				
			||||||
        graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
 | 
					        graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
 | 
				
			||||||
        graphNode->scale = scale;
 | 
					        graphNode->scale = scale;
 | 
				
			||||||
        graphNode->prevScale = scale;
 | 
					        graphNode->displayList = dynos_gfx_get_writable_display_list(displayList);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return graphNode;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Allocates and returns a newly created XYZ scaling node
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct GraphNodeScaleXYZ *init_graph_node_scale_xyz(struct DynamicPool *pool,
 | 
				
			||||||
 | 
					                                                    struct GraphNodeScaleXYZ *graphNode, s32 drawingLayer,
 | 
				
			||||||
 | 
					                                                    void *displayList, Vec3f scale) {
 | 
				
			||||||
 | 
					    if (pool != NULL) {
 | 
				
			||||||
 | 
					        graphNode = dynamic_pool_alloc(pool, sizeof(struct GraphNodeScaleXYZ));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (graphNode != NULL) {
 | 
				
			||||||
 | 
					        init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_SCALE_XYZ);
 | 
				
			||||||
 | 
					        graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
 | 
				
			||||||
 | 
					        vec3f_copy(graphNode->scale, scale);
 | 
				
			||||||
        graphNode->displayList = dynos_gfx_get_writable_display_list(displayList);
 | 
					        graphNode->displayList = dynos_gfx_get_writable_display_list(displayList);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,6 +44,7 @@
 | 
				
			||||||
#define GRAPH_NODE_TYPE_BILLBOARD             0x01A
 | 
					#define GRAPH_NODE_TYPE_BILLBOARD             0x01A
 | 
				
			||||||
#define GRAPH_NODE_TYPE_DISPLAY_LIST          0x01B
 | 
					#define GRAPH_NODE_TYPE_DISPLAY_LIST          0x01B
 | 
				
			||||||
#define GRAPH_NODE_TYPE_SCALE                 0x01C
 | 
					#define GRAPH_NODE_TYPE_SCALE                 0x01C
 | 
				
			||||||
 | 
					#define GRAPH_NODE_TYPE_SCALE_XYZ             0x01D
 | 
				
			||||||
#define GRAPH_NODE_TYPE_SHADOW                0x028
 | 
					#define GRAPH_NODE_TYPE_SHADOW                0x028
 | 
				
			||||||
#define GRAPH_NODE_TYPE_OBJECT_PARENT         0x029
 | 
					#define GRAPH_NODE_TYPE_OBJECT_PARENT         0x029
 | 
				
			||||||
#define GRAPH_NODE_TYPE_GENERATED_LIST       (0x02A | GRAPH_NODE_TYPE_FUNCTIONAL)
 | 
					#define GRAPH_NODE_TYPE_GENERATED_LIST       (0x02A | GRAPH_NODE_TYPE_FUNCTIONAL)
 | 
				
			||||||
| 
						 | 
					@ -241,8 +242,6 @@ struct GraphNodeRotation
 | 
				
			||||||
    /*0x00*/ struct GraphNode node;
 | 
					    /*0x00*/ struct GraphNode node;
 | 
				
			||||||
    /*0x14*/ Gfx *displayList;
 | 
					    /*0x14*/ Gfx *displayList;
 | 
				
			||||||
    /*0x18*/ Vec3s rotation;
 | 
					    /*0x18*/ Vec3s rotation;
 | 
				
			||||||
    Vec3s prevRotation;
 | 
					 | 
				
			||||||
    u32 prevTimestamp;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** GraphNode part that transforms itself and its children based on animation
 | 
					/** GraphNode part that transforms itself and its children based on animation
 | 
				
			||||||
| 
						 | 
					@ -293,7 +292,16 @@ struct GraphNodeScale
 | 
				
			||||||
    /*0x00*/ struct GraphNode node;
 | 
					    /*0x00*/ struct GraphNode node;
 | 
				
			||||||
    /*0x14*/ Gfx *displayList;
 | 
					    /*0x14*/ Gfx *displayList;
 | 
				
			||||||
    /*0x18*/ f32 scale;
 | 
					    /*0x18*/ f32 scale;
 | 
				
			||||||
    /*????*/ f32 prevScale;
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** GraphNodeScale but on X, Y and Z independently.
 | 
				
			||||||
 | 
					 *  Must be another graph node type for retro-compatibility.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct GraphNodeScaleXYZ
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /*0x00*/ struct GraphNode node;
 | 
				
			||||||
 | 
					    /*0x14*/ Gfx *displayList;
 | 
				
			||||||
 | 
					    /*0x18*/ Vec3f scale;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** GraphNode that draws a shadow under an object.
 | 
					/** GraphNode that draws a shadow under an object.
 | 
				
			||||||
| 
						 | 
					@ -403,6 +411,8 @@ struct GraphNodeRotation *init_graph_node_rotation(struct DynamicPool *pool, str
 | 
				
			||||||
                                                   s32 drawingLayer, void *displayList, Vec3s rotation);
 | 
					                                                   s32 drawingLayer, void *displayList, Vec3s rotation);
 | 
				
			||||||
struct GraphNodeScale *init_graph_node_scale(struct DynamicPool *pool, struct GraphNodeScale *graphNode,
 | 
					struct GraphNodeScale *init_graph_node_scale(struct DynamicPool *pool, struct GraphNodeScale *graphNode,
 | 
				
			||||||
                                             s32 drawingLayer, void *displayList, f32 scale);
 | 
					                                             s32 drawingLayer, void *displayList, f32 scale);
 | 
				
			||||||
 | 
					struct GraphNodeScaleXYZ *init_graph_node_scale_xyz(struct DynamicPool *pool, struct GraphNodeScaleXYZ *graphNode,
 | 
				
			||||||
 | 
					                                             s32 drawingLayer, void *displayList, Vec3f scale);
 | 
				
			||||||
struct GraphNodeObject *init_graph_node_object(struct DynamicPool *pool, struct GraphNodeObject *graphNode,
 | 
					struct GraphNodeObject *init_graph_node_object(struct DynamicPool *pool, struct GraphNodeObject *graphNode,
 | 
				
			||||||
                                               struct GraphNode *sharedChild, Vec3f pos, Vec3s angle, Vec3f scale);
 | 
					                                               struct GraphNode *sharedChild, Vec3f pos, Vec3s angle, Vec3f scale);
 | 
				
			||||||
struct GraphNodeCullingRadius *init_graph_node_culling_radius(struct DynamicPool *pool, struct GraphNodeCullingRadius *graphNode, s16 radius);
 | 
					struct GraphNodeCullingRadius *init_graph_node_culling_radius(struct DynamicPool *pool, struct GraphNodeCullingRadius *graphNode, s16 radius);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -471,8 +471,8 @@ void alloc_surface_pools(void) {
 | 
				
			||||||
    clear_static_surfaces();
 | 
					    clear_static_surfaces();
 | 
				
			||||||
    clear_dynamic_surfaces();
 | 
					    clear_dynamic_surfaces();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sSurfaceNodePool = growing_array_init(sSurfaceNodePool, 0x1000);
 | 
					    sSurfaceNodePool = growing_array_init(sSurfaceNodePool, 0x1000, malloc, free);
 | 
				
			||||||
    sSurfacePool = growing_array_init(sSurfacePool, 0x400);
 | 
					    sSurfacePool = growing_array_init(sSurfacePool, 0x400, malloc, smlua_free_surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    gEnvironmentRegions = NULL;
 | 
					    gEnvironmentRegions = NULL;
 | 
				
			||||||
    gSurfaceNodesAllocated = 0;
 | 
					    gSurfaceNodesAllocated = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -253,6 +253,7 @@ void clear_areas(void) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    le_clear();
 | 
					    le_clear();
 | 
				
			||||||
 | 
					    geo_clear_interp_data();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void clear_area_graph_nodes(void) {
 | 
					void clear_area_graph_nodes(void) {
 | 
				
			||||||
| 
						 | 
					@ -311,6 +312,7 @@ void unload_area(void) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    le_clear();
 | 
					    le_clear();
 | 
				
			||||||
 | 
					    geo_clear_interp_data();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void load_mario_area(void) {
 | 
					void load_mario_area(void) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#include "main.h"
 | 
					#include "main.h"
 | 
				
			||||||
#include "engine/math_util.h"
 | 
					#include "engine/math_util.h"
 | 
				
			||||||
#include "engine/graph_node.h"
 | 
					#include "engine/graph_node.h"
 | 
				
			||||||
 | 
					#include "rendering_graph_node.h"
 | 
				
			||||||
#include "area.h"
 | 
					#include "area.h"
 | 
				
			||||||
#include "save_file.h"
 | 
					#include "save_file.h"
 | 
				
			||||||
#include "sound_init.h"
 | 
					#include "sound_init.h"
 | 
				
			||||||
| 
						 | 
					@ -1749,6 +1750,7 @@ s32 update_level(void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
s32 init_level(void) {
 | 
					s32 init_level(void) {
 | 
				
			||||||
    sync_objects_clear();
 | 
					    sync_objects_clear();
 | 
				
			||||||
 | 
					    geo_clear_interp_data();
 | 
				
			||||||
    reset_dialog_render_state();
 | 
					    reset_dialog_render_state();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s32 val4 = 0;
 | 
					    s32 val4 = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -460,11 +460,6 @@ Gfx* geo_mario_tilt_torso(s32 callContext, struct GraphNode* node, Mat4* mtx) {
 | 
				
			||||||
        rotNode->rotation[0] = bodyState->torsoAngle[1] * character->torsoRotMult;
 | 
					        rotNode->rotation[0] = bodyState->torsoAngle[1] * character->torsoRotMult;
 | 
				
			||||||
        rotNode->rotation[1] = bodyState->torsoAngle[2] * character->torsoRotMult;
 | 
					        rotNode->rotation[1] = bodyState->torsoAngle[2] * character->torsoRotMult;
 | 
				
			||||||
        rotNode->rotation[2] = bodyState->torsoAngle[0] * character->torsoRotMult;
 | 
					        rotNode->rotation[2] = bodyState->torsoAngle[0] * character->torsoRotMult;
 | 
				
			||||||
        if (plrIdx != 0) {
 | 
					 | 
				
			||||||
            // only interpolate angles for the local player
 | 
					 | 
				
			||||||
            vec3s_copy(rotNode->prevRotation, rotNode->rotation);
 | 
					 | 
				
			||||||
            rotNode->prevTimestamp = gGlobalTimer;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        // update torso position in bodyState
 | 
					        // update torso position in bodyState
 | 
				
			||||||
        get_pos_from_transform_mtx(bodyState->torsoPos, *curTransform, *gCurGraphNodeCamera->matrixPtr);
 | 
					        get_pos_from_transform_mtx(bodyState->torsoPos, *curTransform, *gCurGraphNodeCamera->matrixPtr);
 | 
				
			||||||
        bodyState->updateTorsoTime = gGlobalTimer;
 | 
					        bodyState->updateTorsoTime = gGlobalTimer;
 | 
				
			||||||
| 
						 | 
					@ -502,12 +497,6 @@ Gfx* geo_mario_head_rotation(s32 callContext, struct GraphNode* node, Mat4* c) {
 | 
				
			||||||
            vec3s_set(rotNode->rotation, 0, 0, 0);
 | 
					            vec3s_set(rotNode->rotation, 0, 0, 0);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (plrIdx != 0) {
 | 
					 | 
				
			||||||
            // only interpolate angles for the local player
 | 
					 | 
				
			||||||
            vec3s_copy(rotNode->prevRotation, rotNode->rotation);
 | 
					 | 
				
			||||||
            rotNode->prevTimestamp = gGlobalTimer;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // update head position in bodyState
 | 
					        // update head position in bodyState
 | 
				
			||||||
        get_pos_from_transform_mtx(bodyState->headPos,
 | 
					        get_pos_from_transform_mtx(bodyState->headPos,
 | 
				
			||||||
                                   *c,
 | 
					                                   *c,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,6 @@
 | 
				
			||||||
#include "memory.h"
 | 
					#include "memory.h"
 | 
				
			||||||
#include "print.h"
 | 
					#include "print.h"
 | 
				
			||||||
#include "pc/debuglog.h"
 | 
					#include "pc/debuglog.h"
 | 
				
			||||||
#include "pc/lua/smlua.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ALIGN16(val) (((val) + 0xF) & ~0xF)
 | 
					#define ALIGN16(val) (((val) + 0xF) & ~0xF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -186,12 +185,14 @@ void growing_pool_free_pool(struct GrowingPool *pool) {
 | 
				
			||||||
 // growing array //
 | 
					 // growing array //
 | 
				
			||||||
///////////////////
 | 
					///////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct GrowingArray *growing_array_init(struct GrowingArray *array, u32 capacity) {
 | 
					struct GrowingArray *growing_array_init(struct GrowingArray *array, u32 capacity, GrowingArrayAllocFunc alloc, GrowingArrayFreeFunc free) {
 | 
				
			||||||
    growing_array_free(&array);
 | 
					    growing_array_free(&array);
 | 
				
			||||||
    array = calloc(1, sizeof(struct GrowingArray));
 | 
					    array = calloc(1, sizeof(struct GrowingArray));
 | 
				
			||||||
    array->buffer = calloc(capacity, sizeof(void *));
 | 
					    array->buffer = calloc(capacity, sizeof(void *));
 | 
				
			||||||
    array->capacity = capacity;
 | 
					    array->capacity = capacity;
 | 
				
			||||||
    array->count = 0;
 | 
					    array->count = 0;
 | 
				
			||||||
 | 
					    array->alloc = alloc;
 | 
				
			||||||
 | 
					    array->free = free;
 | 
				
			||||||
    return array;
 | 
					    return array;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -211,7 +212,7 @@ void *growing_array_alloc(struct GrowingArray *array, u32 size) {
 | 
				
			||||||
        // Alloc element if needed
 | 
					        // Alloc element if needed
 | 
				
			||||||
        void **elem = &array->buffer[array->count++];
 | 
					        void **elem = &array->buffer[array->count++];
 | 
				
			||||||
        if (!*elem) {
 | 
					        if (!*elem) {
 | 
				
			||||||
            *elem = malloc(size);
 | 
					            *elem = array->alloc(size);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        memset(*elem, 0, size);
 | 
					        memset(*elem, 0, size);
 | 
				
			||||||
        return *elem;
 | 
					        return *elem;
 | 
				
			||||||
| 
						 | 
					@ -223,7 +224,7 @@ void growing_array_free(struct GrowingArray **array) {
 | 
				
			||||||
    if (*array) {
 | 
					    if (*array) {
 | 
				
			||||||
        for (u32 i = 0; i != (*array)->capacity; ++i) {
 | 
					        for (u32 i = 0; i != (*array)->capacity; ++i) {
 | 
				
			||||||
            if ((*array)->buffer[i]) {
 | 
					            if ((*array)->buffer[i]) {
 | 
				
			||||||
                smlua_free((*array)->buffer[i]);
 | 
					                (*array)->free((*array)->buffer[i]);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        free((*array)->buffer);
 | 
					        free((*array)->buffer);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,11 +39,16 @@ struct GrowingPoolNode
 | 
				
			||||||
    struct GrowingPoolNode* prev;
 | 
					    struct GrowingPoolNode* prev;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef void *(*GrowingArrayAllocFunc)(size_t);
 | 
				
			||||||
 | 
					typedef void (*GrowingArrayFreeFunc)(void *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct GrowingArray
 | 
					struct GrowingArray
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    void **buffer;
 | 
					    void **buffer;
 | 
				
			||||||
    u32 count;
 | 
					    u32 count;
 | 
				
			||||||
    u32 capacity;
 | 
					    u32 capacity;
 | 
				
			||||||
 | 
					    GrowingArrayAllocFunc alloc;
 | 
				
			||||||
 | 
					    GrowingArrayFreeFunc free;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct MarioAnimation;
 | 
					struct MarioAnimation;
 | 
				
			||||||
| 
						 | 
					@ -70,7 +75,7 @@ struct GrowingPool* growing_pool_init(struct GrowingPool* pool, u32 nodeSize);
 | 
				
			||||||
void* growing_pool_alloc(struct GrowingPool *pool, u32 size);
 | 
					void* growing_pool_alloc(struct GrowingPool *pool, u32 size);
 | 
				
			||||||
void growing_pool_free_pool(struct GrowingPool *pool);
 | 
					void growing_pool_free_pool(struct GrowingPool *pool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct GrowingArray *growing_array_init(struct GrowingArray *array, u32 capacity);
 | 
					struct GrowingArray *growing_array_init(struct GrowingArray *array, u32 capacity, GrowingArrayAllocFunc alloc, GrowingArrayFreeFunc free);
 | 
				
			||||||
void *growing_array_alloc(struct GrowingArray *array, u32 size);
 | 
					void *growing_array_alloc(struct GrowingArray *array, u32 size);
 | 
				
			||||||
void growing_array_free(struct GrowingArray **array);
 | 
					void growing_array_free(struct GrowingArray **array);
 | 
				
			||||||
void growing_array_debug_print(struct GrowingArray *array, const char *name, s32 x, s32 y);
 | 
					void growing_array_debug_print(struct GrowingArray *array, const char *name, s32 x, s32 y);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,7 @@
 | 
				
			||||||
#include "obj_behaviors.h"
 | 
					#include "obj_behaviors.h"
 | 
				
			||||||
#include "platform_displacement.h"
 | 
					#include "platform_displacement.h"
 | 
				
			||||||
#include "profiler.h"
 | 
					#include "profiler.h"
 | 
				
			||||||
 | 
					#include "rendering_graph_node.h"
 | 
				
			||||||
#include "spawn_object.h"
 | 
					#include "spawn_object.h"
 | 
				
			||||||
#include "first_person_cam.h"
 | 
					#include "first_person_cam.h"
 | 
				
			||||||
#include "engine/math_util.h"
 | 
					#include "engine/math_util.h"
 | 
				
			||||||
| 
						 | 
					@ -624,6 +625,7 @@ void clear_objects(void) {
 | 
				
			||||||
    gObjectLists = gObjectListArray;
 | 
					    gObjectLists = gObjectListArray;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    clear_dynamic_surfaces();
 | 
					    clear_dynamic_surfaces();
 | 
				
			||||||
 | 
					    geo_clear_interp_data();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
#include "area.h"
 | 
					#include "area.h"
 | 
				
			||||||
#include "engine/math_util.h"
 | 
					#include "engine/math_util.h"
 | 
				
			||||||
#include "engine/lighting_engine.h"
 | 
					#include "engine/lighting_engine.h"
 | 
				
			||||||
 | 
					#include "data/dynos_cmap.cpp.h"
 | 
				
			||||||
#include "game_init.h"
 | 
					#include "game_init.h"
 | 
				
			||||||
#include "gfx_dimensions.h"
 | 
					#include "gfx_dimensions.h"
 | 
				
			||||||
#include "main.h"
 | 
					#include "main.h"
 | 
				
			||||||
| 
						 | 
					@ -183,28 +184,27 @@ static Gfx* sViewportClipPos = NULL;
 | 
				
			||||||
static Vp   sViewportPrev    = { 0 };
 | 
					static Vp   sViewportPrev    = { 0 };
 | 
				
			||||||
static Vp   sViewportInterp  = { 0 };
 | 
					static Vp   sViewportInterp  = { 0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct GraphNodeBackground* sBackgroundNode = NULL;
 | 
					 | 
				
			||||||
Gfx* gBackgroundSkyboxGfx = NULL;
 | 
					Gfx* gBackgroundSkyboxGfx = NULL;
 | 
				
			||||||
Vtx* gBackgroundSkyboxVerts[SKYBOX_TILES_Y][SKYBOX_TILES_X] = { 0 };
 | 
					Vtx* gBackgroundSkyboxVerts[SKYBOX_TILES_Y][SKYBOX_TILES_X] = { 0 };
 | 
				
			||||||
Mtx* gBackgroundSkyboxMtx = NULL;
 | 
					Mtx* gBackgroundSkyboxMtx = NULL;
 | 
				
			||||||
struct GraphNodeRoot* sBackgroundNodeRoot = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define MAX_SHADOW_NODES 128
 | 
					 | 
				
			||||||
struct ShadowInterp sShadowInterp[MAX_SHADOW_NODES] = { 0 };
 | 
					 | 
				
			||||||
struct ShadowInterp* gShadowInterpCurrent = NULL;
 | 
					 | 
				
			||||||
static u8 sShadowInterpCount = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct GraphNodeBackground* sBackgroundNode = NULL;
 | 
				
			||||||
 | 
					static struct GraphNodeRoot* sBackgroundNodeRoot = NULL;
 | 
				
			||||||
static struct GraphNodeCamera* sCameraNode = NULL;
 | 
					static struct GraphNodeCamera* sCameraNode = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct {
 | 
					static struct GrowingArray* sShadowInterp = NULL;
 | 
				
			||||||
 | 
					struct ShadowInterp* gShadowInterpCurrent = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct MtxInterp {
 | 
				
			||||||
    Gfx *pos;
 | 
					    Gfx *pos;
 | 
				
			||||||
    Mtx *mtx;
 | 
					    Mtx *mtx;
 | 
				
			||||||
    Mtx *mtxPrev;
 | 
					    Mtx *mtxPrev;
 | 
				
			||||||
    void *displayList;
 | 
					    void *displayList;
 | 
				
			||||||
    Mtx interp;
 | 
					    Mtx interp;
 | 
				
			||||||
    u8 usingCamSpace;
 | 
					    u8 usingCamSpace;
 | 
				
			||||||
} gMtxTbl[6400];
 | 
					};
 | 
				
			||||||
s32 gMtxTblSize = 0;
 | 
					
 | 
				
			||||||
 | 
					static struct GrowingArray* sMtxTbl = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Object* gCurGraphNodeProcessingObject = NULL;
 | 
					struct Object* gCurGraphNodeProcessingObject = NULL;
 | 
				
			||||||
struct MarioState* gCurGraphNodeMarioState = NULL;
 | 
					struct MarioState* gCurGraphNodeMarioState = NULL;
 | 
				
			||||||
| 
						 | 
					@ -213,8 +213,36 @@ f32 gOverrideFOV = 0;
 | 
				
			||||||
f32 gOverrideNear = 0;
 | 
					f32 gOverrideNear = 0;
 | 
				
			||||||
f32 gOverrideFar = 0;
 | 
					f32 gOverrideFar = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void init_mtx(void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // matrices
 | 
				
			||||||
 | 
					    if (!sMtxTbl) {
 | 
				
			||||||
 | 
					        sMtxTbl = growing_array_init(NULL, 1024, malloc, free);
 | 
				
			||||||
 | 
					        if (!sMtxTbl) {
 | 
				
			||||||
 | 
					            sys_fatal("Cannot allocate matrix buffer for interpolation");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    sMtxTbl->count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // shadows
 | 
				
			||||||
 | 
					    if (!sShadowInterp) {
 | 
				
			||||||
 | 
					        sShadowInterp = growing_array_init(NULL, 32, malloc, free);
 | 
				
			||||||
 | 
					        if (!sShadowInterp) {
 | 
				
			||||||
 | 
					            sys_fatal("Cannot allocate shadow buffer for interpolation");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    sShadowInterp->count = 0;
 | 
				
			||||||
 | 
					    gShadowInterpCurrent = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void reset_mtx(void) {
 | 
				
			||||||
 | 
					    growing_array_free(&sMtxTbl);
 | 
				
			||||||
 | 
					    growing_array_free(&sShadowInterp);
 | 
				
			||||||
 | 
					    init_mtx();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void patch_mtx_before(void) {
 | 
					void patch_mtx_before(void) {
 | 
				
			||||||
    gMtxTblSize = 0;
 | 
					    init_mtx();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (sPerspectiveNode != NULL) {
 | 
					    if (sPerspectiveNode != NULL) {
 | 
				
			||||||
        sPerspectiveNode->prevFov = sPerspectiveNode->fov;
 | 
					        sPerspectiveNode->prevFov = sPerspectiveNode->fov;
 | 
				
			||||||
| 
						 | 
					@ -235,8 +263,6 @@ void patch_mtx_before(void) {
 | 
				
			||||||
        sBackgroundNode = NULL;
 | 
					        sBackgroundNode = NULL;
 | 
				
			||||||
        gBackgroundSkyboxGfx = NULL;
 | 
					        gBackgroundSkyboxGfx = NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    sShadowInterpCount = 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void patch_mtx_interpolated(f32 delta) {
 | 
					void patch_mtx_interpolated(f32 delta) {
 | 
				
			||||||
| 
						 | 
					@ -285,8 +311,8 @@ void patch_mtx_interpolated(f32 delta) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct GraphNodeObject* savedObj = gCurGraphNodeObject;
 | 
					    struct GraphNodeObject* savedObj = gCurGraphNodeObject;
 | 
				
			||||||
    for (s32 i = 0; i < sShadowInterpCount; i++) {
 | 
					    for (u32 i = 0; i < sShadowInterp->count; i++) {
 | 
				
			||||||
        struct ShadowInterp* interp = &sShadowInterp[i];
 | 
					        struct ShadowInterp* interp = sShadowInterp->buffer[i];
 | 
				
			||||||
        if (!interp->gfx) { continue; }
 | 
					        if (!interp->gfx) { continue; }
 | 
				
			||||||
        gShadowInterpCurrent = interp;
 | 
					        gShadowInterpCurrent = interp;
 | 
				
			||||||
        Vec3f posInterp;
 | 
					        Vec3f posInterp;
 | 
				
			||||||
| 
						 | 
					@ -304,7 +330,7 @@ void patch_mtx_interpolated(f32 delta) {
 | 
				
			||||||
    // technically this is improper use of mtxf functions, but coop doesn't target N64
 | 
					    // technically this is improper use of mtxf functions, but coop doesn't target N64
 | 
				
			||||||
    Mtx camTranfInv, prevCamTranfInv;
 | 
					    Mtx camTranfInv, prevCamTranfInv;
 | 
				
			||||||
    Mtx camInterp;
 | 
					    Mtx camInterp;
 | 
				
			||||||
    bool translateCamSpace = (gMtxTblSize > 0) && sCameraNode && (sCameraNode->matrixPtr != NULL) && (sCameraNode->matrixPtrPrev != NULL);
 | 
					    bool translateCamSpace = (sMtxTbl->count > 0) && sCameraNode && (sCameraNode->matrixPtr != NULL) && (sCameraNode->matrixPtrPrev != NULL);
 | 
				
			||||||
    if (translateCamSpace) {
 | 
					    if (translateCamSpace) {
 | 
				
			||||||
        // compute inverse camera matrix to transform out of camera space later
 | 
					        // compute inverse camera matrix to transform out of camera space later
 | 
				
			||||||
        mtxf_inverse(camTranfInv.m, *sCameraNode->matrixPtr);
 | 
					        mtxf_inverse(camTranfInv.m, *sCameraNode->matrixPtr);
 | 
				
			||||||
| 
						 | 
					@ -318,12 +344,13 @@ void patch_mtx_interpolated(f32 delta) {
 | 
				
			||||||
        mtxf_to_mtx(&camInterp, camInterp.m);
 | 
					        mtxf_to_mtx(&camInterp, camInterp.m);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (s32 i = 0; i < gMtxTblSize; i++) {
 | 
					    for (u32 i = 0; i < sMtxTbl->count; i++) {
 | 
				
			||||||
        Gfx *pos = gMtxTbl[i].pos;
 | 
					        struct MtxInterp *interp = sMtxTbl->buffer[i];
 | 
				
			||||||
        Mtx *srcMtx = gMtxTbl[i].mtx;
 | 
					        Gfx *pos = interp->pos;
 | 
				
			||||||
        Mtx *srcMtxPrev = gMtxTbl[i].mtxPrev;
 | 
					        Mtx *srcMtx = interp->mtx;
 | 
				
			||||||
 | 
					        Mtx *srcMtxPrev = interp->mtxPrev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (gMtxTbl[i].usingCamSpace && translateCamSpace) {
 | 
					        if (interp->usingCamSpace && translateCamSpace) {
 | 
				
			||||||
            // transform out of camera space so the matrix can interp in world space
 | 
					            // transform out of camera space so the matrix can interp in world space
 | 
				
			||||||
            Mtx bufMtx, bufMtxPrev;
 | 
					            Mtx bufMtx, bufMtxPrev;
 | 
				
			||||||
            mtxf_copy(bufMtx.m, srcMtx->m);
 | 
					            mtxf_copy(bufMtx.m, srcMtx->m);
 | 
				
			||||||
| 
						 | 
					@ -333,18 +360,96 @@ void patch_mtx_interpolated(f32 delta) {
 | 
				
			||||||
            srcMtx = &bufMtx;
 | 
					            srcMtx = &bufMtx;
 | 
				
			||||||
            srcMtxPrev = &bufMtxPrev;
 | 
					            srcMtxPrev = &bufMtxPrev;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        delta_interpolate_mtx(&gMtxTbl[i].interp, srcMtxPrev, srcMtx, delta);
 | 
					        delta_interpolate_mtx(&interp->interp, srcMtxPrev, srcMtx, delta);
 | 
				
			||||||
        if (gMtxTbl[i].usingCamSpace) {
 | 
					        if (interp->usingCamSpace) {
 | 
				
			||||||
            // transform back to camera space, respecting camera interpolation
 | 
					            // transform back to camera space, respecting camera interpolation
 | 
				
			||||||
            mtxf_mul(gMtxTbl[i].interp.m, gMtxTbl[i].interp.m, camInterp.m);
 | 
					            mtxf_mul(interp->interp.m, interp->interp.m, camInterp.m);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        gSPMatrix(pos++, VIRTUAL_TO_PHYSICAL(&gMtxTbl[i].interp),
 | 
					        gSPMatrix(pos++, VIRTUAL_TO_PHYSICAL(&interp->interp),
 | 
				
			||||||
                  G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
 | 
					                  G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    gCamSkipInterp = 0;
 | 
					    gCamSkipInterp = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Graph node interpolation
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct GraphNodeInterpData {
 | 
				
			||||||
 | 
					    Vec3s translation;
 | 
				
			||||||
 | 
					    Vec3s rotation;
 | 
				
			||||||
 | 
					    Vec3f scale;
 | 
				
			||||||
 | 
					    u32 timestamp;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *sGraphNodeInterpDataMap = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct GraphNodeInterpData *geo_get_interp_data(void *node, struct GraphNodeObject *obj) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Map for nodes
 | 
				
			||||||
 | 
					    if (!sGraphNodeInterpDataMap) {
 | 
				
			||||||
 | 
					        sGraphNodeInterpDataMap = hmap_create(true);
 | 
				
			||||||
 | 
					        if (!sGraphNodeInterpDataMap) {
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Map for objects
 | 
				
			||||||
 | 
					    void *nodeInterpData = hmap_get(sGraphNodeInterpDataMap, (int64_t) node);
 | 
				
			||||||
 | 
					    if (!nodeInterpData) {
 | 
				
			||||||
 | 
					        nodeInterpData = hmap_create(true);
 | 
				
			||||||
 | 
					        if (!nodeInterpData) {
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        hmap_put(sGraphNodeInterpDataMap, (int64_t) node, nodeInterpData);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Node/object interp data
 | 
				
			||||||
 | 
					    struct GraphNodeInterpData *interp = hmap_get(nodeInterpData, (int64_t) obj);
 | 
				
			||||||
 | 
					    if (!interp) {
 | 
				
			||||||
 | 
					        interp = calloc(1, sizeof(struct GraphNodeInterpData));
 | 
				
			||||||
 | 
					        if (!interp) {
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        hmap_put(nodeInterpData, (int64_t) obj, interp);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return interp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void geo_init_or_update_interp_data(struct GraphNodeInterpData *interp, Vec3s translation, Vec3s rotation, Vec3f scale, bool update) {
 | 
				
			||||||
 | 
					    if (interp && (update || interp->timestamp < gGlobalTimer - 1)) {
 | 
				
			||||||
 | 
					        if (translation) { vec3s_copy(interp->translation, translation); }
 | 
				
			||||||
 | 
					        if (rotation) { vec3s_copy(interp->rotation, rotation); }
 | 
				
			||||||
 | 
					        if (scale) { vec3f_copy(interp->scale, scale); }
 | 
				
			||||||
 | 
					        interp->timestamp = gGlobalTimer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool geo_should_interpolate(struct GraphNodeInterpData *interp) {
 | 
				
			||||||
 | 
					    return interp != NULL && interp->timestamp == gGlobalTimer - 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void geo_clear_interp_data() {
 | 
				
			||||||
 | 
					    for (void *nodeInterpData = hmap_begin(sGraphNodeInterpDataMap); nodeInterpData; nodeInterpData = hmap_next(sGraphNodeInterpDataMap)) {
 | 
				
			||||||
 | 
					        for (struct GraphNodeInterpData *interp = hmap_begin(nodeInterpData); interp; interp = hmap_next(nodeInterpData)) {
 | 
				
			||||||
 | 
					            free(interp);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        hmap_destroy(nodeInterpData);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    hmap_destroy(sGraphNodeInterpDataMap);
 | 
				
			||||||
 | 
					    sGraphNodeInterpDataMap = NULL;
 | 
				
			||||||
 | 
					    reset_mtx();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define geo_update_interpolation(translation, rotation, scale, ...) { \
 | 
				
			||||||
 | 
					    struct GraphNodeInterpData *interp = geo_get_interp_data(node, gCurGraphNodeObject); \
 | 
				
			||||||
 | 
					    geo_init_or_update_interp_data(interp, translation, rotation, scale, false); \
 | 
				
			||||||
 | 
					    { __VA_ARGS__; } \
 | 
				
			||||||
 | 
					    geo_init_or_update_interp_data(interp, translation, rotation, scale, true); \
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Increments the matrix stack index and sets the matrixs at the new index.
 | 
					 * Increments the matrix stack index and sets the matrixs at the new index.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -397,13 +502,13 @@ static void geo_process_master_list_sub(struct GraphNodeMasterList *node) {
 | 
				
			||||||
            gDPSetRenderMode(gDisplayListHead++, modeList->modes[i], mode2List->modes[i]);
 | 
					            gDPSetRenderMode(gDisplayListHead++, modeList->modes[i], mode2List->modes[i]);
 | 
				
			||||||
            while (currList != NULL) {
 | 
					            while (currList != NULL) {
 | 
				
			||||||
                detect_and_skip_mtx_interpolation(&currList->transform, &currList->transformPrev);
 | 
					                detect_and_skip_mtx_interpolation(&currList->transform, &currList->transformPrev);
 | 
				
			||||||
                if ((u32) gMtxTblSize < sizeof(gMtxTbl) / sizeof(gMtxTbl[0])) {
 | 
					
 | 
				
			||||||
                    gMtxTbl[gMtxTblSize].pos = gDisplayListHead;
 | 
					                struct MtxInterp *interp = growing_array_alloc(sMtxTbl, sizeof(struct MtxInterp));
 | 
				
			||||||
                    gMtxTbl[gMtxTblSize].mtx = currList->transform;
 | 
					                interp->pos = gDisplayListHead;
 | 
				
			||||||
                    gMtxTbl[gMtxTblSize].mtxPrev = currList->transformPrev;
 | 
					                interp->mtx = currList->transform;
 | 
				
			||||||
                    gMtxTbl[gMtxTblSize].displayList = currList->displayList;
 | 
					                interp->mtxPrev = currList->transformPrev;
 | 
				
			||||||
                    gMtxTbl[gMtxTblSize++].usingCamSpace = currList->usingCamSpace;
 | 
					                interp->displayList = currList->displayList;
 | 
				
			||||||
                }
 | 
					                interp->usingCamSpace = currList->usingCamSpace;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transformPrev),
 | 
					                gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transformPrev),
 | 
				
			||||||
                          G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
 | 
					                          G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
 | 
				
			||||||
| 
						 | 
					@ -648,10 +753,19 @@ static void geo_process_translation_rotation(struct GraphNodeTranslationRotation
 | 
				
			||||||
    // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB.
 | 
					    // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB.
 | 
				
			||||||
    if ((gMatStackIndex + 1) >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
 | 
					    if ((gMatStackIndex + 1) >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // current frame
 | 
				
			||||||
    vec3s_to_vec3f(translation, node->translation);
 | 
					    vec3s_to_vec3f(translation, node->translation);
 | 
				
			||||||
    mtxf_rotate_zxy_and_translate(mtxf, translation, node->rotation);
 | 
					    mtxf_rotate_zxy_and_translate(mtxf, translation, node->rotation);
 | 
				
			||||||
    mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
 | 
					    mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // previous frame
 | 
				
			||||||
 | 
					    geo_update_interpolation(node->translation, node->rotation, NULL,
 | 
				
			||||||
 | 
					        if (geo_should_interpolate(interp)) {
 | 
				
			||||||
 | 
					            vec3s_to_vec3f(translation, interp->translation);
 | 
				
			||||||
 | 
					            mtxf_rotate_zxy_and_translate(mtxf, translation, interp->rotation);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]);
 | 
					        mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]);
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Increment the matrix stack, If we fail to do so. Just return.
 | 
					    // Increment the matrix stack, If we fail to do so. Just return.
 | 
				
			||||||
    if (!increment_mat_stack()) { return; }
 | 
					    if (!increment_mat_stack()) { return; }
 | 
				
			||||||
| 
						 | 
					@ -677,10 +791,19 @@ static void geo_process_translation(struct GraphNodeTranslation *node) {
 | 
				
			||||||
    // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
 | 
					    // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
 | 
				
			||||||
    if ((gMatStackIndex + 1) >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
 | 
					    if ((gMatStackIndex + 1) >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // current frame
 | 
				
			||||||
    vec3s_to_vec3f(translation, node->translation);
 | 
					    vec3s_to_vec3f(translation, node->translation);
 | 
				
			||||||
    mtxf_rotate_zxy_and_translate(mtxf, translation, gVec3sZero);
 | 
					    mtxf_rotate_zxy_and_translate(mtxf, translation, gVec3sZero);
 | 
				
			||||||
    mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
 | 
					    mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // previous frame
 | 
				
			||||||
 | 
					    geo_update_interpolation(node->translation, NULL, NULL,
 | 
				
			||||||
 | 
					        if (geo_should_interpolate(interp)) {
 | 
				
			||||||
 | 
					            vec3s_to_vec3f(translation, interp->translation);
 | 
				
			||||||
 | 
					            mtxf_rotate_zxy_and_translate(mtxf, translation, gVec3sZero);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]);
 | 
					        mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]);
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Increment the matrix stack, If we fail to do so. Just return.
 | 
					    // Increment the matrix stack, If we fail to do so. Just return.
 | 
				
			||||||
    if (!increment_mat_stack()) { return; }
 | 
					    if (!increment_mat_stack()) { return; }
 | 
				
			||||||
| 
						 | 
					@ -705,17 +828,17 @@ static void geo_process_rotation(struct GraphNodeRotation *node) {
 | 
				
			||||||
    // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
 | 
					    // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
 | 
				
			||||||
    if ((gMatStackIndex + 1) >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
 | 
					    if ((gMatStackIndex + 1) >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // current frame
 | 
				
			||||||
    mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, node->rotation);
 | 
					    mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, node->rotation);
 | 
				
			||||||
    mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
 | 
					    mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (gGlobalTimer == node->prevTimestamp + 1) {
 | 
					    // previous frame
 | 
				
			||||||
        mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, node->prevRotation);
 | 
					    geo_update_interpolation(NULL, node->rotation, NULL,
 | 
				
			||||||
    } else {
 | 
					        if (geo_should_interpolate(interp)) {
 | 
				
			||||||
        mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, node->rotation);
 | 
					            mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, interp->rotation);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]);
 | 
					        mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]);
 | 
				
			||||||
    vec3s_copy(node->prevRotation, node->rotation);
 | 
					    );
 | 
				
			||||||
    node->prevTimestamp = gGlobalTimer;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Increment the matrix stack, If we fail to do so. Just return.
 | 
					    // Increment the matrix stack, If we fail to do so. Just return.
 | 
				
			||||||
    if (!increment_mat_stack()) { return; }
 | 
					    if (!increment_mat_stack()) { return; }
 | 
				
			||||||
| 
						 | 
					@ -741,17 +864,53 @@ static void geo_process_scale(struct GraphNodeScale *node) {
 | 
				
			||||||
    // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
 | 
					    // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
 | 
				
			||||||
    if ((gMatStackIndex + 1) >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
 | 
					    if ((gMatStackIndex + 1) >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // current frame
 | 
				
			||||||
    vec3f_set(scaleVec, node->scale, node->scale, node->scale);
 | 
					    vec3f_set(scaleVec, node->scale, node->scale, node->scale);
 | 
				
			||||||
    mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex], scaleVec);
 | 
					    mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex], scaleVec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* TODO: this fails because multiple player models reuse the same scalenode
 | 
					    // previous frame
 | 
				
			||||||
    vec3f_set(prevScaleVec, node->prevScale, node->prevScale, node->prevScale);
 | 
					    geo_update_interpolation(NULL, NULL, scaleVec,
 | 
				
			||||||
 | 
					        vec3f_copy(prevScaleVec,
 | 
				
			||||||
 | 
					            geo_should_interpolate(interp) ?
 | 
				
			||||||
 | 
					            interp->scale :
 | 
				
			||||||
 | 
					            scaleVec
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        mtxf_scale_vec3f(gMatStackPrev[gMatStackIndex + 1], gMatStackPrev[gMatStackIndex], prevScaleVec);
 | 
					        mtxf_scale_vec3f(gMatStackPrev[gMatStackIndex + 1], gMatStackPrev[gMatStackIndex], prevScaleVec);
 | 
				
			||||||
    node->prevScale = node->scale;*/
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // just use the current scale for now
 | 
					    // Increment the matrix stack, If we fail to do so. Just return.
 | 
				
			||||||
    vec3f_set(prevScaleVec, node->scale, node->scale, node->scale);
 | 
					    if (!increment_mat_stack()) { return; }
 | 
				
			||||||
    mtxf_scale_vec3f(gMatStackPrev[gMatStackIndex + 1], gMatStackPrev[gMatStackIndex], scaleVec);
 | 
					
 | 
				
			||||||
 | 
					    if (node->displayList != NULL) {
 | 
				
			||||||
 | 
					        geo_append_display_list(node->displayList, node->node.flags >> 8);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (node->node.children != NULL) {
 | 
				
			||||||
 | 
					        geo_process_node_and_siblings(node->node.children);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    gMatStackIndex--;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Process an XYZ scaling node. A transformation matrix based on the node's
 | 
				
			||||||
 | 
					 * scale is created and pushed on both the float and fixed point matrix stacks.
 | 
				
			||||||
 | 
					 * For the rest it acts as a normal display list node.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void geo_process_scale_xyz(struct GraphNodeScaleXYZ *node) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
 | 
				
			||||||
 | 
					    if ((gMatStackIndex + 1) >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // current frame
 | 
				
			||||||
 | 
					    mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex], node->scale);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // previous frame
 | 
				
			||||||
 | 
					    geo_update_interpolation(NULL, NULL, node->scale,
 | 
				
			||||||
 | 
					        mtxf_scale_vec3f(gMatStackPrev[gMatStackIndex + 1], gMatStackPrev[gMatStackIndex],
 | 
				
			||||||
 | 
					            geo_should_interpolate(interp) ?
 | 
				
			||||||
 | 
					            interp->scale :
 | 
				
			||||||
 | 
					            node->scale
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Increment the matrix stack, If we fail to do so. Just return.
 | 
					    // Increment the matrix stack, If we fail to do so. Just return.
 | 
				
			||||||
    if (!increment_mat_stack()) { return; }
 | 
					    if (!increment_mat_stack()) { return; }
 | 
				
			||||||
| 
						 | 
					@ -779,21 +938,28 @@ static void geo_process_billboard(struct GraphNodeBillboard *node) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s16 nextMatStackIndex = gMatStackIndex + 1;
 | 
					    s16 nextMatStackIndex = gMatStackIndex + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // current frame
 | 
				
			||||||
    vec3s_to_vec3f(translation, node->translation);
 | 
					    vec3s_to_vec3f(translation, node->translation);
 | 
				
			||||||
    mtxf_billboard(gMatStack[nextMatStackIndex], gMatStack[gMatStackIndex], translation,
 | 
					    mtxf_billboard(gMatStack[nextMatStackIndex], gMatStack[gMatStackIndex], translation, gCurGraphNodeCamera->roll);
 | 
				
			||||||
                   gCurGraphNodeCamera->roll);
 | 
					
 | 
				
			||||||
    mtxf_billboard(gMatStackPrev[nextMatStackIndex], gMatStackPrev[gMatStackIndex], translation,
 | 
					    // previous frame
 | 
				
			||||||
                   gCurGraphNodeCamera->roll);
 | 
					    geo_update_interpolation(node->translation, NULL, NULL,
 | 
				
			||||||
 | 
					        if (geo_should_interpolate(interp)) {
 | 
				
			||||||
 | 
					            vec3s_to_vec3f(translation, interp->translation);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        mtxf_billboard(gMatStackPrev[nextMatStackIndex], gMatStackPrev[gMatStackIndex], translation, gCurGraphNodeCamera->roll);
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (gCurGraphNodeHeldObject != NULL) {
 | 
					    if (gCurGraphNodeHeldObject != NULL) {
 | 
				
			||||||
        mtxf_scale_vec3f(gMatStack[nextMatStackIndex], gMatStack[nextMatStackIndex],
 | 
					        mtxf_scale_vec3f(gMatStack[nextMatStackIndex], gMatStack[nextMatStackIndex],
 | 
				
			||||||
                         gCurGraphNodeHeldObject->objNode->header.gfx.scale);
 | 
					                         gCurGraphNodeHeldObject->objNode->header.gfx.scale);
 | 
				
			||||||
        mtxf_scale_vec3f(gMatStackPrev[nextMatStackIndex], gMatStackPrev[nextMatStackIndex],
 | 
					        mtxf_scale_vec3f(gMatStackPrev[nextMatStackIndex], gMatStackPrev[nextMatStackIndex],
 | 
				
			||||||
                         gCurGraphNodeHeldObject->objNode->header.gfx.scale);
 | 
					                         gCurGraphNodeHeldObject->objNode->header.gfx.prevScale);
 | 
				
			||||||
    } else if (gCurGraphNodeObject != NULL) {
 | 
					    } else if (gCurGraphNodeObject != NULL) {
 | 
				
			||||||
        mtxf_scale_vec3f(gMatStack[nextMatStackIndex], gMatStack[nextMatStackIndex],
 | 
					        mtxf_scale_vec3f(gMatStack[nextMatStackIndex], gMatStack[nextMatStackIndex],
 | 
				
			||||||
                         gCurGraphNodeObject->scale);
 | 
					                         gCurGraphNodeObject->scale);
 | 
				
			||||||
        mtxf_scale_vec3f(gMatStackPrev[nextMatStackIndex], gMatStackPrev[nextMatStackIndex],
 | 
					        mtxf_scale_vec3f(gMatStackPrev[nextMatStackIndex], gMatStackPrev[nextMatStackIndex],
 | 
				
			||||||
                         gCurGraphNodeObject->scale);
 | 
					                         gCurGraphNodeObject->prevScale);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        //LOG_ERROR("gCurGraphNodeObject and gCurGraphNodeHeldObject are both NULL!");
 | 
					        //LOG_ERROR("gCurGraphNodeObject and gCurGraphNodeHeldObject are both NULL!");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -938,8 +1104,6 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) {
 | 
				
			||||||
    Mat4 matrix;
 | 
					    Mat4 matrix;
 | 
				
			||||||
    Vec3s rotation;
 | 
					    Vec3s rotation;
 | 
				
			||||||
    Vec3f translation;
 | 
					    Vec3f translation;
 | 
				
			||||||
    Vec3s rotationPrev;
 | 
					 | 
				
			||||||
    Vec3f translationPrev;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
 | 
					    // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
 | 
				
			||||||
    if ((gMatStackIndex + 1) >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
 | 
					    if ((gMatStackIndex + 1) >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
 | 
				
			||||||
| 
						 | 
					@ -947,20 +1111,25 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) {
 | 
				
			||||||
    u16 *animAttribute = gCurrAnimAttribute;
 | 
					    u16 *animAttribute = gCurrAnimAttribute;
 | 
				
			||||||
    u8 animType = gCurAnimType;
 | 
					    u8 animType = gCurAnimType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // current frame
 | 
				
			||||||
    vec3s_copy(rotation, gVec3sZero);
 | 
					    vec3s_copy(rotation, gVec3sZero);
 | 
				
			||||||
    vec3f_set(translation, node->translation[0], node->translation[1], node->translation[2]);
 | 
					    vec3s_to_vec3f(translation, node->translation);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    vec3s_copy(rotationPrev, rotation);
 | 
					 | 
				
			||||||
    vec3f_copy(translationPrev, translation);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    anim_process(translationPrev, rotationPrev, &animType, gPrevAnimFrame, &animAttribute);
 | 
					 | 
				
			||||||
    anim_process(translation, rotation, &gCurAnimType, gCurrAnimFrame, &gCurrAnimAttribute);
 | 
					    anim_process(translation, rotation, &gCurAnimType, gCurrAnimFrame, &gCurrAnimAttribute);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    mtxf_rotate_xyz_and_translate(matrix, translation, rotation);
 | 
					    mtxf_rotate_xyz_and_translate(matrix, translation, rotation);
 | 
				
			||||||
    mtxf_mul(gMatStack[gMatStackIndex + 1], matrix, gMatStack[gMatStackIndex]);
 | 
					    mtxf_mul(gMatStack[gMatStackIndex + 1], matrix, gMatStack[gMatStackIndex]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mtxf_rotate_xyz_and_translate(matrix, translationPrev, rotationPrev);
 | 
					    // previous frame
 | 
				
			||||||
 | 
					    geo_update_interpolation(node->translation, NULL, NULL,
 | 
				
			||||||
 | 
					        vec3s_to_vec3f(translation,
 | 
				
			||||||
 | 
					            geo_should_interpolate(interp) ?
 | 
				
			||||||
 | 
					            interp->translation :
 | 
				
			||||||
 | 
					            node->translation
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        vec3s_copy(rotation, gVec3sZero);
 | 
				
			||||||
 | 
					        anim_process(translation, rotation, &animType, gPrevAnimFrame, &animAttribute);
 | 
				
			||||||
 | 
					        mtxf_rotate_xyz_and_translate(matrix, translation, rotation);
 | 
				
			||||||
        mtxf_mul(gMatStackPrev[gMatStackIndex + 1], matrix, gMatStackPrev[gMatStackIndex]);
 | 
					        mtxf_mul(gMatStackPrev[gMatStackIndex + 1], matrix, gMatStackPrev[gMatStackIndex]);
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Increment the matrix stack, If we fail to do so. Just return.
 | 
					    // Increment the matrix stack, If we fail to do so. Just return.
 | 
				
			||||||
    if (!increment_mat_stack()) { return; }
 | 
					    if (!increment_mat_stack()) { return; }
 | 
				
			||||||
| 
						 | 
					@ -1058,18 +1227,25 @@ static void geo_process_shadow(struct GraphNodeShadow *node) {
 | 
				
			||||||
            shadowScale = node->shadowScale * gCurGraphNodeObject->scale[0];
 | 
					            shadowScale = node->shadowScale * gCurGraphNodeObject->scale[0];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        f32 objScale = 1.0f;
 | 
					        Vec3f objScale = { 1, 1, 1 };
 | 
				
			||||||
        if (gCurAnimEnabled) {
 | 
					        if (gCurAnimEnabled) {
 | 
				
			||||||
            if (gCurAnimType == ANIM_TYPE_TRANSLATION
 | 
					            if (gCurAnimType == ANIM_TYPE_TRANSLATION
 | 
				
			||||||
                || gCurAnimType == ANIM_TYPE_LATERAL_TRANSLATION) {
 | 
					                || gCurAnimType == ANIM_TYPE_LATERAL_TRANSLATION) {
 | 
				
			||||||
                struct GraphNode *geo = node->node.children;
 | 
					                struct GraphNode *geo = node->node.children;
 | 
				
			||||||
                if (geo != NULL && geo->type == GRAPH_NODE_TYPE_SCALE) {
 | 
					                if (geo != NULL) {
 | 
				
			||||||
                    objScale = ((struct GraphNodeScale *) geo)->scale;
 | 
					                    switch (geo->type) {
 | 
				
			||||||
 | 
					                        case GRAPH_NODE_TYPE_SCALE:
 | 
				
			||||||
 | 
					                            vec3f_mul(objScale, ((struct GraphNodeScale *) geo)->scale);
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        case GRAPH_NODE_TYPE_SCALE_XYZ:
 | 
				
			||||||
 | 
					                            vec3f_copy(objScale, ((struct GraphNodeScaleXYZ *) geo)->scale);
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                animOffset[0] = retrieve_animation_value(gCurAnim, gCurrAnimFrame, &gCurrAnimAttribute) * gCurAnimTranslationMultiplier * objScale;
 | 
					                }
 | 
				
			||||||
 | 
					                animOffset[0] = retrieve_animation_value(gCurAnim, gCurrAnimFrame, &gCurrAnimAttribute) * gCurAnimTranslationMultiplier * objScale[0];
 | 
				
			||||||
                animOffset[1] = 0.0f;
 | 
					                animOffset[1] = 0.0f;
 | 
				
			||||||
                gCurrAnimAttribute += 2;
 | 
					                gCurrAnimAttribute += 2;
 | 
				
			||||||
                animOffset[2] = retrieve_animation_value(gCurAnim, gCurrAnimFrame, &gCurrAnimAttribute) * gCurAnimTranslationMultiplier * objScale;
 | 
					                animOffset[2] = retrieve_animation_value(gCurAnim, gCurrAnimFrame, &gCurrAnimAttribute) * gCurAnimTranslationMultiplier * objScale[2];
 | 
				
			||||||
                gCurrAnimAttribute -= 6;
 | 
					                gCurrAnimAttribute -= 6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // simple matrix rotation so the shadow offset rotates along with the object
 | 
					                // simple matrix rotation so the shadow offset rotates along with the object
 | 
				
			||||||
| 
						 | 
					@ -1103,8 +1279,7 @@ static void geo_process_shadow(struct GraphNodeShadow *node) {
 | 
				
			||||||
            gCurGraphNodeObject->prevShadowPosTimestamp = gGlobalTimer;
 | 
					            gCurGraphNodeObject->prevShadowPosTimestamp = gGlobalTimer;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (sShadowInterpCount < MAX_SHADOW_NODES) {
 | 
					        struct ShadowInterp* interp = growing_array_alloc(sShadowInterp, sizeof(struct ShadowInterp));
 | 
				
			||||||
            struct ShadowInterp* interp = &sShadowInterp[sShadowInterpCount++];
 | 
					 | 
				
			||||||
        gShadowInterpCurrent = interp;
 | 
					        gShadowInterpCurrent = interp;
 | 
				
			||||||
        interp->gfx = NULL;
 | 
					        interp->gfx = NULL;
 | 
				
			||||||
        interp->node = node;
 | 
					        interp->node = node;
 | 
				
			||||||
| 
						 | 
					@ -1112,9 +1287,6 @@ static void geo_process_shadow(struct GraphNodeShadow *node) {
 | 
				
			||||||
        interp->obj = gCurGraphNodeObject;
 | 
					        interp->obj = gCurGraphNodeObject;
 | 
				
			||||||
        vec3f_copy(interp->shadowPos, gCurGraphNodeObject->shadowPos);
 | 
					        vec3f_copy(interp->shadowPos, gCurGraphNodeObject->shadowPos);
 | 
				
			||||||
        vec3f_copy(interp->shadowPosPrev, shadowPosPrev);
 | 
					        vec3f_copy(interp->shadowPosPrev, shadowPosPrev);
 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            gShadowInterpCurrent = NULL;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Gfx *shadowListPrev = create_shadow_below_xyz(shadowPosPrev[0], shadowPosPrev[1],
 | 
					        Gfx *shadowListPrev = create_shadow_below_xyz(shadowPosPrev[0], shadowPosPrev[1],
 | 
				
			||||||
                                                      shadowPosPrev[2], shadowScale,
 | 
					                                                      shadowPosPrev[2], shadowScale,
 | 
				
			||||||
| 
						 | 
					@ -1640,6 +1812,9 @@ void geo_process_node_and_siblings(struct GraphNode *firstNode) {
 | 
				
			||||||
                    case GRAPH_NODE_TYPE_SCALE:
 | 
					                    case GRAPH_NODE_TYPE_SCALE:
 | 
				
			||||||
                        geo_process_scale((struct GraphNodeScale *) curGraphNode);
 | 
					                        geo_process_scale((struct GraphNodeScale *) curGraphNode);
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case GRAPH_NODE_TYPE_SCALE_XYZ:
 | 
				
			||||||
 | 
					                        geo_process_scale_xyz((struct GraphNodeScaleXYZ *) curGraphNode);
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
                    case GRAPH_NODE_TYPE_SHADOW:
 | 
					                    case GRAPH_NODE_TYPE_SHADOW:
 | 
				
			||||||
                        geo_process_shadow((struct GraphNodeShadow *) curGraphNode);
 | 
					                        geo_process_shadow((struct GraphNodeShadow *) curGraphNode);
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
| 
						 | 
					@ -1685,11 +1860,11 @@ static void geo_clear_interp_variables(void) {
 | 
				
			||||||
    gBackgroundSkyboxMtx = NULL;
 | 
					    gBackgroundSkyboxMtx = NULL;
 | 
				
			||||||
    sBackgroundNodeRoot = NULL;
 | 
					    sBackgroundNodeRoot = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sShadowInterp->count = 0;
 | 
				
			||||||
    gShadowInterpCurrent = NULL;
 | 
					    gShadowInterpCurrent = NULL;
 | 
				
			||||||
    sShadowInterpCount = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sMtxTbl->count = 0;
 | 
				
			||||||
    sCameraNode = NULL;
 | 
					    sCameraNode = NULL;
 | 
				
			||||||
    gMtxTblSize = 0;
 | 
					 | 
				
			||||||
    gCurGraphNodeProcessingObject = NULL;
 | 
					    gCurGraphNodeProcessingObject = NULL;
 | 
				
			||||||
    gCurGraphNodeMarioState = NULL;
 | 
					    gCurGraphNodeMarioState = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,7 @@ extern f32 gOverrideFar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void geo_process_node_and_siblings(struct GraphNode *firstNode);
 | 
					void geo_process_node_and_siblings(struct GraphNode *firstNode);
 | 
				
			||||||
void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor);
 | 
					void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor);
 | 
				
			||||||
 | 
					void geo_clear_interp_data();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ShadowInterp {
 | 
					struct ShadowInterp {
 | 
				
			||||||
    Gfx*  gfx;
 | 
					    Gfx*  gfx;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@
 | 
				
			||||||
DialogTable *gDialogTable = NULL;
 | 
					DialogTable *gDialogTable = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void dialog_table_init(void) {
 | 
					void dialog_table_init(void) {
 | 
				
			||||||
    gDialogTable = growing_array_init(gDialogTable, 256);
 | 
					    gDialogTable = growing_array_init(gDialogTable, 256, malloc, free);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (u32 i = 0; i < DIALOG_COUNT; i++) {
 | 
					    for (u32 i = 0; i < DIALOG_COUNT; i++) {
 | 
				
			||||||
        const struct DialogEntry* dialogOrig = smlua_text_utils_dialog_get_unmodified(i);
 | 
					        const struct DialogEntry* dialogOrig = smlua_text_utils_dialog_get_unmodified(i);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1248,23 +1248,27 @@ static struct LuaObjectField sGraphNodeRootFields[LUA_GRAPH_NODE_ROOT_FIELD_COUN
 | 
				
			||||||
    { "y",         LVT_S16,     offsetof(struct GraphNodeRoot, y),         false, LOT_NONE,      1, sizeof(s16)              },
 | 
					    { "y",         LVT_S16,     offsetof(struct GraphNodeRoot, y),         false, LOT_NONE,      1, sizeof(s16)              },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LUA_GRAPH_NODE_ROTATION_FIELD_COUNT 5
 | 
					#define LUA_GRAPH_NODE_ROTATION_FIELD_COUNT 3
 | 
				
			||||||
static struct LuaObjectField sGraphNodeRotationFields[LUA_GRAPH_NODE_ROTATION_FIELD_COUNT] = {
 | 
					static struct LuaObjectField sGraphNodeRotationFields[LUA_GRAPH_NODE_ROTATION_FIELD_COUNT] = {
 | 
				
			||||||
    { "displayList", LVT_COBJECT_P, offsetof(struct GraphNodeRotation, displayList), false, LOT_GFX,       1, sizeof(Gfx*)             },
 | 
					    { "displayList", LVT_COBJECT_P, offsetof(struct GraphNodeRotation, displayList), false, LOT_GFX,       1, sizeof(Gfx*)             },
 | 
				
			||||||
    { "node",        LVT_COBJECT,   offsetof(struct GraphNodeRotation, node),        true,  LOT_GRAPHNODE, 1, sizeof(struct GraphNode) },
 | 
					    { "node",        LVT_COBJECT,   offsetof(struct GraphNodeRotation, node),        true,  LOT_GRAPHNODE, 1, sizeof(struct GraphNode) },
 | 
				
			||||||
    { "prevRotation",  LVT_COBJECT,   offsetof(struct GraphNodeRotation, prevRotation),  true,  LOT_VEC3S,     1, sizeof(Vec3s)            },
 | 
					 | 
				
			||||||
    { "prevTimestamp", LVT_U32,       offsetof(struct GraphNodeRotation, prevTimestamp), false, LOT_NONE,      1, sizeof(u32)              },
 | 
					 | 
				
			||||||
    { "rotation",    LVT_COBJECT,   offsetof(struct GraphNodeRotation, rotation),    true,  LOT_VEC3S,     1, sizeof(Vec3s)            },
 | 
					    { "rotation",    LVT_COBJECT,   offsetof(struct GraphNodeRotation, rotation),    true,  LOT_VEC3S,     1, sizeof(Vec3s)            },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LUA_GRAPH_NODE_SCALE_FIELD_COUNT 4
 | 
					#define LUA_GRAPH_NODE_SCALE_FIELD_COUNT 3
 | 
				
			||||||
static struct LuaObjectField sGraphNodeScaleFields[LUA_GRAPH_NODE_SCALE_FIELD_COUNT] = {
 | 
					static struct LuaObjectField sGraphNodeScaleFields[LUA_GRAPH_NODE_SCALE_FIELD_COUNT] = {
 | 
				
			||||||
    { "displayList", LVT_COBJECT_P, offsetof(struct GraphNodeScale, displayList), false, LOT_GFX,       1, sizeof(Gfx*)             },
 | 
					    { "displayList", LVT_COBJECT_P, offsetof(struct GraphNodeScale, displayList), false, LOT_GFX,       1, sizeof(Gfx*)             },
 | 
				
			||||||
    { "node",        LVT_COBJECT,   offsetof(struct GraphNodeScale, node),        true,  LOT_GRAPHNODE, 1, sizeof(struct GraphNode) },
 | 
					    { "node",        LVT_COBJECT,   offsetof(struct GraphNodeScale, node),        true,  LOT_GRAPHNODE, 1, sizeof(struct GraphNode) },
 | 
				
			||||||
    { "prevScale",   LVT_F32,       offsetof(struct GraphNodeScale, prevScale),   false, LOT_NONE,      1, sizeof(f32)              },
 | 
					 | 
				
			||||||
    { "scale",       LVT_F32,       offsetof(struct GraphNodeScale, scale),       false, LOT_NONE,      1, sizeof(f32)              },
 | 
					    { "scale",       LVT_F32,       offsetof(struct GraphNodeScale, scale),       false, LOT_NONE,      1, sizeof(f32)              },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LUA_GRAPH_NODE_SCALE_XYZ_FIELD_COUNT 3
 | 
				
			||||||
 | 
					static struct LuaObjectField sGraphNodeScaleXYZFields[LUA_GRAPH_NODE_SCALE_XYZ_FIELD_COUNT] = {
 | 
				
			||||||
 | 
					    { "displayList", LVT_COBJECT_P, offsetof(struct GraphNodeScaleXYZ, displayList), false, LOT_GFX,       1, sizeof(Gfx*)             },
 | 
				
			||||||
 | 
					    { "node",        LVT_COBJECT,   offsetof(struct GraphNodeScaleXYZ, node),        true,  LOT_GRAPHNODE, 1, sizeof(struct GraphNode) },
 | 
				
			||||||
 | 
					    { "scale",       LVT_COBJECT,   offsetof(struct GraphNodeScaleXYZ, scale),       true,  LOT_VEC3F,     1, sizeof(Vec3f)            },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LUA_GRAPH_NODE_SHADOW_FIELD_COUNT 4
 | 
					#define LUA_GRAPH_NODE_SHADOW_FIELD_COUNT 4
 | 
				
			||||||
static struct LuaObjectField sGraphNodeShadowFields[LUA_GRAPH_NODE_SHADOW_FIELD_COUNT] = {
 | 
					static struct LuaObjectField sGraphNodeShadowFields[LUA_GRAPH_NODE_SHADOW_FIELD_COUNT] = {
 | 
				
			||||||
    { "node",           LVT_COBJECT, offsetof(struct GraphNodeShadow, node),           true,  LOT_GRAPHNODE, 1, sizeof(struct GraphNode) },
 | 
					    { "node",           LVT_COBJECT, offsetof(struct GraphNodeShadow, node),           true,  LOT_GRAPHNODE, 1, sizeof(struct GraphNode) },
 | 
				
			||||||
| 
						 | 
					@ -2924,6 +2928,7 @@ struct LuaObjectTable sLuaObjectAutogenTable[LOT_AUTOGEN_MAX - LOT_AUTOGEN_MIN]
 | 
				
			||||||
    { LOT_GRAPHNODEROOT,                sGraphNodeRootFields,                LUA_GRAPH_NODE_ROOT_FIELD_COUNT                 },
 | 
					    { LOT_GRAPHNODEROOT,                sGraphNodeRootFields,                LUA_GRAPH_NODE_ROOT_FIELD_COUNT                 },
 | 
				
			||||||
    { LOT_GRAPHNODEROTATION,            sGraphNodeRotationFields,            LUA_GRAPH_NODE_ROTATION_FIELD_COUNT             },
 | 
					    { LOT_GRAPHNODEROTATION,            sGraphNodeRotationFields,            LUA_GRAPH_NODE_ROTATION_FIELD_COUNT             },
 | 
				
			||||||
    { LOT_GRAPHNODESCALE,               sGraphNodeScaleFields,               LUA_GRAPH_NODE_SCALE_FIELD_COUNT                },
 | 
					    { LOT_GRAPHNODESCALE,               sGraphNodeScaleFields,               LUA_GRAPH_NODE_SCALE_FIELD_COUNT                },
 | 
				
			||||||
 | 
					    { LOT_GRAPHNODESCALEXYZ,            sGraphNodeScaleXYZFields,            LUA_GRAPH_NODE_SCALE_XYZ_FIELD_COUNT            },
 | 
				
			||||||
    { LOT_GRAPHNODESHADOW,              sGraphNodeShadowFields,              LUA_GRAPH_NODE_SHADOW_FIELD_COUNT               },
 | 
					    { LOT_GRAPHNODESHADOW,              sGraphNodeShadowFields,              LUA_GRAPH_NODE_SHADOW_FIELD_COUNT               },
 | 
				
			||||||
    { LOT_GRAPHNODESTART,               sGraphNodeStartFields,               LUA_GRAPH_NODE_START_FIELD_COUNT                },
 | 
					    { LOT_GRAPHNODESTART,               sGraphNodeStartFields,               LUA_GRAPH_NODE_START_FIELD_COUNT                },
 | 
				
			||||||
    { LOT_GRAPHNODESWITCHCASE,          sGraphNodeSwitchCaseFields,          LUA_GRAPH_NODE_SWITCH_CASE_FIELD_COUNT          },
 | 
					    { LOT_GRAPHNODESWITCHCASE,          sGraphNodeSwitchCaseFields,          LUA_GRAPH_NODE_SWITCH_CASE_FIELD_COUNT          },
 | 
				
			||||||
| 
						 | 
					@ -3052,6 +3057,7 @@ const char *sLuaLotNames[] = {
 | 
				
			||||||
	[LOT_GRAPHNODEROOT] = "GraphNodeRoot",
 | 
						[LOT_GRAPHNODEROOT] = "GraphNodeRoot",
 | 
				
			||||||
	[LOT_GRAPHNODEROTATION] = "GraphNodeRotation",
 | 
						[LOT_GRAPHNODEROTATION] = "GraphNodeRotation",
 | 
				
			||||||
	[LOT_GRAPHNODESCALE] = "GraphNodeScale",
 | 
						[LOT_GRAPHNODESCALE] = "GraphNodeScale",
 | 
				
			||||||
 | 
						[LOT_GRAPHNODESCALEXYZ] = "GraphNodeScaleXYZ",
 | 
				
			||||||
	[LOT_GRAPHNODESHADOW] = "GraphNodeShadow",
 | 
						[LOT_GRAPHNODESHADOW] = "GraphNodeShadow",
 | 
				
			||||||
	[LOT_GRAPHNODESTART] = "GraphNodeStart",
 | 
						[LOT_GRAPHNODESTART] = "GraphNodeStart",
 | 
				
			||||||
	[LOT_GRAPHNODESWITCHCASE] = "GraphNodeSwitchCase",
 | 
						[LOT_GRAPHNODESWITCHCASE] = "GraphNodeSwitchCase",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,6 +77,7 @@ enum LuaObjectAutogenType {
 | 
				
			||||||
    LOT_GRAPHNODEROOT,
 | 
					    LOT_GRAPHNODEROOT,
 | 
				
			||||||
    LOT_GRAPHNODEROTATION,
 | 
					    LOT_GRAPHNODEROTATION,
 | 
				
			||||||
    LOT_GRAPHNODESCALE,
 | 
					    LOT_GRAPHNODESCALE,
 | 
				
			||||||
 | 
					    LOT_GRAPHNODESCALEXYZ,
 | 
				
			||||||
    LOT_GRAPHNODESHADOW,
 | 
					    LOT_GRAPHNODESHADOW,
 | 
				
			||||||
    LOT_GRAPHNODESTART,
 | 
					    LOT_GRAPHNODESTART,
 | 
				
			||||||
    LOT_GRAPHNODESWITCHCASE,
 | 
					    LOT_GRAPHNODESWITCHCASE,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1561,6 +1561,7 @@ char gSmluaConstants[] = ""
 | 
				
			||||||
"GRAPH_NODE_TYPE_BILLBOARD=0x01A\n"
 | 
					"GRAPH_NODE_TYPE_BILLBOARD=0x01A\n"
 | 
				
			||||||
"GRAPH_NODE_TYPE_DISPLAY_LIST=0x01B\n"
 | 
					"GRAPH_NODE_TYPE_DISPLAY_LIST=0x01B\n"
 | 
				
			||||||
"GRAPH_NODE_TYPE_SCALE=0x01C\n"
 | 
					"GRAPH_NODE_TYPE_SCALE=0x01C\n"
 | 
				
			||||||
 | 
					"GRAPH_NODE_TYPE_SCALE_XYZ=0x01D\n"
 | 
				
			||||||
"GRAPH_NODE_TYPE_SHADOW=0x028\n"
 | 
					"GRAPH_NODE_TYPE_SHADOW=0x028\n"
 | 
				
			||||||
"GRAPH_NODE_TYPE_OBJECT_PARENT=0x029\n"
 | 
					"GRAPH_NODE_TYPE_OBJECT_PARENT=0x029\n"
 | 
				
			||||||
"GRAPH_NODE_TYPE_GENERATED_LIST=(0x02A | GRAPH_NODE_TYPE_FUNCTIONAL)\n"
 | 
					"GRAPH_NODE_TYPE_GENERATED_LIST=(0x02A | GRAPH_NODE_TYPE_FUNCTIONAL)\n"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,6 +183,12 @@ void* smlua_to_cobject(lua_State* L, int index, u16 lot) {
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (cobject->freed) {
 | 
				
			||||||
 | 
					        LOG_LUA_LINE("smlua_to_cobject received freed pointer.");
 | 
				
			||||||
 | 
					        gSmLuaConvertSuccess = false;
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    gSmLuaConvertSuccess = true;
 | 
					    gSmLuaConvertSuccess = true;
 | 
				
			||||||
    return cobject->pointer;
 | 
					    return cobject->pointer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -387,6 +393,10 @@ bool packet_read_lnt(struct Packet* p, struct LSTNetworkType* lnt) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
///////////////////////////////////////////////////////////////////////////////////////////
 | 
					///////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline static uintptr_t smlua_get_pointer_key(void *ptr, u16 lt) {
 | 
				
			||||||
 | 
					    return (lt * 0x9E3779B97F4A7C15) ^ ((uintptr_t) ptr >> 3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CObject *smlua_push_object(lua_State* L, u16 lot, void* p, void *extraInfo) {
 | 
					CObject *smlua_push_object(lua_State* L, u16 lot, void* p, void *extraInfo) {
 | 
				
			||||||
    if (p == NULL) {
 | 
					    if (p == NULL) {
 | 
				
			||||||
        lua_pushnil(L);
 | 
					        lua_pushnil(L);
 | 
				
			||||||
| 
						 | 
					@ -394,7 +404,7 @@ CObject *smlua_push_object(lua_State* L, u16 lot, void* p, void *extraInfo) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    LUA_STACK_CHECK_BEGIN_NUM(L, 1);
 | 
					    LUA_STACK_CHECK_BEGIN_NUM(L, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uintptr_t key = (lot * 0x9E3779B97F4A7C15) ^ ((uintptr_t)p >> 3);
 | 
					    uintptr_t key = smlua_get_pointer_key(p, lot);
 | 
				
			||||||
    lua_rawgeti(L, LUA_REGISTRYINDEX, gSmLuaCObjects);
 | 
					    lua_rawgeti(L, LUA_REGISTRYINDEX, gSmLuaCObjects);
 | 
				
			||||||
    lua_pushinteger(L, key);
 | 
					    lua_pushinteger(L, key);
 | 
				
			||||||
    lua_gettable(L, -2);
 | 
					    lua_gettable(L, -2);
 | 
				
			||||||
| 
						 | 
					@ -431,7 +441,7 @@ CPointer *smlua_push_pointer(lua_State* L, u16 lvt, void* p, void *extraInfo) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    LUA_STACK_CHECK_BEGIN_NUM(L, 1);
 | 
					    LUA_STACK_CHECK_BEGIN_NUM(L, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uintptr_t key = (lvt * 0x9E3779B97F4A7C15) ^ ((uintptr_t)p >> 3);
 | 
					    uintptr_t key = smlua_get_pointer_key(p, lvt);
 | 
				
			||||||
    lua_rawgeti(L, LUA_REGISTRYINDEX, gSmLuaCPointers);
 | 
					    lua_rawgeti(L, LUA_REGISTRYINDEX, gSmLuaCPointers);
 | 
				
			||||||
    lua_pushinteger(L, key);
 | 
					    lua_pushinteger(L, key);
 | 
				
			||||||
    lua_gettable(L, -2);
 | 
					    lua_gettable(L, -2);
 | 
				
			||||||
| 
						 | 
					@ -840,15 +850,11 @@ void smlua_logline(void) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// If an object is freed that Lua has a CObject to,
 | 
					void smlua_free(void *ptr, u16 lot) {
 | 
				
			||||||
// Lua is able to use-after-free that pointer
 | 
					 | 
				
			||||||
// todo figure out a better way to do this
 | 
					 | 
				
			||||||
void smlua_free(void *ptr) {
 | 
					 | 
				
			||||||
    if (ptr && gLuaState) {
 | 
					    if (ptr && gLuaState) {
 | 
				
			||||||
        lua_State *L = gLuaState;
 | 
					        lua_State *L = gLuaState;
 | 
				
			||||||
        LUA_STACK_CHECK_BEGIN(L);
 | 
					        LUA_STACK_CHECK_BEGIN(L);
 | 
				
			||||||
        u16 lot = LOT_SURFACE; // Assuming this is a surface
 | 
					        uintptr_t key = smlua_get_pointer_key(ptr, lot);
 | 
				
			||||||
        uintptr_t key = lot ^ (uintptr_t) ptr;
 | 
					 | 
				
			||||||
        lua_rawgeti(L, LUA_REGISTRYINDEX, gSmLuaCObjects);
 | 
					        lua_rawgeti(L, LUA_REGISTRYINDEX, gSmLuaCObjects);
 | 
				
			||||||
        lua_pushinteger(L, key);
 | 
					        lua_pushinteger(L, key);
 | 
				
			||||||
        lua_gettable(L, -2);
 | 
					        lua_gettable(L, -2);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,6 +62,11 @@ void smlua_logline(void);
 | 
				
			||||||
void smlua_dump_stack(void);
 | 
					void smlua_dump_stack(void);
 | 
				
			||||||
void smlua_dump_globals(void);
 | 
					void smlua_dump_globals(void);
 | 
				
			||||||
void smlua_dump_table(int index);
 | 
					void smlua_dump_table(int index);
 | 
				
			||||||
void smlua_free(void *ptr);
 | 
					void smlua_free(void *ptr, u16 lot);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define smlua_free_lot(name, lot) \
 | 
				
			||||||
 | 
					static inline void smlua_free_##name(void *ptr) { smlua_free(ptr, lot); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					smlua_free_lot(surface, LOT_SURFACE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue