Skip to content

Instantly share code, notes, and snippets.

@x4fx77x4f
Last active April 21, 2021 04:09
Show Gist options
  • Save x4fx77x4f/cc9415ff66c0fcf5efe1fd5e17bdc67b to your computer and use it in GitHub Desktop.
Save x4fx77x4f/cc9415ff66c0fcf5efe1fd5e17bdc67b to your computer and use it in GitHub Desktop.
Tests relating to loading and displaying the Super Mario 64 logo in StarfallEx
--@name Super Mario 64
--@client
-- assets
local SF_DATAPATH = 'data/sf_filedata/sm64/'
--[[
local its_a_me
bass.loadFile(
datapath..'/sound/samples/sfx_mario_peach/07_mario_its_a_me_mario.aiff',
'noplay',
function(obj, errno, errstr)
assert(obj, errstr)
its_a_me = obj
end
)
--]]
-- fallback
local known = {}
local function nop() end
setmetatable(_G, {
__index = function(self, k)
if not known[k] then
known[k] = true
printf("WARNING: Unknown global %q", k)
end
return nop
end
})
-- where the ~MAGIC~ is
--local mtx = Matrix()
local vec = Vector()
local ang = Angle()
function guScale(m, x, y, z)
vec[1] = x
vec[2] = y
vec[3] = z
return m:setScale(vec)
end
function gSPMatrix(pkt, m, p)
render.pushMatrix(m)
end
function gSPPopMatrix(pkt, n)
render.popMatrix()
end
function gSPDisplayList(pkt, dl)
end
function gSPEndDisplayList(pkt)
end
-- code
function printf(fmt, ...)
return print(string.format(fmt, ...))
end
-- hand translated from https://github.com/n64decomp/sm64
-- include/PR/gbi.h
do
-- Need these defined for Sprite Microcode
G_TX_LOADTILE = 7
G_TX_RENDERTILE = 0
G_TX_NOMIRROR = 0
G_TX_WRAP = 0
G_TX_MIRROR = 0x1
G_TX_CLAMP = 0x2
G_TX_NOMASK = 0
G_TX_NOLOD = 0
-- G_MTX: parameter flags
G_MTX_MODELVIEW = 0x00
G_MTX_PROJECTION = 0x01
G_MTX_MUL = 0x00
G_MTX_LOAD = 0x02
G_MTX_NOPUSH = 0x00
G_MTX_PUSH = 0x00
end
-- levels/intro/leveldata.c
do
-- 0x07007EA0 - 0x07007EA2
intro_seg7_texture_07007EA0 = material.createFromImage('../'..SF_DATAPATH..'/levels/intro/0.rgba16.png', '')
-- 0x070086A0 - 0x070086A2
intro_seg7_texture_070086A0 = material.createFromImage('../'..SF_DATAPATH..'/levels/intro/1.rgba16.png', '')
-- 0x0700B4A0 - 0x0700B4A2
intro_seg7_texture_0700B4A0 = material.createFromImage('../'..SF_DATAPATH..'/levels/intro/2_copyright.rgba16.png', '')
-- 0x0700C4A0 - 0x0700D4A0
intro_seg7_texture_0700C4A0 = material.createFromImage('../'..SF_DATAPATH..'/levels/intro/3_tm.rgba16.png', '')
-- 0x0700C6A0 - 0x0700C790
intro_seg7_dl_0700C6A0 = {[0]=
--gsDPPipeSync(),
--gsDPSetCombineMode(G_CC_DECALFADE, G_CC_DECALFADE),
gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON),
gsDPLoadTextureBlock(intro_seg7_texture_0700B4A0, G_IM_FMT_RGBA, G_IM_SIZ_16b, 128, 16, 0, G_TX_CLAMP, G_TX_CLAMP, 7, 4, G_TX_NOLOD, G_TX_NOLOD),
gsSPVertex(intro_seg7_vertex_0700B420, 4, 0),
gsSP2Triangles( 0, 1, 2, 0x0, 0, 2, 3, 0x0),
gsDPLoadTextureBlock(intro_seg7_texture_0700C4A0, G_IM_FMT_RGBA, G_IM_SIZ_16b, 16, 16, 0, G_TX_CLAMP, G_TX_CLAMP, 4, 4, G_TX_NOLOD, G_TX_NOLOD),
gsSPVertex(intro_seg7_vertex_0700B460, 4, 0),
gsSP2Triangles( 0, 1, 2, 0x0, 0, 2, 3, 0x0),
gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF),
gsDPPipeSync(),
gsSPSetGeometryMode(G_LIGHTING),
gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
gsDPSetEnvColor(255, 255, 255, 255),
gsDPSetRenderMode(G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2),
gsSPEndDisplayList(),
}
-- 0x0700C790
intro_seg7_table_0700C790 = {[0]=
0.016000, 0.052000, 0.002500, 0.148300,
0.189200, 0.035200, 0.471600, 0.525300,
0.116600, 0.875800, 0.947000, 0.222100,
1.250500, 1.341300, 0.327000, 1.485400,
1.594900, 0.406500, 1.230500, 1.563700,
0.464300, 0.913900, 1.351300, 0.520200,
1.022900, 1.216100, 0.574400, 1.122300,
1.097200, 0.627000, 1.028300, 0.955600,
0.678100, 0.934800, 1.049400, 0.727700,
0.994200, 1.005200, 0.775900, 1.070200,
0.961500, 0.822900, 0.995600, 0.995000,
0.868700, 0.991600, 1.005700, 0.913500,
1.016500, 0.985200, 0.957200, 0.985200,
1.007100, 1.000000, 0.999900, 0.999800,
1.010600, 1.000000, 1.000000, 1.000000,
}
-- 0x0700C880
intro_seg7_table_0700C880 = {[0]=
1.000000, 1.000000, 1.000000, 0.987300,
0.987300, 0.987300, 0.951400, 0.951400,
0.951400, 0.896000, 0.896000, 0.896000,
0.824600, 0.824600, 0.824600, 0.740700,
0.740700, 0.740700, 0.648000, 0.648000,
0.648000, 0.549900, 0.549900, 0.549900,
0.450100, 0.450100, 0.450100, 0.352000,
0.352000, 0.352000, 0.259300, 0.259300,
0.259300, 0.175400, 0.175400, 0.175400,
0.104000, 0.104000, 0.104000, 0.048600,
0.048600, 0.048600, 0.012800, 0.012800,
0.012800, 0.000000, 0.000000, 0.000000,
}
end
-- src/menu/intro_geo.c
do
-- frame counts for the zoom in, hold, and zoom out of title model
local INTRO_STEPS_ZOOM_IN = 20
local INTRO_STEPS_HOLD_1 = 75
local INTRO_STEPS_ZOOM_OUT = 91
local sIntroFrameCounter
local sTmCopyrightAlpha
-- Geo callback to render the "Super Mario 64" logo on the title screen
function geo_intro_super_mario_64_logo(state, node, context)
--local graphNodes = node
local dl
local dlIter
local scaleMat
local scaleTable1 = intro_seg7_table_0700C790
local scaleTable2 = intro_seg7_table_0700C880
local scaleX
local scaleY
local scaleZ
if state ~= 1 then
sIntroFrameCounter = 0
elseif state == 1 then
--graphNode.flags = bit.bor(bit.band(graphNode.flags, 0xff), bit.lshift(LAYER_OPAQUE, 8))
scaleMat = Matrix()
--dl = alloc_display_list(4 * #dl)
dlIter = dl or 0
-- determine scale based on the frame counter
if sIntroFrameCounter >= 0 and sIntroFrameCounter < INTRO_STEPS_ZOOM_IN then
-- zooming in
scaleX = scaleTable1[sIntroFrameCounter * 3]
scaleY = scaleTable1[sIntroFrameCounter * 3 + 1]
scaleZ = scaleTable1[sIntroFrameCounter * 3 + 2]
elseif sIntroFrameCounter >= INTRO_STEPS_ZOOM_IN and sIntroFrameCounter < INTRO_STEPS_HOLD_1 then
-- holding
scaleX = 1
scaleY = 1
scaleZ = 1
elseif sIntroFrameCounter >= INTRO_STEPS_HOLD_1 and sIntroFrameCounter < INTRO_STEPS_ZOOM_OUT then
-- zooming out
scaleX = scaleTable2[(sIntroFrameCounter - INTRO_STEPS_HOLD_1) * 3]
scaleY = scaleTable2[(sIntroFrameCounter - INTRO_STEPS_HOLD_1) * 3 + 1]
scaleZ = scaleTable2[(sIntroFrameCounter - INTRO_STEPS_HOLD_1) * 3 + 2]
else
-- disappeared
scaleX = 0
scaleY = 0
scaleZ = 0
end
guScale(scaleMat, scaleX, scaleY, scaleZ)
gSPMatrix(dlIter, scaleMat, bit.bor(bit.bor(G_MTX_MODELVIEW, G_MTX_MUL), G_MTX_PUSH)); dlIter = dlIter+1
gSPDisplayList(dlIter, intro_seg7_dl_0700B3A0); dlIter = dlIter+1 -- draw model
gSPPopMatrix(dlIter, G_MTX_MODELVIEW); dlIter = dlIter+1
gSPEndDisplayList(dlIter)
sIntroFrameCounter = sIntroFrameCounter+1
end
return dl
end
-- Geo callback to render TM and Copyright on the title screen
function geo_intro_tm_copyright(state, node, context)
local graphNode = node
local dl
local dlIter
if state ~= 1 then -- reset
sTmCopyrightAlpha = 0
elseif state == 1 then -- draw
--dl = alloc_display_list(5 * #dl)
dlIter = dl or 0
gSPDisplayList(dlIter, dl_proj_mtx_fullscreen); dlIter = dlIter+1
gDPSetEnvColor(dlIter, 255, 255, 255, sTmCopyrightAlpha); dlIter = dlIter+1
if sTmCopyrightAlpha == 255 then -- opaque
--graphNode.flags = bit.bor(bit.band(graphNode.flags, 0xff), bit.lshift(LAYER_OPAQUE, 8))
gDPSetRenderMode(G_RM_AA_OPA_SURF, G_RM_AA_OPA_SURF2); dlIter = dlIter+1
else -- blend
--graphNode.flags = bit.bor(bit.band(graphNode.flags, 0xff), bit.lshift(LAYER_TRANSPARENT, 8))
gDPSetRenderMode(G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2); dlIter = dlIter+1
end
gSPDisplayList(dlIter, intro_seg7_dl_0700C6A0); dlIter = dlIter+1
gSPEndDisplayList(dlIter)
-- Once the "Super Mario 64" logo has just about zoomed fully, fade in the "TM" and copyright text
if sIntroFrameCounter >= 19 then
sTmCopyrightAlpha = sTmCopyrightAlpha+26
if sTmCopyrightAlpha > 255 then
sTmCopyrightAlpha = 255
end
end
end
return dl
end
end
-- custom loop
local threshold = quotaMax()*0.5
local thread = coroutine.create(function()
geo_intro_super_mario_64_logo(0)
geo_intro_tm_copyright(0)
while true do
--geo_intro_super_mario_64_logo(1)
geo_intro_tm_copyright(1)
coroutine.yield(true)
end
end)
-- rendering
render.createRenderTarget('screen')
hook.add('render', '', function()
render.setFilterMag(TEXFILTER.POINT)
render.setFilterMin(TEXFILTER.POINT)
render.selectRenderTarget('screen')
while quotaUsed() < threshold do
if coroutine.resume(thread) then
break
end
end
render.selectRenderTarget()
render.setRenderTargetTexture('screen')
render.drawTexturedRect(0, 191, 512, 384, 0, 0, 0.3125, 0.234375)
-- material debug
render.setMaterial(intro_seg7_texture_07007EA0)
render.drawTexturedRect(0, 0, 32, 32)
render.setMaterial(intro_seg7_texture_070086A0)
render.drawTexturedRect(32, 0, 32, 32)
render.setMaterial(intro_seg7_texture_0700B4A0)
render.drawTexturedRect(64, 0, 128, 16)
render.setMaterial(intro_seg7_texture_0700C4A0)
render.drawTexturedRect(192, 0, 16, 16)
end)
--@name Super Mario 64
--@client
-- https://github.com/n64decomp/sm64
-- ecd3d15
--@includedata sm64/levels/intro/0.rgba16.png
--@includedata sm64/levels/intro/1.rgba16.png
--@includedata sm64/levels/intro/2_copyright.rgba16.png
--@includedata sm64/levels/intro/3_tm.rgba16.png
sprintf = string.format
function printf(...)
return print(sprintf(...))
end
-- include/PR/gbi.h
do
function gsSPVertex(v, n, v0)
-- assumes rectangular; will likely have to change later
-- right is +x, up is +y (y is OPPOSITE starfallex)
local bl = v[1][1]
local br = v[2][1]
local tr = v[3][1]
local tl = v[4][1]
local blx, brx, trx, tlx = bl[1][1], br[1][1], tr[1][1], tl[1][1]
local bly, bry, try, tly = bl[1][2], br[1][2], tr[1][2], tl[1][2]
local x = blx
local y = 240-tly
local w = brx-blx
local h = tly-bly
return x, y, w, h
end
end
-- levels/intro/leveldata.c
do
local SF_USE_INCLUDEDATA = true
local SF_CACHE_INCLUDEDATA = true
local SF_INCLUDE_PREFIX = 'sm64'
for path in pairs(getScripts()) do
if string.find(path, '%.png$') then
SF_USE_INCLUDEDATA = true
break
end
end
local SF_PATH_USABLE_EXTENSIONS = {
txt = true,
dat = true,
json = true,
xml = true,
csv = true,
jpg = true,
jpeg = true,
png = true,
vtf = true,
vmt = true,
mp3 = true,
wav = true,
ogg = true
}
local function SF_PATH_HASH(path)
local ext = string.getExtensionFromFilename(path)
ext = SF_PATH_USABLE_EXTENSIONS[ext] and ext or 'dat'
path = string.normalizePath(path)
path = string.lower(path)
return sprintf('sm64_%s.%s', crc(path), ext)
end
local SF_PATH_USABLE = {}
local function SF_PATH_PATCH(path)
if SF_USE_INCLUDEDATA then
local newpath = SF_PATH_USABLE[path]
if newpath then
return newpath
end
local hash = SF_PATH_HASH(path)
local newpath = SF_CACHE_INCLUDEDATA and file.existsTemp(hash)
if newpath then
return newpath
end
local data = getScripts()[SF_INCLUDE_PREFIX..path]
assert(data, sprintf("could find included %q", path))
newpath = file.writeTemp(hash, data)
SF_PATH_USABLE[path] = newpath
return newpath
end
return 'data/sf_filedata/sm64/'..path
end
-- 0x07007EA0 - 0x07007EA2
intro_seg7_texture_07007EA0 = material.createFromImage(
'../'..SF_PATH_PATCH('/levels/intro/0.rgba16.png'),
''
)
-- 0x070086A0 - 0x070086A2
intro_seg7_texture_070086A0 = material.createFromImage(
'../'..SF_PATH_PATCH('/levels/intro/1.rgba16.png'),
''
)
-- 0x07008EA0 - 0x07009E38
function intro_seg7_dl_07008EA0()
render.setMaterial(intro_seg7_texture_070086A0)
render.draw3DWireframeBox(Vector(), Angle(0, 0, -30), Vector(-1200, -300, -100), Vector(1200, 1000, 100))
end
-- 0x0700B3A0 - 0x0700B420
function intro_seg7_dl_0700B3A0()
intro_seg7_dl_07008EA0()
-- intro_seg7_dl_07009E38
-- intro_seg7_dl_0700ADC0
end
-- 0x0700B420 - 0x0700B460
intro_seg7_vertex_0700B420 = {
{{{ 96, 42, -1}, 0, { 0, 512}, {0xff, 0xff, 0xff, 0xff}}},
{{{ 224, 42, -1}, 0, { 4096, 512}, {0xff, 0xff, 0xff, 0xff}}},
{{{ 224, 58, -1}, 0, { 4096, 0}, {0xff, 0xff, 0xff, 0xff}}},
{{{ 96, 58, -1}, 0, { 0, 0}, {0xff, 0xff, 0xff, 0xff}}},
}
-- 0x0700B460 - 0x0700B4A0
intro_seg7_vertex_0700B460 = {
{{{ 268, 180, -1}, 0, { 0, 512}, {0xff, 0xff, 0xff, 0xff}}},
{{{ 284, 180, -1}, 0, { 544, 512}, {0xff, 0xff, 0xff, 0xff}}},
{{{ 284, 196, -1}, 0, { 544, 0}, {0xff, 0xff, 0xff, 0xff}}},
{{{ 268, 196, -1}, 0, { 0, 0}, {0xff, 0xff, 0xff, 0xff}}},
}
-- 0x0700B4A0 - 0x0700B4A2
intro_seg7_texture_0700B4A0 = material.createFromImage(
'../'..SF_PATH_PATCH('/levels/intro/2_copyright.rgba16.png'),
''
)
-- 0x0700C4A0 - 0x0700D4A0
intro_seg7_texture_0700C4A0 = material.createFromImage(
'../'..SF_PATH_PATCH('/levels/intro/3_tm.rgba16.png'),
''
)
-- 0x0700C6A0 - 0x0700C790
function intro_seg7_dl_0700C6A0()
render.setMaterial(intro_seg7_texture_0700B4A0)
render.drawTexturedRect(gsSPVertex(intro_seg7_vertex_0700B420))
render.setMaterial(intro_seg7_texture_0700C4A0)
render.drawTexturedRect(gsSPVertex(intro_seg7_vertex_0700B460))
end
-- 0x0700C790
intro_seg7_table_0700C790 = {[0]=
0.016000, 0.052000, 0.002500, 0.148300,
0.189200, 0.035200, 0.471600, 0.525300,
0.116600, 0.875800, 0.947000, 0.222100,
1.250500, 1.341300, 0.327000, 1.485400,
1.594900, 0.406500, 1.230500, 1.563700,
0.464300, 0.913900, 1.351300, 0.520200,
1.022900, 1.216100, 0.574400, 1.122300,
1.097200, 0.627000, 1.028300, 0.955600,
0.678100, 0.934800, 1.049400, 0.727700,
0.994200, 1.005200, 0.775900, 1.070200,
0.961500, 0.822900, 0.995600, 0.995000,
0.868700, 0.991600, 1.005700, 0.913500,
1.016500, 0.985200, 0.957200, 0.985200,
1.007100, 1.000000, 0.999900, 0.999800,
1.010600, 1.000000, 1.000000, 1.000000,
}
-- 0x0700C880
intro_seg7_table_0700C880 = {[0]=
1.000000, 1.000000, 1.000000, 0.987300,
0.987300, 0.987300, 0.951400, 0.951400,
0.951400, 0.896000, 0.896000, 0.896000,
0.824600, 0.824600, 0.824600, 0.740700,
0.740700, 0.740700, 0.648000, 0.648000,
0.648000, 0.549900, 0.549900, 0.549900,
0.450100, 0.450100, 0.450100, 0.352000,
0.352000, 0.352000, 0.259300, 0.259300,
0.259300, 0.175400, 0.175400, 0.175400,
0.104000, 0.104000, 0.104000, 0.048600,
0.048600, 0.048600, 0.012800, 0.012800,
0.012800, 0.000000, 0.000000, 0.000000,
}
end
-- levels/entry.c
do
function level_script_entry()
INIT_LEVEL()
SLEEP(2)
BLACKOUT(false)
SET_REG(0)
EXECUTE(0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_splash_screen)
return level_script_entry()
end
end
-- levels/intro/script.c
do
function level_intro_splash_screen()
end
end
-- src/menu/intro_geo.c
do
-- frame counts for the zoom in, hold, and zoom out of title model
local INTRO_STEPS_ZOOM_IN = 20
local INTRO_STEPS_HOLD_1 = 75
local INTRO_STEPS_ZOOM_OUT = 91
sIntroFrameCounter = nil
sTmCopyrightAlpha = nil
-- Geo callback to render the "Super Mario 64" logo on the title screen
function geo_intro_super_mario_64_logo(state)
local scaleMat
local scaleTable1 = intro_seg7_table_0700C790
local scaleTable2 = intro_seg7_table_0700C880
local scaleX
local scaleY
local scaleZ
if state ~= 1 then
sIntroFrameCounter = 0
else
scaleMat = Matrix()
-- determine scale based on the frame counter
if sIntroFrameCounter >= 0 and sIntroFrameCounter < INTRO_STEPS_ZOOM_IN then
-- zooming in
scaleX = scaleTable1[sIntroFrameCounter * 3]
scaleY = scaleTable1[sIntroFrameCounter * 3 + 1]
scaleZ = scaleTable1[sIntroFrameCounter * 3 + 2]
elseif sIntroFrameCounter >= INTRO_STEPS_ZOOM_IN and sIntroFrameCounter < INTRO_STEPS_HOLD_1 then
-- holding
scaleX = 1
scaleY = 1
scaleZ = 1
elseif sIntroFrameCounter >= INTRO_STEPS_HOLD_1 and sIntroFrameCounter < INTRO_STEPS_ZOOM_OUT then
-- zooming out
scaleX = scaleTable2[(sIntroFrameCounter - INTRO_STEPS_HOLD_1) * 3]
scaleY = scaleTable2[(sIntroFrameCounter - INTRO_STEPS_HOLD_1) * 3 + 1]
scaleZ = scaleTable2[(sIntroFrameCounter - INTRO_STEPS_HOLD_1) * 3 + 2]
else
-- disappeared
scaleX = 0
scaleY = 0
scaleZ = 0
end
scaleMat:setScale(Vector(scaleX, scaleY, scaleZ))
render.pushMatrix(scaleMat)
intro_seg7_dl_0700B3A0() -- draw model
render.popMatrix()
sIntroFrameCounter = sIntroFrameCounter+1
end
return dl
end
-- Geo callback to render TM and Copyright on the title screen
function geo_intro_tm_copyright(state)
if state ~= 1 then -- reset
sTmCopyrightAlpha = 0
else -- draw
render.setRGBA(255, 255, 255, sTmCopyrightAlpha)
intro_seg7_dl_0700C6A0() -- draw model
-- Once the "Super Mario 64" logo has just about zoomed fully, fade in the "TM" and copyright text
if sIntroFrameCounter >= 19 then
sTmCopyrightAlpha = sTmCopyrightAlpha+26
if sTmCopyrightAlpha > 255 then
sTmCopyrightAlpha = 255
end
end
end
end
end
-- src/engine/level_script.c
do
SCRIPT_RUNNING = 1
SCRIPT_PAUSED = 0
SCRIPT_PAUSED2 = -1
local LevelScriptJumpTable = {
[0x00] = level_cmd_load_and_execute,
[0x01] = level_cmd_exit_and_execute,
[0x02] = level_cmd_exit,
[0x03] = level_cmd_sleep,
[0x04] = level_cmd_sleep2,
[0x05] = level_cmd_jump,
[0x06] = level_cmd_jump_and_link,
[0x07] = level_cmd_return,
[0x08] = level_cmd_jump_and_link_push_arg,
[0x09] = level_cmd_jump_repeat,
[0x0A] = level_cmd_loop_begin,
[0x0B] = level_cmd_loop_until,
[0x0C] = level_cmd_jump_if,
[0x0D] = level_cmd_jump_and_link_if,
[0x0E] = level_cmd_skip_if,
[0x0F] = level_cmd_skip,
[0x10] = level_cmd_skippable_nop,
[0x11] = level_cmd_call,
[0x12] = level_cmd_call_loop,
[0x13] = level_cmd_set_register,
[0x14] = level_cmd_push_pool_state,
[0x15] = level_cmd_pop_pool_state,
[0x16] = level_cmd_load_to_fixed_address,
[0x17] = level_cmd_load_raw,
[0x18] = level_cmd_load_mio0,
[0x19] = level_cmd_load_mario_head,
[0x1A] = level_cmd_load_mio0_texture,
[0x1B] = level_cmd_init_level,
[0x1C] = level_cmd_clear_level,
[0x1D] = level_cmd_alloc_level_pool,
[0x1E] = level_cmd_free_level_pool,
[0x1F] = level_cmd_begin_area,
[0x20] = level_cmd_end_area,
[0x21] = level_cmd_load_model_from_dl,
[0x22] = level_cmd_load_model_from_geo,
[0x23] = level_cmd_23,
[0x24] = level_cmd_place_object,
[0x25] = level_cmd_init_mario,
[0x26] = level_cmd_create_warp_node,
[0x27] = level_cmd_create_painting_warp_node,
[0x28] = level_cmd_create_instant_warp,
[0x29] = level_cmd_load_area,
[0x2A] = level_cmd_unload_area,
[0x2B] = level_cmd_set_mario_start_pos,
[0x2C] = level_cmd_2C,
[0x2D] = level_cmd_2D,
[0x2E] = level_cmd_set_terrain_data,
[0x2F] = level_cmd_set_rooms,
[0x30] = level_cmd_show_dialog,
[0x31] = level_cmd_set_terrain_type,
[0x32] = level_cmd_nop,
[0x33] = level_cmd_set_transition,
[0x34] = level_cmd_set_blackout,
[0x35] = level_cmd_set_gamma,
[0x36] = level_cmd_set_music,
[0x37] = level_cmd_set_menu_music,
[0x38] = level_cmd_38,
[0x39] = level_cmd_set_macro_objects,
[0x3A] = level_cmd_3A,
[0x3B] = level_cmd_create_whirlpool,
[0x3C] = level_cmd_get_or_set_var,
}
function level_script_execute(cmd)
sScriptStatus = SCRIPT_RUNNING
sCurrentCmd = cmd
while sScriptStatus == SCRIPT_RUNNING do
sCurrentCmd()
end
init_render_image()
render_game()
return sCurrentCmd
end
end
-- src/game/game_init.c
do
gGlobalTimer = 0 -- u32
frameBufferIndex = 0 -- u16
-- Clear the Z buffer.
clear_z_buffer = render.clearDepth
-- Sets up the final framebuffer image.
function display_frame_buffer()
render.setRGBA(255, 255, 255, 255)
render.selectRenderTarget('final')
render.setRenderTargetTexture('screen')
render.drawTexturedRect(0, 0, 1024, 1024)
render.selectRenderTarget('screen')
end
-- Clears the framebuffer, allowing it to be overwritten.
function clear_frame_buffer(color)
render.clear(Color(0, 0, 0, 255), false)
end
-- Starts rendering the scene.
function init_render_image()
clear_z_buffer()
display_frame_buffer()
end
function rendering_init()
init_render_image()
clear_frame_buffer(0)
frameBufferIndex = frameBufferIndex+1
gGlobalTimer = gGlobalTimer+1
end
-- Handles vsync.
function display_and_vsync()
frameBufferIndex = frameBufferIndex+1
if frameBufferIndex == 3 then
frameBufferIndex = 0
end
gGlobalTimer = gGlobalTimer+1
end
function thread5_game_loop()
local addr
-- point addr to the entry point into the level script data.
addr = level_script_entry
rendering_init()
while true do
addr = level_script_execute(addr)
display_and_vsync()
coroutine.yield(true)
end
end
end
local thread = coroutine.create(function()
geo_intro_super_mario_64_logo(0)
geo_intro_tm_copyright(0)
while true do
rendering_init()
geo_intro_super_mario_64_logo(1)
geo_intro_tm_copyright(1)
display_and_vsync()
display_frame_buffer()
coroutine.yield(true)
end
end)
local threshold = quotaMax()*0.5
local waitUntil = 0
local frameTime = 1/30
local fps = 0
local frames = 0
local frameExpire = timer.systime()+1
local bg = Color(31, 31, 31)
render.createRenderTarget('screen')
render.createRenderTarget('final')
hook.add('render', '', function()
render.setBackgroundColor(bg)
--render.setFilterMag(TEXFILTER.POINT)
--render.setFilterMin(TEXFILTER.POINT)
local now = timer.systime()
if now >= frameExpire then
fps = frames
frames = 0
frameExpire = now+1
end
if now >= waitUntil then
render.selectRenderTarget('screen')
while quotaUsed() < threshold do
if coroutine.resume(thread) then
frames = frames+1
break
end
end
waitUntil = now+frameTime
render.selectRenderTarget()
end
render.setRGBA(255, 255, 255, 255)
render.setRenderTargetTexture('final')
render.drawTexturedRectUV(0, 63, 512, 384, 0, 0, 0.3125, 0.234375)
-- material debug
--[[
render.setMaterial(intro_seg7_texture_07007EA0)
render.drawTexturedRect(0, 0, 32, 32)
render.setMaterial(intro_seg7_texture_070086A0)
render.drawTexturedRect(32, 0, 32, 32)
render.setMaterial(intro_seg7_texture_0700B4A0)
render.drawTexturedRect(64, 0, 128, 16)
render.setMaterial(intro_seg7_texture_0700C4A0)
render.drawTexturedRect(192, 0, 16, 16)
--]]
-- debug text
-- [[
local dbgstr = string.format(
"fps: %d\n"..
"gGlobalTimer: %d\n"..
"sIntroFrameCounter: %d\n"..
"sTmCopyrightAlpha: %f",
fps,
gGlobalTimer or -1,
sIntroFrameCounter or -1,
sTmCopyrightAlpha or -1
)
render.setFont('DebugFixed')
render.drawText(0, 0, dbgstr)
--]]
end)
--@name SM64 intro logo test
--@client
--@includedata sm64/levels/intro/leveldata.c
--@includedata sm64/levels/intro/0.rgba16.png
--@includedata sm64/levels/intro/1.rgba16.png
--@includedata sm64/levels/intro/2_copyright.rgba16.png
--@includedata sm64/levels/intro/3_tm.rgba16.png
-- derived from https://github.com/n64decomp/sm64
-- commit ecd3d15
sprintf = string.format
function printf(...)
return print(sprintf(...))
end
local leveldata = getScripts()['sm64/levels/intro/leveldata.c']
-- textures
-- [[
do
local SF_USE_INCLUDEDATA = true
local SF_CACHE_INCLUDEDATA = true
local SF_INCLUDE_PREFIX = 'sm64'
local SF_PATH_USABLE_EXTENSIONS = {
txt = true,
dat = true,
json = true,
xml = true,
csv = true,
jpg = true,
jpeg = true,
png = true,
vtf = true,
vmt = true,
mp3 = true,
wav = true,
ogg = true
}
local function SF_PATH_HASH(path)
local ext = string.getExtensionFromFilename(path)
ext = SF_PATH_USABLE_EXTENSIONS[ext] and ext or 'dat'
path = string.normalizePath(path)
path = string.lower(path)
return sprintf(SF_INCLUDE_PREFIX..'_%s.%s', crc(path), ext)
end
local SF_PATH_USABLE = {}
local function SF_PATH_PATCH(path)
local newpath = SF_PATH_USABLE[path]
if newpath then
return newpath
end
local hash = SF_PATH_HASH(path)
local newpath = SF_CACHE_INCLUDEDATA and file.existsTemp(hash)
if newpath then
return newpath
end
if SF_USE_INCLUDEDATA then
local data = getScripts()[SF_INCLUDE_PREFIX..path]
if data then
newpath = file.writeTemp(hash, data)
SF_PATH_USABLE[path] = newpath
return newpath
end
printf("WARNING: could find included %q", path)
end
return 'data/sf_filedata/sm64/'..path
end
intro_seg7_texture_07007EA0 = material.createFromImage(
'../'..SF_PATH_PATCH('/levels/intro/0.rgba16.png'),
'noclamp'
)
intro_seg7_texture_070086A0 = material.createFromImage(
'../'..SF_PATH_PATCH('/levels/intro/1.rgba16.png'),
'noclamp'
)
intro_seg7_texture_0700B4A0 = material.createFromImage(
'../'..SF_PATH_PATCH('/levels/intro/2_copyright.rgba16.png'),
''
)
intro_seg7_texture_0700C4A0 = material.createFromImage(
'../'..SF_PATH_PATCH('/levels/intro/3_tm.rgba16.png'),
''
)
end
--]]
-- model data
local EZ_MESH_DATA = {}
for k, vp in leveldata:gmatch('\nstatic const Vtx (intro_seg7_vertex_%x+)%[%] = {\n(.-)};\n') do
local D = {}
local i = 0
for line in vp:gmatch('[ \t]*([^\n]+)\n') do
local x, y, z, unk0, u, v, r, g, b, a = line:match('{{{ *(-?%d+), *(-?%d+), *(-?%d+)}, *(-?%d+), *{ *(-?%d+), *(-?%d+)}, *{0x(%x+), *0x(%x+), *0x(%x+), *0x(%x+)}}},')
assert(x, sprintf("failed to read %d from %q", i, k))
x, y, z, unk0, u, v = tonumber(x), tonumber(y), tonumber(z), tonumber(unk0), tonumber(u), tonumber(v)
r, g, b, a = tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), tonumber(a, 16)
D[i] = {{{x, y, z}, unk0, {u, v}, {r, g, b, a}}}
--D[i] = {Vector(x, y, z), unk0, {u, v}, Color(r, g, b, a)}
i = i+1
end
EZ_MESH_DATA[k] = D
end
-- rendering info
local DS3 = {}
local function parseIntroMesh(funcname, DS2r)
local DS2 = DS3[funcname] or {}
DS2r = DS2r or string.match(
leveldata,
'static const Gfx '..funcname..'%[%] = {\n'..
'[ \t]*gsDPSetTextureImage%(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, intro_seg7_texture_%x+%),\n'..
'[ \t]*gsDPLoadSync%(%),\n'..
'[ \t]*gsDPLoadBlock%(G_TX_LOADTILE, 0, 0, 32 %* 32 %- 1, CALC_DXT%(32, G_IM_SIZ_16b_BYTES%)%),\n'..
'(.-)'..
'[ \t]*gsSPEndDisplayList%(%),\n'..
'};\n'
) or string.match(
leveldata,
'static const Gfx '..funcname..'%[%] = {\n'..
'(.-)'..
'[ \t]*gsSPEndDisplayList%(%),\n'..
'};\n'
)
DS2r = string.gsub(DS2r, '^\n+', '')
DS2r = string.gsub(DS2r, '\n*$', '\n')
DS2r = string.gsub(DS2r, '[ \t]+', '')
local tex, vert
for line in string.gmatch(DS2r, '([^\n]+)\n') do
local v, n, v0 = line:match('^gsSPVertex%(([%w_]+),(%d+),(%d+)%),?$')
if v then
if tex then
DS2[tex] = vert
end
tex = v
vert = {}
else
local v00, v01, v02, flag0, v10, v11, v12, flag1 =
line:match('^gsSP2Triangles%((%d+),(%d+),(%d+),0x(%x+),(%d+),(%d+),(%d+),0x(%x+)%),?$')
if not v00 then
v00, v01, v02, flag0 = line:match('^gsSP1Triangle%((%d+),(%d+),(%d+),0x(%x+)%),?$')
assert(v00, sprintf("failed to parse in %s: %q", funcname, line))
end
v00 = tonumber(v00)
v01 = tonumber(v01)
v02 = tonumber(v02)
flag0 = tonumber(flag0, 16)
if v10 then
v10 = tonumber(v10)
v11 = tonumber(v11)
v12 = tonumber(v12)
flag1 = tonumber(flag1, 16)
end
table.insert(vert, {v00, v01, v02, flag0})
if v10 then
table.insert(vert, {v10, v11, v12, flag1})
end
end
end
DS2[tex] = vert
DS3[funcname] = DS2
end
-- these three make the logo
parseIntroMesh('intro_seg7_dl_07008EA0') -- letter fronts, "64" border
parseIntroMesh('intro_seg7_dl_07009E38') -- letter backs
parseIntroMesh('intro_seg7_dl_0700ADC0') -- "64" back, 2 stray tris
-- add 2d shit too
parseIntroMesh(
'intro_seg7_dl_0700C6A0',
'\tgsSPVertex(intro_seg7_vertex_0700B420, 4, 0),\n'..
'\tgsSP2Triangles( 0, 1, 2, 0x0, 0, 2, 3, 0x0),\n'
)
parseIntroMesh(
'intro_seg7_dl_0700C6A0',
'\tgsSPVertex(intro_seg7_vertex_0700B460, 4, 0),\n'..
'\tgsSP2Triangles( 0, 1, 2, 0x0, 0, 2, 3, 0x0),\n'
)
-- generate mesh
local function countPrimitives(DS2)
local Dl = 0
for k, v in pairs(DS2) do
for _, v2 in pairs(v) do
Dl = Dl+3
end
end
return Dl
end
local function meshBuilder(data)
for k, v in pairs(data) do
local D = EZ_MESH_DATA[k]
for _, v2 in ipairs(v) do
local vx0, vx1, vx2, flagx = unpack(v2)
vx0 = D[vx0]
mesh.writePosition(Vector(unpack(vx0[1][1])))
mesh.writeColor(unpack(vx0[1][4]))
mesh.writeUV(0, vx0[1][3][1]/1024, vx0[1][3][2]/1024)
mesh.advanceVertex()
vx1 = D[vx1]
mesh.writePosition(Vector(unpack(vx1[1][1])))
mesh.writeColor(unpack(vx1[1][4]))
mesh.writeUV(0, vx1[1][3][1]/1024, vx1[1][3][2]/1024)
mesh.advanceVertex()
vx2 = D[vx2]
mesh.writePosition(Vector(unpack(vx2[1][1])))
mesh.writeColor(unpack(vx2[1][4]))
mesh.writeUV(0, vx2[1][3][1]/1024, vx2[1][3][2]/1024)
mesh.advanceVertex()
end
end
end
local function buildMesh(funcname, obj)
local DS2 = DS3[funcname]
obj = obj or mesh.createEmpty()
mesh.generate(obj, MATERIAL.TRIANGLES, countPrimitives(DS2), function()
meshBuilder(DS2)
end)
return obj
end
local EZ_MESH_LOGO_SOLID = buildMesh('intro_seg7_dl_0700ADC0') -- "64" front, stray tris
local EZ_MESH_LOGO_WOOD = buildMesh('intro_seg7_dl_07009E38') -- letter sides
local EZ_MESH_LOGO_PLASTIC = buildMesh('intro_seg7_dl_07008EA0') -- letter fronts, "64" sides
--local EZ_MESH_COPYRIGHT = buildMesh('intro_seg7_dl_0700C6A0')
-- draw
local n64 = true
local mtx = Matrix()
mtx:setScale(Vector(0.2, 0.2, 0.2))
local spin = Matrix()
local rot = Angle()
local vmtx = {
x = 0,
y = 0,
w = n64 and 320 or 1024,
h = n64 and 240 or 1024,
type = '3D',
origin = Vector(0, 0, 1000),
angles = Angle(90, 90, 0),
fov = 45,
aspect = n64 and 320/240 or 1,
}
local debugFont = render.createFont('DejaVu Sans Mono', 12, false)
render.createRenderTarget('out')
hook.add('render', '', function()
render.setBackgroundColor(Color(31, 31, 31))
rot.pitch = math.sin(timer.systime()*2)*22.5
rot.roll = math.sin(timer.systime()*3)*11.25
spin:setAngles(rot)
--render.setFilterMag(TEXFILTER.POINT)
--render.setFilterMin(TEXFILTER.POINT)
render.selectRenderTarget('out')
render.clear(Color(0, 0, 0, 255), true)
render.pushViewMatrix(vmtx)
render.enableDepth(true)
render.setCullMode(1)
render.pushMatrix(mtx)
render.pushMatrix(spin)
--render.draw3DWireframeBox(Vector(), Angle(0, 0, -30), Vector(-1200, -300, -100), Vector(1200, 1000, 100))
render.setMaterial()
EZ_MESH_LOGO_SOLID:draw()
render.setMaterial(intro_seg7_texture_07007EA0)
EZ_MESH_LOGO_WOOD:draw()
render.setMaterial(intro_seg7_texture_070086A0)
EZ_MESH_LOGO_PLASTIC:draw()
render.popMatrix()
render.popMatrix()
--render.setMaterial(intro_seg7_texture_0700B4A0)
--EZ_MESH_COPYRIGHT:draw()
render.setCullMode(0)
render.enableDepth(false)
render.popViewMatrix()
render.selectRenderTarget()
render.setRGBA(255, 255, 255, 255)
render.setRenderTargetTexture('out')
if n64 then
render.drawTexturedRectUV(0, 63, 512, 384, 0, 0, 0.3125, 0.234375)
else
render.drawTexturedRect(0, 0, 512, 512)
end
-- material debug
--[[
render.setMaterial(intro_seg7_texture_07007EA0)
render.drawTexturedRect(0, 0, 32, 32)
render.setMaterial(intro_seg7_texture_070086A0)
render.drawTexturedRect(32, 0, 32, 32)
render.setMaterial(intro_seg7_texture_0700B4A0)
render.drawTexturedRect(64, 0, 128, 16)
render.setMaterial(intro_seg7_texture_0700C4A0)
render.drawTexturedRect(192, 0, 16, 16)
--]]
render.setFont(debugFont)
local str = sprintf(
"quota: %d%%\n"..
"THIS IS NOT AN EMULATOR.\n"..
"THIS IS NOT YET PLAYABLE.\n"..
"SOURCE CODE: gist.github.com/x4fx77x4f",
math.ceil(quotaAverage()/quotaMax()*100-0.5)
)
local w, h = render.getTextSize(str)
render.setRGBA(0, 0, 0, 191)
render.drawRect(0, 0, w, h)
render.setRGBA(255, 255, 255, 255)
render.drawText(0, 0, str)
end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment