luax wip
This commit is contained in:
parent
9360423a5c
commit
f4b633d560
28 changed files with 180 additions and 58 deletions
|
|
@ -53,6 +53,10 @@ $ ./lovr xurfer
|
|||
...
|
||||
```
|
||||
|
||||
## Longterm goal
|
||||
|
||||
* Android launcher for OpenXR & WebXR apps
|
||||
|
||||
## Security
|
||||
|
||||
Instead of the traditional sandbox-in-a-browser-model (Chromium/Firefox e.g.), we suggest running XURFER via [bubblewrap](https://github.com/meta-quest/bubblewrap)
|
||||
|
|
|
|||
19
nix/luax-release.sh
Executable file
19
nix/luax-release.sh
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
export PATH=$PATH:.
|
||||
which luax || {
|
||||
wget "https://cdelord.fr/pub/luax/10.10.0/luax-linux-x86_64-musl"
|
||||
ln -s luax-linux-x86_64-musl luax
|
||||
chmod +x luax
|
||||
}
|
||||
|
||||
cd xurfer
|
||||
files="$(find * -type f | grep lua | grep -vE '(runtime/lov*)')"
|
||||
echo $files
|
||||
|
||||
luax compile -t list | tail -n+3 | awk '$1 ~ /[a-z]-[a-z]/ {print $1}' | \
|
||||
while read platform; do
|
||||
#luax compile -t $platform -o ./../xurfer-$platform ${files}
|
||||
# TODO: luaX needs unique modulenames : main.lua clashes in the binary
|
||||
luax compile -t $platform -o ./../xurfer-$platform conf.lua ecs.lua events.lua ext/kitchensink/main.lua ext/xrfragments/main.lua #ext/xrfragments/level2.lua ext/xrfragments/level4.lua ext/xrfragments/lovr-xrf.lua ext/skeleton/main.lua ext/unixy/main.lua ext/gazecontrol/main.lua ext/janusxr/main.lua ext/http-lovr/main.lua ext/startupscene/main.lua ext/3DFile/main.lua ext/tween/main.lua ext/tween/tween.lua ext/AudioFile/main.lua ext/button/main.lua ext/URI/main.lua init.lua lib/lust.lua lib/tiny-ecs.lua lib/xmlSimple.lua lib/json.lua lib/url.lua main.lua runtime/lua/conf.lua runtime/lua/main.lua runtime/lua/api.lua runtime/detect.lua test/main.lua util.lua
|
||||
exit
|
||||
done
|
||||
|
|
@ -1,8 +1,13 @@
|
|||
#!/bin/sh
|
||||
export DEBUG=1
|
||||
cd xurfer
|
||||
runtime="/home/leon/apps/lovr-v0.18.0-x86_64.AppImage"
|
||||
#./main.lua
|
||||
#runtime="/home/leon/apps/lovr-v0.18.0-x86_64.AppImage"
|
||||
runtime="/home/leon/apps/lovr-v0.18.1-x86_64.AppImage"
|
||||
#appimage-run $runtime . test.glb
|
||||
appimage-run $runtime . https://snips.sh/f/_U5-XctEVE?r=1
|
||||
#appimage-run $runtime . http://localhost:8080/simple-a.glb
|
||||
#appimage-run $runtime . http://localhost:8080/level3-4-playaudio.glb
|
||||
#appimage-run $runtime . http://localhost:8080/simple-b.glb
|
||||
#appimage-run $runtime . test.localhost.jml0
|
||||
#appimage-run $runtime . http://localhost:8080/simple-b-wireframe.glb
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
-- default argument
|
||||
--@LIB
|
||||
if arg[1] == nil then
|
||||
arg[1] = "https://snips.sh/f/_U5-XctEVE?r=1"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
local ecs = require("lib/tiny-ecs")
|
||||
|
||||
ecs.init = function(api)
|
||||
|
|
|
|||
10
xurfer/events.lua
Normal file
10
xurfer/events.lua
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
--@LIB
|
||||
return {
|
||||
input = {
|
||||
pointer = { released = false, pressed = false, moved = false, hover = false, wheel = false},
|
||||
key = { released = false, pressed = false },
|
||||
input = false, -- string if true,
|
||||
collider = false, -- lovr collider
|
||||
hitpoint = false, -- {x=0, y=0, z=0}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
local api = ...
|
||||
local ecs = api.ecs
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
local api = ...
|
||||
local ecs = api.ecs
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
local api = ...
|
||||
local ecs = api.ecs
|
||||
|
||||
|
|
|
|||
63
xurfer/ext/button/main.lua
Normal file
63
xurfer/ext/button/main.lua
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
--@LIB
|
||||
local api = ...
|
||||
local ecs = api.ecs
|
||||
|
||||
-- this is an input extension which adds data the input-event
|
||||
-- which is fed to update-calls of extensions and ECS
|
||||
|
||||
local button
|
||||
button = {
|
||||
name = "button",
|
||||
enabled = true,
|
||||
settings = { -- keep this settings serializable (no functions e.g.) + use lovr key-names
|
||||
|
||||
-- (SHIFT) TAB/ENTER as described in the Accessibility guidelines
|
||||
-- of XR (URI) fragments: https://xrfragment.org/#accessibility
|
||||
{ event={name="next"}, key="tab" },
|
||||
{ event={name="previous"}, key="tab", shift=true},
|
||||
{ event={name="select"}, key="return", pointer={released=true} },
|
||||
{ event={name="select"}, key="space", pointer={released=true} },
|
||||
|
||||
},
|
||||
state = { shift = false },
|
||||
|
||||
init = function()
|
||||
if not api.settings.button then
|
||||
api.settings.button = button.settings
|
||||
end
|
||||
end,
|
||||
|
||||
isShift = function(key) return key == "rshift" or key == "lshift" end,
|
||||
|
||||
matchKey = function(mapping, event)
|
||||
return mapping.key ~= nil and
|
||||
mapping.shift == (button.state.shift or nil) and
|
||||
mapping.key == event.key
|
||||
end,
|
||||
|
||||
input = function(dt,input)
|
||||
-- sense shift state
|
||||
if input.key.pressed and button.isShift(input.key.pressed.key) then button.state.shift = true end
|
||||
if input.key.released and button.isShift(input.key.released.key) then button.state.shift = false end
|
||||
|
||||
local mappings = api.settings.button
|
||||
-- process keymapping
|
||||
if input.key.released then
|
||||
foreach(mappings, function(k,mapping)
|
||||
if button.matchKey( mapping, input.key.released ) then
|
||||
input[ mapping.event.name ] = mapping.event -- add to input event (so update-calls can see it)
|
||||
end
|
||||
end)
|
||||
end
|
||||
-- process keymapping
|
||||
if input.pointer.released then
|
||||
foreach(mappings, function(k,mapping)
|
||||
if mapping.pointer and mapping.pointer.released then
|
||||
input[ mapping.event.name ] = mapping.event -- add to input event (so update-calls can see it)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
return button
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
local api = ...
|
||||
local ecs = api.ecs
|
||||
|
||||
|
|
@ -25,7 +26,6 @@ gctl = {
|
|||
init = function()
|
||||
--lovr.mouse.setRelativeMode(true)
|
||||
gctl.initVisor()
|
||||
gctl.extendECS()
|
||||
api.player.matrix = lovr.math.newMat4()
|
||||
end,
|
||||
|
||||
|
|
@ -84,23 +84,6 @@ gctl = {
|
|||
pass:plane(x, y, z, scale, scale, angle, ax, ay, az)
|
||||
end,
|
||||
|
||||
-- ECS API docs: https://bakpakin.github.io/tiny-ecs/doc
|
||||
extendECS = function()
|
||||
|
||||
local visorSystem = ecs.processingSystem({
|
||||
updatethread = true,
|
||||
filter = ecs.requireAll('mycomponent'),
|
||||
onAdd = function(self,obj) print_r(obj) end,
|
||||
onRemove = function(self,obj) end,
|
||||
process = function(self,obj) end,
|
||||
})
|
||||
ecs.addSystem( api.world, visorSystem )
|
||||
|
||||
ecs.add( api.world, { visor = gctl.visor } )
|
||||
--gctl.visor.commit() -- notify other systems to update entitycache
|
||||
|
||||
end
|
||||
|
||||
}
|
||||
|
||||
return gctl
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
-- this extension will make network requests run async in LoVR runtime
|
||||
|
||||
local api = ...
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
--@LIB
|
||||
local api = ...
|
||||
|
||||
local sample
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
local api = ...
|
||||
local ecs = api.ecs
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
local api = ...
|
||||
local envTex
|
||||
local shader
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
local api = ...
|
||||
local tween = require "ext/tween/tween" -- https://github.com/kikito/tween.lua
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
local tween = {
|
||||
_VERSION = 'tween 2.1.1',
|
||||
_DESCRIPTION = 'tweening for lua',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
-- The unixy extension allows proxying api-functions through cli apps.
|
||||
-- Why?
|
||||
-- Sometimes the host OS already has cli-apps which can make up for missing lua functionality.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
local api = ...
|
||||
local xrf = require("ext/xrfragments/lovr-xrf")
|
||||
local url = require("url")
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
local xrf = require("ext/xrfragments/lovr-xrf")
|
||||
local url = require("url")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
-- Copyright 2026 Leon van Kammen / coderofsalvation. All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without modification, are
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB=xrfragment/main.lua
|
||||
local api = ...
|
||||
local url = require('url')
|
||||
local ecs = api.ecs
|
||||
|
|
@ -19,7 +20,7 @@ xrfimpl = {
|
|||
local href = obj.node.extras.href
|
||||
trace("\n[xrf] href was clicked: " .. href)
|
||||
api.ext.exec("onClick", obj, collider)
|
||||
local ok = xrf.level2.load( href, obj, api.ext.URI.current, xrfimpl.onLoad)
|
||||
local ok = xrf.level2.load( href, obj, referer, xrfimpl.onLoad)
|
||||
or
|
||||
xrf.level4.import( href, obj, referer, xrfimpl.onImport)
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
--@LIB
|
||||
print("hello!")
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ function url.parse(url_string)
|
|||
URN = "",
|
||||
isLocal = false
|
||||
}
|
||||
if not url_string then return URI end
|
||||
local remaining = url_string
|
||||
local protocol = string.match(remaining, "^(%w+://)") -- protocol
|
||||
if protocol then
|
||||
|
|
@ -152,11 +153,18 @@ url.getAbsolute = function(href,referer,keephash)
|
|||
if referer ~= nil and URL.protocol == 'file' and URLref.protocol ~= 'file' then
|
||||
URL.protocol = URLref.protocol or ''
|
||||
URL.domain = URLref.domain or ''
|
||||
URL.string = URL.protocol .. '://' .. URL.domain .. '/' .. URL.path .. URL.hash
|
||||
if keephash then
|
||||
URL.URN = URL.string
|
||||
URL.string = URL.protocol .. '://' .. URL.domain .. '/'
|
||||
if href[1] == "/" then
|
||||
URL.string = URL.string .. URL.path
|
||||
else
|
||||
URL.URN = URL.string:gsub("#.*", "")
|
||||
URL.string = URL.string ..
|
||||
URLref.path:sub( 0, URLref.path:find( URLref.file,1,true)-1 ) ..
|
||||
URL.file
|
||||
end
|
||||
URL.string = URL.string .. URL.hash
|
||||
URL = url.parse(URL.string) -- reparse
|
||||
if keephash then
|
||||
URL.hash = URLref.hash
|
||||
end
|
||||
end
|
||||
URL.referer = referer
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---------------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------------
|
||||
--
|
||||
--@LIB
|
||||
-- xml.lua - XML parser for use with the Corona SDK.
|
||||
-- https://github.com/Cluain/Lua-Simple-XML-Parser
|
||||
--
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
#!/usr/bin/env lua
|
||||
--please do not remove the following luaX tag:
|
||||
--@MAIN
|
||||
--
|
||||
-- -- GLB URLS
|
||||
-- ./lovr xurfer https://coderofsalvation.codeberg.page/xrfragment-haxe/example/assets/example.glb?bar=1&f=2#foo'
|
||||
-- ./lovr xurfer https://codeberg.org/coderofsalvation/xrfragment/raw/branch/main/assets/template/website/website.glb'
|
||||
|
|
@ -37,6 +40,10 @@ api = {
|
|||
max = 10000, -- max plugins (used for sorting)
|
||||
exec = function(...) util.exec(api.ext,...) end -- util function to call func on each extension
|
||||
},
|
||||
settings = { -- settings to store to ~/.config/xurfer/config.lua e.g.
|
||||
version="0.0.1"
|
||||
},
|
||||
events = require('events'),
|
||||
i = 1
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ function lovr.load()
|
|||
end
|
||||
|
||||
function lovr.update(dt)
|
||||
local event = interactions.collect()
|
||||
ecs.update( api.world, dt, ecs.filterUpdate )
|
||||
|
||||
iui.beginFrame(dt)
|
||||
|
|
@ -89,7 +90,7 @@ function lovr.update(dt)
|
|||
-- In desktop mode, we use IUI's standard window API to fill the screen.
|
||||
iui.beginWindow(lovr.system.getWindowDimensions())
|
||||
|
||||
api.ext.exec("update", dt, interactions.event )
|
||||
api.ext.exec("update", dt, event )
|
||||
|
||||
iui.endWindow()
|
||||
|
||||
|
|
@ -99,7 +100,7 @@ function lovr.update(dt)
|
|||
if mainWindow:beginFrame() then
|
||||
iui.beginWindow(mainWindow.w, mainWindow.h)
|
||||
|
||||
api.ext.exec("update", dt, interactions.event )
|
||||
api.ext.exec("update", dt, event )
|
||||
|
||||
iui.endWindow()
|
||||
|
||||
|
|
@ -108,6 +109,7 @@ function lovr.update(dt)
|
|||
end
|
||||
|
||||
iui.endFrame()
|
||||
interactions.clear()
|
||||
end
|
||||
|
||||
function lovr.draw(pass)
|
||||
|
|
@ -129,7 +131,7 @@ function lovr.draw(pass)
|
|||
|
||||
|
||||
-- -- Dot
|
||||
--if interactions.selectedBox then
|
||||
--if interactions.hitpoint then
|
||||
-- pass:setColor(0, 0, 1)
|
||||
-- pass:sphere( interactions.hitpoint, .01)
|
||||
--end
|
||||
|
|
@ -173,7 +175,6 @@ end
|
|||
function lovr.wheelmoved(x, y)
|
||||
backend.wheelmoved(x, y)
|
||||
interactions.pointer.wheel = {x=x, y=y}
|
||||
print_r(interactions.pointer.wheel)
|
||||
end
|
||||
|
||||
function lovr.keypressed(key, scancode, isRepeat)
|
||||
|
|
@ -197,12 +198,13 @@ function initInteractions(ecs)
|
|||
interactions = ecs.processingSystem()
|
||||
interactions.updatethread = true
|
||||
interactions.filter = function(obj) return true end -- always run
|
||||
interactions.pointer = util.clone( api.events.input.pointer )
|
||||
interactions.key = util.clone( api.events.input.key )
|
||||
interactions.input = ""
|
||||
-- collider vars
|
||||
interactions.pointer = { released = false, pressed = false, moved = false, hover = false, wheel = false}
|
||||
interactions.key = { released = false, pressed = false }
|
||||
interactions.input = ""
|
||||
interactions.hitpoint = vector()
|
||||
interactions.selectedBox = nil
|
||||
interactions.direction = quat():direction()
|
||||
interactions.clearTable = function(o) foreach( o, function(k,v) o[k] = false end ) end
|
||||
interactions.clear = function()
|
||||
interactions.clearTable( interactions.pointer )
|
||||
|
|
@ -210,23 +212,20 @@ function initInteractions(ecs)
|
|||
interactions.input = false
|
||||
end
|
||||
|
||||
function interactions:process(obj, dt)
|
||||
ecs.worldPhysics:update(dt)
|
||||
|
||||
local castsrc = 'hand/left/point'
|
||||
local castsrc = 'head'
|
||||
|
||||
interactions.collect = function(dt)
|
||||
local castsrc = 'head' -- 'hand/left/point'
|
||||
local event = util.clone(api.events.input)
|
||||
interactions.event = event -- for convenience (ecs systems can always reach it)
|
||||
local ox, oy, oz = lovr.headset.getPosition(castsrc)
|
||||
|
||||
local direction = quat(lovr.headset.getOrientation(castsrc)):direction()
|
||||
if direction ~= nil then
|
||||
local dx, dy, dz = vector( direction * 50 ):unpack()
|
||||
interactions.direction = quat(lovr.headset.getOrientation(castsrc)):direction()
|
||||
if interactions.direction ~= nil then
|
||||
local dx, dy, dz = vector( interactions.direction * 50 ):unpack()
|
||||
local collider, shape, x, y, z = ecs.worldPhysics:raycast(ox, oy, oz, ox + dx, oy + dy, oz + dz)
|
||||
|
||||
if collider then
|
||||
interactions.pointer.hover = true
|
||||
local node = collider:getUserData()
|
||||
interactions.selectedBox = collider
|
||||
interactions.pointer.hover = true
|
||||
interactions.hitpoint.x = x
|
||||
interactions.hitpoint.y = y
|
||||
interactions.hitpoint.z = z
|
||||
|
|
@ -239,22 +238,29 @@ function initInteractions(ecs)
|
|||
interactions.pointer.released = true
|
||||
end
|
||||
end
|
||||
if interactions.pointer.released and node.onclick ~= nil then
|
||||
node.onclick(node,collider)
|
||||
end
|
||||
event.collider = collider
|
||||
event.node = node
|
||||
end
|
||||
end
|
||||
event.direction = util.clone(direction)
|
||||
event.input = interactions.input
|
||||
event.pointer = util.clone(interactions.pointer)
|
||||
event.key = util.clone(interactions.key)
|
||||
event.hitpoint = { x = interactions.hitpoint.x, y = interactions.hitpoint.y, z = interactions.z }
|
||||
--event.head = { x = ox, y = oy, z = oz, direction = direction},
|
||||
api.ext.exec('input', dt, event )
|
||||
return event
|
||||
end
|
||||
|
||||
function interactions:process(obj, dt)
|
||||
ecs.worldPhysics:update(dt)
|
||||
local event = interactions.event
|
||||
if event.collider then
|
||||
--if event.pointer.released and event.node and event.node.onclick ~= nil then
|
||||
if event.select and event.node and event.node.onclick ~= nil then
|
||||
event.node.onclick(event.node, event.collider)
|
||||
end
|
||||
end
|
||||
-- backup & reset stuff
|
||||
interactions.event = {
|
||||
input = util.clone(interactions.input),
|
||||
pointer = util.clone(interactions.pointer),
|
||||
key = util.clone(interactions.key),
|
||||
hitpoint = { x = interactions.hitpoint.x, y = interactions.hitpoint.y, z = interactions.z },
|
||||
--head = { x = ox, y = oy, z = oz, direction = direction},
|
||||
collider = collider
|
||||
}
|
||||
-- clear interactions
|
||||
interactions.clear()
|
||||
end
|
||||
ecs.addSystem( api.world, interactions )
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
--@LIB
|
||||
local lust = require 'lust'
|
||||
local describe, it, expect = lust.describe, lust.it, lust.expect
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue