mirror of
https://github.com/teverse/teverse
synced 2025-08-25 07:34:46 +02:00
Compare commits
2 Commits
d7b768e5fa
...
38920adfa2
Author | SHA1 | Date | |
---|---|---|---|
![]() |
38920adfa2 | ||
![]() |
567839d691 |
@ -7,6 +7,27 @@ local function round(n, mult)
|
|||||||
return math.floor((n + mult/2)/mult) * mult
|
return math.floor((n + mult/2)/mult) * mult
|
||||||
end
|
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 {
|
return {
|
||||||
-- Storing workshop is important because sandbox access is restricted.
|
-- Storing workshop is important because sandbox access is restricted.
|
||||||
workshop = nil,
|
workshop = nil,
|
||||||
@ -17,6 +38,32 @@ return {
|
|||||||
roundVector3 = function(v, mult)
|
roundVector3 = function(v, mult)
|
||||||
return vector3(round(v.x, mult), round(v.y, mult), round(v.z, mult))
|
return vector3(round(v.x, mult), round(v.y, mult), round(v.z, mult))
|
||||||
end,
|
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
|
-- this is set when workshop is set
|
||||||
-- using the haslocaltevgit api
|
-- using the haslocaltevgit api
|
||||||
|
@ -6,5 +6,5 @@ return {
|
|||||||
handTool = require("tevgit:workshop/controllers/sidetools/hand.lua"),
|
handTool = require("tevgit:workshop/controllers/sidetools/hand.lua"),
|
||||||
moveTool = require("tevgit:workshop/controllers/sidetools/move.lua"),
|
moveTool = require("tevgit:workshop/controllers/sidetools/move.lua"),
|
||||||
scaleTool = require("tevgit:workshop/controllers/sidetools/scale.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
|
for _,v in pairs(handles) do
|
||||||
v[1].size = vector3(0,0,0)
|
v[1].size = vector3(0,0,0)
|
||||||
v[1].opacity = 0
|
v[1].opacity = 0
|
||||||
|
v[1].line.positionA = vector3(0, 0, 0)
|
||||||
|
v[1].line.positionB = vector3(0, 0, 0)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for _,v in pairs(handles) do
|
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].rotation = v[1].rotation * quaternion():setEuler(math.rad(90), 0, 0)
|
||||||
v[1].size = vector3(0.2, 0.4, 0.2)
|
v[1].size = vector3(0.2, 0.4, 0.2)
|
||||||
v[1].opacity = 1
|
v[1].opacity = 1
|
||||||
|
v[1].line.positionA = v[1].position
|
||||||
|
v[1].line.positionB = selection.box.position
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -118,6 +122,8 @@ return {
|
|||||||
mesh = "primitive:cone"
|
mesh = "primitive:cone"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
engine.construct("line", handle, {name = "line", colour = handle.colour})
|
||||||
|
|
||||||
handle:mouseLeftPressed(function()
|
handle:mouseLeftPressed(function()
|
||||||
gridGuideline.size = vector3(300, 0.1, 300)
|
gridGuideline.size = vector3(300, 0.1, 300)
|
||||||
|
|
||||||
@ -130,6 +136,8 @@ return {
|
|||||||
|
|
||||||
local last = nil
|
local last = nil
|
||||||
|
|
||||||
|
history.beginAction(selection.selection, "Move tool drag")
|
||||||
|
|
||||||
while engine.input:isMouseButtonDown(enums.mouseButton.left) do
|
while engine.input:isMouseButtonDown(enums.mouseButton.left) do
|
||||||
-- Position and rotate the invisible guideline to face the camera.
|
-- Position and rotate the invisible guideline to face the camera.
|
||||||
-- We use this guideline to raycast with
|
-- We use this guideline to raycast with
|
||||||
@ -190,6 +198,8 @@ return {
|
|||||||
wait()
|
wait()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
history.endAction()
|
||||||
|
|
||||||
gridVisual:destroy()
|
gridVisual:destroy()
|
||||||
gridGuideline.size = vector3(0, 0, 0)
|
gridGuideline.size = vector3(0, 0, 0)
|
||||||
end)
|
end)
|
||||||
|
@ -5,16 +5,207 @@ local toolName = "Rotate"
|
|||||||
local toolDesc = ""
|
local toolDesc = ""
|
||||||
local toolIcon = "fa:s-redo"
|
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 {
|
return {
|
||||||
name = toolName,
|
name = toolName,
|
||||||
icon = toolIcon,
|
icon = toolIcon,
|
||||||
desc = toolDesc,
|
desc = toolDesc,
|
||||||
|
|
||||||
activate = function()
|
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,
|
end,
|
||||||
|
|
||||||
deactivate = function ()
|
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
|
end
|
||||||
}
|
}
|
@ -22,6 +22,8 @@ local function updateHandles()
|
|||||||
for _,v in pairs(handles) do
|
for _,v in pairs(handles) do
|
||||||
v[1].size = vector3(0,0,0)
|
v[1].size = vector3(0,0,0)
|
||||||
v[1].opacity = 0
|
v[1].opacity = 0
|
||||||
|
v[1].line.positionA = vector3(0, 0, 0)
|
||||||
|
v[1].line.positionB = vector3(0, 0, 0)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for _,v in pairs(handles) do
|
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].rotation = v[1].rotation * quaternion():setEuler(math.rad(90), 0, 0)
|
||||||
v[1].size = vector3(0.4, 0.4, 0.4)
|
v[1].size = vector3(0.4, 0.4, 0.4)
|
||||||
v[1].opacity = 1
|
v[1].opacity = 1
|
||||||
|
v[1].line.positionA = v[1].position
|
||||||
|
v[1].line.positionB = selection.box.position
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -125,6 +129,8 @@ return {
|
|||||||
workshopLocked = true
|
workshopLocked = true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
engine.construct("line", handle, {name = "line", colour = handle.colour})
|
||||||
|
|
||||||
handle:mouseLeftPressed(function()
|
handle:mouseLeftPressed(function()
|
||||||
gridGuideline.size = vector3(300, 0.1, 300)
|
gridGuideline.size = vector3(300, 0.1, 300)
|
||||||
|
|
||||||
@ -137,6 +143,8 @@ return {
|
|||||||
|
|
||||||
local last = nil
|
local last = nil
|
||||||
|
|
||||||
|
history.beginAction(selection.selection, "Scale tool drag")
|
||||||
|
|
||||||
while engine.input:isMouseButtonDown(enums.mouseButton.left) do
|
while engine.input:isMouseButtonDown(enums.mouseButton.left) do
|
||||||
-- Position and rotate the invisible guideline to face the camera.
|
-- Position and rotate the invisible guideline to face the camera.
|
||||||
-- We use this guideline to raycast with
|
-- We use this guideline to raycast with
|
||||||
@ -221,7 +229,7 @@ return {
|
|||||||
|
|
||||||
wait()
|
wait()
|
||||||
end
|
end
|
||||||
|
history.endAction()
|
||||||
gridVisual:destroy()
|
gridVisual:destroy()
|
||||||
gridGuideline.size = vector3(0, 0, 0)
|
gridGuideline.size = vector3(0, 0, 0)
|
||||||
end)
|
end)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user