mirror of https://github.com/teverse/teverse
Compare commits
26 Commits
bd5e8bef35
...
264d8df31b
Author | SHA1 | Date |
---|---|---|
teverse | 264d8df31b | |
teverse | 609a964f6f | |
Jay | e8d9f89095 | |
Jay | a5ef592fa7 | |
Jay | 38920adfa2 | |
Jay | 567839d691 | |
Jay | d7b768e5fa | |
Jay | 3e1024e497 | |
teverse | 239a137cdb | |
teverse | b08d9d5e23 | |
teverse | e91fad1555 | |
teverse | 4fd6375073 | |
teverse | 2426c83bde | |
Jay | 46fda8fe65 | |
Jay | c4803464b7 | |
Jay | 64c7894bef | |
Jay | 46de27b588 | |
Jay | ebb379f010 | |
Jay | 136dc01ccd | |
Jay | 7f5068fce7 | |
teverse | 50d84f37fa | |
Jay | 3524d7b08f | |
Jay | 15b40acf71 | |
teverse | 87f91a7b86 | |
Alessandro | 29c730c536 | |
teverse | d100bffab3 |
|
@ -5,4 +5,8 @@ This repo contains open source components produced for Teverse.
|
|||
|
||||
# Copyright
|
||||
|
||||
Copyright (c) 2019 teverse.com
|
||||
Copyright (c) 2020 teverse.com
|
||||
|
||||
# Acknowledgements
|
||||
- sound/click.ogg sourced from http://soundbible.com/1705-Click2.html
|
||||
- sound/tick.ogg sourced from http://soundbible.com/2044-Tick.html
|
3031
apiDump.json
3031
apiDump.json
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
--[[
|
||||
Copyright 2019 Teverse
|
||||
Copyright 2020 Teverse
|
||||
@File core/client/cameraController.lua
|
||||
@Author(s) Jay
|
||||
--]]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--[[
|
||||
Copyright 2019 Teverse
|
||||
Copyright 2020 Teverse
|
||||
@File core/client/characterController.lua
|
||||
@Author(s) Jay
|
||||
--]]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--[[
|
||||
Copyright 2019 Teverse
|
||||
Copyright 2020 Teverse
|
||||
@File core/client/chat.lua
|
||||
@Author(s) Jay
|
||||
--]]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--[[
|
||||
Copyright 2019 Teverse
|
||||
Copyright 2020 Teverse
|
||||
@File core/client/loader.lua
|
||||
@Author(s) Jay
|
||||
@Description Loads all open sourced components of the client.
|
||||
|
@ -9,4 +9,4 @@ print("Loaded Client")
|
|||
require("tevgit:core/client/debug.lua")
|
||||
require("tevgit:core/client/chat.lua")
|
||||
require("tevgit:core/client/playerList.lua")
|
||||
|
||||
--require("tevgit:core/client/characterController.lua")
|
|
@ -1,5 +1,5 @@
|
|||
--[[
|
||||
Copyright 2019 Teverse
|
||||
Copyright 2020 Teverse
|
||||
@File core/client/playerList.lua
|
||||
@Author(s) Jay
|
||||
--]]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--[[
|
||||
Copyright 2019 Teverse
|
||||
Copyright 2020 Teverse
|
||||
@File core/server/characterController.lua
|
||||
@Author(s) Jay
|
||||
--]]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--[[
|
||||
Copyright 2019 Teverse
|
||||
Copyright 2020 Teverse
|
||||
@File core/server/chat.lua
|
||||
@Author(s) Jay
|
||||
--]]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--[[
|
||||
Copyright 2019 Teverse
|
||||
Copyright 2020 Teverse
|
||||
@File core/server/loader.lua
|
||||
@Author(s) Jay
|
||||
@Description Loads all open sourced components of the server.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
--[[
|
||||
create.lua
|
||||
Copyright (c) 2019 teverse.com
|
||||
Copyright (c) 2020 teverse.com
|
||||
|
||||
This script is ran when the user loads create mode,
|
||||
it is given workshop level sandboxing permissions.
|
||||
|
|
|
@ -62,7 +62,7 @@ local function runTutorial(module)
|
|||
|
||||
local instructions = engine.construct("guiFrame", body, {
|
||||
size = guiCoord(1/4, 0, 1, 0),
|
||||
backgroundColour= colour:white(),
|
||||
backgroundColour=colour:fromRGB(37, 37, 44),
|
||||
})
|
||||
|
||||
local code = engine.construct("guiFrame", body, {
|
||||
|
@ -96,7 +96,7 @@ local function runTutorial(module)
|
|||
fontFile = "local:OpenSans-Regular.ttf",
|
||||
fontSize = 20,
|
||||
text = page,
|
||||
textColour = colour:black(),
|
||||
textColour = colour:white(),
|
||||
handleEvents = false
|
||||
})
|
||||
|
||||
|
@ -132,7 +132,7 @@ local function runTutorial(module)
|
|||
fontFile = "local:OpenSans-Regular.ttf",
|
||||
fontSize = 20,
|
||||
text = v,
|
||||
textColour = colour:black(),
|
||||
textColour = colour:white(),
|
||||
handleEvents = false
|
||||
})
|
||||
|
||||
|
@ -187,7 +187,7 @@ local function runTutorial(module)
|
|||
fontFile = "tevurl:font/OpenSans-Italic.ttf",
|
||||
fontSize = 20,
|
||||
text = v.text,
|
||||
textColour = colour:black(),
|
||||
textColour = colour:white(),
|
||||
handleEvents = false
|
||||
})
|
||||
|
||||
|
|
|
@ -38,10 +38,9 @@ addDocs("baseClass", {
|
|||
getDescendants = method("Returns a table of all descended objects", nil, {"table"}),
|
||||
destroy = method("Locks the object before removing it from the hierarchy. Children will also be destroyed."),
|
||||
destroyAllChildren = method("Invokes the destroy method on each child of this instance."),
|
||||
isContainer = method("", nil, {
|
||||
isContainer = method("Returns true if this object can contain other objects.", nil, {
|
||||
"boolean"
|
||||
}),
|
||||
clone = method(),
|
||||
isA = method("Returns true if this object is derived from the className given.", {
|
||||
className = "string"
|
||||
}, {
|
||||
|
@ -54,7 +53,8 @@ addDocs("baseClass", {
|
|||
ancestor = "baseClass"
|
||||
}, {"boolean"}),
|
||||
getFullName = method("Returns a string including ancestor names", nil, {"string"}),
|
||||
clone = method("Creates and returns a copy of this object", nil, {"variant"})
|
||||
clone = method("Creates and returns a copy of this object", nil, {"variant"}),
|
||||
describe = method("", nil, {"string"})
|
||||
},
|
||||
|
||||
events = {
|
||||
|
@ -64,10 +64,10 @@ addDocs("baseClass", {
|
|||
oldValue = "variant"
|
||||
}),
|
||||
childAdded = event("Fired when a child is added", {
|
||||
child = "baseClass"
|
||||
child = "variant"
|
||||
}),
|
||||
childRemoved = event("Fired when a child is removed", {
|
||||
child = "baseClass"
|
||||
child = "variant"
|
||||
}),
|
||||
destroying = event("Fired just before an object is destroyed."),
|
||||
}
|
||||
|
@ -125,7 +125,6 @@ addDocs("block", {
|
|||
}
|
||||
})
|
||||
|
||||
|
||||
addDocs("camera", {
|
||||
description = "",
|
||||
properties = {
|
||||
|
@ -141,4 +140,17 @@ addDocs("camera", {
|
|||
}
|
||||
})
|
||||
|
||||
addDocs("guiBase", {
|
||||
description = "",
|
||||
properties = {
|
||||
|
||||
},
|
||||
methods = {
|
||||
bindSizeBreakpoint = method("", {
|
||||
breakpoint = "enums.sizeBreakpoint",
|
||||
properties = "table"
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
return docs
|
|
@ -33,8 +33,17 @@ local newObjects = {}
|
|||
|
||||
local eventListeners = {}
|
||||
local actionName = ""
|
||||
|
||||
local changedListener, ChildAddedListener, destroyingListener;
|
||||
|
||||
local function registerEvents(object)
|
||||
table.insert(eventListeners, object:onSync("changed", changedListener))
|
||||
table.insert(eventListeners, object:onSync("childAdded", ChildAddedListener))
|
||||
table.insert(eventListeners, object:onSync("destroying", destroyingListener))
|
||||
end
|
||||
|
||||
-- oldValue added to changed event from "POTATO 0.7.0"
|
||||
local function changedListener(property, value, oldValue)
|
||||
changedListener = function (property, value, oldValue)
|
||||
local changedObject = self.object
|
||||
if not changes[changedObject] then
|
||||
changes[changedObject] = {}
|
||||
|
@ -48,7 +57,7 @@ local function changedListener(property, value, oldValue)
|
|||
end
|
||||
end
|
||||
|
||||
local function destroyingListener()
|
||||
destroyingListener = function()
|
||||
local changedObject = self.object
|
||||
if not changes[changedObject] then
|
||||
changes[changedObject] = {}
|
||||
|
@ -68,12 +77,35 @@ local function destroyingListener()
|
|||
|
||||
toStore["parent"] = changedObject.parent
|
||||
toStore["className"] = changedObject.className
|
||||
toStore["_ref"] = changedObject
|
||||
|
||||
table.insert(destroyedObjects, toStore)
|
||||
end
|
||||
|
||||
local function ChildAddedListener(child)
|
||||
table.insert(newObjects, child)
|
||||
ChildAddedListener = function(child)
|
||||
local changedObject = child
|
||||
if not changes[changedObject] then
|
||||
changes[changedObject] = {}
|
||||
end
|
||||
-- Object is being destroyed, let's save a copy of all their writable properties so the user can undo this action
|
||||
local members = shared.workshop:getMembersOfObject( changedObject )
|
||||
local toStore = {}
|
||||
for _, prop in pairs(members) do
|
||||
local val = changedObject[prop.property]
|
||||
local pType = type(val)
|
||||
|
||||
if prop.writable and pType ~= "function" then
|
||||
-- We can save it and re-construct it
|
||||
toStore[prop.property] = val
|
||||
end
|
||||
end
|
||||
|
||||
toStore["parent"] = changedObject.parent
|
||||
toStore["className"] = changedObject.className
|
||||
toStore["_ref"] = changedObject
|
||||
registerEvents(changedObject)
|
||||
|
||||
table.insert(newObjects, toStore)
|
||||
end
|
||||
|
||||
local function count(dictionary)
|
||||
|
@ -98,14 +130,10 @@ local function beginAction( object, name )
|
|||
actionName = name or ""
|
||||
if type(object) == "table" then
|
||||
for _,v in pairs(object) do
|
||||
table.insert(eventListeners, v:onSync("changed", changedListener))
|
||||
table.insert(eventListeners, v:onSync("childAdded", ChildAddedListener))
|
||||
table.insert(eventListeners, v:onSync("destroying", destroyingListener))
|
||||
registerEvents(v)
|
||||
end
|
||||
else
|
||||
table.insert(eventListeners, object:onSync("changed", changedListener))
|
||||
table.insert(eventListeners, object:onSync("childAdded", ChildAddedListener))
|
||||
table.insert(eventListeners, object:onSync("destroying", destroyingListener))
|
||||
registerEvents(object)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -119,7 +147,7 @@ local function endAction()
|
|||
eventListeners = {}
|
||||
|
||||
-- if nothing changed dont create an action
|
||||
if count(changes) > 0 or #destroyedObjects > 0 or #newObjects > 0 then
|
||||
if count(changes) > 0 or count(destroyedObjects) > 0 or count(newObjects) > 0 then
|
||||
pointer = pointer + 1
|
||||
if pointer >= limit then
|
||||
actions[pointer - limit] = nil
|
||||
|
@ -136,6 +164,20 @@ local function endAction()
|
|||
end
|
||||
|
||||
actionInProgress = false
|
||||
end
|
||||
|
||||
local function updateReferences(old, new)
|
||||
for p, a in pairs(actions) do
|
||||
local newTbl = {}
|
||||
for ref, props in pairs(a[3]) do
|
||||
if ref ~= old then
|
||||
newTbl[ref] = props
|
||||
else
|
||||
newTbl[new] = props
|
||||
end
|
||||
end
|
||||
a[3] = newTbl
|
||||
end
|
||||
end
|
||||
|
||||
local function undo()
|
||||
|
@ -147,6 +189,16 @@ local function undo()
|
|||
for property, value in pairs(properties) do
|
||||
obj[property] = value
|
||||
end
|
||||
local oldRef = properties["_ref"]
|
||||
properties["_ref"] = obj
|
||||
updateReferences(oldRef, obj)
|
||||
end
|
||||
|
||||
-- created objects (destroy)
|
||||
for _,properties in pairs(actions[pointer][5]) do
|
||||
if properties["_ref"].alive then
|
||||
properties["_ref"]:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
for object, properties in pairs(actions[pointer][3]) do
|
||||
|
@ -175,6 +227,25 @@ end
|
|||
local function redo()
|
||||
if actions[pointer + 1] ~= nil then
|
||||
pointer = pointer + 1
|
||||
|
||||
-- destroyed objects (destroy)
|
||||
for _, properties in pairs(actions[pointer][4]) do
|
||||
if properties["_ref"].alive then
|
||||
properties["_ref"]:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
-- created objects (create)
|
||||
for _,properties in pairs(actions[pointer][5]) do
|
||||
local obj = engine[properties["className"]]()
|
||||
for property, value in pairs(properties) do
|
||||
obj[property] = value
|
||||
end
|
||||
local oldRef = properties["_ref"]
|
||||
properties["_ref"] = obj
|
||||
updateReferences(oldRef, obj)
|
||||
end
|
||||
|
||||
for object, properties in pairs(actions[pointer][3]) do
|
||||
if object and object.alive then
|
||||
for property, values in pairs(properties) do
|
||||
|
@ -201,7 +272,13 @@ keybinder:bind({
|
|||
name = "undo",
|
||||
priorKey = enums.key.leftCtrl,
|
||||
key = enums.key.z,
|
||||
action = undo
|
||||
action = function ()
|
||||
if not engine.input:isKeyDown(enums.key.leftShift) then
|
||||
undo()
|
||||
else
|
||||
redo()
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
keybinder:bind({
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- Copyright (c) 2019 teverse.com
|
||||
-- Copyright (c) 2020 teverse.com
|
||||
|
||||
local hotkeysController = {
|
||||
bindings = {}
|
||||
|
|
|
@ -97,7 +97,9 @@ local function boundUpdate()
|
|||
bounds.max = controller.selection[1].position
|
||||
|
||||
for _,v in pairs(controller.selection) do
|
||||
bounds:expand(v) -- new in 0.13.2
|
||||
if type(v) == "block" then
|
||||
bounds:expand(v) -- new in 0.13.2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -122,7 +124,9 @@ controller.registerCallback(function()
|
|||
|
||||
for _,v in pairs(controller.selection) do
|
||||
if type(v.position) == "vector3" and type(v.size) == "vector3" then
|
||||
bounds:expand(v)
|
||||
if type(v) == "block" then
|
||||
bounds:expand(v)
|
||||
end
|
||||
table.insert(boundingEvents, v:changed(boundUpdate))
|
||||
end
|
||||
end
|
||||
|
@ -186,4 +190,6 @@ keybinder:bind({
|
|||
end
|
||||
})
|
||||
|
||||
return controller
|
||||
controller.box = boundingBox
|
||||
|
||||
return controller
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- Copyright 2019 teverse.com
|
||||
-- Copyright 2020 teverse.com
|
||||
|
||||
local cameraController = {
|
||||
zoomStep = 3,
|
||||
|
|
|
@ -32,16 +32,9 @@ return {
|
|||
colour = colour(0, 1, 0),
|
||||
size = vector3(1, 1, 1),
|
||||
position = vector3(1, 0, 0),
|
||||
mesh = "tevurl:3d/Samba.glb", --"primitive:wedge",
|
||||
mesh = "primitive:wedge",
|
||||
rotation = quaternion:setEuler(0, math.rad(90), 0)
|
||||
}):on("changed", function(p, v)
|
||||
if p == "meshScale" then
|
||||
self.object.size = v/50
|
||||
self.object.position = vector3(0, (self.object.size.y/2) - 0.5, 2)
|
||||
self.disconnect()
|
||||
end
|
||||
end)
|
||||
|
||||
})
|
||||
|
||||
local block = engine.construct("block", workspace, {
|
||||
name = "blueBlock",
|
||||
|
@ -74,4 +67,4 @@ return {
|
|||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- Copyright 2019 Teverse.com
|
||||
-- Copyright 2020 Teverse.com
|
||||
-- Used to share variables between scripts
|
||||
|
||||
-- shamelessly stolen from http://lua-users.org/wiki/SimpleRound
|
||||
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- Copyright 2019 Teverse.com
|
||||
-- Copyright 2020 Teverse.com
|
||||
|
||||
-- Tool Constants:
|
||||
local toolName = "Hand"
|
||||
|
@ -111,9 +111,9 @@ return {
|
|||
history.beginAction(selection.selection, "Hand tool drag")
|
||||
|
||||
local grid = engine.construct("grid", workspace, {
|
||||
step = 0.5,
|
||||
step = gridStep,
|
||||
colour = colour(0.1, 0, 0.1),
|
||||
size = 10,
|
||||
size = 12,
|
||||
rotation = quaternion:setEuler(math.rad(90), 0, 0)
|
||||
})
|
||||
|
||||
|
@ -152,7 +152,7 @@ return {
|
|||
end
|
||||
end
|
||||
|
||||
grid.position = avgPos / #selection.selection
|
||||
grid.position = (avgPos / #selection.selection) + vector3(0, 0.1, 0)
|
||||
end
|
||||
wait()
|
||||
end
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
-- Copyright 2019 Teverse.com
|
||||
-- Copyright 2020 Teverse.com
|
||||
-- This script is responsible for loading in the other sidetools
|
||||
-- This is required by the UI system and the array returned is used to generate the sidebar
|
||||
|
||||
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"),
|
||||
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"),
|
||||
}
|
||||
|
|
|
@ -1,20 +1,238 @@
|
|||
-- Copyright 2019 Teverse.com
|
||||
-- Copyright 2020 Teverse.com
|
||||
|
||||
-- Tool Constants:
|
||||
local toolName = "Move"
|
||||
local toolDesc = ""
|
||||
local toolIcon = "fa:s-arrows-alt"
|
||||
|
||||
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 boundingBoxChangedEvent;
|
||||
local gridGuideline;
|
||||
local handles;
|
||||
|
||||
local settingsGui = nil
|
||||
|
||||
local function updateHandles()
|
||||
if handles then
|
||||
if selection.box.size == vector3(0,0,0) then
|
||||
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
|
||||
v[1].position = selection.box.position + selection.box.rotation* ((v[2] * selection.box.size/2) + (v[2]*1.5))
|
||||
v[1]:lookAt(selection.box.position)
|
||||
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
|
||||
end
|
||||
|
||||
local axes = {"x", "y", "z"}
|
||||
|
||||
return {
|
||||
name = toolName,
|
||||
icon = toolIcon,
|
||||
desc = toolDesc,
|
||||
|
||||
activate = function()
|
||||
print("tool activated")
|
||||
settingsGui = ui.create("guiFrame", shared.workshop.interface["_toolBar"], {
|
||||
size = guiCoord(0, 120, 0, 28),
|
||||
position = guiCoord(0, 80, 0, 0),
|
||||
backgroundAlpha = 0.8,
|
||||
borderRadius = 4
|
||||
}, "primary")
|
||||
|
||||
ui.create("guiTextBox", settingsGui, {
|
||||
size = guiCoord(0.6, 0, 0, 18),
|
||||
position = guiCoord(0, 5, 0, 5),
|
||||
text = "Grid Step",
|
||||
fontSize = 18,
|
||||
textAlpha = 0.8
|
||||
}, "primaryText")
|
||||
|
||||
local gridStep = 0.25
|
||||
|
||||
local gridStepInput = ui.create("guiTextBox", settingsGui, {
|
||||
size = guiCoord(0.4, -6, 0, 18),
|
||||
position = guiCoord(0.6, 3, 0, 5),
|
||||
text = tostring(gridStep),
|
||||
fontSize = 18,
|
||||
textAlpha = 0.8,
|
||||
borderRadius = 4,
|
||||
align = enums.align.middle,
|
||||
readOnly = false
|
||||
}, "primaryVariant")
|
||||
|
||||
gridStepInput:on("changed", function()
|
||||
gridStep = tonumber(gridStepInput.text) or 0
|
||||
end)
|
||||
|
||||
local offsets = {}
|
||||
keyEvent = engine.input:keyPressed(function( inputObj )
|
||||
if inputObj.key == enums.key.r and isDragging then
|
||||
local targetRot = quaternion:setEuler(0,math.rad(-45),0)
|
||||
for _,v in pairs(selection.selection) do
|
||||
if offsets[v] then
|
||||
offsets[v][2] = offsets[v][2] * targetRot
|
||||
v.rotation = offsets[v][2]
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- This is used to raycast the user's mouse position to an axis
|
||||
gridGuideline = engine.construct("block", workspace, {
|
||||
name = "_GridGuideline",
|
||||
size = vector3(0, 0, 0),
|
||||
colour = colour(1, 1, 1),
|
||||
opacity = 0,
|
||||
workshopLocked = true,
|
||||
castsShadows = false
|
||||
})
|
||||
|
||||
handles = {}
|
||||
|
||||
for axisNumber, axis in pairs(axes) do
|
||||
for i = -1, 1, 2 do
|
||||
local face = vector3(0, 0, 0)
|
||||
face[axis] = i
|
||||
|
||||
local handle = engine.construct("block", nil, {
|
||||
name = "_CreateMode_",
|
||||
castsShadows = false,
|
||||
opacity = 0,
|
||||
renderQueue = 1,
|
||||
doNotSerialise = true,
|
||||
size = vector3(0.1, 0.1, 0.1),
|
||||
colour = colour(axisNumber == 1 and 1 or 0, axisNumber == 2 and 1 or 0, axisNumber == 3 and 1 or 0),
|
||||
emissiveColour = colour(axisNumber == 1 and 1 or 0, axisNumber == 2 and 1 or 0, axisNumber == 3 and 1 or 0),
|
||||
workshopLocked = true,
|
||||
mesh = "primitive:cone"
|
||||
})
|
||||
|
||||
engine.construct("line", handle, {name = "line", colour = handle.colour})
|
||||
|
||||
handle:mouseLeftPressed(function()
|
||||
gridGuideline.size = vector3(300, 0.1, 300)
|
||||
|
||||
local gridVisual = engine.construct("grid", workspace, {
|
||||
step = gridStep,
|
||||
colour = colour(0.1, 0, 0.1),
|
||||
size = 25,
|
||||
rotation = quaternion:setEuler(math.rad(90), 0, 0)
|
||||
})
|
||||
|
||||
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
|
||||
local pos1 = gridGuideline.position
|
||||
pos1[axis] = 0
|
||||
|
||||
local pos2 = workspace.camera.position
|
||||
pos2[axis] = 0
|
||||
|
||||
local lookAt = gridGuideline.rotation:setLookRotation( pos1 - pos2 )
|
||||
gridGuideline.rotation = lookAt * quaternion():setEuler(math.rad(90),0,0)
|
||||
gridGuideline.position = selection.box.position
|
||||
|
||||
if axis == "y" then
|
||||
gridVisual.rotation = quaternion:setLookRotation( pos1 - pos2 ) * quaternion():setEuler(math.rad(180),0,0)
|
||||
end
|
||||
gridVisual.position = selection.box.position
|
||||
|
||||
local mouseHits = engine.physics:rayTestScreenAllHits( engine.input.mousePosition )
|
||||
local mouseHit = nil
|
||||
-- We only want the gridGuideline
|
||||
for _,hit in pairs(mouseHits) do
|
||||
if hit.object == gridGuideline then
|
||||
mouseHit = hit
|
||||
goto skip_loop
|
||||
end
|
||||
end
|
||||
::skip_loop::
|
||||
|
||||
if mouseHit and mouseHit.object == gridGuideline then
|
||||
local target = mouseHit.hitPosition
|
||||
local didMove = true
|
||||
if last ~= nil then
|
||||
local translateBy = vector3(0, 0, 0)
|
||||
translateBy[axis] = target[axis] - last
|
||||
|
||||
if gridStep ~= 0 then
|
||||
translateBy = shared.roundVector3(translateBy, gridStep)
|
||||
if translateBy[axis] == 0 then
|
||||
didMove = false
|
||||
end
|
||||
end
|
||||
|
||||
if didMove then
|
||||
for _,v in pairs(selection.selection) do
|
||||
if type(v.position) == "vector3" then
|
||||
v.position = v.position + translateBy
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if didMove then
|
||||
last = target[axis]
|
||||
end
|
||||
end
|
||||
|
||||
wait()
|
||||
end
|
||||
|
||||
history.endAction()
|
||||
|
||||
gridVisual:destroy()
|
||||
gridGuideline.size = vector3(0, 0, 0)
|
||||
end)
|
||||
|
||||
table.insert(handles, {handle, face})
|
||||
end
|
||||
end
|
||||
|
||||
boundingBoxChangedEvent = selection.box:changed(updateHandles)
|
||||
updateHandles()
|
||||
end,
|
||||
|
||||
deactivate = function ()
|
||||
print("tool deactivated")
|
||||
if settingsGui then
|
||||
settingsGui:destroy()
|
||||
settingsGui = nil
|
||||
end
|
||||
|
||||
if boundingBoxChangedEvent then
|
||||
boundingBoxChangedEvent:disconnect()
|
||||
boundingBoxChangedEvent = nil
|
||||
end
|
||||
|
||||
if gridGuideline then
|
||||
gridGuideline:destroy()
|
||||
gridGuideline = nil
|
||||
end
|
||||
|
||||
if handles then
|
||||
for _,v in pairs(handles) do
|
||||
v[1]:destroy()
|
||||
end
|
||||
handles = nil
|
||||
end
|
||||
end
|
||||
}
|
|
@ -1,20 +1,211 @@
|
|||
-- Copyright 2019 Teverse.com
|
||||
-- Copyright 2020 Teverse.com
|
||||
|
||||
-- Tool Constants:
|
||||
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
|
||||
}
|
||||
}
|
|
@ -1,20 +1,268 @@
|
|||
-- Copyright 2019 Teverse.com
|
||||
-- Copyright 2020 Teverse.com
|
||||
|
||||
-- Tool Constants:
|
||||
local toolName = "Scale"
|
||||
local toolDesc = ""
|
||||
local toolIcon = "fa:s-expand"
|
||||
|
||||
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 boundingBoxChangedEvent;
|
||||
local gridGuideline;
|
||||
local handles;
|
||||
|
||||
local settingsGui = nil
|
||||
|
||||
local function updateHandles()
|
||||
if handles then
|
||||
if selection.box.size == vector3(0,0,0) then
|
||||
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
|
||||
v[1].position = selection.box.position + selection.box.rotation* ((v[2] * selection.box.size/2) + (v[2]*1.5))
|
||||
v[1]:lookAt(selection.box.position)
|
||||
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
|
||||
end
|
||||
|
||||
local axes = {"x", "y", "z"}
|
||||
|
||||
local debugBlock = engine.construct("block", nil, {
|
||||
name = "_CreateMode_",
|
||||
castsShadows = false,
|
||||
doNotSerialise = true,
|
||||
size = vector3(0.1, 0.1, 0.1),
|
||||
workshopLocked = true
|
||||
})
|
||||
|
||||
return {
|
||||
name = toolName,
|
||||
icon = toolIcon,
|
||||
desc = toolDesc,
|
||||
|
||||
activate = function()
|
||||
print("tool activated")
|
||||
settingsGui = ui.create("guiFrame", shared.workshop.interface["_toolBar"], {
|
||||
size = guiCoord(0, 120, 0, 28),
|
||||
position = guiCoord(0, 80, 0, 0),
|
||||
backgroundAlpha = 0.8,
|
||||
borderRadius = 4
|
||||
}, "primary")
|
||||
|
||||
ui.create("guiTextBox", settingsGui, {
|
||||
size = guiCoord(0.6, 0, 0, 18),
|
||||
position = guiCoord(0, 5, 0, 5),
|
||||
text = "Grid Step",
|
||||
fontSize = 18,
|
||||
textAlpha = 0.8
|
||||
}, "primaryText")
|
||||
|
||||
local gridStep = 1
|
||||
|
||||
local gridStepInput = ui.create("guiTextBox", settingsGui, {
|
||||
size = guiCoord(0.4, -6, 0, 18),
|
||||
position = guiCoord(0.6, 3, 0, 5),
|
||||
text = tostring(gridStep),
|
||||
fontSize = 18,
|
||||
textAlpha = 0.8,
|
||||
borderRadius = 4,
|
||||
align = enums.align.middle,
|
||||
readOnly = false
|
||||
}, "primaryVariant")
|
||||
|
||||
gridStepInput:on("changed", function()
|
||||
gridStep = tonumber(gridStepInput.text) or 0
|
||||
end)
|
||||
|
||||
local offsets = {}
|
||||
keyEvent = engine.input:keyPressed(function( inputObj )
|
||||
if inputObj.key == enums.key.r and isDragging then
|
||||
local targetRot = quaternion:setEuler(0,math.rad(-45),0)
|
||||
for _,v in pairs(selection.selection) do
|
||||
if offsets[v] then
|
||||
offsets[v][2] = offsets[v][2] * targetRot
|
||||
v.rotation = offsets[v][2]
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- This is used to raycast the user's mouse position to an axis
|
||||
gridGuideline = engine.construct("block", workspace, {
|
||||
name = "_GridGuideline",
|
||||
size = vector3(0, 0, 0),
|
||||
colour = colour(1, 1, 1),
|
||||
opacity = 0,
|
||||
workshopLocked = true,
|
||||
castsShadows = false
|
||||
})
|
||||
|
||||
handles = {}
|
||||
|
||||
for axisNumber, axis in pairs(axes) do
|
||||
for i = -1, 1, 2 do
|
||||
local face = vector3(0, 0, 0)
|
||||
face[axis] = i
|
||||
|
||||
local handle = engine.construct("block", nil, {
|
||||
name = "_CreateMode_",
|
||||
castsShadows = false,
|
||||
opacity = 0,
|
||||
renderQueue = 1,
|
||||
doNotSerialise = true,
|
||||
size = vector3(0.1, 0.1, 0.1),
|
||||
colour = colour(axisNumber == 1 and 1 or 0, axisNumber == 2 and 1 or 0, axisNumber == 3 and 1 or 0),
|
||||
emissiveColour = colour(axisNumber == 1 and 1 or 0, axisNumber == 2 and 1 or 0, axisNumber == 3 and 1 or 0),
|
||||
workshopLocked = true
|
||||
})
|
||||
|
||||
engine.construct("line", handle, {name = "line", colour = handle.colour})
|
||||
|
||||
handle:mouseLeftPressed(function()
|
||||
gridGuideline.size = vector3(300, 0.1, 300)
|
||||
|
||||
local gridVisual = engine.construct("grid", workspace, {
|
||||
step = gridStep,
|
||||
colour = colour(0.1, 0, 0.1),
|
||||
size = 25,
|
||||
rotation = quaternion:setEuler(math.rad(90), 0, 0)
|
||||
})
|
||||
|
||||
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
|
||||
local pos1 = gridGuideline.position
|
||||
pos1[axis] = 0
|
||||
|
||||
local pos2 = workspace.camera.position
|
||||
pos2[axis] = 0
|
||||
|
||||
local lookAt = gridGuideline.rotation:setLookRotation( pos1 - pos2 )
|
||||
gridGuideline.rotation = lookAt * quaternion():setEuler(math.rad(90),0,0)
|
||||
gridGuideline.position = selection.box.position
|
||||
|
||||
if axis == "y" then
|
||||
gridVisual.rotation = quaternion:setLookRotation( pos1 - pos2 ) * quaternion():setEuler(math.rad(180),0,0)
|
||||
end
|
||||
|
||||
gridVisual.position = selection.box.position
|
||||
|
||||
local mouseHits = engine.physics:rayTestScreenAllHits( engine.input.mousePosition )
|
||||
local mouseHit = nil
|
||||
-- We only want the gridGuideline
|
||||
for _,hit in pairs(mouseHits) do
|
||||
if hit.object == gridGuideline then
|
||||
mouseHit = hit
|
||||
goto skip_loop
|
||||
end
|
||||
end
|
||||
::skip_loop::
|
||||
|
||||
if mouseHit and mouseHit.object == gridGuideline then
|
||||
local target = mouseHit.hitPosition
|
||||
local dist = selection.box.position[axis] - target[axis]
|
||||
local didMove = true
|
||||
if last ~= nil then
|
||||
local translateBy = vector3(0, 0, 0)
|
||||
translateBy[axis] = math.abs(dist) - math.abs(last)
|
||||
|
||||
local offsetBy = vector3(0, 0, 0)
|
||||
offsetBy[axis] = dist - last
|
||||
|
||||
if gridStep ~= 0 then
|
||||
translateBy = shared.roundVector3(translateBy, gridStep)
|
||||
offsetBy = shared.roundVector3(offsetBy, gridStep)
|
||||
if translateBy[axis] == 0 then
|
||||
didMove = false
|
||||
end
|
||||
end
|
||||
|
||||
print(translateBy, offsetBy)
|
||||
|
||||
if didMove then
|
||||
--print(dist, translateBy)
|
||||
for _,v in pairs(selection.selection) do
|
||||
if type(v.position) == "vector3" and type(v.size) == "vector3" then
|
||||
local scaleBy = (v.rotation * translateBy)
|
||||
scaleBy = vector3(math.abs(scaleBy.x), math.abs(scaleBy.y), math.abs(scaleBy.z))
|
||||
if scaleBy.x < 0.01 then
|
||||
scaleBy.x = 0
|
||||
end
|
||||
if scaleBy.y < 0.01 then
|
||||
scaleBy.y = 0
|
||||
end
|
||||
if scaleBy.z < 0.01 then
|
||||
scaleBy.z = 0
|
||||
end
|
||||
|
||||
if translateBy[axis] < 0 then
|
||||
scaleBy = -scaleBy
|
||||
end
|
||||
v.position = v.position - (offsetBy / 2)
|
||||
v.size = v.size + scaleBy
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if didMove then
|
||||
last = dist
|
||||
end
|
||||
end
|
||||
|
||||
wait()
|
||||
end
|
||||
history.endAction()
|
||||
gridVisual:destroy()
|
||||
gridGuideline.size = vector3(0, 0, 0)
|
||||
end)
|
||||
|
||||
table.insert(handles, {handle, face})
|
||||
end
|
||||
end
|
||||
|
||||
boundingBoxChangedEvent = selection.box:changed(updateHandles)
|
||||
updateHandles()
|
||||
end,
|
||||
|
||||
deactivate = function ()
|
||||
print("tool deactivated")
|
||||
if settingsGui then
|
||||
settingsGui:destroy()
|
||||
settingsGui = nil
|
||||
end
|
||||
|
||||
if boundingBoxChangedEvent then
|
||||
boundingBoxChangedEvent:disconnect()
|
||||
boundingBoxChangedEvent = nil
|
||||
end
|
||||
|
||||
if gridGuideline then
|
||||
gridGuideline:destroy()
|
||||
gridGuideline = nil
|
||||
end
|
||||
|
||||
if handles then
|
||||
for _,v in pairs(handles) do
|
||||
v[1]:destroy()
|
||||
end
|
||||
handles = nil
|
||||
end
|
||||
end
|
||||
}
|
||||
}
|
|
@ -0,0 +1,298 @@
|
|||
--[[
|
||||
Requires refactoring
|
||||
]]
|
||||
|
||||
local controller = {}
|
||||
|
||||
local ui = require("tevgit:workshop/controllers/ui/core/ui.lua")
|
||||
local shared = require("tevgit:workshop/controllers/shared.lua")
|
||||
|
||||
local hues = {
|
||||
colour(1,0,0),
|
||||
colour(1,0,1),
|
||||
colour(0,0,1),
|
||||
colour(0,1,1),
|
||||
colour(0,1,0),
|
||||
colour(1,1,0),
|
||||
colour(1,0,0),
|
||||
}
|
||||
|
||||
local window = ui.window(shared.workshop.interface,
|
||||
"Colour Picker",
|
||||
guiCoord(0, 300, 0, 186),
|
||||
guiCoord(0.5, -150, 0.5, -93),
|
||||
false,
|
||||
true)
|
||||
window.visible = false
|
||||
local callback = nil
|
||||
|
||||
local startColour = colour(1,0,0)
|
||||
local currentColour = colour(1,0,0)
|
||||
|
||||
local colourPickerGradient = engine.construct("guiFrameMultiColour", window.content, {
|
||||
name = "square",
|
||||
size = guiCoord(0, 150, 0, 150),
|
||||
position = guiCoord(0, 5, 0, 5),
|
||||
topLeftColour = colour(1,1,1),
|
||||
topRightColour = startColour,
|
||||
bottomLeftColour = colour(1,1,1),
|
||||
bottomRightColour = startColour
|
||||
})
|
||||
|
||||
-- To have black on the bottom we need to overlay this...
|
||||
engine.construct("guiFrameMultiColour", colourPickerGradient, {
|
||||
name = "overlay",
|
||||
size = guiCoord(1,0,1,0),
|
||||
position = guiCoord(0, 0, 0, 0),
|
||||
|
||||
topLeftColour = colour(0,0,0),
|
||||
topLeftAlpha = 0,
|
||||
|
||||
topRightColour = colour(0,0,0),
|
||||
topRightAlpha = 0,
|
||||
|
||||
bottomLeftColour = colour(0,0,0),
|
||||
bottomLeftAlpha = 1,
|
||||
|
||||
bottomRightColour = colour(0,0,0),
|
||||
bottomRightAlpha = 1,
|
||||
|
||||
handleEvents = false
|
||||
})
|
||||
|
||||
local marker = engine.construct("guiFrame", colourPickerGradient, {
|
||||
name = "marker",
|
||||
size = guiCoord(0, 6, 0, 6),
|
||||
position = guiCoord(0, 0, 0, 0),
|
||||
handleEvents=false,
|
||||
backgroundColour = colour(1,1,1),
|
||||
borderColour = colour(0,0,0),
|
||||
zIndex = 10,
|
||||
borderWidth = 1,
|
||||
borderRadius = 6,
|
||||
borderAlpha = 1
|
||||
})
|
||||
|
||||
local hueBar = engine.construct("guiFrame", window.content, {
|
||||
name = "hueBar",
|
||||
size = guiCoord(0, 30, 1, -10),
|
||||
position = guiCoord(0, 160, 0, 5),
|
||||
backgroundAlpha = 0
|
||||
})
|
||||
|
||||
local hueBarMARKER = engine.construct("guiFrame", hueBar, {
|
||||
name = "hueBarMARKER",
|
||||
size = guiCoord(1, 0, 0, 1),
|
||||
position = guiCoord(0, 0, 0, 0),
|
||||
handleEvents=false,
|
||||
backgroundAlpha = 0,
|
||||
borderColour = colour(0,0,0),
|
||||
zIndex = 10,
|
||||
borderWidth = 2,
|
||||
borderAlpha = 1
|
||||
})
|
||||
|
||||
for i = 1, 6 do
|
||||
local colourPickerGradient = engine.construct("guiFrameMultiColour", hueBar, {
|
||||
handleEvents = false,
|
||||
size = guiCoord(1, 0, 1/6, 1),
|
||||
position = guiCoord(0, 0, (i-1)*(1/6), 0),
|
||||
topLeftColour = hues[i],
|
||||
topRightColour = hues[i],
|
||||
bottomLeftColour = hues[i+1],
|
||||
bottomRightColour = hues[i+1],
|
||||
handleEvents = false
|
||||
})
|
||||
end
|
||||
|
||||
local rLabel = ui.create("guiTextBox", window.content, {
|
||||
name = "labelR",
|
||||
size = guiCoord(0, 20, 0, 16),
|
||||
position = guiCoord(0,200,0,5),
|
||||
fontSize = 16,
|
||||
textAlpha = 0.6,
|
||||
text = "R",
|
||||
align = enums.align.topLeft
|
||||
}, "primaryText")
|
||||
|
||||
local rInput = ui.create("guiTextBox", window.content, {
|
||||
backgroundAlpha = 0.25,
|
||||
readOnly = false,
|
||||
multiline = false,
|
||||
fontSize = 18,
|
||||
name = "r",
|
||||
size = guiCoord(1, -230, 0,16),
|
||||
position = guiCoord(0, 220, 0, 5),
|
||||
text = "1",
|
||||
align = enums.align.middle
|
||||
}, "primary")
|
||||
|
||||
local gLabel = rLabel:clone()
|
||||
gLabel.name = "gLabel"
|
||||
gLabel.text = "G"
|
||||
gLabel.parent = window.content
|
||||
gLabel.position = guiCoord(0, 200, 0, 22)
|
||||
--themeController.add(gLabel, "primaryText")
|
||||
|
||||
local g = rInput:clone()
|
||||
g.name = "g"
|
||||
g.parent = window.content
|
||||
g.position = guiCoord(0, 220, 0, 22)
|
||||
-- themeController.add(g, "primary")
|
||||
|
||||
local bLabel = rLabel:clone()
|
||||
bLabel.name = "bLabel"
|
||||
bLabel.text = "B"
|
||||
bLabel.parent = window.content
|
||||
bLabel.position = guiCoord(0, 200, 0, 39)
|
||||
--themeController.add(bLabel, "primaryText")
|
||||
|
||||
local b = rInput:clone()
|
||||
b.name = "b"
|
||||
b.parent = window.content
|
||||
b.position = guiCoord(0, 220, 0, 39)
|
||||
|
||||
|
||||
local hexLabel = rLabel:clone()
|
||||
hexLabel.name = "hexLabel"
|
||||
hexLabel.text = "#"
|
||||
hexLabel.parent = window.content
|
||||
hexLabel.position = guiCoord(0, 200, 0, 56)
|
||||
--themeController.add(bLabel, "primaryText")
|
||||
|
||||
local HEX = rInput:clone()
|
||||
HEX.name = "FFFFFF"
|
||||
HEX.parent = window.content
|
||||
HEX.position = guiCoord(0, 220, 0, 56)
|
||||
-- themeController.add(b, "primary")
|
||||
|
||||
local preview = engine.construct("guiFrame", window.content, {
|
||||
position = guiCoord(0, 200, 0, 73),
|
||||
size = guiCoord(1, -210, 0, 16)
|
||||
})
|
||||
|
||||
local function handler()
|
||||
local newR = tonumber(rInput.text)
|
||||
local newG = tonumber(g.text)
|
||||
local newB = tonumber(b.text)
|
||||
if not newR or not newG or not newB then return end
|
||||
|
||||
controller.setColour(colour:fromRGB(newR, newG, newB))
|
||||
end
|
||||
|
||||
rInput:textInput(handler)
|
||||
g:textInput(handler)
|
||||
b:textInput(handler)
|
||||
HEX:textInput(function()
|
||||
controller.setColour(colour:fromHex(HEX.text), true)
|
||||
end)
|
||||
|
||||
hueBar:mouseLeftPressed(function ()
|
||||
while engine.input:isMouseButtonDown(enums.mouseButton.left) do
|
||||
local pos = engine.input.mousePosition - hueBar.absolutePosition
|
||||
local size = hueBar.absoluteSize
|
||||
|
||||
local y = pos.y/hueBar.absoluteSize.y
|
||||
|
||||
local sector = math.ceil(pos.y/(size.y * (1/6)))
|
||||
local hue = hues[sector]
|
||||
if hue and hues[sector+1] then
|
||||
|
||||
hueBarMARKER.position = guiCoord(0,0,y,0)
|
||||
|
||||
local selected = hue:lerp(hues[sector+1], (y - ((size.y * ((sector-1)/6))/hueBar.absoluteSize.y)) / (1/6))
|
||||
startColour = selected
|
||||
colourPickerGradient.topRightColour = startColour
|
||||
colourPickerGradient.bottomRightColour = startColour
|
||||
|
||||
local x = (marker.position.offsetX-2)/colourPickerGradient.absoluteSize.x
|
||||
local y = (marker.position.offsetY+2)/colourPickerGradient.absoluteSize.y
|
||||
|
||||
local selectedColour = startColour:lerp(colour(1,1,1), 1-x)
|
||||
selectedColour = selectedColour:lerp(colour(0,0,0), y)
|
||||
preview.backgroundColour = selectedColou
|
||||
|
||||
rInput.text = tostring(math.floor(selectedColour.r*255))
|
||||
g.text = tostring(math.floor(selectedColour.g*255))
|
||||
b.text = tostring(math.floor(selectedColour.b*255))
|
||||
HEX.text = selectedColour:getHex()
|
||||
end
|
||||
|
||||
wait()
|
||||
end
|
||||
|
||||
if callback then
|
||||
callback(preview.backgroundColour)
|
||||
end
|
||||
end)
|
||||
|
||||
colourPickerGradient:mouseLeftPressed(function ()
|
||||
while engine.input:isMouseButtonDown(enums.mouseButton.left) do
|
||||
local pos = engine.input.mousePosition - colourPickerGradient.absolutePosition
|
||||
marker.position = guiCoord(0, pos.x+2, 0, pos.y-2)
|
||||
|
||||
local x = pos.x/colourPickerGradient.absoluteSize.x
|
||||
local y = pos.y/colourPickerGradient.absoluteSize.y
|
||||
|
||||
local selectedColour = startColour:lerp(colour(1,1,1), 1-x)
|
||||
selectedColour = selectedColour:lerp(colour(0,0,0), y)
|
||||
preview.backgroundColour = selectedColour
|
||||
|
||||
rInput.text = tostring(math.floor(selectedColour.r*255))
|
||||
g.text = tostring(math.floor(selectedColour.g*255))
|
||||
b.text = tostring(math.floor(selectedColour.b*255))
|
||||
HEX.text = selectedColour:getHex()
|
||||
wait()
|
||||
end
|
||||
|
||||
if callback then
|
||||
callback(preview.backgroundColour)
|
||||
end
|
||||
end)
|
||||
|
||||
controller.setColour = function(c, dontUpdateHex)
|
||||
local h,s,l = c:getHSV()
|
||||
h=(1-h)*360
|
||||
local markerh = math.ceil(h / 60)
|
||||
if markerh <= 0 then markerh = 1 end
|
||||
|
||||
local pos = hueBar.absolutePosition
|
||||
local size = hueBar.absoluteSize
|
||||
|
||||
local hue = hues[markerh]
|
||||
|
||||
local selected = hue:lerp(hues[markerh+1], ((h - (60*(markerh-1)))/60))
|
||||
|
||||
startColour = selected
|
||||
colourPickerGradient.topRightColour = startColour
|
||||
colourPickerGradient.bottomRightColour = startColour
|
||||
|
||||
preview.backgroundColour = c
|
||||
|
||||
rInput.text = tostring(math.floor(c.r*255))
|
||||
g.text = tostring(math.floor(c.g*255))
|
||||
b.text = tostring(math.floor(c.b*255))
|
||||
if not dontUpdateHex then
|
||||
HEX.text = c:getHex()
|
||||
end
|
||||
|
||||
marker.position = guiCoord(0, (s) * colourPickerGradient.absoluteSize.x, 0, (1-l) * colourPickerGradient.absoluteSize.y)
|
||||
marker.position = marker.position + guiCoord(0, -2, 0, -2)
|
||||
|
||||
hueBarMARKER.position = guiCoord(0,0,h/360,0)
|
||||
|
||||
if callback then
|
||||
callback(preview.backgroundColour)
|
||||
end
|
||||
end
|
||||
|
||||
controller.window = window
|
||||
|
||||
controller.prompt = function(startColour, cb)
|
||||
callback = nil
|
||||
controller.setColour(startColour)
|
||||
callback = cb
|
||||
controller.window.visible = true
|
||||
end
|
||||
|
||||
return controller
|
|
@ -152,7 +152,7 @@ local function createHierarchyButton(object, guiParent)
|
|||
controller.scrollView.canvasSize =
|
||||
guiCoord(1, 0, 0, updatePositions())
|
||||
end
|
||||
else
|
||||
elseif object.name ~= "_bounding" then
|
||||
-- single click
|
||||
local currentTime = os.time()
|
||||
lastClick = currentTime
|
||||
|
|
|
@ -4,6 +4,7 @@ local modulePrefix = "tevgit:workshop/controllers/ui/components/propertyEditor/"
|
|||
|
||||
local ui = require("tevgit:workshop/controllers/ui/core/ui.lua")
|
||||
local themer = require("tevgit:workshop/controllers/ui/core/themer.lua")
|
||||
local colourPicker = require("tevgit:workshop/controllers/ui/components/colourPicker.lua")
|
||||
|
||||
local parseInputs = require(modulePrefix .. "parseInputs.lua")
|
||||
local meshShortcuts = require(modulePrefix .. "meshShortcuts.lua")
|
||||
|
@ -629,18 +630,11 @@ createInputs = {
|
|||
borderRadius = 2,
|
||||
})
|
||||
|
||||
-- col:mouseLeftReleased(function ()
|
||||
-- controller.colourPicker.window.visible = not controller.colourPicker.window.visible
|
||||
-- if controller.colourPicker.window.visible and instanceEditing and instanceEditing[property] then
|
||||
-- controller.colourPicker.setColour(instanceEditing[property])
|
||||
-- controller.colourPicker.setCallback(function (c)
|
||||
-- x.text = tostring(c.r)
|
||||
-- g.text = tostring(c.g)
|
||||
-- b.text = tostring(c.b)
|
||||
-- parseInputs[type(value)](property, container)
|
||||
-- end)
|
||||
-- end
|
||||
-- end)
|
||||
col:mouseLeftReleased(function ()
|
||||
colourPicker.prompt(value, function(c)
|
||||
instance[property] = c
|
||||
end)
|
||||
end)
|
||||
|
||||
return container
|
||||
end,
|
||||
|
|
|
@ -52,7 +52,7 @@ return {
|
|||
colour = function(property, gui)
|
||||
local r,g,b = tonumber(gui.r.text),tonumber(gui.g.text),tonumber(gui.b.text)
|
||||
if r and g and b then
|
||||
callbackInput(property, colour(r,g,b))
|
||||
callbackInput(property, colour:fromRGB(r,g,b))
|
||||
end
|
||||
end,
|
||||
|
||||
|
|
|
@ -27,9 +27,9 @@ return {
|
|||
gui.y.text = string.format("%.3f", value.y)
|
||||
end,
|
||||
colour = function(instance, gui, value)
|
||||
gui.r.text = string.format("%.5f", value.r)
|
||||
gui.g.text = string.format("%.5f", value.g)
|
||||
gui.b.text = string.format("%.5f", value.b)
|
||||
gui.r.text = string.format("%.0f", value.r * 255)
|
||||
gui.g.text = string.format("%.0f", value.g * 255)
|
||||
gui.b.text = string.format("%.0f", value.b * 255)
|
||||
gui.col.backgroundColour = value
|
||||
end,
|
||||
quaternion = function(instance, gui, value)
|
||||
|
|
|
@ -107,6 +107,18 @@ if shared.developerMode then
|
|||
local dump = shared.workshop:apiDump()
|
||||
print(engine.json:encode(dump))
|
||||
end)
|
||||
|
||||
local physicsEnabled = engine.physics.running
|
||||
local physicsToggle= ui.button(developmentPage, physicsEnabled and "Stop Simulating Physics" or "Simulate Physics", guiCoord(0, 190, 0, 30), guiCoord(0, 15, 0, 250), "secondary")
|
||||
physicsToggle:mouseLeftPressed(function ()
|
||||
physicsEnabled = not physicsEnabled
|
||||
if physicsEnabled then
|
||||
engine.physics:resume()
|
||||
else
|
||||
engine.physics:pause()
|
||||
end
|
||||
physicsToggle.label.text = physicsEnabled and "Stop Simulating Physics" or "Simulate Physics"
|
||||
end)
|
||||
|
||||
addTab("Development", developmentPage)
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ local toolBar = ui.create("guiFrame", toolDock, {
|
|||
local activeTool = nil
|
||||
|
||||
local function toggleTool(toolName)
|
||||
--engine.sounds:play("tevurl:sound/click.ogg") -- too much?
|
||||
if activeTool ~= toolName then
|
||||
if activeTool then
|
||||
tools[activeTool].deactivate()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- Copyright 2019 Teverse.com
|
||||
-- Copyright 2020 Teverse.com
|
||||
-- Responsible for managing the aesthetics of different UI elements
|
||||
|
||||
local currentTheme = require("tevgit:workshop/controllers/ui/themes/default.lua")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- Copyright 2019 Teverse.com
|
||||
-- Copyright 2020 Teverse.com
|
||||
-- This script includes shorcuts for creating UIs.
|
||||
-- Any interface created here will be properly themed.
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- Copyright 2019 Teverse.com
|
||||
-- Copyright 2020 Teverse.com
|
||||
-- Responsible for creating the workshop interface
|
||||
|
||||
local shared = require("tevgit:workshop/controllers/shared.lua")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- Copyright 2019 Teverse.com
|
||||
-- Copyright 2020 Teverse.com
|
||||
|
||||
return {
|
||||
primary = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- Copyright 2019 Teverse
|
||||
-- Copyright 2020 Teverse
|
||||
-- This script is required when workshop is loaded,
|
||||
-- and engine.workshop is passed to the function returned.
|
||||
-- e.g. require('tevgit:workshop/main.lua')(engine.workshop)
|
||||
|
@ -86,6 +86,8 @@ local function beginLoad(workshop)
|
|||
loadingScreen = nil
|
||||
end
|
||||
|
||||
local colourPicker = require("tevgit:workshop/controllers/ui/components/colourPicker.lua")
|
||||
|
||||
--print("Workshop Loaded. ", #engine.workspace.children) Lets not spam the console
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue