Last active
April 21, 2021 04:09
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--@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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--@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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--@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