Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions [editor]/edf/edf.lua
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ function edfCreateElement(elementType, creatorClient, fromResource, parametersTa
if dataField == "position" then
edfSetElementPosition(newElement, dataValue[1], dataValue[2], dataValue[3])
elseif dataField == "rotation" then
edfSetElementRotation(newElement, dataValue[1], dataValue[2], dataValue[3])
edfSetElementRotation(newElement, dataValue[1], dataValue[2], dataValue[3], dataValue[4])
elseif dataField == "interior" then
setElementInterior(newElement, dataValue)
setElementData(newElement, dataField, dataValue)
Expand Down Expand Up @@ -899,25 +899,24 @@ function edfSetElementPosition(element, px, py, pz)
end

--Sets an element's rotation, or its rotX/Y/Z element data
function edfSetElementRotation(element, rx, ry, rz)
function edfSetElementRotation(element, rx, ry, rz, rotOrder)
local ancestor = edfGetAncestor(element) or element
setElementData(ancestor, "rotation", {rx, ry, rz})

setElementData(ancestor, "rotation", {rx, ry, rz, rotOrder})
local etype = getElementType(element)
if etype == "object" or etype == "vehicle" then
if rx and ry and rz and setElementRotation(element, rx, ry, rz) then
if rx and ry and rz and setElementRotation(element, rx, ry, rz, rotOrder) then
triggerEvent ( "onElementPropertyChanged", ancestor, "rotation" )
return true
end
elseif etype == "player" or etype == "ped" then
if setElementRotation(element, 0, 0, rz) then
if setElementRotation(element, 0, 0, rz, rotOrder) then
triggerEvent ( "onElementPropertyChanged", ancestor, "rotation" )
return true
end
else
local handle = edfGetHandle(element)
if handle then
if setElementRotation(handle, rx, ry, rz) then
if setElementRotation(handle, rx, ry, rz, rotOrder) then
triggerEvent ( "onElementPropertyChanged", ancestor, "rotation" )
return true
end
Expand Down
3 changes: 3 additions & 0 deletions [editor]/edf/edf_client.lua
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ function edfSetElementRotation(element, rx, ry, rz)
if rx and ry and rz then
local etype = getElementType(element)
if etype == "object" or etype == "vehicle" or etype == "player" or etype == "ped" then
-- Clear the quat rotation when set manually
exports.editor_main:clearElementQuat(element)

return setElementRotation(element, rx, ry, rz)
else
local handle = edfGetHandle(element)
Expand Down
4 changes: 4 additions & 0 deletions [editor]/editor_gui/client/options_action.lua
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ function optionsActions.enableColPatch(value)
end
end

function optionsActions.enableRotPatch(value)
optionsData.enableRotPatch = value
end

function optionsActions.smoothCamMove (value)
local loaded = freecam.setFreecamOption ( "smoothMovement", value )
if ( loaded ) then
Expand Down
3 changes: 3 additions & 0 deletions [editor]/editor_gui/client/options_backend.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ local xmlVariants = {
["enablePrecisionSnap"]="enableprecisionsnap",
["enablePrecisionRotation"]="enableprecisionrotation",
["enableColPatch"]="enablecolpatch",
["enableRotPatch"]="enablerotpatch",
["fov"]="fov",
}
local nodeTypes = {
Expand Down Expand Up @@ -57,6 +58,7 @@ local nodeTypes = {
["enablePrecisionRotation"]="bool",
["enableXYZlines"]="bool",
["enableColPatch"]="bool",
["enableRotPatch"]="bool",
["fov"]="progress",
}
local defaults = {
Expand Down Expand Up @@ -86,6 +88,7 @@ local defaults = {
["enablePrecisionRotation"]=false,
["enableXYZlines"]=true,
["enableColPatch"]=false,
["enableRotPatch"]=true,
["fov"]=dxGetStatus()["SettingFOV"],
}

Expand Down
17 changes: 9 additions & 8 deletions [editor]/editor_gui/client/options_gui.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ function createOptionsDialog()

---------------------------------
dialog.enableBox = editingControl.boolean:create{["x"]=0.60,["y"]=0.02,["width"]=1,["height"]=0.1,["relative"]=true,["parent"]=dialog.generalTab,["label"]="Enable Bounding Box"}
dialog.enableXYZlines = editingControl.boolean:create{["x"]=0.60,["y"]=0.1,["width"]=1,["height"]=0.1,["relative"]=true,["parent"]=dialog.generalTab,["label"]="Enable XYZ Lines"}
dialog.enableXYZlines = editingControl.boolean:create{["x"]=0.60,["y"]=0.12,["width"]=1,["height"]=0.1,["relative"]=true,["parent"]=dialog.generalTab,["label"]="Enable XYZ Lines"}
---------------------------------
dialog.enablePrecisionSnap = editingControl.boolean:create{["x"]=0.60,["y"]=0.2,["width"]=1,["height"]=0.1,["relative"]=true,["parent"]=dialog.generalTab,["label"]="Precise Position"}
guiCreateLabel ( 0.55, 0.3, 70, 17, "Snap Level:", true, dialog.generalTab )
dialog.precisionLevel = editingControl.dropdown:create{["x"]=0.68,["y"]=0.3,["width"]=0.3,["height"]=0.07,["dropWidth"]=0.30,["dropHeight"]=0.55,["relative"]=true,["rows"]={"10","5","2","1","0.1","0.01","0.001","0.0001"},["parent"]=dialog.generalTab}
guiCreateLabel ( 0.47, 0.4, 70, 17, "Rotation Precision:", true, dialog.generalTab )
dialog.precisionRotLevel = editingControl.dropdown:create{["x"]=0.68,["y"]=0.4,["width"]=0.3,["height"]=0.07,["dropWidth"]=0.30,["dropHeight"]=0.55,["relative"]=true,["rows"]={"180","90","45","30","20","10","5","1"},["parent"]=dialog.generalTab}
dialog.enablePrecisionRotation = editingControl.boolean:create{["x"]=0.60,["y"]=0.5,["width"]=1,["height"]=0.1,["relative"]=true,["parent"]=dialog.generalTab,["label"]="Precise Rotation"}
dialog.enablePrecisionSnap = editingControl.boolean:create{["x"]=0.60,["y"]=0.22,["width"]=1,["height"]=0.1,["relative"]=true,["parent"]=dialog.generalTab,["label"]="Enable Snap - Precise Position"}
guiCreateLabel ( 0.47, 0.34, 70, 17, "Position Snap Level:", true, dialog.generalTab )
dialog.precisionLevel = editingControl.dropdown:create{["x"]=0.68,["y"]=0.34,["width"]=0.3,["height"]=0.07,["dropWidth"]=0.30,["dropHeight"]=0.55,["relative"]=true,["rows"]={"10","5","2","1","0.1","0.01","0.001","0.0001"},["parent"]=dialog.generalTab}
guiCreateLabel ( 0.47, 0.44, 70, 17, "Rotation Snap Level:", true, dialog.generalTab )
dialog.precisionRotLevel = editingControl.dropdown:create{["x"]=0.68,["y"]=0.44,["width"]=0.3,["height"]=0.07,["dropWidth"]=0.30,["dropHeight"]=0.55,["relative"]=true,["rows"]={"180","90","45","30","20","10","5","1"},["parent"]=dialog.generalTab}
dialog.enablePrecisionRotation = editingControl.boolean:create{["x"]=0.60,["y"]=0.52,["width"]=1,["height"]=0.1,["relative"]=true,["parent"]=dialog.generalTab,["label"]="Enable Snap - Precise Rotation"}
---------------------------------
dialog.enableColPatch = editingControl.boolean:create{["x"]=0.60,["y"]=0.6,["width"]=1,["height"]=0.1,["relative"]=true,["parent"]=dialog.generalTab,["label"]="Enable collision patches"}
dialog.enableColPatch = editingControl.boolean:create{["x"]=0.60,["y"]=0.62,["width"]=1,["height"]=0.1,["relative"]=true,["parent"]=dialog.generalTab,["label"]="Enable collision patches"}
dialog.enableRotPatch = editingControl.boolean:create{["x"]=0.60,["y"]=0.72,["width"]=1,["height"]=0.1,["relative"]=true,["parent"]=dialog.generalTab,["label"]="Enable rotation patches"}
---------------------------------
--camera settings
guiCreateLabel ( 0.02, 0.02, 1, 0.1, "Normal camera move speed:", true, dialog.cameraTab )
Expand Down
4 changes: 2 additions & 2 deletions [editor]/editor_gui/client/tutorialdefinition.lua
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ tutorial = {
addEventHandler ("onClientElementDrop",root,tutorialAction.dropped2)
removeEventHandler ("onClientElementSelect",root,tutorialAction.selected1)
end },
{ message = "A tip for selecting objects with poor collisions is to enable 'High sensitivity mode'. Press "..cc.high_sensitivity_mode.." to toggle this. It will detect objects with poor collisions at the expense of accuracy.",
{ message = "A tip for selecting objects with poor collisions is to enable 'High sensitivity mode'. Press "..cc.high_sensitivity_mode.." to toggle this. It will detect objects with poor collisions at the expense of accuracy. If you still cannot select the object, try 'Enable collision patches' in options.",
initiate = function()
setTimer ( tutorialNext, 15000, 1 )
end },
Expand All @@ -158,7 +158,7 @@ tutorial = {
setTimer(tutorialNext,17000,1)
end },
--14
{ message = "You can use the "..cc.mod_rotate.." modifier to switch into rotation mode. While holding down the "..cc.mod_rotate.." key, press the "..cc.element_move_forward..", "..cc.element_move_backward..", "..cc.element_move_left..", "..cc.element_move_right..", "..cc.element_move_upwards.." and "..cc.element_move_downwards.." keys to rotate the element.",
{ message = "You can use the "..cc.mod_rotate.." and "..cc.mod_rotate_local.." modifiers to switch into rotation mode. While holding down the "..cc.mod_rotate.." or "..cc.mod_rotate_local.." key, press the "..cc.element_move_forward..", "..cc.element_move_backward..", "..cc.element_move_left..", "..cc.element_move_right..", "..cc.element_move_upwards.." and "..cc.element_move_downwards.." keys to rotate the element in world ("..cc.mod_rotate..") or local ("..cc.mod_rotate_local..") space.",
initiate = function()
setTimer(tutorialNext,16000,1)
end },
Expand Down
19 changes: 10 additions & 9 deletions [editor]/editor_main/client/controls.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,21 @@ local defaultControls = {
{ name="toggle_cursor", key ="f", friendlyName="Toggle Cursor" },
{ name="select_target_keyboard", key ="mouse1", friendlyName="Select (Keyboard Mode)" },
{ name="select_target_mouse", key ="mouse2", friendlyName="Select (Mouse Mode)" },
{ name="quick_rotate_increase", key ="mouse_wheel_up", friendlyName="+Z Rotate (Rotate Modifier)" },
{ name="quick_rotate_decrease", key ="mouse_wheel_down",friendlyName="-Z Rotate (Rotate Modifier)" },
{ name="quick_rotate_increase", key ="mouse_wheel_up", friendlyName="+Z / Yaw (Rotate Modifier)" },
{ name="quick_rotate_decrease", key ="mouse_wheel_down",friendlyName="-Z / Yaw (Rotate Modifier)" },
{ name="zoom_in", key ="mouse_wheel_down",friendlyName="Increase Select Distance" },
{ name="zoom_out", key ="mouse_wheel_up", friendlyName="Decrease Select Distance" },
{ name="mod_fast_speed", key ="lshift", friendlyName="Fast speed Modifier" },
{ name="mod_slow_speed", key ="lalt", friendlyName="Slow speed Modifier" },
{ name="mod_rotate", key ="lctrl", friendlyName="Rotate Modifier" },
{ name="mod_rotate", key ="lctrl", friendlyName="Rotate Modifier World Space" },
{ name="mod_rotate_local", key ="rctrl", friendlyName="Rotate Modifier Local Space" },
{ name="high_sensitivity_mode", key ="e", friendlyName="High Sensivity Mode" },
{ name="element_move_right", key ="arrow_r", friendlyName="Move Element Right" },
{ name="element_move_left", key ="arrow_l", friendlyName="Move Element Left" },
{ name="element_move_forward", key ="arrow_u", friendlyName="Move Element Forward" },
{ name="element_move_backward", key ="arrow_d", friendlyName="Move Element Backward" },
{ name="element_move_upwards", key ="pgup", friendlyName="Move Element Upwards" },
{ name="element_move_downwards", key ="pgdn", friendlyName="Move Element Downwards" },
{ name="element_move_right", key ="arrow_r", friendlyName="Move Element Right / Yaw" },
{ name="element_move_left", key ="arrow_l", friendlyName="Move Element Left / Yaw" },
{ name="element_move_forward", key ="arrow_u", friendlyName="Move Element Forward / Pitch" },
{ name="element_move_backward", key ="arrow_d", friendlyName="Move Element Backward / Pitch" },
{ name="element_move_upwards", key ="pgup", friendlyName="Move Element Upwards / Roll" },
{ name="element_move_downwards", key ="pgdn", friendlyName="Move Element Downwards / Roll" },
{ name="camera_move_forwards", key ="w", friendlyName="Camera forwards" },
{ name="camera_move_backwards", key ="s", friendlyName="Camera backwards" },
{ name="camera_move_left", key ="a", friendlyName="Camera strafe left" },
Expand Down
8 changes: 7 additions & 1 deletion [editor]/editor_main/client/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ function startWhenLoaded()
end
if isInterfaceLoaded() then
removeEventHandler("onClientResourceStart", root, startWhenLoaded)
loadRotationFixXML()
startEditor()
end
end
Expand Down Expand Up @@ -877,6 +878,9 @@ function dropElement(releaseLock,clonedrop)

-- trigger server selection events
triggerServerEvent("onElementDrop", g_selectedElement)

-- Clear rotation as it can be rotated by other players
clearElementQuat(g_selectedElement)

local droppedElement = g_selectedElement
g_selectedElement = false
Expand Down Expand Up @@ -1281,8 +1285,10 @@ function setMovementType( movementType )
if g_arrowMarker then
if movementType == "move" then
setMarkerColor(g_arrowMarker, 255, 255, 0)
elseif movementType == "rotate" then
elseif movementType == "rotate" or movementType == "rotate_world" then
setMarkerColor(g_arrowMarker, 0, 255, 0)
elseif movementType == "rotate_local" then
setMarkerColor(g_arrowMarker, 0, 255, 255)
end
end
end
Expand Down
139 changes: 139 additions & 0 deletions [editor]/editor_main/client/rotation.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
local rotationFixes = {}
local elementQuat = {}

function loadRotationFixXML()
local xmlRoot = xmlLoadFile("client/rotation_fix.xml")
if not xmlRoot then
outputDebugString("Cannot load rotation_fix.xml")
return false
end

rotationFixes = {}

local models = xmlNodeGetChildren(xmlRoot)
for k,model in ipairs(models) do
local id = tonumber(xmlNodeGetAttribute(model, "id"))
local x = tonumber(xmlNodeGetAttribute(model, "x"))
local y = tonumber(xmlNodeGetAttribute(model, "y"))
local z = tonumber(xmlNodeGetAttribute(model, "z"))
local w = tonumber(xmlNodeGetAttribute(model, "w"))

if id and x and y and z and w then
rotationFixes[id] = {z, y, x, w}
else
outputDebugString("Incorrect entry in rotation_fix.xml")
end
end

xmlUnloadFile(xmlRoot)

return true
end

function clearElementQuat(element)
elementQuat[element] = nil
end

addEventHandler("onClientElementDestroy", root, function()
clearElementQuat(source)
end)

function applyIncrementalRotation(element, axis, angle, world_space)
-- Create the offset angle/axis quaternion
local offset_quat -- Normalized
local arad = math.rad(angle)
local sina = math.sin(arad / 2)

if axis == "yaw" then
offset_quat = {
sina, 0, 0
}
elseif axis == "pitch" then
offset_quat = {
0, sina, 0
}
elseif axis == "roll" then
offset_quat = {
0, 0, sina
}
else
return false
end
offset_quat[4] = math.cos(arad / 2)

-- Get current rotation
local cur_quat
if elementQuat[element] then
cur_quat = elementQuat[element]
else
local euler_rot = {getElementRotation(element, "ZYX")}
-- Is it not rotated ingame
if euler_rot[1] == 0 and euler_rot[2] == 0 and euler_rot[3] == 0 then
-- Is there a fix and are rotation patches enabled
local id = getElementModel(element)
if rotationFixes[id] and exports["editor_gui"]:sx_getOptionData("enableRotPatch") then
-- Rotate from the fix
cur_quat = {unpack(rotationFixes[id])}
else
-- Rotate from 0
cur_quat = {1, 0, 0, 0}
end
else
-- Convert the current euler rotation to quaternion
cur_quat = getQuatFromEuler(euler_rot)
end
end

-- Rotate by the offset quaternion
-- Right or left multiplication for world or local space
if world_space then
cur_quat = quatMul(cur_quat, offset_quat)
else
cur_quat = quatMul(offset_quat, cur_quat)
end
elementQuat[element] = cur_quat

-- Convert to euler and apply
local cur_euler = getEulerFromQuat(cur_quat)
setElementRotation(element, cur_euler[1], cur_euler[2], cur_euler[3], "ZYX")

return unpack(cur_euler)
end

-- https://paroj.github.io/gltut/Positioning/Tut08%20Quaternions.html
function quatMul(a, b)
local result = {}
result[1] = a[4]*b[1] + a[1]*b[4] + a[2]*b[3] - a[3]*b[2]
result[2] = a[4]*b[2] + a[2]*b[4] + a[3]*b[1] - a[1]*b[3]
result[3] = a[4]*b[3] + a[3]*b[4] + a[1]*b[2] - a[2]*b[1]
result[4] = a[4]*b[4] - a[1]*b[1] - a[2]*b[2] - a[3]*b[3]
return result
end

-- http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
function getQuatFromEuler(euler)
local result = {}
local tcos = {}
local tsin = {}
for i=1,3 do
tcos[i] = math.cos(math.rad(euler[i]/2))
tsin[i] = math.sin(math.rad(euler[i]/2))
end
result[1] = tcos[1]*tcos[2]*tcos[3] + tsin[1]*tsin[2]*tsin[3]
result[2] = tsin[1]*tcos[2]*tcos[3] - tcos[1]*tsin[2]*tsin[3]
result[3] = tcos[1]*tsin[2]*tcos[3] + tsin[1]*tcos[2]*tsin[3]
result[4] = tcos[1]*tcos[2]*tsin[3] - tsin[1]*tsin[2]*tcos[3]
return result
end

function getEulerFromQuat(quat)
local result = {}
local q0 = quat[1]
local q1 = quat[2]
local q2 = quat[3]
local q3 = quat[4]
result[1] = math.deg(math.atan2(2*(q0*q1 + q2*q3), 1-2*(q1^2 + q2^2)))
result[2] = math.deg(math.asin(2*(q0*q2 - q3*q1)))
result[3] = math.deg(math.atan2(2*(q0*q3 + q1*q2), 1-2*(q2^2 + q3^2)))
return result
end
Loading