2018-09-27 03:14:16 +00:00
|
|
|
lovr = require 'lovr'
|
|
|
|
|
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 = {
|
2022-10-16 04:49:25 +00:00
|
|
|
version = '0.16.0',
|
2019-11-25 01:27:17 +00:00
|
|
|
identity = 'default',
|
2020-06-21 15:02:36 +00:00
|
|
|
saveprecedence = true,
|
2018-04-26 03:07:28 +00:00
|
|
|
modules = {
|
|
|
|
audio = true,
|
|
|
|
data = true,
|
|
|
|
event = true,
|
|
|
|
graphics = true,
|
|
|
|
headset = true,
|
|
|
|
math = true,
|
|
|
|
physics = true,
|
2021-02-25 16:00:12 +00:00
|
|
|
system = true,
|
2018-04-26 03:07:28 +00:00
|
|
|
thread = true,
|
|
|
|
timer = true
|
|
|
|
},
|
2021-02-05 11:48:18 +00:00
|
|
|
audio = {
|
|
|
|
start = true,
|
2021-03-08 05:42:17 +00:00
|
|
|
spatializer = nil
|
2021-02-05 11:48:18 +00:00
|
|
|
},
|
2022-04-27 05:48:51 +00:00
|
|
|
graphics = {
|
2022-05-11 22:28:04 +00:00
|
|
|
debug = false,
|
2022-08-13 03:18:55 +00:00
|
|
|
vsync = true,
|
2022-08-03 05:00:11 +00:00
|
|
|
stencil = false,
|
2022-08-03 05:05:12 +00:00
|
|
|
antialias = true,
|
|
|
|
shadercache = true
|
2022-04-27 05:48:51 +00:00
|
|
|
},
|
2018-04-26 03:07:28 +00:00
|
|
|
headset = {
|
2022-03-22 22:47:18 +00:00
|
|
|
drivers = { 'openxr', 'webxr', 'desktop' },
|
2020-09-25 22:41:30 +00:00
|
|
|
supersample = false,
|
2018-07-29 01:12:57 +00:00
|
|
|
offset = 1.7,
|
2022-08-03 05:00:11 +00:00
|
|
|
stencil = false,
|
|
|
|
antialias = true,
|
2022-08-07 06:45:37 +00:00
|
|
|
submitdepth = true,
|
2020-11-18 00:38:27 +00:00
|
|
|
overlay = false
|
2018-04-26 03:07:28 +00:00
|
|
|
},
|
2019-06-10 07:11:20 +00:00
|
|
|
math = {
|
2019-07-01 09:16:13 +00:00
|
|
|
globals = true
|
2019-06-10 07:11:20 +00:00
|
|
|
},
|
2018-04-26 03:07:28 +00:00
|
|
|
window = {
|
2022-08-02 04:46:00 +00:00
|
|
|
width = 720,
|
|
|
|
height = 800,
|
2018-04-26 03:07:28 +00:00
|
|
|
fullscreen = false,
|
2019-08-28 07:56:46 +00:00
|
|
|
resizable = false,
|
2018-04-26 03:07:28 +00:00
|
|
|
title = 'LÖVR',
|
2022-05-09 19:43:19 +00:00
|
|
|
icon = nil
|
2018-04-26 03:07:28 +00:00
|
|
|
}
|
|
|
|
}
|
2017-12-19 00:01:12 +00:00
|
|
|
|
2018-04-26 03:07:28 +00:00
|
|
|
lovr.filesystem = require('lovr.filesystem')
|
2022-04-23 05:47:49 +00:00
|
|
|
local main = arg[0] and arg[0]:match('[^\\/]-%.lua$') or 'main.lua'
|
|
|
|
local hasConf, hasMain = lovr.filesystem.isFile('conf.lua'), lovr.filesystem.isFile(main)
|
2022-07-07 06:50:43 +00:00
|
|
|
if not lovr.filesystem.getSource() or not (hasConf or hasMain) then require('nogame') end
|
2017-12-19 00:01:12 +00:00
|
|
|
|
2022-03-28 20:24:44 +00:00
|
|
|
-- Shift args up in fused mode, instead of consuming one for the source path
|
|
|
|
if lovr.filesystem.isFused() then
|
|
|
|
for i = 1, #arg + 1 do
|
|
|
|
arg[i] = arg[i - 1]
|
|
|
|
end
|
|
|
|
arg[0] = lovr.filesystem.getSource()
|
|
|
|
end
|
|
|
|
|
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)
|
2020-06-21 15:02:36 +00:00
|
|
|
lovr.filesystem.setIdentity(conf.identity, conf.saveprecedence)
|
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
|
|
|
|
|
2022-05-09 19:43:19 +00:00
|
|
|
if lovr.system and conf.window then
|
|
|
|
lovr.system.openWindow(conf.window)
|
|
|
|
end
|
|
|
|
|
2022-04-21 07:27:13 +00:00
|
|
|
if lovr.graphics then
|
2022-09-10 17:22:52 +00:00
|
|
|
lovr.graphics.initialize()
|
2022-04-21 07:27:13 +00:00
|
|
|
end
|
|
|
|
|
2020-08-25 21:49:19 +00:00
|
|
|
if lovr.headset and lovr.graphics and conf.window then
|
2021-06-10 23:26:15 +00:00
|
|
|
lovr.headset.start()
|
2022-08-26 04:57:15 +00:00
|
|
|
|
|
|
|
if lovr.headset.getDriver() == 'desktop' then
|
|
|
|
lovr.mirror = nil
|
|
|
|
end
|
2020-08-25 21:49:19 +00:00
|
|
|
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
|
2022-04-23 05:47:49 +00:00
|
|
|
if hasMain then require(main:gsub('%.lua$', '')) end
|
2018-04-26 03:07:28 +00:00
|
|
|
return lovr.run()
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|
|
|
|
|
2018-04-26 03:07:28 +00:00
|
|
|
function lovr.run()
|
2021-02-09 15:26:44 +00:00
|
|
|
if lovr.timer then lovr.timer.step() end
|
2018-04-26 03:07:28 +00:00
|
|
|
if lovr.load then lovr.load(arg) end
|
|
|
|
return function()
|
2021-02-09 15:26:44 +00:00
|
|
|
if lovr.event then
|
|
|
|
lovr.event.pump()
|
|
|
|
for name, a, b, c, d in lovr.event.poll() do
|
|
|
|
if name == 'restart' then
|
|
|
|
local cookie = lovr.restart and lovr.restart()
|
|
|
|
return 'restart', cookie
|
|
|
|
elseif name == 'quit' and (not lovr.quit or not lovr.quit(a)) then
|
|
|
|
return a or 0
|
|
|
|
end
|
|
|
|
if lovr.handlers[name] then lovr.handlers[name](a, b, c, d) end
|
2018-04-26 03:07:28 +00:00
|
|
|
end
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|
2022-03-23 00:52:16 +00:00
|
|
|
local dt = 0
|
2021-02-09 15:26:44 +00:00
|
|
|
if lovr.timer then dt = lovr.timer.step() end
|
2022-03-23 00:52:16 +00:00
|
|
|
if lovr.headset then dt = lovr.headset.update() end
|
2018-04-26 03:07:28 +00:00
|
|
|
if lovr.update then lovr.update(dt) end
|
2022-05-30 22:35:07 +00:00
|
|
|
if lovr.graphics then
|
2022-08-03 05:00:11 +00:00
|
|
|
if lovr.headset then
|
|
|
|
local pass = lovr.headset.getPass()
|
|
|
|
if pass then
|
|
|
|
local skip = lovr.draw and lovr.draw(pass)
|
|
|
|
if not skip then lovr.graphics.submit(pass) end
|
2022-06-06 03:38:14 +00:00
|
|
|
end
|
|
|
|
end
|
2022-08-26 04:57:15 +00:00
|
|
|
if lovr.system.isWindowOpen() then
|
|
|
|
if lovr.mirror then
|
|
|
|
local pass = lovr.graphics.getWindowPass()
|
|
|
|
local skip = lovr.mirror(pass)
|
|
|
|
if not skip then lovr.graphics.submit(pass) end
|
|
|
|
end
|
2022-08-04 07:06:54 +00:00
|
|
|
lovr.graphics.present()
|
2022-06-06 03:38:14 +00:00
|
|
|
end
|
2022-05-30 22:35:07 +00:00
|
|
|
end
|
2022-06-06 03:38:14 +00:00
|
|
|
if lovr.headset then lovr.headset.submit() end
|
2021-02-09 15:26:44 +00:00
|
|
|
if lovr.math then lovr.math.drain() end
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-06-06 03:38:14 +00:00
|
|
|
function lovr.mirror(pass)
|
|
|
|
if lovr.headset then
|
2022-07-18 03:07:31 +00:00
|
|
|
local texture = lovr.headset.getTexture()
|
|
|
|
if texture then
|
|
|
|
pass:fill(texture)
|
|
|
|
else
|
2022-08-03 05:00:11 +00:00
|
|
|
return true
|
2022-07-18 03:07:31 +00:00
|
|
|
end
|
2022-06-06 03:38:14 +00:00
|
|
|
else
|
2022-07-18 03:07:31 +00:00
|
|
|
return lovr.draw and lovr.draw(pass)
|
2022-06-06 03:38:14 +00:00
|
|
|
end
|
2019-01-24 21:20:14 +00:00
|
|
|
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
|
|
|
|
|
2022-08-13 03:32:45 +00:00
|
|
|
function lovr.errhand(message)
|
|
|
|
message = tostring(message) .. formatTraceback(debug.traceback('', 4))
|
2019-08-01 07:14:37 +00:00
|
|
|
print('Error:\n' .. message)
|
2022-06-21 01:26:32 +00:00
|
|
|
|
2022-08-13 03:32:45 +00:00
|
|
|
if not lovr.graphics then return function() return 1 end end
|
2022-07-11 04:37:52 +00:00
|
|
|
|
2022-08-13 03:46:59 +00:00
|
|
|
if lovr.audio then lovr.audio.stop() end
|
|
|
|
|
2022-08-13 04:08:25 +00:00
|
|
|
local scale = .35
|
2022-07-11 04:37:52 +00:00
|
|
|
local font = lovr.graphics.getDefaultFont()
|
|
|
|
local wrap = .7 * font:getPixelDensity()
|
|
|
|
local lines = font:getLines(message, wrap)
|
2022-08-02 04:46:00 +00:00
|
|
|
local width = math.min(font:getWidth(message), wrap) * scale
|
|
|
|
local height = .8 + #lines * font:getHeight() * scale
|
2022-07-11 04:37:52 +00:00
|
|
|
local x = -width / 2
|
|
|
|
local y = math.min(height / 2, 10)
|
2022-08-02 04:46:00 +00:00
|
|
|
local z = -10
|
2022-08-13 03:32:45 +00:00
|
|
|
|
2022-08-14 04:10:58 +00:00
|
|
|
lovr.graphics.setBackgroundColor(.11, .10, .14)
|
2022-07-11 04:37:52 +00:00
|
|
|
font:setPixelDensity()
|
|
|
|
|
2022-06-21 01:26:32 +00:00
|
|
|
local function render(pass)
|
2022-07-11 04:37:52 +00:00
|
|
|
pass:setColor(.95, .95, .95)
|
2022-08-02 04:46:00 +00:00
|
|
|
pass:text('Error', x, y, z, scale * 1.6, 0, 0, 0, 0, nil, 'left', 'top')
|
|
|
|
pass:text(message, x, y - .8, z, scale, 0, 0, 0, 0, wrap, 'left', 'top')
|
2022-06-21 01:26:32 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
return function()
|
|
|
|
lovr.event.pump()
|
2022-08-13 03:32:45 +00:00
|
|
|
|
2022-06-21 01:26:32 +00:00
|
|
|
for name, a in lovr.event.poll() do
|
|
|
|
if name == 'quit' then return a or 1
|
2022-07-11 04:37:52 +00:00
|
|
|
elseif name == 'restart' then return 'restart', lovr.restart and lovr.restart()
|
|
|
|
elseif name == 'keypressed' and a == 'f5' then lovr.event.restart() end
|
2022-06-21 01:26:32 +00:00
|
|
|
end
|
2022-08-13 03:32:45 +00:00
|
|
|
|
2022-08-13 02:28:25 +00:00
|
|
|
if lovr.headset and lovr.headset.getDriver() ~= 'desktop' then
|
2022-06-21 01:26:32 +00:00
|
|
|
lovr.headset.update()
|
2022-08-06 07:29:40 +00:00
|
|
|
local pass = lovr.headset.getPass()
|
|
|
|
if pass then
|
2022-06-21 01:26:32 +00:00
|
|
|
render(pass)
|
2022-08-13 02:28:25 +00:00
|
|
|
lovr.graphics.submit(pass)
|
2022-08-13 03:32:45 +00:00
|
|
|
lovr.headset.submit()
|
2022-06-21 01:26:32 +00:00
|
|
|
end
|
|
|
|
end
|
2022-08-13 03:32:45 +00:00
|
|
|
|
2022-06-21 01:26:32 +00:00
|
|
|
if lovr.system.isWindowOpen() then
|
2022-08-06 07:29:40 +00:00
|
|
|
local pass = lovr.graphics.getWindowPass()
|
2022-06-21 01:26:32 +00:00
|
|
|
render(pass)
|
2022-08-13 02:28:25 +00:00
|
|
|
lovr.graphics.submit(pass)
|
|
|
|
lovr.graphics.present()
|
2022-06-21 01:26:32 +00:00
|
|
|
end
|
|
|
|
end
|
2017-12-19 00:01:12 +00:00
|
|
|
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
|
|
|
|
|
lovr.log;
lovr.log is a new callback that is invoked whenever LÖVR wants to
send the project a message. For example, this could be a performance
warning from the graphics module, an error message from one of the
headset backends, or an API deprecation notice.
The callback's signature is (message, level, tag). The message is a
string containing the message to log, level is a string that is currently
one of "debug", "info", "warn", "error", and tag is an optional string
that is used to indicate the source of the message for grouping purposes.
The default implementation of the callback just prints the message,
but the callback can be overridden to do things like filter messages,
write them to a file, or even render them in VR. Projects can also
invoke the callback directly to log their own messages.
2020-07-06 22:20:55 +00:00
|
|
|
function lovr.log(message, level, tag)
|
2022-08-13 03:18:55 +00:00
|
|
|
print(message:gsub('\n$', ''))
|
lovr.log;
lovr.log is a new callback that is invoked whenever LÖVR wants to
send the project a message. For example, this could be a performance
warning from the graphics module, an error message from one of the
headset backends, or an API deprecation notice.
The callback's signature is (message, level, tag). The message is a
string containing the message to log, level is a string that is currently
one of "debug", "info", "warn", "error", and tag is an optional string
that is used to indicate the source of the message for grouping purposes.
The default implementation of the callback just prints the message,
but the callback can be overridden to do things like filter messages,
write them to a file, or even render them in VR. Projects can also
invoke the callback directly to log their own messages.
2020-07-06 22:20:55 +00:00
|
|
|
end
|
|
|
|
|
2018-04-26 03:07:28 +00:00
|
|
|
return function()
|
2022-08-13 03:18:55 +00:00
|
|
|
local errored = false
|
|
|
|
|
|
|
|
local function onerror(...)
|
2018-11-13 06:34:02 +00:00
|
|
|
if not errored then
|
2022-08-13 03:18:55 +00:00
|
|
|
errored = true -- Ensure errhand is only called once
|
|
|
|
return lovr.errhand(...) or function() return 1 end
|
2018-11-13 06:34:02 +00:00
|
|
|
else
|
2022-08-13 03:18:55 +00:00
|
|
|
local message = tostring(...) .. formatTraceback(debug.traceback('', 2))
|
|
|
|
print('Error occurred while trying to display another error:\n' .. message)
|
|
|
|
return function() return 1 end
|
2018-11-13 06:34:02 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-08-13 03:18:55 +00:00
|
|
|
-- thread will be either lovr.run's step function, or the result of errhand
|
|
|
|
local _, thread = xpcall(lovr.boot, onerror)
|
2018-04-26 03:07:28 +00:00
|
|
|
|
|
|
|
while true do
|
2022-08-13 03:18:55 +00:00
|
|
|
local ok, result, cookie = xpcall(thread, onerror)
|
2018-11-13 06:34:02 +00:00
|
|
|
|
2022-08-26 04:57:15 +00:00
|
|
|
-- If step function returned something, exit coroutine and return to C
|
|
|
|
if result and ok then
|
2022-08-13 03:18:55 +00:00
|
|
|
return result, cookie
|
|
|
|
elseif not ok then -- Switch to errhand loop
|
|
|
|
thread = result
|
|
|
|
if type(thread) ~= 'function' then
|
|
|
|
print('Error occurred while trying to display another error:\n' .. tostring(result))
|
|
|
|
return 1
|
|
|
|
end
|
2018-11-13 06:34:02 +00:00
|
|
|
end
|
2022-08-13 03:18:55 +00:00
|
|
|
|
|
|
|
coroutine.yield()
|
2018-11-13 06:34:02 +00:00
|
|
|
end
|
2017-12-19 00:01:12 +00:00
|
|
|
end
|