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 | ||||
| GRAPH_NODE_TYPE_SCALE = 0x01C | ||||
| 
 | ||||
| --- @type integer | ||||
| GRAPH_NODE_TYPE_SCALE_XYZ = 0x01D | ||||
| 
 | ||||
| --- @type integer | ||||
| GRAPH_NODE_TYPE_SHADOW = 0x028 | ||||
| 
 | ||||
|  |  | |||
|  | @ -969,16 +969,18 @@ | |||
| --- @class GraphNodeRotation | ||||
| --- @field public displayList Pointer_Gfx | ||||
| --- @field public node GraphNode | ||||
| --- @field public prevRotation Vec3s | ||||
| --- @field public prevTimestamp integer | ||||
| --- @field public rotation Vec3s | ||||
| 
 | ||||
| --- @class GraphNodeScale | ||||
| --- @field public displayList Pointer_Gfx | ||||
| --- @field public node GraphNode | ||||
| --- @field public prevScale number | ||||
| --- @field public scale number | ||||
| 
 | ||||
| --- @class GraphNodeScaleXYZ | ||||
| --- @field public displayList Pointer_Gfx | ||||
| --- @field public node GraphNode | ||||
| --- @field public scale Vec3f | ||||
| 
 | ||||
| --- @class GraphNodeShadow | ||||
| --- @field public node GraphNode | ||||
| --- @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_2(GEO_SCALE, 0); | ||||
|     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_1F); | ||||
|     geo_symbol_1(GEO_CULLING_RADIUS, 0); | ||||
|  |  | |||
|  | @ -135,8 +135,8 @@ private: | |||
| }; | ||||
| 
 | ||||
| extern "C" { | ||||
| void* hmap_create(MapType type) { | ||||
|     return new HMap(type); | ||||
| void* hmap_create(bool useUnordered) { | ||||
|     return new HMap(useUnordered ? MapType::Unordered : MapType::Ordered); | ||||
| } | ||||
| 
 | ||||
| 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_ROTATION,             sizeof(GraphNodeRotation) }, | ||||
|     { GRAPH_NODE_TYPE_SCALE,                sizeof(GraphNodeScale) }, | ||||
|     { GRAPH_NODE_TYPE_SCALE_XYZ,            sizeof(GraphNodeScaleXYZ) }, | ||||
|     { GRAPH_NODE_TYPE_OBJECT,               sizeof(GraphNodeObject) }, | ||||
|     { GRAPH_NODE_TYPE_CULLING_RADIUS,       sizeof(GraphNodeCullingRadius) }, | ||||
|     { GRAPH_NODE_TYPE_ANIMATED_PART,        sizeof(GraphNodeAnimatedPart) }, | ||||
|  |  | |||
|  | @ -1352,6 +1352,7 @@ | |||
| - GRAPH_NODE_TYPE_BILLBOARD | ||||
| - GRAPH_NODE_TYPE_DISPLAY_LIST | ||||
| - GRAPH_NODE_TYPE_SCALE | ||||
| - GRAPH_NODE_TYPE_SCALE_XYZ | ||||
| - GRAPH_NODE_TYPE_SHADOW | ||||
| - GRAPH_NODE_TYPE_OBJECT_PARENT | ||||
| - GRAPH_NODE_TYPE_GENERATED_LIST | ||||
|  |  | |||
|  | @ -56,6 +56,7 @@ | |||
| - [GraphNodeRoot](#GraphNodeRoot) | ||||
| - [GraphNodeRotation](#GraphNodeRotation) | ||||
| - [GraphNodeScale](#GraphNodeScale) | ||||
| - [GraphNodeScaleXYZ](#GraphNodeScaleXYZ) | ||||
| - [GraphNodeShadow](#GraphNodeShadow) | ||||
| - [GraphNodeStart](#GraphNodeStart) | ||||
| - [GraphNodeSwitchCase](#GraphNodeSwitchCase) | ||||
|  | @ -1477,8 +1478,6 @@ | |||
| | ----- | ---- | ------ | | ||||
| | displayList | `Pointer` <`Gfx`> |  | | ||||
| | node | [GraphNode](structs.md#GraphNode) | read-only | | ||||
| | prevRotation | [Vec3s](structs.md#Vec3s) | read-only | | ||||
| | prevTimestamp | `integer` |  | | ||||
| | rotation | [Vec3s](structs.md#Vec3s) | read-only | | ||||
| 
 | ||||
| [:arrow_up_small:](#) | ||||
|  | @ -1491,13 +1490,24 @@ | |||
| | ----- | ---- | ------ | | ||||
| | displayList | `Pointer` <`Gfx`> |  | | ||||
| | node | [GraphNode](structs.md#GraphNode) | read-only | | ||||
| | prevScale | `number` |  | | ||||
| | scale | `number` |  | | ||||
| 
 | ||||
| [:arrow_up_small:](#) | ||||
| 
 | ||||
| <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) | ||||
| 
 | ||||
| | Field | Type | Access | | ||||
|  |  | |||
|  | @ -407,6 +407,30 @@ enum SkyBackgroundParams { | |||
|     CMD_W(scale), \ | ||||
|     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 | ||||
|  */ | ||||
|  |  | |||
|  | @ -535,29 +535,45 @@ void geo_layout_cmd_node_rotation(void) { | |||
|   0x1D: Create scale scene graph node with optional display list | ||||
|    cmd+0x01: u8 params | ||||
|      (params & 0x80): if set, enable displayList field and drawingLayer | ||||
|      (params & 0x40): if set, enable scale XYZ | ||||
|      (params & 0x0F): drawingLayer | ||||
|    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) { | ||||
|     struct GraphNodeScale *graphNode; | ||||
| 
 | ||||
|     s16 drawingLayer = 0; | ||||
|     s16 params = cur_geo_cmd_u8(0x01); | ||||
|     f32 scale = cur_geo_cmd_u32(0x04) / 65536.0f; | ||||
|     Vec3f scale; | ||||
|     void *displayList = NULL; | ||||
|     bool isScaleXYZ = (params & 0x40) != 0; | ||||
| 
 | ||||
|     if (params & 0x80) { | ||||
|         displayList = cur_geo_cmd_ptr(0x08); | ||||
|         drawingLayer = params & 0x0F; | ||||
|         gGeoLayoutCommand += 4 << CMD_SIZE_SHIFT; | ||||
|     if (isScaleXYZ) { | ||||
|         scale[0] = cur_geo_cmd_u32(0x04) / 65536.0f; | ||||
|         scale[1] = cur_geo_cmd_u32(0x08) / 65536.0f; | ||||
|         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
 | ||||
|  |  | |||
|  | @ -291,7 +291,26 @@ struct GraphNodeScale *init_graph_node_scale(struct DynamicPool *pool, | |||
|         init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_SCALE); | ||||
|         graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF); | ||||
|         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); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -44,6 +44,7 @@ | |||
| #define GRAPH_NODE_TYPE_BILLBOARD             0x01A | ||||
| #define GRAPH_NODE_TYPE_DISPLAY_LIST          0x01B | ||||
| #define GRAPH_NODE_TYPE_SCALE                 0x01C | ||||
| #define GRAPH_NODE_TYPE_SCALE_XYZ             0x01D | ||||
| #define GRAPH_NODE_TYPE_SHADOW                0x028 | ||||
| #define GRAPH_NODE_TYPE_OBJECT_PARENT         0x029 | ||||
| #define GRAPH_NODE_TYPE_GENERATED_LIST       (0x02A | GRAPH_NODE_TYPE_FUNCTIONAL) | ||||
|  | @ -241,8 +242,6 @@ struct GraphNodeRotation | |||
|     /*0x00*/ struct GraphNode node; | ||||
|     /*0x14*/ Gfx *displayList; | ||||
|     /*0x18*/ Vec3s rotation; | ||||
|     Vec3s prevRotation; | ||||
|     u32 prevTimestamp; | ||||
| }; | ||||
| 
 | ||||
| /** GraphNode part that transforms itself and its children based on animation
 | ||||
|  | @ -293,7 +292,16 @@ struct GraphNodeScale | |||
|     /*0x00*/ struct GraphNode node; | ||||
|     /*0x14*/ Gfx *displayList; | ||||
|     /*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.
 | ||||
|  | @ -403,6 +411,8 @@ struct GraphNodeRotation *init_graph_node_rotation(struct DynamicPool *pool, str | |||
|                                                    s32 drawingLayer, void *displayList, Vec3s rotation); | ||||
| struct GraphNodeScale *init_graph_node_scale(struct DynamicPool *pool, struct GraphNodeScale *graphNode, | ||||
|                                              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 GraphNode *sharedChild, Vec3f pos, Vec3s angle, Vec3f scale); | ||||
| 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_dynamic_surfaces(); | ||||
| 
 | ||||
|     sSurfaceNodePool = growing_array_init(sSurfaceNodePool, 0x1000); | ||||
|     sSurfacePool = growing_array_init(sSurfacePool, 0x400); | ||||
|     sSurfaceNodePool = growing_array_init(sSurfaceNodePool, 0x1000, malloc, free); | ||||
|     sSurfacePool = growing_array_init(sSurfacePool, 0x400, malloc, smlua_free_surface); | ||||
| 
 | ||||
|     gEnvironmentRegions = NULL; | ||||
|     gSurfaceNodesAllocated = 0; | ||||
|  |  | |||
|  | @ -253,6 +253,7 @@ void clear_areas(void) { | |||
|     } | ||||
| 
 | ||||
|     le_clear(); | ||||
|     geo_clear_interp_data(); | ||||
| } | ||||
| 
 | ||||
| void clear_area_graph_nodes(void) { | ||||
|  | @ -311,6 +312,7 @@ void unload_area(void) { | |||
|     } | ||||
| 
 | ||||
|     le_clear(); | ||||
|     geo_clear_interp_data(); | ||||
| } | ||||
| 
 | ||||
| void load_mario_area(void) { | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ | |||
| #include "main.h" | ||||
| #include "engine/math_util.h" | ||||
| #include "engine/graph_node.h" | ||||
| #include "rendering_graph_node.h" | ||||
| #include "area.h" | ||||
| #include "save_file.h" | ||||
| #include "sound_init.h" | ||||
|  | @ -1749,6 +1750,7 @@ s32 update_level(void) { | |||
| 
 | ||||
| s32 init_level(void) { | ||||
|     sync_objects_clear(); | ||||
|     geo_clear_interp_data(); | ||||
|     reset_dialog_render_state(); | ||||
| 
 | ||||
|     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[1] = bodyState->torsoAngle[2] * 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
 | ||||
|         get_pos_from_transform_mtx(bodyState->torsoPos, *curTransform, *gCurGraphNodeCamera->matrixPtr); | ||||
|         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); | ||||
|         } | ||||
| 
 | ||||
|         if (plrIdx != 0) { | ||||
|             // only interpolate angles for the local player
 | ||||
|             vec3s_copy(rotNode->prevRotation, rotNode->rotation); | ||||
|             rotNode->prevTimestamp = gGlobalTimer; | ||||
|         } | ||||
| 
 | ||||
|         // update head position in bodyState
 | ||||
|         get_pos_from_transform_mtx(bodyState->headPos, | ||||
|                                    *c, | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ | |||
| #include "memory.h" | ||||
| #include "print.h" | ||||
| #include "pc/debuglog.h" | ||||
| #include "pc/lua/smlua.h" | ||||
| 
 | ||||
| #define ALIGN16(val) (((val) + 0xF) & ~0xF) | ||||
| 
 | ||||
|  | @ -186,12 +185,14 @@ void growing_pool_free_pool(struct GrowingPool *pool) { | |||
|  // 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); | ||||
|     array = calloc(1, sizeof(struct GrowingArray)); | ||||
|     array->buffer = calloc(capacity, sizeof(void *)); | ||||
|     array->capacity = capacity; | ||||
|     array->count = 0; | ||||
|     array->alloc = alloc; | ||||
|     array->free = free; | ||||
|     return array; | ||||
| } | ||||
| 
 | ||||
|  | @ -211,7 +212,7 @@ void *growing_array_alloc(struct GrowingArray *array, u32 size) { | |||
|         // Alloc element if needed
 | ||||
|         void **elem = &array->buffer[array->count++]; | ||||
|         if (!*elem) { | ||||
|             *elem = malloc(size); | ||||
|             *elem = array->alloc(size); | ||||
|         } | ||||
|         memset(*elem, 0, size); | ||||
|         return *elem; | ||||
|  | @ -223,7 +224,7 @@ void growing_array_free(struct GrowingArray **array) { | |||
|     if (*array) { | ||||
|         for (u32 i = 0; i != (*array)->capacity; ++i) { | ||||
|             if ((*array)->buffer[i]) { | ||||
|                 smlua_free((*array)->buffer[i]); | ||||
|                 (*array)->free((*array)->buffer[i]); | ||||
|             } | ||||
|         } | ||||
|         free((*array)->buffer); | ||||
|  |  | |||
|  | @ -39,11 +39,16 @@ struct GrowingPoolNode | |||
|     struct GrowingPoolNode* prev; | ||||
| }; | ||||
| 
 | ||||
| typedef void *(*GrowingArrayAllocFunc)(size_t); | ||||
| typedef void (*GrowingArrayFreeFunc)(void *); | ||||
| 
 | ||||
| struct GrowingArray | ||||
| { | ||||
|     void **buffer; | ||||
|     u32 count; | ||||
|     u32 capacity; | ||||
|     GrowingArrayAllocFunc alloc; | ||||
|     GrowingArrayFreeFunc free; | ||||
| }; | ||||
| 
 | ||||
| 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_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_free(struct GrowingArray **array); | ||||
| void growing_array_debug_print(struct GrowingArray *array, const char *name, s32 x, s32 y); | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ | |||
| #include "obj_behaviors.h" | ||||
| #include "platform_displacement.h" | ||||
| #include "profiler.h" | ||||
| #include "rendering_graph_node.h" | ||||
| #include "spawn_object.h" | ||||
| #include "first_person_cam.h" | ||||
| #include "engine/math_util.h" | ||||
|  | @ -624,6 +625,7 @@ void clear_objects(void) { | |||
|     gObjectLists = gObjectListArray; | ||||
| 
 | ||||
|     clear_dynamic_surfaces(); | ||||
|     geo_clear_interp_data(); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| #include "area.h" | ||||
| #include "engine/math_util.h" | ||||
| #include "engine/lighting_engine.h" | ||||
| #include "data/dynos_cmap.cpp.h" | ||||
| #include "game_init.h" | ||||
| #include "gfx_dimensions.h" | ||||
| #include "main.h" | ||||
|  | @ -183,28 +184,27 @@ static Gfx* sViewportClipPos = NULL; | |||
| static Vp   sViewportPrev    = { 0 }; | ||||
| static Vp   sViewportInterp  = { 0 }; | ||||
| 
 | ||||
| static struct GraphNodeBackground* sBackgroundNode = NULL; | ||||
| Gfx* gBackgroundSkyboxGfx = NULL; | ||||
| Vtx* gBackgroundSkyboxVerts[SKYBOX_TILES_Y][SKYBOX_TILES_X] = { 0 }; | ||||
| Mtx* gBackgroundSkyboxMtx = NULL; | ||||
| struct GraphNodeRoot* sBackgroundNodeRoot = NULL; | ||||
| 
 | ||||
| #define MAX_SHADOW_NODES 128 | ||||
| struct ShadowInterp sShadowInterp[MAX_SHADOW_NODES] = { 0 }; | ||||
| static struct GraphNodeBackground* sBackgroundNode = NULL; | ||||
| static struct GraphNodeRoot* sBackgroundNodeRoot = NULL; | ||||
| static struct GraphNodeCamera* sCameraNode = NULL; | ||||
| 
 | ||||
| static struct GrowingArray* sShadowInterp = NULL; | ||||
| struct ShadowInterp* gShadowInterpCurrent = NULL; | ||||
| static u8 sShadowInterpCount = 0; | ||||
| 
 | ||||
| static struct GraphNodeCamera * sCameraNode = NULL; | ||||
| 
 | ||||
| struct { | ||||
| struct MtxInterp { | ||||
|     Gfx *pos; | ||||
|     Mtx *mtx; | ||||
|     Mtx *mtxPrev; | ||||
|     void *displayList; | ||||
|     Mtx interp; | ||||
|     u8 usingCamSpace; | ||||
| } gMtxTbl[6400]; | ||||
| s32 gMtxTblSize = 0; | ||||
| }; | ||||
| 
 | ||||
| static struct GrowingArray* sMtxTbl = NULL; | ||||
| 
 | ||||
| struct Object* gCurGraphNodeProcessingObject = NULL; | ||||
| struct MarioState* gCurGraphNodeMarioState = NULL; | ||||
|  | @ -213,8 +213,36 @@ f32 gOverrideFOV = 0; | |||
| f32 gOverrideNear = 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) { | ||||
|     gMtxTblSize = 0; | ||||
|     init_mtx(); | ||||
| 
 | ||||
|     if (sPerspectiveNode != NULL) { | ||||
|         sPerspectiveNode->prevFov = sPerspectiveNode->fov; | ||||
|  | @ -235,8 +263,6 @@ void patch_mtx_before(void) { | |||
|         sBackgroundNode = NULL; | ||||
|         gBackgroundSkyboxGfx = NULL; | ||||
|     } | ||||
| 
 | ||||
|     sShadowInterpCount = 0; | ||||
| } | ||||
| 
 | ||||
| void patch_mtx_interpolated(f32 delta) { | ||||
|  | @ -285,8 +311,8 @@ void patch_mtx_interpolated(f32 delta) { | |||
|     } | ||||
| 
 | ||||
|     struct GraphNodeObject* savedObj = gCurGraphNodeObject; | ||||
|     for (s32 i = 0; i < sShadowInterpCount; i++) { | ||||
|         struct ShadowInterp* interp = &sShadowInterp[i]; | ||||
|     for (u32 i = 0; i < sShadowInterp->count; i++) { | ||||
|         struct ShadowInterp* interp = sShadowInterp->buffer[i]; | ||||
|         if (!interp->gfx) { continue; } | ||||
|         gShadowInterpCurrent = interp; | ||||
|         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
 | ||||
|     Mtx camTranfInv, prevCamTranfInv; | ||||
|     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) { | ||||
|         // compute inverse camera matrix to transform out of camera space later
 | ||||
|         mtxf_inverse(camTranfInv.m, *sCameraNode->matrixPtr); | ||||
|  | @ -318,12 +344,13 @@ void patch_mtx_interpolated(f32 delta) { | |||
|         mtxf_to_mtx(&camInterp, camInterp.m); | ||||
|     } | ||||
| 
 | ||||
|     for (s32 i = 0; i < gMtxTblSize; i++) { | ||||
|         Gfx *pos = gMtxTbl[i].pos; | ||||
|         Mtx *srcMtx = gMtxTbl[i].mtx; | ||||
|         Mtx *srcMtxPrev = gMtxTbl[i].mtxPrev; | ||||
|     for (u32 i = 0; i < sMtxTbl->count; i++) { | ||||
|         struct MtxInterp *interp = sMtxTbl->buffer[i]; | ||||
|         Gfx *pos = interp->pos; | ||||
|         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
 | ||||
|             Mtx bufMtx, bufMtxPrev; | ||||
|             mtxf_copy(bufMtx.m, srcMtx->m); | ||||
|  | @ -333,18 +360,96 @@ void patch_mtx_interpolated(f32 delta) { | |||
|             srcMtx = &bufMtx; | ||||
|             srcMtxPrev = &bufMtxPrev; | ||||
|         } | ||||
|         delta_interpolate_mtx(&gMtxTbl[i].interp, srcMtxPrev, srcMtx, delta); | ||||
|         if (gMtxTbl[i].usingCamSpace) { | ||||
|         delta_interpolate_mtx(&interp->interp, srcMtxPrev, srcMtx, delta); | ||||
|         if (interp->usingCamSpace) { | ||||
|             // 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); | ||||
|     } | ||||
| 
 | ||||
|     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. | ||||
|  */ | ||||
|  | @ -397,13 +502,13 @@ static void geo_process_master_list_sub(struct GraphNodeMasterList *node) { | |||
|             gDPSetRenderMode(gDisplayListHead++, modeList->modes[i], mode2List->modes[i]); | ||||
|             while (currList != NULL) { | ||||
|                 detect_and_skip_mtx_interpolation(&currList->transform, &currList->transformPrev); | ||||
|                 if ((u32) gMtxTblSize < sizeof(gMtxTbl) / sizeof(gMtxTbl[0])) { | ||||
|                     gMtxTbl[gMtxTblSize].pos = gDisplayListHead; | ||||
|                     gMtxTbl[gMtxTblSize].mtx = currList->transform; | ||||
|                     gMtxTbl[gMtxTblSize].mtxPrev = currList->transformPrev; | ||||
|                     gMtxTbl[gMtxTblSize].displayList = currList->displayList; | ||||
|                     gMtxTbl[gMtxTblSize++].usingCamSpace = currList->usingCamSpace; | ||||
|                 } | ||||
| 
 | ||||
|                 struct MtxInterp *interp = growing_array_alloc(sMtxTbl, sizeof(struct MtxInterp)); | ||||
|                 interp->pos = gDisplayListHead; | ||||
|                 interp->mtx = currList->transform; | ||||
|                 interp->mtxPrev = currList->transformPrev; | ||||
|                 interp->displayList = currList->displayList; | ||||
|                 interp->usingCamSpace = currList->usingCamSpace; | ||||
| 
 | ||||
|                 gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transformPrev), | ||||
|                           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.
 | ||||
|     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); | ||||
|     mtxf_rotate_zxy_and_translate(mtxf, translation, node->rotation); | ||||
|     mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); | ||||
|     mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[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]); | ||||
|     ); | ||||
| 
 | ||||
|     // Increment the matrix stack, If we fail to do so. Just 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\.
 | ||||
|     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); | ||||
|     mtxf_rotate_zxy_and_translate(mtxf, translation, gVec3sZero); | ||||
|     mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); | ||||
|     mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[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]); | ||||
|     ); | ||||
| 
 | ||||
|     // Increment the matrix stack, If we fail to do so. Just 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\.
 | ||||
|     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_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); | ||||
| 
 | ||||
|     if (gGlobalTimer == node->prevTimestamp + 1) { | ||||
|         mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, node->prevRotation); | ||||
|     } else { | ||||
|         mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, node->rotation); | ||||
|     } | ||||
|     mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]); | ||||
|     vec3s_copy(node->prevRotation, node->rotation); | ||||
|     node->prevTimestamp = gGlobalTimer; | ||||
|     // previous frame
 | ||||
|     geo_update_interpolation(NULL, node->rotation, NULL, | ||||
|         if (geo_should_interpolate(interp)) { | ||||
|             mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, interp->rotation); | ||||
|         } | ||||
|         mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]); | ||||
|     ); | ||||
| 
 | ||||
|     // Increment the matrix stack, If we fail to do so. Just 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\.
 | ||||
|     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); | ||||
|     mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex], scaleVec); | ||||
| 
 | ||||
|     /* TODO: this fails because multiple player models reuse the same scalenode
 | ||||
|     vec3f_set(prevScaleVec, node->prevScale, node->prevScale, node->prevScale); | ||||
|     mtxf_scale_vec3f(gMatStackPrev[gMatStackIndex + 1], gMatStackPrev[gMatStackIndex], prevScaleVec); | ||||
|     node->prevScale = node->scale;*/ | ||||
|     // previous frame
 | ||||
|     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); | ||||
|     ); | ||||
| 
 | ||||
|     // just use the current scale for now
 | ||||
|     vec3f_set(prevScaleVec, node->scale, node->scale, node->scale); | ||||
|     mtxf_scale_vec3f(gMatStackPrev[gMatStackIndex + 1], gMatStackPrev[gMatStackIndex], scaleVec); | ||||
|     // Increment the matrix stack, If we fail to do so. Just return.
 | ||||
|     if (!increment_mat_stack()) { return; } | ||||
| 
 | ||||
|     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.
 | ||||
|     if (!increment_mat_stack()) { return; } | ||||
|  | @ -779,21 +938,28 @@ static void geo_process_billboard(struct GraphNodeBillboard *node) { | |||
| 
 | ||||
|     s16 nextMatStackIndex = gMatStackIndex + 1; | ||||
| 
 | ||||
|     // current frame
 | ||||
|     vec3s_to_vec3f(translation, node->translation); | ||||
|     mtxf_billboard(gMatStack[nextMatStackIndex], gMatStack[gMatStackIndex], translation, | ||||
|                    gCurGraphNodeCamera->roll); | ||||
|     mtxf_billboard(gMatStackPrev[nextMatStackIndex], gMatStackPrev[gMatStackIndex], translation, | ||||
|                    gCurGraphNodeCamera->roll); | ||||
|     mtxf_billboard(gMatStack[nextMatStackIndex], gMatStack[gMatStackIndex], translation, gCurGraphNodeCamera->roll); | ||||
| 
 | ||||
|     // previous frame
 | ||||
|     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) { | ||||
|         mtxf_scale_vec3f(gMatStack[nextMatStackIndex], gMatStack[nextMatStackIndex], | ||||
|                          gCurGraphNodeHeldObject->objNode->header.gfx.scale); | ||||
|         mtxf_scale_vec3f(gMatStackPrev[nextMatStackIndex], gMatStackPrev[nextMatStackIndex], | ||||
|                          gCurGraphNodeHeldObject->objNode->header.gfx.scale); | ||||
|                          gCurGraphNodeHeldObject->objNode->header.gfx.prevScale); | ||||
|     } else if (gCurGraphNodeObject != NULL) { | ||||
|         mtxf_scale_vec3f(gMatStack[nextMatStackIndex], gMatStack[nextMatStackIndex], | ||||
|                          gCurGraphNodeObject->scale); | ||||
|         mtxf_scale_vec3f(gMatStackPrev[nextMatStackIndex], gMatStackPrev[nextMatStackIndex], | ||||
|                          gCurGraphNodeObject->scale); | ||||
|                          gCurGraphNodeObject->prevScale); | ||||
|     } else { | ||||
|         //LOG_ERROR("gCurGraphNodeObject and gCurGraphNodeHeldObject are both NULL!");
 | ||||
|     } | ||||
|  | @ -938,8 +1104,6 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) { | |||
|     Mat4 matrix; | ||||
|     Vec3s rotation; | ||||
|     Vec3f translation; | ||||
|     Vec3s rotationPrev; | ||||
|     Vec3f translationPrev; | ||||
| 
 | ||||
|     // 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; } | ||||
|  | @ -947,20 +1111,25 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) { | |||
|     u16 *animAttribute = gCurrAnimAttribute; | ||||
|     u8 animType = gCurAnimType; | ||||
| 
 | ||||
|     // current frame
 | ||||
|     vec3s_copy(rotation, gVec3sZero); | ||||
|     vec3f_set(translation, node->translation[0], node->translation[1], node->translation[2]); | ||||
| 
 | ||||
|     vec3s_copy(rotationPrev, rotation); | ||||
|     vec3f_copy(translationPrev, translation); | ||||
| 
 | ||||
|     anim_process(translationPrev, rotationPrev, &animType, gPrevAnimFrame, &animAttribute); | ||||
|     vec3s_to_vec3f(translation, node->translation); | ||||
|     anim_process(translation, rotation, &gCurAnimType, gCurrAnimFrame, &gCurrAnimAttribute); | ||||
| 
 | ||||
|     mtxf_rotate_xyz_and_translate(matrix, translation, rotation); | ||||
|     mtxf_mul(gMatStack[gMatStackIndex + 1], matrix, gMatStack[gMatStackIndex]); | ||||
| 
 | ||||
|     mtxf_rotate_xyz_and_translate(matrix, translationPrev, rotationPrev); | ||||
|     mtxf_mul(gMatStackPrev[gMatStackIndex + 1], matrix, gMatStackPrev[gMatStackIndex]); | ||||
|     // 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]); | ||||
|     ); | ||||
| 
 | ||||
|     // Increment the matrix stack, If we fail to do so. Just return.
 | ||||
|     if (!increment_mat_stack()) { return; } | ||||
|  | @ -1058,18 +1227,25 @@ static void geo_process_shadow(struct GraphNodeShadow *node) { | |||
|             shadowScale = node->shadowScale * gCurGraphNodeObject->scale[0]; | ||||
|         } | ||||
| 
 | ||||
|         f32 objScale = 1.0f; | ||||
|         Vec3f objScale = { 1, 1, 1 }; | ||||
|         if (gCurAnimEnabled) { | ||||
|             if (gCurAnimType == ANIM_TYPE_TRANSLATION | ||||
|                 || gCurAnimType == ANIM_TYPE_LATERAL_TRANSLATION) { | ||||
|                 struct GraphNode *geo = node->node.children; | ||||
|                 if (geo != NULL && geo->type == GRAPH_NODE_TYPE_SCALE) { | ||||
|                     objScale = ((struct GraphNodeScale *) geo)->scale; | ||||
|                 if (geo != NULL) { | ||||
|                     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; | ||||
|                 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; | ||||
| 
 | ||||
|                 // simple matrix rotation so the shadow offset rotates along with the object
 | ||||
|  | @ -1103,18 +1279,14 @@ static void geo_process_shadow(struct GraphNodeShadow *node) { | |||
|             gCurGraphNodeObject->prevShadowPosTimestamp = gGlobalTimer; | ||||
|         } | ||||
| 
 | ||||
|         if (sShadowInterpCount < MAX_SHADOW_NODES) { | ||||
|             struct ShadowInterp* interp = &sShadowInterp[sShadowInterpCount++]; | ||||
|             gShadowInterpCurrent = interp; | ||||
|             interp->gfx = NULL; | ||||
|             interp->node = node; | ||||
|             interp->shadowScale = shadowScale; | ||||
|             interp->obj = gCurGraphNodeObject; | ||||
|             vec3f_copy(interp->shadowPos, gCurGraphNodeObject->shadowPos); | ||||
|             vec3f_copy(interp->shadowPosPrev, shadowPosPrev); | ||||
|         } else { | ||||
|             gShadowInterpCurrent = NULL; | ||||
|         } | ||||
|         struct ShadowInterp* interp = growing_array_alloc(sShadowInterp, sizeof(struct ShadowInterp)); | ||||
|         gShadowInterpCurrent = interp; | ||||
|         interp->gfx = NULL; | ||||
|         interp->node = node; | ||||
|         interp->shadowScale = shadowScale; | ||||
|         interp->obj = gCurGraphNodeObject; | ||||
|         vec3f_copy(interp->shadowPos, gCurGraphNodeObject->shadowPos); | ||||
|         vec3f_copy(interp->shadowPosPrev, shadowPosPrev); | ||||
| 
 | ||||
|         Gfx *shadowListPrev = create_shadow_below_xyz(shadowPosPrev[0], shadowPosPrev[1], | ||||
|                                                       shadowPosPrev[2], shadowScale, | ||||
|  | @ -1640,6 +1812,9 @@ void geo_process_node_and_siblings(struct GraphNode *firstNode) { | |||
|                     case GRAPH_NODE_TYPE_SCALE: | ||||
|                         geo_process_scale((struct GraphNodeScale *) curGraphNode); | ||||
|                         break; | ||||
|                     case GRAPH_NODE_TYPE_SCALE_XYZ: | ||||
|                         geo_process_scale_xyz((struct GraphNodeScaleXYZ *) curGraphNode); | ||||
|                         break; | ||||
|                     case GRAPH_NODE_TYPE_SHADOW: | ||||
|                         geo_process_shadow((struct GraphNodeShadow *) curGraphNode); | ||||
|                         break; | ||||
|  | @ -1685,11 +1860,11 @@ static void geo_clear_interp_variables(void) { | |||
|     gBackgroundSkyboxMtx = NULL; | ||||
|     sBackgroundNodeRoot = NULL; | ||||
| 
 | ||||
|     sShadowInterp->count = 0; | ||||
|     gShadowInterpCurrent = NULL; | ||||
|     sShadowInterpCount = 0; | ||||
| 
 | ||||
|     sMtxTbl->count = 0; | ||||
|     sCameraNode = NULL; | ||||
|     gMtxTblSize = 0; | ||||
|     gCurGraphNodeProcessingObject = NULL; | ||||
|     gCurGraphNodeMarioState = NULL; | ||||
| } | ||||
|  |  | |||
|  | @ -43,6 +43,7 @@ extern f32 gOverrideFar; | |||
| 
 | ||||
| void geo_process_node_and_siblings(struct GraphNode *firstNode); | ||||
| void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor); | ||||
| void geo_clear_interp_data(); | ||||
| 
 | ||||
| struct ShadowInterp { | ||||
|     Gfx*  gfx; | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ | |||
| DialogTable *gDialogTable = NULL; | ||||
| 
 | ||||
| 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++) { | ||||
|         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)              }, | ||||
| }; | ||||
| 
 | ||||
| #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] = { | ||||
|     { "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) }, | ||||
|     { "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)            }, | ||||
|     { "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) }, | ||||
|     { "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] = { | ||||
|     { "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) }, | ||||
|     { "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)              }, | ||||
| }; | ||||
| 
 | ||||
| #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 | ||||
| static struct LuaObjectField sGraphNodeShadowFields[LUA_GRAPH_NODE_SHADOW_FIELD_COUNT] = { | ||||
|     { "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_GRAPHNODEROTATION,            sGraphNodeRotationFields,            LUA_GRAPH_NODE_ROTATION_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_GRAPHNODESTART,               sGraphNodeStartFields,               LUA_GRAPH_NODE_START_FIELD_COUNT                }, | ||||
|     { LOT_GRAPHNODESWITCHCASE,          sGraphNodeSwitchCaseFields,          LUA_GRAPH_NODE_SWITCH_CASE_FIELD_COUNT          }, | ||||
|  | @ -3052,6 +3057,7 @@ const char *sLuaLotNames[] = { | |||
| 	[LOT_GRAPHNODEROOT] = "GraphNodeRoot", | ||||
| 	[LOT_GRAPHNODEROTATION] = "GraphNodeRotation", | ||||
| 	[LOT_GRAPHNODESCALE] = "GraphNodeScale", | ||||
| 	[LOT_GRAPHNODESCALEXYZ] = "GraphNodeScaleXYZ", | ||||
| 	[LOT_GRAPHNODESHADOW] = "GraphNodeShadow", | ||||
| 	[LOT_GRAPHNODESTART] = "GraphNodeStart", | ||||
| 	[LOT_GRAPHNODESWITCHCASE] = "GraphNodeSwitchCase", | ||||
|  |  | |||
|  | @ -77,6 +77,7 @@ enum LuaObjectAutogenType { | |||
|     LOT_GRAPHNODEROOT, | ||||
|     LOT_GRAPHNODEROTATION, | ||||
|     LOT_GRAPHNODESCALE, | ||||
|     LOT_GRAPHNODESCALEXYZ, | ||||
|     LOT_GRAPHNODESHADOW, | ||||
|     LOT_GRAPHNODESTART, | ||||
|     LOT_GRAPHNODESWITCHCASE, | ||||
|  |  | |||
|  | @ -1561,6 +1561,7 @@ char gSmluaConstants[] = "" | |||
| "GRAPH_NODE_TYPE_BILLBOARD=0x01A\n" | ||||
| "GRAPH_NODE_TYPE_DISPLAY_LIST=0x01B\n" | ||||
| "GRAPH_NODE_TYPE_SCALE=0x01C\n" | ||||
| "GRAPH_NODE_TYPE_SCALE_XYZ=0x01D\n" | ||||
| "GRAPH_NODE_TYPE_SHADOW=0x028\n" | ||||
| "GRAPH_NODE_TYPE_OBJECT_PARENT=0x029\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; | ||||
|     } | ||||
| 
 | ||||
|     if (cobject->freed) { | ||||
|         LOG_LUA_LINE("smlua_to_cobject received freed pointer."); | ||||
|         gSmLuaConvertSuccess = false; | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     gSmLuaConvertSuccess = true; | ||||
|     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) { | ||||
|     if (p == NULL) { | ||||
|         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); | ||||
| 
 | ||||
|     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_pushinteger(L, key); | ||||
|     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); | ||||
| 
 | ||||
|     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_pushinteger(L, key); | ||||
|     lua_gettable(L, -2); | ||||
|  | @ -840,15 +850,11 @@ void smlua_logline(void) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| // If an object is freed that Lua has a CObject to,
 | ||||
| // Lua is able to use-after-free that pointer
 | ||||
| // todo figure out a better way to do this
 | ||||
| void smlua_free(void *ptr) { | ||||
| void smlua_free(void *ptr, u16 lot) { | ||||
|     if (ptr && gLuaState) { | ||||
|         lua_State *L = gLuaState; | ||||
|         LUA_STACK_CHECK_BEGIN(L); | ||||
|         u16 lot = LOT_SURFACE; // Assuming this is a surface
 | ||||
|         uintptr_t key = lot ^ (uintptr_t) ptr; | ||||
|         uintptr_t key = smlua_get_pointer_key(ptr, lot); | ||||
|         lua_rawgeti(L, LUA_REGISTRYINDEX, gSmLuaCObjects); | ||||
|         lua_pushinteger(L, key); | ||||
|         lua_gettable(L, -2); | ||||
|  |  | |||
|  | @ -62,6 +62,11 @@ void smlua_logline(void); | |||
| void smlua_dump_stack(void); | ||||
| void smlua_dump_globals(void); | ||||
| 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 | ||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 PeachyPeach
						PeachyPeach