sm64coopdx/docs/lua/examples/gfx-vtx-demo/main.lua
PeachyPeach 0f351e11fb
Some checks failed
Build coop / build-windows (push) Has been cancelled
Build coop / build-ubuntu (push) Has been cancelled
Build coop / build-macos-arm (push) Has been cancelled
Build coop / build-macos-intel (push) Has been cancelled
Gfx/Vtx improvements (#756)
- Renamed the `new` and `realloc` functions to `create` and `resize`
- Added `delete_all`
- Made Mod Data a class:
  - Allocation is now limited to prevent out-of-memory crashes: 1024 display lists of max size 2048 and 1024 vertex buffers of max size 4096 per mod
  - Added error codes to identify the cause of a failure (name not found, pointer not found, max size exceeded, item pool is full, ...)
2025-04-24 14:03:17 +10:00

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)