From 0f351e11fb9d11719f902c87e0d4e12c6e784dfe Mon Sep 17 00:00:00 2001 From: PeachyPeach <72323920+PeachyPeachSM64@users.noreply.github.com> Date: Thu, 24 Apr 2025 06:03:17 +0200 Subject: [PATCH] Gfx/Vtx improvements (#756) - Renamed the `new` and `realloc` functions to `create` and `resize` - Added `delete_all` - Made Mod Data a class: - Allocation is now limited to prevent out-of-memory crashes: 1024 display lists of max size 2048 and 1024 vertex buffers of max size 4096 per mod - Added error codes to identify the cause of a failure (name not found, pointer not found, max size exceeded, item pool is full, ...) --- autogen/lua_definitions/functions.lua | 28 +- data/dynos.c.h | 11 +- data/dynos.cpp.h | 15 +- data/dynos.h | 12 + data/dynos_bin_gfx.cpp | 4 +- data/dynos_bin_vtx.cpp | 4 +- data/dynos_c.cpp | 24 +- data/dynos_mgr_gfx.cpp | 119 ++++-- data/dynos_mgr_moddata.cpp | 11 + data/dynos_mgr_moddata.hpp | 368 +++++++++++++----- docs/lua/examples/gfx-vtx-demo/a-math.lua | 8 +- .../gfx-vtx-demo/actors/shape/geo.inc.c | 2 +- docs/lua/examples/gfx-vtx-demo/main.lua | 82 ++-- docs/lua/examples/gfx-vtx-demo/update.lua | 38 +- docs/lua/functions-6.md | 78 +++- docs/lua/functions.md | 10 +- lang/French.ini | 4 +- src/pc/lua/smlua_functions_autogen.c | 80 ++-- src/pc/lua/utils/smlua_gfx_utils.c | 116 ++++-- src/pc/lua/utils/smlua_gfx_utils.h | 24 +- 20 files changed, 739 insertions(+), 299 deletions(-) create mode 100644 data/dynos_mgr_moddata.cpp diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index d2ed82d09..29625d6c3 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -9760,24 +9760,28 @@ end --- @param length integer --- @return Pointer_Gfx --- Creates a new named display list of `length` commands -function gfx_new(name, length) +function gfx_create(name, length) -- ... end --- @param gfx Pointer_Gfx --- @param newLength integer ---- @return Pointer_Gfx ---- Reallocates a display list created by `gfx_new` to modify its length -function gfx_realloc(gfx, newLength) +--- Resizes a display list created by `gfx_create` +function gfx_resize(gfx, newLength) -- ... end --- @param gfx Pointer_Gfx ---- Deletes a display list created by `gfx_new` +--- Deletes a display list created by `gfx_create` function gfx_delete(gfx) -- ... end +--- Deletes all display lists created by `gfx_create` +function gfx_delete_all() + -- ... +end + --- @param vtx Pointer_Vtx --- @return integer --- Gets the max count of vertices of a vertex buffer @@ -9812,24 +9816,28 @@ end --- @param count integer --- @return Pointer_Vtx --- Creates a new named vertex buffer of `count` vertices -function vtx_new(name, count) +function vtx_create(name, count) -- ... end --- @param vtx Pointer_Vtx --- @param newCount integer ---- @return Pointer_Vtx ---- Reallocates a vertex buffer created by `vtx_new` to modify its count -function vtx_realloc(vtx, newCount) +--- Resizes a vertex buffer created by `vtx_create` +function vtx_resize(vtx, newCount) -- ... end --- @param vtx Pointer_Vtx ---- Deletes a vertex buffer created by `vtx_new` +--- Deletes a vertex buffer created by `vtx_create` function vtx_delete(vtx) -- ... end +--- Deletes all vertex buffers created by `vtx_create` +function vtx_delete_all() + -- ... +end + --- @param areaIndex integer --- Instantly changes the current area to `areaIndex` function smlua_level_util_change_area(areaIndex) diff --git a/data/dynos.c.h b/data/dynos.c.h index 46b719759..851fd7635 100644 --- a/data/dynos.c.h +++ b/data/dynos.c.h @@ -87,17 +87,20 @@ void dynos_model_clear_pool(enum ModelPool aModelPool); // -- gfx -- // Gfx *dynos_gfx_get_writable_display_list(Gfx* gfx); Gfx *dynos_gfx_get(const char *name, u32 *outLength); -Gfx *dynos_gfx_new(const char *name, u32 length); -Gfx *dynos_gfx_realloc(Gfx *gfx, u32 newLength); +Gfx *dynos_gfx_create(const char *name, u32 length); +bool dynos_gfx_resize(Gfx *gfx, u32 newLength); bool dynos_gfx_delete(Gfx *gfx); +void dynos_gfx_delete_all(); Vtx *dynos_vtx_get(const char *name, u32 *outCount); -Vtx *dynos_vtx_new(const char *name, u32 count); -Vtx *dynos_vtx_realloc(Vtx *vtx, u32 newCount); +Vtx *dynos_vtx_create(const char *name, u32 count); +bool dynos_vtx_resize(Vtx *vtx, u32 newCount); bool dynos_vtx_delete(Vtx *vtx); +void dynos_vtx_delete_all(); // -- other -- // void dynos_mod_shutdown(void); void dynos_add_scroll_target(u32 index, const char *name, u32 offset, u32 size); +u32 dynos_mod_data_get_last_error(); // -- smlua -- // bool dynos_smlua_parse_gfx_command(lua_State *L, Gfx *gfx, const char *command, bool hasSpecifiers, char *errorMsg, u32 errorSize); diff --git a/data/dynos.cpp.h b/data/dynos.cpp.h index 16d36bf62..73de49c42 100644 --- a/data/dynos.cpp.h +++ b/data/dynos.cpp.h @@ -662,10 +662,6 @@ struct LvlCmd { u8 mSize; }; -// modIndex -> itemName -> (itemPointer, itemSize) -template -using ModData = std::map>>; - // // Utils // @@ -988,20 +984,21 @@ void DynOS_Model_ClearPool(enum ModelPool aModelPool); Gfx *DynOS_Gfx_GetWritableDisplayList(Gfx *aGfx); Gfx *DynOS_Gfx_Get(const char *aName, u32 *outLength); -Gfx *DynOS_Gfx_New(const char *aName, u32 aLength); -Gfx *DynOS_Gfx_Realloc(Gfx *aGfx, u32 aNewLength); +Gfx *DynOS_Gfx_Create(const char *aName, u32 aLength); +bool DynOS_Gfx_Resize(Gfx *aGfx, u32 aNewLength); bool DynOS_Gfx_Delete(Gfx *aGfx); +void DynOS_Gfx_DeleteAll(); Vtx *DynOS_Vtx_Get(const char *aName, u32 *outCount); -Vtx *DynOS_Vtx_New(const char *aName, u32 aCount); -Vtx *DynOS_Vtx_Realloc(Vtx *aVtx, u32 aNewCount); +Vtx *DynOS_Vtx_Create(const char *aName, u32 aCount); +bool DynOS_Vtx_Resize(Vtx *aVtx, u32 aNewCount); bool DynOS_Vtx_Delete(Vtx *aVtx); +void DynOS_Vtx_DeleteAll(); void DynOS_Gfx_ModShutdown(); // // Mod Data Manager // -// template functions #include "dynos_mgr_moddata.hpp" // diff --git a/data/dynos.h b/data/dynos.h index 536e4668b..337307bde 100644 --- a/data/dynos.h +++ b/data/dynos.h @@ -45,4 +45,16 @@ enum ModelPool { MODEL_POOL_MAX, }; +enum { + DYNOS_MOD_DATA_ERROR_NAME_IS_NULL = 1, + DYNOS_MOD_DATA_ERROR_NAME_IS_EMPTY, + DYNOS_MOD_DATA_ERROR_NAME_NOT_FOUND, + DYNOS_MOD_DATA_ERROR_POINTER_IS_NULL, + DYNOS_MOD_DATA_ERROR_POINTER_NOT_FOUND, + DYNOS_MOD_DATA_ERROR_SIZE_IS_ZERO, + DYNOS_MOD_DATA_ERROR_SIZE_IS_ABOVE_MAX, + DYNOS_MOD_DATA_ERROR_ALREADY_EXISTS, + DYNOS_MOD_DATA_ERROR_POOL_IS_FULL, +}; + #endif diff --git a/data/dynos_bin_gfx.cpp b/data/dynos_bin_gfx.cpp index 677f1fd6c..d30a8a1a1 100644 --- a/data/dynos_bin_gfx.cpp +++ b/data/dynos_bin_gfx.cpp @@ -1122,7 +1122,7 @@ DataNode* DynOS_Gfx_Parse(GfxData* aGfxData, DataNode* aNode) { // Display list data u32 _Length = aNode->mTokens.Count() * DISPLAY_LIST_SIZE_PER_TOKEN; - aNode->mData = gfx_allocate_internal(_Length); + aNode->mData = gfx_allocate_internal(NULL, _Length); Gfx* _Head = aNode->mData; for (u64 _TokenIndex = 0; _TokenIndex < aNode->mTokens.Count();) { // Don't increment _TokenIndex here! ParseGfxSymbol(aGfxData, aNode, _Head, _TokenIndex); @@ -1171,7 +1171,7 @@ void DynOS_Gfx_Load(BinFile *aFile, GfxData *aGfxData) { // Data _Node->mSize = aFile->Read(); - _Node->mData = gfx_allocate_internal(_Node->mSize); + _Node->mData = gfx_allocate_internal(NULL, _Node->mSize); for (u32 i = 0; i != _Node->mSize; ++i) { u32 _WordsW0 = aFile->Read(); u32 _WordsW1 = aFile->Read(); diff --git a/data/dynos_bin_vtx.cpp b/data/dynos_bin_vtx.cpp index b3b7f578e..477c4d282 100644 --- a/data/dynos_bin_vtx.cpp +++ b/data/dynos_bin_vtx.cpp @@ -35,7 +35,7 @@ DataNode* DynOS_Vtx_Parse(GfxData* aGfxData, DataNode* aNode) { // Vertex data aNode->mSize = (u32) (aNode->mTokens.Count() / 10); - aNode->mData = vtx_allocate_internal(aNode->mSize); + aNode->mData = vtx_allocate_internal(NULL, aNode->mSize); for (u32 i = 0; i != aNode->mSize; ++i) { f32 px = (f32) aNode->mTokens[10 * i + 0].ParseFloat(); f32 py = (f32) aNode->mTokens[10 * i + 1].ParseFloat(); @@ -116,7 +116,7 @@ void DynOS_Vtx_Load(BinFile *aFile, GfxData *aGfxData) { // Data bool isUsingF32Vtx = false; _Node->mSize = aFile->Read(); - _Node->mData = vtx_allocate_internal(_Node->mSize); + _Node->mData = vtx_allocate_internal(NULL, _Node->mSize); for (u32 i = 0; i != _Node->mSize; ++i) { if (isUsingF32Vtx) { _Node->mData[i].n.ob[0] = aFile->Read(); diff --git a/data/dynos_c.cpp b/data/dynos_c.cpp index 57568a8cc..212ae1a32 100644 --- a/data/dynos_c.cpp +++ b/data/dynos_c.cpp @@ -280,34 +280,42 @@ Gfx *dynos_gfx_get(const char *name, u32 *outLength) { return DynOS_Gfx_Get(name, outLength); } -Gfx *dynos_gfx_new(const char *name, u32 length) { - return DynOS_Gfx_New(name, length); +Gfx *dynos_gfx_create(const char *name, u32 length) { + return DynOS_Gfx_Create(name, length); } -Gfx *dynos_gfx_realloc(Gfx *gfx, u32 newLength) { - return DynOS_Gfx_Realloc(gfx, newLength); +bool dynos_gfx_resize(Gfx *gfx, u32 newLength) { + return DynOS_Gfx_Resize(gfx, newLength); } bool dynos_gfx_delete(Gfx *gfx) { return DynOS_Gfx_Delete(gfx); } +void dynos_gfx_delete_all() { + return DynOS_Gfx_DeleteAll(); +} + Vtx *dynos_vtx_get(const char *name, u32 *outCount) { return DynOS_Vtx_Get(name, outCount); } -Vtx *dynos_vtx_new(const char *name, u32 count) { - return DynOS_Vtx_New(name, count); +Vtx *dynos_vtx_create(const char *name, u32 count) { + return DynOS_Vtx_Create(name, count); } -Vtx *dynos_vtx_realloc(Vtx *vtx, u32 newCount) { - return DynOS_Vtx_Realloc(vtx, newCount); +bool dynos_vtx_resize(Vtx *vtx, u32 newCount) { + return DynOS_Vtx_Resize(vtx, newCount); } bool dynos_vtx_delete(Vtx *vtx) { return DynOS_Vtx_Delete(vtx); } +void dynos_vtx_delete_all() { + return DynOS_Vtx_DeleteAll(); +} + // -- other -- // void dynos_mod_shutdown(void) { diff --git a/data/dynos_mgr_gfx.cpp b/data/dynos_mgr_gfx.cpp index 9ba84c5a8..a0a0cba1e 100644 --- a/data/dynos_mgr_gfx.cpp +++ b/data/dynos_mgr_gfx.cpp @@ -11,9 +11,6 @@ struct MapNode { Gfx *gfxCopy; }; -static ModData sModDisplayLists; -static ModData sModVertexBuffers; - // Maps read-only Gfx and Vtx buffers to their writable duplicates static std::map sRomToRamGfxVtxMap; @@ -29,7 +26,7 @@ static Vtx *DynOS_Vtx_Duplicate(Vtx *aVtx, u32 vtxCount, bool shouldDuplicate) { // Duplicate vertex buffer and return the copy if (shouldDuplicate) { size_t vtxSize = vtxCount * sizeof(Vtx); - Vtx *vtxDuplicate = vtx_allocate_internal(vtxCount); + Vtx *vtxDuplicate = vtx_allocate_internal(NULL, vtxCount); memcpy(vtxDuplicate, aVtx, vtxSize); sRomToRamGfxVtxMap[aVtx] = { (void *) vtxDuplicate, vtxSize, NULL }; return vtxDuplicate; @@ -56,7 +53,7 @@ static Gfx *DynOS_Gfx_Duplicate(Gfx *aGfx, bool shouldDuplicate) { Gfx *gfxDuplicate = aGfx; u32 gfxLength = shouldDuplicate ? gfx_get_length_no_sentinel(aGfx) : gfx_get_length(aGfx); if (shouldDuplicate) { - gfxDuplicate = gfx_allocate_internal(gfxLength); + gfxDuplicate = gfx_allocate_internal(NULL, gfxLength); memcpy(gfxDuplicate, aGfx, gfxLength * sizeof(Gfx)); } @@ -95,12 +92,44 @@ Gfx *DynOS_Gfx_GetWritableDisplayList(Gfx *aGfx) { return DynOS_Gfx_Duplicate(aGfx, false); } + /////////////////// + // Display lists // +/////////////////// + +#define MOD_DATA_MAX_DISPLAY_LISTS 0x400 +#define MOD_DATA_DISPLAY_LIST_MAX_LENGTH 0x800 + +static Gfx *dynos_mod_data_gfx_allocate(u32 length) { + return gfx_allocate_internal(NULL, length); +} + +static void dynos_mod_data_gfx_resize(Gfx *gfx, u32 oldLength, u32 newLength) { + if (newLength < oldLength) { + gfx_allocate_internal(gfx + newLength, 0); + } else { + gfx_allocate_internal(gfx + oldLength, newLength - oldLength); + } +} + +static void dynos_mod_data_gfx_deallocate(Gfx *gfx, UNUSED u32 length) { + free(gfx); +} + +DEFINE_MODS_DATA(sModsDisplayLists, + Gfx, + MOD_DATA_MAX_DISPLAY_LISTS, + MOD_DATA_DISPLAY_LIST_MAX_LENGTH, + dynos_mod_data_gfx_allocate, + dynos_mod_data_gfx_resize, + dynos_mod_data_gfx_deallocate +); + Gfx *DynOS_Gfx_Get(const char *aName, u32 *outLength) { if (!aName) { return NULL; } s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1); // Check mod data - Gfx *gfx = DynOS_ModData_Get(sModDisplayLists, modIndex, aName, outLength); + Gfx *gfx = sModsDisplayLists.Get(modIndex, aName, outLength); if (gfx) { return gfx; } @@ -147,33 +176,64 @@ Gfx *DynOS_Gfx_Get(const char *aName, u32 *outLength) { return NULL; } -Gfx *DynOS_Gfx_New(const char *aName, u32 aLength) { - if (!aName || !aLength) { return NULL; } +Gfx *DynOS_Gfx_Create(const char *aName, u32 aLength) { s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1); - - return DynOS_ModData_New(sModDisplayLists, modIndex, aName, aLength, gfx_allocate_internal); + return sModsDisplayLists.Create(modIndex, aName, aLength); } -Gfx *DynOS_Gfx_Realloc(Gfx *aGfx, u32 aNewLength) { - if (!aGfx || !aNewLength) { return NULL; } +bool DynOS_Gfx_Resize(Gfx *aGfx, u32 aNewLength) { s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1); - - return DynOS_ModData_Realloc(sModDisplayLists, modIndex, aGfx, aNewLength, gfx_allocate_internal, free); + return sModsDisplayLists.Resize(modIndex, aGfx, aNewLength); } bool DynOS_Gfx_Delete(Gfx *aGfx) { - if (!aGfx) { return false; } s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1); - - return DynOS_ModData_Delete(sModDisplayLists, modIndex, aGfx, free); + return sModsDisplayLists.Delete(modIndex, aGfx); } +void DynOS_Gfx_DeleteAll() { + s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1); + sModsDisplayLists.DeleteAll(modIndex); +} + + //////////////////// + // Vertex buffers // +//////////////////// + +#define MOD_DATA_MAX_VERTEX_BUFFERS 0x400 +#define MOD_DATA_VERTEX_BUFFER_MAX_COUNT 0x1000 + +static Vtx *dynos_mod_data_vtx_allocate(u32 count) { + return vtx_allocate_internal(NULL, count); +} + +static void dynos_mod_data_vtx_resize(Vtx *vtx, u32 oldCount, u32 newCount) { + if (newCount < oldCount) { + vtx_allocate_internal(vtx + newCount, 0); + } else { + vtx_allocate_internal(vtx + oldCount, newCount - oldCount); + } +} + +static void dynos_mod_data_vtx_deallocate(Vtx *vtx, UNUSED u32 count) { + free(vtx); +} + +DEFINE_MODS_DATA(sModsVertexBuffers, + Vtx, + MOD_DATA_MAX_VERTEX_BUFFERS, + MOD_DATA_VERTEX_BUFFER_MAX_COUNT, + dynos_mod_data_vtx_allocate, + dynos_mod_data_vtx_resize, + dynos_mod_data_vtx_deallocate +); + Vtx *DynOS_Vtx_Get(const char *aName, u32 *outCount) { if (!aName) { return NULL; } s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1); // Check mod data - Vtx *vtx = DynOS_ModData_Get(sModVertexBuffers, modIndex, aName, outCount); + Vtx *vtx = sModsVertexBuffers.Get(modIndex, aName, outCount); if (vtx) { return vtx; } @@ -205,32 +265,31 @@ Vtx *DynOS_Vtx_Get(const char *aName, u32 *outCount) { return NULL; } -Vtx *DynOS_Vtx_New(const char *aName, u32 aCount) { - if (!aName || !aCount) { return NULL; } +Vtx *DynOS_Vtx_Create(const char *aName, u32 aCount) { s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1); - - return DynOS_ModData_New(sModVertexBuffers, modIndex, aName, aCount, vtx_allocate_internal); + return sModsVertexBuffers.Create(modIndex, aName, aCount); } -Vtx *DynOS_Vtx_Realloc(Vtx *aVtx, u32 aNewCount) { - if (!aVtx || !aNewCount) { return NULL; } +bool DynOS_Vtx_Resize(Vtx *aVtx, u32 aNewCount) { s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1); - - return DynOS_ModData_Realloc(sModVertexBuffers, modIndex, aVtx, aNewCount, vtx_allocate_internal, free); + return sModsVertexBuffers.Resize(modIndex, aVtx, aNewCount); } bool DynOS_Vtx_Delete(Vtx *aVtx) { - if (!aVtx) { return false; } s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1); + return sModsVertexBuffers.Delete(modIndex, aVtx); +} - return DynOS_ModData_Delete(sModVertexBuffers, modIndex, aVtx, free); +void DynOS_Vtx_DeleteAll() { + s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1); + sModsVertexBuffers.DeleteAll(modIndex); } void DynOS_Gfx_ModShutdown() { // Delete all allocated display lists and vertex buffers - DynOS_ModData_DeleteAll(sModDisplayLists, free); - DynOS_ModData_DeleteAll(sModVertexBuffers, free); + sModsDisplayLists.Clear(); + sModsVertexBuffers.Clear(); // Restore vanilla display lists for (auto &it : sRomToRamGfxVtxMap) { diff --git a/data/dynos_mgr_moddata.cpp b/data/dynos_mgr_moddata.cpp new file mode 100644 index 000000000..f40dedb7e --- /dev/null +++ b/data/dynos_mgr_moddata.cpp @@ -0,0 +1,11 @@ +#include "dynos.cpp.h" + +u32 gDynosModDataLastError = 0; + +extern "C" { + +u32 dynos_mod_data_get_last_error() { + return gDynosModDataLastError; +} + +} diff --git a/data/dynos_mgr_moddata.hpp b/data/dynos_mgr_moddata.hpp index fb15cd60a..f1855671a 100644 --- a/data/dynos_mgr_moddata.hpp +++ b/data/dynos_mgr_moddata.hpp @@ -1,104 +1,284 @@ +extern u32 gDynosModDataLastError; + template -T *DynOS_ModData_Get(ModData &aModData, s32 aModIndex, const char *aName, u32 *outCount) { - if (!aName) { return NULL; } - - auto itMod = aModData.find(aModIndex); - if (itMod == aModData.end()) { - return NULL; - } - - auto itItem = itMod->second.find(aName); - if (itItem == itMod->second.end()) { - return NULL; - } - - if (outCount) { - *outCount = itItem->second.second; - } - return itItem->second.first; -} +struct ModDataItem { + T *mBuffer; + u32 mSize; + bool mAvailable; +}; template -bool DynOS_ModData_Find(ModData &aModData, s32 aModIndex, T *aPointer, std::string &outName) { - if (!aPointer) { return false; } +using ModDataPool = ModDataItem *; - auto itMod = aModData.find(aModIndex); - if (itMod == aModData.end()) { - return false; +template +using ModDataMap = std::map *>; + +template +using ModDataResult = std::pair; + + +template +class ModData : NoCopy { +public: + inline ModData(ItemAllocator *itemAllocator, ItemResize *itemResize, ItemDeallocator *itemDeallocator) : + mMapNameToItem(), mItems(), mItemAllocator(itemAllocator), mItemResize(itemResize), mItemDeallocator(itemDeallocator) { } - for (auto &modItem : itMod->second) { - if (modItem.second.first == aPointer) { - outName = modItem.first; - return true; + inline ~ModData() { + Clear(); + } + +public: + ModDataResult *> Get(const char *aName) { + if (!aName) { + return { NULL, DYNOS_MOD_DATA_ERROR_NAME_IS_NULL }; } - } - - return false; -} - -template -T *DynOS_ModData_New(ModData &aModData, s32 aModIndex, const char *aName, u32 aCount, Allocator aAllocator) { - if (!aName || !aCount) { return NULL; } - - if (DynOS_ModData_Get(aModData, aModIndex, aName, NULL)) { - return NULL; - } - - auto itMod = aModData.find(aModIndex); - if (itMod == aModData.end()) { - aModData[aModIndex] = {}; - } - - T *newItem = aAllocator(aCount); - aModData[aModIndex][aName] = { newItem, aCount }; - return newItem; -} - -template -T *DynOS_ModData_Realloc(ModData &aModData, s32 aModIndex, T *aPointer, u32 aNewCount, Allocator aAllocator, Deallocator aDeallocator) { - if (!aPointer) { return NULL; } - - std::string itemName; - if (!DynOS_ModData_Find(aModData, aModIndex, aPointer, itemName)) { - return NULL; - } - - // No need to shrink the existing buffer - auto &modItem = aModData[aModIndex][itemName]; - u32 itemCount = modItem.second; - if (aNewCount < itemCount) { - return modItem.first; - } - - T *newItem = aAllocator(aNewCount); - memcpy(newItem, aPointer, itemCount * sizeof(T)); - aDeallocator(aPointer); - aModData[aModIndex][itemName] = { newItem, aNewCount }; - return newItem; -} - -template -bool DynOS_ModData_Delete(ModData &aModData, s32 aModIndex, T *aPointer, Deallocator aDeallocator) { - if (!aPointer) { return false; } - - std::string itemName; - if (!DynOS_ModData_Find(aModData, aModIndex, aPointer, itemName)) { - return false; - } - - aDeallocator(aPointer); - aModData[aModIndex].erase(itemName); - return true; -} - -template -void DynOS_ModData_DeleteAll(ModData &aModData, Deallocator aDeallocator) { - for (auto &modItems : aModData) { - for (auto &modItem : modItems.second) { - aDeallocator(modItem.second.first); + if (!*aName) { + return { NULL, DYNOS_MOD_DATA_ERROR_NAME_IS_EMPTY }; } + + auto itItem = mMapNameToItem.find(aName); + if (itItem == mMapNameToItem.end()) { + return { NULL, DYNOS_MOD_DATA_ERROR_NAME_NOT_FOUND }; + } + + return { itItem->second, 0 }; } - aModData.clear(); -} + + ModDataResult *> Create(const char *aName, u32 aSize) { + if (!aName) { + return { NULL, DYNOS_MOD_DATA_ERROR_NAME_IS_NULL }; + } + if (!*aName) { + return { NULL, DYNOS_MOD_DATA_ERROR_NAME_IS_EMPTY }; + } + if (!aSize) { + return { NULL, DYNOS_MOD_DATA_ERROR_SIZE_IS_ZERO }; + } + if (aSize > MaxItemSize) { + return { NULL, DYNOS_MOD_DATA_ERROR_SIZE_IS_ABOVE_MAX }; + } + + auto getResult = Get(aName); + if (getResult.first) { + return { NULL, DYNOS_MOD_DATA_ERROR_ALREADY_EXISTS }; + } + + auto findAvailableResult = FindAvailableItem(); + ModDataItem *item = findAvailableResult.first; + if (!item) { + return { NULL, findAvailableResult.second ? findAvailableResult.second : DYNOS_MOD_DATA_ERROR_POOL_IS_FULL }; + } + + mItemResize(item->mBuffer, 0, aSize); + item->mSize = aSize; + item->mAvailable = false; + mMapNameToItem[aName] = item; + return { item, 0 }; + } + + ModDataResult Resize(T *aPointer, u32 aNewSize) { + if (!aPointer) { + return { false, DYNOS_MOD_DATA_ERROR_POINTER_IS_NULL }; + } + if (!aNewSize) { + return { false, DYNOS_MOD_DATA_ERROR_SIZE_IS_ZERO }; + } + if (aNewSize > MaxItemSize) { + return { false, DYNOS_MOD_DATA_ERROR_SIZE_IS_ABOVE_MAX }; + } + + std::string name; + auto findResult = Find(aPointer, name); + ModDataItem *item = findResult.first; + if (!item) { + return { false, findResult.second ? findResult.second : DYNOS_MOD_DATA_ERROR_POINTER_NOT_FOUND }; + } + + mItemResize(item->mBuffer, item->mSize, aNewSize); + item->mSize = aNewSize; + return { true, 0 }; + } + + ModDataResult Delete(T *aPointer) { + if (!aPointer) { + return { false, DYNOS_MOD_DATA_ERROR_POINTER_IS_NULL }; + } + + std::string name; + auto findResult = Find(aPointer, name); + ModDataItem *item = findResult.first; + if (!item) { + return { false, findResult.second ? findResult.second : DYNOS_MOD_DATA_ERROR_POINTER_NOT_FOUND }; + } + + // Mark the item as available, but don't free its content yet + // It will be reused by the next call to Create + // Also prevents use-after-free issues + item->mAvailable = true; + mMapNameToItem.erase(name); + return { true, 0 }; + } + + void Clear() { + if (mItems) { + for (size_t i = 0; i != MaxPoolSize; ++i) { + ModDataItem *item = mItems + i; + if (item->mBuffer) { + mItemDeallocator(item->mBuffer, item->mSize); + } + } + free(mItems); + mItems = NULL; + } + mMapNameToItem.clear(); + } + +private: + ModDataResult *> Find(T *aPointer, std::string &outName) { + if (!aPointer) { + return { NULL, DYNOS_MOD_DATA_ERROR_POINTER_IS_NULL }; + } + + for (auto &nameItem : mMapNameToItem) { + if (nameItem.second->mBuffer == aPointer) { + outName = nameItem.first; + return { nameItem.second, 0 }; + } + } + + return { NULL, 0 }; + } + + ModDataResult *> FindAvailableItem() { + + // Create pool if it doesn't exist yet + if (!mItems) { + mItems = (ModDataPool) calloc(MaxPoolSize, sizeof(ModDataItem)); + } + + for (size_t i = 0; i != MaxPoolSize; ++i) { + ModDataItem *item = mItems + i; + + // Fresh new item + if (!item->mBuffer) { + item->mBuffer = mItemAllocator(MaxItemSize); + item->mSize = 0; + item->mAvailable = true; + return { item, 0 }; + } + + // Available item + if (item->mAvailable) { + return { item, 0 }; + } + } + + return { NULL, DYNOS_MOD_DATA_ERROR_POOL_IS_FULL }; + } + +private: + ModDataMap mMapNameToItem; + ModDataPool mItems; + ItemAllocator *mItemAllocator; + ItemResize *mItemResize; + ItemDeallocator *mItemDeallocator; +}; + + +template +class ModsData : NoCopy { + typedef ModData ModDataT; + +public: + inline ModsData(ItemAllocator *itemAllocator, ItemResize *itemResize, ItemDeallocator *itemDeallocator) : + mMods(), mItemAllocator(itemAllocator), mItemResize(itemResize), mItemDeallocator(itemDeallocator) { + } + + inline ~ModsData() { + Clear(); + } + +public: + T *Get(s32 aModIndex, const char *aName, u32 *outSize) { + ModDataT *modData = GetModData(aModIndex); + auto getResult = modData->Get(aName); + if (!getResult.first) { + gDynosModDataLastError = getResult.second; + return NULL; + } + *outSize = getResult.first->mSize; + return getResult.first->mBuffer; + } + + T *Create(s32 aModIndex, const char *aName, u32 aSize) { + ModDataT *modData = GetModData(aModIndex); + auto createResult = modData->Create(aName, aSize); + if (!createResult.first) { + gDynosModDataLastError = createResult.second; + return NULL; + } + return createResult.first->mBuffer; + } + + bool Resize(s32 aModIndex, T *aPointer, u32 aNewSize) { + ModDataT *modData = GetModData(aModIndex); + auto resizeResult = modData->Resize(aPointer, aNewSize); + if (!resizeResult.first) { + gDynosModDataLastError = resizeResult.second; + return false; + } + return true; + } + + bool Delete(s32 aModIndex, T *aPointer) { + ModDataT *modData = GetModData(aModIndex); + auto deleteResult = modData->Delete(aPointer); + if (!deleteResult.first) { + gDynosModDataLastError = deleteResult.second; + return false; + } + return true; + } + + void DeleteAll(s32 aModIndex) { + ModDataT *modData = GetModData(aModIndex); + modData->Clear(); + } + + void Clear() { + for (auto &indexData : mMods) { + indexData.second->Clear(); + delete indexData.second; + } + mMods.clear(); + } + +private: + ModDataT *GetModData(s32 aModIndex) { + gDynosModDataLastError = 0; + auto itModData = mMods.find(aModIndex); + if (itModData == mMods.end()) { + ModDataT *modData = new ModDataT(mItemAllocator, mItemResize, mItemDeallocator); + mMods[aModIndex] = modData; + return modData; + } + return itModData->second; + } + +private: + std::map mMods; + ItemAllocator *mItemAllocator; + ItemResize *mItemResize; + ItemDeallocator *mItemDeallocator; +}; + +// - `_ItemAllocator_` should be a function of signature: `T *_ItemAllocator_(u32 size)` +// allocates buffer of size `_MaxItemSize_`, but does not edit its contents (internal size is 0) +// - `_ItemResize_` should be a function of signature: `void _ItemResize_(T *ptr, u32 oldSize, u32 newSize)` +// updates the contents of `ptr`, but does not allocate nor free memory +// - `_ItemDeallocator_` should be a function of signature: `void _ItemDeallocator_(T *ptr, u32 size)` +// frees buffer of size `size` +#define DEFINE_MODS_DATA(_Name_, _Type_, _MaxPoolSize_, _MaxItemSize_, _ItemAllocator_, _ItemResize_, _ItemDeallocator_) \ +static ModsData<_Type_, _MaxPoolSize_, _MaxItemSize_, typeof(_ItemAllocator_), typeof(_ItemResize_), typeof(_ItemDeallocator_)> _Name_(_ItemAllocator_, _ItemResize_, _ItemDeallocator_) diff --git a/docs/lua/examples/gfx-vtx-demo/a-math.lua b/docs/lua/examples/gfx-vtx-demo/a-math.lua index 0362c24cc..3bf8d43fb 100644 --- a/docs/lua/examples/gfx-vtx-demo/a-math.lua +++ b/docs/lua/examples/gfx-vtx-demo/a-math.lua @@ -20,10 +20,10 @@ local CUBE_ROTATIONS = { } local CUBE_POINTS = { - { x = -1, y = -1, z = -1, tu = 0, tv = (SHAPE_TEXTURE_SIZE - 1) << 5 }, - { x = 1, y = -1, z = -1, tu = 0, tv = 0 }, - { x = -1, y = 1, z = -1, tu = (SHAPE_TEXTURE_SIZE - 1) << 5, tv = (SHAPE_TEXTURE_SIZE - 1) << 5 }, - { x = 1, y = 1, z = -1, tu = (SHAPE_TEXTURE_SIZE - 1) << 5, tv = 0 }, + { x = -0.75, y = -0.75, z = -0.75, tu = 0, tv = (SHAPE_TEXTURE_SIZE - 1) << 5 }, + { x = 0.75, y = -0.75, z = -0.75, tu = 0, tv = 0 }, + { x = -0.75, y = 0.75, z = -0.75, tu = (SHAPE_TEXTURE_SIZE - 1) << 5, tv = (SHAPE_TEXTURE_SIZE - 1) << 5 }, + { x = 0.75, y = 0.75, z = -0.75, tu = (SHAPE_TEXTURE_SIZE - 1) << 5, tv = 0 }, } function get_cube_vertices() diff --git a/docs/lua/examples/gfx-vtx-demo/actors/shape/geo.inc.c b/docs/lua/examples/gfx-vtx-demo/actors/shape/geo.inc.c index 580096544..ba2d584c6 100644 --- a/docs/lua/examples/gfx-vtx-demo/actors/shape/geo.inc.c +++ b/docs/lua/examples/gfx-vtx-demo/actors/shape/geo.inc.c @@ -1,5 +1,5 @@ const GeoLayout shape_geo[] = { - GEO_NODE_START(), + GEO_SCALE(0, 0x8000), GEO_OPEN_NODE(), GEO_ASM(0, geo_update_shape), GEO_DISPLAY_LIST(LAYER_OPAQUE, shape_template_dl), diff --git a/docs/lua/examples/gfx-vtx-demo/main.lua b/docs/lua/examples/gfx-vtx-demo/main.lua index 2e4ab586c..6a993b22e 100644 --- a/docs/lua/examples/gfx-vtx-demo/main.lua +++ b/docs/lua/examples/gfx-vtx-demo/main.lua @@ -1,5 +1,5 @@ -- name: Gfx and Vtx manipulation demo --- description: Press X to move the shape in front of Mario.\nPress Y to change the shape. +-- description: Press X to spawn three different shapes orbiting around Mario. local SHAPE_TEXTURES = {} for i = 0, 10 do @@ -8,21 +8,18 @@ end SHAPES = { { - name = "Cube", get_vertices = get_cube_vertices, get_triangles = get_cube_triangles, get_geometry_mode = get_cube_geometry_mode, get_texture_scaling = get_cube_texture_scaling, }, { - name = "Octahedron", get_vertices = get_octahedron_vertices, get_triangles = get_octahedron_triangles, get_geometry_mode = get_octahedron_geometry_mode, get_texture_scaling = get_octahedron_texture_scaling, }, { - name = "Star", get_vertices = get_star_vertices, get_triangles = get_star_triangles, get_geometry_mode = get_star_geometry_mode, @@ -30,44 +27,53 @@ SHAPES = { } } + +--- @param obj Object +--- Get a unique identifier for gfx and vtx allocation. +local function get_obj_identifier(obj) + return tostring(obj._pointer) +end + +--- @param obj Object --- @param gfx Gfx --- Set the geometry mode of the current shape. -local function set_geometry_mode(gfx) - local clear, set = SHAPES[current_shape + 1].get_geometry_mode() +local function set_geometry_mode(obj, gfx) + local clear, set = SHAPES[obj.oAction].get_geometry_mode() gfx_set_command(gfx, "gsSPGeometryMode(%s, %s)", clear, set) end +--- @param obj Object --- @param gfx Gfx --- @param on integer --- Toggle on/off the texture rendering and set the texture scaling. -local function set_texture_scaling(gfx, on) - local scaling = SHAPES[current_shape + 1].get_texture_scaling() +local function set_texture_scaling(obj, gfx, on) + local scaling = SHAPES[obj.oAction].get_texture_scaling() gfx_set_command(gfx, "gsSPTexture(%i, %i, 0, G_TX_RENDERTILE, %i)", scaling, scaling, on) end ---- @param gfx Gfx --- @param obj Object +--- @param gfx Gfx --- Update the texture of the current shape. -local function update_texture(gfx, obj) +local function update_texture(obj, gfx) local texture = SHAPE_TEXTURES[obj.oAnimState].texture gfx_set_command(gfx, "gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_32b, 1, %t)", texture) end ---- @param gfx Gfx --- @param obj Object +--- @param gfx Gfx --- Compute the vertices of the current shape and fill the vertex buffer. -local function compute_vertices(gfx, obj) - local vertices = SHAPES[current_shape + 1].get_vertices() +local function compute_vertices(obj, gfx) + local vertices = SHAPES[obj.oAction].get_vertices() local num_vertices = #vertices -- Create a new or retrieve an existing vertex buffer for the shape -- Use the object pointer to form a unique identifier - local vtx_name = "shape_vertices_" .. tostring(obj._pointer) + local vtx_name = "shape_vertices_" .. get_obj_identifier(obj) local vtx = vtx_get_from_name(vtx_name) if vtx == nil then - vtx = vtx_new(vtx_name, num_vertices) + vtx = vtx_create(vtx_name, num_vertices) else - vtx = vtx_realloc(vtx, num_vertices) + vtx_resize(vtx, num_vertices) end -- Update the vertex command @@ -88,21 +94,21 @@ local function compute_vertices(gfx, obj) end end ---- @param gfx Gfx --- @param obj Object +--- @param gfx Gfx --- Build the triangles for the current shape. -local function build_triangles(gfx, obj) - local triangles = SHAPES[current_shape + 1].get_triangles() +local function build_triangles(obj, gfx) + local triangles = SHAPES[obj.oAction].get_triangles() local num_triangles = #triangles -- Create a new or retrieve an existing triangles display list for the shape -- Use the object pointer to form a unique identifier - local tris_name = "shape_triangles_" .. tostring(obj._pointer) + local tris_name = "shape_triangles_" .. get_obj_identifier(obj) local tris = gfx_get_from_name(tris_name) if tris == nil then - tris = gfx_new(tris_name, num_triangles + 1) -- +1 for the gsSPEndDisplayList command + tris = gfx_create(tris_name, num_triangles + 1) -- +1 for the gsSPEndDisplayList command else - tris = gfx_realloc(tris, num_triangles + 1) + gfx_resize(tris, num_triangles + 1) end -- Update the triangles command @@ -133,14 +139,14 @@ function geo_update_shape(node, matStackIndex) -- Create a new display list that will be attached to the display list node -- To get a different display list for each object, we can use the object pointer to form a unique identifier - local gfx_name = "shape_dl_" .. tostring(obj._pointer) + local gfx_name = "shape_dl_" .. get_obj_identifier(obj) local gfx = gfx_get_from_name(gfx_name) if gfx == nil then -- Get and copy the template to the newly created display list local gfx_template = gfx_get_from_name("shape_template_dl") local gfx_template_length = gfx_get_length(gfx_template) - gfx = gfx_new(gfx_name, gfx_template_length) + gfx = gfx_create(gfx_name, gfx_template_length) gfx_copy(gfx, gfx_template, gfx_template_length) end @@ -157,26 +163,42 @@ function geo_update_shape(node, matStackIndex) -- Change the geometry mode local cmd_geometry_mode = gfx_get_command(gfx, 0) - set_geometry_mode(cmd_geometry_mode) + set_geometry_mode(obj, cmd_geometry_mode) -- Change the texture scaling local cmd_texture_scaling_1 = gfx_get_command(gfx, 2) - set_texture_scaling(cmd_texture_scaling_1, 1) + set_texture_scaling(obj, cmd_texture_scaling_1, 1) local cmd_texture_scaling_2 = gfx_get_command(gfx, 12) - set_texture_scaling(cmd_texture_scaling_2, 0) + set_texture_scaling(obj, cmd_texture_scaling_2, 0) -- Update texture local cmd_texture = gfx_get_command(gfx, 3) - update_texture(cmd_texture, obj) + update_texture(obj, cmd_texture) -- Compute vertices local cmd_vertices = gfx_get_command(gfx, 10) - compute_vertices(cmd_vertices, obj) + compute_vertices(obj, cmd_vertices) -- Build triangles local cmd_triangles = gfx_get_command(gfx, 11) - build_triangles(cmd_triangles, obj) + build_triangles(obj, cmd_triangles) -- Update the graph node display list cast_graph_node(node.next).displayList = gfx end + +--- @param obj Object +--- Delete allocated gfx and vtx for this object. +local function on_object_unload(obj) + + local gfx = gfx_get_from_name("shape_dl_" .. get_obj_identifier(obj)) + if gfx then gfx_delete(gfx) end + + local tris = gfx_get_from_name("shape_triangles_" .. get_obj_identifier(obj)) + if tris then gfx_delete(tris) end + + local vtx = vtx_get_from_name("shape_vertices_" .. get_obj_identifier(obj)) + if vtx then vtx_delete(vtx) end +end + +hook_event(HOOK_ON_OBJECT_UNLOAD, on_object_unload) diff --git a/docs/lua/examples/gfx-vtx-demo/update.lua b/docs/lua/examples/gfx-vtx-demo/update.lua index 956e80f02..e20c32fe2 100644 --- a/docs/lua/examples/gfx-vtx-demo/update.lua +++ b/docs/lua/examples/gfx-vtx-demo/update.lua @@ -3,7 +3,7 @@ -- Don't mind this file, it's not relevant to the purpose of this demo. -- -current_shape = 0 +shape_toggle = false local E_MODEL_SHAPE = smlua_model_util_get_id("shape_geo") @@ -13,7 +13,12 @@ local function bhv_shape_init(o) end local function bhv_shape_loop(o) + local m = gMarioStates[0] + o.oPosX = m.pos.x + 160 * sins(o.oMoveAngleYaw + o.oAction * 0x5555) + o.oPosY = m.pos.y + 80 + o.oPosZ = m.pos.z + 160 * coss(o.oMoveAngleYaw + o.oAction * 0x5555) o.oFaceAngleYaw = o.oFaceAngleYaw - 0x100 + o.oMoveAngleYaw = o.oMoveAngleYaw + 0x100 if o.oTimer % 2 == 0 then o.oAnimState = (o.oAnimState + 1) % 11 end @@ -24,25 +29,28 @@ local id_bhvShape = hook_behavior(nil, OBJ_LIST_DEFAULT, true, bhv_shape_init, b local function mario_update(m) if m.playerIndex == 0 then if m.controller.buttonPressed & X_BUTTON ~= 0 then - local obj = obj_get_first_with_behavior_id(id_bhvShape) - if obj == nil then - obj = spawn_non_sync_object(id_bhvShape, E_MODEL_SHAPE, 0, 0, 0, nil) + shape_toggle = not shape_toggle + if shape_toggle then + for i = 1, 3 do + local obj = spawn_non_sync_object(id_bhvShape, E_MODEL_SHAPE, 0, 0, 0, nil) + if obj then obj.oAction = i end + end + else + local obj = obj_get_first_with_behavior_id(id_bhvShape) + while obj ~= nil do + obj_mark_for_deletion(obj) + obj = obj_get_next_with_same_behavior_id(obj) + end end - obj.oPosX = m.pos.x + 200 * sins(m.faceAngle.y) - obj.oPosY = m.pos.y + 150 - obj.oPosZ = m.pos.z + 200 * coss(m.faceAngle.y) - elseif m.controller.buttonPressed & Y_BUTTON ~= 0 then - current_shape = (current_shape + 1) % #SHAPES end end end -local function on_hud_render() - djui_hud_set_resolution(RESOLUTION_DJUI) - djui_hud_set_font(FONT_MENU) - djui_hud_set_color(0xFF, 0xFF, 0x00, 0xFF) - djui_hud_print_text(SHAPES[current_shape + 1].name, 8, djui_hud_get_screen_height() - 64, 1) +local function on_level_init() + shape_toggle = false + gfx_delete_all() + vtx_delete_all() end hook_event(HOOK_MARIO_UPDATE, mario_update) -hook_event(HOOK_ON_HUD_RENDER, on_hud_render) +hook_event(HOOK_ON_LEVEL_INIT, on_level_init) diff --git a/docs/lua/functions-6.md b/docs/lua/functions-6.md index 240ee850d..4fde0782f 100644 --- a/docs/lua/functions-6.md +++ b/docs/lua/functions-6.md @@ -661,13 +661,13 @@ Copies `length` commands from display list `src` to display list `dest`
-## [gfx_new](#gfx_new) +## [gfx_create](#gfx_create) ### Description Creates a new named display list of `length` commands ### Lua Example -`local PointerValue = gfx_new(name, length)` +`local PointerValue = gfx_create(name, length)` ### Parameters | Field | Type | @@ -679,19 +679,19 @@ Creates a new named display list of `length` commands - `Pointer` <`Gfx`> ### C Prototype -`Gfx *gfx_new(const char *name, u32 length);` +`Gfx *gfx_create(const char *name, u32 length);` [:arrow_up_small:](#)
-## [gfx_realloc](#gfx_realloc) +## [gfx_resize](#gfx_resize) ### Description -Reallocates a display list created by `gfx_new` to modify its length +Resizes a display list created by `gfx_create` ### Lua Example -`local PointerValue = gfx_realloc(gfx, newLength)` +`gfx_resize(gfx, newLength)` ### Parameters | Field | Type | @@ -700,10 +700,10 @@ Reallocates a display list created by `gfx_new` to modify its length | newLength | `integer` | ### Returns -- `Pointer` <`Gfx`> +- None ### C Prototype -`Gfx *gfx_realloc(Gfx *gfx, u32 newLength);` +`void gfx_resize(Gfx *gfx, u32 newLength);` [:arrow_up_small:](#) @@ -712,7 +712,7 @@ Reallocates a display list created by `gfx_new` to modify its length ## [gfx_delete](#gfx_delete) ### Description -Deletes a display list created by `gfx_new` +Deletes a display list created by `gfx_create` ### Lua Example `gfx_delete(gfx)` @@ -732,6 +732,27 @@ Deletes a display list created by `gfx_new`
+## [gfx_delete_all](#gfx_delete_all) + +### Description +Deletes all display lists created by `gfx_create` + +### Lua Example +`gfx_delete_all()` + +### Parameters +- None + +### Returns +- None + +### C Prototype +`void gfx_delete_all();` + +[:arrow_up_small:](#) + +
+ ## [vtx_get_count](#vtx_get_count) ### Description @@ -827,13 +848,13 @@ Copies `count` vertices from vertex buffer `src` to vertex buffer `dest`
-## [vtx_new](#vtx_new) +## [vtx_create](#vtx_create) ### Description Creates a new named vertex buffer of `count` vertices ### Lua Example -`local PointerValue = vtx_new(name, count)` +`local PointerValue = vtx_create(name, count)` ### Parameters | Field | Type | @@ -845,19 +866,19 @@ Creates a new named vertex buffer of `count` vertices - `Pointer` <`Vtx`> ### C Prototype -`Vtx *vtx_new(const char *name, u32 count);` +`Vtx *vtx_create(const char *name, u32 count);` [:arrow_up_small:](#)
-## [vtx_realloc](#vtx_realloc) +## [vtx_resize](#vtx_resize) ### Description -Reallocates a vertex buffer created by `vtx_new` to modify its count +Resizes a vertex buffer created by `vtx_create` ### Lua Example -`local PointerValue = vtx_realloc(vtx, newCount)` +`vtx_resize(vtx, newCount)` ### Parameters | Field | Type | @@ -866,10 +887,10 @@ Reallocates a vertex buffer created by `vtx_new` to modify its count | newCount | `integer` | ### Returns -- `Pointer` <`Vtx`> +- None ### C Prototype -`Vtx *vtx_realloc(Vtx *vtx, u32 newCount);` +`void vtx_resize(Vtx *vtx, u32 newCount);` [:arrow_up_small:](#) @@ -878,7 +899,7 @@ Reallocates a vertex buffer created by `vtx_new` to modify its count ## [vtx_delete](#vtx_delete) ### Description -Deletes a vertex buffer created by `vtx_new` +Deletes a vertex buffer created by `vtx_create` ### Lua Example `vtx_delete(vtx)` @@ -898,6 +919,27 @@ Deletes a vertex buffer created by `vtx_new`
+## [vtx_delete_all](#vtx_delete_all) + +### Description +Deletes all vertex buffers created by `vtx_create` + +### Lua Example +`vtx_delete_all()` + +### Parameters +- None + +### Returns +- None + +### C Prototype +`void vtx_delete_all();` + +[:arrow_up_small:](#) + +
+ --- # functions from smlua_level_utils.h diff --git a/docs/lua/functions.md b/docs/lua/functions.md index ef5742e68..0772e8aff 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -1793,16 +1793,18 @@ - [gfx_get_command](functions-6.md#gfx_get_command) - [gfx_get_next_command](functions-6.md#gfx_get_next_command) - [gfx_copy](functions-6.md#gfx_copy) - - [gfx_new](functions-6.md#gfx_new) - - [gfx_realloc](functions-6.md#gfx_realloc) + - [gfx_create](functions-6.md#gfx_create) + - [gfx_resize](functions-6.md#gfx_resize) - [gfx_delete](functions-6.md#gfx_delete) + - [gfx_delete_all](functions-6.md#gfx_delete_all) - [vtx_get_count](functions-6.md#vtx_get_count) - [vtx_get_vertex](functions-6.md#vtx_get_vertex) - [vtx_get_next_vertex](functions-6.md#vtx_get_next_vertex) - [vtx_copy](functions-6.md#vtx_copy) - - [vtx_new](functions-6.md#vtx_new) - - [vtx_realloc](functions-6.md#vtx_realloc) + - [vtx_create](functions-6.md#vtx_create) + - [vtx_resize](functions-6.md#vtx_resize) - [vtx_delete](functions-6.md#vtx_delete) + - [vtx_delete_all](functions-6.md#vtx_delete_all)
diff --git a/lang/French.ini b/lang/French.ini index 531963a93..02047248a 100644 --- a/lang/French.ini +++ b/lang/French.ini @@ -134,10 +134,10 @@ C_RIGHT = "C Droite" ANALOG_STICK_OPTIONS = "Options du stick analogique" -ROTATE_LEFT = "Rotation du bâton gauche de 90 degrés" +ROTATE_LEFT = "Rotation du stick gauche de 90 degrés" INVERT_LEFT_X = "Inverser l'axe X du stick gauche" INVERT_LEFT_Y = "Inverser l'axe Y du stick gauche" -ROTATE_RIGHT = "Rotation du bâton droit de 90 degrés" +ROTATE_RIGHT = "Rotation du stick droit de 90 degrés" INVERT_RIGHT_X = "Inverser l'axe X du stick droit" INVERT_RIGHT_Y = "Inverser l'axe Y du stick droit" diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index 8d3111d19..c6062c2c8 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -30286,41 +30286,41 @@ int smlua_func_gfx_copy(lua_State* L) { return 1; } -int smlua_func_gfx_new(lua_State* L) { +int smlua_func_gfx_create(lua_State* L) { if (L == NULL) { return 0; } int top = lua_gettop(L); if (top != 2) { - LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_new", 2, top); + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_create", 2, top); return 0; } const char* name = smlua_to_string(L, 1); - if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "gfx_new"); return 0; } + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "gfx_create"); return 0; } u32 length = smlua_to_integer(L, 2); - if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "gfx_new"); return 0; } + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "gfx_create"); return 0; } - smlua_push_object(L, LOT_GFX, gfx_new(name, length), NULL); + smlua_push_object(L, LOT_GFX, gfx_create(name, length), NULL); return 1; } -int smlua_func_gfx_realloc(lua_State* L) { +int smlua_func_gfx_resize(lua_State* L) { if (L == NULL) { return 0; } int top = lua_gettop(L); if (top != 2) { - LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_realloc", 2, top); + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_resize", 2, top); return 0; } if (lua_isnil(L, 1)) { return 0; } Gfx * gfx = (Gfx *)smlua_to_cobject(L, 1, LOT_GFX); - if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "gfx_realloc"); return 0; } + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "gfx_resize"); return 0; } u32 newLength = smlua_to_integer(L, 2); - if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "gfx_realloc"); return 0; } + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "gfx_resize"); return 0; } - smlua_push_object(L, LOT_GFX, gfx_realloc(gfx, newLength), NULL); + gfx_resize(gfx, newLength); return 1; } @@ -30343,6 +30343,21 @@ int smlua_func_gfx_delete(lua_State* L) { return 1; } +int smlua_func_gfx_delete_all(UNUSED lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 0) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_delete_all", 0, top); + return 0; + } + + + gfx_delete_all(); + + return 1; +} + int smlua_func_vtx_get_count(lua_State* L) { if (L == NULL) { return 0; } @@ -30422,41 +30437,41 @@ int smlua_func_vtx_copy(lua_State* L) { return 1; } -int smlua_func_vtx_new(lua_State* L) { +int smlua_func_vtx_create(lua_State* L) { if (L == NULL) { return 0; } int top = lua_gettop(L); if (top != 2) { - LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "vtx_new", 2, top); + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "vtx_create", 2, top); return 0; } const char* name = smlua_to_string(L, 1); - if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "vtx_new"); return 0; } + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "vtx_create"); return 0; } u32 count = smlua_to_integer(L, 2); - if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "vtx_new"); return 0; } + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "vtx_create"); return 0; } - smlua_push_object(L, LOT_VTX, vtx_new(name, count), NULL); + smlua_push_object(L, LOT_VTX, vtx_create(name, count), NULL); return 1; } -int smlua_func_vtx_realloc(lua_State* L) { +int smlua_func_vtx_resize(lua_State* L) { if (L == NULL) { return 0; } int top = lua_gettop(L); if (top != 2) { - LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "vtx_realloc", 2, top); + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "vtx_resize", 2, top); return 0; } if (lua_isnil(L, 1)) { return 0; } Vtx * vtx = (Vtx *)smlua_to_cobject(L, 1, LOT_VTX); - if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "vtx_realloc"); return 0; } + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "vtx_resize"); return 0; } u32 newCount = smlua_to_integer(L, 2); - if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "vtx_realloc"); return 0; } + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "vtx_resize"); return 0; } - smlua_push_object(L, LOT_VTX, vtx_realloc(vtx, newCount), NULL); + vtx_resize(vtx, newCount); return 1; } @@ -30479,6 +30494,21 @@ int smlua_func_vtx_delete(lua_State* L) { return 1; } +int smlua_func_vtx_delete_all(UNUSED lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 0) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "vtx_delete_all", 0, top); + return 0; + } + + + vtx_delete_all(); + + return 1; +} + ///////////////////////// // smlua_level_utils.h // ///////////////////////// @@ -35864,16 +35894,18 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "gfx_get_command", smlua_func_gfx_get_command); smlua_bind_function(L, "gfx_get_next_command", smlua_func_gfx_get_next_command); smlua_bind_function(L, "gfx_copy", smlua_func_gfx_copy); - smlua_bind_function(L, "gfx_new", smlua_func_gfx_new); - smlua_bind_function(L, "gfx_realloc", smlua_func_gfx_realloc); + smlua_bind_function(L, "gfx_create", smlua_func_gfx_create); + smlua_bind_function(L, "gfx_resize", smlua_func_gfx_resize); smlua_bind_function(L, "gfx_delete", smlua_func_gfx_delete); + smlua_bind_function(L, "gfx_delete_all", smlua_func_gfx_delete_all); smlua_bind_function(L, "vtx_get_count", smlua_func_vtx_get_count); smlua_bind_function(L, "vtx_get_vertex", smlua_func_vtx_get_vertex); smlua_bind_function(L, "vtx_get_next_vertex", smlua_func_vtx_get_next_vertex); smlua_bind_function(L, "vtx_copy", smlua_func_vtx_copy); - smlua_bind_function(L, "vtx_new", smlua_func_vtx_new); - smlua_bind_function(L, "vtx_realloc", smlua_func_vtx_realloc); + smlua_bind_function(L, "vtx_create", smlua_func_vtx_create); + smlua_bind_function(L, "vtx_resize", smlua_func_vtx_resize); smlua_bind_function(L, "vtx_delete", smlua_func_vtx_delete); + smlua_bind_function(L, "vtx_delete_all", smlua_func_vtx_delete_all); // smlua_level_utils.h smlua_bind_function(L, "smlua_level_util_change_area", smlua_func_smlua_level_util_change_area); diff --git a/src/pc/lua/utils/smlua_gfx_utils.c b/src/pc/lua/utils/smlua_gfx_utils.c index 9d5995f25..1740e0744 100644 --- a/src/pc/lua/utils/smlua_gfx_utils.c +++ b/src/pc/lua/utils/smlua_gfx_utils.c @@ -134,16 +134,22 @@ void set_skybox_color(u8 index, u8 value) { static const Gfx SENTINEL_GFX[1] = {{{ _SHIFTL(G_ENDDL, 24, 8) | _SHIFTL(UINT32_MAX, 0, 24), UINT32_MAX }}}; static const u8 SENTINEL_VTX[sizeof(Vtx)] = {[0 ... sizeof(Vtx) - 1] = UINT8_MAX}; -Gfx *gfx_allocate_internal(u32 length) { - if (!length) { return NULL; } - Gfx *gfx = calloc(length + 1, sizeof(Gfx)); +Gfx *gfx_allocate_internal(Gfx *gfx, u32 length) { + if (!gfx) { + gfx = calloc(length + 1, sizeof(Gfx)); // +1 to insert SENTINEL_GFX at the end of the buffer + } else { + memset(gfx, 0, length * sizeof(Gfx)); + } memcpy(gfx + length, SENTINEL_GFX, sizeof(Gfx)); return gfx; } -Vtx *vtx_allocate_internal(u32 count) { - if (!count) { return NULL; } - Vtx *vtx = calloc(count + 1, sizeof(Vtx)); +Vtx *vtx_allocate_internal(Vtx *vtx, u32 count) { + if (!vtx) { + vtx = calloc(count + 1, sizeof(Vtx)); // +1 to insert SENTINEL_VTX at the end of the buffer + } else { + memset(vtx, 0, count * sizeof(Vtx)); + } memcpy(vtx + count, SENTINEL_VTX, sizeof(Vtx)); return vtx; } @@ -272,45 +278,68 @@ void gfx_copy(Gfx *dest, Gfx *src, u32 length) { memcpy(dest, src, length * sizeof(Gfx)); } -Gfx *gfx_new(const char *name, u32 length) { +Gfx *gfx_create(const char *name, u32 length) { if (!name || !length) { return NULL; } // Make sure to not take the name of a level/model/vanilla display list u32 outLength; if (dynos_gfx_get(name, &outLength)) { - LOG_LUA_LINE("gfx_new: Display list `%s` already exists", name); + LOG_LUA_LINE("gfx_create: Display list `%s` already exists", name); return NULL; } - Gfx *gfx = dynos_gfx_new(name, length); + Gfx *gfx = dynos_gfx_create(name, length); if (!gfx) { - LOG_LUA_LINE("gfx_new: Display list `%s` already exists", name); + switch (dynos_mod_data_get_last_error()) { + case DYNOS_MOD_DATA_ERROR_NAME_IS_EMPTY: + LOG_LUA_LINE("gfx_create: A display list cannot have an empty name"); break; + case DYNOS_MOD_DATA_ERROR_SIZE_IS_ABOVE_MAX: + LOG_LUA_LINE("gfx_create: Cannot allocate display list of length %u, max length exceeded", length); break; + case DYNOS_MOD_DATA_ERROR_ALREADY_EXISTS: + LOG_LUA_LINE("gfx_create: Display list `%s` already exists", name); break; + case DYNOS_MOD_DATA_ERROR_POOL_IS_FULL: + LOG_LUA_LINE("gfx_create: Cannot allocate more display lists, limit reached"); break; + default: + LOG_LUA_LINE("gfx_create: Unable to allocate display list"); break; + } return NULL; } return gfx; } -Gfx *gfx_realloc(Gfx *gfx, u32 newLength) { - if (!gfx || !newLength) { return NULL; } +void gfx_resize(Gfx *gfx, u32 newLength) { + if (!gfx || !newLength) { return; } - Gfx *newGfx = dynos_gfx_realloc(gfx, newLength); - if (!newGfx) { - LOG_LUA_LINE("gfx_realloc: Display list was not allocated by `gfx_new`"); - return NULL; + if (!dynos_gfx_resize(gfx, newLength)) { + switch (dynos_mod_data_get_last_error()) { + case DYNOS_MOD_DATA_ERROR_SIZE_IS_ABOVE_MAX: + LOG_LUA_LINE("gfx_resize: Cannot resize display list to new length %u, max length exceeded", newLength); break; + case DYNOS_MOD_DATA_ERROR_POINTER_NOT_FOUND: + LOG_LUA_LINE("gfx_resize: Display list was not allocated by `gfx_create`"); break; + default: + LOG_LUA_LINE("gfx_resize: Unable to resize display list"); break; + } } - - return newGfx; } void gfx_delete(Gfx *gfx) { if (!gfx) { return; } if (!dynos_gfx_delete(gfx)) { - LOG_LUA_LINE("gfx_delete: Display list was not allocated by `gfx_new`"); + switch (dynos_mod_data_get_last_error()) { + case DYNOS_MOD_DATA_ERROR_POINTER_NOT_FOUND: + LOG_LUA_LINE("gfx_delete: Display list was not allocated by `gfx_create`"); break; + default: + LOG_LUA_LINE("gfx_delete: Unable to delete display list"); break; + } } } +void gfx_delete_all() { + dynos_gfx_delete_all(); +} + u32 vtx_get_count(Vtx *vtx) { if (!vtx) { return 0; } @@ -351,41 +380,64 @@ void vtx_copy(Vtx *dest, Vtx *src, u32 count) { memcpy(dest, src, count * sizeof(Vtx)); } -Vtx *vtx_new(const char *name, u32 count) { +Vtx *vtx_create(const char *name, u32 count) { if (!name || !count) { return NULL; } // Make sure to not take the name of a level/model/vanilla vertex buffer u32 outCount; if (dynos_vtx_get(name, &outCount)) { - LOG_LUA_LINE("vtx_new: Vertex buffer `%s` already exists", name); + LOG_LUA_LINE("vtx_create: Vertex buffer `%s` already exists", name); return NULL; } - Vtx *vtx = dynos_vtx_new(name, count); + Vtx *vtx = dynos_vtx_create(name, count); if (!vtx) { - LOG_LUA_LINE("vtx_new: Vertex buffer `%s` already exists", name); + switch (dynos_mod_data_get_last_error()) { + case DYNOS_MOD_DATA_ERROR_NAME_IS_EMPTY: + LOG_LUA_LINE("vtx_create: A vertex buffer cannot have an empty name"); break; + case DYNOS_MOD_DATA_ERROR_SIZE_IS_ABOVE_MAX: + LOG_LUA_LINE("vtx_create: Cannot allocate vertex buffer of count %u, max count exceeded", count); break; + case DYNOS_MOD_DATA_ERROR_ALREADY_EXISTS: + LOG_LUA_LINE("vtx_create: Vertex buffer `%s` already exists", name); break; + case DYNOS_MOD_DATA_ERROR_POOL_IS_FULL: + LOG_LUA_LINE("vtx_create: Cannot allocate more vertex buffers, limit reached"); break; + default: + LOG_LUA_LINE("vtx_create: Unable to allocate vertex buffer"); break; + } return NULL; } return vtx; } -Vtx *vtx_realloc(Vtx *vtx, u32 newCount) { - if (!vtx || !newCount) { return NULL; } +void vtx_resize(Vtx *vtx, u32 newCount) { + if (!vtx || !newCount) { return; } - Vtx *newVtx = dynos_vtx_realloc(vtx, newCount); - if (!newVtx) { - LOG_LUA_LINE("vtx_realloc: Vertex buffer was not allocated by `vtx_new`"); - return NULL; + if (!dynos_vtx_resize(vtx, newCount)) { + switch (dynos_mod_data_get_last_error()) { + case DYNOS_MOD_DATA_ERROR_SIZE_IS_ABOVE_MAX: + LOG_LUA_LINE("vtx_resize: Cannot resize vertex buffer to new count %u, max count exceeded", newCount); break; + case DYNOS_MOD_DATA_ERROR_POINTER_NOT_FOUND: + LOG_LUA_LINE("vtx_resize: Vertex buffer was not allocated by `vtx_create`"); break; + default: + LOG_LUA_LINE("vtx_resize: Unable to resize vertex buffer"); break; + } } - - return newVtx; } void vtx_delete(Vtx *vtx) { if (!vtx) { return; } if (!dynos_vtx_delete(vtx)) { - LOG_LUA_LINE("vtx_delete: Vertex buffer was not allocated by `vtx_new`"); + switch (dynos_mod_data_get_last_error()) { + case DYNOS_MOD_DATA_ERROR_POINTER_NOT_FOUND: + LOG_LUA_LINE("vtx_delete: Vertex buffer was not allocated by `vtx_create`"); break; + default: + LOG_LUA_LINE("vtx_delete: Unable to delete vertex buffer"); break; + } } } + +void vtx_delete_all() { + dynos_vtx_delete_all(); +} diff --git a/src/pc/lua/utils/smlua_gfx_utils.h b/src/pc/lua/utils/smlua_gfx_utils.h index b17407a7e..4369205ae 100644 --- a/src/pc/lua/utils/smlua_gfx_utils.h +++ b/src/pc/lua/utils/smlua_gfx_utils.h @@ -7,8 +7,8 @@ #define C0(cmd, pos, width) (((cmd)->words.w0 >> (pos)) & ((1U << width) - 1)) #define GFX_OP(cmd) C0(cmd, 24, 8) -Gfx *gfx_allocate_internal(u32 length); -Vtx *vtx_allocate_internal(u32 count); +Gfx *gfx_allocate_internal(Gfx *gfx, u32 length); +Vtx *vtx_allocate_internal(Vtx *vtx, u32 count); u32 gfx_get_length_no_sentinel(const Gfx *gfx); /* |description|Sets the override FOV|descriptionEnd| */ @@ -75,11 +75,13 @@ Gfx *gfx_get_next_command(Gfx *gfx); /* |description|Copies `length` commands from display list `src` to display list `dest`|descriptionEnd| */ void gfx_copy(Gfx *dest, Gfx *src, u32 length); /* |description|Creates a new named display list of `length` commands|descriptionEnd| */ -Gfx *gfx_new(const char *name, u32 length); -/* |description|Reallocates a display list created by `gfx_new` to modify its length|descriptionEnd| */ -Gfx *gfx_realloc(Gfx *gfx, u32 newLength); -/* |description|Deletes a display list created by `gfx_new`|descriptionEnd| */ +Gfx *gfx_create(const char *name, u32 length); +/* |description|Resizes a display list created by `gfx_create`|descriptionEnd| */ +void gfx_resize(Gfx *gfx, u32 newLength); +/* |description|Deletes a display list created by `gfx_create`|descriptionEnd| */ void gfx_delete(Gfx *gfx); +/* |description|Deletes all display lists created by `gfx_create`|descriptionEnd| */ +void gfx_delete_all(); /* |description|Gets the max count of vertices of a vertex buffer|descriptionEnd| */ u32 vtx_get_count(Vtx *vtx); @@ -90,10 +92,12 @@ Vtx *vtx_get_next_vertex(Vtx *vtx); /* |description|Copies `count` vertices from vertex buffer `src` to vertex buffer `dest`|descriptionEnd| */ void vtx_copy(Vtx *dest, Vtx *src, u32 count); /* |description|Creates a new named vertex buffer of `count` vertices|descriptionEnd| */ -Vtx *vtx_new(const char *name, u32 count); -/* |description|Reallocates a vertex buffer created by `vtx_new` to modify its count|descriptionEnd| */ -Vtx *vtx_realloc(Vtx *vtx, u32 newCount); -/* |description|Deletes a vertex buffer created by `vtx_new`|descriptionEnd| */ +Vtx *vtx_create(const char *name, u32 count); +/* |description|Resizes a vertex buffer created by `vtx_create`|descriptionEnd| */ +void vtx_resize(Vtx *vtx, u32 newCount); +/* |description|Deletes a vertex buffer created by `vtx_create`|descriptionEnd| */ void vtx_delete(Vtx *vtx); +/* |description|Deletes all vertex buffers created by `vtx_create`|descriptionEnd| */ +void vtx_delete_all(); #endif