mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2025-10-30 08:01:01 +00:00
- Renamed the `new` and `realloc` functions to `create` and `resize` - Added `delete_all` - Made Mod Data a class: - Allocation is now limited to prevent out-of-memory crashes: 1024 display lists of max size 2048 and 1024 vertex buffers of max size 4096 per mod - Added error codes to identify the cause of a failure (name not found, pointer not found, max size exceeded, item pool is full, ...)
204 lines
7 KiB
Lua
204 lines
7 KiB
Lua
-- name: Gfx and Vtx manipulation demo
|
|
-- description: Press X to spawn three different shapes orbiting around Mario.
|
|
|
|
local SHAPE_TEXTURES = {}
|
|
for i = 0, 10 do
|
|
SHAPE_TEXTURES[i] = get_texture_info("matrix_" .. i)
|
|
end
|
|
|
|
SHAPES = {
|
|
{
|
|
get_vertices = get_cube_vertices,
|
|
get_triangles = get_cube_triangles,
|
|
get_geometry_mode = get_cube_geometry_mode,
|
|
get_texture_scaling = get_cube_texture_scaling,
|
|
},
|
|
{
|
|
get_vertices = get_octahedron_vertices,
|
|
get_triangles = get_octahedron_triangles,
|
|
get_geometry_mode = get_octahedron_geometry_mode,
|
|
get_texture_scaling = get_octahedron_texture_scaling,
|
|
},
|
|
{
|
|
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 obj Object
|
|
--- Get a unique identifier for gfx and vtx allocation.
|
|
local function get_obj_identifier(obj)
|
|
return tostring(obj._pointer)
|
|
end
|
|
|
|
--- @param obj Object
|
|
--- @param gfx Gfx
|
|
--- Set the geometry mode of the current shape.
|
|
local function set_geometry_mode(obj, gfx)
|
|
local clear, set = SHAPES[obj.oAction].get_geometry_mode()
|
|
gfx_set_command(gfx, "gsSPGeometryMode(%s, %s)", clear, set)
|
|
end
|
|
|
|
--- @param obj Object
|
|
--- @param gfx Gfx
|
|
--- @param on integer
|
|
--- Toggle on/off the texture rendering and set the texture scaling.
|
|
local function set_texture_scaling(obj, gfx, on)
|
|
local scaling = SHAPES[obj.oAction].get_texture_scaling()
|
|
gfx_set_command(gfx, "gsSPTexture(%i, %i, 0, G_TX_RENDERTILE, %i)", scaling, scaling, on)
|
|
end
|
|
|
|
--- @param obj Object
|
|
--- @param gfx Gfx
|
|
--- Update the texture of the current shape.
|
|
local function update_texture(obj, gfx)
|
|
local texture = SHAPE_TEXTURES[obj.oAnimState].texture
|
|
gfx_set_command(gfx, "gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_32b, 1, %t)", texture)
|
|
end
|
|
|
|
--- @param obj Object
|
|
--- @param gfx Gfx
|
|
--- Compute the vertices of the current shape and fill the vertex buffer.
|
|
local function compute_vertices(obj, gfx)
|
|
local vertices = SHAPES[obj.oAction].get_vertices()
|
|
local num_vertices = #vertices
|
|
|
|
-- Create a new or retrieve an existing vertex buffer for the shape
|
|
-- Use the object pointer to form a unique identifier
|
|
local vtx_name = "shape_vertices_" .. get_obj_identifier(obj)
|
|
local vtx = vtx_get_from_name(vtx_name)
|
|
if vtx == nil then
|
|
vtx = vtx_create(vtx_name, num_vertices)
|
|
else
|
|
vtx_resize(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 obj Object
|
|
--- @param gfx Gfx
|
|
--- Build the triangles for the current shape.
|
|
local function build_triangles(obj, gfx)
|
|
local triangles = SHAPES[obj.oAction].get_triangles()
|
|
local num_triangles = #triangles
|
|
|
|
-- Create a new or retrieve an existing triangles display list for the shape
|
|
-- Use the object pointer to form a unique identifier
|
|
local tris_name = "shape_triangles_" .. get_obj_identifier(obj)
|
|
local tris = gfx_get_from_name(tris_name)
|
|
if tris == nil then
|
|
tris = gfx_create(tris_name, num_triangles + 1) -- +1 for the gsSPEndDisplayList command
|
|
else
|
|
gfx_resize(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_" .. get_obj_identifier(obj)
|
|
local gfx = gfx_get_from_name(gfx_name)
|
|
if gfx == nil then
|
|
|
|
-- Get and copy the template to the newly created display list
|
|
local gfx_template = gfx_get_from_name("shape_template_dl")
|
|
local gfx_template_length = gfx_get_length(gfx_template)
|
|
gfx = gfx_create(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(obj, cmd_geometry_mode)
|
|
|
|
-- Change the texture scaling
|
|
local cmd_texture_scaling_1 = gfx_get_command(gfx, 2)
|
|
set_texture_scaling(obj, cmd_texture_scaling_1, 1)
|
|
local cmd_texture_scaling_2 = gfx_get_command(gfx, 12)
|
|
set_texture_scaling(obj, cmd_texture_scaling_2, 0)
|
|
|
|
-- Update texture
|
|
local cmd_texture = gfx_get_command(gfx, 3)
|
|
update_texture(obj, cmd_texture)
|
|
|
|
-- Compute vertices
|
|
local cmd_vertices = gfx_get_command(gfx, 10)
|
|
compute_vertices(obj, cmd_vertices)
|
|
|
|
-- Build triangles
|
|
local cmd_triangles = gfx_get_command(gfx, 11)
|
|
build_triangles(obj, cmd_triangles)
|
|
|
|
-- Update the graph node display list
|
|
cast_graph_node(node.next).displayList = gfx
|
|
end
|
|
|
|
--- @param obj Object
|
|
--- Delete allocated gfx and vtx for this object.
|
|
local function on_object_unload(obj)
|
|
|
|
local gfx = gfx_get_from_name("shape_dl_" .. get_obj_identifier(obj))
|
|
if gfx then gfx_delete(gfx) end
|
|
|
|
local tris = gfx_get_from_name("shape_triangles_" .. get_obj_identifier(obj))
|
|
if tris then gfx_delete(tris) end
|
|
|
|
local vtx = vtx_get_from_name("shape_vertices_" .. get_obj_identifier(obj))
|
|
if vtx then vtx_delete(vtx) end
|
|
end
|
|
|
|
hook_event(HOOK_ON_OBJECT_UNLOAD, on_object_unload)
|