Gfx set command: v2 + Gfx/Vtx dynamic alloc (#718)
Some checks failed
Build coop / build-ubuntu (push) Has been cancelled
Build coop / build-windows (push) Has been cancelled
Build coop / build-macos-arm (push) Has been cancelled
Build coop / build-macos-intel (push) Has been cancelled

* set_gfx_command part 2

* part 3

* get gfx/vtx from name; copy gfx/vtx

* gfx/vtx dynamic allocation lua

* gfx/vtx_new: don't take level/model/vanilla names

* Clean up gbi constants

* update example

* Isaac review; add gfx_get_next_command and vtx_get_next_vertex

* make all commands length 1; missing NULL checks
This commit is contained in:
PeachyPeach 2025-04-13 00:19:14 +02:00 committed by GitHub
parent 26d64ee79d
commit 467b22e939
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 2629 additions and 2147 deletions

View file

@ -57,15 +57,49 @@ exclude_constants = {
"src/game/obj_behaviors.c": [ "^o$" ],
"src/pc/djui/djui_console.h": [ "CONSOLE_MAX_TMP_BUFFER" ],
"src/pc/lua/smlua_hooks.h": [ "MAX_HOOKED_MOD_MENU_ELEMENTS" ],
"src/pc/djui/djui_panel_menu.h": [ "RAINBOW_TEXT_LEN" ],
"include/PR/gbi.h": ["RM_AA_", "G_RM_", "G_CC_"]
"src/pc/djui/djui_panel_menu.h": [ "RAINBOW_TEXT_LEN" ]
}
include_constants = {
"include/geo_commands.h": [ "BACKGROUND" ],
"include/level_commands.h": [ "WARP_CHECKPOINT", "WARP_NO_CHECKPOINT" ],
"src/audio/external.h": [ "SEQ_PLAYER", "DS_" ],
"src/pc/mods/mod_storage.h": [ "MAX_KEYS", "MAX_KEY_VALUE_LENGTH" ]
"src/pc/mods/mod_storage.h": [ "MAX_KEYS", "MAX_KEY_VALUE_LENGTH" ],
"include/PR/gbi.h": [
"^G_NOOP$",
"^G_SETOTHERMODE_H$",
"^G_SETOTHERMODE_L$",
"^G_ENDDL$",
"^G_DL$",
"^G_MOVEMEM$",
"^G_MOVEWORD$",
"^G_MTX$",
"^G_GEOMETRYMODE$",
"^G_POPMTX$",
"^G_TEXTURE$",
"^G_COPYMEM$",
"^G_VTX$",
"^G_TRI1$",
"^G_TRI2$",
"^G_SETCIMG$",
"^G_SETZIMG$",
"^G_SETTIMG$",
"^G_SETCOMBINE$",
"^G_SETENVCOLOR$",
"^G_SETPRIMCOLOR$",
"^G_SETBLENDCOLOR$",
"^G_SETFOGCOLOR$",
"^G_SETFILLCOLOR$",
"^G_FILLRECT$",
"^G_SETTILE$",
"^G_LOADTILE$",
"^G_LOADBLOCK$",
"^G_SETTILESIZE$",
"^G_LOADTLUT$",
"^G_SETSCISSOR$",
"^G_TEXRECTFLIP$",
"^G_TEXRECT$",
]
}
pretend_find = [
@ -80,6 +114,13 @@ overrideConstant = {
'VERSION_REGION': '"US"',
}
forced_defines = ['F3DEX_GBI_2']
defined_values = {
'VERSION_US': True,
'VERSION_EU': False,
'VERSION_JP': False,
'VERSION_SH': False,
'F3DEX_GBI_2': True,
}
############################################################################
@ -384,7 +425,7 @@ def doc_files(processed_files):
############################################################################
def def_constant(processed_constant):
def def_constant(processed_constant, skip_constant):
global totalConstants
constants = processed_constant
s = ''
@ -393,7 +434,7 @@ def def_constant(processed_constant):
if is_enum:
constants = processed_constant['constants']
if len(constants) == 0:
return ''
return '', skip_constant
id = translate_to_def(processed_constant['identifier'])
klen = 0
vlen = 0
@ -407,10 +448,18 @@ def def_constant(processed_constant):
s += '\n--- @alias %s\n' % id
for c in constants:
s += '--- | `%s`\n' % c[0]
return s
return s, skip_constant
for c in [processed_constant]:
if c[0].startswith('#'):
if c[0].startswith('#ifdef'):
skip_constant = not defined_values[c[0].split()[1]]
elif c[0].startswith('#else'):
skip_constant = not skip_constant
elif c[0].startswith('#endif'):
skip_constant = False
continue
if skip_constant:
continue
if '"' in c[1]:
s += '\n--- @type string\n'
@ -419,7 +468,7 @@ def def_constant(processed_constant):
s += '%s = %s\n' % (c[0], c[1])
totalConstants += 1
return s
return s, skip_constant
def build_to_def(processed_files):
s = '-- AUTOGENERATED FOR CODE EDITORS --\n\n'
@ -429,8 +478,10 @@ def build_to_def(processed_files):
for file in processed_files:
constants = file['constants']
skip_constant = False
for c in constants:
s += def_constant(c)
cs, skip_constant = def_constant(c, skip_constant)
s += cs
return s

View file

@ -125,6 +125,7 @@ override_disallowed_functions = {
"src/pc/lua/utils/smlua_level_utils.h": [ "smlua_level_util_reset" ],
"src/pc/lua/utils/smlua_text_utils.h": [ "smlua_text_utils_init", "smlua_text_utils_shutdown" ],
"src/pc/lua/utils/smlua_anim_utils.h": [ "smlua_anim_util_reset", "smlua_anim_util_register_animation" ],
"src/pc/lua/utils/smlua_gfx_utils.h": [ "gfx_allocate_internal", "vtx_allocate_internal", "gfx_get_length_no_sentinel" ],
"src/pc/network/lag_compensation.h": [ "lag_compensation_clear" ],
"src/game/first_person_cam.h": [ "first_person_update" ],
"src/pc/lua/utils/smlua_collision_utils.h": [ "collision_find_surface_on_ray" ],
@ -758,11 +759,30 @@ N/A
## [gfx_set_command](#gfx_set_command)
Sets the specified display list command on the display list given.
Sets a display list command on the display list given.
### Lua Example
If `command` includes parameter specifiers (subsequences beginning with `%`), the additional arguments following `command` are converted and inserted in `command` replacing their respective specifiers.
The number of provided parameters must be equal to the number of specifiers in `command`, and the order of parameters must be the same as the specifiers.
The following specifiers are allowed:
- `%i` for an `integer` parameter
- `%s` for a `string` parameter
- `%v` for a `Vtx` parameter
- `%t` for a `Texture` parameter
- `%g` for a `Gfx` parameter
### Lua Examples
Plain string:
```lua
gfx_set_command(gfx, "gsDPSetEnvColor", 0x00, 0xFF, 0x00, 0xFF)
gfx_set_command(gfx, "gsDPSetEnvColor(0x00, 0xFF, 0x00, 0xFF)")
```
With parameter specifiers:
```lua
r, g, b, a = 0x00, 0xFF, 0x00, 0xFF
gfx_set_command(gfx, "gsDPSetEnvColor(%i, %i, %i, %i)", r, g, b, a)
```
### Parameters
@ -770,7 +790,7 @@ gfx_set_command(gfx, "gsDPSetEnvColor", 0x00, 0xFF, 0x00, 0xFF)
| ----- | ---- |
| gfx | [Gfx](structs.md#Gfx) |
| command | `string` |
| (Any number of arguments) | `integer` |
| parameters... | any of `integer`, `string`, `Gfx`, `Texture`, `Vtx` |
### Returns
- None

View file

@ -165,7 +165,7 @@ sLuaManuallyDefinedStructs = [{
override_types = {
"Gwords": "Gfx",
"Vtx_t": "Vtx"
"Vtx_L": "Vtx"
}
reversed_override_types = {v: k for k, v in override_types.items()}
@ -275,6 +275,7 @@ def table_to_string(table):
def parse_struct(struct_str, sortFields = True):
struct = {}
struct_str = strip_anonymous_blocks(struct_str) # Allow unions and sub-structs to be accessed
match = re.match(r"struct\s*(\w+)?\s*{(.*?)}\s*(\w+)?\s*", struct_str.replace("typedef ", ""), re.DOTALL)
struct_name, body, trailing_name = match.groups()
identifier = struct_name if struct_name else trailing_name

File diff suppressed because it is too large Load diff

View file

@ -9698,50 +9698,135 @@ function gfx_parse(cmd, func)
-- ...
end
--- @param gfx Pointer_Gfx
--- @param offset integer
--- @param cmd Pointer_Gfx
--- @return integer
--- Gets the op of the display list command
function gfx_get_op(cmd)
-- ...
end
--- @param cmd Pointer_Gfx
--- @return Pointer_Gfx
--- Gets the display list from a display list command if it has the op `G_DL`
function gfx_get_display_list(cmd)
-- ...
end
--- @param cmd Pointer_Gfx
--- @return Pointer_Vtx
--- Gets a vertex from a display list command if it has the correct op. Intended to be used with `gfx_parse`
function gfx_get_vtx(gfx, offset)
--- Gets the vertex buffer from a display list command if it has the op `G_VTX`
function gfx_get_vertex_buffer(cmd)
-- ...
end
--- @param cmd Pointer_Gfx
--- @return integer
--- Gets the number of vertices from a display list command if it has the correct op
function gfx_get_vtx_count(cmd)
--- Gets the number of vertices from a display list command if it has the op `G_VTX`
function gfx_get_vertex_count(cmd)
-- ...
end
--- @param gfx Pointer_Gfx
--- @param a0 integer
--- @param b0 integer
--- @param c0 integer
--- @param d0 integer
--- @param Aa0 integer
--- @param Ab0 integer
--- @param Ac0 integer
--- @param Ad0 integer
--- @param a1 integer
--- @param b1 integer
--- @param c1 integer
--- @param d1 integer
--- @param Aa1 integer
--- @param Ab1 integer
--- @param Ac1 integer
--- @param Ad1 integer
--- Sets the display list combine mode. you can fill this function with G_CCMUX_* and G_ACMUX_* constants
function gfx_set_combine_lerp(gfx, a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1)
--- @return integer
--- Gets the max length of a display list
function gfx_get_length(gfx)
-- ...
end
--- @param gfx Pointer_Gfx
--- @param format integer
--- @param size integer
--- @param width integer
--- @param texture Pointer_integer
--- Sets the display list texture image. Pass in textureInfo.texture as `texture`
function gfx_set_texture_image(gfx, format, size, width, texture)
--- @param offset integer
--- @return Pointer_Gfx
--- Gets a command of a display list at position `offset`
function gfx_get_command(gfx, offset)
-- ...
end
--- @param gfx Pointer_Gfx
--- @return Pointer_Gfx
--- Gets the next command of a given display list pointer. Intended to use in a for loop
function gfx_get_next_command(gfx)
-- ...
end
--- @param dest Pointer_Gfx
--- @param src Pointer_Gfx
--- @param length integer
--- Copies `length` commands from display list `src` to display list `dest`
function gfx_copy(dest, src, length)
-- ...
end
--- @param name string
--- @param length integer
--- @return Pointer_Gfx
--- Creates a new named display list of `length` commands
function gfx_new(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)
-- ...
end
--- @param gfx Pointer_Gfx
--- Deletes a display list created by `gfx_new`
function gfx_delete(gfx)
-- ...
end
--- @param vtx Pointer_Vtx
--- @return integer
--- Gets the max count of vertices of a vertex buffer
function vtx_get_count(vtx)
-- ...
end
--- @param vtx Pointer_Vtx
--- @param offset integer
--- @return Pointer_Vtx
--- Gets a vertex of a vertex buffer at position `offset`
function vtx_get_vertex(vtx, offset)
-- ...
end
--- @param vtx Pointer_Vtx
--- @return Pointer_Vtx
--- Gets the next vertex of a given vertex pointer. Intended to use in a for loop
function vtx_get_next_vertex(vtx)
-- ...
end
--- @param dest Pointer_Vtx
--- @param src Pointer_Vtx
--- @param count integer
--- Copies `count` vertices from vertex buffer `src` to vertex buffer `dest`
function vtx_copy(dest, src, count)
-- ...
end
--- @param name string
--- @param count integer
--- @return Pointer_Vtx
--- Creates a new named vertex buffer of `count` vertices
function vtx_new(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)
-- ...
end
--- @param vtx Pointer_Vtx
--- Deletes a vertex buffer created by `vtx_new`
function vtx_delete(vtx)
-- ...
end

View file

@ -451,8 +451,39 @@ end
--- @param gfx Gfx
--- @param command string
--- @vararg integer Parameters for the command
--- Sets the specified display list command on the display list given
--- @vararg integer | string | Gfx | Texture | Vtx Parameters for the command
--- Sets a display list command on the display list given.
---
--- If `command` includes parameter specifiers (subsequences beginning with `%`), the additional arguments
--- following `command` are converted and inserted in `command` replacing their respective specifiers.
---
--- The number of provided parameters must be equal to the number of specifiers in `command`,
--- and the order of parameters must be the same as the specifiers.
---
--- The following specifiers are allowed:
--- - `%i` for an `integer` parameter
--- - `%s` for a `string` parameter
--- - `%v` for a `Vtx` parameter
--- - `%t` for a `Texture` parameter
--- - `%g` for a `Gfx` parameter
function gfx_set_command(gfx, command, ...)
-- ...
end
--- @param name string
--- @return Pointer_Gfx
--- @return integer
--- Gets a display list of the current mod from its name.
--- Returns a pointer to the display list and its length
function gfx_get_from_name(name)
-- ...
end
--- @param name string
--- @return Pointer_Vtx
--- @return integer
--- Gets a vertex buffer of the current mod from its name.
--- Returns a pointer to the vertex buffering and its vertex count
function vtx_get_from_name(name)
-- ...
end

View file

@ -2333,10 +2333,19 @@
--- @field public posYaw integer
--- @class Vtx
--- @field public cn integer[]
--- @field public a integer
--- @field public b integer
--- @field public flag integer
--- @field public ob number[]
--- @field public tc integer[]
--- @field public g integer
--- @field public nx integer
--- @field public ny integer
--- @field public nz integer
--- @field public r integer
--- @field public tu integer
--- @field public tv integer
--- @field public x number
--- @field public y number
--- @field public z number
--- @class Vtx_Interp
--- @field public n string

View file

@ -6,6 +6,7 @@
#include "types.h"
#include "engine/behavior_script.h"
#include "game/moving_texture.h"
#include "lua.h"
void *dynos_swap_cmd(void *cmd);
@ -79,16 +80,29 @@ struct GraphNode* dynos_model_load_dl(u32* aId, enum ModelPool aModelPool, u8 aL
struct GraphNode* dynos_model_store_geo(u32* aId, enum ModelPool aModelPool, void* aAsset, struct GraphNode* aGraphNode);
struct GraphNode* dynos_model_get_geo(u32 aId);
void dynos_model_overwrite_slot(u32 srcSlot, u32 dstSlot);
Gfx *dynos_model_get_writable_display_list(Gfx* gfx);
void dynos_model_restore_vanilla_display_lists();
u32 dynos_model_get_id_from_asset(void* aAsset);
u32 dynos_model_get_id_from_graph_node(struct GraphNode* aGraphNode);
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);
bool dynos_gfx_delete(Gfx *gfx);
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);
bool dynos_vtx_delete(Vtx *vtx);
// -- other -- //
void dynos_mod_shutdown(void);
void dynos_pending_scroll_targets_clear(void);
void dynos_add_scroll_target(u32 index, const char *name, u32 offset, u32 size);
// -- smlua -- //
bool dynos_smlua_parse_gfx_command(lua_State *L, Gfx *gfx, const char *command, bool hasSpecifiers, char *errorMsg, u32 errorSize);
void dynos_smlua_clear_gfx_command_cache();
#endif
#endif

View file

@ -556,6 +556,7 @@ struct GfxData : NoCopy {
DataNodes<Movtex> mMovtexs;
DataNodes<MovtexQC> mMovtexQCs;
DataNodes<u8> mRooms;
DataNodes<void> mRawPointers;
// Animation data
Array<AnimBuffer<s16> *> mAnimValues;
@ -661,6 +662,10 @@ 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
//
@ -886,6 +891,7 @@ void DynOS_Pack_AddTex(PackData* aPackData, DataNode<TexData>* aTexData);
// Actor Manager
//
std::map<const void *, ActorGfx> &DynOS_Actor_GetValidActors();
void DynOS_Actor_AddCustom(s32 aModIndex, const SysPath &aFilename, const char *aActorName);
const void *DynOS_Actor_GetLayoutFromName(const char *aActorName);
bool DynOS_Actor_GetModIndexAndToken(const GraphNode *aGraphNode, u32 aTokenIndex, s32 *outModIndex, const char **outToken);
@ -974,10 +980,30 @@ struct GraphNode* DynOS_Model_GetGeo(u32 aId);
u32 DynOS_Model_GetIdFromAsset(void* asset);
u32 DynOS_Model_GetIdFromGraphNode(struct GraphNode* aNode);
void DynOS_Model_OverwriteSlot(u32 srcSlot, u32 dstSlot);
Gfx *DynOS_Model_GetWritableDisplayList(Gfx* aGfx);
void DynOS_Model_RestoreVanillaDisplayLists();
void DynOS_Model_ClearPool(enum ModelPool aModelPool);
//
// Gfx Manager
//
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);
bool DynOS_Gfx_Delete(Gfx *aGfx);
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);
bool DynOS_Vtx_Delete(Vtx *aVtx);
void DynOS_Gfx_ModShutdown();
//
// Mod Data Manager
//
// template functions
#include "dynos_mgr_moddata.hpp"
//
// Bin
//

View file

@ -17,6 +17,7 @@
#include <new>
#include <utility>
#include <string>
#include <map>
extern "C" {
#endif
#include "config.h"

View file

@ -1,8 +1,31 @@
#include "dynos.cpp.h"
#include <map>
extern "C" {
#include <assert.h>
#include "sm64.h"
#include "include/textures.h"
#include "src/pc/lua/smlua.h"
#include "src/pc/lua/utils/smlua_gfx_utils.h"
}
static std::map<std::string, std::pair<Gfx *, u32>> sGfxCommandCache;
static char *sGfxCommandErrorMsg = NULL;
static u32 sGfxCommandErrorSize = 0;
#define PrintDataErrorGfx(...) { \
if (sGfxCommandErrorMsg) { \
snprintf(sGfxCommandErrorMsg, sGfxCommandErrorSize, __VA_ARGS__); \
aGfxData->mErrorCount++; \
} else { \
PrintDataError(__VA_ARGS__); \
} \
}
#define CHECK_TOKEN_INDEX(tokenIndex, returnValue) { \
if (tokenIndex >= aNode->mTokens.Count()) { \
PrintDataErrorGfx(" ERROR: Invalid token index: %llu, tokens count is: %d", tokenIndex, aNode->mTokens.Count()); \
return returnValue; \
} \
}
#pragma GCC diagnostic push
@ -403,6 +426,7 @@ s64 DynOS_Gfx_ParseGfxConstants(const String& _Arg, bool* found) {
static s64 ParseGfxSymbolArg(GfxData* aGfxData, DataNode<Gfx>* aNode, u64* pTokenIndex, const char *aPrefix) {
assert(aPrefix != NULL);
if (pTokenIndex != NULL) { CHECK_TOKEN_INDEX(*pTokenIndex, 0); }
String _Token = (pTokenIndex != NULL ? aNode->mTokens[(*pTokenIndex)++] : "");
String _Arg("%s%s", aPrefix, _Token.begin());
@ -419,6 +443,13 @@ static s64 ParseGfxSymbolArg(GfxData* aGfxData, DataNode<Gfx>* aNode, u64* pToke
return constantValue;
}
// Pointers
for (auto& _Node : aGfxData->mRawPointers) {
if (_Arg == _Node->mName) {
return (s64) _Node->mData;
}
}
// Offset
s32 _Offset = 0;
s32 _Plus = _Arg.Find('+');
@ -534,11 +565,11 @@ static s64 ParseGfxSymbolArg(GfxData* aGfxData, DataNode<Gfx>* aNode, u64* pToke
bool rdSuccess = false;
s64 rdValue = DynOS_RecursiveDescent_Parse(_Arg.begin(), &rdSuccess, DynOS_Gfx_ParseGfxConstants);
if (rdSuccess) {
return (LevelScript)rdValue;
return rdValue;
}
// Unknown
PrintDataError(" ERROR: Unknown gfx arg: %s", _Arg.begin());
PrintDataErrorGfx(" ERROR: Unknown gfx arg: %s", _Arg.begin());
return 0;
}
@ -653,10 +684,11 @@ static s64 ParseGfxSymbolArg(GfxData* aGfxData, DataNode<Gfx>* aNode, u64* pToke
return; \
}
#define gfx_arg_with_suffix(argname, suffix) \
#define gfx_arg_with_suffix(argname, suffix) \
CHECK_TOKEN_INDEX(aTokenIndex,); \
const String& argname##_token = aNode->mTokens[aTokenIndex]; \
String _Token##suffix = String("%s%s", argname##_token.begin(), #suffix); \
s64 argname = ParseGfxSymbolArg(aGfxData, aNode, NULL, _Token##suffix.begin()); \
String _Token##suffix = String("%s%s", argname##_token.begin(), #suffix); \
s64 argname = ParseGfxSymbolArg(aGfxData, aNode, NULL, _Token##suffix.begin()); \
#define STR_VALUE_2(...) #__VA_ARGS__
#define STR_VALUE(...) STR_VALUE_2(__VA_ARGS__)
@ -731,11 +763,12 @@ static String ConvertSetCombineModeArgToString(GfxData *aGfxData, const String&
gfx_set_combine_mode_arg(G_CC_HILITERGBA2);
gfx_set_combine_mode_arg(G_CC_HILITERGBDECALA2);
gfx_set_combine_mode_arg(G_CC_HILITERGBPASSA2);
PrintDataError(" ERROR: Unknown gfx gsDPSetCombineMode arg: %s", _Arg.begin());
PrintDataErrorGfx(" ERROR: Unknown gfx gsDPSetCombineMode arg: %s", _Arg.begin());
return "";
}
static Array<s64> ParseGfxSetCombineMode(GfxData* aGfxData, DataNode<Gfx>* aNode, u64* pTokenIndex) {
CHECK_TOKEN_INDEX(*pTokenIndex, Array<s64>());
String _Buffer = ConvertSetCombineModeArgToString(aGfxData, aNode->mTokens[(*pTokenIndex)++]);
Array<s64> _Args;
String _Token;
@ -751,7 +784,7 @@ static Array<s64> ParseGfxSetCombineMode(GfxData* aGfxData, DataNode<Gfx>* aNode
}
}
if (_Args.Count() < 8) {
PrintDataError(" ERROR: gsDPSetCombineMode %s: Not enough arguments", _Buffer.begin());
PrintDataErrorGfx(" ERROR: gsDPSetCombineMode %s: Not enough arguments", _Buffer.begin());
}
return _Args;
}
@ -763,6 +796,13 @@ static void UpdateTextureInfo(GfxData* aGfxData, s64 *aTexPtr, s32 aFormat, s32
return;
}
// Skip raw pointers
for (const auto &ptrNode : aGfxData->mRawPointers) {
if ((void *) *aTexPtr == ptrNode->mData) {
return;
}
}
aGfxData->mGfxContext.mCurrentTexture = (DataNode<TexData>*) (*aTexPtr);
}
@ -787,6 +827,7 @@ extern "C" {
#define define_gfx_symbol(symb, params, ...) gfx_symbol_##params(symb, ##__VA_ARGS__)
static void ParseGfxSymbol(GfxData* aGfxData, DataNode<Gfx>* aNode, Gfx*& aHead, u64& aTokenIndex) {
CHECK_TOKEN_INDEX(aTokenIndex,);
const String& _Symbol = aNode->mTokens[aTokenIndex++];
// Simple symbols
@ -1073,20 +1114,22 @@ static void ParseGfxSymbol(GfxData* aGfxData, DataNode<Gfx>* aNode, Gfx*& aHead,
}
// Unknown
PrintDataError(" ERROR: Unknown gfx symbol: %s", _Symbol.begin());
PrintDataErrorGfx(" ERROR: Unknown gfx symbol: %s", _Symbol.begin());
}
DataNode<Gfx>* DynOS_Gfx_Parse(GfxData* aGfxData, DataNode<Gfx>* aNode) {
if (aNode->mData) return aNode;
// Display list data
aNode->mData = New<Gfx>(aNode->mTokens.Count() * DISPLAY_LIST_SIZE_PER_TOKEN);
u32 _Length = aNode->mTokens.Count() * DISPLAY_LIST_SIZE_PER_TOKEN;
aNode->mData = gfx_allocate_internal(_Length);
Gfx* _Head = aNode->mData;
for (u64 _TokenIndex = 0; _TokenIndex < aNode->mTokens.Count();) { // Don't increment _TokenIndex here!
ParseGfxSymbol(aGfxData, aNode, _Head, _TokenIndex);
}
aNode->mSize = (u32) (_Head - aNode->mData);
aNode->mLoadIndex = aGfxData->mLoadIndex++;
memmove(aNode->mData + aNode->mSize, aNode->mData + _Length, sizeof(Gfx)); // Move the sentinel to the true end of the display list
return aNode;
}
@ -1128,7 +1171,7 @@ void DynOS_Gfx_Load(BinFile *aFile, GfxData *aGfxData) {
// Data
_Node->mSize = aFile->Read<u32>();
_Node->mData = New<Gfx>(_Node->mSize);
_Node->mData = gfx_allocate_internal(_Node->mSize);
for (u32 i = 0; i != _Node->mSize; ++i) {
u32 _WordsW0 = aFile->Read<u32>();
u32 _WordsW1 = aFile->Read<u32>();
@ -1144,4 +1187,254 @@ void DynOS_Gfx_Load(BinFile *aFile, GfxData *aGfxData) {
// Append
aGfxData->mDisplayLists.Add(_Node);
}
/////////
// Lua //
/////////
//
// Parameter specifiers for gfx_set_command:
//
// %i -> integer
// %s -> string
// %v -> Vtx pointer
// %t -> Texture pointer
// %g -> Gfx pointer
//
static String CreateRawPointerDataNode(GfxData *aGfxData, void *pointer) {
String ptrNodeName = String("PTR_%016llX", (u64) pointer);
DataNode<void> *ptrNode = New<DataNode<void>>();
ptrNode->mName = ptrNodeName;
ptrNode->mData = pointer;
aGfxData->mRawPointers.Add(ptrNode);
return ptrNodeName;
}
template <typename T, typename SmluaToFunc, typename ReturnFunc>
static String ConvertParam(lua_State *L, GfxData *aGfxData, u32 paramIndex, const char *typeName, const SmluaToFunc &smluaToFunc, const ReturnFunc &returnFunc) {
T value = smluaToFunc(L, paramIndex);
if (!gSmLuaConvertSuccess) {
PrintDataErrorGfx(" ERROR: Failed to convert parameter %u to %s", paramIndex, typeName);
return "";
}
return returnFunc(value);
}
static String ResolveParam(lua_State *L, GfxData *aGfxData, u32 paramIndex, char paramType) {
switch (paramType) {
// Integer
case 'i': return ConvertParam<s64>(
L, aGfxData, paramIndex,
"integer",
[] (lua_State *L, u32 paramIndex) { return smlua_to_integer(L, paramIndex); },
[] (s64 integer) { return String("%lld", integer); }
);
// String
case 's': return ConvertParam<const char *>(
L, aGfxData, paramIndex,
"string",
[] (lua_State *L, u32 paramIndex) { return smlua_to_string(L, paramIndex); },
[] (const char *string) { return String(string); }
);
// Vtx pointer
case 'v': return ConvertParam<Vtx *>(
L, aGfxData, paramIndex,
"Vtx pointer",
[] (lua_State *L, u32 paramIndex) { return (Vtx *) smlua_to_cobject(L, paramIndex, LOT_VTX); },
[&aGfxData] (Vtx *vtx) { return CreateRawPointerDataNode(aGfxData, vtx); }
);
// Texture pointer
case 't': return ConvertParam<Texture *>(
L, aGfxData, paramIndex,
"Texture pointer",
[] (lua_State *L, u32 paramIndex) { return (Texture *) smlua_to_cpointer(L, paramIndex, LVT_U8_P); },
[&aGfxData] (Texture *texture) { return CreateRawPointerDataNode(aGfxData, texture); }
);
// Gfx pointer
case 'g': return ConvertParam<Gfx *>(
L, aGfxData, paramIndex,
"Gfx pointer",
[] (lua_State *L, u32 paramIndex) { return (Gfx *) smlua_to_cobject(L, paramIndex, LOT_GFX); },
[&aGfxData] (Gfx *gfx) { return CreateRawPointerDataNode(aGfxData, gfx); }
);
}
PrintDataErrorGfx(" ERROR: Unknown parameter type: '%c'", paramType);
return "";
}
static std::string ResolveGfxCommand(lua_State *L, GfxData *aGfxData, const char *command) {
std::string output;
for (u32 paramIndex = 3; *command; command++) {
char c = *command;
if (c == '%') {
char paramType = *(++command);
String value = ResolveParam(L, aGfxData, paramIndex++, paramType);
if (aGfxData->mErrorCount > 0) {
return "";
}
output.append(value.begin());
} else {
output += c;
}
}
return output;
}
static Array<String> TokenizeGfxCommand(const std::string &command) {
Array<String> tokens;
String token;
for (u32 i = 0, scope = 0; i < command.length(); ++i) {
char c = command[i];
// Remove whitespaces
if (c <= ' ') {
continue;
}
if (c == '(') {
// End of the command name, beginning of the arguments
if (scope == 0) {
if (!token.Empty()) {
tokens.Add(token);
token.Clear();
}
}
// That's an argument
else {
token.Add(c);
}
scope++;
}
else if (c == ')') {
scope--;
// End of the command
if (scope == 0) {
break;
}
// That's an argument
else {
token.Add(c);
}
}
// End of an argument
else if (c == ',') {
if (!token.Empty()) {
tokens.Add(token);
token.Clear();
}
}
else {
token.Add(c);
}
}
if (!token.Empty()) {
tokens.Add(token);
}
return tokens;
}
static bool CheckGfxLength(GfxData *aGfxData, Gfx *gfx, u32 lengthToWrite) {
if (lengthToWrite > 1) {
u32 gfxLength = gfx_get_length(gfx);
if (gfxLength < lengthToWrite) {
PrintDataErrorGfx(" ERROR: Cannot write %u commands to display list of length: %u", lengthToWrite, gfxLength);
return false;
}
}
return true;
}
static bool ParseGfxCommand(lua_State *L, GfxData *aGfxData, Gfx *gfx, const char *command, bool hasSpecifiers) {
// Resolve command
std::string resolved = hasSpecifiers ? ResolveGfxCommand(L, aGfxData, command) : command;
if (aGfxData->mErrorCount > 0) {
return false;
}
// Check cache
const auto &it = sGfxCommandCache.find(resolved);
if (it != sGfxCommandCache.end()) {
const Gfx *src = it->second.first;
u32 length = it->second.second;
if (!CheckGfxLength(aGfxData, gfx, length)) {
return false;
}
memcpy(gfx, src, length * sizeof(Gfx));
return true;
}
// Tokenize command
DataNode<Gfx> aNode;
aNode.mTokens = TokenizeGfxCommand(resolved);
if (aGfxData->mErrorCount > 0) {
return false;
}
// Parse tokenized command
u64 aTokenIndex = 0;
Gfx gfxBuffer[16] = {0};
Gfx *gfxHead = gfxBuffer;
ParseGfxSymbol(aGfxData, &aNode, gfxHead, aTokenIndex);
if (aGfxData->mErrorCount > 0) {
return false;
}
// Cache parsed command
u32 commandLength = (u32) (gfxHead - gfxBuffer);
size_t commandSize = commandLength * sizeof(Gfx);
Gfx *cached = (Gfx *) malloc(commandSize);
memcpy(cached, gfxBuffer, commandSize);
sGfxCommandCache[resolved] = { cached, commandLength };
// Copy buffer to gfx
if (!CheckGfxLength(aGfxData, gfx, commandLength)) {
return false;
}
memcpy(gfx, gfxBuffer, commandLength * sizeof(Gfx));
return true;
}
extern "C" {
bool dynos_smlua_parse_gfx_command(lua_State *L, Gfx *gfx, const char *command, bool hasSpecifiers, char *errorMsg, u32 errorSize) {
// Parse command
GfxData aGfxData;
sGfxCommandErrorMsg = errorMsg;
sGfxCommandErrorSize = errorSize;
bool ok = ParseGfxCommand(L, &aGfxData, gfx, command, hasSpecifiers);
// Clear stuff
sGfxCommandErrorMsg = NULL;
sGfxCommandErrorSize = 0;
for (auto &ptrNode : aGfxData.mRawPointers) {
Delete(ptrNode);
}
return ok;
}
void dynos_smlua_clear_gfx_command_cache() {
for (auto &cached : sGfxCommandCache) {
free(cached.second.first);
}
sGfxCommandCache.clear();
}
}

View file

@ -1,6 +1,7 @@
#include "dynos.cpp.h"
extern "C" {
#include "engine/graph_node.h"
#include "pc/lua/utils/smlua_gfx_utils.h"
}
#define F32VTX_SENTINEL_0 0x3346
@ -34,7 +35,7 @@ DataNode<Vtx>* DynOS_Vtx_Parse(GfxData* aGfxData, DataNode<Vtx>* aNode) {
// Vertex data
aNode->mSize = (u32) (aNode->mTokens.Count() / 10);
aNode->mData = New<Vtx>(aNode->mSize);
aNode->mData = vtx_allocate_internal(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();
@ -115,7 +116,7 @@ void DynOS_Vtx_Load(BinFile *aFile, GfxData *aGfxData) {
// Data
bool isUsingF32Vtx = false;
_Node->mSize = aFile->Read<u32>();
_Node->mData = New<Vtx>(_Node->mSize);
_Node->mData = vtx_allocate_internal(_Node->mSize);
for (u32 i = 0; i != _Node->mSize; ++i) {
if (isUsingF32Vtx) {
_Node->mData[i].n.ob[0] = aFile->Read<f32>();

View file

@ -270,12 +270,42 @@ void dynos_model_overwrite_slot(u32 srcSlot, u32 dstSlot) {
DynOS_Model_OverwriteSlot(srcSlot, dstSlot);
}
Gfx *dynos_model_get_writable_display_list(Gfx* gfx) {
return DynOS_Model_GetWritableDisplayList(gfx);
// -- gfx -- //
Gfx *dynos_gfx_get_writable_display_list(Gfx* gfx) {
return DynOS_Gfx_GetWritableDisplayList(gfx);
}
void dynos_model_restore_vanilla_display_lists() {
return DynOS_Model_RestoreVanillaDisplayLists();
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_realloc(Gfx *gfx, u32 newLength) {
return DynOS_Gfx_Realloc(gfx, newLength);
}
bool dynos_gfx_delete(Gfx *gfx) {
return DynOS_Gfx_Delete(gfx);
}
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_realloc(Vtx *vtx, u32 newCount) {
return DynOS_Vtx_Realloc(vtx, newCount);
}
bool dynos_vtx_delete(Vtx *vtx) {
return DynOS_Vtx_Delete(vtx);
}
// -- other -- //

View file

@ -45,6 +45,7 @@ void DynOS_Mod_Update() {
DynOS_Bhv_ModShutdown();
DynOS_MovtexQC_ModShutdown();
DynOS_Tex_ModShutdown();
DynOS_Gfx_ModShutdown();
}
}

View file

@ -24,6 +24,10 @@ static Array<Pair<const char*, void *>>& DynosCustomActors() {
// TODO: the cleanup/refactor didn't really go as planned.
// clean up the actor management code more
std::map<const void *, ActorGfx> &DynOS_Actor_GetValidActors() {
return DynosValidActors();
}
void DynOS_Actor_AddCustom(s32 aModIndex, const SysPath &aFilename, const char *aActorName) {
const void* georef = DynOS_Builtin_Actor_GetFromName(aActorName);

230
data/dynos_mgr_gfx.cpp Normal file
View file

@ -0,0 +1,230 @@
#include "dynos.cpp.h"
extern "C" {
#include "pc/lua/smlua.h"
#include "pc/lua/utils/smlua_gfx_utils.h"
}
static ModData<Gfx> sModDisplayLists;
static ModData<Vtx> sModVertexBuffers;
// Maps read-only Gfx and Vtx buffers to their writable duplicates
static std::map<const void *, std::pair<void *, size_t>> sRomToRamGfxVtxMap;
static Vtx *DynOS_Vtx_Duplicate(Vtx *aVtx, u32 vtxCount, bool shouldDuplicate) {
if (!aVtx) { return NULL; }
// Return duplicate if it already exists
auto it = sRomToRamGfxVtxMap.find(aVtx);
if (it != sRomToRamGfxVtxMap.end()) {
return (Vtx *) it->second.first;
}
// Duplicate vertex buffer and return the copy
if (shouldDuplicate) {
size_t vtxSize = vtxCount * sizeof(Vtx);
Vtx *vtxDuplicate = vtx_allocate_internal(vtxCount);
memcpy(vtxDuplicate, aVtx, vtxSize);
DynOS_Find_Pending_Scroll_Target(aVtx, vtxDuplicate);
sRomToRamGfxVtxMap[aVtx] = { (void *) vtxDuplicate, vtxSize };
return vtxDuplicate;
}
return aVtx;
}
static Gfx *DynOS_Gfx_Duplicate(Gfx *aGfx, bool shouldDuplicate) {
if (!aGfx) { return NULL; }
// Return duplicate if it already exists
auto it = sRomToRamGfxVtxMap.find(aGfx);
if (it != sRomToRamGfxVtxMap.end()) {
return (Gfx *) it->second.first;
}
// Check if it's vanilla
if (!shouldDuplicate) {
shouldDuplicate = (DynOS_Builtin_Gfx_GetFromData(aGfx) != NULL);
}
// Duplicate display list
Gfx *gfxDuplicate = aGfx;
u32 gfxLength = shouldDuplicate ? gfx_get_length_no_sentinel(aGfx) : gfx_get_length(aGfx);
if (shouldDuplicate) {
size_t gfxSize = gfxLength * sizeof(Gfx);
gfxDuplicate = gfx_allocate_internal(gfxLength);
memcpy(gfxDuplicate, aGfx, gfxSize);
sRomToRamGfxVtxMap[aGfx] = { (void *) gfxDuplicate, gfxSize };
}
// Look for other display lists or vertices
for (u32 i = 0; i < gfxLength; i++) {
Gfx *cmd = gfxDuplicate + i;
u32 op = GFX_OP(cmd);
// Duplicate referenced display lists
if (op == G_DL) {
cmd->words.w1 = (uintptr_t) DynOS_Gfx_Duplicate((Gfx *) cmd->words.w1, shouldDuplicate);
if (C0(cmd, 16, 1) == G_DL_NOPUSH) { break; } // This is a branch (jump), end of display list
}
// Duplicate referenced vertices
if (op == G_VTX) {
cmd->words.w1 = (uintptr_t) DynOS_Vtx_Duplicate((Vtx *) cmd->words.w1, C0(cmd, 12, 8), shouldDuplicate);
}
}
return gfxDuplicate;
}
// Get a writable display list so it can be modified by mods
// If it's a vanilla display list, duplicate it, so it can be restored later
Gfx *DynOS_Gfx_GetWritableDisplayList(Gfx *aGfx) {
return DynOS_Gfx_Duplicate(aGfx, false);
}
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);
if (gfx) {
return gfx;
}
// Check levels
for (auto &lvl : DynOS_Lvl_GetArray()) {
if (modIndex == -1 || lvl.second->mModIndex == modIndex) {
for (auto &gfx : lvl.second->mDisplayLists) {
if (gfx->mName == aName) {
*outLength = gfx->mSize;
return gfx->mData;
}
}
}
}
// Check loaded actors
for (auto &actor : DynOS_Actor_GetValidActors()) {
if (modIndex == -1 || actor.second.mGfxData->mModIndex == modIndex) {
for (auto &gfx : actor.second.mGfxData->mDisplayLists) {
if (gfx->mName == aName) {
*outLength = gfx->mSize;
return gfx->mData;
}
}
}
}
// Check vanilla display lists
const Gfx *gfxVanilla = DynOS_Builtin_Gfx_GetFromName(aName);
if (gfxVanilla) {
auto it = sRomToRamGfxVtxMap.find(gfxVanilla);
// If not found, duplicate the display list now
if (it == sRomToRamGfxVtxMap.end()) {
DynOS_Gfx_Duplicate((Gfx *) gfxVanilla, true);
it = sRomToRamGfxVtxMap.find(gfxVanilla);
}
*outLength = it->second.second / sizeof(Gfx);
return (Gfx *) it->second.first;
}
return NULL;
}
Gfx *DynOS_Gfx_New(const char *aName, u32 aLength) {
if (!aName || !aLength) { return NULL; }
s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1);
return DynOS_ModData_New(sModDisplayLists, modIndex, aName, aLength, gfx_allocate_internal);
}
Gfx *DynOS_Gfx_Realloc(Gfx *aGfx, u32 aNewLength) {
if (!aGfx || !aNewLength) { return NULL; }
s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1);
return DynOS_ModData_Realloc(sModDisplayLists, modIndex, aGfx, aNewLength, gfx_allocate_internal, free);
}
bool DynOS_Gfx_Delete(Gfx *aGfx) {
if (!aGfx) { return false; }
s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1);
return DynOS_ModData_Delete(sModDisplayLists, modIndex, aGfx, free);
}
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);
if (vtx) {
return vtx;
}
// Check levels
for (auto &lvl : DynOS_Lvl_GetArray()) {
if (modIndex == -1 || lvl.second->mModIndex == modIndex) {
for (auto &vtx : lvl.second->mVertices) {
if (vtx->mName == aName) {
*outCount = vtx->mSize;
return vtx->mData;
}
}
}
}
// Check loaded actors
for (auto &actor : DynOS_Actor_GetValidActors()) {
if (modIndex == -1 || actor.second.mGfxData->mModIndex == modIndex) {
for (auto &vtx : actor.second.mGfxData->mVertices) {
if (vtx->mName == aName) {
*outCount = vtx->mSize;
return vtx->mData;
}
}
}
}
return NULL;
}
Vtx *DynOS_Vtx_New(const char *aName, u32 aCount) {
if (!aName || !aCount) { return NULL; }
s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1);
return DynOS_ModData_New(sModVertexBuffers, modIndex, aName, aCount, vtx_allocate_internal);
}
Vtx *DynOS_Vtx_Realloc(Vtx *aVtx, u32 aNewCount) {
if (!aVtx || !aNewCount) { return NULL; }
s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1);
return DynOS_ModData_Realloc(sModVertexBuffers, modIndex, aVtx, aNewCount, vtx_allocate_internal, free);
}
bool DynOS_Vtx_Delete(Vtx *aVtx) {
if (!aVtx) { return false; }
s32 modIndex = (gLuaActiveMod ? gLuaActiveMod->index : -1);
return DynOS_ModData_Delete(sModVertexBuffers, modIndex, aVtx, free);
}
void DynOS_Gfx_ModShutdown() {
// Delete all allocated display lists and vertex buffers
DynOS_ModData_DeleteAll(sModDisplayLists, free);
DynOS_ModData_DeleteAll(sModVertexBuffers, free);
// Restore vanilla display lists
for (auto &it : sRomToRamGfxVtxMap) {
const void *original = it.first;
void *duplicate = it.second.first;
size_t size = it.second.second;
memcpy(duplicate, original, size);
}
}

104
data/dynos_mgr_moddata.hpp Normal file
View file

@ -0,0 +1,104 @@
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;
}
template <typename T>
bool DynOS_ModData_Find(ModData<T> &aModData, s32 aModIndex, T *aPointer, std::string &outName) {
if (!aPointer) { return false; }
auto itMod = aModData.find(aModIndex);
if (itMod == aModData.end()) {
return false;
}
for (auto &modItem : itMod->second) {
if (modItem.second.first == aPointer) {
outName = modItem.first;
return true;
}
}
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);
}
}
aModData.clear();
}

View file

@ -1,4 +1,3 @@
#include <map>
#include <vector>
#include "dynos.cpp.h"
@ -7,8 +6,6 @@ extern "C" {
#include "engine/graph_node.h"
#include "model_ids.h"
#include "pc/lua/utils/smlua_model_utils.h"
#include "engine/display_list.h"
#include "dynos_mgr_builtin_externs.h"
}
enum ModelLoadType {
@ -30,9 +27,6 @@ static std::map<void*, struct ModelInfo> sAssetMap[MODEL_POOL_MAX];
static std::map<u32, std::vector<struct ModelInfo>> sIdMap;
static std::map<u32, u32> sOverwriteMap;
// Maps read-only Gfx and Vtx buffers to their writable duplicates
static std::map<void *, std::pair<void *, size_t>> sRomToRamGfxVtxMap;
static u32 find_empty_id(bool aIsPermanent) {
u32 id = aIsPermanent ? 9999 : VANILLA_ID_END + 1;
s8 dir = aIsPermanent ? -1 : 1;
@ -247,87 +241,6 @@ void DynOS_Model_OverwriteSlot(u32 srcSlot, u32 dstSlot) {
sOverwriteMap[srcSlot] = dstSlot;
}
static Vtx *DynOS_Model_DuplicateVtx(Vtx *aVtx, u32 vtxCount, bool shouldDuplicate) {
if (!aVtx) { return NULL; }
// Return duplicate if it already exists
auto it = sRomToRamGfxVtxMap.find((void *) aVtx);
if (it != sRomToRamGfxVtxMap.end()) {
return (Vtx *) it->second.first;
}
// Duplicate vertex buffer and return the copy
if (shouldDuplicate) {
size_t vtxSize = vtxCount * sizeof(Vtx);
Vtx *vtxDuplicate = (Vtx *) malloc(vtxSize);
memcpy(vtxDuplicate, aVtx, vtxSize);
DynOS_Find_Pending_Scroll_Target(aVtx, vtxDuplicate);
sRomToRamGfxVtxMap[(void *) aVtx] = { (void *) vtxDuplicate, vtxSize };
return vtxDuplicate;
}
return aVtx;
}
static Gfx *DynOS_Model_DuplicateDisplayList(Gfx *aGfx, bool shouldDuplicate) {
if (!aGfx) { return NULL; }
// Return duplicate if it already exists
auto it = sRomToRamGfxVtxMap.find((void *) aGfx);
if (it != sRomToRamGfxVtxMap.end()) {
return (Gfx *) it->second.first;
}
// Check if it's vanilla
if (!shouldDuplicate) {
shouldDuplicate = (DynOS_Builtin_Gfx_GetFromData(aGfx) != NULL);
}
// Duplicate display list
Gfx *gfxDuplicate = aGfx;
u32 gfxLength = gfx_get_size(aGfx);
if (shouldDuplicate) {
size_t gfxSize = gfxLength * sizeof(Gfx);
gfxDuplicate = (Gfx *) malloc(gfxSize);
memcpy(gfxDuplicate, aGfx, gfxSize);
sRomToRamGfxVtxMap[(void *) aGfx] = { (void *) gfxDuplicate, gfxSize };
}
// Look for other display lists or vertices
for (u32 i = 0; i < gfxLength; i++) {
Gfx *cmd = gfxDuplicate + i;
u32 op = cmd->words.w0 >> 24;
// Duplicate referenced display lists
if (op == G_DL) {
cmd->words.w1 = (uintptr_t) DynOS_Model_DuplicateDisplayList((Gfx *) cmd->words.w1, shouldDuplicate);
if (C0(cmd, 16, 1) == G_DL_NOPUSH) { break; } // This is a branch (jump), end of display list
}
// Duplicate referenced vertices
if (op == G_VTX) {
cmd->words.w1 = (uintptr_t) DynOS_Model_DuplicateVtx((Vtx *) cmd->words.w1, C0(cmd, 12, 8), shouldDuplicate);
}
}
return gfxDuplicate;
}
// Get a writable display list so it can be modified by mods
// If it's a vanilla display list, duplicate it, so it can be restored later
Gfx *DynOS_Model_GetWritableDisplayList(Gfx *aGfx) {
return DynOS_Model_DuplicateDisplayList(aGfx, false);
}
void DynOS_Model_RestoreVanillaDisplayLists() {
for (auto &it : sRomToRamGfxVtxMap) {
const void *original = it.first;
void *duplicate = it.second.first;
size_t size = it.second.second;
memcpy(duplicate, original, size);
}
}
void DynOS_Model_ClearPool(enum ModelPool aModelPool) {
if (!sModelPools[aModelPool]) { return; }

View file

@ -35,6 +35,11 @@ static Array<DataNode<TexData> *>& DynosScheduledInvalidTextures() {
return sDynosScheduledInvalidTextures;
}
static Array<Pair<const char*, DataNode<TexData>*>>& DynosCustomTexs() {
static Array<Pair<const char*, DataNode<TexData>*>> sDynosCustomTexs;
return sDynosCustomTexs;
}
static bool sDynosDumpTextureCache = false;
//
@ -329,6 +334,15 @@ static DataNode<TexData> *DynOS_Tex_RetrieveNode(void *aPtr) {
if (_ValidTextures.find((DataNode<TexData>*)aPtr) != _ValidTextures.end()) {
return (DataNode<TexData>*)aPtr;
}
auto& _DynosCustomTexs = DynosCustomTexs();
for (auto &_DynosCustomTex : _DynosCustomTexs) {
auto& _Node = _DynosCustomTex.second;
if (aPtr == (void *) _Node->mData->mRawData.begin()) {
return _Node;
}
}
return NULL;
}
@ -360,11 +374,6 @@ bool DynOS_Tex_Import(void **aOutput, void *aPtr, s32 aTile, void *aGfxRApi, voi
// Custom Textures //
/////////////////////
static Array<Pair<const char*, DataNode<TexData>*>>& DynosCustomTexs() {
static Array<Pair<const char*, DataNode<TexData>*>> sDynosCustomTexs;
return sDynosCustomTexs;
}
void DynOS_Tex_Activate(DataNode<TexData>* aNode, bool aCustomTexture) {
if (!aNode) { return; }

View file

@ -1237,58 +1237,30 @@
## [gbi.h](#gbi.h)
- G_COPYMEM
- G_NOOP
- G_RDPHALF_2
- G_SETOTHERMODE_H
- G_SETOTHERMODE_L
- G_RDPHALF_1
- G_SPNOOP
- G_ENDDL
- G_DL
- G_LOAD_UCODE
- G_MOVEMEM
- G_MOVEWORD
- G_MTX
- G_GEOMETRYMODE
- G_POPMTX
- G_TEXTURE
- G_DMA_IO
- G_SPECIAL_1
- G_SPECIAL_2
- G_SPECIAL_3
- G_VTX
- G_MODIFYVTX
- G_CULLDL
- G_BRANCH_Z
- G_TRI1
- G_TRI2
- G_QUAD
- G_LINE3D
- G_SPNOOP
- G_MTX
- G_RESERVED0
- G_MOVEMEM
- G_VTX
- G_RESERVED1
- G_DL
- G_RESERVED2
- G_RESERVED3
- G_SPRITE2D_BASE
- G_IMMFIRST
- G_TRI1
- G_CULLDL
- G_POPMTX
- G_MOVEWORD
- G_TEXTURE
- G_SETOTHERMODE_H
- G_SETOTHERMODE_L
- G_ENDDL
- G_SETGEOMETRYMODE
- G_CLEARGEOMETRYMODE
- G_LINE3D
- G_RDPHALF_1
- G_RDPHALF_2
- G_SPRITE2D_SCALEFLIP
- G_SPRITE2D_DRAW
- G_NOOP
- G_SETCIMG
- G_SETZIMG
@ -1305,316 +1277,9 @@
- G_LOADBLOCK
- G_SETTILESIZE
- G_LOADTLUT
- G_RDPSETOTHERMODE
- G_SETPRIMDEPTH
- G_SETSCISSOR
- G_SETCONVERT
- G_SETKEYR
- G_SETKEYGB
- G_RDPFULLSYNC
- G_RDPTILESYNC
- G_RDPPIPESYNC
- G_RDPLOADSYNC
- G_TEXRECTFLIP
- G_TEXRECT
- G_TRI_FILL
- G_TRI_SHADE
- G_TRI_TXTR
- G_TRI_SHADE_TXTR
- G_TRI_FILL_ZBUFF
- G_TRI_SHADE_ZBUFF
- G_TRI_TXTR_ZBUFF
- G_TRI_SHADE_TXTR_ZBUFF
- G_RDP_TRI_FILL_MASK
- G_RDP_TRI_SHADE_MASK
- G_RDP_TRI_TXTR_MASK
- G_RDP_TRI_ZBUFF_MASK
- BOWTIE_VAL
- G_RDP_ADDR_FIXUP
- G_DMACMDSIZ
- G_IMMCMDSIZ
- G_RDPCMDSIZ
- G_TEXTURE_IMAGE_FRAC
- G_TEXTURE_SCALE_FRAC
- G_SCALE_FRAC
- G_ROTATE_FRAC
- G_MAXFBZ
- G_ZBUFFER
- G_SHADE
- G_FOG
- G_LIGHTING
- G_TEXTURE_GEN
- G_TEXTURE_GEN_LINEAR
- G_LOD
- G_IM_FMT_RGBA
- G_IM_FMT_YUV
- G_IM_FMT_CI
- G_IM_FMT_IA
- G_IM_FMT_I
- G_IM_SIZ_4b
- G_IM_SIZ_8b
- G_IM_SIZ_16b
- G_IM_SIZ_32b
- G_IM_SIZ_DD
- G_IM_SIZ_4b_BYTES
- G_IM_SIZ_8b_BYTES
- G_IM_SIZ_16b_BYTES
- G_IM_SIZ_32b_BYTES
- G_IM_SIZ_32b_TILE_BYTES
- G_IM_SIZ_32b_LINE_BYTES
- G_IM_SIZ_4b_SHIFT
- G_IM_SIZ_8b_SHIFT
- G_IM_SIZ_16b_SHIFT
- G_IM_SIZ_32b_SHIFT
- G_IM_SIZ_4b_INCR
- G_IM_SIZ_8b_INCR
- G_IM_SIZ_16b_INCR
- G_IM_SIZ_32b_INCR
- G_CCMUX_COMBINED
- G_CCMUX_TEXEL0
- G_CCMUX_TEXEL1
- G_CCMUX_PRIMITIVE
- G_CCMUX_SHADE
- G_CCMUX_ENVIRONMENT
- G_CCMUX_CENTER
- G_CCMUX_SCALE
- G_CCMUX_COMBINED_ALPHA
- G_CCMUX_TEXEL0_ALPHA
- G_CCMUX_TEXEL1_ALPHA
- G_CCMUX_PRIMITIVE_ALPHA
- G_CCMUX_SHADE_ALPHA
- G_CCMUX_ENV_ALPHA
- G_CCMUX_LOD_FRACTION
- G_CCMUX_PRIM_LOD_FRAC
- G_CCMUX_NOISE
- G_CCMUX_K4
- G_CCMUX_K5
- G_CCMUX_1
- G_CCMUX_0
- G_ACMUX_COMBINED
- G_ACMUX_TEXEL0
- G_ACMUX_TEXEL1
- G_ACMUX_PRIMITIVE
- G_ACMUX_SHADE
- G_ACMUX_ENVIRONMENT
- G_ACMUX_LOD_FRACTION
- G_ACMUX_PRIM_LOD_FRAC
- G_ACMUX_1
- G_ACMUX_0
- G_MDSFT_ALPHACOMPARE
- G_MDSFT_ZSRCSEL
- G_MDSFT_RENDERMODE
- G_MDSFT_BLENDER
- G_MDSFT_BLENDMASK
- G_MDSFT_ALPHADITHER
- G_MDSFT_RGBDITHER
- G_MDSFT_COMBKEY
- G_MDSFT_TEXTCONV
- G_MDSFT_TEXTFILT
- G_MDSFT_TEXTLUT
- G_MDSFT_TEXTLOD
- G_MDSFT_TEXTDETAIL
- G_MDSFT_TEXTPERSP
- G_MDSFT_CYCLETYPE
- G_MDSFT_COLORDITHER
- G_MDSFT_PIPELINE
- G_PM_1PRIMITIVE
- G_PM_NPRIMITIVE
- G_CYC_1CYCLE
- G_CYC_2CYCLE
- G_CYC_COPY
- G_CYC_FILL
- G_TP_NONE
- G_TP_PERSP
- G_TD_CLAMP
- G_TD_SHARPEN
- G_TD_DETAIL
- G_TL_TILE
- G_TL_LOD
- G_TT_NONE
- G_TT_RGBA16
- G_TT_IA16
- G_TF_POINT
- G_TF_AVERAGE
- G_TF_BILERP
- G_TC_CONV
- G_TC_FILTCONV
- G_TC_FILT
- G_CK_NONE
- G_CK_KEY
- G_CD_MAGICSQ
- G_CD_BAYER
- G_CD_NOISE
- G_CD_DISABLE
- G_CD_ENABLE
- G_CD_ENABLE
- G_CD_DISABLE
- G_AD_PATTERN
- G_AD_NOTPATTERN
- G_AD_NOISE
- G_AD_DISABLE
- G_AC_NONE
- G_AC_THRESHOLD
- G_AC_DITHER
- G_ZS_PIXEL
- G_ZS_PRIM
- AA_EN
- Z_CMP
- Z_UPD
- IM_RD
- CLR_ON_CVG
- CVG_DST_CLAMP
- CVG_DST_WRAP
- CVG_DST_FULL
- CVG_DST_SAVE
- ZMODE_OPA
- ZMODE_INTER
- ZMODE_XLU
- ZMODE_DEC
- CVG_X_ALPHA
- ALPHA_CVG_SEL
- FORCE_BL
- TEX_EDGE
- G_BL_CLR_IN
- G_BL_CLR_MEM
- G_BL_CLR_BL
- G_BL_CLR_FOG
- G_BL_1MA
- G_BL_A_MEM
- G_BL_A_IN
- G_BL_A_FOG
- G_BL_A_SHADE
- G_BL_1
- G_BL_0
- G_CV_K0
- G_CV_K1
- G_CV_K2
- G_CV_K3
- G_CV_K4
- G_CV_K5
- G_SC_NON_INTERLACE
- G_SC_ODD_INTERLACE
- G_SC_EVEN_INTERLACE
- G_DL_PUSH
- G_DL_NOPUSH
- G_MW_MATRIX
- G_MW_NUMLIGHT
- G_MW_CLIP
- G_MW_SEGMENT
- G_MW_FOG
- G_MW_LIGHTCOL
- G_MW_PERSPNORM
- G_MWO_NUMLIGHT
- G_MWO_CLIP_RNX
- G_MWO_CLIP_RNY
- G_MWO_CLIP_RPX
- G_MWO_CLIP_RPY
- G_MWO_SEGMENT_0
- G_MWO_SEGMENT_1
- G_MWO_SEGMENT_2
- G_MWO_SEGMENT_3
- G_MWO_SEGMENT_4
- G_MWO_SEGMENT_5
- G_MWO_SEGMENT_6
- G_MWO_SEGMENT_7
- G_MWO_SEGMENT_8
- G_MWO_SEGMENT_9
- G_MWO_SEGMENT_A
- G_MWO_SEGMENT_B
- G_MWO_SEGMENT_C
- G_MWO_SEGMENT_D
- G_MWO_SEGMENT_E
- G_MWO_SEGMENT_F
- G_MWO_FOG
- G_MWO_aLIGHT_1
- G_MWO_bLIGHT_1
- G_MWO_aLIGHT_2
- G_MWO_bLIGHT_2
- G_MWO_aLIGHT_3
- G_MWO_bLIGHT_3
- G_MWO_aLIGHT_4
- G_MWO_bLIGHT_4
- G_MWO_aLIGHT_5
- G_MWO_bLIGHT_5
- G_MWO_aLIGHT_6
- G_MWO_bLIGHT_6
- G_MWO_aLIGHT_7
- G_MWO_bLIGHT_7
- G_MWO_aLIGHT_8
- G_MWO_bLIGHT_8
- G_MWO_aLIGHT_2
- G_MWO_bLIGHT_2
- G_MWO_aLIGHT_3
- G_MWO_bLIGHT_3
- G_MWO_aLIGHT_4
- G_MWO_bLIGHT_4
- G_MWO_aLIGHT_5
- G_MWO_bLIGHT_5
- G_MWO_aLIGHT_6
- G_MWO_bLIGHT_6
- G_MWO_aLIGHT_7
- G_MWO_bLIGHT_7
- G_MWO_aLIGHT_8
- G_MWO_bLIGHT_8
- G_MWO_MATRIX_XX_XY_I
- G_MWO_MATRIX_XZ_XW_I
- G_MWO_MATRIX_YX_YY_I
- G_MWO_MATRIX_YZ_YW_I
- G_MWO_MATRIX_ZX_ZY_I
- G_MWO_MATRIX_ZZ_ZW_I
- G_MWO_MATRIX_WX_WY_I
- G_MWO_MATRIX_WZ_WW_I
- G_MWO_MATRIX_XX_XY_F
- G_MWO_MATRIX_XZ_XW_F
- G_MWO_MATRIX_YX_YY_F
- G_MWO_MATRIX_YZ_YW_F
- G_MWO_MATRIX_ZX_ZY_F
- G_MWO_MATRIX_ZZ_ZW_F
- G_MWO_MATRIX_WX_WY_F
- G_MWO_MATRIX_WZ_WW_F
- G_MWO_POINT_RGBA
- G_MWO_POINT_ST
- G_MWO_POINT_XYSCREEN
- G_MWO_POINT_ZSCREEN
- FR_NEG_FRUSTRATIO_1
- FR_POS_FRUSTRATIO_1
- FR_NEG_FRUSTRATIO_2
- FR_POS_FRUSTRATIO_2
- FR_NEG_FRUSTRATIO_3
- FR_POS_FRUSTRATIO_3
- FR_NEG_FRUSTRATIO_4
- FR_POS_FRUSTRATIO_4
- FR_NEG_FRUSTRATIO_5
- FR_POS_FRUSTRATIO_5
- FR_NEG_FRUSTRATIO_6
- FR_POS_FRUSTRATIO_6
- NUMLIGHTS_0
- NUMLIGHTS_1
- NUMLIGHTS_2
- NUMLIGHTS_3
- NUMLIGHTS_4
- NUMLIGHTS_5
- NUMLIGHTS_6
- NUMLIGHTS_7
- LIGHT_1
- LIGHT_2
- LIGHT_3
- LIGHT_4
- LIGHT_5
- LIGHT_6
- LIGHT_7
- LIGHT_8
- G_TX_LOADTILE
- G_TX_RENDERTILE
- G_TX_NOMIRROR
- G_TX_WRAP
- G_TX_MIRROR
- G_TX_CLAMP
- G_TX_NOMASK
- G_TX_NOLOD
- G_TX_DXT_FRAC
- G_TX_LDBLK_MAX_TXL
- G_TX_LDBLK_MAX_TXL
[:arrow_up_small:](#)

View file

@ -0,0 +1,155 @@
--
-- Math stuff
-- Don't mind this file, it's not relevant to the purpose of this demo.
--
local SHAPE_SIZE = 100
local SHAPE_TEXTURE_SIZE = 512
----------
-- Cube --
----------
local CUBE_ROTATIONS = {
{ x = 0x0000, y = 0x0000, z = 0 },
{ x = 0x0000, y = 0x4000, z = 0 },
{ x = 0x0000, y = 0x8000, z = 0 },
{ x = 0x0000, y = 0xC000, z = 0 },
{ x = 0x4000, y = 0x0000, z = 0 },
{ x = 0xC000, y = 0x0000, z = 0 },
}
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 },
}
function get_cube_vertices()
vertices = {}
for _, r in ipairs(CUBE_ROTATIONS) do
for _, p in ipairs(CUBE_POINTS) do
local v = { x = p.x * SHAPE_SIZE, y = p.y * SHAPE_SIZE, z = p.z * SHAPE_SIZE }
vec3f_rotate_zxy(v, r)
table.insert(vertices, { x = v.x, y = v.y, z = v.z, tu = p.tu, tv = p.tv, r = 0xFF, g = 0xFF, b = 0xFF })
end
end
return vertices
end
function get_cube_triangles()
local triangles = {}
for i = 0, 5 do
local offset = 4 * i
table.insert(triangles, {
offset + 0, offset + 1, offset + 2,
offset + 2, offset + 1, offset + 3
})
end
return triangles
end
function get_cube_geometry_mode()
return "G_TEXTURE_GEN | G_CULL_BOTH | G_LIGHTING", "0"
end
function get_cube_texture_scaling()
return 0xFFFF
end
----------------
-- Octahedron --
----------------
function get_octahedron_vertices()
local vertices = {}
table.insert(vertices, { x = 0, y = -SHAPE_SIZE, z = 0, tu = 0, tv = (SHAPE_TEXTURE_SIZE / 2) << 5, r = 0xFF, g = 0xFF, b = 0xFF })
table.insert(vertices, { x = 0, y = SHAPE_SIZE, z = 0, tu = (SHAPE_TEXTURE_SIZE - 1) << 5, tv = (SHAPE_TEXTURE_SIZE / 2) << 5, r = 0xFF, g = 0xFF, b = 0xFF })
for i = 0, 3 do
local sina = sins(0x4000 * i) * SHAPE_SIZE
local cosa = coss(0x4000 * i) * SHAPE_SIZE
table.insert(vertices, { x = sina, y = 0, z = cosa, tu = (SHAPE_TEXTURE_SIZE - 1) << 5, tv = (SHAPE_TEXTURE_SIZE - 1) << 5, r = 0xFF, g = 0xFF, b = 0xFF })
table.insert(vertices, { x = sina, y = 0, z = cosa, tu = (SHAPE_TEXTURE_SIZE - 1) << 5, tv = 0, r = 0xFF, g = 0xFF, b = 0xFF })
table.insert(vertices, { x = sina, y = 0, z = cosa, tu = 0, tv = (SHAPE_TEXTURE_SIZE - 1) << 5, r = 0xFF, g = 0xFF, b = 0xFF })
table.insert(vertices, { x = sina, y = 0, z = cosa, tu = 0, tv = 0, r = 0xFF, g = 0xFF, b = 0xFF })
end
return vertices
end
function get_octahedron_triangles()
local triangles = {}
for i = 0, 3 do
table.insert(triangles, {
0, 2 + i * 4 + 0, 2 + ((i + 1) % 4) * 4 + 1,
1, 2 + i * 4 + 2, 2 + ((i + 1) % 4) * 4 + 3
})
end
return triangles
end
function get_octahedron_geometry_mode()
return "G_TEXTURE_GEN | G_CULL_BOTH | G_LIGHTING", "0"
end
function get_octahedron_texture_scaling()
return 0xFFFF
end
----------
-- Star --
----------
local STAR_POINTS = {
{ x = 0, y = 8, z = -90, r = 0x00, g = 0x07, b = 0x82 },
{ x = 190, y = -201, z = 0, r = 0x55, g = 0xa3, b = 0x00 },
{ x = 0, y = -129, z = 0, r = 0x00, g = 0x82, b = 0x00 },
{ x = 146, y = -42, z = 0, r = 0x7c, g = 0xe7, b = 0x00 },
{ x = 0, y = 8, z = 90, r = 0x00, g = 0x07, b = 0x7e },
{ x = 256, y = 84, z = 0, r = 0x68, g = 0x47, b = 0x00 },
{ x = -146, y = -42, z = 0, r = 0x84, g = 0xe7, b = 0x00 },
{ x = -190, y = -201, z = 0, r = 0xaa, g = 0xa3, b = 0x00 },
{ x = -256, y = 84, z = 0, r = 0x97, g = 0x47, b = 0x00 },
{ x = 0, y = 246, z = 0, r = 0x00, g = 0x7e, b = 0x00 },
{ x = 96, y = 99, z = 0, r = 0x3d, g = 0x6f, b = 0x00 },
{ x = -96, y = 99, z = 0, r = 0xc3, g = 0x6f, b = 0x00 },
}
local STAR_TRIANGLES = {
{ 0, 1, 2, 0, 3, 1 },
{ 2, 1, 4, 1, 3, 4 },
{ 5, 3, 0, 4, 3, 5 },
{ 6, 7, 4, 7, 2, 4 },
{ 8, 6, 4, 9, 4, 10 },
{ 9, 11, 4, 4, 5, 10 },
{ 11, 8, 4, 0, 2, 7 },
{ 0, 7, 6, 0, 6, 8 },
{ 0, 8, 11, 0, 11, 9 },
{ 10, 5, 0, 10, 0, 9 },
}
function get_star_vertices()
local vertices = {}
for _, p in ipairs(STAR_POINTS) do
table.insert(vertices, {
x = p.x * SHAPE_SIZE / 256,
y = p.y * SHAPE_SIZE / 256,
z = p.z * SHAPE_SIZE / 256,
tu = 0, tv = 0,
r = p.r, g = p.g, b = p.b
})
end
return vertices
end
function get_star_triangles()
return STAR_TRIANGLES
end
function get_star_geometry_mode()
return "G_CULL_BOTH", "G_LIGHTING | G_TEXTURE_GEN"
end
function get_star_texture_scaling()
return 0x7FC0
end

View file

@ -0,0 +1,8 @@
const GeoLayout shape_geo[] = {
GEO_NODE_START(),
GEO_OPEN_NODE(),
GEO_ASM(0, geo_update_shape),
GEO_DISPLAY_LIST(LAYER_OPAQUE, shape_template_dl),
GEO_CLOSE_NODE(),
GEO_END(),
};

View file

@ -0,0 +1,19 @@
// The template display list.
// Some values are placeholders that will be filled during the custom GEO ASM function.
Gfx shape_template_dl[] = {
/* [00] */ gsSPGeometryMode(0, 0),
/* [01] */ gsDPSetCombineMode(G_CC_DECALRGBA, G_CC_DECALRGBA),
/* [02] */ gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON),
/* [03] */ gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_32b_LOAD_BLOCK, 1, NULL),
/* [04] */ gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_32b_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 0 , G_TX_CLAMP, 0, G_TX_NOLOD, G_TX_CLAMP, 0, G_TX_NOLOD),
/* [05] */ gsDPLoadSync(),
/* [06] */ gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 0, 0),
/* [07] */ gsDPPipeSync(),
/* [08] */ gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_32b, 128, 0, G_TX_RENDERTILE, 0, G_TX_CLAMP, 0, G_TX_NOLOD, G_TX_CLAMP, 0, G_TX_NOLOD),
/* [09] */ gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, 511 << G_TEXTURE_IMAGE_FRAC, 511 << G_TEXTURE_IMAGE_FRAC),
/* [10] */ gsSPVertex(NULL, 0, 0),
/* [11] */ gsSPDisplayList(NULL),
/* [12] */ gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF),
/* [13] */ gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
/* [14] */ gsSPEndDisplayList(),
};

View file

@ -0,0 +1,182 @@
-- name: Gfx and Vtx manipulation demo
-- description: Press X to move the shape in front of Mario.\nPress Y to change the shape.
local SHAPE_TEXTURES = {}
for i = 0, 10 do
SHAPE_TEXTURES[i] = get_texture_info("matrix_" .. i)
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,
get_texture_scaling = get_star_texture_scaling,
}
}
--- @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()
gfx_set_command(gfx, "gsSPGeometryMode(%s, %s)", clear, set)
end
--- @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()
gfx_set_command(gfx, "gsSPTexture(%i, %i, 0, G_TX_RENDERTILE, %i)", scaling, scaling, on)
end
--- @param gfx Gfx
--- @param obj Object
--- Update the texture of the current shape.
local function update_texture(gfx, obj)
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
--- 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 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 = vtx_get_from_name(vtx_name)
if vtx == nil then
vtx = vtx_new(vtx_name, num_vertices)
else
vtx = vtx_realloc(vtx, num_vertices)
end
-- Update the vertex command
gfx_set_command(gfx, "gsSPVertex(%v, %i, 0)", vtx, num_vertices)
-- Fill the vertex buffer
for _, vertex in ipairs(vertices) do
vtx.x = vertex.x
vtx.y = vertex.y
vtx.z = vertex.z
vtx.tu = vertex.tu
vtx.tv = vertex.tv
vtx.r = vertex.r
vtx.g = vertex.g
vtx.b = vertex.b
vtx.a = 0xFF
vtx = vtx_get_next_vertex(vtx)
end
end
--- @param gfx Gfx
--- @param obj Object
--- Build the triangles for the current shape.
local function build_triangles(gfx, obj)
local triangles = SHAPES[current_shape + 1].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 = gfx_get_from_name(tris_name)
if tris == nil then
tris = gfx_new(tris_name, num_triangles + 1) -- +1 for the gsSPEndDisplayList command
else
tris = gfx_realloc(tris, num_triangles + 1)
end
-- Update the triangles command
gfx_set_command(gfx, "gsSPDisplayList(%g)", tris)
-- Fill the triangles display list
for _, indices in ipairs(triangles) do
if #indices == 6 then
gfx_set_command(tris, "gsSP2Triangles(%i, %i, %i, 0, %i, %i, %i, 0)",
indices[1], indices[2], indices[3],
indices[4], indices[5], indices[6]
)
elseif #indices == 3 then
gfx_set_command(tris, "gsSP1Triangle(%i, %i, %i, 0)",
indices[1], indices[2], indices[3]
)
end
tris = gfx_get_next_command(tris)
end
gfx_set_command(tris, "gsSPEndDisplayList()")
end
--- @param node GraphNode
--- @param matStackIndex integer
--- The custom GEO ASM function.
function geo_update_shape(node, matStackIndex)
local obj = geo_get_current_object()
-- 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 = 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_copy(gfx, gfx_template, gfx_template_length)
end
-- Now fill the display list with the appropriate commands (see actors/shape/model.inc.c)
-- We can retrieve the commands directly with `gfx_get_command`
-- Index | Command | What to do
-- ------|----------------------|----------------------------------------
-- [00] | gsSPGeometryMode | Change the geometry mode
-- [02] | gsSPTexture | Change the texture scaling
-- [03] | gsDPSetTextureImage | Update the texture
-- [10] | gsSPVertex | Compute vertices
-- [11] | gsSPDisplayList | Build triangles
-- [12] | gsSPTexture | Change the texture scaling
-- Change the geometry mode
local cmd_geometry_mode = gfx_get_command(gfx, 0)
set_geometry_mode(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)
local cmd_texture_scaling_2 = gfx_get_command(gfx, 12)
set_texture_scaling(cmd_texture_scaling_2, 0)
-- Update texture
local cmd_texture = gfx_get_command(gfx, 3)
update_texture(cmd_texture, obj)
-- Compute vertices
local cmd_vertices = gfx_get_command(gfx, 10)
compute_vertices(cmd_vertices, obj)
-- Build triangles
local cmd_triangles = gfx_get_command(gfx, 11)
build_triangles(cmd_triangles, obj)
-- Update the graph node display list
cast_graph_node(node.next).displayList = gfx
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

View file

@ -0,0 +1,48 @@
--
-- Custom object and Mario update
-- Don't mind this file, it's not relevant to the purpose of this demo.
--
current_shape = 0
local E_MODEL_SHAPE = smlua_model_util_get_id("shape_geo")
local function bhv_shape_init(o)
o.oFlags = o.oFlags | OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
o.oAnimState = 0
end
local function bhv_shape_loop(o)
o.oFaceAngleYaw = o.oFaceAngleYaw - 0x100
if o.oTimer % 2 == 0 then
o.oAnimState = (o.oAnimState + 1) % 11
end
end
local id_bhvShape = hook_behavior(nil, OBJ_LIST_DEFAULT, true, bhv_shape_init, bhv_shape_loop, "bhvShape")
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)
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)
end
hook_event(HOOK_MARIO_UPDATE, mario_update)
hook_event(HOOK_ON_HUD_RENDER, on_hud_render)

View file

@ -8,7 +8,7 @@ function geo_hide_if_dnc(node)
local dl = cast_graph_node(node.next)
gfx_parse(dl.displayList, function(cmd, op)
if op == G_SETENVCOLOR then
gfx_set_command(cmd, "gsDPSetEnvColor", 255, 255, 255, if_then_else(_G.dayNightCycleApi ~= nil and _G.dayNightCycleApi.is_dnc_enabled(), 0, 255))
gfx_set_command(cmd, "gsDPSetEnvColor(255, 255, 255, %i)", if_then_else(_G.dayNightCycleApi ~= nil and _G.dayNightCycleApi.is_dnc_enabled(), 0, 255))
end
end)
end

View file

@ -468,43 +468,19 @@ Traverses a display list. Takes a Lua function as a parameter, which is called b
- None
### C Prototype
`void gfx_parse(Gfx* cmd, LuaFunction func);`
`void gfx_parse(Gfx *cmd, LuaFunction func);`
[:arrow_up_small:](#)
<br />
## [gfx_get_vtx](#gfx_get_vtx)
## [gfx_get_op](#gfx_get_op)
### Description
Gets a vertex from a display list command if it has the correct op. Intended to be used with `gfx_parse`
Gets the op of the display list command
### Lua Example
`local PointerValue = gfx_get_vtx(gfx, offset)`
### Parameters
| Field | Type |
| ----- | ---- |
| gfx | `Pointer` <`Gfx`> |
| offset | `integer` |
### Returns
- `Pointer` <`Vtx`>
### C Prototype
`Vtx *gfx_get_vtx(Gfx* gfx, u16 offset);`
[:arrow_up_small:](#)
<br />
## [gfx_get_vtx_count](#gfx_get_vtx_count)
### Description
Gets the number of vertices from a display list command if it has the correct op
### Lua Example
`local integerValue = gfx_get_vtx_count(cmd)`
`local integerValue = gfx_get_op(cmd)`
### Parameters
| Field | Type |
@ -515,73 +491,408 @@ Gets the number of vertices from a display list command if it has the correct op
- `integer`
### C Prototype
`u16 gfx_get_vtx_count(Gfx* cmd);`
`u32 gfx_get_op(Gfx *cmd);`
[:arrow_up_small:](#)
<br />
## [gfx_set_combine_lerp](#gfx_set_combine_lerp)
## [gfx_get_display_list](#gfx_get_display_list)
### Description
Sets the display list combine mode. you can fill this function with G_CCMUX_* and G_ACMUX_* constants
Gets the display list from a display list command if it has the op `G_DL`
### Lua Example
`gfx_set_combine_lerp(gfx, a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1)`
`local PointerValue = gfx_get_display_list(cmd)`
### Parameters
| Field | Type |
| ----- | ---- |
| gfx | `Pointer` <`Gfx`> |
| a0 | `integer` |
| b0 | `integer` |
| c0 | `integer` |
| d0 | `integer` |
| Aa0 | `integer` |
| Ab0 | `integer` |
| Ac0 | `integer` |
| Ad0 | `integer` |
| a1 | `integer` |
| b1 | `integer` |
| c1 | `integer` |
| d1 | `integer` |
| Aa1 | `integer` |
| Ab1 | `integer` |
| Ac1 | `integer` |
| Ad1 | `integer` |
| cmd | `Pointer` <`Gfx`> |
### Returns
- None
- `Pointer` <`Gfx`>
### C Prototype
`void gfx_set_combine_lerp(Gfx* gfx, u32 a0, u32 b0, u32 c0, u32 d0, u32 Aa0, u32 Ab0, u32 Ac0, u32 Ad0, u32 a1, u32 b1, u32 c1, u32 d1, u32 Aa1, u32 Ab1, u32 Ac1, u32 Ad1);`
`Gfx *gfx_get_display_list(Gfx *cmd);`
[:arrow_up_small:](#)
<br />
## [gfx_set_texture_image](#gfx_set_texture_image)
## [gfx_get_vertex_buffer](#gfx_get_vertex_buffer)
### Description
Sets the display list texture image. Pass in textureInfo.texture as `texture`
Gets the vertex buffer from a display list command if it has the op `G_VTX`
### Lua Example
`gfx_set_texture_image(gfx, format, size, width, texture)`
`local PointerValue = gfx_get_vertex_buffer(cmd)`
### Parameters
| Field | Type |
| ----- | ---- |
| cmd | `Pointer` <`Gfx`> |
### Returns
- `Pointer` <`Vtx`>
### C Prototype
`Vtx *gfx_get_vertex_buffer(Gfx *cmd);`
[:arrow_up_small:](#)
<br />
## [gfx_get_vertex_count](#gfx_get_vertex_count)
### Description
Gets the number of vertices from a display list command if it has the op `G_VTX`
### Lua Example
`local integerValue = gfx_get_vertex_count(cmd)`
### Parameters
| Field | Type |
| ----- | ---- |
| cmd | `Pointer` <`Gfx`> |
### Returns
- `integer`
### C Prototype
`u16 gfx_get_vertex_count(Gfx *cmd);`
[:arrow_up_small:](#)
<br />
## [gfx_get_length](#gfx_get_length)
### Description
Gets the max length of a display list
### Lua Example
`local integerValue = gfx_get_length(gfx)`
### Parameters
| Field | Type |
| ----- | ---- |
| gfx | `Pointer` <`Gfx`> |
| format | `integer` |
| size | `integer` |
| width | `integer` |
| texture | `Pointer` <`integer`> |
### Returns
- `integer`
### C Prototype
`u32 gfx_get_length(Gfx *gfx);`
[:arrow_up_small:](#)
<br />
## [gfx_get_command](#gfx_get_command)
### Description
Gets a command of a display list at position `offset`
### Lua Example
`local PointerValue = gfx_get_command(gfx, offset)`
### Parameters
| Field | Type |
| ----- | ---- |
| gfx | `Pointer` <`Gfx`> |
| offset | `integer` |
### Returns
- `Pointer` <`Gfx`>
### C Prototype
`Gfx *gfx_get_command(Gfx *gfx, u32 offset);`
[:arrow_up_small:](#)
<br />
## [gfx_get_next_command](#gfx_get_next_command)
### Description
Gets the next command of a given display list pointer. Intended to use in a for loop
### Lua Example
`local PointerValue = gfx_get_next_command(gfx)`
### Parameters
| Field | Type |
| ----- | ---- |
| gfx | `Pointer` <`Gfx`> |
### Returns
- `Pointer` <`Gfx`>
### C Prototype
`Gfx *gfx_get_next_command(Gfx *gfx);`
[:arrow_up_small:](#)
<br />
## [gfx_copy](#gfx_copy)
### Description
Copies `length` commands from display list `src` to display list `dest`
### Lua Example
`gfx_copy(dest, src, length)`
### Parameters
| Field | Type |
| ----- | ---- |
| dest | `Pointer` <`Gfx`> |
| src | `Pointer` <`Gfx`> |
| length | `integer` |
### Returns
- None
### C Prototype
`void gfx_set_texture_image(Gfx* gfx, u32 format, u32 size, u32 width, u8* texture);`
`void gfx_copy(Gfx *dest, Gfx *src, u32 length);`
[:arrow_up_small:](#)
<br />
## [gfx_new](#gfx_new)
### Description
Creates a new named display list of `length` commands
### Lua Example
`local PointerValue = gfx_new(name, length)`
### Parameters
| Field | Type |
| ----- | ---- |
| name | `string` |
| length | `integer` |
### Returns
- `Pointer` <`Gfx`>
### C Prototype
`Gfx *gfx_new(const char *name, u32 length);`
[:arrow_up_small:](#)
<br />
## [gfx_realloc](#gfx_realloc)
### Description
Reallocates a display list created by `gfx_new` to modify its length
### Lua Example
`local PointerValue = gfx_realloc(gfx, newLength)`
### Parameters
| Field | Type |
| ----- | ---- |
| gfx | `Pointer` <`Gfx`> |
| newLength | `integer` |
### Returns
- `Pointer` <`Gfx`>
### C Prototype
`Gfx *gfx_realloc(Gfx *gfx, u32 newLength);`
[:arrow_up_small:](#)
<br />
## [gfx_delete](#gfx_delete)
### Description
Deletes a display list created by `gfx_new`
### Lua Example
`gfx_delete(gfx)`
### Parameters
| Field | Type |
| ----- | ---- |
| gfx | `Pointer` <`Gfx`> |
### Returns
- None
### C Prototype
`void gfx_delete(Gfx *gfx);`
[:arrow_up_small:](#)
<br />
## [vtx_get_count](#vtx_get_count)
### Description
Gets the max count of vertices of a vertex buffer
### Lua Example
`local integerValue = vtx_get_count(vtx)`
### Parameters
| Field | Type |
| ----- | ---- |
| vtx | `Pointer` <`Vtx`> |
### Returns
- `integer`
### C Prototype
`u32 vtx_get_count(Vtx *vtx);`
[:arrow_up_small:](#)
<br />
## [vtx_get_vertex](#vtx_get_vertex)
### Description
Gets a vertex of a vertex buffer at position `offset`
### Lua Example
`local PointerValue = vtx_get_vertex(vtx, offset)`
### Parameters
| Field | Type |
| ----- | ---- |
| vtx | `Pointer` <`Vtx`> |
| offset | `integer` |
### Returns
- `Pointer` <`Vtx`>
### C Prototype
`Vtx *vtx_get_vertex(Vtx *vtx, u32 offset);`
[:arrow_up_small:](#)
<br />
## [vtx_get_next_vertex](#vtx_get_next_vertex)
### Description
Gets the next vertex of a given vertex pointer. Intended to use in a for loop
### Lua Example
`local PointerValue = vtx_get_next_vertex(vtx)`
### Parameters
| Field | Type |
| ----- | ---- |
| vtx | `Pointer` <`Vtx`> |
### Returns
- `Pointer` <`Vtx`>
### C Prototype
`Vtx *vtx_get_next_vertex(Vtx *vtx);`
[:arrow_up_small:](#)
<br />
## [vtx_copy](#vtx_copy)
### Description
Copies `count` vertices from vertex buffer `src` to vertex buffer `dest`
### Lua Example
`vtx_copy(dest, src, count)`
### Parameters
| Field | Type |
| ----- | ---- |
| dest | `Pointer` <`Vtx`> |
| src | `Pointer` <`Vtx`> |
| count | `integer` |
### Returns
- None
### C Prototype
`void vtx_copy(Vtx *dest, Vtx *src, u32 count);`
[:arrow_up_small:](#)
<br />
## [vtx_new](#vtx_new)
### Description
Creates a new named vertex buffer of `count` vertices
### Lua Example
`local PointerValue = vtx_new(name, count)`
### Parameters
| Field | Type |
| ----- | ---- |
| name | `string` |
| count | `integer` |
### Returns
- `Pointer` <`Vtx`>
### C Prototype
`Vtx *vtx_new(const char *name, u32 count);`
[:arrow_up_small:](#)
<br />
## [vtx_realloc](#vtx_realloc)
### Description
Reallocates a vertex buffer created by `vtx_new` to modify its count
### Lua Example
`local PointerValue = vtx_realloc(vtx, newCount)`
### Parameters
| Field | Type |
| ----- | ---- |
| vtx | `Pointer` <`Vtx`> |
| newCount | `integer` |
### Returns
- `Pointer` <`Vtx`>
### C Prototype
`Vtx *vtx_realloc(Vtx *vtx, u32 newCount);`
[:arrow_up_small:](#)
<br />
## [vtx_delete](#vtx_delete)
### Description
Deletes a vertex buffer created by `vtx_new`
### Lua Example
`vtx_delete(vtx)`
### Parameters
| Field | Type |
| ----- | ---- |
| vtx | `Pointer` <`Vtx`> |
### Returns
- None
### C Prototype
`void vtx_delete(Vtx *vtx);`
[:arrow_up_small:](#)

View file

@ -1785,10 +1785,24 @@
- [get_skybox_color](functions-6.md#get_skybox_color)
- [set_skybox_color](functions-6.md#set_skybox_color)
- [gfx_parse](functions-6.md#gfx_parse)
- [gfx_get_vtx](functions-6.md#gfx_get_vtx)
- [gfx_get_vtx_count](functions-6.md#gfx_get_vtx_count)
- [gfx_set_combine_lerp](functions-6.md#gfx_set_combine_lerp)
- [gfx_set_texture_image](functions-6.md#gfx_set_texture_image)
- [gfx_get_op](functions-6.md#gfx_get_op)
- [gfx_get_display_list](functions-6.md#gfx_get_display_list)
- [gfx_get_vertex_buffer](functions-6.md#gfx_get_vertex_buffer)
- [gfx_get_vertex_count](functions-6.md#gfx_get_vertex_count)
- [gfx_get_length](functions-6.md#gfx_get_length)
- [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_delete](functions-6.md#gfx_delete)
- [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_delete](functions-6.md#vtx_delete)
<br />
@ -2563,11 +2577,30 @@ N/A
## [gfx_set_command](#gfx_set_command)
Sets the specified display list command on the display list given.
Sets a display list command on the display list given.
### Lua Example
If `command` includes parameter specifiers (subsequences beginning with `%`), the additional arguments following `command` are converted and inserted in `command` replacing their respective specifiers.
The number of provided parameters must be equal to the number of specifiers in `command`, and the order of parameters must be the same as the specifiers.
The following specifiers are allowed:
- `%i` for an `integer` parameter
- `%s` for a `string` parameter
- `%v` for a `Vtx` parameter
- `%t` for a `Texture` parameter
- `%g` for a `Gfx` parameter
### Lua Examples
Plain string:
```lua
gfx_set_command(gfx, "gsDPSetEnvColor", 0x00, 0xFF, 0x00, 0xFF)
gfx_set_command(gfx, "gsDPSetEnvColor(0x00, 0xFF, 0x00, 0xFF)")
```
With parameter specifiers:
```lua
r, g, b, a = 0x00, 0xFF, 0x00, 0xFF
gfx_set_command(gfx, "gsDPSetEnvColor(%i, %i, %i, %i)", r, g, b, a)
```
### Parameters
@ -2575,7 +2608,7 @@ gfx_set_command(gfx, "gsDPSetEnvColor", 0x00, 0xFF, 0x00, 0xFF)
| ----- | ---- |
| gfx | [Gfx](structs.md#Gfx) |
| command | `string` |
| (Any number of arguments) | `integer` |
| parameters... | any of `integer`, `string`, `Gfx`, `Texture`, `Vtx` |
### Returns
- None

View file

@ -3249,10 +3249,19 @@
| Field | Type | Access |
| ----- | ---- | ------ |
| cn | `Array` <`integer`> | |
| a | `integer` | |
| b | `integer` | |
| flag | `integer` | |
| ob | `Array` <`number`> | |
| tc | `Array` <`integer`> | |
| g | `integer` | |
| nx | `integer` | |
| ny | `integer` | |
| nz | `integer` | |
| r | `integer` | |
| tu | `integer` | |
| tv | `integer` | |
| x | `number` | |
| y | `number` | |
| z | `number` | |
[:arrow_up_small:](#)

View file

@ -95,6 +95,10 @@
# define GBI_FLOATS
#endif
#ifndef GBI_NO_MULTI_COMMANDS
# define GBI_NO_MULTI_COMMANDS
#endif
#ifdef F3DEX_GBI_2
# ifndef F3DEX_GBI
# define F3DEX_GBI
@ -1133,10 +1137,33 @@ typedef struct {
unsigned char a; /* alpha */
} Vtx_tn;
typedef struct {
float x;
float y;
float z;
unsigned short flag;
short tu;
short tv;
union {
unsigned char r;
signed char nx;
};
union {
unsigned char g;
signed char ny;
};
union {
unsigned char b;
signed char nz;
};
unsigned char a;
} Vtx_L;
typedef union {
Vtx_t v; /* Use this one for colors */
Vtx_tn n; /* Use this one for normals */
long long int force_structure_alignment;
Vtx_t v; /* Use this one for colors */
Vtx_tn n; /* Use this one for normals */
Vtx_L l; /* Use this one for Lua */
long long int force_structure_alignment;
} Vtx;
/*
@ -4457,6 +4484,22 @@ typedef union {
}}
/* Fraction never used in fill */
#ifdef GBI_NO_MULTI_COMMANDS
#define gDPFillRectangle(pkt, ulx, uly, lrx, lry) \
{ \
Gfx *_g = (Gfx *) pkt; \
_g->words.w0 = _SHIFTL(G_FILLRECT, 24, 8) | _SHIFTL((uly), 12, 12) | _SHIFTL((lry), 0, 12); \
_g->words.w1 = _SHIFTL((ulx), 16, 16) | _SHIFTL((lrx), 0, 16); \
}
#define gsDPFillRectangle(ulx, uly, lrx, lry) \
{{ \
_SHIFTL(G_FILLRECT, 24, 8) | _SHIFTL((uly), 12, 12) | _SHIFTL((lry), 0, 12), \
_SHIFTL((ulx), 16, 16) | _SHIFTL((lrx), 0, 16), \
}}
#else
#ifdef F3DEX_GBI_2E
#define gDPFillRectangle(pkt, ulx, uly, lrx, lry) \
{ \
@ -4492,6 +4535,7 @@ typedef union {
(_SHIFTL((ulx), 14, 10) | _SHIFTL((uly), 2, 10)) \
}}
#endif
#endif
/* like gDPFillRectangle but accepts negative arguments */
#ifndef F3DEX_GBI_2E
@ -4590,6 +4634,7 @@ typedef union {
* under normal circumstances (use gsSPTextureRectangle()).
* That is also why there is no gDPTextureRectangle() macros.
*/
#if 0 // DO NOT USE
#define gsDPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
{{ \
(_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | \
@ -4637,7 +4682,50 @@ typedef union {
_g->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)); \
_g->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \
}
#endif
#ifdef GBI_NO_MULTI_COMMANDS
#define gSPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
{ \
Gfx *_g = (Gfx *) (pkt); \
_g->words.w0 = _SHIFTL(G_TEXRECT, 24, 8) | \
_SHIFTL((xh) >> 2, 13, 11) | \
_SHIFTL((yh) >> 2, 4, 9) | \
_SHIFTL((dtdy) >> 6, 0, 4); /* decimal part */ \
_g->words.w1 = _SHIFTL((xl) >> 2, 21, 11) | \
_SHIFTL((yl) >> 2, 12, 9) | \
_SHIFTL((dsdx) >> 6, 4, 8) | \
_SHIFTL((dtdy) >> 10, 0, 4); /* integer part */ \
}
#define gsSPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
{{ \
_SHIFTL(G_TEXRECT, 24, 8) | \
_SHIFTL((xh) >> 2, 13, 11) | \
_SHIFTL((yh) >> 2, 4, 9) | \
_SHIFTL((dtdy) >> 6, 0, 4), /* decimal part */ \
\
_SHIFTL((xl) >> 2, 21, 11) | \
_SHIFTL((yl) >> 2, 12, 9) | \
_SHIFTL((dsdx) >> 6, 4, 8) | \
_SHIFTL((dtdy) >> 10, 0, 4) /* integer part */ \
}}
#define gSPTextureRectangleFlip(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
{ \
Gfx *_g = (Gfx *) (pkt); \
_g->words.w0 = _SHIFTL(G_TEXRECTFLIP, 24, 8) | \
_SHIFTL((xh) >> 2, 13, 11) | \
_SHIFTL((yh) >> 2, 4, 9) | \
_SHIFTL((dtdy) >> 6, 0, 4); /* decimal part */ \
_g->words.w1 = _SHIFTL((xl) >> 2, 21, 11) | \
_SHIFTL((yl) >> 2, 12, 9) | \
_SHIFTL((dsdx) >> 6, 4, 8) | \
_SHIFTL((dtdy) >> 10, 0, 4); /* integer part */ \
}
#else
#ifdef F3D_OLD
# define gSPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)\
{ \
@ -4809,6 +4897,7 @@ typedef union {
gImmp1(pkt, G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16))); \
}
#endif
#endif
#define gsDPWord(wordhi, wordlo) \
gsImmp1(G_RDPHALF_1, (uintptr_t)(wordhi)), \

View file

@ -1,25 +0,0 @@
#include "display_list.h"
// Get the size of a display list by iterating
// until gsSPEndDisplayList or gsSPBranchList is found
u32 gfx_get_size(const Gfx* gfx) {
for (u32 i = 0;;) {
u32 op = (gfx + i)->words.w0 >> 24;
u32 cmdSize = 1;
switch (op) {
case G_DL:
if (C0(gfx + i, 16, 1) == G_DL_NOPUSH) { return i + 1; } // For displaylists that end with branches (jumps)
break;
case G_ENDDL:
return i + 1;
case G_TEXRECT:
case G_TEXRECTFLIP:
cmdSize = 3;
break;
case G_FILLRECT:
cmdSize = 2;
break;
}
i += cmdSize;
}
}

View file

@ -1,5 +0,0 @@
#include <PR/gbi.h>
#define C0(cmd, pos, width) (((cmd)->words.w0 >> (pos)) & ((1U << width) - 1))
u32 gfx_get_size(const Gfx* gfx);

View file

@ -235,7 +235,7 @@ init_graph_node_translation_rotation(struct DynamicPool *pool,
vec3s_copy(graphNode->translation, translation);
vec3s_copy(graphNode->rotation, rotation);
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->displayList = dynos_model_get_writable_display_list(displayList);
graphNode->displayList = dynos_gfx_get_writable_display_list(displayList);
}
return graphNode;
@ -257,7 +257,7 @@ struct GraphNodeTranslation *init_graph_node_translation(struct DynamicPool *poo
vec3s_copy(graphNode->translation, translation);
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->displayList = dynos_model_get_writable_display_list(displayList);
graphNode->displayList = dynos_gfx_get_writable_display_list(displayList);
}
return graphNode;
@ -278,7 +278,7 @@ struct GraphNodeRotation *init_graph_node_rotation(struct DynamicPool *pool,
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_ROTATION);
vec3s_copy(graphNode->rotation, rotation);
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->displayList = dynos_model_get_writable_display_list(displayList);
graphNode->displayList = dynos_gfx_get_writable_display_list(displayList);
}
return graphNode;
@ -299,7 +299,7 @@ struct GraphNodeScale *init_graph_node_scale(struct DynamicPool *pool,
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->scale = scale;
graphNode->prevScale = scale;
graphNode->displayList = dynos_model_get_writable_display_list(displayList);
graphNode->displayList = dynos_gfx_get_writable_display_list(displayList);
}
return graphNode;
@ -369,7 +369,7 @@ struct GraphNodeAnimatedPart *init_graph_node_animated_part(struct DynamicPool *
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_ANIMATED_PART);
vec3s_copy(graphNode->translation, translation);
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->displayList = dynos_model_get_writable_display_list(displayList);
graphNode->displayList = dynos_gfx_get_writable_display_list(displayList);
}
return graphNode;
@ -390,7 +390,7 @@ struct GraphNodeBillboard *init_graph_node_billboard(struct DynamicPool *pool,
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_BILLBOARD);
vec3s_copy(graphNode->translation, translation);
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->displayList = dynos_model_get_writable_display_list(displayList);
graphNode->displayList = dynos_gfx_get_writable_display_list(displayList);
}
return graphNode;
@ -409,7 +409,7 @@ struct GraphNodeDisplayList *init_graph_node_display_list(struct DynamicPool *po
if (graphNode != NULL) {
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_DISPLAY_LIST);
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
graphNode->displayList = dynos_model_get_writable_display_list(displayList);
graphNode->displayList = dynos_gfx_get_writable_display_list(displayList);
}
return graphNode;

View file

@ -384,6 +384,9 @@ static void level_reset_globals(void) {
// free models stored in dynos
dynos_model_clear_pool(MODEL_POOL_LEVEL);
// clear the gfx command cache filled by gfx_set_command
dynos_smlua_clear_gfx_command_cache();
}
static void level_cmd_alloc_level_pool(void) {

View file

@ -770,6 +770,8 @@ static float gfx_adjust_x_for_aspect_ratio(float x) {
}
static void OPTIMIZE_O3 gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *vertices, bool luaVertexColor) {
if (!vertices) { return; }
float globalLightCached[2][3];
float vertexColorCached[3];
if (rsp.geometry_mode & G_LIGHTING) {
@ -1635,6 +1637,8 @@ static inline void *seg_addr(uintptr_t w1) {
#define C1(pos, width) ((cmd->words.w1 >> (pos)) & ((1U << width) - 1))
static void OPTIMIZE_O3 gfx_run_dl(Gfx* cmd) {
if (!cmd) { return; }
for (;;) {
uint32_t opcode = cmd->words.w0 >> 24;
@ -1788,6 +1792,16 @@ static void OPTIMIZE_O3 gfx_run_dl(Gfx* cmd) {
int32_t lrx, lry, tile, ulx, uly;
uint32_t uls, ult, dsdx, dtdy;
tile = 0;
#ifdef GBI_NO_MULTI_COMMANDS
lrx = (int32_t) (C0(13, 11) << 21) >> 19;
lry = (int32_t) (C0(4, 9) << 23) >> 21;
ulx = (int32_t) (C1(21, 11) << 21) >> 19;
uly = (int32_t) (C1(12, 9) << 23) >> 21;
uls = 0;
ult = 0;
dsdx = C1(4, 8) << 6;
dtdy = (C1(0, 4) << 10) | (C0(0, 4) << 6);
#else
#ifdef F3DEX_GBI_2E
lrx = (int32_t)(C0(0, 24) << 8) >> 8;
lry = (int32_t)(C1(0, 24) << 8) >> 8;
@ -1811,11 +1825,23 @@ static void OPTIMIZE_O3 gfx_run_dl(Gfx* cmd) {
++cmd;
dsdx = C1(16, 16);
dtdy = C1(0, 16);
#endif
#endif
gfx_dp_texture_rectangle(ulx, uly, lrx, lry, tile, uls, ult, dsdx, dtdy, opcode == G_TEXRECTFLIP);
break;
}
case G_FILLRECT:
#ifdef GBI_NO_MULTI_COMMANDS
{
int32_t lrx, lry, ulx, uly;
uly = (int32_t) (C0(12, 12) << 20) >> 18;
lry = (int32_t) (C0(0, 12) << 20) >> 18;
ulx = (int32_t) (C1(16, 16) << 16) >> 14;
lrx = (int32_t) (C1(0, 16) << 16) >> 14;
gfx_dp_fill_rectangle(ulx, uly, lrx, lry);
break;
}
#else
#ifdef F3DEX_GBI_2E
{
int32_t lrx, lry, ulx, uly;
@ -1830,6 +1856,7 @@ static void OPTIMIZE_O3 gfx_run_dl(Gfx* cmd) {
#else
gfx_dp_fill_rectangle(C1(12, 12), C1(0, 12), C0(12, 12), C0(0, 12));
break;
#endif
#endif
case G_SETSCISSOR:
gfx_dp_set_scissor(C1(24, 2), C0(12, 12), C0(0, 12), C1(12, 12), C1(0, 12));

View file

@ -2703,12 +2703,21 @@ static struct LuaObjectField sTransitionInfoFields[LUA_TRANSITION_INFO_FIELD_COU
{ "posYaw", LVT_S16, offsetof(struct TransitionInfo, posYaw), false, LOT_NONE, 1, sizeof(s16) },
};
#define LUA_VTX_FIELD_COUNT 4
#define LUA_VTX_FIELD_COUNT 13
static struct LuaObjectField sVtxFields[LUA_VTX_FIELD_COUNT] = {
{ "cn", LVT_U8, offsetof(Vtx_t, cn), false, LOT_NONE, 4, sizeof(unsigned char) },
{ "flag", LVT_U16, offsetof(Vtx_t, flag), false, LOT_NONE, 1, sizeof(unsigned short) },
{ "ob", LVT_F32, offsetof(Vtx_t, ob), false, LOT_NONE, 3, sizeof(float) },
{ "tc", LVT_S16, offsetof(Vtx_t, tc), false, LOT_NONE, 2, sizeof(short) },
{ "a", LVT_U8, offsetof(Vtx_L, a), false, LOT_NONE, 1, sizeof(unsigned char) },
{ "b", LVT_U8, offsetof(Vtx_L, b), false, LOT_NONE, 1, sizeof(unsigned char) },
{ "flag", LVT_U16, offsetof(Vtx_L, flag), false, LOT_NONE, 1, sizeof(unsigned short) },
{ "g", LVT_U8, offsetof(Vtx_L, g), false, LOT_NONE, 1, sizeof(unsigned char) },
{ "nx", LVT_S8, offsetof(Vtx_L, nx), false, LOT_NONE, 1, sizeof(signed char) },
{ "ny", LVT_S8, offsetof(Vtx_L, ny), false, LOT_NONE, 1, sizeof(signed char) },
{ "nz", LVT_S8, offsetof(Vtx_L, nz), false, LOT_NONE, 1, sizeof(signed char) },
{ "r", LVT_U8, offsetof(Vtx_L, r), false, LOT_NONE, 1, sizeof(unsigned char) },
{ "tu", LVT_S16, offsetof(Vtx_L, tu), false, LOT_NONE, 1, sizeof(short) },
{ "tv", LVT_S16, offsetof(Vtx_L, tv), false, LOT_NONE, 1, sizeof(short) },
{ "x", LVT_F32, offsetof(Vtx_L, x), false, LOT_NONE, 1, sizeof(float) },
{ "y", LVT_F32, offsetof(Vtx_L, y), false, LOT_NONE, 1, sizeof(float) },
{ "z", LVT_F32, offsetof(Vtx_L, z), false, LOT_NONE, 1, sizeof(float) },
};
#define LUA_VTX__INTERP_FIELD_COUNT 2

View file

@ -1313,59 +1313,31 @@ char gSmluaConstants[] = ""
"G_COPYMEM=0xd2\n"
#ifdef F3DEX_GBI_2
"G_NOOP=0x00\n"
"G_RDPHALF_2=0xf1\n"
"G_SETOTHERMODE_H=0xe3\n"
"G_SETOTHERMODE_L=0xe2\n"
"G_RDPHALF_1=0xe1\n"
"G_SPNOOP=0xe0\n"
"G_ENDDL=0xdf\n"
"G_DL=0xde\n"
"G_LOAD_UCODE=0xdd\n"
"G_MOVEMEM=0xdc\n"
"G_MOVEWORD=0xdb\n"
"G_MTX=0xda\n"
"G_GEOMETRYMODE=0xd9\n"
"G_POPMTX=0xd8\n"
"G_TEXTURE=0xd7\n"
"G_DMA_IO=0xd6\n"
"G_SPECIAL_1=0xd5\n"
"G_SPECIAL_2=0xd4\n"
"G_SPECIAL_3=0xd3\n"
"G_VTX=0x01\n"
"G_MODIFYVTX=0x02\n"
"G_CULLDL=0x03\n"
"G_BRANCH_Z=0x04\n"
"G_TRI1=0x05\n"
"G_TRI2=0x06\n"
"G_QUAD=0x07\n"
"G_LINE3D=0x08\n"
#else // #ifdef F3DEX_GBI_2
"G_SPNOOP=0\n"
"G_MTX=1\n"
"G_RESERVED0=2\n"
"G_MOVEMEM=3\n"
"G_VTX=4\n"
"G_RESERVED1=5\n"
"G_DL=6\n"
"G_RESERVED2=7\n"
"G_RESERVED3=8\n"
"G_SPRITE2D_BASE=9\n"
"G_IMMFIRST=-65\n"
"G_TRI1=(G_IMMFIRST-0)\n"
"G_CULLDL=(G_IMMFIRST-1)\n"
"G_POPMTX=(G_IMMFIRST-2)\n"
"G_MOVEWORD=(G_IMMFIRST-3)\n"
"G_TEXTURE=(G_IMMFIRST-4)\n"
"G_SETOTHERMODE_H=(G_IMMFIRST-5)\n"
"G_SETOTHERMODE_L=(G_IMMFIRST-6)\n"
"G_ENDDL=(G_IMMFIRST-7)\n"
"G_SETGEOMETRYMODE=(G_IMMFIRST-8)\n"
"G_CLEARGEOMETRYMODE=(G_IMMFIRST-9)\n"
"G_LINE3D=(G_IMMFIRST-10)\n"
"G_RDPHALF_1=(G_IMMFIRST-11)\n"
"G_RDPHALF_2=(G_IMMFIRST-12)\n"
"G_SPRITE2D_SCALEFLIP=(G_IMMFIRST-1)\n"
"G_SPRITE2D_DRAW=(G_IMMFIRST-2)\n"
"G_NOOP=0xc0\n"
#endif // #ifdef F3DEX_GBI_2
"G_SETCIMG=0xff\n"
@ -1383,325 +1355,9 @@ char gSmluaConstants[] = ""
"G_LOADBLOCK=0xf3\n"
"G_SETTILESIZE=0xf2\n"
"G_LOADTLUT=0xf0\n"
"G_RDPSETOTHERMODE=0xef\n"
"G_SETPRIMDEPTH=0xee\n"
"G_SETSCISSOR=0xed\n"
"G_SETCONVERT=0xec\n"
"G_SETKEYR=0xeb\n"
"G_SETKEYGB=0xea\n"
"G_RDPFULLSYNC=0xe9\n"
"G_RDPTILESYNC=0xe8\n"
"G_RDPPIPESYNC=0xe7\n"
"G_RDPLOADSYNC=0xe6\n"
"G_TEXRECTFLIP=0xe5\n"
"G_TEXRECT=0xe4\n"
"G_TRI_FILL=0xc8\n"
"G_TRI_SHADE=0xcc\n"
"G_TRI_TXTR=0xca\n"
"G_TRI_SHADE_TXTR=0xce\n"
"G_TRI_FILL_ZBUFF=0xc9\n"
"G_TRI_SHADE_ZBUFF=0xcd\n"
"G_TRI_TXTR_ZBUFF=0xcb\n"
"G_TRI_SHADE_TXTR_ZBUFF=0xcf\n"
"G_RDP_TRI_FILL_MASK=0x08\n"
"G_RDP_TRI_SHADE_MASK=0x04\n"
"G_RDP_TRI_TXTR_MASK=0x02\n"
"G_RDP_TRI_ZBUFF_MASK=0x01\n"
"BOWTIE_VAL=0\n"
"G_RDP_ADDR_FIXUP=3\n"
"G_DMACMDSIZ=128\n"
"G_IMMCMDSIZ=64\n"
"G_RDPCMDSIZ=64\n"
"G_TEXTURE_IMAGE_FRAC=2\n"
"G_TEXTURE_SCALE_FRAC=16\n"
"G_SCALE_FRAC=8\n"
"G_ROTATE_FRAC=16\n"
"G_MAXFBZ=0x3fff\n"
"G_ZBUFFER=0x00000001\n"
"G_SHADE=0x00000004\n"
"G_FOG=0x00010000\n"
"G_LIGHTING=0x00020000\n"
"G_TEXTURE_GEN=0x00040000\n"
"G_TEXTURE_GEN_LINEAR=0x00080000\n"
"G_LOD=0x00100000\n"
"G_IM_FMT_RGBA=0\n"
"G_IM_FMT_YUV=1\n"
"G_IM_FMT_CI=2\n"
"G_IM_FMT_IA=3\n"
"G_IM_FMT_I=4\n"
"G_IM_SIZ_4b=0\n"
"G_IM_SIZ_8b=1\n"
"G_IM_SIZ_16b=2\n"
"G_IM_SIZ_32b=3\n"
"G_IM_SIZ_DD=5\n"
"G_IM_SIZ_4b_BYTES=0\n"
"G_IM_SIZ_8b_BYTES=1\n"
"G_IM_SIZ_16b_BYTES=2\n"
"G_IM_SIZ_32b_BYTES=4\n"
"G_IM_SIZ_32b_TILE_BYTES=2\n"
"G_IM_SIZ_32b_LINE_BYTES=2\n"
"G_IM_SIZ_4b_SHIFT=2\n"
"G_IM_SIZ_8b_SHIFT=1\n"
"G_IM_SIZ_16b_SHIFT=0\n"
"G_IM_SIZ_32b_SHIFT=0\n"
"G_IM_SIZ_4b_INCR=3\n"
"G_IM_SIZ_8b_INCR=1\n"
"G_IM_SIZ_16b_INCR=0\n"
"G_IM_SIZ_32b_INCR=0\n"
"G_CCMUX_COMBINED=0\n"
"G_CCMUX_TEXEL0=1\n"
"G_CCMUX_TEXEL1=2\n"
"G_CCMUX_PRIMITIVE=3\n"
"G_CCMUX_SHADE=4\n"
"G_CCMUX_ENVIRONMENT=5\n"
"G_CCMUX_CENTER=6\n"
"G_CCMUX_SCALE=6\n"
"G_CCMUX_COMBINED_ALPHA=7\n"
"G_CCMUX_TEXEL0_ALPHA=8\n"
"G_CCMUX_TEXEL1_ALPHA=9\n"
"G_CCMUX_PRIMITIVE_ALPHA=10\n"
"G_CCMUX_SHADE_ALPHA=11\n"
"G_CCMUX_ENV_ALPHA=12\n"
"G_CCMUX_LOD_FRACTION=13\n"
"G_CCMUX_PRIM_LOD_FRAC=14\n"
"G_CCMUX_NOISE=7\n"
"G_CCMUX_K4=7\n"
"G_CCMUX_K5=15\n"
"G_CCMUX_1=6\n"
"G_CCMUX_0=31\n"
"G_ACMUX_COMBINED=0\n"
"G_ACMUX_TEXEL0=1\n"
"G_ACMUX_TEXEL1=2\n"
"G_ACMUX_PRIMITIVE=3\n"
"G_ACMUX_SHADE=4\n"
"G_ACMUX_ENVIRONMENT=5\n"
"G_ACMUX_LOD_FRACTION=0\n"
"G_ACMUX_PRIM_LOD_FRAC=6\n"
"G_ACMUX_1=6\n"
"G_ACMUX_0=7\n"
"G_MDSFT_ALPHACOMPARE=0\n"
"G_MDSFT_ZSRCSEL=2\n"
"G_MDSFT_RENDERMODE=3\n"
"G_MDSFT_BLENDER=16\n"
"G_MDSFT_BLENDMASK=0\n"
"G_MDSFT_ALPHADITHER=4\n"
"G_MDSFT_RGBDITHER=6\n"
"G_MDSFT_COMBKEY=8\n"
"G_MDSFT_TEXTCONV=9\n"
"G_MDSFT_TEXTFILT=12\n"
"G_MDSFT_TEXTLUT=14\n"
"G_MDSFT_TEXTLOD=16\n"
"G_MDSFT_TEXTDETAIL=17\n"
"G_MDSFT_TEXTPERSP=19\n"
"G_MDSFT_CYCLETYPE=20\n"
"G_MDSFT_COLORDITHER=22\n"
"G_MDSFT_PIPELINE=23\n"
"G_PM_1PRIMITIVE=(1 << G_MDSFT_PIPELINE)\n"
"G_PM_NPRIMITIVE=(0 << G_MDSFT_PIPELINE)\n"
"G_CYC_1CYCLE=(0 << G_MDSFT_CYCLETYPE)\n"
"G_CYC_2CYCLE=(1 << G_MDSFT_CYCLETYPE)\n"
"G_CYC_COPY=(2 << G_MDSFT_CYCLETYPE)\n"
"G_CYC_FILL=(3 << G_MDSFT_CYCLETYPE)\n"
"G_TP_NONE=(0 << G_MDSFT_TEXTPERSP)\n"
"G_TP_PERSP=(1 << G_MDSFT_TEXTPERSP)\n"
"G_TD_CLAMP=(0 << G_MDSFT_TEXTDETAIL)\n"
"G_TD_SHARPEN=(1 << G_MDSFT_TEXTDETAIL)\n"
"G_TD_DETAIL=(2 << G_MDSFT_TEXTDETAIL)\n"
"G_TL_TILE=(0 << G_MDSFT_TEXTLOD)\n"
"G_TL_LOD=(1 << G_MDSFT_TEXTLOD)\n"
"G_TT_NONE=(0 << G_MDSFT_TEXTLUT)\n"
"G_TT_RGBA16=(2 << G_MDSFT_TEXTLUT)\n"
"G_TT_IA16=(3 << G_MDSFT_TEXTLUT)\n"
"G_TF_POINT=(0 << G_MDSFT_TEXTFILT)\n"
"G_TF_AVERAGE=(3 << G_MDSFT_TEXTFILT)\n"
"G_TF_BILERP=(2 << G_MDSFT_TEXTFILT)\n"
"G_TC_CONV=(0 << G_MDSFT_TEXTCONV)\n"
"G_TC_FILTCONV=(5 << G_MDSFT_TEXTCONV)\n"
"G_TC_FILT=(6 << G_MDSFT_TEXTCONV)\n"
"G_CK_NONE=(0 << G_MDSFT_COMBKEY)\n"
"G_CK_KEY=(1 << G_MDSFT_COMBKEY)\n"
"G_CD_MAGICSQ=(0 << G_MDSFT_RGBDITHER)\n"
"G_CD_BAYER=(1 << G_MDSFT_RGBDITHER)\n"
"G_CD_NOISE=(2 << G_MDSFT_RGBDITHER)\n"
#ifndef _HW_VERSION_1
"G_CD_DISABLE=(3 << G_MDSFT_RGBDITHER)\n"
"G_CD_ENABLE=G_CD_NOISE\n"
#else // #ifndef _HW_VERSION_1
"G_CD_ENABLE=(1 << G_MDSFT_COLORDITHER)\n"
"G_CD_DISABLE=(0 << G_MDSFT_COLORDITHER)\n"
#endif // #ifndef _HW_VERSION_1
"G_AD_PATTERN=(0 << G_MDSFT_ALPHADITHER)\n"
"G_AD_NOTPATTERN=(1 << G_MDSFT_ALPHADITHER)\n"
"G_AD_NOISE=(2 << G_MDSFT_ALPHADITHER)\n"
"G_AD_DISABLE=(3 << G_MDSFT_ALPHADITHER)\n"
"G_AC_NONE=(0 << G_MDSFT_ALPHACOMPARE)\n"
"G_AC_THRESHOLD=(1 << G_MDSFT_ALPHACOMPARE)\n"
"G_AC_DITHER=(3 << G_MDSFT_ALPHACOMPARE)\n"
"G_ZS_PIXEL=(0 << G_MDSFT_ZSRCSEL)\n"
"G_ZS_PRIM=(1 << G_MDSFT_ZSRCSEL)\n"
"AA_EN=0x8\n"
"Z_CMP=0x10\n"
"Z_UPD=0x20\n"
"IM_RD=0x40\n"
"CLR_ON_CVG=0x80\n"
"CVG_DST_CLAMP=0\n"
"CVG_DST_WRAP=0x100\n"
"CVG_DST_FULL=0x200\n"
"CVG_DST_SAVE=0x300\n"
"ZMODE_OPA=0\n"
"ZMODE_INTER=0x400\n"
"ZMODE_XLU=0x800\n"
"ZMODE_DEC=0xc00\n"
"CVG_X_ALPHA=0x1000\n"
"ALPHA_CVG_SEL=0x2000\n"
"FORCE_BL=0x4000\n"
"TEX_EDGE=0x0000\n"
"G_BL_CLR_IN=0\n"
"G_BL_CLR_MEM=1\n"
"G_BL_CLR_BL=2\n"
"G_BL_CLR_FOG=3\n"
"G_BL_1MA=0\n"
"G_BL_A_MEM=1\n"
"G_BL_A_IN=0\n"
"G_BL_A_FOG=1\n"
"G_BL_A_SHADE=2\n"
"G_BL_1=2\n"
"G_BL_0=3\n"
"G_CV_K0=175\n"
"G_CV_K1=-43\n"
"G_CV_K2=-89\n"
"G_CV_K3=222\n"
"G_CV_K4=114\n"
"G_CV_K5=42\n"
"G_SC_NON_INTERLACE=0\n"
"G_SC_ODD_INTERLACE=3\n"
"G_SC_EVEN_INTERLACE=2\n"
"G_DL_PUSH=0x00\n"
"G_DL_NOPUSH=0x01\n"
"G_MW_MATRIX=0x00\n"
"G_MW_NUMLIGHT=0x02\n"
"G_MW_CLIP=0x04\n"
"G_MW_SEGMENT=0x06\n"
"G_MW_FOG=0x08\n"
"G_MW_LIGHTCOL=0x0a\n"
"G_MW_PERSPNORM=0x0e\n"
"G_MWO_NUMLIGHT=0x00\n"
"G_MWO_CLIP_RNX=0x04\n"
"G_MWO_CLIP_RNY=0x0c\n"
"G_MWO_CLIP_RPX=0x14\n"
"G_MWO_CLIP_RPY=0x1c\n"
"G_MWO_SEGMENT_0=0x00\n"
"G_MWO_SEGMENT_1=0x01\n"
"G_MWO_SEGMENT_2=0x02\n"
"G_MWO_SEGMENT_3=0x03\n"
"G_MWO_SEGMENT_4=0x04\n"
"G_MWO_SEGMENT_5=0x05\n"
"G_MWO_SEGMENT_6=0x06\n"
"G_MWO_SEGMENT_7=0x07\n"
"G_MWO_SEGMENT_8=0x08\n"
"G_MWO_SEGMENT_9=0x09\n"
"G_MWO_SEGMENT_A=0x0a\n"
"G_MWO_SEGMENT_B=0x0b\n"
"G_MWO_SEGMENT_C=0x0c\n"
"G_MWO_SEGMENT_D=0x0d\n"
"G_MWO_SEGMENT_E=0x0e\n"
"G_MWO_SEGMENT_F=0x0f\n"
"G_MWO_FOG=0x00\n"
"G_MWO_aLIGHT_1=0x00\n"
"G_MWO_bLIGHT_1=0x04\n"
#ifdef F3DEX_GBI_2
"G_MWO_aLIGHT_2=0x18\n"
"G_MWO_bLIGHT_2=0x1c\n"
"G_MWO_aLIGHT_3=0x30\n"
"G_MWO_bLIGHT_3=0x34\n"
"G_MWO_aLIGHT_4=0x48\n"
"G_MWO_bLIGHT_4=0x4c\n"
"G_MWO_aLIGHT_5=0x60\n"
"G_MWO_bLIGHT_5=0x64\n"
"G_MWO_aLIGHT_6=0x78\n"
"G_MWO_bLIGHT_6=0x7c\n"
"G_MWO_aLIGHT_7=0x90\n"
"G_MWO_bLIGHT_7=0x94\n"
"G_MWO_aLIGHT_8=0xa8\n"
"G_MWO_bLIGHT_8=0xac\n"
#else // #ifdef F3DEX_GBI_2
"G_MWO_aLIGHT_2=0x20\n"
"G_MWO_bLIGHT_2=0x24\n"
"G_MWO_aLIGHT_3=0x40\n"
"G_MWO_bLIGHT_3=0x44\n"
"G_MWO_aLIGHT_4=0x60\n"
"G_MWO_bLIGHT_4=0x64\n"
"G_MWO_aLIGHT_5=0x80\n"
"G_MWO_bLIGHT_5=0x84\n"
"G_MWO_aLIGHT_6=0xa0\n"
"G_MWO_bLIGHT_6=0xa4\n"
"G_MWO_aLIGHT_7=0xc0\n"
"G_MWO_bLIGHT_7=0xc4\n"
"G_MWO_aLIGHT_8=0xe0\n"
"G_MWO_bLIGHT_8=0xe4\n"
#endif // #ifdef F3DEX_GBI_2
"G_MWO_MATRIX_XX_XY_I=0x00\n"
"G_MWO_MATRIX_XZ_XW_I=0x04\n"
"G_MWO_MATRIX_YX_YY_I=0x08\n"
"G_MWO_MATRIX_YZ_YW_I=0x0c\n"
"G_MWO_MATRIX_ZX_ZY_I=0x10\n"
"G_MWO_MATRIX_ZZ_ZW_I=0x14\n"
"G_MWO_MATRIX_WX_WY_I=0x18\n"
"G_MWO_MATRIX_WZ_WW_I=0x1c\n"
"G_MWO_MATRIX_XX_XY_F=0x20\n"
"G_MWO_MATRIX_XZ_XW_F=0x24\n"
"G_MWO_MATRIX_YX_YY_F=0x28\n"
"G_MWO_MATRIX_YZ_YW_F=0x2c\n"
"G_MWO_MATRIX_ZX_ZY_F=0x30\n"
"G_MWO_MATRIX_ZZ_ZW_F=0x34\n"
"G_MWO_MATRIX_WX_WY_F=0x38\n"
"G_MWO_MATRIX_WZ_WW_F=0x3c\n"
"G_MWO_POINT_RGBA=0x10\n"
"G_MWO_POINT_ST=0x14\n"
"G_MWO_POINT_XYSCREEN=0x18\n"
"G_MWO_POINT_ZSCREEN=0x1c\n"
"FR_NEG_FRUSTRATIO_1=0x00000001\n"
"FR_POS_FRUSTRATIO_1=0x0000ffff\n"
"FR_NEG_FRUSTRATIO_2=0x00000002\n"
"FR_POS_FRUSTRATIO_2=0x0000fffe\n"
"FR_NEG_FRUSTRATIO_3=0x00000003\n"
"FR_POS_FRUSTRATIO_3=0x0000fffd\n"
"FR_NEG_FRUSTRATIO_4=0x00000004\n"
"FR_POS_FRUSTRATIO_4=0x0000fffc\n"
"FR_NEG_FRUSTRATIO_5=0x00000005\n"
"FR_POS_FRUSTRATIO_5=0x0000fffb\n"
"FR_NEG_FRUSTRATIO_6=0x00000006\n"
"FR_POS_FRUSTRATIO_6=0x0000fffa\n"
"NUMLIGHTS_0=1\n"
"NUMLIGHTS_1=1\n"
"NUMLIGHTS_2=2\n"
"NUMLIGHTS_3=3\n"
"NUMLIGHTS_4=4\n"
"NUMLIGHTS_5=5\n"
"NUMLIGHTS_6=6\n"
"NUMLIGHTS_7=7\n"
"LIGHT_1=1\n"
"LIGHT_2=2\n"
"LIGHT_3=3\n"
"LIGHT_4=4\n"
"LIGHT_5=5\n"
"LIGHT_6=6\n"
"LIGHT_7=7\n"
"LIGHT_8=8\n"
"G_TX_LOADTILE=7\n"
"G_TX_RENDERTILE=0\n"
"G_TX_NOMIRROR=0\n"
"G_TX_WRAP=0\n"
"G_TX_MIRROR=0x1\n"
"G_TX_CLAMP=0x2\n"
"G_TX_NOMASK=0\n"
"G_TX_NOLOD=0\n"
"G_TX_DXT_FRAC=11\n"
#ifdef _HW_VERSION_1
"G_TX_LDBLK_MAX_TXL=4095\n"
#else // #ifdef _HW_VERSION_1
"G_TX_LDBLK_MAX_TXL=2047\n"
#endif // #ifdef _HW_VERSION_1
"BACKGROUND_OCEAN_SKY=0\n"
"BACKGROUND_FLAMING_SKY=1\n"
"BACKGROUND_UNDERWATER_CITY=2\n"

View file

@ -1067,44 +1067,78 @@ int smlua_func_get_uncolored_string(lua_State* L) {
// display list //
//////////////////
#define HANDLE_PARAM(paramNum) \
s64 arg##paramNum = smlua_to_integer(L, 2 + paramNum); \
if (!gSmLuaConvertSuccess) { \
LOG_LUA("gfx_set_command: '%s' failed to convert parameter " #paramNum ".", symbolName); \
return 0; \
}
#define GET_ARG(paramNum) arg##paramNum
#define CALL_SYMB(symb, ...) symb(__VA_ARGS__)
// Uses macro iterators to dynamically handle the correct number of parameters
#define define_gfx_symbol(symb, params, ...) \
if (strcmp(command, #symb) == 0) { \
if (paramCount != params) { LOG_LUA("gfx_set_command: '" #symb "' received incorrect number of parameters. Received %u, expected %u", paramCount, params); return 0; } \
UNUSED const char symbolName[] = #symb; \
REPEAT(HANDLE_PARAM, params); \
const Gfx _Gfx[] = { CALL_SYMB(symb, LIST_ARGS(GET_ARG, params)) }; \
memcpy(gfx, _Gfx, sizeof(_Gfx)); \
return 1; \
static int get_gfx_command_specifiers_count(const char *command) {
int count = 0;
for (; *command; count += (*command == '%'), command++);
return count;
}
int smlua_func_gfx_set_command(lua_State* L) {
int top = lua_gettop(L);
if (top < 2) {
LOG_LUA_LINE("Improper param count: Expected at least 2, Received %u", top);
LOG_LUA_LINE("gfx_set_command: Improper param count: Expected at least 2, Received %u", top);
return 0;
}
Gfx* gfx = smlua_to_cobject(L, 1, LOT_GFX);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "gfx_set_command"); return 0; }
if (!gSmLuaConvertSuccess) {
LOG_LUA("gfx_set_command: Failed to convert parameter %u", 1);
return 0;
}
const char *command = smlua_to_string(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "gfx_set_command"); return 0; }
if (!gSmLuaConvertSuccess) {
LOG_LUA("gfx_set_command: Failed to convert parameter %u", 2);
return 0;
}
u16 paramCount = top - 2;
// Compare the number of provided parameters to the number of specifiers in the command
int paramCount = top - 2;
int specifiersCount = get_gfx_command_specifiers_count(command);
if (specifiersCount != paramCount) {
LOG_LUA_LINE("gfx_set_command: Command \"%s\": Invalid number of command parameters: Expected %u, provided %u", command, specifiersCount, paramCount);
return 0;
}
// Handle commands using the define_gfx_symbol macro
GFX_SYMBOLS();
// Parse the command
const u32 errorSize = 0x400;
char errorMsg[errorSize];
if (!dynos_smlua_parse_gfx_command(L, gfx, command, specifiersCount != 0, errorMsg, errorSize)) {
LOG_LUA_LINE("gfx_set_command: Command \"%s\": %s", command, errorMsg);
return 0;
}
return 1;
}
int smlua_func_gfx_get_from_name(lua_State *L) {
if (!smlua_functions_valid_param_count(L, 1)) { return 0; }
const char *name = smlua_to_string(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("gfx_get_from_name: Failed to convert parameter 1"); return 0; }
u32 length = 0;
Gfx *gfx = dynos_gfx_get(name, &length);
smlua_push_object(L, LOT_GFX, gfx, NULL);
lua_pushinteger(L, length);
return 2;
}
int smlua_func_vtx_get_from_name(lua_State *L) {
if (!smlua_functions_valid_param_count(L, 1)) { return 0; }
const char *name = smlua_to_string(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("vtx_get_from_name: Failed to convert parameter 1"); return 0; }
u32 count = 0;
Vtx *vtx = dynos_vtx_get(name, &count);
smlua_push_object(L, LOT_VTX, vtx, NULL);
lua_pushinteger(L, count);
return 2;
}
//////////
@ -1139,4 +1173,6 @@ void smlua_bind_functions(void) {
smlua_bind_function(L, "cast_graph_node", smlua_func_cast_graph_node);
smlua_bind_function(L, "get_uncolored_string", smlua_func_get_uncolored_string);
smlua_bind_function(L, "gfx_set_command", smlua_func_gfx_set_command);
smlua_bind_function(L, "gfx_get_from_name", smlua_func_gfx_get_from_name);
smlua_bind_function(L, "vtx_get_from_name", smlua_func_vtx_get_from_name);
}

View file

@ -30125,7 +30125,7 @@ int smlua_func_gfx_parse(lua_State* L) {
}
if (lua_isnil(L, 1)) { return 0; }
Gfx* cmd = (Gfx*)smlua_to_cobject(L, 1, LOT_GFX);
Gfx * cmd = (Gfx *)smlua_to_cobject(L, 1, LOT_GFX);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "gfx_parse"); return 0; }
LuaFunction func = smlua_to_lua_function(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "gfx_parse"); return 0; }
@ -30135,116 +30135,346 @@ int smlua_func_gfx_parse(lua_State* L) {
return 1;
}
int smlua_func_gfx_get_vtx(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_get_vtx", 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_get_vtx"); return 0; }
u16 offset = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "gfx_get_vtx"); return 0; }
smlua_push_object(L, LOT_VTX, gfx_get_vtx(gfx, offset), NULL);
return 1;
}
int smlua_func_gfx_get_vtx_count(lua_State* L) {
int smlua_func_gfx_get_op(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_get_vtx_count", 1, top);
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_get_op", 1, top);
return 0;
}
if (lua_isnil(L, 1)) { return 0; }
Gfx* cmd = (Gfx*)smlua_to_cobject(L, 1, LOT_GFX);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "gfx_get_vtx_count"); return 0; }
Gfx * cmd = (Gfx *)smlua_to_cobject(L, 1, LOT_GFX);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "gfx_get_op"); return 0; }
lua_pushinteger(L, gfx_get_vtx_count(cmd));
lua_pushinteger(L, gfx_get_op(cmd));
return 1;
}
int smlua_func_gfx_set_combine_lerp(lua_State* L) {
int smlua_func_gfx_get_display_list(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 17) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_set_combine_lerp", 17, top);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_get_display_list", 1, 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_set_combine_lerp"); return 0; }
u32 a0 = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "gfx_set_combine_lerp"); return 0; }
u32 b0 = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "gfx_set_combine_lerp"); return 0; }
u32 c0 = smlua_to_integer(L, 4);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 4, "gfx_set_combine_lerp"); return 0; }
u32 d0 = smlua_to_integer(L, 5);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 5, "gfx_set_combine_lerp"); return 0; }
u32 Aa0 = smlua_to_integer(L, 6);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 6, "gfx_set_combine_lerp"); return 0; }
u32 Ab0 = smlua_to_integer(L, 7);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 7, "gfx_set_combine_lerp"); return 0; }
u32 Ac0 = smlua_to_integer(L, 8);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 8, "gfx_set_combine_lerp"); return 0; }
u32 Ad0 = smlua_to_integer(L, 9);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 9, "gfx_set_combine_lerp"); return 0; }
u32 a1 = smlua_to_integer(L, 10);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 10, "gfx_set_combine_lerp"); return 0; }
u32 b1 = smlua_to_integer(L, 11);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 11, "gfx_set_combine_lerp"); return 0; }
u32 c1 = smlua_to_integer(L, 12);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 12, "gfx_set_combine_lerp"); return 0; }
u32 d1 = smlua_to_integer(L, 13);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 13, "gfx_set_combine_lerp"); return 0; }
u32 Aa1 = smlua_to_integer(L, 14);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 14, "gfx_set_combine_lerp"); return 0; }
u32 Ab1 = smlua_to_integer(L, 15);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 15, "gfx_set_combine_lerp"); return 0; }
u32 Ac1 = smlua_to_integer(L, 16);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 16, "gfx_set_combine_lerp"); return 0; }
u32 Ad1 = smlua_to_integer(L, 17);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 17, "gfx_set_combine_lerp"); return 0; }
Gfx * cmd = (Gfx *)smlua_to_cobject(L, 1, LOT_GFX);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "gfx_get_display_list"); return 0; }
gfx_set_combine_lerp(gfx, a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1);
smlua_push_object(L, LOT_GFX, gfx_get_display_list(cmd), NULL);
return 1;
}
int smlua_func_gfx_set_texture_image(lua_State* L) {
int smlua_func_gfx_get_vertex_buffer(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 5) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_set_texture_image", 5, top);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_get_vertex_buffer", 1, 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_set_texture_image"); return 0; }
u32 format = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "gfx_set_texture_image"); return 0; }
u32 size = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "gfx_set_texture_image"); return 0; }
u32 width = smlua_to_integer(L, 4);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 4, "gfx_set_texture_image"); return 0; }
u8* texture = (u8*)smlua_to_cpointer(L, 5, LVT_U8_P);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 5, "gfx_set_texture_image"); return 0; }
Gfx * cmd = (Gfx *)smlua_to_cobject(L, 1, LOT_GFX);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "gfx_get_vertex_buffer"); return 0; }
gfx_set_texture_image(gfx, format, size, width, texture);
smlua_push_object(L, LOT_VTX, gfx_get_vertex_buffer(cmd), NULL);
return 1;
}
int smlua_func_gfx_get_vertex_count(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_get_vertex_count", 1, top);
return 0;
}
if (lua_isnil(L, 1)) { return 0; }
Gfx * cmd = (Gfx *)smlua_to_cobject(L, 1, LOT_GFX);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "gfx_get_vertex_count"); return 0; }
lua_pushinteger(L, gfx_get_vertex_count(cmd));
return 1;
}
int smlua_func_gfx_get_length(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_get_length", 1, 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_get_length"); return 0; }
lua_pushinteger(L, gfx_get_length(gfx));
return 1;
}
int smlua_func_gfx_get_command(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_get_command", 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_get_command"); return 0; }
u32 offset = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "gfx_get_command"); return 0; }
smlua_push_object(L, LOT_GFX, gfx_get_command(gfx, offset), NULL);
return 1;
}
int smlua_func_gfx_get_next_command(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_get_next_command", 1, 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_get_next_command"); return 0; }
smlua_push_object(L, LOT_GFX, gfx_get_next_command(gfx), NULL);
return 1;
}
int smlua_func_gfx_copy(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 3) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_copy", 3, top);
return 0;
}
if (lua_isnil(L, 1)) { return 0; }
Gfx * dest = (Gfx *)smlua_to_cobject(L, 1, LOT_GFX);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "gfx_copy"); return 0; }
if (lua_isnil(L, 2)) { return 0; }
Gfx * src = (Gfx *)smlua_to_cobject(L, 2, LOT_GFX);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "gfx_copy"); return 0; }
u32 length = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "gfx_copy"); return 0; }
gfx_copy(dest, src, length);
return 1;
}
int smlua_func_gfx_new(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);
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; }
u32 length = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "gfx_new"); return 0; }
smlua_push_object(L, LOT_GFX, gfx_new(name, length), NULL);
return 1;
}
int smlua_func_gfx_realloc(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);
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; }
u32 newLength = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "gfx_realloc"); return 0; }
smlua_push_object(L, LOT_GFX, gfx_realloc(gfx, newLength), NULL);
return 1;
}
int smlua_func_gfx_delete(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "gfx_delete", 1, 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_delete"); return 0; }
gfx_delete(gfx);
return 1;
}
int smlua_func_vtx_get_count(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "vtx_get_count", 1, 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_get_count"); return 0; }
lua_pushinteger(L, vtx_get_count(vtx));
return 1;
}
int smlua_func_vtx_get_vertex(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_get_vertex", 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_get_vertex"); return 0; }
u32 offset = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "vtx_get_vertex"); return 0; }
smlua_push_object(L, LOT_VTX, vtx_get_vertex(vtx, offset), NULL);
return 1;
}
int smlua_func_vtx_get_next_vertex(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "vtx_get_next_vertex", 1, 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_get_next_vertex"); return 0; }
smlua_push_object(L, LOT_VTX, vtx_get_next_vertex(vtx), NULL);
return 1;
}
int smlua_func_vtx_copy(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 3) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "vtx_copy", 3, top);
return 0;
}
if (lua_isnil(L, 1)) { return 0; }
Vtx * dest = (Vtx *)smlua_to_cobject(L, 1, LOT_VTX);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "vtx_copy"); return 0; }
if (lua_isnil(L, 2)) { return 0; }
Vtx * src = (Vtx *)smlua_to_cobject(L, 2, LOT_VTX);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "vtx_copy"); return 0; }
u32 count = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "vtx_copy"); return 0; }
vtx_copy(dest, src, count);
return 1;
}
int smlua_func_vtx_new(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);
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; }
u32 count = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "vtx_new"); return 0; }
smlua_push_object(L, LOT_VTX, vtx_new(name, count), NULL);
return 1;
}
int smlua_func_vtx_realloc(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);
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; }
u32 newCount = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "vtx_realloc"); return 0; }
smlua_push_object(L, LOT_VTX, vtx_realloc(vtx, newCount), NULL);
return 1;
}
int smlua_func_vtx_delete(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "vtx_delete", 1, 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_delete"); return 0; }
vtx_delete(vtx);
return 1;
}
@ -35626,10 +35856,24 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "get_skybox_color", smlua_func_get_skybox_color);
smlua_bind_function(L, "set_skybox_color", smlua_func_set_skybox_color);
smlua_bind_function(L, "gfx_parse", smlua_func_gfx_parse);
smlua_bind_function(L, "gfx_get_vtx", smlua_func_gfx_get_vtx);
smlua_bind_function(L, "gfx_get_vtx_count", smlua_func_gfx_get_vtx_count);
smlua_bind_function(L, "gfx_set_combine_lerp", smlua_func_gfx_set_combine_lerp);
smlua_bind_function(L, "gfx_set_texture_image", smlua_func_gfx_set_texture_image);
smlua_bind_function(L, "gfx_get_op", smlua_func_gfx_get_op);
smlua_bind_function(L, "gfx_get_display_list", smlua_func_gfx_get_display_list);
smlua_bind_function(L, "gfx_get_vertex_buffer", smlua_func_gfx_get_vertex_buffer);
smlua_bind_function(L, "gfx_get_vertex_count", smlua_func_gfx_get_vertex_count);
smlua_bind_function(L, "gfx_get_length", smlua_func_gfx_get_length);
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_delete", smlua_func_gfx_delete);
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_delete", smlua_func_vtx_delete);
// smlua_level_utils.h
smlua_bind_function(L, "smlua_level_util_change_area", smlua_func_smlua_level_util_change_area);

View file

@ -3,7 +3,6 @@
#include "game/rendering_graph_node.h"
#include "game/skybox.h"
#include "geo_commands.h"
#include "engine/display_list.h"
void set_override_fov(f32 fov) {
gOverrideFOV = fov;
@ -108,16 +107,70 @@ void set_skybox_color(u8 index, u8 value) {
gSkyboxColor[index] = value;
}
///
///////////////////
// Display lists //
///////////////////
//
// The following code and functions assume the current microcode
// is Fast3DEX2 Extended, and all commands are of size 1
//
#ifndef GBI_NO_MULTI_COMMANDS
#error "GBI_NO_MULTI_COMMANDS not set: All GBI commands must be of size 1"
#endif
#ifndef F3DEX_GBI_2E
#error "F3DEX_GBI_2E not set: Microcode must be set to `f3dex2e`"
#endif
//
// Sentinel values for dynamically allocated Gfx and Vtx buffers
// It will prevent out-of-bounds accesses and buffer overflows
//
// SENTINEL_GFX is a gsSPEndDisplayList() with all other bits set
// SENTINEL_VTX bits are all set, which results in a bunch of NaN when treated as a Vtx
//
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));
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));
memcpy(vtx + count, SENTINEL_VTX, sizeof(Vtx));
return vtx;
}
// Get the size of a display list by iterating
// until gsSPEndDisplayList or gsSPBranchList is found
u32 gfx_get_length_no_sentinel(const Gfx *gfx) {
if (!gfx) { return 0; }
for (u32 i = 0;; ++i) {
u32 op = GFX_OP(gfx + i);
switch (op) {
case G_DL:
if (C0(gfx + i, 16, 1) == G_DL_NOPUSH) { return i + 1; } // For displaylists that end with branches (jumps)
break;
case G_ENDDL:
return i + 1;
}
}
}
// Assumes the current microcode is Fast3DEX2 Extended (default for pc port)
void gfx_parse(Gfx* cmd, LuaFunction func) {
if (!cmd) { return; }
if (func == 0) { return; }
lua_State* L = gLuaState;
while (true) {
u32 op = cmd->words.w0 >> 24;
for (;; cmd++) {
u32 op = GFX_OP(cmd);
switch (op) {
case G_DL:
if (C0(cmd, 16, 1) == G_DL_PUSH) {
@ -127,16 +180,10 @@ void gfx_parse(Gfx* cmd, LuaFunction func) {
--cmd;
}
break;
case (uint8_t) G_ENDDL:
return; // Reached end of display list
case G_TEXRECT:
case G_TEXRECTFLIP:
++cmd;
++cmd;
break;
case G_FILLRECT:
++cmd;
break;
default:
lua_rawgeti(L, LUA_REGISTRYINDEX, func);
smlua_push_object(L, LOT_GFX, cmd, NULL);
@ -149,37 +196,196 @@ void gfx_parse(Gfx* cmd, LuaFunction func) {
}
break;
}
++cmd;
}
}
Vtx *gfx_get_vtx(Gfx* cmd, u16 offset) {
u32 gfx_get_op(Gfx *cmd) {
if (!cmd) { return G_NOOP; }
return GFX_OP(cmd);
}
Gfx *gfx_get_display_list(Gfx *cmd) {
if (!cmd) { return NULL; }
u32 op = cmd->words.w0 >> 24;
u32 op = GFX_OP(cmd);
if (op != G_DL) { return NULL; }
if (cmd->words.w1 == 0) { return NULL; }
return (Gfx *) cmd->words.w1;
}
Vtx *gfx_get_vertex_buffer(Gfx *cmd) {
if (!cmd) { return NULL; }
u32 op = GFX_OP(cmd);
if (op != G_VTX) { return NULL; }
if (cmd->words.w1 == 0) { return NULL; }
u16 numVertices = C0(cmd, 12, 8);
if (offset >= numVertices) { return NULL; }
return &((Vtx *) cmd->words.w1)[offset];
return (Vtx *) cmd->words.w1;
}
u16 gfx_get_vtx_count(Gfx* cmd) {
u16 gfx_get_vertex_count(Gfx *cmd) {
if (!cmd) { return 0; }
u32 op = cmd->words.w0 >> 24;
u32 op = GFX_OP(cmd);
if (op != G_VTX) { return 0; }
if (cmd->words.w1 == 0) { return 0; }
return C0(cmd, 12, 8);
}
void gfx_set_combine_lerp(Gfx* gfx, u32 a0, u32 b0, u32 c0, u32 d0, u32 Aa0, u32 Ab0, u32 Ac0, u32 Ad0, u32 a1, u32 b1, u32 c1, u32 d1, u32 Aa1, u32 Ab1, u32 Ac1, u32 Ad1) {
if (!gfx) { return; }
gDPSetCombineLERPNoString(gfx, a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1);
u32 gfx_get_length(Gfx *gfx) {
if (!gfx) { return 0; }
u32 length = 0;
for (; memcmp(gfx, SENTINEL_GFX, sizeof(Gfx)) != 0; ++length, gfx++);
return length;
}
void gfx_set_texture_image(Gfx* gfx, u32 format, u32 size, u32 width, u8* texture) {
if (!gfx) { return; }
gDPSetTextureImage(gfx, format, size, width, texture);
Gfx *gfx_get_command(Gfx *gfx, u32 offset) {
if (!gfx) { return NULL; }
if (offset >= gfx_get_length(gfx)) { return NULL; }
return &gfx[offset];
}
Gfx *gfx_get_next_command(Gfx *gfx) {
if (!gfx) { return NULL; }
gfx++;
return memcmp(gfx, SENTINEL_GFX, sizeof(Gfx)) != 0 ? gfx : NULL;
}
void gfx_copy(Gfx *dest, Gfx *src, u32 length) {
if (!src || !dest || !length) { return; }
u32 srcLength = gfx_get_length(src);
if (length > srcLength) {
LOG_LUA_LINE("gfx_copy: Cannot copy %u commands from a display list of length: %u", length, srcLength);
return;
}
u32 destLength = gfx_get_length(dest);
if (length > destLength) {
LOG_LUA_LINE("gfx_copy: Cannot copy %u commands to a display list of length: %u", length, srcLength);
return;
}
memcpy(dest, src, length * sizeof(Gfx));
}
Gfx *gfx_new(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);
return NULL;
}
Gfx *gfx = dynos_gfx_new(name, length);
if (!gfx) {
LOG_LUA_LINE("gfx_new: Display list `%s` already exists", name);
return NULL;
}
return gfx;
}
Gfx *gfx_realloc(Gfx *gfx, u32 newLength) {
if (!gfx || !newLength) { return NULL; }
Gfx *newGfx = dynos_gfx_realloc(gfx, newLength);
if (!newGfx) {
LOG_LUA_LINE("gfx_realloc: Display list was not allocated by `gfx_new`");
return NULL;
}
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`");
}
}
u32 vtx_get_count(Vtx *vtx) {
if (!vtx) { return 0; }
u32 count = 0;
for (; memcmp(vtx, SENTINEL_VTX, sizeof(Vtx)) != 0; ++count, vtx++);
return count;
}
Vtx *vtx_get_vertex(Vtx *vtx, u32 offset) {
if (!vtx) { return NULL; }
if (offset >= vtx_get_count(vtx)) { return NULL; }
return &vtx[offset];
}
Vtx *vtx_get_next_vertex(Vtx *vtx) {
if (!vtx) { return NULL; }
vtx++;
return memcmp(vtx, SENTINEL_VTX, sizeof(Vtx)) != 0 ? vtx : NULL;
}
void vtx_copy(Vtx *dest, Vtx *src, u32 count) {
if (!src || !dest || !count) { return; }
u32 srcLength = vtx_get_count(src);
if (count > srcLength) {
LOG_LUA_LINE("vtx_copy: Cannot copy %u vertices from a vertex buffer of count: %u", count, srcLength);
return;
}
u32 destLength = vtx_get_count(dest);
if (count > destLength) {
LOG_LUA_LINE("vtx_copy: Cannot copy %u vertices to a vertex buffer of count: %u", count, srcLength);
return;
}
memcpy(dest, src, count * sizeof(Vtx));
}
Vtx *vtx_new(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);
return NULL;
}
Vtx *vtx = dynos_vtx_new(name, count);
if (!vtx) {
LOG_LUA_LINE("vtx_new: Vertex buffer `%s` already exists", name);
return NULL;
}
return vtx;
}
Vtx *vtx_realloc(Vtx *vtx, u32 newCount) {
if (!vtx || !newCount) { return NULL; }
Vtx *newVtx = dynos_vtx_realloc(vtx, newCount);
if (!newVtx) {
LOG_LUA_LINE("vtx_realloc: Vertex buffer was not allocated by `vtx_new`");
return NULL;
}
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`");
}
}

View file

@ -4,6 +4,13 @@
#include "pc/lua/smlua.h"
#include "types.h"
#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);
u32 gfx_get_length_no_sentinel(const Gfx *gfx);
/* |description|Sets the override FOV|descriptionEnd| */
void set_override_fov(f32 fov);
/* |description|Sets the override near plane|descriptionEnd| */
@ -49,14 +56,44 @@ u8 get_skybox_color(u8 index);
void set_skybox_color(u8 index, u8 value);
/* |description|Traverses a display list. Takes a Lua function as a parameter, which is called back for each command in the display list with the parameters `cmd` (display list pointer), and `op`|descriptionEnd| */
void gfx_parse(Gfx* cmd, LuaFunction func);
/* |description|Gets a vertex from a display list command if it has the correct op. Intended to be used with `gfx_parse`|descriptionEnd| */
Vtx *gfx_get_vtx(Gfx* gfx, u16 offset);
/* |description|Gets the number of vertices from a display list command if it has the correct op|descriptionEnd| */
u16 gfx_get_vtx_count(Gfx* cmd);
/* |description|Sets the display list combine mode. you can fill this function with G_CCMUX_* and G_ACMUX_* constants|descriptionEnd| */
void gfx_set_combine_lerp(Gfx* gfx, u32 a0, u32 b0, u32 c0, u32 d0, u32 Aa0, u32 Ab0, u32 Ac0, u32 Ad0, u32 a1, u32 b1, u32 c1, u32 d1, u32 Aa1, u32 Ab1, u32 Ac1, u32 Ad1);
/* |description|Sets the display list texture image. Pass in textureInfo.texture as `texture`|descriptionEnd| */
void gfx_set_texture_image(Gfx* gfx, u32 format, u32 size, u32 width, u8* texture);
void gfx_parse(Gfx *cmd, LuaFunction func);
/* |description|Gets the op of the display list command|descriptionEnd| */
u32 gfx_get_op(Gfx *cmd);
/* |description|Gets the display list from a display list command if it has the op `G_DL`|descriptionEnd| */
Gfx *gfx_get_display_list(Gfx *cmd);
/* |description|Gets the vertex buffer from a display list command if it has the op `G_VTX`|descriptionEnd| */
Vtx *gfx_get_vertex_buffer(Gfx *cmd);
/* |description|Gets the number of vertices from a display list command if it has the op `G_VTX`|descriptionEnd| */
u16 gfx_get_vertex_count(Gfx *cmd);
/* |description|Gets the max length of a display list|descriptionEnd| */
u32 gfx_get_length(Gfx *gfx);
/* |description|Gets a command of a display list at position `offset`|descriptionEnd| */
Gfx *gfx_get_command(Gfx *gfx, u32 offset);
/* |description|Gets the next command of a given display list pointer. Intended to use in a for loop|descriptionEnd| */
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| */
void gfx_delete(Gfx *gfx);
/* |description|Gets the max count of vertices of a vertex buffer|descriptionEnd| */
u32 vtx_get_count(Vtx *vtx);
/* |description|Gets a vertex of a vertex buffer at position `offset`|descriptionEnd| */
Vtx *vtx_get_vertex(Vtx *vtx, u32 offset);
/* |description|Gets the next vertex of a given vertex pointer. Intended to use in a for loop|descriptionEnd| */
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| */
void vtx_delete(Vtx *vtx);
#endif

View file

@ -668,7 +668,6 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup, bool reconnect
if (exiting) { return; }
dynos_model_clear_pool(MODEL_POOL_SESSION);
dynos_model_restore_vanilla_display_lists();
// reset other stuff
extern u8* gOverrideEeprom;