I need a guru. Here's my script for Genesis Gargoyles that draws BG.
Right now, I'm using a 1D array of "structs", with each unit representing a block with its attributes, and if the block is offscreen, its unit becomes nil, if it's onscreen, its unit gets calculated and cached.
I'm also iterating through the whole map, and the array I create that way is very huge. This results in low speed of the function.
This is all happening in function Background(), the rest don't seem to matter too much.
Can someone help me to speed this thing up? If I make a consecutive array instead of index=x+y*mapwidth, it draws only the first bunch of blocks in the map. There's also some garbage left from camhack and size divider, ignore that.
Download Gargoyles.luaLanguage: lua
-- Gargoyles, Genesis (BizHawk)
-- feos, 2015-2016
--== Shortcuts ==--
rb = memory.read_u8
rw = memory.read_u16_be
rws = memory.read_s16_be
r24 = memory.read_u24_be
rl = memory.read_u32_be
box = gui.drawBox
text = gui.pixelText
line = gui.drawLine
AND = bit.band
SHIFT = bit.rshift
--== RAM addresses ==--
levnum = 0xff00ba
LevelFlr = 0xff00c0
LevelCon = 0xff00c4
mapline_tab = 0xff0244
GlobalBase = 0xff1c76
GolBase = 0xff2c76
MapA_Buff = 0xff4af0
--== Camera Hack ==--
camhack = false
div = 1 -- scale
size = 16/div -- block size
--== Other stuff ==--
XposLast = 0
YposLast = 0
room = 0
workinglast = 0
lagcount = emu.lagcount()
gui.defaultPixelFont("fceux")
--== Block cache ==--
cache = {}
function main()
rnd1 = rl (0xff001c)
rnd2 = rw (0xff0020)
working = rb (0xff0073)
xblocks = rw (0xff00d4)
mapw = rw (0xff00d4)*8
maph = rw (0xff00d6)*8
Xpos = rws(0xff0106)
Ypos = rws(0xff0108)
camx = rws(0xff010c)+16
camy = rws(0xff010e)+16
run = rb (0xff1699)
inv = rw (0xff16d2)
health = rws(0xff2cc6)
backx = camx
backy = camy
Xspd = Xpos-XposLast
Yspd = Ypos-YposLast
XposLast = Xpos
YposLast = Ypos
facing = AND(rb(GolBase+0x48),2) -- object flag 1
Background()
rndlast = rnd1
workinglast = working
end
function Background()
if working>0 then return end
local border = -16
local basex = camx+border
local basey = camy+border
local boundx = 320-border
local boundy = 224-border
-- xblocks = ((camx+boundx+32)-(basex-32))/16
for i = PosToIndex(basex-32,basey-32), PosToIndex((camx+boundx+32),(camy+boundy+32)) do
local pos = IndexToPos(i)
if InBounds(pos.x,basex-32,camx+boundx+32) then
local unit = cache[i]
if unit == nil or workinglast>0 then
if InBounds(pos.x,basex,camx+boundx)
and InBounds(pos.y,basey,camy+boundy)
then cache[i] = GetBlock(pos.x,pos.y)
end
else
if not InBounds(pos.x,basex,camx+boundx)
and not InBounds(pos.y,basey,camy+boundy)
then cache[i] = nil
end
end
if unit ~= nil then
DrawBG(unit, pos)
end
elseif cache[i] ~= nil
then cache[i] = nil
end
end
end
function DrawBG(unit, pos)
local val = unit.block
local x1 = pos.x/div-camx/div
local x2 = x1+size-1
local y1 = pos.y/div-camy/div
local y2 = y1+size-1
local col = 0 -- block color
local opout = 0x33000000 -- outer opacity
local opin = 0x66000000 -- inner opacity
local op = 0xff000000
if unit.contour ~= nil then
box(x1,y1,x2,y2,0x5500ff00,0x5500ff00)
for pixel=0,15 do
if unit.contour[pixel]>0 then
gui.drawPixel(
x1+pixel/div,
y1+unit.contour[pixel]/div-1/div,
0xffffff00)
end
end
end
if val>0 then
if val==0x80 then -- WALL
col = 0x00ffffff -- white
line(x1,y1,x1,y2,col+op) -- left
line(x2,y1,x2,y2,col+op) -- right
elseif val==0x81 then -- CEILING
col = 0x00ffffff -- white
line(x1,y2,x2,y2,col+op) -- bottom
elseif val==0x82 then -- CLIMB_U
col = 0x0000ffff -- cyan
line(x1,y2,x2,y2,col+op) -- bottom
elseif val==0x83 then -- CLIMB_R
col = 0x0000ffff -- cyan
line(x1,y1,x1,y2,col+op) -- left
elseif val==0x84 then -- CLIMB_L
col = 0x0000ffff -- cyan
line(x2,y1,x2,y2,col+op) -- right
elseif val==0x85 then -- CLIMB_LR
col = 0x0000ffff -- cyan
line(x1,y1,x1,y2,col+op) -- left
line(x2,y1,x2,y2,col+op) -- right
elseif val==0x86 then -- CLIMB_R_STAND_R
col = 0x00ffffff -- white
line(x1,y1,x2,y1,col+op) -- top
col = 0x0000ffff -- cyan
line(x1,y1,x1,y2,col+op) -- left
elseif val==0x87 then -- CLIMB_L_STAND_L
col = 0x00ffffff -- white
line(x1,y1,x2,y1,col+op) -- top
col = 0x0000ffff -- cyan
line(x2,y1,x2,y2,col+op) -- right
elseif val==0x87 then -- CLIMB_LR_STAND_LR
col = 0x00ffffff -- white
line(x1,y1,x2,y1,col+op) -- top
col = 0x00ff00ff -- cyan
line(x1,y1,x1,y2,col+op) -- left
col = 0x0000ffff -- cyan
line(x2,y1,x2,y2,col+op) -- right
elseif val==0x70 then -- GRAB_SWING
col = 0x0000ff00 -- green
box(x1,y1,x2,y2,col,col+opout)
elseif val==0x7f then -- EXIT
col = 0x00ffff00 -- yellow
elseif val==0xd0
or val==0xd1 then -- SPIKES
col = 0x00ff0000 -- red
box(x1,y1,x2,y2,col,col+opout)
else -- LEVEL_SPECIFIC
col = 0x00ff8800 -- orange
box(x1,y1,x2,y2,col+opin,col+opout)
end
box(x1,y1,x2,y2,col+opin,col+opout)
end
end
function GetBlock(x,y)
if working>0 then return nil end
local final = { contour={}, block=0 }
if x>0 and x<mapw
and y>0 and y<maph then
local x1 = x/div-camx/div
local x2 = x1+size-1
local y1 = y/div-camy/div
local y2 = y1+size-1
local d4 = rw(mapline_tab+SHIFT(y,4)*2)
local a1 = r24(LevelFlr+1)
local d1 = SHIFT(rw(MapA_Buff+d4+SHIFT(x,4)*2),1)
final.block = rb(a1+d1+2)
d1 = rw(a1+d1)
a1 = r24(LevelCon+1)+d1
if rb(a1)>0 or rb(a1+8)>0 then
for pixel=0,15 do
final.contour[pixel] = rb(a1+pixel)
end
else
final.contour = nil
end
else
return nil
end
return final
end
function PosToIndex(x,y)
return math.floor(x/16)+math.floor(y/16)*xblocks
end
function IndexToPos(i)
return { x=(i%xblocks)*16, y=math.floor(i/xblocks)*16 }
end
function InBounds(x,minimum,maximum)
if x>=minimum and x<=maximum
then return true
else return false
end
end
while true do
main()
emu.frameadvance()
end