Skip to content

Commit

Permalink
Merge pull request #719 from bjornbytes/boot-rework
Browse files Browse the repository at this point in the history
Boot rework
  • Loading branch information
bjornbytes authored Dec 1, 2023
2 parents edecbc5 + afd11cf commit 4da1f26
Show file tree
Hide file tree
Showing 12 changed files with 309 additions and 311 deletions.
24 changes: 17 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1.0)
cmake_minimum_required(VERSION 3.3.0)
cmake_policy(SET CMP0063 NEW)
cmake_policy(SET CMP0079 NEW)
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum macOS deployment version")
Expand Down Expand Up @@ -629,6 +629,20 @@ foreach(path ${LOVR_RESOURCES})
file(WRITE ${output} "const unsigned char ${identifier}[] = {${data}};\nconst unsigned int ${identifier}_len = sizeof(${identifier});\n")
endforeach()

if(NOT ANDROID)
if(APPLE AND LOVR_BUILD_BUNDLE)
set(NOGAME_BUNDLE "${CMAKE_CURRENT_BINARY_DIR}/lovr.app/Contents/Resources/nogame.lovr")
else()
set(NOGAME_BUNDLE "$<TARGET_FILE:lovr>")
endif()
add_custom_command(TARGET lovr POST_BUILD
DEPENDS "etc/nogame"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/etc/nogame"
COMMAND ${CMAKE_COMMAND} -E tar c "${CMAKE_CURRENT_BINARY_DIR}/nogame.zip" --format=zip arg.lua conf.lua main.lua
COMMAND ${CMAKE_COMMAND} -E cat "${CMAKE_CURRENT_BINARY_DIR}/nogame.zip" >> ${NOGAME_BUNDLE}
)
endif()

# Add a custom target that is always out of date so libraries are always moved
add_custom_target(move_files ALL)

Expand Down Expand Up @@ -765,11 +779,7 @@ elseif(ANDROID)
if(LOVR_BUILD_EXE)
set(ANDROID_JAR "${ANDROID_SDK}/platforms/${ANDROID_PLATFORM}/android.jar")
set(ANDROID_TOOLS "${ANDROID_SDK}/build-tools/${ANDROID_BUILD_TOOLS_VERSION}")

# If assets are included in the apk then add '-A assets' to aapt, otherwise don't add any flags
if(ANDROID_ASSETS)
set(ANDROID_ASSETS -A ${ANDROID_ASSETS})
endif()
set(ANDROID_ASSETS "${CMAKE_CURRENT_SOURCE_DIR}/etc/nogame" CACHE STRING "The project folder to include in the APK")

if(LOVR_USE_OPENXR)
add_custom_command(TARGET move_files POST_BUILD
Expand Down Expand Up @@ -811,7 +821,7 @@ elseif(ANDROID)
-M AndroidManifest.xml
-I ${ANDROID_JAR}
-F lovr.unaligned.apk
${ANDROID_ASSETS}
-A ${ANDROID_ASSETS}
raw
COMMAND ${ANDROID_TOOLS}/zipalign -f -p 4 lovr.unaligned.apk lovr.unsigned.apk
COMMAND ${ANDROID_TOOLS}/apksigner
Expand Down
2 changes: 1 addition & 1 deletion Tupfile.lua
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ src += config.modules.math and 'src/lib/noise/*.c' or nil

-- embed resource files with xxd

res = { 'etc/boot.lua', 'etc/nogame.lua', 'etc/*.ttf', 'etc/shaders/*.glsl' }
res = { 'etc/boot.lua', 'etc/*.ttf', 'etc/shaders/*.glsl' }
tup.foreach_rule(res, '^ XD %b^ xxd -i %f > %o', '%f.h')

for i, pattern in ipairs(res) do
Expand Down
235 changes: 140 additions & 95 deletions etc/boot.lua
Original file line number Diff line number Diff line change
@@ -1,83 +1,127 @@
lovr = require 'lovr'

-- Note: Cannot be overloaded
function lovr.boot()
local conf = {
version = '0.17.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,
seated = false,
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
}
local lovr = lovr

local conf = {
version = '0.17.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,
seated = false,
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
}
}

function lovr.boot()
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]

-- See if there's a ZIP archive fused to the executable, and set up the fused CLI if it exists

local bundle, root = lovr.filesystem.getBundlePath()
local fused = lovr.filesystem.mount(bundle, nil, true, root)
local cli = lovr.filesystem.isFile('arg.lua') and assert(pcall(require, 'arg')) and lovr.arg and lovr.arg(arg)

-- Implement a barebones CLI if there is no bundled CLI/project

if not fused then
if arg[1] and not arg[1]:match('^%-') then
for i = 0, #arg do
arg[i - 1], arg[i] = arg[i], nil
end
else
return function()
print(table.concat({
'usage: lovr <source>',
'<source> can be a Lua file, a folder with a main.lua file, or a zip archive'
}, '\n'))
return 1
end
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
-- Figure out source archive and main module. CLI places source at arg[0]

local source, main
if (cli or not fused) and arg[0] then
if arg[0]:match('[^/\\]+%.lua$') then
source = arg[0]:match('[/\\]') and arg[0]:match('(.+)[/\\][^/\\]+$') or '.'
main = arg[0]:match('[^/\\]+%.lua$')
else
source = arg[0]
main = 'main.lua'
end
elseif fused then
source = bundle
main = 'main.lua'
end

conf.graphics.debug = arg['--graphics-debug'] or conf.graphics.debug
-- Mount source archive, make sure it's got the main file, and load conf.lua

local ok, failure = true, nil
if source ~= bundle and not lovr.filesystem.mount(source) then
ok, failure = false, ('Failed to load project at %q\nMake sure the path or archive is valid.'):format(source)
elseif not lovr.filesystem.isFile(main) then
local location = source == '.' and '' or (' in %q'):format(source:match('[^/\\]+[/\\]?$'))
ok, failure = false, ('No %s file found%s.\nThe project may be packaged incorrectly.'):format(main, location)
else
lovr.filesystem.setSource(source)
if lovr.filesystem.isFile('conf.lua') then ok, failure = pcall(require, 'conf') end
if ok and lovr.conf then ok, failure = pcall(lovr.conf, conf) end
end

lovr._setConf(conf)
lovr.filesystem.setIdentity(conf.identity, conf.saveprecedence)

-- CLI gets a chance to use/modify conf and handle arguments

if ok and not failure and cli then ok, failure = pcall(cli, conf) end

-- Boot!

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))
local loaded, result = pcall(require, 'lovr.' .. module)
if not loaded then
lovr.log('warn', string.format('Could not load module %q: %s', module, result))
else
lovr[module] = result
end
Expand All @@ -96,9 +140,12 @@ function lovr.boot()
lovr.headset.start()
end

lovr.handlers = setmetatable({}, { __index = lovr })
if not confOk then error(confError) end
if hasMain then require(main:gsub('%.lua$', '')) end
if not ok and failure then
error(failure)
end

require(main:sub(1, -5))

return lovr.run()
end

Expand Down Expand Up @@ -151,7 +198,7 @@ function lovr.errhand(message)

print(message)

if not lovr.graphics or not lovr.graphics.isInitialized() then
if not lovr.graphics then
return function() return 1 end
end

Expand Down Expand Up @@ -185,7 +232,9 @@ function lovr.errhand(message)
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 maxWidth = 0
for i, line in ipairs(lines) do maxWidth = math.max(maxWidth, font:getWidth(line)) end
local width = maxWidth * scale
local height = .8 + #lines * font:getHeight() * scale
local x = -width / 2
local y = math.min(height / 2, 10)
Expand All @@ -203,12 +252,15 @@ function lovr.errhand(message)
local pass = lovr.graphics.getWindowPass()
if pass then
local w, h = lovr.system.getWindowDimensions()
pass:setProjection(1, lovr.math.mat4():orthographic(0, w, 0, h, -1, 1))
pass:setProjection(1, lovr.math.mat4():orthographic(w, h))
font:setPixelDensity(1)

local scale = .6
local wrap = w * .8 / scale
local width = math.min(font:getWidth(message), wrap) * scale
local lines = font:getLines(message, wrap)
local maxWidth = 0
for i, line in ipairs(lines) do maxWidth = math.max(maxWidth, font:getWidth(line)) end
local width = maxWidth * scale
local x = w / 2 - width / 2

pass:setColor(.95, .95, .95)
Expand All @@ -232,37 +284,30 @@ function lovr.log(message, level, tag)
print(message)
end

return function()
local errored = false
lovr.handlers = setmetatable({}, { __index = lovr })

return coroutine.create(function()
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)
onerror = function(...)
print('Error:\n\n' .. tostring(...) .. formatTraceback(debug.traceback('', 1)))
return function() return 1 end
end

local ok, result = pcall(lovr.errhand or onerror, ...)

if ok then
return result or function() return 1 end
else
return onerror(result)
end
end

-- thread will be either lovr.run's step function, or the result of errhand
local _, thread = xpcall(lovr.boot, onerror)
local thread = select(2, 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

if not ok then thread = result
elseif result then return result, cookie end
coroutine.yield()
end
end
end)
Loading

0 comments on commit 4da1f26

Please sign in to comment.