-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathhand.lua
134 lines (122 loc) · 4.21 KB
/
hand.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
local Hand = {
device = "hand/left"
}
setmetatable(Hand, {__index=letters.Node})
local Hand_mt = {
__index = Hand
}
function Hand:new(o)
o = letters.Node.new(self, o)
setmetatable(o, Hand_mt)
o.model = letters.headset.newModel and letters.headset.newModel(o.device)
o.from = lovr.math.newVec3()
o.to = lovr.math.newVec3()
o.highlightedNodes = {}
o.selectedNode = nil
o.grabbedNode = nil
return o
end
function Hand:draw()
if not letters.headset.isTracked(self.device) then return end
if self.model then
self.model:draw(mat4(letters.headset.getPose(self.device)))
else
lovr.graphics.setColor(0.5, 0.7, 0.5)
lovr.graphics.box('fill', self.from, .03, .04, .06, letters.headset.getOrientation(self.device))
end
if self.from and self.to then
lovr.graphics.line(self.from, self.to)
end
end
function Hand:update()
local handPos = lovr.math.vec3(letters.headset.getPosition(self.device))
if handPos.x ~= handPos.x then
return
end
local straightAhead = lovr.math.vec3(0, 0, -1)
local handRotation = lovr.math.mat4():rotate(letters.headset.getOrientation(self.device))
local pointedDirection = handRotation:mul(straightAhead)
local distantPoint = lovr.math.newVec3(pointedDirection):mul(10):add(handPos)
self.from:set(handPos)
self.to:set(distantPoint)
local newlyHighlightedNodes = {}
letters.world:raycast(self.from.x, self.from.y, self.from.z, self.to.x, self.to.y, self.to.z, function(shape, hx, hy, hz)
local newPoint = lovr.math.newVec3(hx, hy, hz)
table.insert(newlyHighlightedNodes, {
distance= (newPoint - self.from):length(),
node = shape:getCollider():getUserData()
})
end)
table.sort(newlyHighlightedNodes, function(x, y) return x.distance < y.distance end)
-- only highlight the nearest node
while #newlyHighlightedNodes > 1 do
table.remove(newlyHighlightedNodes, 2)
end
-- unhighlight no longer highlighted nodes
for _, oldNode in ipairs(self.highlightedNodes) do
local existed = false
for _, newNode in ipairs(newlyHighlightedNodes) do
if newNode.node == oldNode.node then existed = true end
end
if existed == false then
if oldNode.node.dehighlight then
oldNode.node:dehighlight()
end
end
end
-- highlight fresly highlighted nodes
for _, newNode in ipairs(newlyHighlightedNodes) do
local existed = false
for _, oldNode in ipairs(self.highlightedNodes) do
if newNode.node == oldNode.node then existed = true end
end
if existed == false then
if newNode.node.highlight then
newNode.node:highlight(self)
end
end
end
self.highlightedNodes = newlyHighlightedNodes
-- select items with trigger
if letters.headset.isDown(self.device, "trigger") and self.selectedNode == nil then
for _, node in ipairs(self.highlightedNodes) do
if node.node.select then
node.node:select(self)
self.selectedNode = node.node
letters.headset.vibrate(self.device, 0.6, 0.02, 100)
break
end
end
end
-- deselect items on released trigger, actuating on buttons and other clickables
if not letters.headset.isDown(self.device, "trigger") and self.selectedNode ~= nil then
local found = false
for _, node in ipairs(self.highlightedNodes) do
if node.node == self.selectedNode then found = true end
end
if found then
if self.selectedNode.actuate then
letters.headset.vibrate(self.device, 0.7, 0.03, 400)
self.selectedNode:actuate(self)
end
end
if self.selectedNode.deselect then self.selectedNode:deselect(self) end
self.selectedNode = nil
end
-- grab items with grip
if letters.headset.isDown(self.device, "grip") and self.grabbedNode == nil then
for _, node in ipairs(self.highlightedNodes) do
if node.node.grab and node.node:grab(self) then
self.grabbedNode = node.node
letters.headset.vibrate(self.device, 0.6, 0.02, 100)
break
end
end
end
-- deselect items on released trigger, actuating on buttons and other clickables
if not letters.headset.isDown(self.device, "grip") and self.grabbedNode ~= nil then
if self.grabbedNode.ungrab then self.grabbedNode:ungrab(self) end
self.grabbedNode = nil
end
end
return Hand