Compare commits

...

2 Commits

Author SHA1 Message Date
Jay 38920adfa2 rotate tool 2020-01-12 12:10:58 +00:00
Jay 567839d691 Tools 2020-01-12 11:39:10 +00:00
5 changed files with 261 additions and 5 deletions

View File

@ -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

View File

@ -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"),
}

View File

@ -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)

View File

@ -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
}
}

View File

@ -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)