File size: 3,611 Bytes
b6a38d7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
DefineClass.XStickToObjsBase = {
__parents = { "XObjectPlacementHelper" },
InXPlaceObjectTool = true,
InXSelectObjectsTool = true,
AllowRotationAfterPlacement = true,
HasSnapSetting = true,
pivot_obj_id = false,
intersection_class = "WallSlab",
set_angle = true,
}
function XStickToObjsBase:StartMoveObjects(mouse_pos, objects)
local cur_pos = GetTerrainCursor()
local bestIp = false
local bestId = -1
local eye = camera.GetEye()
local cursor = ScreenToGame(mouse_pos)
local sp = eye
local ep = (cursor - eye) * 1000 + cursor
self.init_move_positions = {}
self.init_orientations = {}
for i, o in ipairs(objects) do
local hisPos = o:GetPos()
if not hisPos:IsValid() then
o:SetPos(cur_pos)
hisPos = cur_pos
end
self.init_move_positions[i] = hisPos
self.init_orientations[i] = { o:GetOrientation() }
local ip1, ip2 = ClipSegmentWithBox3D(sp, ep, o)
if ip1 and (bestId == -1 or IsCloser(sp, ip1, bestIp)) then
bestIp = ip1
bestId = i
end
end
if bestId == -1 then
bestId = 1 --that sux, no obj crossed the ray from camera
end
self.pivot_obj_id = bestId
self.init_drag_position = objects[bestId]:GetPos():SetTerrainZ()
end
function XStickToObjsBase:MoveObjects(mouse_pos, objects)
local vMove = (GetTerrainCursor() - self.init_drag_position):SetZ(0)
for i, obj in ipairs(objects) do
local offset = self.init_move_positions[i] - self.init_move_positions[self.pivot_obj_id]
if not offset:z() then
offset = offset:SetZ(0)
end
local eye = camera.GetEye()
local cursor = ScreenToGame(mouse_pos)
local sp = eye + offset
local ep = (cursor - eye) * 1000 + cursor + offset
local objs = IntersectObjectsOnSegment(sp, ep, 0, self.intersection_class, function(o)
if not o.isVisible then
return rawget(o, "wall_obj") == obj
end
return true
end)
--[[DbgClear()
print(eye)
DbgAddVector(eye, cursor - eye, RGB(255, 0, 0))
DbgAddVector(sp, ep - sp)
if objs and objs[1] then
DbgAddBox(objs[1]:GetObjectBBox())
end]]
if objs and #objs > 0 then
local closest = objs[1]
local p1, p2 = ClipSegmentWithBox3D(sp, ep, closest)
local ip = closest:GetPos()
if p1 then
ip = p1 == sp and p2 or p1
end
local angle = closest:GetAngle()
local x, y, z
if XEditorSettings:GetSnapEnabled() then
x, y, z, angle = WallWorldToVoxel(ip:x(), ip:y(), ip:z(), angle)
x, y, z = WallVoxelToWorld(x, y, z, angle)
else
x, y, z = ip:xyz()
end
if IsKindOf(obj, "AlignedObj") then
obj:AlignObj(point(x, y, z), self.set_angle and angle or nil)
else
if self.set_angle then
obj:SetPosAngle(x, y, z, angle)
else
obj:SetPos(x, y, z)
end
end
else
local pos = (self.init_move_positions[i] + vMove):SetTerrainZ()
if IsKindOf(obj, "AlignedObj") then
obj:AlignObj(pos)
else
obj:SetPos(pos)
end
end
end
Msg("EditorCallback", "EditorCallbackMove", objects)
end
DefineClass.XStickToWallsHelper = {
__parents = { "XStickToObjsBase" },
Title = "Stick to walls (Y)",
Description = false,
ActionSortKey = "6",
ActionIcon = "CommonAssets/UI/Editor/Tools/StickToWall.tga",
ActionShortcut = "Y",
UndoOpName = "Stuck %d object(s) to wall",
intersection_class = "WallSlab",
set_angle = true,
}
DefineClass.XStickToFloorsHelper = {
__parents = { "XStickToObjsBase" },
Title = "Stick to floors (U)",
Description = false,
ActionSortKey = "7",
ActionIcon = "CommonAssets/UI/Editor/Tools/StickToFloor.tga",
ActionShortcut = "U",
UndoOpName = "Stuck %d object(s) to floor",
intersection_class = "FloorSlab",
set_angle = false,
}
|