xurfer/xurfer/runtime/lovr/main.lua

226 lines
6.5 KiB
Lua

if os.getenv("LOCAL_LUA_DEBUGGER_VSCODE") == "1" then
require "lldebugger".start()
end
local util = require "util"
local launch = require "launch"
local iui = require "lib.iui"
local backend = require "lib.lovr-iui"
-- modify for nested lovr path for api
iui.resourcePath = "runtime/lovr/" .. iui.resourcePath
backend.resourcePath = "runtime/lovr/" .. backend.resourcePath
api.iui = iui
api.backend = backend
-- decorate api
local http = require('http')
api.protocol.http = {
request = function(url,opts,cb)
local status, data, headers = http.request(url,opts)
if cb == nil then print("error: api.protocol.http.request called without callback") end
cb(status,data,headers)
end
}
local ecs = api.ecs
ecs.filterDraw = ecs.requireAll('drawthread')
ecs.filterUpdate = ecs.requireAll('updatethread')
-- ecs systems
local interactionsUpdater
--- @type Texture
local envTex
--- @type LovrIUIWorldWindow
local mainWindow
function lovr.load()
if launch.mode == "desktop" then
backend.mouse = require "lib.lovr-mouse"
lovr.system.setKeyRepeat(true)
end
iui.load(backend)
api.ext.exec("load")
if iui.idiom == "vr" then
lovr.headset.setPassthrough("opaque")
mainWindow = backend.worldWindow.new()
api.mainWindow = mainWindow
end
end
function lovr.update(dt)
ecs.update( api.world, dt, ecs.filterUpdate )
iui.beginFrame(dt)
if iui.idiom == "desktop" then
-- In desktop mode, we use IUI's standard window API to fill the screen.
iui.beginWindow(lovr.system.getWindowDimensions())
api.ext.exec("update", dt)
iui.endWindow()
elseif iui.idiom == "vr" then
-- In VR mode, we have access to the backend's `LovrIUIWorldWindow`
-- class, which handles windowing in world-space.
if mainWindow:beginFrame() then
iui.beginWindow(mainWindow.w, mainWindow.h)
api.ext.exec("update", dt)
iui.endWindow()
mainWindow:endFrame()
end
end
iui.endFrame()
end
function lovr.draw(pass)
if iui.idiom == "desktop" then
backend.graphics.pass = pass
iui.draw()
end
if api.iui.idiom == "vr" then
pass:setClear(0.5, 0.5, 0.5)
end
api.ext.exec("draw",pass)
ecs.update( api.world, pass, ecs.filterDraw )
-- Dot
if interactionsUpdater.selectedBox then
pass:setColor(0, 0, 1)
pass:sphere( interactionsUpdater.hitpoint, .01)
end
-- Laser pointer
local hand = vec3(lovr.headset.getPosition('hand/left/point'))
local direction = quat(lovr.headset.getOrientation('hand/left/point')):direction()
pass:setColor(1, 1, 1)
pass:line(hand, interactionsUpdater.selectedBox and interactionsUpdater.hitpoint or (hand + direction * 50))
if api.mainWindow then
api.mainWindow:draw(pass)
end
return false
end
function lovr.recenter()
if iui.idiom == "vr" and lovr.headset.isActive() then
mainWindow:recenter()
end
end
if launch.mode == "desktop" then
function lovr.mousemoved(x, y, dx, dy)
backend.mousemoved(x, y, dx, dy)
interactionsUpdater.mouse.moved = {x=x, y=y}
end
function lovr.mousepressed(x, y, button)
backend.mousepressed(x, y, button)
interactionsUpdater.mouse.pressed = {x=x, y=y, button=button}
end
function lovr.mousereleased(x, y, button)
backend.mousereleased(x, y, button)
interactionsUpdater.mouse.released = {x=x, y=y, button=button}
print("mouserelease")
end
function lovr.wheelmoved(x, y)
backend.wheelmoved(x, y)
interactionsUpdater.mouse.wheel = {x=x, y=y}
end
function lovr.keypressed(key, scancode, isRepeat)
backend.keypressed(key, scancode, isRepeat)
interactionsUpdater.key.pressed = {key=key,scancode=scancode,isRepeat=isRepeat}
end
function lovr.keyreleased(key, scancode)
backend.keyreleased(key, scancode)
interactionsUpdater.key.released = {key=key,scancode=scancode}
end
function lovr.textinput(text)
backend.textinput(text)
interactionsUpdater.input = text
end
end
function initInteractions(ecs)
ecs.worldPhysics = lovr.physics.newWorld(0, 0, 0)
interactionsUpdater = ecs.processingSystem()
interactionsUpdater.updatethread = true
interactionsUpdater.filter = function(obj) return true end -- always run
-- collider vars
interactionsUpdater.mouse = { released = false, pressed = false, moved = false, wheel = false}
interactionsUpdater.key = { released = false, pressed = false }
interactionsUpdater.input = ""
interactionsUpdater.hitpoint = lovr.math.newVec3()
interactionsUpdater.selectedBox = nil
interactionsUpdater.clear = function(o) foreach( o, function(k,v) o[k] = false end ) end
function interactionsUpdater:process(obj, dt)
ecs.worldPhysics:update(dt)
local ox, oy, oz = lovr.headset.getPosition('hand/left/point')
local direction = quat(lovr.headset.getOrientation('hand/left/point')):direction()
if direction ~= nil then
local dx, dy, dz = direction:mul(50):unpack()
local collider, shape, x, y, z = ecs.worldPhysics:raycast(ox, oy, oz, ox + dx, oy + dy, oz + dz)
if collider then
for i, hand in ipairs(lovr.headset.getHands()) do
if lovr.headset.isDown(hand, 'trigger') then
print("buttondown")
end
if lovr.headset.wasReleased(hand, 'trigger') or interactionsUpdater['mouse']['released'] then
local node = collider:getUserData()
interactionsUpdater.selectedBox = collider
interactionsUpdater.hitpoint:set(x, y, z)
if node.onclick ~= nil then node.onclick(node,collider) end
end
end
end
end
-- reset stuff
interactionsUpdater.clear( interactionsUpdater.mouse )
interactionsUpdater.clear( interactionsUpdater.key )
interactionsUpdater.input = false
end
ecs.addSystem( api.world, interactionsUpdater )
end
function initCleanups(ecs)
local navigateListener = ecs.processingSystem({
updatethread = true,
filter = ecs.requireAll('URI', ecs.rejectAll('URLResponse') ),
onAdd = function(self,obj)
-- clear colliders if needed
if obj.URI.target ~= nil and obj.URI.target == '_top' then
ecs.worldPhysics:destroy()
ecs.worldPhysics = lovr.physics.newWorld(0, 0, 0)
end
end
})
ecs.addSystem( api.world, navigateListener )
end
initInteractions(api.ecs)
initCleanups(api.ecs)
require("render/model").init(api)