1
0
Fork 0
mirror of https://github.com/bjornbytes/lovr.git synced 2024-07-02 12:33:52 +00:00
lovr/etc/boot.lua
bjorn a723ec7c5c Update error screen;
The error screen uses an orthographic projection when rendered in a
window, so the text is always the same size instead of scaling with the
window size.

Also you can close it with escape.
2023-05-12 17:16:22 +01:00

273 lines
7.5 KiB
Lua

lovr = require 'lovr'
-- Note: Cannot be overloaded
function lovr.boot()
local conf = {
version = '0.16.0',
identity = 'default',
saveprecedence = true,
modules = {
audio = true,
data = true,
event = true,
graphics = true,
headset = true,
math = true,
physics = true,
system = true,
thread = true,
timer = true
},
audio = {
start = true,
spatializer = nil
},
graphics = {
debug = false,
vsync = true,
stencil = false,
antialias = true,
shadercache = true
},
headset = {
drivers = { 'openxr', 'webxr', 'desktop' },
supersample = false,
offset = 1.7,
stencil = false,
antialias = true,
submitdepth = true,
overlay = false
},
math = {
globals = true
},
window = {
width = 720,
height = 800,
fullscreen = false,
resizable = false,
title = 'LÖVR',
icon = nil
}
}
lovr.filesystem = require('lovr.filesystem')
local main = arg[0] and arg[0]:match('[^\\/]-%.lua$') or 'main.lua'
local hasConf, hasMain = lovr.filesystem.isFile('conf.lua'), lovr.filesystem.isFile(main)
if not lovr.filesystem.getSource() or not (hasConf or hasMain) then require('nogame') end
-- 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
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
conf.graphics.debug = arg['--graphics-debug'] or conf.graphics.debug
lovr._setConf(conf)
lovr.filesystem.setIdentity(conf.identity, conf.saveprecedence)
for module in pairs(conf.modules) do
if conf.modules[module] then
local ok, result = pcall(require, 'lovr.' .. module)
if not ok then
print(string.format('Warning: Could not load module %q: %s', module, result))
else
lovr[module] = result
end
end
end
if lovr.system and conf.window then
lovr.system.openWindow(conf.window)
end
if lovr.graphics then
lovr.graphics.initialize()
end
if lovr.headset then
lovr.headset.start()
end
lovr.handlers = setmetatable({}, { __index = lovr })
if not confOk then error(confError) end
if hasMain then require(main:gsub('%.lua$', '')) end
return lovr.run()
end
function lovr.run()
if lovr.timer then lovr.timer.step() end
if lovr.load then lovr.load(arg) end
return function()
if lovr.system then lovr.system.pollEvents() end
if lovr.event then
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
end
end
local dt = 0
if lovr.timer then dt = lovr.timer.step() end
if lovr.headset then dt = lovr.headset.update() end
if lovr.update then lovr.update(dt) end
if lovr.graphics then
local headset = lovr.headset and lovr.headset.getPass()
if headset and (not lovr.draw or lovr.draw(headset)) then headset = nil end
local window = lovr.graphics.getWindowPass()
if window and (not lovr.mirror or lovr.mirror(window)) then window = nil end
lovr.graphics.submit(headset, window)
lovr.graphics.present()
end
if lovr.headset then lovr.headset.submit() end
if lovr.math then lovr.math.drain() end
end
end
function lovr.mirror(pass)
if lovr.headset then
local texture = lovr.headset.getTexture()
if texture then
pass:fill(texture)
end
else
return lovr.draw and lovr.draw(pass)
end
end
local function formatTraceback(s)
return s:gsub('\n[^\n]+$', ''):gsub('\t', ''):gsub('stack traceback:', '\nStack:\n')
end
function lovr.errhand(message)
message = 'Error:\n\n' .. tostring(message) .. formatTraceback(debug.traceback('', 4))
print(message)
if not lovr.graphics or not lovr.graphics.isInitialized() then
return function() return 1 end
end
if lovr.audio then lovr.audio.stop() end
if lovr.headset.getPassthrough() == 'opaque' then
lovr.graphics.setBackgroundColor(.11, .10, .14)
else
lovr.graphics.setBackgroundColor(0, 0, 0, 0)
end
local font = lovr.graphics.getDefaultFont()
return function()
lovr.system.pollEvents()
for name, a in lovr.event.poll() do
if name == 'quit' then return a or 1
elseif name == 'restart' then return 'restart', lovr.restart and lovr.restart()
elseif name == 'keypressed' and a == 'f5' then lovr.event.restart()
elseif name == 'keypressed' and a == 'escape' then lovr.event.quit() end
end
if lovr.headset and lovr.headset.getDriver() ~= 'desktop' then
lovr.headset.update()
local pass = lovr.headset.getPass()
if pass then
font:setPixelDensity()
local scale = .35
local font = lovr.graphics.getDefaultFont()
local wrap = .7 * font:getPixelDensity()
local lines = font:getLines(message, wrap)
local width = math.min(font:getWidth(message), wrap) * scale
local height = .8 + #lines * font:getHeight() * scale
local x = -width / 2
local y = math.min(height / 2, 10)
local z = -10
pass:setColor(.95, .95, .95)
pass:text(message, x, y, z, scale, 0, 0, 0, 0, wrap, 'left', 'top')
lovr.graphics.submit(pass)
lovr.headset.submit()
end
end
if lovr.system.isWindowOpen() then
local pass = lovr.graphics.getWindowPass()
if pass then
local w, h = lovr.system.getWindowDimensions()
pass:setProjection(1, mat4():orthographic(0, w, 0, h, -1, 1))
font:setPixelDensity(1)
local scale = .6
local wrap = w * .8 / scale
local width = math.min(font:getWidth(message), wrap) * scale
local x = w / 2 - width / 2
pass:setColor(.95, .95, .95)
pass:text(message, x, h / 2, 0, scale, 0, 0, 0, 0, wrap, 'left', 'middle')
lovr.graphics.submit(pass)
lovr.graphics.present()
end
end
lovr.math.drain()
end
end
function lovr.threaderror(thread, err)
error('Thread error\n\n' .. err, 0)
end
function lovr.log(message, level, tag)
message = message:gsub('\n$', '')
print(message)
end
return function()
local errored = false
local function onerror(...)
if not errored then
errored = true -- Ensure errhand is only called once
return lovr.errhand(...) or function() return 1 end
else
local message = tostring(...) .. formatTraceback(debug.traceback('', 2))
print('Error occurred while trying to display another error:\n' .. message)
return function() return 1 end
end
end
-- thread will be either lovr.run's step function, or the result of errhand
local _, thread = xpcall(lovr.boot, onerror)
while true do
local ok, result, cookie = xpcall(thread, onerror)
-- If step function returned something, exit coroutine and return to C
if result and ok then
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
end
coroutine.yield()
end
end