mirror of https://github.com/teverse/teverse
Compare commits
2 Commits
d7b768e5fa
...
38920adfa2
Author | SHA1 | Date |
---|---|---|
Jay | 38920adfa2 | |
Jay | 567839d691 |
|
@ -7,6 +7,27 @@ local function round(n, mult)
|
|||
return math.floor((n + mult/2)/mult) * mult
|
||||
end
|
||||
|
||||
local function calculateVertices (block)
|
||||
local vertices = {}
|
||||
for x = -1,1,2 do
|
||||
for y = -1,1,2 do
|
||||
for z = -1,1,2 do
|
||||
table.insert(vertices, block.position + block.rotation* (vector3(x,y,z) *block.size/2))
|
||||
end
|
||||
end
|
||||
end
|
||||
return vertices
|
||||
end
|
||||
|
||||
local faces = {
|
||||
{5, 6, 8, 7}, -- x forward,
|
||||
{1, 2, 4, 3}, -- x backward,
|
||||
{7, 8, 4, 3}, -- y upward,
|
||||
{5, 6, 2, 1}, -- y downward,
|
||||
{6, 2, 4, 8}, -- z forward
|
||||
{5, 1, 3, 7} -- z backward
|
||||
}
|
||||
|
||||
return {
|
||||
-- Storing workshop is important because sandbox access is restricted.
|
||||
workshop = nil,
|
||||
|
@ -17,6 +38,32 @@ return {
|
|||
roundVector3 = function(v, mult)
|
||||
return vector3(round(v.x, mult), round(v.y, mult), round(v.z, mult))
|
||||
end,
|
||||
roundDp = function (num, numDecimalPlaces)
|
||||
local mult = 10^(numDecimalPlaces or 0)
|
||||
return math.floor(num * mult + 0.5) / mult
|
||||
end,
|
||||
|
||||
calculateVertices = calculateVertices,
|
||||
|
||||
getCentreOfFace = function (block, face)
|
||||
local vertices = calculateVertices(block)
|
||||
local avg = vector3(0,0,0)
|
||||
for _,i in pairs(faces[face]) do
|
||||
avg = avg + vertices[i]
|
||||
end
|
||||
|
||||
return avg/4
|
||||
end,
|
||||
|
||||
--[[guiLine = function(a, b, parent)
|
||||
local avg = (a + b) / 2
|
||||
local size = a - b
|
||||
local length = size:length()
|
||||
return engine.construct("guiFrame", parent, {
|
||||
position = guiCoord(0, avg.x, 0, avg.y),
|
||||
size = guiCoord(0, 2, 0, length)
|
||||
})
|
||||
end,]]
|
||||
|
||||
-- this is set when workshop is set
|
||||
-- using the haslocaltevgit api
|
||||
|
|
|
@ -6,5 +6,5 @@ return {
|
|||
handTool = require("tevgit:workshop/controllers/sidetools/hand.lua"),
|
||||
moveTool = require("tevgit:workshop/controllers/sidetools/move.lua"),
|
||||
scaleTool = require("tevgit:workshop/controllers/sidetools/scale.lua"),
|
||||
--rotateTool = require("tevgit:workshop/controllers/sidetools/rotate.lua"),
|
||||
rotateTool = require("tevgit:workshop/controllers/sidetools/rotate.lua"),
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ local function updateHandles()
|
|||
for _,v in pairs(handles) do
|
||||
v[1].size = vector3(0,0,0)
|
||||
v[1].opacity = 0
|
||||
v[1].line.positionA = vector3(0, 0, 0)
|
||||
v[1].line.positionB = vector3(0, 0, 0)
|
||||
end
|
||||
else
|
||||
for _,v in pairs(handles) do
|
||||
|
@ -30,6 +32,8 @@ local function updateHandles()
|
|||
v[1].rotation = v[1].rotation * quaternion():setEuler(math.rad(90), 0, 0)
|
||||
v[1].size = vector3(0.2, 0.4, 0.2)
|
||||
v[1].opacity = 1
|
||||
v[1].line.positionA = v[1].position
|
||||
v[1].line.positionB = selection.box.position
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -118,6 +122,8 @@ return {
|
|||
mesh = "primitive:cone"
|
||||
})
|
||||
|
||||
engine.construct("line", handle, {name = "line", colour = handle.colour})
|
||||
|
||||
handle:mouseLeftPressed(function()
|
||||
gridGuideline.size = vector3(300, 0.1, 300)
|
||||
|
||||
|
@ -130,6 +136,8 @@ return {
|
|||
|
||||
local last = nil
|
||||
|
||||
history.beginAction(selection.selection, "Move tool drag")
|
||||
|
||||
while engine.input:isMouseButtonDown(enums.mouseButton.left) do
|
||||
-- Position and rotate the invisible guideline to face the camera.
|
||||
-- We use this guideline to raycast with
|
||||
|
@ -190,6 +198,8 @@ return {
|
|||
wait()
|
||||
end
|
||||
|
||||
history.endAction()
|
||||
|
||||
gridVisual:destroy()
|
||||
gridGuideline.size = vector3(0, 0, 0)
|
||||
end)
|
||||
|
|
|
@ -5,16 +5,207 @@ local toolName = "Rotate"
|
|||
local toolDesc = ""
|
||||
local toolIcon = "fa:s-redo"
|
||||
|
||||
local selection = require("tevgit:workshop/controllers/core/selection.lua")
|
||||
local history = require("tevgit:workshop/controllers/core/history.lua")
|
||||
local ui = require("tevgit:workshop/controllers/ui/core/ui.lua")
|
||||
local shared = require("tevgit:workshop/controllers/shared.lua")
|
||||
|
||||
local sensitivity = 50
|
||||
|
||||
local arrows = {
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
}
|
||||
|
||||
-- Each axis gets four arrows...
|
||||
-- This table maps each arrow index to an vertice index
|
||||
local arrowsVerticesMap = {
|
||||
{6, 4, 2, 1}, --x
|
||||
{2, 1, 7, 6}, --y
|
||||
{5, 7, 3, 1} --z
|
||||
}
|
||||
|
||||
local function positionArrows()
|
||||
if selection.box.size == vector3(0,0,0) then
|
||||
for _,v in pairs(arrows) do
|
||||
for i,arrow in pairs(v) do
|
||||
arrow.physics = false
|
||||
arrow.opacity = 0
|
||||
end
|
||||
end
|
||||
else
|
||||
local vertices = shared.calculateVertices(selection.box)
|
||||
|
||||
for a,v in pairs(arrows) do
|
||||
for i,arrow in pairs(v) do
|
||||
if i == 2 then i = 3 end
|
||||
arrow.physics = true
|
||||
arrow.opacity = 1
|
||||
arrow.position = vertices[arrowsVerticesMap[a][i]]
|
||||
if a == 1 then
|
||||
arrow.rotation = quaternion:setEuler(math.rad((i)*90), 0, math.rad(-90))
|
||||
elseif a == 2 then
|
||||
arrow.rotation = quaternion:setEuler(0, math.rad((i-1)*-90), 0)
|
||||
else
|
||||
arrow.rotation = quaternion:setEuler(math.rad((i-1)*-90), math.rad(90), math.rad(90))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local boundingEvent
|
||||
|
||||
-- calculates angle ABC
|
||||
-- returns in radians
|
||||
local function calculateAngleBetween3Points(a, b, c)
|
||||
local v1 = a - b
|
||||
local v2 = c - b
|
||||
return math.acos(v1:normal():dot(v2:normal()))
|
||||
end
|
||||
|
||||
local function calculateCircleAngle(hitbox, pos)
|
||||
local hitboxPosition = hitbox.position
|
||||
local hitboxRotation = hitbox.rotation
|
||||
|
||||
local hitboxUp = hitboxPosition + (hitboxRotation * vector3(0,0,-10))
|
||||
local hitboxRight = hitboxPosition + (hitboxRotation * vector3(10,0,0))
|
||||
|
||||
local angle = calculateAngleBetween3Points(hitboxUp, hitboxPosition, pos)
|
||||
if hitboxRight:dot(pos) < 0 then
|
||||
angle = (math.pi-angle)+math.pi
|
||||
end
|
||||
|
||||
return angle
|
||||
end
|
||||
|
||||
return {
|
||||
name = toolName,
|
||||
icon = toolIcon,
|
||||
desc = toolDesc,
|
||||
|
||||
activate = function()
|
||||
print("tool activated")
|
||||
for axis = 1, 3 do
|
||||
local newArrow = engine.construct("block", engine.workspace, {
|
||||
name = "_CreateMode_",
|
||||
castsShadows = false,
|
||||
opacity = 0,
|
||||
renderQueue=1,
|
||||
doNotSerialise=true,
|
||||
size = vector3(.4, 0.1, .4),
|
||||
colour = colour(axis == 1 and 1 or 0, axis == 2 and 1 or 0, axis == 3 and 1 or 0),
|
||||
emissiveColour = colour(axis == 1 and 0.5 or 0, axis == 2 and 0.5 or 0, axis == 3 and 0.5 or 0),
|
||||
workshopLocked = true,
|
||||
mesh = "tevurl:3d/arrowCurved.glb"
|
||||
})
|
||||
|
||||
newArrow:mouseLeftPressed(function ()
|
||||
local hitbox = engine.construct("block", workspace, {
|
||||
name = "_CreateMode_",
|
||||
castsShadows = false,
|
||||
opacity = 0,
|
||||
renderQueue = 1,
|
||||
doNotSerialise=true,
|
||||
size = vector3(60, 0.1, 60),
|
||||
workshopLocked = true,
|
||||
position = shared.getCentreOfFace(selection.box, (axis*2)-1),
|
||||
rotation = newArrow.rotation
|
||||
})
|
||||
hitbox.rotation = hitbox.rotation:setLookRotation( hitbox.position - workspace.camera.position ) * quaternion():setEuler(math.rad(90),0,0)
|
||||
--hitbox:lookAt(workspace.camera.position)
|
||||
|
||||
local mouseHits = engine.physics:rayTestScreenAllHits( engine.input.mousePosition )
|
||||
local mouseHit = nil
|
||||
for _,hit in pairs(mouseHits) do
|
||||
if hit.object == hitbox then
|
||||
mouseHit = hit
|
||||
goto skip_loop
|
||||
end
|
||||
end
|
||||
::skip_loop::
|
||||
|
||||
if not mouseHit then
|
||||
print("Did not collide")
|
||||
hitbox:destroy()
|
||||
return nil
|
||||
end
|
||||
|
||||
local start = mouseHit.hitPosition
|
||||
history.beginAction(selection.selection, "Rotate tool drag")
|
||||
|
||||
while engine.input:isMouseButtonDown(enums.mouseButton.left) and wait() do
|
||||
hitbox.rotation = hitbox.rotation:setLookRotation( hitbox.position - workspace.camera.position ) * quaternion():setEuler(math.rad(90),0,0)
|
||||
|
||||
local mouseHits = engine.physics:rayTestScreenAllHits( engine.input.mousePosition )
|
||||
local mouseHit = nil
|
||||
for _,hit in pairs(mouseHits) do
|
||||
if hit.object == hitbox then
|
||||
mouseHit = hit
|
||||
goto skip_loop
|
||||
end
|
||||
end
|
||||
::skip_loop::
|
||||
|
||||
if mouseHit then
|
||||
local current = mouseHit.hitPosition
|
||||
local diff = (start-current)
|
||||
local travelled = diff:length()
|
||||
|
||||
-- length of vectors is never less than 0. let's fix that
|
||||
if (newArrow.rotation * vector3(0,0,1)):dot(diff) < 0 then
|
||||
--user moved their mouse in an opposite direction to the arrow
|
||||
travelled = -travelled
|
||||
end
|
||||
|
||||
local n = shared.round(math.rad(travelled*sensitivity), math.rad(10))
|
||||
|
||||
for _,v in pairs(selection.selection) do
|
||||
local euler = vector3(
|
||||
axis == 1 and n or 0,
|
||||
axis == 2 and n or 0,
|
||||
axis == 3 and n or 0
|
||||
)
|
||||
|
||||
v.rotation = v.rotation * quaternion:setEuler(v.rotation:inverse() * euler)
|
||||
end
|
||||
|
||||
if n ~= 0 then
|
||||
start = current
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
hitbox:destroy()
|
||||
|
||||
history.endAction()
|
||||
end)
|
||||
|
||||
|
||||
|
||||
table.insert(arrows[axis], newArrow)
|
||||
end
|
||||
|
||||
boundingEvent = selection.box:changed(positionArrows)
|
||||
|
||||
positionArrows()
|
||||
end,
|
||||
|
||||
deactivate = function ()
|
||||
print("tool deactivated")
|
||||
boundingEvent:disconnect()
|
||||
boundingEvent = nil
|
||||
|
||||
for _,v in pairs(arrows) do
|
||||
for _,arrow in pairs(v) do
|
||||
print(arrow)
|
||||
arrow:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
arrows = {
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
}
|
||||
end
|
||||
}
|
||||
}
|
|
@ -22,6 +22,8 @@ local function updateHandles()
|
|||
for _,v in pairs(handles) do
|
||||
v[1].size = vector3(0,0,0)
|
||||
v[1].opacity = 0
|
||||
v[1].line.positionA = vector3(0, 0, 0)
|
||||
v[1].line.positionB = vector3(0, 0, 0)
|
||||
end
|
||||
else
|
||||
for _,v in pairs(handles) do
|
||||
|
@ -30,6 +32,8 @@ local function updateHandles()
|
|||
v[1].rotation = v[1].rotation * quaternion():setEuler(math.rad(90), 0, 0)
|
||||
v[1].size = vector3(0.4, 0.4, 0.4)
|
||||
v[1].opacity = 1
|
||||
v[1].line.positionA = v[1].position
|
||||
v[1].line.positionB = selection.box.position
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -125,6 +129,8 @@ return {
|
|||
workshopLocked = true
|
||||
})
|
||||
|
||||
engine.construct("line", handle, {name = "line", colour = handle.colour})
|
||||
|
||||
handle:mouseLeftPressed(function()
|
||||
gridGuideline.size = vector3(300, 0.1, 300)
|
||||
|
||||
|
@ -137,6 +143,8 @@ return {
|
|||
|
||||
local last = nil
|
||||
|
||||
history.beginAction(selection.selection, "Scale tool drag")
|
||||
|
||||
while engine.input:isMouseButtonDown(enums.mouseButton.left) do
|
||||
-- Position and rotate the invisible guideline to face the camera.
|
||||
-- We use this guideline to raycast with
|
||||
|
@ -221,7 +229,7 @@ return {
|
|||
|
||||
wait()
|
||||
end
|
||||
|
||||
history.endAction()
|
||||
gridVisual:destroy()
|
||||
gridGuideline.size = vector3(0, 0, 0)
|
||||
end)
|
||||
|
|
Loading…
Reference in New Issue