2015-08-20 10:03:01 +00:00
|
|
|
require "strict"
|
|
|
|
|
2015-09-11 11:30:37 +00:00
|
|
|
local __pico_fps=30
|
|
|
|
|
|
|
|
local frametime = 1/__pico_fps
|
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
local __compression_map = {
|
|
|
|
'INVALID',
|
|
|
|
' ',
|
|
|
|
'0',
|
|
|
|
'1',
|
|
|
|
'2',
|
|
|
|
'3',
|
|
|
|
'4',
|
|
|
|
'5',
|
|
|
|
'6',
|
|
|
|
'7',
|
|
|
|
'8',
|
|
|
|
'9',
|
|
|
|
'a',
|
|
|
|
'b',
|
|
|
|
'c',
|
|
|
|
'd',
|
|
|
|
'e',
|
|
|
|
'f',
|
|
|
|
'g',
|
|
|
|
'h',
|
|
|
|
'i',
|
|
|
|
'j',
|
|
|
|
'k',
|
|
|
|
'l',
|
|
|
|
'm',
|
|
|
|
'n',
|
|
|
|
'o',
|
|
|
|
'p',
|
|
|
|
'q',
|
|
|
|
'r',
|
|
|
|
's',
|
|
|
|
't',
|
|
|
|
'u',
|
|
|
|
'v',
|
|
|
|
'w',
|
|
|
|
'x',
|
|
|
|
'y',
|
|
|
|
'z',
|
|
|
|
'!',
|
|
|
|
'#',
|
|
|
|
'%',
|
|
|
|
'(',
|
|
|
|
')',
|
|
|
|
'{',
|
|
|
|
'}',
|
|
|
|
'[',
|
|
|
|
']',
|
|
|
|
'<',
|
|
|
|
'>',
|
|
|
|
'+',
|
|
|
|
'=',
|
|
|
|
'/',
|
|
|
|
'*',
|
|
|
|
':',
|
|
|
|
';',
|
|
|
|
'.',
|
|
|
|
',',
|
|
|
|
'~',
|
|
|
|
'_',
|
|
|
|
'"',
|
|
|
|
}
|
|
|
|
|
2015-08-20 10:03:01 +00:00
|
|
|
local cart = nil
|
|
|
|
local cartname = nil
|
|
|
|
local love_args = nil
|
|
|
|
local __screen
|
|
|
|
local __pico_clip
|
|
|
|
local __pico_color
|
|
|
|
local __pico_map
|
|
|
|
local __pico_quads
|
|
|
|
local __pico_spritesheet_data
|
|
|
|
local __pico_spritesheet
|
|
|
|
local __pico_spriteflags
|
|
|
|
local __draw_palette
|
|
|
|
local __draw_shader
|
|
|
|
local __sprite_shader
|
|
|
|
local __text_shader
|
|
|
|
local __display_palette
|
|
|
|
local __display_shader
|
2015-08-16 16:00:39 +00:00
|
|
|
local scale = 4
|
2015-08-17 14:47:42 +00:00
|
|
|
local xpadding = 8.5
|
|
|
|
local ypadding = 3.5
|
2015-08-16 16:00:39 +00:00
|
|
|
local __accum = 0
|
|
|
|
|
2015-09-12 09:30:38 +00:00
|
|
|
local __audio_buffer_size = 1024
|
2015-09-12 03:54:23 +00:00
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
local __pico_pal_transparent = {
|
|
|
|
}
|
|
|
|
|
2015-09-11 11:30:37 +00:00
|
|
|
__pico_resolution = {128,128}
|
|
|
|
|
2015-09-10 11:24:53 +00:00
|
|
|
local lineMesh = love.graphics.newMesh(128,nil,"points")
|
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
local __pico_palette = {
|
2015-08-18 09:45:04 +00:00
|
|
|
{0,0,0,255},
|
2015-08-16 16:00:39 +00:00
|
|
|
{29,43,83,255},
|
|
|
|
{126,37,83,255},
|
|
|
|
{0,135,81,255},
|
|
|
|
{171,82,54,255},
|
|
|
|
{95,87,79,255},
|
|
|
|
{194,195,199,255},
|
|
|
|
{255,241,232,255},
|
|
|
|
{255,0,77,255},
|
|
|
|
{255,163,0,255},
|
|
|
|
{255,255,39,255},
|
|
|
|
{0,231,86,255},
|
|
|
|
{41,173,255,255},
|
|
|
|
{131,118,156,255},
|
|
|
|
{255,119,168,255},
|
|
|
|
{255,204,170,255}
|
|
|
|
}
|
|
|
|
|
2015-08-20 10:03:01 +00:00
|
|
|
local video_frames = nil
|
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
local __pico_camera_x = 0
|
|
|
|
local __pico_camera_y = 0
|
2015-08-21 16:10:34 +00:00
|
|
|
local osc
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-08-17 14:47:42 +00:00
|
|
|
local host_time = 0
|
|
|
|
|
|
|
|
local retro_mode = false
|
|
|
|
|
2015-08-21 16:10:34 +00:00
|
|
|
local __pico_audio_channels = {
|
2015-09-12 09:30:38 +00:00
|
|
|
[0]={},
|
|
|
|
[1]={},
|
|
|
|
[2]={},
|
|
|
|
[3]={}
|
2015-08-21 16:10:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
local __pico_sfx = {}
|
2015-09-09 11:51:34 +00:00
|
|
|
local __audio_channels
|
2015-09-12 09:30:38 +00:00
|
|
|
local __sample_rate = 22050
|
2015-09-12 03:54:23 +00:00
|
|
|
local channels = 1
|
2015-09-12 09:30:38 +00:00
|
|
|
local bits = 16
|
2015-08-21 16:10:34 +00:00
|
|
|
|
|
|
|
local __pico_music = {}
|
|
|
|
|
|
|
|
local __pico_current_music = nil
|
|
|
|
|
|
|
|
function get_bits(v,s,e)
|
|
|
|
local mask = shl(shl(1,s)-1,e)
|
|
|
|
return shr(band(mask,v))
|
|
|
|
end
|
|
|
|
|
2015-09-12 03:54:23 +00:00
|
|
|
local _noise_lookup_table = {}
|
|
|
|
for i=0,1023 do
|
|
|
|
_noise_lookup_table[i] = love.math.random()*2-1
|
|
|
|
end
|
|
|
|
|
2015-09-09 11:51:34 +00:00
|
|
|
local QueueableSource = require "QueueableSource"
|
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
function love.load(argv)
|
|
|
|
love_args = argv
|
2015-08-17 14:47:42 +00:00
|
|
|
if love.system.getOS() == "Android" then
|
|
|
|
love.resize(love.window.getDimensions())
|
|
|
|
else
|
2015-09-11 11:30:37 +00:00
|
|
|
love.window.setMode(__pico_resolution[1]*scale+xpadding*scale*2,__pico_resolution[2]*scale+ypadding*scale*2)
|
2015-08-17 14:47:42 +00:00
|
|
|
end
|
2015-08-21 16:10:34 +00:00
|
|
|
|
|
|
|
osc = {}
|
2015-09-09 11:51:34 +00:00
|
|
|
osc[0] = function(x)
|
|
|
|
-- tri
|
|
|
|
return (abs((x%2)-1)-0.5) * 0.5
|
|
|
|
end
|
|
|
|
osc[1] = function(x)
|
|
|
|
-- uneven tri
|
|
|
|
local t = x%1
|
|
|
|
return (((t < 0.875) and (t * 16 / 7) or ((1-t)*16)) -1) * 0.5
|
|
|
|
end
|
|
|
|
osc[2] = function(x)
|
|
|
|
-- saw
|
|
|
|
return (x%1-0.5) * 0.333
|
|
|
|
end
|
|
|
|
osc[3] = function(x)
|
|
|
|
-- sqr
|
|
|
|
return (x%2 < 0.5 and 1 or -1) * 0.25
|
|
|
|
end
|
|
|
|
osc[4] = function(x)
|
|
|
|
-- pulse
|
|
|
|
return (x%2 < 0.25 and 1 or -1) * 0.25
|
|
|
|
end
|
|
|
|
osc[5] = function(x)
|
|
|
|
-- tri/2
|
|
|
|
return (abs((x%2)-1)-0.5 + (abs(((x*0.5)%2)-1)-0.5)/2) * 0.333
|
|
|
|
end
|
|
|
|
osc[6] = function(x)
|
2015-09-12 03:54:23 +00:00
|
|
|
-- noise FIXME: (zep said this is brown noise)
|
|
|
|
return lerp(_noise_lookup_table[flr(x)%1024],_noise_lookup_table[flr(x+1)%1024],x%1) + ((love.math.random()*2-1) * 0.5) * 0.666
|
2015-09-09 11:51:34 +00:00
|
|
|
end
|
|
|
|
osc[7] = function(x)
|
|
|
|
-- detuned tri
|
|
|
|
return (abs((x%2)-1)-0.5 + (abs(((x*0.97)%2)-1)-0.5)/2) * 0.333
|
|
|
|
end
|
|
|
|
|
|
|
|
__audio_channels = {
|
2015-09-12 03:54:23 +00:00
|
|
|
[0]=QueueableSource:new(8),
|
|
|
|
QueueableSource:new(8),
|
|
|
|
QueueableSource:new(8),
|
|
|
|
QueueableSource:new(8)
|
2015-09-09 11:51:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for i=0,3 do
|
|
|
|
__audio_channels[i]:play()
|
2015-08-21 16:10:34 +00:00
|
|
|
end
|
|
|
|
|
2015-08-18 09:45:04 +00:00
|
|
|
love.graphics.clear()
|
2015-08-16 16:00:39 +00:00
|
|
|
love.graphics.setDefaultFilter('nearest','nearest')
|
2015-09-11 11:30:37 +00:00
|
|
|
__screen = love.graphics.newCanvas(__pico_resolution[1],__pico_resolution[2])
|
2015-08-17 14:47:42 +00:00
|
|
|
__screen:setFilter('linear','nearest')
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-09-10 11:23:46 +00:00
|
|
|
local font = love.graphics.newImageFont("font.png","abcdefghijklmnopqrstuvwxyz\"'`-_/1234567890!?[](){}.,;:<>+=%#^*~ ")
|
2015-08-16 16:00:39 +00:00
|
|
|
love.graphics.setFont(font)
|
|
|
|
font:setFilter('nearest','nearest')
|
|
|
|
|
|
|
|
love.mouse.setVisible(false)
|
2015-08-20 10:03:01 +00:00
|
|
|
love.window.setTitle("picolove")
|
2015-08-16 16:00:39 +00:00
|
|
|
love.graphics.setLineStyle('rough')
|
|
|
|
love.graphics.setPointStyle('rough')
|
|
|
|
love.graphics.setPointSize(1)
|
|
|
|
love.graphics.setLineWidth(1)
|
|
|
|
|
|
|
|
love.graphics.origin()
|
|
|
|
love.graphics.setCanvas(__screen)
|
2015-08-18 12:00:57 +00:00
|
|
|
restore_clip()
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-08-18 09:45:04 +00:00
|
|
|
__draw_palette = {}
|
|
|
|
__display_palette = {}
|
|
|
|
__pico_pal_transparent = {}
|
|
|
|
for i=1,16 do
|
|
|
|
__draw_palette[i] = i
|
|
|
|
__pico_pal_transparent[i] = i == 1 and 0 or 1
|
|
|
|
__display_palette[i] = __pico_palette[i]
|
|
|
|
end
|
2015-08-17 14:47:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
__draw_shader = love.graphics.newShader([[
|
2015-08-18 09:45:04 +00:00
|
|
|
extern float palette[16];
|
2015-08-17 14:47:42 +00:00
|
|
|
|
|
|
|
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
|
2015-08-17 16:36:58 +00:00
|
|
|
int index = int(color.r*16.0);
|
2015-08-18 09:45:04 +00:00
|
|
|
return vec4(vec3(palette[index]/16.0),1.0);
|
2015-08-17 14:47:42 +00:00
|
|
|
}]])
|
2015-08-18 09:45:04 +00:00
|
|
|
__draw_shader:send('palette',unpack(__draw_palette))
|
2015-08-16 16:00:39 +00:00
|
|
|
|
|
|
|
__sprite_shader = love.graphics.newShader([[
|
2015-08-18 09:45:04 +00:00
|
|
|
extern float palette[16];
|
|
|
|
extern float transparent[16];
|
2015-08-17 14:47:42 +00:00
|
|
|
|
|
|
|
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
|
2015-08-18 09:45:04 +00:00
|
|
|
int index = int(floor(Texel(texture, texture_coords).r*16.0));
|
|
|
|
float alpha = transparent[index];
|
|
|
|
return vec4(vec3(palette[index]/16.0),alpha);
|
2015-08-17 14:47:42 +00:00
|
|
|
}]])
|
2015-08-18 09:45:04 +00:00
|
|
|
__sprite_shader:send('palette',unpack(__draw_palette))
|
|
|
|
__sprite_shader:send('transparent',unpack(__pico_pal_transparent))
|
2015-08-17 14:47:42 +00:00
|
|
|
|
|
|
|
__text_shader = love.graphics.newShader([[
|
2015-08-18 09:45:04 +00:00
|
|
|
extern float palette[16];
|
2015-08-16 16:00:39 +00:00
|
|
|
|
|
|
|
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
|
|
|
|
vec4 texcolor = Texel(texture, texture_coords);
|
2015-08-17 14:47:42 +00:00
|
|
|
if(texcolor.a == 0) {
|
|
|
|
return vec4(0.0,0.0,0.0,0.0);
|
2015-08-16 16:00:39 +00:00
|
|
|
}
|
2015-08-17 14:47:42 +00:00
|
|
|
int index = int(color.r*16.0);
|
|
|
|
// lookup the colour in the palette by index
|
2015-08-18 09:45:04 +00:00
|
|
|
return vec4(vec3(palette[index]/16.0),1.0);
|
2015-08-16 16:00:39 +00:00
|
|
|
}]])
|
2015-08-18 09:45:04 +00:00
|
|
|
__text_shader:send('palette',unpack(__draw_palette))
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-08-17 14:47:42 +00:00
|
|
|
__display_shader = love.graphics.newShader([[
|
2015-08-18 09:45:04 +00:00
|
|
|
|
|
|
|
extern vec4 palette[16];
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-08-17 14:47:42 +00:00
|
|
|
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
|
2015-08-18 09:45:04 +00:00
|
|
|
int index = int(Texel(texture, texture_coords).r*15.0);
|
2015-08-17 14:47:42 +00:00
|
|
|
// lookup the colour in the palette by index
|
2015-08-18 09:45:04 +00:00
|
|
|
return palette[index]/256.0;
|
2015-08-17 14:47:42 +00:00
|
|
|
}]])
|
2015-08-18 09:45:04 +00:00
|
|
|
__display_shader:send('palette',unpack(__display_palette))
|
2015-08-17 14:47:42 +00:00
|
|
|
|
|
|
|
pal()
|
2015-08-16 16:00:39 +00:00
|
|
|
|
|
|
|
-- load the cart
|
2015-08-17 09:11:50 +00:00
|
|
|
clip()
|
|
|
|
camera()
|
|
|
|
pal()
|
2015-09-11 11:30:37 +00:00
|
|
|
palt()
|
2015-08-17 09:11:50 +00:00
|
|
|
color(0)
|
2015-09-11 14:49:38 +00:00
|
|
|
|
2015-09-11 11:18:24 +00:00
|
|
|
_load(argv[2] or 'nocart.p8')
|
2015-08-17 11:14:08 +00:00
|
|
|
run()
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function load_p8(filename)
|
2015-09-11 14:49:38 +00:00
|
|
|
log("Loading",filename)
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
local lua = ""
|
2015-08-16 16:00:39 +00:00
|
|
|
__pico_map = {}
|
|
|
|
__pico_quads = {}
|
|
|
|
for y=0,63 do
|
|
|
|
__pico_map[y] = {}
|
2015-08-17 16:36:58 +00:00
|
|
|
for x=0,127 do
|
|
|
|
__pico_map[y][x] = 0
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
__pico_spritesheet_data = love.image.newImageData(128,128)
|
2015-09-11 14:49:38 +00:00
|
|
|
__pico_spriteflags = {}
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
if filename:sub(#filename-3,#filename) == '.png' then
|
|
|
|
local img = love.graphics.newImage(filename)
|
|
|
|
if img:getWidth() ~= 160 or img:getHeight() ~= 205 then
|
|
|
|
error("Image is the wrong size")
|
|
|
|
end
|
|
|
|
local data = img:getData()
|
|
|
|
|
|
|
|
local outX = 0
|
|
|
|
local outY = 0
|
|
|
|
local inbyte = 0
|
|
|
|
local lastbyte = nil
|
|
|
|
local mapY = 32
|
|
|
|
local mapX = 0
|
|
|
|
local version = nil
|
|
|
|
local codelen = nil
|
|
|
|
local code = ""
|
|
|
|
local sprite = 0
|
|
|
|
for y=0,204 do
|
|
|
|
for x=0,159 do
|
|
|
|
local r,g,b,a = data:getPixel(x,y)
|
|
|
|
-- extract lowest bits
|
|
|
|
r = bit.band(r,0x0003)
|
|
|
|
g = bit.band(g,0x0003)
|
|
|
|
b = bit.band(b,0x0003)
|
|
|
|
a = bit.band(a,0x0003)
|
|
|
|
data:setPixel(x,y,bit.lshift(r,6),bit.lshift(g,6),bit.lshift(b,6),255)
|
|
|
|
local byte = b + bit.lshift(g,2) + bit.lshift(r,4) + bit.lshift(a,6)
|
|
|
|
local lo = bit.band(byte,0x0f)
|
|
|
|
local hi = bit.rshift(byte,4)
|
|
|
|
if inbyte < 0x2000 then
|
|
|
|
if outY >= 64 then
|
|
|
|
__pico_map[mapY][mapX] = byte
|
|
|
|
mapX = mapX + 1
|
|
|
|
if mapX == 128 then
|
|
|
|
mapX = 0
|
|
|
|
mapY = mapY + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
__pico_spritesheet_data:setPixel(outX,outY,lo*16,lo*16,lo*16)
|
|
|
|
outX = outX + 1
|
|
|
|
__pico_spritesheet_data:setPixel(outX,outY,hi*16,hi*16,hi*16)
|
|
|
|
outX = outX + 1
|
|
|
|
if outX == 128 then
|
|
|
|
outY = outY + 1
|
|
|
|
outX = 0
|
|
|
|
if outY == 128 then
|
|
|
|
-- end of spritesheet, generate quads
|
|
|
|
__pico_spritesheet = love.graphics.newImage(__pico_spritesheet_data)
|
|
|
|
local sprite = 0
|
|
|
|
for yy=0,15 do
|
|
|
|
for xx=0,15 do
|
|
|
|
__pico_quads[sprite] = love.graphics.newQuad(xx*8,yy*8,8,8,__pico_spritesheet:getDimensions())
|
|
|
|
sprite = sprite + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
mapY = 0
|
|
|
|
mapX = 0
|
|
|
|
end
|
|
|
|
end
|
|
|
|
elseif inbyte < 0x3000 then
|
2015-08-25 13:15:58 +00:00
|
|
|
__pico_map[mapY][mapX] = byte
|
|
|
|
mapX = mapX + 1
|
|
|
|
if mapX == 128 then
|
|
|
|
mapX = 0
|
|
|
|
mapY = mapY + 1
|
|
|
|
end
|
2015-09-11 14:49:38 +00:00
|
|
|
elseif inbyte < 0x3100 then
|
|
|
|
__pico_spriteflags[sprite] = byte
|
|
|
|
sprite = sprite + 1
|
|
|
|
elseif inbyte < 0x3200 then
|
|
|
|
-- load song
|
|
|
|
elseif inbyte < 0x4300 then
|
|
|
|
-- sfx
|
|
|
|
elseif inbyte == 0x8000 then
|
|
|
|
version = byte
|
|
|
|
else
|
|
|
|
-- code, possibly compressed
|
|
|
|
if inbyte == 0x4305 then
|
|
|
|
codelen = bit.lshift(lastbyte,8) + byte
|
|
|
|
elseif inbyte >= 0x4308 then
|
|
|
|
code = code .. string.char(byte)
|
|
|
|
end
|
|
|
|
lastbyte = byte
|
2015-08-25 13:15:58 +00:00
|
|
|
end
|
2015-09-11 14:49:38 +00:00
|
|
|
inbyte = inbyte + 1
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
-- decompress code
|
|
|
|
log('version',version)
|
|
|
|
log('codelen',codelen)
|
|
|
|
if version == 0 then
|
|
|
|
lua = code
|
|
|
|
elseif version == 1 then
|
|
|
|
-- decompress code
|
|
|
|
local mode = 0
|
|
|
|
local copy = nil
|
|
|
|
local i = 0
|
|
|
|
while #lua < codelen do
|
|
|
|
i = i + 1
|
|
|
|
local byte = string.byte(code,i,i)
|
|
|
|
if byte == nil then
|
|
|
|
error('reached end of code')
|
|
|
|
else
|
|
|
|
if mode == 1 then
|
|
|
|
lua = lua .. code:sub(i,i)
|
|
|
|
mode = 0
|
|
|
|
elseif mode == 2 then
|
|
|
|
-- copy from buffer
|
|
|
|
local offset = (copy - 0x3c) * 16 + bit.band(byte,0xf)
|
|
|
|
local length = bit.rshift(byte,4) + 2
|
|
|
|
|
|
|
|
local offset = #lua - offset
|
|
|
|
local buffer = lua:sub(offset+1,offset+1+length-1)
|
|
|
|
lua = lua .. buffer
|
|
|
|
mode = 0
|
|
|
|
elseif byte == 0x00 then
|
|
|
|
-- output next byte
|
|
|
|
mode = 1
|
|
|
|
elseif byte == 0x01 then
|
|
|
|
-- output newline
|
|
|
|
lua = lua .. "\n"
|
|
|
|
elseif byte >= 0x02 and byte <= 0x3b then
|
|
|
|
-- output this byte from map
|
|
|
|
lua = lua .. __compression_map[byte]
|
|
|
|
elseif byte >= 0x3c then
|
|
|
|
-- copy previous bytes
|
|
|
|
mode = 2
|
|
|
|
copy = byte
|
2015-08-25 13:15:58 +00:00
|
|
|
end
|
|
|
|
end
|
2015-08-17 16:36:58 +00:00
|
|
|
end
|
2015-09-11 14:49:38 +00:00
|
|
|
else
|
|
|
|
error(string.format('unknown file version %d',version))
|
2015-08-17 16:36:58 +00:00
|
|
|
end
|
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
else
|
|
|
|
local f = love.filesystem.newFile(filename,'r')
|
|
|
|
if not f then
|
2015-09-12 03:54:23 +00:00
|
|
|
error(string.format("Unable to open: %s",filename))
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-09-11 14:49:38 +00:00
|
|
|
local data,size = f:read()
|
|
|
|
f:close()
|
|
|
|
if not data then
|
|
|
|
error("invalid cart")
|
|
|
|
end
|
|
|
|
local header = "pico-8 cartridge // http://www.pico-8.com\nversion "
|
|
|
|
local start = data:find("pico%-8 cartridge // http://www.pico%-8.com\nversion ")
|
|
|
|
if start == nil then
|
|
|
|
error("invalid cart")
|
|
|
|
end
|
|
|
|
local next_line = data:find("\n",start+#header)
|
|
|
|
local version_str = data:sub(start+#header,next_line-1)
|
|
|
|
local version = tonumber(version_str)
|
|
|
|
log("version",version)
|
|
|
|
-- extract the lua
|
|
|
|
local lua_start = data:find("__lua__") + 8
|
|
|
|
local lua_end = data:find("__gfx__") - 1
|
|
|
|
|
2015-09-11 15:25:50 +00:00
|
|
|
lua = data:sub(lua_start,lua_end)
|
2015-09-11 14:49:38 +00:00
|
|
|
|
|
|
|
-- load the sprites into an imagedata
|
|
|
|
-- generate a quad for each sprite index
|
|
|
|
local gfx_start = data:find("__gfx__") + 8
|
|
|
|
local gfx_end = data:find("__gff__") - 1
|
|
|
|
local gfxdata = data:sub(gfx_start,gfx_end)
|
|
|
|
|
|
|
|
local row = 0
|
|
|
|
local tile_row = 32
|
|
|
|
local tile_col = 0
|
|
|
|
local col = 0
|
|
|
|
local sprite = 0
|
|
|
|
local tiles = 0
|
|
|
|
local shared = 0
|
|
|
|
|
|
|
|
local next_line = 1
|
|
|
|
while next_line do
|
|
|
|
local end_of_line = gfxdata:find("\n",next_line)
|
|
|
|
if end_of_line == nil then break end
|
|
|
|
end_of_line = end_of_line - 1
|
|
|
|
local line = gfxdata:sub(next_line,end_of_line)
|
|
|
|
for i=1,#line do
|
|
|
|
local v = line:sub(i,i)
|
|
|
|
v = tonumber(v,16)
|
|
|
|
__pico_spritesheet_data:setPixel(col,row,v*16,v*16,v*16,255)
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
col = col + 1
|
|
|
|
if col == 128 then
|
|
|
|
col = 0
|
|
|
|
row = row + 1
|
2015-08-25 13:15:58 +00:00
|
|
|
end
|
|
|
|
end
|
2015-09-11 14:49:38 +00:00
|
|
|
next_line = gfxdata:find("\n",end_of_line)+1
|
2015-08-25 13:15:58 +00:00
|
|
|
end
|
2015-08-20 10:03:01 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
if version > 2 then
|
|
|
|
local tx,ty = 0,32
|
|
|
|
for sy=64,127 do
|
|
|
|
for sx=0,127,2 do
|
|
|
|
-- get the two pixel values and merge them
|
|
|
|
local lo = flr(__pico_spritesheet_data:getPixel(sx,sy)/16)
|
|
|
|
local hi = flr(__pico_spritesheet_data:getPixel(sx+1,sy)/16)
|
|
|
|
local v = bor(shl(hi,4),lo)
|
|
|
|
__pico_map[ty][tx] = v
|
|
|
|
shared = shared + 1
|
|
|
|
tx = tx + 1
|
|
|
|
if tx == 128 then
|
|
|
|
tx = 0
|
|
|
|
ty = ty + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
assert(shared == 128 * 32,shared)
|
2015-08-25 13:15:58 +00:00
|
|
|
end
|
2015-08-20 10:03:01 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
for y=0,15 do
|
|
|
|
for x=0,15 do
|
|
|
|
__pico_quads[sprite] = love.graphics.newQuad(8*x,8*y,8,8,128,128)
|
|
|
|
sprite = sprite + 1
|
|
|
|
end
|
2015-08-25 13:15:58 +00:00
|
|
|
end
|
2015-08-20 10:03:01 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
assert(sprite == 256,sprite)
|
2015-08-20 10:03:01 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
__pico_spritesheet = love.graphics.newImage(__pico_spritesheet_data)
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
-- load the sprite flags
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
local gff_start = data:find("__gff__") + 8
|
|
|
|
local gff_end = data:find("__map__") - 1
|
|
|
|
local gffdata = data:sub(gff_start,gff_end)
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
local sprite = 0
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
local next_line = 1
|
|
|
|
while next_line do
|
|
|
|
local end_of_line = gffdata:find("\n",next_line)
|
|
|
|
if end_of_line == nil then break end
|
|
|
|
end_of_line = end_of_line - 1
|
|
|
|
local line = gffdata:sub(next_line,end_of_line)
|
|
|
|
if version <= 2 then
|
|
|
|
for i=1,#line do
|
|
|
|
local v = line:sub(i)
|
|
|
|
v = tonumber(v,16)
|
|
|
|
__pico_spriteflags[sprite] = v
|
|
|
|
sprite = sprite + 1
|
|
|
|
end
|
|
|
|
else
|
|
|
|
for i=1,#line,2 do
|
|
|
|
local v = line:sub(i,i+1)
|
|
|
|
v = tonumber(v,16)
|
|
|
|
__pico_spriteflags[sprite] = v
|
|
|
|
sprite = sprite + 1
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-09-11 14:49:38 +00:00
|
|
|
next_line = gfxdata:find("\n",end_of_line)+1
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
2015-09-11 15:21:04 +00:00
|
|
|
assert(sprite == 256,"wrong number of spriteflags:"..sprite)
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
-- convert the tile data to a table
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
local map_start = data:find("__map__") + 8
|
|
|
|
local map_end = data:find("__sfx__") - 1
|
|
|
|
local mapdata = data:sub(map_start,map_end)
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
local row = 0
|
|
|
|
local col = 0
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
local next_line = 1
|
|
|
|
while next_line do
|
|
|
|
local end_of_line = mapdata:find("\n",next_line)
|
|
|
|
if end_of_line == nil then
|
|
|
|
break
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-09-11 14:49:38 +00:00
|
|
|
end_of_line = end_of_line - 1
|
|
|
|
local line = mapdata:sub(next_line,end_of_line)
|
|
|
|
for i=1,#line,2 do
|
|
|
|
local v = line:sub(i,i+1)
|
|
|
|
v = tonumber(v,16)
|
|
|
|
if col == 0 then
|
|
|
|
end
|
|
|
|
__pico_map[row][col] = v
|
|
|
|
col = col + 1
|
|
|
|
tiles = tiles + 1
|
|
|
|
if col == 128 then
|
|
|
|
col = 0
|
|
|
|
row = row + 1
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-09-11 14:49:38 +00:00
|
|
|
next_line = mapdata:find("\n",end_of_line)+1
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-09-11 14:49:38 +00:00
|
|
|
assert(tiles + shared == 128 * 64,string.format("%d + %d != %d",tiles,shared,128*64))
|
2015-09-12 03:54:23 +00:00
|
|
|
|
|
|
|
-- load sfx
|
|
|
|
local sfx_start = data:find("__sfx__") + 8
|
|
|
|
local sfx_end = data:find("__music__") - 1
|
|
|
|
local sfxdata = data:sub(sfx_start,sfx_end)
|
|
|
|
|
|
|
|
__pico_sfx = {}
|
|
|
|
for i=0,63 do
|
|
|
|
__pico_sfx[i] = {
|
|
|
|
speed=16,
|
|
|
|
loop_start=0,
|
|
|
|
loop_end=0
|
|
|
|
}
|
|
|
|
for j=0,31 do
|
|
|
|
__pico_sfx[i][j] = {0,0,0,0}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local _sfx = 0
|
|
|
|
local step = 0
|
|
|
|
|
|
|
|
local next_line = 1
|
|
|
|
while next_line do
|
|
|
|
local end_of_line = sfxdata:find("\n",next_line)
|
|
|
|
if end_of_line == nil then break end
|
|
|
|
end_of_line = end_of_line - 1
|
|
|
|
local line = sfxdata:sub(next_line,end_of_line)
|
|
|
|
local editor_mode = tonumber(line:sub(1,2),16)
|
|
|
|
__pico_sfx[_sfx].speed = tonumber(line:sub(3,4),16)
|
|
|
|
__pico_sfx[_sfx].loop_start = tonumber(line:sub(5,6),16)
|
|
|
|
__pico_sfx[_sfx].loop_end = tonumber(line:sub(7,8),16)
|
|
|
|
for i=9,#line,5 do
|
|
|
|
local v = line:sub(i,i+4)
|
|
|
|
assert(#v == 5)
|
|
|
|
local note = tonumber(line:sub(i,i+1),16)
|
|
|
|
local instr = tonumber(line:sub(i+2,i+2),16)
|
|
|
|
local vol = tonumber(line:sub(i+3,i+3),16)
|
|
|
|
local fx = tonumber(line:sub(i+4,i+4),16)
|
|
|
|
__pico_sfx[_sfx][step] = {note,instr,vol,fx}
|
|
|
|
step = step + 1
|
|
|
|
end
|
|
|
|
_sfx = _sfx + 1
|
|
|
|
step = 0
|
|
|
|
next_line = sfxdata:find("\n",end_of_line)+1
|
|
|
|
end
|
|
|
|
|
|
|
|
assert(_sfx == 64)
|
|
|
|
|
|
|
|
-- load music
|
|
|
|
local music_start = data:find("__music__") + 10
|
|
|
|
local music_end = #data-1
|
|
|
|
local musicdata = data:sub(music_start,music_end)
|
|
|
|
|
|
|
|
local _music = 0
|
|
|
|
__pico_music = {}
|
|
|
|
|
|
|
|
local next_line = 1
|
|
|
|
while next_line do
|
|
|
|
local end_of_line = musicdata:find("\n",next_line)
|
|
|
|
if end_of_line == nil then break end
|
|
|
|
end_of_line = end_of_line - 1
|
|
|
|
local line = musicdata:sub(next_line,end_of_line)
|
|
|
|
|
|
|
|
__pico_music[_music] = {
|
|
|
|
loop = tonumber(line:sub(1,2),16),
|
|
|
|
a = tonumber(line:sub(4,5),16),
|
|
|
|
b = tonumber(line:sub(6,7),16),
|
|
|
|
c = tonumber(line:sub(8,9),16),
|
|
|
|
d = tonumber(line:sub(10,11),16)
|
|
|
|
}
|
|
|
|
_music = _music + 1
|
|
|
|
next_line = musicdata:find("\n",end_of_line)+1
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-08-17 04:25:08 +00:00
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
-- patch the lua
|
2015-08-18 17:42:23 +00:00
|
|
|
--lua = lua:gsub("%-%-[^\n]*\n","\n")
|
2015-08-16 16:00:39 +00:00
|
|
|
lua = lua:gsub("!=","~=")
|
2015-08-18 16:35:53 +00:00
|
|
|
-- rewrite shorthand if statements eg. if (not b) i=1 j=2
|
|
|
|
lua = lua:gsub("if%s*(%b())%s*([^\n]*)\n",function(a,b)
|
|
|
|
local nl = a:find('\n')
|
|
|
|
local th = b:find('%f[%w]then%f[%W]')
|
|
|
|
local an = b:find('%f[%w]and%f[%W]')
|
|
|
|
local o = b:find('%f[%w]or%f[W]')
|
|
|
|
if nl or th or an or o then
|
|
|
|
return string.format('if %s %s\n',a,b)
|
|
|
|
else
|
|
|
|
return "if "..a:sub(2,#a-1).." then "..b.." end\n"
|
2015-08-21 16:10:34 +00:00
|
|
|
end
|
2015-08-18 16:35:53 +00:00
|
|
|
end)
|
2015-08-16 16:00:39 +00:00
|
|
|
-- rewrite assignment operators
|
2015-09-11 11:18:37 +00:00
|
|
|
lua = lua:gsub("(%S+)%s*([%+-%*/%%])=","%1 = %1 %2 ")
|
2015-08-21 16:10:34 +00:00
|
|
|
|
|
|
|
local cart_G = {
|
|
|
|
-- extra functions provided by picolove
|
|
|
|
assert=assert,
|
|
|
|
error=error,
|
|
|
|
log=log,
|
|
|
|
pairs=pairs,
|
|
|
|
ipairs=ipairs,
|
2015-09-11 11:17:41 +00:00
|
|
|
warning=warning,
|
2015-09-11 11:30:37 +00:00
|
|
|
setfps=setfps,
|
|
|
|
_keydown=nil,
|
|
|
|
_keyup=nil,
|
2015-09-11 11:35:58 +00:00
|
|
|
_textinput=nil,
|
2015-08-21 16:10:34 +00:00
|
|
|
-- pico8 api functions go here
|
|
|
|
clip=clip,
|
|
|
|
pget=pget,
|
|
|
|
pset=pset,
|
|
|
|
sget=sget,
|
|
|
|
sset=sset,
|
|
|
|
fget=fget,
|
|
|
|
fset=fset,
|
|
|
|
flip=flip,
|
|
|
|
print=print,
|
|
|
|
cursor=cursor,
|
|
|
|
color=color,
|
|
|
|
cls=cls,
|
|
|
|
camera=camera,
|
|
|
|
circ=circ,
|
|
|
|
circfill=circfill,
|
|
|
|
line=line,
|
2015-09-11 11:18:24 +00:00
|
|
|
load=_load,
|
2015-08-21 16:10:34 +00:00
|
|
|
rect=rect,
|
|
|
|
rectfill=rectfill,
|
|
|
|
run=run,
|
|
|
|
reload=reload,
|
|
|
|
pal=pal,
|
|
|
|
palt=palt,
|
|
|
|
spr=spr,
|
|
|
|
sspr=sspr,
|
|
|
|
add=add,
|
|
|
|
del=del,
|
|
|
|
foreach=foreach,
|
|
|
|
count=count,
|
|
|
|
all=all,
|
|
|
|
btn=btn,
|
|
|
|
btnp=btnp,
|
|
|
|
sfx=sfx,
|
|
|
|
music=music,
|
|
|
|
mget=mget,
|
|
|
|
mset=mset,
|
|
|
|
map=map,
|
|
|
|
memcpy=memcpy,
|
|
|
|
peek=peek,
|
|
|
|
poke=poke,
|
|
|
|
max=max,
|
|
|
|
min=min,
|
|
|
|
mid=mid,
|
|
|
|
flr=flr,
|
|
|
|
cos=cos,
|
|
|
|
sin=sin,
|
|
|
|
atan2=atan2,
|
|
|
|
sqrt=sqrt,
|
|
|
|
abs=abs,
|
|
|
|
rnd=rnd,
|
|
|
|
srand=srand,
|
|
|
|
sgn=sgn,
|
|
|
|
band=band,
|
|
|
|
bor=bor,
|
|
|
|
bxor=bxor,
|
|
|
|
bnot=bnot,
|
|
|
|
shl=shl,
|
|
|
|
shr=shr,
|
|
|
|
sub=sub,
|
|
|
|
stat=stat,
|
|
|
|
-- deprecated pico-8 function aliases
|
|
|
|
mapdraw=map
|
|
|
|
}
|
|
|
|
|
2015-09-11 14:49:38 +00:00
|
|
|
local ok,f,e = pcall(load,lua,cartname)
|
2015-08-18 12:00:57 +00:00
|
|
|
if not ok or f==nil then
|
|
|
|
error("Error loading lua: "..tostring(e))
|
|
|
|
else
|
|
|
|
local result
|
|
|
|
setfenv(f,cart_G)
|
|
|
|
love.graphics.setShader(__draw_shader)
|
|
|
|
love.graphics.setCanvas(__screen)
|
|
|
|
love.graphics.origin()
|
|
|
|
restore_clip()
|
|
|
|
ok,result = pcall(f)
|
|
|
|
if not ok then
|
|
|
|
error("Error running lua: "..tostring(result))
|
|
|
|
else
|
2015-08-20 10:03:01 +00:00
|
|
|
log("lua completed")
|
2015-08-18 12:00:57 +00:00
|
|
|
end
|
|
|
|
end
|
2015-09-11 14:49:38 +00:00
|
|
|
log("finished loading cart",filename)
|
2015-08-18 12:00:57 +00:00
|
|
|
|
2015-08-17 04:25:08 +00:00
|
|
|
return cart_G
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function love.update(dt)
|
2015-08-17 14:47:42 +00:00
|
|
|
host_time = host_time + dt
|
2015-08-18 16:35:53 +00:00
|
|
|
for p=0,1 do
|
|
|
|
for i=0,#__keymap[p] do
|
|
|
|
local v = __pico_keypressed[p][i]
|
|
|
|
if v then
|
|
|
|
v = v + 1
|
|
|
|
__pico_keypressed[p][i] = v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2015-08-17 04:25:08 +00:00
|
|
|
if cart._update then cart._update() end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
2015-08-17 14:47:42 +00:00
|
|
|
function love.resize(w,h)
|
2015-08-17 16:36:58 +00:00
|
|
|
love.graphics.clear()
|
2015-08-17 14:47:42 +00:00
|
|
|
-- adjust stuff to fit the screen
|
|
|
|
if w > h then
|
2015-09-11 11:30:37 +00:00
|
|
|
scale = h/(__pico_resolution[2]+ypadding*2)
|
2015-08-17 14:47:42 +00:00
|
|
|
else
|
2015-09-11 11:30:37 +00:00
|
|
|
scale = w/(__pico_resolution[1]+xpadding*2)
|
2015-08-17 14:47:42 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
function love.run()
|
|
|
|
if love.math then
|
|
|
|
love.math.setRandomSeed(os.time())
|
|
|
|
for i=1,3 do love.math.random() end
|
|
|
|
end
|
|
|
|
|
|
|
|
if love.event then
|
|
|
|
love.event.pump()
|
|
|
|
end
|
|
|
|
|
|
|
|
if love.load then love.load(arg) end
|
|
|
|
|
|
|
|
-- We don't want the first frame's dt to include time taken by love.load.
|
|
|
|
if love.timer then love.timer.step() end
|
|
|
|
|
|
|
|
local dt = 0
|
|
|
|
|
|
|
|
-- Main loop time.
|
|
|
|
while true do
|
|
|
|
-- Process events.
|
|
|
|
if love.event then
|
|
|
|
love.event.pump()
|
|
|
|
for e,a,b,c,d in love.event.poll() do
|
|
|
|
if e == "quit" then
|
|
|
|
if not love.quit or not love.quit() then
|
|
|
|
if love.audio then
|
|
|
|
love.audio.stop()
|
|
|
|
end
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
love.handlers[e](a,b,c,d)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Update dt, as we'll be passing it to update
|
|
|
|
if love.timer then
|
|
|
|
love.timer.step()
|
|
|
|
dt = dt + love.timer.getDelta()
|
|
|
|
end
|
|
|
|
|
2015-09-09 11:51:34 +00:00
|
|
|
-- Call update and draw
|
|
|
|
local render = false
|
2015-09-11 11:30:37 +00:00
|
|
|
while dt > frametime do
|
|
|
|
if love.update then love.update(frametime) end -- will pass 0 if love.timer is disabled
|
2015-09-12 03:54:23 +00:00
|
|
|
update_audio(frametime)
|
2015-09-11 11:30:37 +00:00
|
|
|
dt = dt - frametime
|
2015-08-16 16:00:39 +00:00
|
|
|
render = true
|
|
|
|
end
|
|
|
|
|
|
|
|
if render and love.window and love.graphics and love.window.isCreated() then
|
|
|
|
love.graphics.origin()
|
|
|
|
if love.draw then love.draw() end
|
|
|
|
end
|
|
|
|
|
|
|
|
if love.timer then love.timer.sleep(0.001) end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-09-12 09:30:38 +00:00
|
|
|
note_map = {
|
|
|
|
[0] = 'C-',
|
|
|
|
'C#',
|
|
|
|
'D-',
|
|
|
|
'D#',
|
|
|
|
'E-',
|
|
|
|
'F-',
|
|
|
|
'F#',
|
|
|
|
'G-',
|
|
|
|
'G#',
|
|
|
|
'A-',
|
|
|
|
'A#',
|
|
|
|
'B-',
|
|
|
|
}
|
|
|
|
|
|
|
|
function note_to_string(note)
|
|
|
|
local octave = flr(note/12)
|
|
|
|
local note = flr(note%12)
|
|
|
|
return string.format("%s%d",note_map[note],octave)
|
|
|
|
end
|
|
|
|
|
2015-09-12 03:54:23 +00:00
|
|
|
function note_to_hz(note)
|
2015-09-12 09:30:38 +00:00
|
|
|
return 440*math.pow(2,(note-33)/12)
|
2015-09-12 03:54:23 +00:00
|
|
|
end
|
|
|
|
|
2015-09-12 09:30:38 +00:00
|
|
|
total_samples = 0
|
|
|
|
|
2015-09-12 03:54:23 +00:00
|
|
|
function update_audio(time)
|
|
|
|
-- check what sfx should be playing
|
2015-09-12 09:30:38 +00:00
|
|
|
local samples = flr(time*__sample_rate)
|
2015-09-12 03:54:23 +00:00
|
|
|
for channel=0,3 do
|
|
|
|
local ch = __pico_audio_channels[channel]
|
2015-09-12 09:30:38 +00:00
|
|
|
local tick = 0
|
|
|
|
local tickrate = 60*16
|
|
|
|
local note,instr,vol,fx
|
|
|
|
local freq
|
|
|
|
for i=0,samples-1 do
|
|
|
|
if ch.bufferpos == 0 or ch.bufferpos == nil then
|
|
|
|
ch.buffer = love.sound.newSoundData(__audio_buffer_size,__sample_rate,bits,channels)
|
|
|
|
ch.bufferpos = 0
|
|
|
|
end
|
|
|
|
if ch.sfx then
|
|
|
|
local sfx = __pico_sfx[ch.sfx]
|
|
|
|
ch.offset = ch.offset + 1/256*(1/sfx.speed)
|
|
|
|
if sfx.loop_end ~= 0 and ch.offset > sfx.loop_end then
|
|
|
|
log('sfx reached loop end',channel,ch.sfx)
|
|
|
|
if ch.loop then
|
|
|
|
log('looping to ',sfx.loop_start)
|
|
|
|
ch.last_step = -1
|
|
|
|
ch.offset = sfx.loop_start
|
|
|
|
else
|
|
|
|
log('ending')
|
|
|
|
__pico_audio_channels[channel].sfx = nil
|
|
|
|
end
|
|
|
|
elseif ch.offset >= 32 then
|
|
|
|
log('sfx finished',channel,ch.sfx)
|
|
|
|
__pico_audio_channels[channel].sfx = nil
|
2015-09-12 03:54:23 +00:00
|
|
|
end
|
2015-09-12 09:30:38 +00:00
|
|
|
end
|
|
|
|
if ch.sfx then
|
|
|
|
local sfx = __pico_sfx[ch.sfx]
|
|
|
|
-- when we pass a new step
|
|
|
|
if flr(ch.offset) > ch.last_step then
|
|
|
|
ch.lastnote = ch.note
|
|
|
|
ch.note,ch.instr,ch.vol,ch.fx = unpack(sfx[flr(ch.offset)])
|
|
|
|
if ch.vol == 0 then
|
|
|
|
log('-')
|
|
|
|
else
|
|
|
|
log(note_to_string(ch.note),ch.instr,ch.vol,ch.fx)
|
|
|
|
end
|
|
|
|
if ch.vol > 0 then
|
|
|
|
ch.freq = note_to_hz(ch.note)
|
2015-09-12 03:54:23 +00:00
|
|
|
end
|
2015-09-12 09:30:38 +00:00
|
|
|
ch.last_step = flr(ch.offset)
|
2015-09-12 03:54:23 +00:00
|
|
|
end
|
2015-09-12 09:30:38 +00:00
|
|
|
if ch.vol and ch.vol > 0 then
|
|
|
|
local vol = ch.vol
|
|
|
|
if ch.fx == 1 then
|
|
|
|
-- slide from previous note over the length of a step
|
|
|
|
ch.freq = lerp(note_to_hz(ch.lastnote or 0),note_to_hz(ch.note),ch.offset%1)
|
|
|
|
elseif ch.fx == 2 then
|
|
|
|
-- vibrato one semitone?
|
|
|
|
ch.freq = lerp(note_to_hz(ch.note),note_to_hz(ch.note+1),(ch.offset%0.5)*2)
|
|
|
|
elseif ch.fx == 3 then
|
|
|
|
-- drop/bomb slide from note to c-0
|
|
|
|
ch.freq = lerp(note_to_hz(ch.note),note_to_hz(0),ch.offset%1)
|
|
|
|
elseif ch.fx == 4 then
|
|
|
|
-- fade in
|
|
|
|
vol = lerp(0,ch.vol,ch.offset%1)
|
|
|
|
elseif ch.fx == 5 then
|
|
|
|
-- fade out
|
|
|
|
vol = lerp(ch.vol,0,ch.offset%1)
|
|
|
|
elseif ch.fx == 6 then
|
|
|
|
-- fast appreggio over 4 steps
|
|
|
|
ch.freq = note_to_hz(sfx[flr(ch.offset/4)+(ch.offset*tickrate/4)%4][1])
|
|
|
|
elseif ch.fx == 7 then
|
|
|
|
-- slow appreggio over 4 steps
|
|
|
|
ch.freq = note_to_hz(sfx[flr(ch.offset/4)+(ch.offset*tickrate/8)%4][1])
|
2015-09-12 03:54:23 +00:00
|
|
|
end
|
2015-09-12 09:30:38 +00:00
|
|
|
ch.sample = osc[ch.instr]((total_samples+i)*(ch.freq/__sample_rate)) * vol/7
|
|
|
|
if ch.offset%1 < 0.1 then
|
|
|
|
-- ramp up to avoid pops
|
|
|
|
ch.sample = lerp(0,ch.sample,ch.offset%0.1*10)
|
|
|
|
elseif ch.offset%1 > 0.9 then
|
|
|
|
-- ramp down to avoid pops
|
|
|
|
ch.sample = lerp(ch.sample,0,(ch.offset+0.8)%0.1*10)
|
2015-09-12 03:54:23 +00:00
|
|
|
end
|
2015-09-12 09:30:38 +00:00
|
|
|
ch.buffer:setSample(ch.bufferpos,ch.sample)
|
2015-09-12 03:54:23 +00:00
|
|
|
else
|
|
|
|
ch.buffer:setSample(ch.bufferpos,lerp(ch.sample or 0,0,0.1))
|
|
|
|
ch.sample = 0
|
|
|
|
end
|
2015-09-12 09:30:38 +00:00
|
|
|
else
|
|
|
|
ch.buffer:setSample(ch.bufferpos,lerp(ch.sample or 0,0,0.1))
|
|
|
|
ch.sample = 0
|
|
|
|
end
|
|
|
|
ch.bufferpos = ch.bufferpos + 1
|
|
|
|
if ch.bufferpos == __audio_buffer_size then
|
|
|
|
-- queue buffer and reset
|
|
|
|
__audio_channels[channel]:queue(ch.buffer)
|
|
|
|
__audio_channels[channel]:play()
|
|
|
|
ch.bufferpos = 0
|
2015-09-12 03:54:23 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2015-09-12 09:30:38 +00:00
|
|
|
total_samples = total_samples + samples
|
2015-09-12 03:54:23 +00:00
|
|
|
end
|
|
|
|
|
2015-08-18 12:00:57 +00:00
|
|
|
function flip_screen()
|
|
|
|
--love.graphics.setShader(__display_shader)
|
2015-08-17 14:47:42 +00:00
|
|
|
love.graphics.setShader(__display_shader)
|
2015-08-18 09:45:04 +00:00
|
|
|
__display_shader:send('palette',unpack(__display_palette))
|
2015-08-16 16:00:39 +00:00
|
|
|
love.graphics.setCanvas()
|
|
|
|
love.graphics.origin()
|
2015-08-17 16:36:58 +00:00
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
love.graphics.setColor(255,255,255,255)
|
|
|
|
love.graphics.setScissor()
|
2015-08-17 14:47:42 +00:00
|
|
|
|
2015-08-18 09:45:04 +00:00
|
|
|
love.graphics.clear()
|
|
|
|
|
2015-08-17 16:36:58 +00:00
|
|
|
local screen_w,screen_h = love.graphics.getDimensions()
|
2015-08-17 14:47:42 +00:00
|
|
|
if screen_w > screen_h then
|
|
|
|
love.graphics.draw(__screen,screen_w/2-64*scale,ypadding*scale,0,scale,scale)
|
|
|
|
else
|
|
|
|
love.graphics.draw(__screen,xpadding*scale,screen_h/2-64*scale,0,scale,scale)
|
|
|
|
end
|
2015-08-17 16:36:58 +00:00
|
|
|
|
2015-08-18 12:00:57 +00:00
|
|
|
love.graphics.present()
|
2015-08-20 10:03:01 +00:00
|
|
|
|
|
|
|
if video_frames then
|
2015-09-11 11:30:37 +00:00
|
|
|
local tmp = love.graphics.newCanvas(__pico_resolution[1],__pico_resolution[2])
|
2015-08-20 10:03:01 +00:00
|
|
|
love.graphics.setCanvas(tmp)
|
|
|
|
love.graphics.draw(__screen,0,0)
|
|
|
|
table.insert(video_frames,tmp:getImageData())
|
|
|
|
end
|
2015-08-17 16:36:58 +00:00
|
|
|
-- get ready for next time
|
|
|
|
love.graphics.setShader(__draw_shader)
|
2015-08-17 11:14:08 +00:00
|
|
|
love.graphics.setCanvas(__screen)
|
2015-08-18 12:00:57 +00:00
|
|
|
restore_clip()
|
|
|
|
restore_camera()
|
|
|
|
end
|
|
|
|
|
|
|
|
function love.draw()
|
|
|
|
love.graphics.setCanvas(__screen)
|
|
|
|
restore_clip()
|
|
|
|
restore_camera()
|
|
|
|
|
|
|
|
love.graphics.setShader(__draw_shader)
|
|
|
|
|
|
|
|
-- run the cart's draw function
|
|
|
|
if cart._draw then cart._draw() end
|
|
|
|
|
|
|
|
-- draw the contents of pico screen to our screen
|
|
|
|
flip_screen()
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function love.keypressed(key)
|
2015-09-11 11:35:58 +00:00
|
|
|
if cart and cart._keydown then
|
|
|
|
return cart._keydown(key)
|
2015-09-11 11:30:37 +00:00
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
if key == 'r' and love.keyboard.isDown('lctrl') then
|
2015-08-17 14:47:42 +00:00
|
|
|
reload()
|
2015-08-19 08:23:07 +00:00
|
|
|
elseif key == 'q' and love.keyboard.isDown('lctrl') then
|
|
|
|
love.event.quit()
|
2015-08-18 16:35:53 +00:00
|
|
|
elseif key == 'f6' then
|
|
|
|
-- screenshot
|
|
|
|
local screenshot = love.graphics.newScreenshot(false)
|
|
|
|
local filename = cartname..'-'..os.time()..'.png'
|
|
|
|
screenshot:encode(filename)
|
|
|
|
log('saved screenshort to',filename)
|
2015-08-20 10:03:01 +00:00
|
|
|
elseif key == 'f8' then
|
|
|
|
-- start recording
|
|
|
|
video_frames = {}
|
|
|
|
elseif key == 'f9' then
|
|
|
|
-- stop recording and save
|
|
|
|
local basename = cartname..'-'..os.time()..'-'
|
|
|
|
for i,v in ipairs(video_frames) do
|
|
|
|
v:encode(string.format("%s%04d.png",basename,i))
|
|
|
|
end
|
|
|
|
video_frames = nil
|
|
|
|
log('saved video to',basename)
|
2015-08-18 16:35:53 +00:00
|
|
|
else
|
|
|
|
for p=0,1 do
|
|
|
|
for i=0,#__keymap[p] do
|
|
|
|
if key == __keymap[p][i] then
|
2015-08-18 17:42:23 +00:00
|
|
|
__pico_keypressed[p][i] = -1 -- becomes 0 on the next frame
|
2015-08-18 16:35:53 +00:00
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function love.keyreleased(key)
|
2015-09-11 11:35:58 +00:00
|
|
|
if cart and cart._keyup then
|
|
|
|
return cart._keyup(key)
|
2015-09-11 11:30:37 +00:00
|
|
|
end
|
2015-08-18 16:35:53 +00:00
|
|
|
for p=0,1 do
|
|
|
|
for i=0,#__keymap[p] do
|
|
|
|
if key == __keymap[p][i] then
|
|
|
|
__pico_keypressed[p][i] = nil
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-08-21 16:10:34 +00:00
|
|
|
function music(n,fade_len,channel_mask)
|
|
|
|
__pico_current_music = {n,offset=0,channel_mask=channel_mask}
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
2015-09-11 15:21:04 +00:00
|
|
|
function love.textinput(text)
|
|
|
|
if cart and cart._textinput then return cart._textinput(text) end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
2015-08-21 16:10:34 +00:00
|
|
|
function sfx(n,channel,offset)
|
|
|
|
-- n = -1 stop sound on channel
|
|
|
|
-- n = -2 to stop looping on channel
|
|
|
|
channel = channel or -1
|
|
|
|
if n == -1 and channel >= 0 then
|
2015-09-12 09:30:38 +00:00
|
|
|
log('sfx end',channel)
|
|
|
|
__pico_audio_channels[channel].sfx = nil
|
2015-08-21 16:10:34 +00:00
|
|
|
return
|
|
|
|
elseif n == -2 and channel >= 0 then
|
|
|
|
__pico_audio_channels[channel].loop = false
|
|
|
|
end
|
|
|
|
log('sfx',n,channel,offset)
|
|
|
|
offset = offset or 0
|
|
|
|
if channel == -1 then
|
|
|
|
-- find a free channel
|
|
|
|
for i=0,3 do
|
2015-09-12 09:30:38 +00:00
|
|
|
if __pico_audio_channels[i].sfx == nil then
|
2015-08-21 16:10:34 +00:00
|
|
|
channel = i
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if channel == -1 then return end
|
2015-09-12 09:30:38 +00:00
|
|
|
local ch = __pico_audio_channels[channel]
|
|
|
|
ch.sfx=n
|
|
|
|
ch.offset=offset
|
|
|
|
ch.last_step=offset-1
|
|
|
|
ch.loop=true
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function clip(x,y,w,h)
|
|
|
|
if x then
|
|
|
|
love.graphics.setScissor(x,y,w,h)
|
2015-08-18 12:00:57 +00:00
|
|
|
__pico_clip = {x,y,w,h}
|
|
|
|
else
|
2015-09-11 11:30:37 +00:00
|
|
|
love.graphics.setScissor(0,0,__pico_resolution[1],__pico_resolution[2])
|
2015-08-18 12:00:57 +00:00
|
|
|
__pico_clip = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function restore_clip()
|
|
|
|
if __pico_clip then
|
|
|
|
love.graphics.setScissor(unpack(__pico_clip))
|
2015-08-16 16:00:39 +00:00
|
|
|
else
|
2015-09-11 11:30:37 +00:00
|
|
|
love.graphics.setScissor(0,0,__pico_resolution[1],__pico_resolution[2])
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function pget(x,y)
|
2015-09-11 11:30:37 +00:00
|
|
|
if x >= 0 and x < __pico_resolution[1] and y >= 0 and y < __pico_resolution[2] then
|
2015-08-18 12:00:57 +00:00
|
|
|
local r,g,b,a = __screen:getPixel(flr(x),flr(y))
|
|
|
|
return flr(r/17.0)
|
2015-08-16 16:00:39 +00:00
|
|
|
else
|
2015-09-11 11:30:37 +00:00
|
|
|
warning(string.format("pget out of screen %d,%d",x,y))
|
2015-09-10 12:07:12 +00:00
|
|
|
return 0
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function pset(x,y,c)
|
|
|
|
if not c then return end
|
|
|
|
color(c)
|
2015-08-18 12:00:57 +00:00
|
|
|
love.graphics.point(flr(x),flr(y),c*16,0,0,255)
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function sget(x,y)
|
|
|
|
-- return the color from the spritesheet
|
2015-08-17 14:47:42 +00:00
|
|
|
x = flr(x)
|
|
|
|
y = flr(y)
|
|
|
|
local r,g,b,a = __pico_spritesheet_data:getPixel(x,y)
|
|
|
|
return flr(r/16)
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function sset(x,y,c)
|
2015-08-17 14:47:42 +00:00
|
|
|
x = flr(x)
|
|
|
|
y = flr(y)
|
|
|
|
__pico_spritesheet_data:setPixel(x,y,c*16,0,0,255)
|
2015-08-18 16:35:53 +00:00
|
|
|
__pico_spritesheet:refresh()
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function fget(n,f)
|
|
|
|
if n == nil then return nil end
|
|
|
|
if f ~= nil then
|
|
|
|
-- return just that bit as a boolean
|
2015-09-11 14:50:23 +00:00
|
|
|
if not __pico_spriteflags[flr(n)] then
|
|
|
|
warning(string.format('fget(%d,%d)',n,f))
|
|
|
|
return 0
|
|
|
|
end
|
2015-08-17 09:11:50 +00:00
|
|
|
return band(__pico_spriteflags[flr(n)],shl(1,flr(f))) ~= 0
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-08-17 09:11:50 +00:00
|
|
|
return __pico_spriteflags[flr(n)]
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
2015-08-17 09:11:50 +00:00
|
|
|
assert(bit.band(0x01,bit.lshift(1,0)) ~= 0)
|
|
|
|
assert(bit.band(0x02,bit.lshift(1,1)) ~= 0)
|
|
|
|
assert(bit.band(0x04,bit.lshift(1,2)) ~= 0)
|
|
|
|
|
|
|
|
assert(bit.band(0x05,bit.lshift(1,2)) ~= 0)
|
|
|
|
assert(bit.band(0x05,bit.lshift(1,0)) ~= 0)
|
|
|
|
assert(bit.band(0x05,bit.lshift(1,3)) == 0)
|
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
function fset(n,f,v)
|
2015-08-18 12:00:57 +00:00
|
|
|
-- fset n [f] v
|
|
|
|
-- f is the flag index 0..7
|
|
|
|
-- v is boolean
|
2015-08-16 16:00:39 +00:00
|
|
|
if v == nil then
|
|
|
|
v,f = f,nil
|
|
|
|
end
|
|
|
|
if f then
|
2015-08-18 12:00:57 +00:00
|
|
|
-- set specific bit to v (true or false)
|
|
|
|
if f then
|
|
|
|
__pico_spriteflags[n] = bor(__pico_spriteflags[n],shl(1,f))
|
|
|
|
else
|
|
|
|
__pico_spriteflags[n] = band(bnot(__pico_spriteflags[n],shl(1,f)))
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
else
|
2015-08-18 12:00:57 +00:00
|
|
|
-- set bitfield to v (number)
|
2015-08-16 16:00:39 +00:00
|
|
|
__pico_spriteflags[n] = v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function flip()
|
2015-08-18 12:00:57 +00:00
|
|
|
flip_screen()
|
2015-09-11 11:30:37 +00:00
|
|
|
love.timer.sleep(frametime)
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
2015-08-17 03:05:08 +00:00
|
|
|
log = print
|
2015-08-16 16:00:39 +00:00
|
|
|
function print(str,x,y,col)
|
|
|
|
if col then color(col) end
|
2015-08-18 12:00:57 +00:00
|
|
|
if y==nil then
|
|
|
|
y = __pico_cursor[2]
|
2015-08-21 16:10:34 +00:00
|
|
|
__pico_cursor[2] = __pico_cursor[2] + 6
|
2015-08-18 12:00:57 +00:00
|
|
|
end
|
|
|
|
if x==nil then
|
|
|
|
x = __pico_cursor[1]
|
|
|
|
end
|
2015-08-17 14:47:42 +00:00
|
|
|
love.graphics.setShader(__text_shader)
|
2015-08-16 16:00:39 +00:00
|
|
|
love.graphics.print(str,flr(x),flr(y))
|
2015-08-17 14:47:42 +00:00
|
|
|
love.graphics.setShader(__text_shader)
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
2015-08-18 12:00:57 +00:00
|
|
|
__pico_cursor = {0,0}
|
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
function cursor(x,y)
|
|
|
|
__pico_cursor = {x,y}
|
|
|
|
end
|
|
|
|
|
|
|
|
function color(c)
|
|
|
|
c = flr(c)
|
2015-08-18 12:14:35 +00:00
|
|
|
assert(c >= 0 and c <= 16,string.format("c is %s",c))
|
2015-08-16 16:00:39 +00:00
|
|
|
__pico_color = c
|
2015-08-17 14:47:42 +00:00
|
|
|
love.graphics.setColor(c*16,0,0,255)
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function cls()
|
|
|
|
__screen:clear(0,0,0,255)
|
|
|
|
end
|
|
|
|
|
2015-08-17 17:04:45 +00:00
|
|
|
__pico_camera_x = 0
|
|
|
|
__pico_camera_y = 0
|
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
function camera(x,y)
|
|
|
|
if x ~= nil then
|
|
|
|
__pico_camera_x = flr(x)
|
|
|
|
__pico_camera_y = flr(y)
|
2015-08-17 09:11:50 +00:00
|
|
|
else
|
2015-08-16 16:00:39 +00:00
|
|
|
__pico_camera_x = 0
|
|
|
|
__pico_camera_y = 0
|
|
|
|
end
|
2015-08-18 12:00:57 +00:00
|
|
|
restore_camera()
|
|
|
|
end
|
|
|
|
|
|
|
|
function restore_camera()
|
|
|
|
love.graphics.origin()
|
|
|
|
love.graphics.translate(-__pico_camera_x,-__pico_camera_y)
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
2015-08-21 16:10:34 +00:00
|
|
|
function circ(ox,oy,r,col)
|
2015-08-16 16:00:39 +00:00
|
|
|
col = col or __pico_color
|
|
|
|
color(col)
|
2015-08-21 16:10:34 +00:00
|
|
|
ox = flr(ox)
|
|
|
|
oy = flr(oy)
|
2015-08-18 12:00:57 +00:00
|
|
|
r = flr(r)
|
2015-08-21 16:10:34 +00:00
|
|
|
local points = {}
|
|
|
|
local x = r
|
|
|
|
local y = 0
|
2015-09-10 11:24:53 +00:00
|
|
|
local decisionOver2 = 1 - x
|
|
|
|
|
|
|
|
while y <= x do
|
|
|
|
table.insert(points,{ox+x,oy+y})
|
|
|
|
table.insert(points,{ox+y,oy+x})
|
|
|
|
table.insert(points,{ox-x,oy+y})
|
|
|
|
table.insert(points,{ox-y,oy+x})
|
|
|
|
|
|
|
|
table.insert(points,{ox-x,oy-y})
|
|
|
|
table.insert(points,{ox-y,oy-x})
|
|
|
|
table.insert(points,{ox+x,oy-y})
|
|
|
|
table.insert(points,{ox+y,oy-x})
|
2015-08-21 16:10:34 +00:00
|
|
|
y = y + 1
|
2015-09-10 11:24:53 +00:00
|
|
|
if decisionOver2 <= 0 then
|
|
|
|
decisionOver2 = decisionOver2 + 2 * y + 1
|
2015-08-21 16:10:34 +00:00
|
|
|
else
|
|
|
|
x = x - 1
|
2015-09-10 11:24:53 +00:00
|
|
|
decisionOver2 = decisionOver2 + 2 * (y-x) + 1
|
2015-08-21 16:10:34 +00:00
|
|
|
end
|
|
|
|
end
|
2015-09-10 11:24:53 +00:00
|
|
|
lineMesh:setVertices(points)
|
|
|
|
lineMesh:setDrawRange(1,#points)
|
|
|
|
love.graphics.draw(lineMesh)
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
2015-09-10 11:24:53 +00:00
|
|
|
function _plot4points(points,cx,cy,x,y)
|
|
|
|
_horizontal_line(points, cx - x, cy + y, cx + x)
|
|
|
|
if x ~= 0 and y ~= 0 then
|
|
|
|
_horizontal_line(points, cx - x, cy - y, cx + x)
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-08-21 16:10:34 +00:00
|
|
|
|
2015-09-10 11:24:53 +00:00
|
|
|
function _horizontal_line(points,x0,y,x1)
|
|
|
|
for x=x0,x1 do
|
|
|
|
table.insert(points,{x,y})
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
2015-09-10 11:24:53 +00:00
|
|
|
function circfill(cx,cy,r,col)
|
2015-08-16 16:00:39 +00:00
|
|
|
col = col or __pico_color
|
|
|
|
color(col)
|
2015-09-10 11:24:53 +00:00
|
|
|
cx = flr(cx)
|
|
|
|
cy = flr(cy)
|
2015-08-17 14:47:42 +00:00
|
|
|
r = flr(r)
|
2015-08-21 16:10:34 +00:00
|
|
|
local x = r
|
|
|
|
local y = 0
|
2015-09-10 11:24:53 +00:00
|
|
|
local err = -r
|
|
|
|
|
|
|
|
local points = {}
|
|
|
|
|
2015-09-11 11:30:37 +00:00
|
|
|
while y <= x do
|
2015-08-21 16:10:34 +00:00
|
|
|
local lasty = y
|
|
|
|
err = err + y
|
|
|
|
y = y + 1
|
|
|
|
err = err + y
|
2015-09-10 11:24:53 +00:00
|
|
|
_plot4points(points,cx,cy,x,lasty)
|
2015-09-11 11:30:37 +00:00
|
|
|
if err > 0 then
|
2015-08-21 16:10:34 +00:00
|
|
|
if x ~= lasty then
|
2015-09-10 11:24:53 +00:00
|
|
|
_plot4points(points,cx,cy,lasty,x)
|
2015-08-21 16:10:34 +00:00
|
|
|
end
|
|
|
|
err = err - x
|
|
|
|
x = x - 1
|
|
|
|
err = err - x
|
|
|
|
end
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
|
2015-09-10 11:24:53 +00:00
|
|
|
lineMesh:setVertices(points)
|
|
|
|
lineMesh:setDrawRange(1,#points)
|
|
|
|
love.graphics.draw(lineMesh)
|
|
|
|
|
|
|
|
end
|
2015-08-17 14:47:42 +00:00
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
function line(x0,y0,x1,y1,col)
|
|
|
|
col = col or __pico_color
|
|
|
|
color(col)
|
|
|
|
|
2015-09-11 11:17:41 +00:00
|
|
|
if x0 ~= x0 or y0 ~= y0 or x1 ~= x1 or y1 ~= y1 then
|
|
|
|
warning("line has NaN value")
|
|
|
|
return
|
2015-09-10 12:07:47 +00:00
|
|
|
end
|
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
x0 = flr(x0)
|
|
|
|
y0 = flr(y0)
|
|
|
|
x1 = flr(x1)
|
|
|
|
y1 = flr(y1)
|
|
|
|
|
2015-09-10 12:07:47 +00:00
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
local dx = x1 - x0
|
|
|
|
local dy = y1 - y0
|
|
|
|
local stepx, stepy
|
|
|
|
|
2015-09-10 12:07:47 +00:00
|
|
|
local points = {{x0,y0}}
|
2015-08-17 09:11:50 +00:00
|
|
|
|
2015-09-10 12:07:47 +00:00
|
|
|
if dx == 0 then
|
|
|
|
-- simple case draw a vertical line
|
2015-09-10 13:09:30 +00:00
|
|
|
points = {}
|
|
|
|
if y0 > y1 then y0,y1 = y1,y0 end
|
2015-09-10 12:07:47 +00:00
|
|
|
for y=y0,y1 do
|
|
|
|
table.insert(points,{x0,y})
|
|
|
|
end
|
|
|
|
elseif dy == 0 then
|
|
|
|
-- simple case draw a horizontal line
|
2015-09-10 13:09:30 +00:00
|
|
|
points = {}
|
|
|
|
if x0 > x1 then x0,x1 = x1,x0 end
|
2015-09-10 12:07:47 +00:00
|
|
|
for x=x0,x1 do
|
|
|
|
table.insert(points,{x,y0})
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
else
|
2015-09-10 12:07:47 +00:00
|
|
|
if dy < 0 then
|
|
|
|
dy = -dy
|
|
|
|
stepy = -1
|
|
|
|
else
|
|
|
|
stepy = 1
|
|
|
|
end
|
2015-08-17 09:11:50 +00:00
|
|
|
|
2015-09-10 12:07:47 +00:00
|
|
|
if dx < 0 then
|
|
|
|
dx = -dx
|
|
|
|
stepx = -1
|
|
|
|
else
|
|
|
|
stepx = 1
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-09-10 12:07:47 +00:00
|
|
|
|
|
|
|
if dx > dy then
|
|
|
|
local fraction = dy - bit.rshift(dx, 1)
|
|
|
|
while x0 ~= x1 do
|
|
|
|
if fraction >= 0 then
|
|
|
|
y0 = y0 + stepy
|
|
|
|
fraction = fraction - dx
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
x0 = x0 + stepx
|
2015-09-10 12:07:47 +00:00
|
|
|
fraction = fraction + dy
|
|
|
|
table.insert(points,{flr(x0),flr(y0)})
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-09-10 12:07:47 +00:00
|
|
|
else
|
|
|
|
local fraction = dx - bit.rshift(dy, 1)
|
|
|
|
while y0 ~= y1 do
|
|
|
|
if fraction >= 0 then
|
|
|
|
x0 = x0 + stepx
|
|
|
|
fraction = fraction - dy
|
|
|
|
end
|
|
|
|
y0 = y0 + stepy
|
|
|
|
fraction = fraction + dx
|
|
|
|
table.insert(points,{flr(x0),flr(y0)})
|
2015-09-09 11:51:34 +00:00
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
end
|
2015-08-17 14:47:42 +00:00
|
|
|
lineMesh:setVertices(points)
|
|
|
|
lineMesh:setDrawRange(1,#points)
|
|
|
|
love.graphics.draw(lineMesh)
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
2015-09-11 11:18:24 +00:00
|
|
|
function _load(_cartname)
|
2015-08-18 12:00:57 +00:00
|
|
|
love.graphics.setShader(__draw_shader)
|
|
|
|
love.graphics.setCanvas(__screen)
|
|
|
|
love.graphics.origin()
|
2015-08-21 16:10:34 +00:00
|
|
|
camera()
|
2015-08-18 12:00:57 +00:00
|
|
|
restore_clip()
|
2015-08-17 14:47:42 +00:00
|
|
|
cartname = _cartname
|
2015-09-12 03:54:23 +00:00
|
|
|
cart = load_p8(_cartname)
|
2015-08-17 09:11:50 +00:00
|
|
|
end
|
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
function rect(x0,y0,x1,y1,col)
|
|
|
|
col = col or __pico_color
|
|
|
|
color(col)
|
2015-08-18 12:00:57 +00:00
|
|
|
love.graphics.rectangle("line",flr(x0)+1,flr(y0)+1,flr(x1-x0),flr(y1-y0))
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function rectfill(x0,y0,x1,y1,col)
|
|
|
|
col = col or __pico_color
|
|
|
|
color(col)
|
2015-09-11 11:30:37 +00:00
|
|
|
local w = (x1-x0)+1
|
|
|
|
local h = (y1-y0)+1
|
|
|
|
if w < 0 then
|
|
|
|
w = -w
|
|
|
|
x0 = x0-w
|
|
|
|
end
|
|
|
|
if h < 0 then
|
|
|
|
h = -h
|
|
|
|
y0 = y0-h
|
|
|
|
end
|
2015-08-18 12:00:57 +00:00
|
|
|
love.graphics.rectangle("fill",flr(x0),flr(y0),w,h)
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function run()
|
2015-08-17 16:36:58 +00:00
|
|
|
love.graphics.setCanvas(__screen)
|
|
|
|
love.graphics.setShader(__draw_shader)
|
2015-08-18 12:00:57 +00:00
|
|
|
restore_clip()
|
|
|
|
love.graphics.origin()
|
2015-08-17 11:14:08 +00:00
|
|
|
if cart._init then cart._init() end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function reload()
|
2015-09-11 11:18:24 +00:00
|
|
|
_load(cartname)
|
2015-08-17 14:47:42 +00:00
|
|
|
run()
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
2015-08-17 17:04:45 +00:00
|
|
|
local __palette_modified = true
|
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
function pal(c0,c1,p)
|
|
|
|
if c0 == nil then
|
2015-08-17 17:04:45 +00:00
|
|
|
if __palette_modified == false then return end
|
2015-08-18 09:45:04 +00:00
|
|
|
for i=1,16 do
|
|
|
|
__draw_palette[i] = i
|
|
|
|
__display_palette[i] = __pico_palette[i]
|
2015-08-17 14:47:42 +00:00
|
|
|
end
|
2015-08-18 09:45:04 +00:00
|
|
|
__draw_shader:send('palette',unpack(__draw_palette))
|
|
|
|
__sprite_shader:send('palette',unpack(__draw_palette))
|
|
|
|
__text_shader:send('palette',unpack(__draw_palette))
|
|
|
|
__display_shader:send('palette',unpack(__display_palette))
|
2015-08-17 17:04:45 +00:00
|
|
|
__palette_modified = false
|
2015-08-17 17:08:55 +00:00
|
|
|
elseif p == 1 and c1 ~= nil then
|
2015-09-10 14:34:36 +00:00
|
|
|
c0 = flr(c0)%16
|
|
|
|
c1 = flr(c1)%16
|
2015-08-18 09:45:04 +00:00
|
|
|
c1 = c1+1
|
|
|
|
c0 = c0+1
|
|
|
|
__display_palette[c0] = __pico_palette[c1]
|
|
|
|
__display_shader:send('palette',unpack(__display_palette))
|
2015-08-17 17:04:45 +00:00
|
|
|
__palette_modified = true
|
2015-08-17 17:08:55 +00:00
|
|
|
elseif c1 ~= nil then
|
2015-09-10 14:34:36 +00:00
|
|
|
c0 = flr(c0)%16
|
|
|
|
c1 = flr(c1)%16
|
2015-08-18 09:45:04 +00:00
|
|
|
c1 = c1+1
|
|
|
|
c0 = c0+1
|
|
|
|
__draw_palette[c0] = c1
|
|
|
|
__draw_shader:send('palette',unpack(__draw_palette))
|
|
|
|
__sprite_shader:send('palette',unpack(__draw_palette))
|
|
|
|
__text_shader:send('palette',unpack(__draw_palette))
|
2015-08-17 17:04:45 +00:00
|
|
|
__palette_modified = true
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function palt(c,t)
|
|
|
|
if c == nil then
|
2015-08-18 09:45:04 +00:00
|
|
|
for i=1,16 do
|
|
|
|
__pico_pal_transparent[i] = i == 1 and 0 or 1
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
else
|
2015-09-10 14:34:36 +00:00
|
|
|
c = flr(c)%16
|
2015-08-16 16:00:39 +00:00
|
|
|
if t == false then
|
2015-08-18 09:45:04 +00:00
|
|
|
__pico_pal_transparent[c+1] = 1
|
2015-08-18 12:00:57 +00:00
|
|
|
elseif t == true then
|
2015-08-18 09:45:04 +00:00
|
|
|
__pico_pal_transparent[c+1] = 0
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
end
|
2015-08-18 09:45:04 +00:00
|
|
|
__sprite_shader:send('transparent',unpack(__pico_pal_transparent))
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function spr(n,x,y,w,h,flip_x,flip_y)
|
2015-09-09 12:40:14 +00:00
|
|
|
n = flr(n)
|
2015-08-16 16:00:39 +00:00
|
|
|
love.graphics.setShader(__sprite_shader)
|
2015-08-18 12:00:57 +00:00
|
|
|
__sprite_shader:send('transparent',unpack(__pico_pal_transparent))
|
2015-08-21 16:10:34 +00:00
|
|
|
n = flr(n)
|
2015-08-18 17:42:23 +00:00
|
|
|
w = w or 1
|
|
|
|
h = h or 1
|
2015-08-20 08:34:15 +00:00
|
|
|
local q
|
|
|
|
if w == 1 and h == 1 then
|
|
|
|
q = __pico_quads[n]
|
2015-08-21 16:10:34 +00:00
|
|
|
if not q then
|
|
|
|
log('warning: sprite '..n..' is missing')
|
|
|
|
return
|
|
|
|
end
|
2015-08-20 08:34:15 +00:00
|
|
|
else
|
|
|
|
local id = string.format("%d-%d-%d",n,w,h)
|
|
|
|
if __pico_quads[id] then
|
|
|
|
q = __pico_quads[id]
|
|
|
|
else
|
|
|
|
q = love.graphics.newQuad(flr(n%16)*8,flr(n/16)*8,8*w,8*h,128,128)
|
|
|
|
__pico_quads[id] = q
|
|
|
|
end
|
|
|
|
end
|
2015-09-09 12:40:14 +00:00
|
|
|
if not q then
|
|
|
|
log('missing quad',n)
|
|
|
|
end
|
2015-08-18 17:42:23 +00:00
|
|
|
love.graphics.draw(__pico_spritesheet,q,
|
|
|
|
flr(x)+(w*8*(flip_x and 1 or 0)),
|
|
|
|
flr(y)+(h*8*(flip_y and 1 or 0)),
|
|
|
|
0,flip_x and -1 or 1,flip_y and -1 or 1)
|
2015-08-17 14:47:42 +00:00
|
|
|
love.graphics.setShader(__draw_shader)
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function sspr(sx,sy,sw,sh,dx,dy,dw,dh,flip_x,flip_y)
|
2015-08-18 12:00:57 +00:00
|
|
|
-- Stretch rectangle from sprite sheet (sx, sy, sw, sh) // given in pixels
|
|
|
|
-- and draw in rectangle (dx, dy, dw, dh)
|
|
|
|
-- Colour 0 drawn as transparent by default (see palt())
|
|
|
|
-- dw, dh defaults to sw, sh
|
|
|
|
-- flip_x=true to flip horizontally
|
|
|
|
-- flip_y=true to flip vertically
|
2015-08-16 16:00:39 +00:00
|
|
|
dw = dw or sw
|
|
|
|
dh = dh or sh
|
2015-08-17 14:47:42 +00:00
|
|
|
-- FIXME: cache this quad
|
2015-08-18 12:00:57 +00:00
|
|
|
-- FIXME handle flipping
|
|
|
|
local q = love.graphics.newQuad(sx,sy,sw,sh,__pico_spritesheet:getDimensions())
|
2015-08-16 16:00:39 +00:00
|
|
|
love.graphics.setShader(__sprite_shader)
|
2015-08-18 12:00:57 +00:00
|
|
|
__sprite_shader:send('transparent',unpack(__pico_pal_transparent))
|
2015-08-16 16:00:39 +00:00
|
|
|
love.graphics.draw(__pico_spritesheet,q,flr(dx),flr(dy),0,dw/sw,dh/sh)
|
2015-08-17 14:47:42 +00:00
|
|
|
love.graphics.setShader(__draw_shader)
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function add(a,v)
|
|
|
|
table.insert(a,v)
|
|
|
|
end
|
|
|
|
|
|
|
|
function del(a,dv)
|
|
|
|
for i,v in ipairs(a) do
|
|
|
|
if v==dv then
|
|
|
|
table.remove(a,i)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-09-11 11:17:41 +00:00
|
|
|
function warning(msg)
|
|
|
|
log(debug.traceback("WARNING: "..msg,3))
|
|
|
|
end
|
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
function foreach(a,f)
|
2015-09-11 11:17:41 +00:00
|
|
|
if not a then
|
|
|
|
warning("foreach got a nil value")
|
|
|
|
return
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
for i,v in ipairs(a) do
|
|
|
|
f(v)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function count(a)
|
|
|
|
return #a
|
|
|
|
end
|
|
|
|
|
|
|
|
function all(a)
|
|
|
|
local i = 0
|
|
|
|
local n = table.getn(a)
|
|
|
|
return function()
|
|
|
|
i = i + 1
|
|
|
|
if i <= n then return a[i] end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-08-18 16:35:53 +00:00
|
|
|
__pico_keypressed = {
|
2015-08-16 16:00:39 +00:00
|
|
|
[0] = {},
|
|
|
|
[1] = {}
|
|
|
|
}
|
|
|
|
|
2015-08-18 16:35:53 +00:00
|
|
|
__keymap = {
|
2015-08-16 16:00:39 +00:00
|
|
|
[0] = {
|
|
|
|
[0] = 'left',
|
|
|
|
[1] = 'right',
|
|
|
|
[2] = 'up',
|
|
|
|
[3] = 'down',
|
|
|
|
[4] = 'z',
|
|
|
|
[5] = 'x',
|
|
|
|
},
|
|
|
|
[1] = {
|
2015-09-05 06:17:06 +00:00
|
|
|
[0] = 's',
|
|
|
|
[1] = 'f',
|
|
|
|
[2] = 'e',
|
|
|
|
[3] = 'd',
|
|
|
|
[4] = 'q',
|
|
|
|
[5] = 'a',
|
2015-08-16 16:00:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function btn(i,p)
|
|
|
|
p = p or 0
|
|
|
|
if __keymap[p][i] then
|
2015-08-18 16:35:53 +00:00
|
|
|
return __pico_keypressed[p][i] ~= nil
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-08-18 16:35:53 +00:00
|
|
|
return false
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function btnp(i,p)
|
|
|
|
p = p or 0
|
|
|
|
if __keymap[p][i] then
|
2015-08-18 16:35:53 +00:00
|
|
|
local v = __pico_keypressed[p][i]
|
|
|
|
if v and (v == 0 or v == 12 or (v > 12 and v % 4 == 0)) then
|
2015-08-16 16:00:39 +00:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
2015-08-18 16:35:53 +00:00
|
|
|
return false
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function mget(x,y)
|
2015-08-18 16:35:53 +00:00
|
|
|
if x == nil or y == nil then return 0 end
|
|
|
|
if y > 63 or x > 127 or x < 0 or y < 0 then return 0 end
|
2015-08-16 16:00:39 +00:00
|
|
|
return __pico_map[flr(y)][flr(x)]
|
|
|
|
end
|
|
|
|
|
|
|
|
function mset(x,y,v)
|
|
|
|
if x >= 0 and x < 128 and y >= 0 and y < 64 then
|
|
|
|
__pico_map[flr(y)][flr(x)] = v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function map(cel_x,cel_y,sx,sy,cel_w,cel_h,bitmask)
|
|
|
|
love.graphics.setShader(__sprite_shader)
|
|
|
|
love.graphics.setColor(255,255,255,255)
|
2015-08-17 09:11:50 +00:00
|
|
|
cel_x = flr(cel_x)
|
|
|
|
cel_y = flr(cel_y)
|
|
|
|
sx = flr(sx)
|
|
|
|
sy = flr(sy)
|
|
|
|
cel_w = flr(cel_w)
|
|
|
|
cel_h = flr(cel_h)
|
2015-08-18 12:00:57 +00:00
|
|
|
for y=0,cel_h-1 do
|
2015-08-20 10:03:01 +00:00
|
|
|
if cel_y+y < 64 and cel_y+y >= 0 then
|
2015-08-18 12:00:57 +00:00
|
|
|
for x=0,cel_w-1 do
|
2015-08-20 10:03:01 +00:00
|
|
|
if cel_x+x < 128 and cel_x+x >= 0 then
|
2015-08-18 12:00:57 +00:00
|
|
|
local v = __pico_map[flr(cel_y+y)][flr(cel_x+x)]
|
2015-08-17 11:14:08 +00:00
|
|
|
if v > 0 then
|
2015-08-18 12:00:57 +00:00
|
|
|
if bitmask == nil or bitmask == 0 then
|
2015-08-17 11:14:08 +00:00
|
|
|
love.graphics.draw(__pico_spritesheet,__pico_quads[v],sx+8*x,sy+8*y)
|
|
|
|
else
|
|
|
|
if band(__pico_spriteflags[v],bitmask) ~= 0 then
|
|
|
|
love.graphics.draw(__pico_spritesheet,__pico_quads[v],sx+8*x,sy+8*y)
|
|
|
|
else
|
|
|
|
end
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-08-19 11:01:17 +00:00
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-08-19 11:01:17 +00:00
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
2015-08-18 09:45:04 +00:00
|
|
|
love.graphics.setShader(__draw_shader)
|
2015-08-16 16:00:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
-- memory functions excluded
|
|
|
|
|
|
|
|
function memcpy(dest_addr,source_addr,len)
|
|
|
|
-- only for range 0x6000+0x8000
|
|
|
|
if source_addr >= 0x6000 and dest_addr >= 0x6000 then
|
|
|
|
if source_addr + len >= 0x8000 then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
if dest_addr + len >= 0x8000 then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local img = __screen:getImageData()
|
|
|
|
for i=1,len do
|
|
|
|
local x = flr(source_addr-0x6000+i)%128
|
|
|
|
local y = flr((source_addr-0x6000+i)/64)
|
2015-08-17 14:47:42 +00:00
|
|
|
local c = flr(img:getPixel(x,y)/16)
|
2015-08-16 16:00:39 +00:00
|
|
|
|
|
|
|
local dx = flr(dest_addr-0x6000+i)%128
|
|
|
|
local dy = flr((dest_addr-0x6000+i)/64)
|
|
|
|
pset(dx,dy,c)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function peek(...)
|
|
|
|
end
|
|
|
|
|
|
|
|
function poke(...)
|
|
|
|
end
|
|
|
|
|
2015-09-11 14:50:23 +00:00
|
|
|
function min(a,b)
|
|
|
|
if a == nil or b == nil then
|
|
|
|
warning('min a or b are nil returning 0')
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
if a < b then return a end
|
|
|
|
return b
|
|
|
|
end
|
|
|
|
|
|
|
|
function max(a,b)
|
|
|
|
if a == nil or b == nil then
|
|
|
|
warning('max a or b are nil returning 0')
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
if a > b then return a end
|
|
|
|
return b
|
|
|
|
end
|
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
function mid(x,y,z)
|
|
|
|
return x > y and x or y > z and z or y
|
|
|
|
end
|
|
|
|
|
|
|
|
assert(mid(1,5,6) == 5)
|
|
|
|
assert(mid(3,2,6) == 3)
|
|
|
|
assert(mid(3,9,6) == 6)
|
|
|
|
|
|
|
|
function __pico_angle(a)
|
|
|
|
-- FIXME: why does this work?
|
|
|
|
return (((a - math.pi) / (math.pi*2)) + 0.25) % 1.0
|
|
|
|
end
|
|
|
|
|
|
|
|
flr = math.floor
|
2015-08-18 12:14:35 +00:00
|
|
|
cos = function(x) return math.cos((x or 0)*(math.pi*2)) end
|
|
|
|
sin = function(x) return math.sin(-(x or 0)*(math.pi*2)) end
|
2015-08-16 16:00:39 +00:00
|
|
|
atan2 = function(y,x) return __pico_angle(math.atan2(y,x)) end
|
|
|
|
|
|
|
|
sqrt = math.sqrt
|
|
|
|
abs = math.abs
|
2015-08-18 16:35:53 +00:00
|
|
|
rnd = function(x) return love.math.random()*(x or 1) end
|
|
|
|
srand = function(seed)
|
|
|
|
return love.math.setRandomSeed(flr(seed*32768))
|
|
|
|
end
|
2015-08-16 16:00:39 +00:00
|
|
|
sgn = function(x)
|
|
|
|
if x < 0 then
|
|
|
|
return -1
|
|
|
|
elseif x > 0 then
|
|
|
|
return 1
|
|
|
|
else
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-08-17 11:14:08 +00:00
|
|
|
assert(sgn(-10) == -1)
|
|
|
|
assert(sgn(10) == 1)
|
|
|
|
assert(sgn(0) == 0)
|
|
|
|
|
2015-08-16 16:00:39 +00:00
|
|
|
local bit = require("bit")
|
|
|
|
|
|
|
|
band = bit.band
|
|
|
|
bor = bit.bor
|
|
|
|
bxor = bit.bxor
|
|
|
|
bnot = bit.bnot
|
|
|
|
shl = bit.lshift
|
|
|
|
shr = bit.rshift
|
|
|
|
|
|
|
|
sub = string.sub
|
2015-08-17 14:47:42 +00:00
|
|
|
|
2015-08-18 12:14:35 +00:00
|
|
|
function stat(x)
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
|
2015-08-17 14:47:42 +00:00
|
|
|
love.graphics.point = function(x,y)
|
|
|
|
love.graphics.rectangle('fill',x,y,1,1)
|
|
|
|
end
|
2015-09-11 11:30:37 +00:00
|
|
|
|
|
|
|
setfps = function(fps)
|
|
|
|
__pico_fps = flr(fps)
|
|
|
|
if __pico_fps <= 0 then
|
|
|
|
__pico_fps = 30
|
|
|
|
end
|
|
|
|
frametime = 1/__pico_fps
|
|
|
|
end
|
2015-09-12 03:54:23 +00:00
|
|
|
|
|
|
|
function lerp(a,b,t)
|
|
|
|
return (1-t)*a+t*b
|
|
|
|
end
|