2026-06-06 12:35:31 +02:00
|
|
|
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 = "lovr/" .. iui.resourcePath
|
|
|
|
|
backend.resourcePath = "lovr/" .. backend.resourcePath
|
|
|
|
|
api.iui = iui
|
|
|
|
|
api.backend = backend
|
2026-06-09 17:27:06 +02:00
|
|
|
-- decorate api
|
|
|
|
|
api.protocol.http = require('http')
|
2026-06-06 12:35:31 +02:00
|
|
|
local ecs = api.ecs
|
|
|
|
|
|
2026-06-09 17:27:06 +02:00
|
|
|
|
2026-06-07 14:48:52 +02:00
|
|
|
-- ecs systems
|
|
|
|
|
local interactionsUpdater
|
|
|
|
|
local renderer
|
|
|
|
|
|
2026-06-06 12:35:31 +02:00
|
|
|
--- @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.exec( api.ext, "load")
|
|
|
|
|
|
|
|
|
|
if iui.idiom == "vr" then
|
|
|
|
|
lovr.headset.setPassthrough("opaque")
|
|
|
|
|
|
|
|
|
|
mainWindow = backend.worldWindow.new()
|
|
|
|
|
api.mainWindow = mainWindow
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function lovr.update(dt)
|
|
|
|
|
if lovr.system.isKeyDown("escape") then
|
|
|
|
|
lovr.event.quit()
|
|
|
|
|
end
|
|
|
|
|
|
2026-06-09 17:27:06 +02:00
|
|
|
ecs.update( api.world, dt, ecs.filter('updatesystem') )
|
2026-06-06 12:35:31 +02:00
|
|
|
|
|
|
|
|
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.exec( api.ext, "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.exec( api.ext, "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
|
2026-06-07 14:48:52 +02:00
|
|
|
|
2026-06-06 12:35:31 +02:00
|
|
|
api.exec(api.ext, "draw",pass)
|
2026-06-09 17:27:06 +02:00
|
|
|
ecs.update( api.world, pass, ecs.filter('drawsystem') )
|
2026-06-07 14:48:52 +02:00
|
|
|
|
|
|
|
|
-- Dot
|
|
|
|
|
if selectedBox then
|
|
|
|
|
pass:setColor(0, 0, 1)
|
|
|
|
|
pass:sphere(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, selectedBox and hitpoint or (hand + direction * 50))
|
|
|
|
|
|
2026-06-06 12:35:31 +02:00
|
|
|
if api.mainWindow then
|
|
|
|
|
api.mainWindow:draw(pass)
|
|
|
|
|
end
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function lovr.recenter()
|
|
|
|
|
if iui.idiom == "vr" then
|
|
|
|
|
mainWindow:recenter()
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if launch.mode == "desktop" then
|
|
|
|
|
function lovr.mousemoved(x, y, dx, dy)
|
|
|
|
|
backend.mousemoved(x, y, dx, dy)
|
2026-06-07 14:48:52 +02:00
|
|
|
interactionsUpdater['mouse']['moved'] = {x=x, y=y, button=button}
|
2026-06-06 12:35:31 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function lovr.mousepressed(x, y, button)
|
|
|
|
|
backend.mousepressed(x, y, button)
|
2026-06-07 14:48:52 +02:00
|
|
|
interactionsUpdater['mouse']['pressed'] = {x=x, y=y, button=button}
|
2026-06-06 12:35:31 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function lovr.mousereleased(x, y, button)
|
|
|
|
|
backend.mousereleased(x, y, button)
|
2026-06-07 14:48:52 +02:00
|
|
|
interactionsUpdater['mouse']['released'] = {x=x, y=y, button=button}
|
2026-06-09 17:27:06 +02:00
|
|
|
print("mouserelease")
|
2026-06-06 12:35:31 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function lovr.wheelmoved(x, y)
|
|
|
|
|
backend.wheelmoved(x, y)
|
2026-06-07 14:48:52 +02:00
|
|
|
interactionsUpdater['mouse']['wheel'] = {x=x, y=y}
|
2026-06-06 12:35:31 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function lovr.keypressed(key, scancode, isRepeat)
|
|
|
|
|
backend.keypressed(key, scancode, isRepeat)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function lovr.keyreleased(key, scancode)
|
|
|
|
|
backend.keyreleased(key, scancode)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function lovr.textinput(text)
|
|
|
|
|
backend.textinput(text)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local initECS = function(ecs)
|
|
|
|
|
-- lovr.draw => ecs.drawsystem (render-logic thread)
|
2026-06-07 14:48:52 +02:00
|
|
|
renderer = ecs.processingSystem()
|
|
|
|
|
renderer.filter = ecs.requireAny('model')
|
2026-06-06 12:35:31 +02:00
|
|
|
renderer.drawsystem = true
|
|
|
|
|
function renderer:process(obj, pass)
|
|
|
|
|
if obj['model'] ~= nil then
|
|
|
|
|
pass:setMaterial()
|
|
|
|
|
pass:setCullMode('none')
|
|
|
|
|
pass:draw(
|
|
|
|
|
obj['model'],
|
|
|
|
|
obj['x'] or 0,
|
|
|
|
|
obj['y'] or 0,
|
|
|
|
|
obj['z'] or 0,
|
|
|
|
|
1, 0, 1, 0, 0, 1)
|
|
|
|
|
end
|
|
|
|
|
end
|
2026-06-09 17:27:06 +02:00
|
|
|
ecs.addSystem( api.world, renderer )
|
2026-06-06 12:35:31 +02:00
|
|
|
|
|
|
|
|
-- lovr.update => ecs updatesystem (game-logic thread)
|
2026-06-07 14:48:52 +02:00
|
|
|
local updater = ecs.processingSystem()
|
|
|
|
|
updater.updatesystem = true
|
|
|
|
|
updater.filter = ecs.requireAll('update')
|
|
|
|
|
function updater:process(obj, dt)
|
2026-06-06 12:35:31 +02:00
|
|
|
print_r(obj['data'])
|
|
|
|
|
end
|
2026-06-09 17:27:06 +02:00
|
|
|
ecs.addSystem( api.world, updater )
|
2026-06-07 14:48:52 +02:00
|
|
|
|
|
|
|
|
end
|
2026-06-06 12:35:31 +02:00
|
|
|
|
2026-06-07 14:48:52 +02:00
|
|
|
function initInteractions(ecs)
|
|
|
|
|
|
|
|
|
|
ecs.worldPhysics = lovr.physics.newWorld(0, 0, 0)
|
|
|
|
|
interactionsUpdater = ecs.processingSystem()
|
|
|
|
|
interactionsUpdater.updatesystem = true
|
|
|
|
|
interactionsUpdater.filter = ecs.requireAll('collider')
|
|
|
|
|
-- collider vars
|
|
|
|
|
interactionsUpdater.mouse = { released = false}
|
|
|
|
|
interactionsUpdater.hitpoint = lovr.math.newVec3()
|
|
|
|
|
interactionsUpdater.selectedBox = nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function interactionsUpdater:process(obj, dt)
|
|
|
|
|
ecs.worldPhysics:update(dt)
|
|
|
|
|
|
|
|
|
|
local ox, oy, oz = lovr.headset.getPosition('hand/left/point')
|
|
|
|
|
local dx, dy, dz = quat(lovr.headset.getOrientation('hand/left/point')):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
|
|
|
|
|
if lovr.headset.isDown(hand, 'trigger') then
|
|
|
|
|
local node = collider:getUserData()
|
|
|
|
|
selectedBox = collider
|
|
|
|
|
hitpoint:set(x, y, z)
|
|
|
|
|
print( "collide with " .. node['name'] .. " => " .. node['extras']['href'] )
|
|
|
|
|
print("buttondown")
|
|
|
|
|
end
|
|
|
|
|
if lovr.headset.wasReleased(hand, 'trigger') or interactionsUpdater['mouse']['released'] then
|
|
|
|
|
print('click!')
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
-- reset mouse
|
|
|
|
|
mouse['released'] = false
|
|
|
|
|
mouse['pressed'] = false
|
|
|
|
|
end
|
2026-06-09 17:27:06 +02:00
|
|
|
ecs.addSystem( api.world, interactionsUpdater )
|
2026-06-06 12:35:31 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
initECS(api.ecs)
|
2026-06-07 14:48:52 +02:00
|
|
|
initInteractions(api.ecs)
|