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, ...)
This commit is contained in:
PeachyPeach 2025-04-24 06:03:17 +02:00 committed by GitHub
parent cd0a17055e
commit 0f351e11fb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 739 additions and 299 deletions

View File

@ -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)

View File

@ -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);

View File

@ -662,10 +662,6 @@ struct LvlCmd {
u8 mSize;
};
// modIndex -> itemName -> (itemPointer, itemSize)
template <typename T>
using ModData = std::map<s32, std::map<std::string, std::pair<T *, u32>>>;
//
// 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"
//

View File

@ -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

View File

@ -1122,7 +1122,7 @@ DataNode<Gfx>* DynOS_Gfx_Parse(GfxData* aGfxData, DataNode<Gfx>* 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<u32>();
_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>();
u32 _WordsW1 = aFile->Read<u32>();

View File

@ -35,7 +35,7 @@ DataNode<Vtx>* DynOS_Vtx_Parse(GfxData* aGfxData, DataNode<Vtx>* 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<u32>();
_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<f32>();

View File

@ -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) {

View File

@ -11,9 +11,6 @@ struct MapNode {
Gfx *gfxCopy;
};
static ModData<Gfx> sModDisplayLists;
static ModData<Vtx> sModVertexBuffers;
// Maps read-only Gfx and Vtx buffers to their writable duplicates
static std::map<const void *, struct MapNode> 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<Gfx>(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<Vtx>(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) {

View File

@ -0,0 +1,11 @@
#include "dynos.cpp.h"
u32 gDynosModDataLastError = 0;
extern "C" {
u32 dynos_mod_data_get_last_error() {
return gDynosModDataLastError;
}
}

View File

@ -1,104 +1,284 @@
extern u32 gDynosModDataLastError;
template <typename T>
T *DynOS_ModData_Get(ModData<T> &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 <typename T>
bool DynOS_ModData_Find(ModData<T> &aModData, s32 aModIndex, T *aPointer, std::string &outName) {
if (!aPointer) { return false; }
using ModDataPool = ModDataItem<T> *;
auto itMod = aModData.find(aModIndex);
if (itMod == aModData.end()) {
return false;
template <typename T>
using ModDataMap = std::map<std::string, ModDataItem<T> *>;
template <typename T>
using ModDataResult = std::pair<T, u32>;
template <typename T, size_t MaxPoolSize, u32 MaxItemSize, typename ItemAllocator, typename ItemResize, typename ItemDeallocator>
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<ModDataItem<T> *> Get(const char *aName) {
if (!aName) {
return { NULL, DYNOS_MOD_DATA_ERROR_NAME_IS_NULL };
}
}
return false;
}
template <typename T, typename Allocator>
T *DynOS_ModData_New(ModData<T> &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 <typename T, typename Allocator, typename Deallocator>
T *DynOS_ModData_Realloc(ModData<T> &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 <typename T, typename Deallocator>
bool DynOS_ModData_Delete(ModData<T> &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 <typename T, typename Deallocator>
void DynOS_ModData_DeleteAll(ModData<T> &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<ModDataItem<T> *> 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<T> *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<bool> 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<T> *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<bool> Delete(T *aPointer) {
if (!aPointer) {
return { false, DYNOS_MOD_DATA_ERROR_POINTER_IS_NULL };
}
std::string name;
auto findResult = Find(aPointer, name);
ModDataItem<T> *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<T> *item = mItems + i;
if (item->mBuffer) {
mItemDeallocator(item->mBuffer, item->mSize);
}
}
free(mItems);
mItems = NULL;
}
mMapNameToItem.clear();
}
private:
ModDataResult<ModDataItem<T> *> 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<ModDataItem<T> *> FindAvailableItem() {
// Create pool if it doesn't exist yet
if (!mItems) {
mItems = (ModDataPool<T>) calloc(MaxPoolSize, sizeof(ModDataItem<T>));
}
for (size_t i = 0; i != MaxPoolSize; ++i) {
ModDataItem<T> *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<T> mMapNameToItem;
ModDataPool<T> mItems;
ItemAllocator *mItemAllocator;
ItemResize *mItemResize;
ItemDeallocator *mItemDeallocator;
};
template <typename T, size_t MaxPoolSize, u32 MaxItemSize, typename ItemAllocator, typename ItemResize, typename ItemDeallocator>
class ModsData : NoCopy {
typedef ModData<T, MaxPoolSize, MaxItemSize, ItemAllocator, ItemResize, ItemDeallocator> 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<s32, ModDataT *> 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_)

View File

@ -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()

View File

@ -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),

View File

@ -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)

View File

@ -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)

View File

@ -661,13 +661,13 @@ Copies `length` commands from display list `src` to display list `dest`
<br />
## [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:](#)
<br />
## [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`
<br />
## [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:](#)
<br />
## [vtx_get_count](#vtx_get_count)
### Description
@ -827,13 +848,13 @@ Copies `count` vertices from vertex buffer `src` to vertex buffer `dest`
<br />
## [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:](#)
<br />
## [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`
<br />
## [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:](#)
<br />
---
# functions from smlua_level_utils.h

View File

@ -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)
<br />

View File

@ -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"

View File

@ -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);

View File

@ -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();
}

View File

@ -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