From 1eb4ccca51c4bb551545986b2663119f8a45cf80 Mon Sep 17 00:00:00 2001 From: SpookySkeletons <37986496+SpookySkeletons@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:43:21 -0500 Subject: [PATCH 01/10] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 01ba9b6..9aaeb8c 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,7 @@ Press `action_button` (`trigger` by default) to set points. Hold `action_button` ## Configuration Settings are stored separated in the program directory, in `config/`. -- `action_button.txt`: The button to use to do actions like placing points. [See the LÖVR documentation](https://lovr.org/docs/v0.16.0/DeviceButton). -- `check_density.txt`: BROKEN! With how much line-density (in meters) to check if you're close to a wall. +- `action_button.txt`: The button to use to do actions like placing points. [See the LÖVR documentation](https://lovr.org/docs/v0.17.0/DeviceButton). - `color_close_corners.json`: How to color the points you've set when they're close. Borders of edges of your defined shape, as well as your grid\_top/grid\_bottom. - `color_close_grid.json`: How to color the lines between the corners when close. - `color_close_corners.json`: How to color the points you've set when they're far. From 61f0cfcee6677742f0771de606a57c1ba8cb7ab6 Mon Sep 17 00:00:00 2001 From: SpookySkeletons <37986496+SpookySkeletons@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:44:32 -0500 Subject: [PATCH 02/10] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9aaeb8c..94758cb 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Room boundary overlay for OpenXR, made with LÖVR. ## How to run ``` -git clone "https://git.lumen.sh/Fierelier/lovr-playspace" +git clone "https://github.com/SpookySkeletons/lovr-playspace" ./lovr-*.AppImage lovr-playspace ``` From 5c0a42b2e5d663a2dc15a318e36d5fc8423e4483 Mon Sep 17 00:00:00 2001 From: BabbleBones Date: Tue, 30 Jan 2024 19:49:07 -0500 Subject: [PATCH 03/10] ignore points --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d796c95 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +config/points.json From 93b6ecb0e1283789b2fe8e15e7681b1c1efac7df Mon Sep 17 00:00:00 2001 From: BabbleBones Date: Thu, 14 Mar 2024 02:36:27 -0400 Subject: [PATCH 04/10] Update config for lovr 17.1 stable --- conf.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conf.lua b/conf.lua index 7184caa..9f61518 100644 --- a/conf.lua +++ b/conf.lua @@ -1,4 +1,5 @@ function lovr.conf(t) - t.headset.overlay = 2 + t.headset.overlay = true + t.headset.overlayOrder = 2 t.window = false end From 97aa22d6aa049478097b0499d41d80ead471f288 Mon Sep 17 00:00:00 2001 From: BabbleBones Date: Sat, 23 Mar 2024 01:28:12 -0400 Subject: [PATCH 05/10] let's just stuff some ints here because it works --- conf.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf.lua b/conf.lua index 9f61518..3add5f2 100644 --- a/conf.lua +++ b/conf.lua @@ -1,5 +1,5 @@ function lovr.conf(t) - t.headset.overlay = true + t.headset.overlay = 2 t.headset.overlayOrder = 2 t.window = false end From 64fb9d69a2aa2f9d3f2f14fc7f6a593e85f10c59 Mon Sep 17 00:00:00 2001 From: Bones Date: Tue, 18 Jun 2024 05:36:24 -0400 Subject: [PATCH 06/10] Fix hands not being detected --- main.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/main.lua b/main.lua index fd4949a..2c7a695 100644 --- a/main.lua +++ b/main.lua @@ -9,8 +9,8 @@ limbs = { "head", "hand/left", "hand/right", - "hand/left/point", - "hand/right/point", + "hand/left/grip", + "hand/right/grip", "elbow/left", "elbow/right", "shoulder/left", @@ -255,8 +255,8 @@ function modeConfigure(pass) local hx, hy, hz = lovr.headset.getPosition("head") for _, hand in ipairs(hands) do - if isTracked(hand .. "/point") then - local cx, cy, cz = lovr.headset.getPosition(hand .. "/point") + if isTracked(hand) then + local cx, cy, cz = lovr.headset.getPosition(hand) -- Compute the direction from the controller to the headset local dirX = hx - cx @@ -347,4 +347,4 @@ end function lovr.draw(pass) mode(pass) -end \ No newline at end of file +end From a859e60e287ffc483acf3fb326ca95caa3465dda Mon Sep 17 00:00:00 2001 From: BabbleBones Date: Thu, 13 Feb 2025 13:03:21 -0500 Subject: [PATCH 07/10] switch to lovr filesystem api, submodule json, write configs to disk --- .gitmodules | 3 + conf.lua | 1 + config/action_button.txt | 1 - config/check_density.txt | 1 - config/color_close_corners.json | 1 - config/color_close_grid.json | 1 - config/color_far_corners.json | 1 - config/color_far_grid.json | 1 - config/fade_start.txt | 1 - config/fade_stop.txt | 1 - config/grid_bottom.txt | 1 - config/grid_density.txt | 1 - config/grid_top.txt | 1 - json | 1 + lib/json.lua | 388 -------------------------------- main.lua | 172 +++++++------- 16 files changed, 91 insertions(+), 485 deletions(-) create mode 100644 .gitmodules delete mode 100644 config/action_button.txt delete mode 100644 config/check_density.txt delete mode 100644 config/color_close_corners.json delete mode 100644 config/color_close_grid.json delete mode 100644 config/color_far_corners.json delete mode 100644 config/color_far_grid.json delete mode 100644 config/fade_start.txt delete mode 100644 config/fade_stop.txt delete mode 100644 config/grid_bottom.txt delete mode 100644 config/grid_density.txt delete mode 100644 config/grid_top.txt create mode 160000 json delete mode 100644 lib/json.lua diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..50926d4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "json.lua"] + path = json + url = https://github.com/rxi/json.lua diff --git a/conf.lua b/conf.lua index 3add5f2..96e3bcf 100644 --- a/conf.lua +++ b/conf.lua @@ -2,4 +2,5 @@ function lovr.conf(t) t.headset.overlay = 2 t.headset.overlayOrder = 2 t.window = false + t.identity = "lovr-playspace" end diff --git a/config/action_button.txt b/config/action_button.txt deleted file mode 100644 index b28fbc7..0000000 --- a/config/action_button.txt +++ /dev/null @@ -1 +0,0 @@ -trigger \ No newline at end of file diff --git a/config/check_density.txt b/config/check_density.txt deleted file mode 100644 index 30e2fb4..0000000 --- a/config/check_density.txt +++ /dev/null @@ -1 +0,0 @@ -0.05 \ No newline at end of file diff --git a/config/color_close_corners.json b/config/color_close_corners.json deleted file mode 100644 index 3054842..0000000 --- a/config/color_close_corners.json +++ /dev/null @@ -1 +0,0 @@ -[0.45,0.69,0.79,1.0] \ No newline at end of file diff --git a/config/color_close_grid.json b/config/color_close_grid.json deleted file mode 100644 index f95ef1b..0000000 --- a/config/color_close_grid.json +++ /dev/null @@ -1 +0,0 @@ -[0.45,0.69,0.79,0.5] \ No newline at end of file diff --git a/config/color_far_corners.json b/config/color_far_corners.json deleted file mode 100644 index 42e7855..0000000 --- a/config/color_far_corners.json +++ /dev/null @@ -1 +0,0 @@ -[0.45,0.69,0.79,0] \ No newline at end of file diff --git a/config/color_far_grid.json b/config/color_far_grid.json deleted file mode 100644 index 42e7855..0000000 --- a/config/color_far_grid.json +++ /dev/null @@ -1 +0,0 @@ -[0.45,0.69,0.79,0] \ No newline at end of file diff --git a/config/fade_start.txt b/config/fade_start.txt deleted file mode 100644 index ea2303b..0000000 --- a/config/fade_start.txt +++ /dev/null @@ -1 +0,0 @@ -0.5 \ No newline at end of file diff --git a/config/fade_stop.txt b/config/fade_stop.txt deleted file mode 100644 index 415b19f..0000000 --- a/config/fade_stop.txt +++ /dev/null @@ -1 +0,0 @@ -2.0 \ No newline at end of file diff --git a/config/grid_bottom.txt b/config/grid_bottom.txt deleted file mode 100644 index 171538e..0000000 --- a/config/grid_bottom.txt +++ /dev/null @@ -1 +0,0 @@ -0.0 \ No newline at end of file diff --git a/config/grid_density.txt b/config/grid_density.txt deleted file mode 100644 index 9f8e9b6..0000000 --- a/config/grid_density.txt +++ /dev/null @@ -1 +0,0 @@ -1.0 \ No newline at end of file diff --git a/config/grid_top.txt b/config/grid_top.txt deleted file mode 100644 index e440e5c..0000000 --- a/config/grid_top.txt +++ /dev/null @@ -1 +0,0 @@ -3 \ No newline at end of file diff --git a/json b/json new file mode 160000 index 0000000..dbf4b2d --- /dev/null +++ b/json @@ -0,0 +1 @@ +Subproject commit dbf4b2dd2eb7c23be2773c89eb059dadd6436f94 diff --git a/lib/json.lua b/lib/json.lua deleted file mode 100644 index 711ef78..0000000 --- a/lib/json.lua +++ /dev/null @@ -1,388 +0,0 @@ --- --- json.lua --- --- Copyright (c) 2020 rxi --- --- Permission is hereby granted, free of charge, to any person obtaining a copy of --- this software and associated documentation files (the "Software"), to deal in --- the Software without restriction, including without limitation the rights to --- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies --- of the Software, and to permit persons to whom the Software is furnished to do --- so, subject to the following conditions: --- --- The above copyright notice and this permission notice shall be included in all --- copies or substantial portions of the Software. --- --- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --- SOFTWARE. --- - -local json = { _version = "0.1.2" } - -------------------------------------------------------------------------------- --- Encode -------------------------------------------------------------------------------- - -local encode - -local escape_char_map = { - [ "\\" ] = "\\", - [ "\"" ] = "\"", - [ "\b" ] = "b", - [ "\f" ] = "f", - [ "\n" ] = "n", - [ "\r" ] = "r", - [ "\t" ] = "t", -} - -local escape_char_map_inv = { [ "/" ] = "/" } -for k, v in pairs(escape_char_map) do - escape_char_map_inv[v] = k -end - - -local function escape_char(c) - return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) -end - - -local function encode_nil(val) - return "null" -end - - -local function encode_table(val, stack) - local res = {} - stack = stack or {} - - -- Circular reference? - if stack[val] then error("circular reference") end - - stack[val] = true - - if rawget(val, 1) ~= nil or next(val) == nil then - -- Treat as array -- check keys are valid and it is not sparse - local n = 0 - for k in pairs(val) do - if type(k) ~= "number" then - error("invalid table: mixed or invalid key types") - end - n = n + 1 - end - if n ~= #val then - error("invalid table: sparse array") - end - -- Encode - for i, v in ipairs(val) do - table.insert(res, encode(v, stack)) - end - stack[val] = nil - return "[" .. table.concat(res, ",") .. "]" - - else - -- Treat as an object - for k, v in pairs(val) do - if type(k) ~= "string" then - error("invalid table: mixed or invalid key types") - end - table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) - end - stack[val] = nil - return "{" .. table.concat(res, ",") .. "}" - end -end - - -local function encode_string(val) - return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' -end - - -local function encode_number(val) - -- Check for NaN, -inf and inf - if val ~= val or val <= -math.huge or val >= math.huge then - error("unexpected number value '" .. tostring(val) .. "'") - end - return string.format("%.14g", val) -end - - -local type_func_map = { - [ "nil" ] = encode_nil, - [ "table" ] = encode_table, - [ "string" ] = encode_string, - [ "number" ] = encode_number, - [ "boolean" ] = tostring, -} - - -encode = function(val, stack) - local t = type(val) - local f = type_func_map[t] - if f then - return f(val, stack) - end - error("unexpected type '" .. t .. "'") -end - - -function json.encode(val) - return ( encode(val) ) -end - - -------------------------------------------------------------------------------- --- Decode -------------------------------------------------------------------------------- - -local parse - -local function create_set(...) - local res = {} - for i = 1, select("#", ...) do - res[ select(i, ...) ] = true - end - return res -end - -local space_chars = create_set(" ", "\t", "\r", "\n") -local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") -local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") -local literals = create_set("true", "false", "null") - -local literal_map = { - [ "true" ] = true, - [ "false" ] = false, - [ "null" ] = nil, -} - - -local function next_char(str, idx, set, negate) - for i = idx, #str do - if set[str:sub(i, i)] ~= negate then - return i - end - end - return #str + 1 -end - - -local function decode_error(str, idx, msg) - local line_count = 1 - local col_count = 1 - for i = 1, idx - 1 do - col_count = col_count + 1 - if str:sub(i, i) == "\n" then - line_count = line_count + 1 - col_count = 1 - end - end - error( string.format("%s at line %d col %d", msg, line_count, col_count) ) -end - - -local function codepoint_to_utf8(n) - -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa - local f = math.floor - if n <= 0x7f then - return string.char(n) - elseif n <= 0x7ff then - return string.char(f(n / 64) + 192, n % 64 + 128) - elseif n <= 0xffff then - return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) - elseif n <= 0x10ffff then - return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, - f(n % 4096 / 64) + 128, n % 64 + 128) - end - error( string.format("invalid unicode codepoint '%x'", n) ) -end - - -local function parse_unicode_escape(s) - local n1 = tonumber( s:sub(1, 4), 16 ) - local n2 = tonumber( s:sub(7, 10), 16 ) - -- Surrogate pair? - if n2 then - return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) - else - return codepoint_to_utf8(n1) - end -end - - -local function parse_string(str, i) - local res = "" - local j = i + 1 - local k = j - - while j <= #str do - local x = str:byte(j) - - if x < 32 then - decode_error(str, j, "control character in string") - - elseif x == 92 then -- `\`: Escape - res = res .. str:sub(k, j - 1) - j = j + 1 - local c = str:sub(j, j) - if c == "u" then - local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) - or str:match("^%x%x%x%x", j + 1) - or decode_error(str, j - 1, "invalid unicode escape in string") - res = res .. parse_unicode_escape(hex) - j = j + #hex - else - if not escape_chars[c] then - decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") - end - res = res .. escape_char_map_inv[c] - end - k = j + 1 - - elseif x == 34 then -- `"`: End of string - res = res .. str:sub(k, j - 1) - return res, j + 1 - end - - j = j + 1 - end - - decode_error(str, i, "expected closing quote for string") -end - - -local function parse_number(str, i) - local x = next_char(str, i, delim_chars) - local s = str:sub(i, x - 1) - local n = tonumber(s) - if not n then - decode_error(str, i, "invalid number '" .. s .. "'") - end - return n, x -end - - -local function parse_literal(str, i) - local x = next_char(str, i, delim_chars) - local word = str:sub(i, x - 1) - if not literals[word] then - decode_error(str, i, "invalid literal '" .. word .. "'") - end - return literal_map[word], x -end - - -local function parse_array(str, i) - local res = {} - local n = 1 - i = i + 1 - while 1 do - local x - i = next_char(str, i, space_chars, true) - -- Empty / end of array? - if str:sub(i, i) == "]" then - i = i + 1 - break - end - -- Read token - x, i = parse(str, i) - res[n] = x - n = n + 1 - -- Next token - i = next_char(str, i, space_chars, true) - local chr = str:sub(i, i) - i = i + 1 - if chr == "]" then break end - if chr ~= "," then decode_error(str, i, "expected ']' or ','") end - end - return res, i -end - - -local function parse_object(str, i) - local res = {} - i = i + 1 - while 1 do - local key, val - i = next_char(str, i, space_chars, true) - -- Empty / end of object? - if str:sub(i, i) == "}" then - i = i + 1 - break - end - -- Read key - if str:sub(i, i) ~= '"' then - decode_error(str, i, "expected string for key") - end - key, i = parse(str, i) - -- Read ':' delimiter - i = next_char(str, i, space_chars, true) - if str:sub(i, i) ~= ":" then - decode_error(str, i, "expected ':' after key") - end - i = next_char(str, i + 1, space_chars, true) - -- Read value - val, i = parse(str, i) - -- Set - res[key] = val - -- Next token - i = next_char(str, i, space_chars, true) - local chr = str:sub(i, i) - i = i + 1 - if chr == "}" then break end - if chr ~= "," then decode_error(str, i, "expected '}' or ','") end - end - return res, i -end - - -local char_func_map = { - [ '"' ] = parse_string, - [ "0" ] = parse_number, - [ "1" ] = parse_number, - [ "2" ] = parse_number, - [ "3" ] = parse_number, - [ "4" ] = parse_number, - [ "5" ] = parse_number, - [ "6" ] = parse_number, - [ "7" ] = parse_number, - [ "8" ] = parse_number, - [ "9" ] = parse_number, - [ "-" ] = parse_number, - [ "t" ] = parse_literal, - [ "f" ] = parse_literal, - [ "n" ] = parse_literal, - [ "[" ] = parse_array, - [ "{" ] = parse_object, -} - - -parse = function(str, idx) - local chr = str:sub(idx, idx) - local f = char_func_map[chr] - if f then - return f(str, idx) - end - decode_error(str, idx, "unexpected character '" .. chr .. "'") -end - - -function json.decode(str) - if type(str) ~= "string" then - error("expected argument of type string, got " .. type(str)) - end - local res, idx = parse(str, next_char(str, 1, space_chars, true)) - idx = next_char(str, idx, space_chars, true) - if idx <= #str then - decode_error(str, idx, "trailing garbage") - end - return res -end - - -return json diff --git a/main.lua b/main.lua index 2c7a695..c1674d6 100644 --- a/main.lua +++ b/main.lua @@ -1,7 +1,5 @@ -- Bootstrap appName = "lovr-playspace" -mainScriptPath = (debug.getinfo(1, "S").source:sub(2):match("(.*[/\\])") or "./"):sub(1,-2) -package.path = mainScriptPath.. "/lib/?.lua;" ..mainScriptPath.. "/lib/?/_main.lua;" ..package.path -- App hands = {"hand/right","hand/left"} @@ -24,48 +22,12 @@ limbs = { } configDirs = {} -json = require("json") - -function platformConfig() - if os.getenv("HOME") ~= nil then - return os.getenv("HOME") .. "/.config" - end - - return os.getenv("APPDATA") -end - -function fileExists(fileName) - local file = io.open(fileName,"rb") - if file == nil then return false end - file:close() - return true -end - -function getConfigFile(fileName) - for _,path in ipairs(configDirs) do - if fileExists(path .. "/" .. fileName) then - return path .. "/" .. fileName - end - end -end +json = require('json/json') function userConfig(fileName) return configDirs[1] .. "/" ..fileName end -function fileWrite(fileName,content) - local file = io.open(fileName,"wb") - file:write(content) - file:close() -end - -function readFile(fileName) - local file = io.open(fileName,"rb") - content = file:read("*all") - file:close() - return content -end - function getDistanceBetweenPoints3D(x1, y1, z1, x2, y2, z2) return math.sqrt((x2 - x1)^2 + (z2 - z1)^2) end @@ -184,54 +146,92 @@ function drawPointGrid(pass,points,cornerColor,miscColor) end function lovr.load() - lovr.graphics.setBackgroundColor(0.0, 0.0, 0.0, 0.0) - --table.insert(configDirs,platformConfig() .. "/" .. appName) - table.insert(configDirs,mainScriptPath .. "/config") - - settings = {} - settings.action_button = readFile(getConfigFile("action_button.txt")) - settings.check_density = tonumber(readFile(getConfigFile("check_density.txt"))) - settings.fade_start = tonumber(readFile(getConfigFile("fade_start.txt"))) - settings.fade_stop = tonumber(readFile(getConfigFile("fade_stop.txt"))) - settings.grid_density = tonumber(readFile(getConfigFile("grid_density.txt"))) - settings.grid_bottom = tonumber(readFile(getConfigFile("grid_bottom.txt"))) - settings.grid_top = tonumber(readFile(getConfigFile("grid_top.txt"))) - settings.color_close_corners = json.decode(readFile(getConfigFile("color_close_corners.json"))) - settings.color_close_grid = json.decode(readFile(getConfigFile("color_close_grid.json"))) - settings.color_far_corners = json.decode(readFile(getConfigFile("color_far_corners.json"))) - settings.color_far_grid = json.decode(readFile(getConfigFile("color_far_grid.json"))) - settings.points = {} - - --[[if not lovr.filesystem.isDirectory(configDirs[1]) then - fileWrite(userConfig("action_button.txt"),readFile(getConfigFile("action_button.txt"))) - fileWrite(userConfig("check_density.txt"),readFile(getConfigFile("check_density.txt"))) - fileWrite(userConfig("fade_start.txt"),readFile(getConfigFile("fade_start.txt"))) - fileWrite(userConfig("fade_stop.txt"),readFile(getConfigFile("fade_stop.txt"))) - fileWrite(userConfig("grid_density.txt"),readFile(getConfigFile("grid_density.txt"))) - fileWrite(userConfig("grid_bottom.txt"),readFile(getConfigFile("grid_bottom.txt"))) - fileWrite(userConfig("grid_top.txt"),readFile(getConfigFile("grid_top.txt"))) - fileWrite(userConfig("color_close_corners.json"),readFile(getConfigFile("color_close_corners.json"))) - fileWrite(userConfig("color_close_grid.json"),readFile(getConfigFile("color_close_grid.json"))) - fileWrite(userConfig("color_far_corners.json"),readFile(getConfigFile("color_far_corners.json"))) - fileWrite(userConfig("color_far_grid.json"),readFile(getConfigFile("color_far_grid.json"))) - initConfigure() - return - end]]-- - - if getConfigFile("points.json") == nil then - initConfigure() - return - end - - for _,hand in ipairs(hands) do - if lovr.headset.isDown(hand,settings.action_button) then - initConfigure() - return + lovr.graphics.setBackgroundColor(0.0, 0.0, 0.0, 0.0) + + -- Default settings + local defaults = { + action_button = "trigger", + check_density = 0.05, + fade_start = 0.5, + fade_stop = 2.0, + grid_density = 1.0, + grid_bottom = 0.0, + grid_top = 3, + color_close_corners = {0.45, 0.69, 0.79, 1.0}, + color_close_grid = {0.45, 0.69, 0.79, 0.5}, + color_far_corners = {0.45, 0.69, 0.79, 0}, + color_far_grid = {0.45, 0.69, 0.79, 0}, + points = {} + } + + -- Helper function to read file with fallback to default + local function loadSetting(filename, default, parser) + print("Checking file:", filename) + + if not lovr.filesystem.isFile(filename) then + print("File doesn't exist, creating:", filename) + local valueToSave + if type(default) == "table" then + valueToSave = json.encode(default) + else + valueToSave = tostring(default) + end + + local success = lovr.filesystem.write(filename, valueToSave) + print("Write success:", success, "for", filename, "with value:", valueToSave) + return default end + + -- File exists, try to read it + local content = lovr.filesystem.read(filename) + if content and parser then + local success, value = pcall(parser, content) + if success then return value end + elseif content then + return content + end + + return default end - - settings.points = json.decode(readFile(getConfigFile("points.json"))) - mode = modeDraw + + -- Initialize settings with fallbacks + settings = { + action_button = loadSetting("action_button.txt", defaults.action_button), + check_density = loadSetting("check_density.txt", defaults.check_density, tonumber), + fade_start = loadSetting("fade_start.txt", defaults.fade_start, tonumber), + fade_stop = loadSetting("fade_stop.txt", defaults.fade_stop, tonumber), + grid_density = loadSetting("grid_density.txt", defaults.grid_density, tonumber), + grid_bottom = loadSetting("grid_bottom.txt", defaults.grid_bottom, tonumber), + grid_top = loadSetting("grid_top.txt", defaults.grid_top, tonumber), + color_close_corners = loadSetting("color_close_corners.json", defaults.color_close_corners, json.decode), + color_close_grid = loadSetting("color_close_grid.json", defaults.color_close_grid, json.decode), + color_far_corners = loadSetting("color_far_corners.json", defaults.color_far_corners, json.decode), + color_far_grid = loadSetting("color_far_grid.json", defaults.color_far_grid, json.decode), + points = {} + } + + -- Handle points.json + local pointsPath = "points.json" + if not lovr.filesystem.isFile(pointsPath) then + initConfigure() + return + end + + -- Check for action button press + for _, hand in ipairs(hands) do + if lovr.headset.isDown(hand, settings.action_button) then + initConfigure() + return + end + end + + -- Load points if we haven't returned already + local pointsContent = lovr.filesystem.read(pointsPath) + if pointsContent then + settings.points = json.decode(pointsContent) + end + + mode = modeDraw end function initConfigure() @@ -290,7 +290,7 @@ function modeConfigure(pass) if inputDev ~= nil then saveProg = saveProg - (deltaTime / 3) if saveProg <= 0 then - fileWrite(userConfig("points.json"),json.encode(settings.points)) + lovr.filesystem.write("config/points.json", json.encode(settings.points)) deinitConfigure() modeDraw(pass) return From a1c77f74a5536072039394eec3db8ff1fe59fd16 Mon Sep 17 00:00:00 2001 From: BabbleBones Date: Thu, 13 Feb 2025 14:40:56 -0500 Subject: [PATCH 08/10] Overlay atop wlx background --- conf.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/conf.lua b/conf.lua index 96e3bcf..3cef231 100644 --- a/conf.lua +++ b/conf.lua @@ -1,6 +1,5 @@ function lovr.conf(t) - t.headset.overlay = 2 - t.headset.overlayOrder = 2 + t.headset.overlay = 6 t.window = false t.identity = "lovr-playspace" end From cd3b21d12933a227a7969a8dd4150ad166709bcf Mon Sep 17 00:00:00 2001 From: BabbleBones Date: Thu, 13 Feb 2025 15:31:25 -0500 Subject: [PATCH 09/10] Build system --- .gitignore | 8 ++++++++ build.sh | 13 +++++++++++++ lovr-playspace.sh | 3 +++ main.lua | 2 +- 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100755 build.sh create mode 100755 lovr-playspace.sh diff --git a/.gitignore b/.gitignore index d796c95..9c08823 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,10 @@ config/points.json + +lovr-x86_64.AppImage + +playspace.lovr + +build/ + +*.gz diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..cf75249 --- /dev/null +++ b/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +if [ ! -f "$(dirname "$0")/lovr-x86_64.AppImage" ]; then + echo "Error: lovr-x86_64.AppImage not found!" + echo "Please download a LÖVR AppImage from https://github.com/bjornbytes/lovr/actions and save it as lovr-x86_64.AppImage in this repository" + exit 1 +fi + +rm -f playspace.lovr && zip -9qr playspace.lovr json/json.lua conf.lua main.lua + +rm -rf build && mkdir build && cp playspace.lovr lovr-playspace.sh lovr-x86_64.AppImage build/ + +tar -czf "lovr-playspace-$(git describe --tags --abbrev=0).tar.gz" -C build/ . diff --git a/lovr-playspace.sh b/lovr-playspace.sh new file mode 100755 index 0000000..08fbb75 --- /dev/null +++ b/lovr-playspace.sh @@ -0,0 +1,3 @@ +#!/bin/bash +dir="$(dirname "$(readlink -f "$0")")" +"$dir/lovr-x86_64.AppImage" "$dir/playspace.lovr" diff --git a/main.lua b/main.lua index c1674d6..d3139cb 100644 --- a/main.lua +++ b/main.lua @@ -290,7 +290,7 @@ function modeConfigure(pass) if inputDev ~= nil then saveProg = saveProg - (deltaTime / 3) if saveProg <= 0 then - lovr.filesystem.write("config/points.json", json.encode(settings.points)) + lovr.filesystem.write("points.json", json.encode(settings.points)) deinitConfigure() modeDraw(pass) return From 012271df5195c09c73d6c13797dd2d93642abbff Mon Sep 17 00:00:00 2001 From: uvos Date: Sun, 23 Mar 2025 00:12:12 +0100 Subject: [PATCH 10/10] Track Playspace relative to the presitant floor coordinate system --- main.lua | 64 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/main.lua b/main.lua index d3139cb..dab0559 100644 --- a/main.lua +++ b/main.lua @@ -32,6 +32,11 @@ function getDistanceBetweenPoints3D(x1, y1, z1, x2, y2, z2) return math.sqrt((x2 - x1)^2 + (z2 - z1)^2) end +function getFloorMatrix() + local fx, fy, fz, fangle, fax, fay, faz = lovr.headset.getPose("floor") + return lovr.math.newMat4(lovr.math.vec3(fx, fy, fz), lovr.math.vec3(1, 1, 1), lovr.math.quat(fangle, fax, fay, faz)) +end + function getLineDistance(x, _, z, point1, point2) -- Notice the underscore for y -- Vector from point1 to point2 local dx = point2[1] - point1[1] @@ -67,8 +72,6 @@ function getLineDistance(x, _, z, point1, point2) -- Notice the underscore for return math.sqrt(dx_ * dx_ + dz_ * dz_) end - - function getClosestDistanceToPerimeter(x, y, z, points) local lowestDist = 9999 local length = #points @@ -89,12 +92,6 @@ function getButton(method,button,devices) end end -function isTracked(device) - local x,y,z = lovr.headset.getPosition(device) - if x == 0.0 and y == 0.0 and z == 0.0 then return false end - return true -end - function drawSinglePointGrid(pass, point1, point2, cornerColor, miscColor) local _, hy, _ = lovr.headset.getPosition("head") local lx1 = point1[1] @@ -145,8 +142,15 @@ function drawPointGrid(pass,points,cornerColor,miscColor) drawSinglePointGrid(pass,points[length],points[1],cornerColor,miscColor) end +function printTable(table) + for _,point in ipairs(table) do + print(point[1], " ", point[2]) + end +end + function lovr.load() lovr.graphics.setBackgroundColor(0.0, 0.0, 0.0, 0.0) + print("Is tracked floor:", lovr.headset.isTracked('floor')) -- Default settings local defaults = { @@ -207,7 +211,8 @@ function lovr.load() color_close_grid = loadSetting("color_close_grid.json", defaults.color_close_grid, json.decode), color_far_corners = loadSetting("color_far_corners.json", defaults.color_far_corners, json.decode), color_far_grid = loadSetting("color_far_grid.json", defaults.color_far_grid, json.decode), - points = {} + points = {}, + transformed = false } -- Handle points.json @@ -229,6 +234,8 @@ function lovr.load() local pointsContent = lovr.filesystem.read(pointsPath) if pointsContent then settings.points = json.decode(pointsContent) + print("FloorSpace:") + printTable(settings.points) end mode = modeDraw @@ -253,10 +260,14 @@ end function modeConfigure(pass) local hx, hy, hz = lovr.headset.getPosition("head") + floorMatrixInv = getFloorMatrix():invert() for _, hand in ipairs(hands) do - if isTracked(hand) then + if lovr.headset.isTracked(hand) then local cx, cy, cz = lovr.headset.getPosition(hand) + local floorSpaceControlerVector = lovr.math.vec3(cx, cy, cz):transform(floorMatrixInv) + local fcx, fcy, fcz = floorSpaceControlerVector:unpack() + -- Compute the direction from the controller to the headset local dirX = hx - cx @@ -274,23 +285,29 @@ function modeConfigure(pass) pass:text( "- Press '" .. settings.action_button .. "' to add a point -\n" .. "- Hold '" .. settings.action_button .. "' to save -\n\n" .. - string.format("%.2f", cx) .. "," .. string.format("%.2f", cy) .. "," .. string.format("%.2f", cz), + string.format("%.2f", fcx) .. "," .. string.format("%.2f", fcy) .. "," .. string.format("%.2f", fcz), cx, cy - 0.3, cz, 0.066, angle, 0, 1, 0 ) end end local inputDev = getButton(lovr.headset.wasReleased,settings.action_button,hands) - if inputDev ~= nil and isTracked(inputDev) then - local hx,_,hz = lovr.headset.getPosition(inputDev) - table.insert(settings.points,{hx,hz}) + if inputDev ~= nil and lovr.headset.isTracked(inputDev) then + local cx, _, cz = lovr.headset.getPosition(inputDev) + table.insert(settings.points,{cx,cz}) end inputDev = getButton(lovr.headset.isDown,settings.action_button,hands) if inputDev ~= nil then saveProg = saveProg - (deltaTime / 3) if saveProg <= 0 then - lovr.filesystem.write("points.json", json.encode(settings.points)) + local floorSpacePoints = {} + for _,point in ipairs(settings.points) do + local floorSpacePoint = lovr.math.vec3(point[1], 0, point[2]):transform(floorMatrixInv) + local x, _, z = floorSpacePoint:unpack() + table.insert(floorSpacePoints,{x,z}) + end + lovr.filesystem.write("points.json", json.encode(floorSpacePoints)) deinitConfigure() modeDraw(pass) return @@ -310,13 +327,28 @@ end function modeDraw(pass) local hx, hy, hz = lovr.headset.getPosition("head") + if not settings.transformed and lovr.headset.isTracked("floor") then + local floorMatrix = getFloorMatrix() + print("floorMatrix: ", floorMatrix) + transformedPoints = {} + for _,point in ipairs(settings.points) do + local point = lovr.math.vec3(point[1], 0, point[2]):transform(floorMatrix) + local x, _, z = point:unpack() + table.insert(transformedPoints, {x, z}) + end + settings.points = transformedPoints + print("HeadSpace:") + printTable(settings.points) + settings.transformed = true + end + -- Calculate the distance from the head to the perimeter local perimeterDistHead = getClosestDistanceToPerimeter(hx, hy, hz, settings.points) -- Check distance from each hand to the perimeter local handDistances = {perimeterDistHead} for _, hand in ipairs(hands) do - if isTracked(hand) then + if lovr.headset.isTracked(hand) then local handX, handY, handZ = lovr.headset.getPosition(hand) local dist = getClosestDistanceToPerimeter(handX, handY, handZ, settings.points) table.insert(handDistances, dist)