2018-09-27 03:14:16 +00:00
|
|
|
lovr = require 'lovr'
|
|
|
|
|
2018-04-26 03:07:28 +00:00
|
|
|
local function nogame()
|
2017-12-19 00:01:12 +00:00
|
|
|
function lovr.conf(t)
|
|
|
|
t.modules.audio = false
|
|
|
|
t.modules.math = false
|
|
|
|
t.modules.physics = false
|
2018-04-26 03:07:28 +00:00
|
|
|
t.modules.thread = false
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function lovr.load()
|
2019-04-08 10:25:45 +00:00
|
|
|
if not lovr.graphics then
|
2019-04-08 12:18:28 +00:00
|
|
|
print(string.format('LÖVR %d.%d.%d\nNo game', lovr.getVersion()))
|
2019-04-08 10:25:45 +00:00
|
|
|
lovr.event.quit()
|
|
|
|
return
|
|
|
|
end
|
2018-02-20 05:04:53 +00:00
|
|
|
local texture = lovr.graphics.newTexture(lovr.data.newBlob(lovr._logo, 'logo.png'))
|
2017-12-19 00:01:12 +00:00
|
|
|
logo = lovr.graphics.newMaterial(texture)
|
|
|
|
lovr.graphics.setBackgroundColor(.960, .988, 1.0)
|
|
|
|
end
|
|
|
|
|
|
|
|
function lovr.draw()
|
|
|
|
lovr.graphics.setColor(1.0, 1.0, 1.0)
|
|
|
|
local padding = .1
|
|
|
|
local font = lovr.graphics.getFont()
|
|
|
|
local fade = .315 + .685 * math.abs(math.sin(lovr.timer.getTime() * 2))
|
2018-03-05 05:46:37 +00:00
|
|
|
local titlePosition = 1.4 - padding
|
2017-12-19 00:01:12 +00:00
|
|
|
local subtitlePosition = titlePosition - font:getHeight() * .25 - padding
|
2018-03-05 05:46:37 +00:00
|
|
|
lovr.graphics.plane(logo, 0, 1.9, -3, 1, 1, 0, 0, 1)
|
2017-12-19 00:01:12 +00:00
|
|
|
lovr.graphics.setColor(.059, .059, .059)
|
|
|
|
lovr.graphics.print('LÖVR', -.01, titlePosition, -3, .25, 0, 0, 1, 0, nil, 'center', 'top')
|
|
|
|
lovr.graphics.setColor(.059, .059, .059, fade)
|
|
|
|
lovr.graphics.print('No game :(', -.01, subtitlePosition, -3, .15, 0, 0, 1, 0, nil, 'center', 'top')
|
2019-01-29 02:21:46 +00:00
|
|
|
lovr.graphics.setColor(1, 1, 1)
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-11-13 06:34:02 +00:00
|
|
|
-- Note: Cannot be overloaded
|
2018-04-26 03:07:28 +00:00
|
|
|
function lovr.boot()
|
|
|
|
local conf = {
|
2019-05-04 01:39:36 +00:00
|
|
|
version = '0.12.0',
|
|
|
|
compat = false,
|
2018-04-26 03:07:28 +00:00
|
|
|
modules = {
|
|
|
|
audio = true,
|
|
|
|
data = true,
|
|
|
|
event = true,
|
|
|
|
graphics = true,
|
|
|
|
headset = true,
|
|
|
|
math = true,
|
|
|
|
physics = true,
|
|
|
|
thread = true,
|
|
|
|
timer = true
|
|
|
|
},
|
|
|
|
headset = {
|
2019-03-07 07:02:03 +00:00
|
|
|
drivers = { 'oculus', 'oculusmobile', 'openvr', 'webvr', 'desktop' },
|
2018-07-29 01:12:57 +00:00
|
|
|
offset = 1.7,
|
2018-08-05 01:44:19 +00:00
|
|
|
msaa = 4
|
2018-04-26 03:07:28 +00:00
|
|
|
},
|
|
|
|
window = {
|
|
|
|
width = 1080,
|
|
|
|
height = 600,
|
|
|
|
fullscreen = false,
|
|
|
|
msaa = 0,
|
|
|
|
title = 'LÖVR',
|
|
|
|
icon = nil
|
|
|
|
}
|
|
|
|
}
|
2017-12-19 00:01:12 +00:00
|
|
|
|
2018-04-26 03:07:28 +00:00
|
|
|
lovr.filesystem = require('lovr.filesystem')
|
|
|
|
local hasConf, hasMain = lovr.filesystem.isFile('conf.lua'), lovr.filesystem.isFile('main.lua')
|
|
|
|
if not lovr.filesystem.getSource() or not (hasConf or hasMain) then nogame() end
|
2017-12-19 00:01:12 +00:00
|
|
|
|
2018-11-23 07:44:56 +00:00
|
|
|
local confOk, confError = true
|
|
|
|
if hasConf then confOk, confError = pcall(require, 'conf') end
|
|
|
|
if confOk and lovr.conf then confOk, confError = pcall(lovr.conf, conf) end
|
2018-04-26 03:07:28 +00:00
|
|
|
|
|
|
|
lovr._setConf(conf)
|
|
|
|
lovr.filesystem.setIdentity(conf.identity)
|
2017-12-19 00:01:12 +00:00
|
|
|
|
2018-11-16 10:27:34 +00:00
|
|
|
for module in pairs(conf.modules) do
|
2018-04-26 03:07:28 +00:00
|
|
|
if conf.modules[module] then
|
2018-09-27 18:45:43 +00:00
|
|
|
local ok, result = pcall(require, 'lovr.' .. module)
|
2018-11-16 10:27:34 +00:00
|
|
|
if not ok then
|
|
|
|
print(string.format('Warning: Could not load module %q: %s', module, result))
|
|
|
|
else
|
|
|
|
lovr[module] = result
|
|
|
|
end
|
2018-04-26 03:07:28 +00:00
|
|
|
end
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|
|
|
|
|
2019-05-04 01:39:36 +00:00
|
|
|
if conf.compat then
|
|
|
|
assert(loadstring(lovr._compat))(conf.version)
|
|
|
|
end
|
|
|
|
|
2018-04-26 03:07:28 +00:00
|
|
|
lovr.handlers = setmetatable({}, { __index = lovr })
|
2018-11-23 07:44:56 +00:00
|
|
|
if not confOk then error(confError) end
|
2018-04-26 03:07:28 +00:00
|
|
|
if hasMain then require 'main' end
|
|
|
|
return lovr.run()
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|
|
|
|
|
2018-04-26 03:07:28 +00:00
|
|
|
function lovr.run()
|
|
|
|
lovr.timer.step()
|
|
|
|
if lovr.load then lovr.load(arg) end
|
|
|
|
return function()
|
|
|
|
lovr.event.pump()
|
|
|
|
for name, a, b, c, d in lovr.event.poll() do
|
|
|
|
if name == 'quit' and (not lovr.quit or not lovr.quit()) then
|
|
|
|
return a or 0
|
|
|
|
end
|
|
|
|
if lovr.handlers[name] then lovr.handlers[name](a, b, c, d) end
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|
2018-04-26 03:07:28 +00:00
|
|
|
local dt = lovr.timer.step()
|
2018-02-26 00:40:48 +00:00
|
|
|
if lovr.headset then
|
2018-04-26 03:07:28 +00:00
|
|
|
lovr.headset.update(dt)
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|
2018-04-26 03:07:28 +00:00
|
|
|
if lovr.audio then
|
|
|
|
lovr.audio.update()
|
2018-02-26 00:40:48 +00:00
|
|
|
if lovr.headset then
|
2019-02-18 02:26:56 +00:00
|
|
|
lovr.audio.setPose(lovr.headset.getPose())
|
2018-04-26 03:07:28 +00:00
|
|
|
lovr.audio.setVelocity(lovr.headset.getVelocity())
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|
|
|
|
end
|
2018-04-26 03:07:28 +00:00
|
|
|
if lovr.update then lovr.update(dt) end
|
|
|
|
if lovr.graphics then
|
|
|
|
lovr.graphics.origin()
|
|
|
|
if lovr.draw then
|
|
|
|
if lovr.headset then
|
|
|
|
lovr.headset.renderTo(lovr.draw)
|
2019-01-24 21:20:14 +00:00
|
|
|
end
|
2019-01-28 21:53:05 +00:00
|
|
|
if lovr.graphics.hasWindow() then
|
2019-01-24 21:20:14 +00:00
|
|
|
lovr.mirror()
|
2018-04-26 03:07:28 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
lovr.graphics.present()
|
|
|
|
end
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-01-24 21:20:14 +00:00
|
|
|
function lovr.mirror()
|
2019-01-25 20:08:45 +00:00
|
|
|
if lovr.headset then -- On some systems, headset module will be disabled
|
|
|
|
local texture = lovr.headset.getMirrorTexture()
|
|
|
|
if texture then -- On some drivers, texture is printed directly to the window
|
|
|
|
lovr.graphics.fill(texture)
|
|
|
|
end
|
2019-01-24 21:20:14 +00:00
|
|
|
else
|
|
|
|
lovr.graphics.clear()
|
|
|
|
lovr.draw()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-11-13 06:34:02 +00:00
|
|
|
local function formatTraceback(s)
|
|
|
|
return s:gsub('\n[^\n]+$', ''):gsub('\t', ''):gsub('stack traceback', '\nStack')
|
|
|
|
end
|
|
|
|
|
|
|
|
function lovr.errhand(message, traceback)
|
2018-11-23 07:44:56 +00:00
|
|
|
message = tostring(message)
|
2019-02-05 21:14:32 +00:00
|
|
|
message = 'Error:\n' .. message .. formatTraceback(traceback or debug.traceback('', 4))
|
2018-11-14 03:56:29 +00:00
|
|
|
print(message)
|
2018-05-14 00:27:28 +00:00
|
|
|
if not lovr.graphics then return function() return 1 end end
|
2018-04-26 03:07:28 +00:00
|
|
|
lovr.graphics.reset()
|
|
|
|
lovr.graphics.setBackgroundColor(.105, .098, .137)
|
|
|
|
lovr.graphics.setColor(.863, .863, .863)
|
|
|
|
local font = lovr.graphics.getFont()
|
2019-04-13 22:40:09 +00:00
|
|
|
font:setFlipEnabled(false)
|
2018-04-26 03:07:28 +00:00
|
|
|
local pixelDensity = font:getPixelDensity()
|
|
|
|
local width = font:getWidth(message, .55 * pixelDensity)
|
|
|
|
local function render()
|
|
|
|
lovr.graphics.print(message, -width / 2, 0, -20, 1, 0, 0, 0, 0, .55 * pixelDensity, 'left')
|
|
|
|
end
|
|
|
|
return function()
|
|
|
|
lovr.event.pump()
|
|
|
|
for name in lovr.event.poll() do if name == 'quit' then return 1 end end
|
2019-02-14 04:37:06 +00:00
|
|
|
lovr.headset.update(0)
|
2018-04-26 03:07:28 +00:00
|
|
|
lovr.graphics.origin()
|
|
|
|
if lovr.headset then lovr.headset.renderTo(render) end
|
2019-02-05 21:14:32 +00:00
|
|
|
lovr.graphics.clear()
|
2018-04-26 03:07:28 +00:00
|
|
|
render()
|
|
|
|
lovr.graphics.present()
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-03-12 17:37:45 +00:00
|
|
|
function lovr.threaderror(thread, err)
|
2018-04-26 03:07:28 +00:00
|
|
|
error('Thread error\n\n' .. err, 0)
|
2018-03-12 17:37:45 +00:00
|
|
|
end
|
|
|
|
|
2018-11-13 06:34:02 +00:00
|
|
|
-- This splits up the string returned by luax_getstack so it looks like the error message plus the string from
|
|
|
|
-- debug.traceback(). This includes splitting on the newline before 'stack traceback:' and appending a newline
|
|
|
|
local function splitOnLabelLine(s, t)
|
|
|
|
local at = s:reverse():find(t:reverse())
|
|
|
|
if at then
|
|
|
|
local slen = #s
|
|
|
|
at = (#s - at - #t + 2)
|
|
|
|
return s:sub(1, at-2), s:sub(at,slen) .. '\n'
|
|
|
|
else
|
|
|
|
return s, ''
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- lovr will run this function in its own coroutine
|
2018-04-26 03:07:28 +00:00
|
|
|
return function()
|
2018-11-13 06:34:02 +00:00
|
|
|
local errored = false -- lovr.errhand may only be called once
|
|
|
|
local function onerror(e, tb) -- wrapper for errhand to ensure it is only called once
|
|
|
|
local function abortclean()
|
|
|
|
return 1
|
|
|
|
end
|
|
|
|
if not errored then
|
|
|
|
errored = true
|
|
|
|
return lovr.errhand(e, tb) or abortclean
|
|
|
|
else
|
2018-11-14 03:56:29 +00:00
|
|
|
print('Error occurred while trying to display another error:\n' ..
|
2018-11-23 07:44:56 +00:00
|
|
|
tostring(e) .. formatTraceback(tb or debug.traceback('', 2)))
|
2018-11-13 06:34:02 +00:00
|
|
|
return abortclean
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Executes lovr.boot and lovr.run.
|
|
|
|
-- continuation, afterward, will be either lovr.run's per-frame function, or the result of errhand.
|
|
|
|
local _, continuation = xpcall(lovr.boot, onerror)
|
2018-04-26 03:07:28 +00:00
|
|
|
|
|
|
|
while true do
|
2018-11-13 06:34:02 +00:00
|
|
|
if type(continuation) == 'string' then -- LuaJIT returns a fixed string if an error occurs in an xpcall error handler
|
|
|
|
print('Error occurred while trying to display another error.')
|
|
|
|
return 1
|
|
|
|
end
|
2018-04-26 03:07:28 +00:00
|
|
|
|
2018-11-23 07:44:56 +00:00
|
|
|
local ok, result = xpcall(continuation, onerror)
|
|
|
|
if result and ok then return result -- Result is value returned by function. Return it.
|
|
|
|
elseif not ok then continuation = result end -- Result is value returned by error handler. Make it the new error handler.
|
|
|
|
|
2018-11-13 06:34:02 +00:00
|
|
|
local externerror = coroutine.yield() -- Return control to C code
|
|
|
|
|
|
|
|
if externerror then -- A must-report error occurred in the C code
|
|
|
|
local errorpart, tracepart = splitOnLabelLine(externerror, 'stack traceback:')
|
|
|
|
continuation = onerror(errorpart, tracepart) -- Switch continuation to lovr.errhand
|
|
|
|
end
|
|
|
|
end
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|