diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 9c08823..0000000 --- a/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ - -config/points.json - -lovr-x86_64.AppImage - -playspace.lovr - -build/ - -*.gz diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 50926d4..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "json.lua"] - path = json - url = https://github.com/rxi/json.lua diff --git a/README.md b/README.md index 94758cb..01ba9b6 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://github.com/SpookySkeletons/lovr-playspace" +git clone "https://git.lumen.sh/Fierelier/lovr-playspace" ./lovr-*.AppImage lovr-playspace ``` @@ -18,7 +18,8 @@ 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.17.0/DeviceButton). +- `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. - `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. diff --git a/build.sh b/build.sh deleted file mode 100755 index cf75249..0000000 --- a/build.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/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/conf.lua b/conf.lua index 3cef231..7184caa 100644 --- a/conf.lua +++ b/conf.lua @@ -1,5 +1,4 @@ function lovr.conf(t) - t.headset.overlay = 6 + t.headset.overlay = 2 t.window = false - t.identity = "lovr-playspace" end diff --git a/config/action_button.txt b/config/action_button.txt new file mode 100644 index 0000000..b28fbc7 --- /dev/null +++ b/config/action_button.txt @@ -0,0 +1 @@ +trigger \ No newline at end of file diff --git a/config/check_density.txt b/config/check_density.txt new file mode 100644 index 0000000..30e2fb4 --- /dev/null +++ b/config/check_density.txt @@ -0,0 +1 @@ +0.05 \ No newline at end of file diff --git a/config/color_close_corners.json b/config/color_close_corners.json new file mode 100644 index 0000000..3054842 --- /dev/null +++ b/config/color_close_corners.json @@ -0,0 +1 @@ +[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 new file mode 100644 index 0000000..f95ef1b --- /dev/null +++ b/config/color_close_grid.json @@ -0,0 +1 @@ +[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 new file mode 100644 index 0000000..42e7855 --- /dev/null +++ b/config/color_far_corners.json @@ -0,0 +1 @@ +[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 new file mode 100644 index 0000000..42e7855 --- /dev/null +++ b/config/color_far_grid.json @@ -0,0 +1 @@ +[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 new file mode 100644 index 0000000..ea2303b --- /dev/null +++ b/config/fade_start.txt @@ -0,0 +1 @@ +0.5 \ No newline at end of file diff --git a/config/fade_stop.txt b/config/fade_stop.txt new file mode 100644 index 0000000..415b19f --- /dev/null +++ b/config/fade_stop.txt @@ -0,0 +1 @@ +2.0 \ No newline at end of file diff --git a/config/grid_bottom.txt b/config/grid_bottom.txt new file mode 100644 index 0000000..171538e --- /dev/null +++ b/config/grid_bottom.txt @@ -0,0 +1 @@ +0.0 \ No newline at end of file diff --git a/config/grid_density.txt b/config/grid_density.txt new file mode 100644 index 0000000..9f8e9b6 --- /dev/null +++ b/config/grid_density.txt @@ -0,0 +1 @@ +1.0 \ No newline at end of file diff --git a/config/grid_top.txt b/config/grid_top.txt new file mode 100644 index 0000000..e440e5c --- /dev/null +++ b/config/grid_top.txt @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/json b/json deleted file mode 160000 index dbf4b2d..0000000 --- a/json +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dbf4b2dd2eb7c23be2773c89eb059dadd6436f94 diff --git a/lib/json.lua b/lib/json.lua new file mode 100644 index 0000000..711ef78 --- /dev/null +++ b/lib/json.lua @@ -0,0 +1,388 @@ +-- +-- 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/lovr-playspace.sh b/lovr-playspace.sh deleted file mode 100755 index 08fbb75..0000000 --- a/lovr-playspace.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -dir="$(dirname "$(readlink -f "$0")")" -"$dir/lovr-x86_64.AppImage" "$dir/playspace.lovr" diff --git a/main.lua b/main.lua index dab0559..fd4949a 100644 --- a/main.lua +++ b/main.lua @@ -1,5 +1,7 @@ -- 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"} @@ -7,8 +9,8 @@ limbs = { "head", "hand/left", "hand/right", - "hand/left/grip", - "hand/right/grip", + "hand/left/point", + "hand/right/point", "elbow/left", "elbow/right", "shoulder/left", @@ -22,19 +24,50 @@ limbs = { } configDirs = {} -json = require('json/json') +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 function userConfig(fileName) return configDirs[1] .. "/" ..fileName end -function getDistanceBetweenPoints3D(x1, y1, z1, x2, y2, z2) - return math.sqrt((x2 - x1)^2 + (z2 - z1)^2) +function fileWrite(fileName,content) + local file = io.open(fileName,"wb") + file:write(content) + file:close() 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)) +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 function getLineDistance(x, _, z, point1, point2) -- Notice the underscore for y @@ -72,6 +105,8 @@ 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 @@ -92,6 +127,12 @@ 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] @@ -142,103 +183,55 @@ 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 = { - 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 + 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 - - -- 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 = {}, - transformed = false - } - - -- 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) - print("FloorSpace:") - printTable(settings.points) - end - - mode = modeDraw + + for _,hand in ipairs(hands) do + if lovr.headset.isDown(hand,settings.action_button) then + initConfigure() + return + end + end + + settings.points = json.decode(readFile(getConfigFile("points.json"))) + mode = modeDraw end function initConfigure() @@ -260,14 +253,10 @@ end function modeConfigure(pass) local hx, hy, hz = lovr.headset.getPosition("head") - floorMatrixInv = getFloorMatrix():invert() for _, hand in ipairs(hands) do - 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() - + if isTracked(hand .. "/point") then + local cx, cy, cz = lovr.headset.getPosition(hand .. "/point") -- Compute the direction from the controller to the headset local dirX = hx - cx @@ -285,29 +274,23 @@ 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", fcx) .. "," .. string.format("%.2f", fcy) .. "," .. string.format("%.2f", fcz), + string.format("%.2f", cx) .. "," .. string.format("%.2f", cy) .. "," .. string.format("%.2f", cz), 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 lovr.headset.isTracked(inputDev) then - local cx, _, cz = lovr.headset.getPosition(inputDev) - table.insert(settings.points,{cx,cz}) + if inputDev ~= nil and isTracked(inputDev) then + local hx,_,hz = lovr.headset.getPosition(inputDev) + table.insert(settings.points,{hx,hz}) end inputDev = getButton(lovr.headset.isDown,settings.action_button,hands) if inputDev ~= nil then saveProg = saveProg - (deltaTime / 3) if saveProg <= 0 then - 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)) + fileWrite(userConfig("points.json"),json.encode(settings.points)) deinitConfigure() modeDraw(pass) return @@ -327,28 +310,13 @@ 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 lovr.headset.isTracked(hand) then + if isTracked(hand) then local handX, handY, handZ = lovr.headset.getPosition(hand) local dist = getClosestDistanceToPerimeter(handX, handY, handZ, settings.points) table.insert(handDistances, dist) @@ -379,4 +347,4 @@ end function lovr.draw(pass) mode(pass) -end +end \ No newline at end of file