Files
wnsrc/lua/pac3/editor/client/select.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

400 lines
8.7 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local L = pace.LanguageString
pace.selectControl = {}
local selectControl = pace.selectControl
function selectControl.VecToScreen(vec)
return vec:ToScreen()
end
function selectControl.GetMousePos()
return input.GetCursorPos()
end
function selectControl.GUIMousePressed(mcode) end
function selectControl.GUIMouseReleased(mcode) end
function selectControl.HUDPaint() end
local RENDER_ATTACHMENTS = CreateConVar('pac_render_attachments', '0', {FCVAR_ARCHIVE}, 'Render attachments when selecting bones')
function pace.ToggleRenderAttachments()
RunConsoleCommand('pac_render_attachments', RENDER_ATTACHMENTS:GetBool() and '0' or '1')
end
local font_name = "pac_select"
local font_scale = 0.05
surface.CreateFont(
font_name,
{
font = "DejaVu Sans",
size = 500 * font_scale,
weight = 800,
antialias = true,
additive = true,
}
)
local font_name_blur = font_name.."_blur"
surface.CreateFont(
font_name_blur,
{
font = "DejaVu Sans",
size = 500 * font_scale,
weight = 800,
antialias = true,
additive = false,
blursize = 3,
}
)
local function draw_text(text, color, x, y)
surface.SetFont(font_name_blur)
surface.SetTextColor(color_black)
for i=1, 10 do
surface.SetTextPos(x,y)
surface.DrawText(text)
end
surface.SetFont(font_name)
surface.SetTextColor(color)
surface.SetTextPos(x,y)
surface.DrawText(text)
end
local holding
local area = 20
local x, y = 0, 0
local siz = 5
local sizeSelected = 12
local sizeHovered = 7
local currentSizeSelected = 5
local hR = 83
local hG = 167
local hB = 213
local sR = 148
local sG = 67
local sB = 201
local white = surface.GetTextureID("gui/center_gradient.vtf")
function pace.DrawHUDText(x, y, text, lx, ly, mx, my, selected, line_color)
mx = mx or gui.MouseX()
my = my or gui.MouseY()
local color = selected and Color(128, 255, 128) or color_white
surface.SetDrawColor(line_color or color)
pace.util.DrawLine(
Lerp(0.025, mx, x + lx),
Lerp(0.025, my, y + ly),
Lerp(0.05, x + lx, mx),
Lerp(0.05, y + ly, my),
selected and 4 or 1
)
surface.SetFont(font_name)
local w, h = surface.GetTextSize(text)
draw_text(text, color, (x + lx) - w / 2, (y + ly) - h / 2)
end
local function checkVisible(pos)
return
x > pos.x - area and x < pos.x + area and
y > pos.y - area and y < pos.y + area
end
local function DrawSelection(pos, r, g, b, sizeToUse)
if not pos.visible then return false end
surface.SetDrawColor(r, g, b, 255)
surface.DrawOutlinedRect(pos.x - (sizeToUse * 0.5), pos.y - (sizeToUse * 0.5), sizeToUse, sizeToUse)
surface.SetDrawColor(0, 0, 0, 255)
surface.DrawOutlinedRect(pos.x - (sizeToUse * 0.5) - 1, pos.y - (sizeToUse * 0.5) - 1, sizeToUse + 2, sizeToUse + 2)
return checkVisible(pos)
end
function pace.DrawSelection(pos)
return DrawSelection(pos, 255, 255, 255, siz)
end
function pace.DrawSelectionHovered(pos)
return DrawSelection(pos, hR, hG, hB, sizeHovered)
end
function pace.DrawSelectionSelected(pos)
return DrawSelection(pos, sR, sG, sB, sizeSelected + math.sin(RealTime() * 4) * 3)
end
local function get_friendly_name(ent)
local name = ent.Nick and ent:Nick()
if not name or name == "" then
name = language.GetPhrase(ent:GetClass())
end
return ent:EntIndex() .. " - " .. name
end
function pace.StopSelect()
pac.RemoveHook("GUIMouseReleased", "draw_select")
pac.RemoveHook("GUIMousePressed", "draw_select")
pac.RemoveHook("HUDPaint", "draw_select")
function selectControl.GUIMousePressed(mcode) end
function selectControl.GUIMouseReleased(mcode) end
function selectControl.HUDPaint() end
timer.Simple(0.1, function()
pace.IsSelecting = false
end)
end
local function select_something(tblin, check, getpos, getfriendly, callback, selectCallback, poll)
local data
local selected = {}
holding = nil
local function GUIMousePressed(mcode)
if mcode == MOUSE_LEFT then
if not selected then
pace.StopSelect()
end
holding = Vector(selectControl.GetMousePos())
end
end
local function GUIMouseReleased(mcode)
if mcode == MOUSE_LEFT then
if data then
data.dist = nil
callback(data)
pace.StopSelect()
end
end
end
local function HUDPaint()
if poll and not poll() then pace.StopSelect() return end
surface.SetAlphaMultiplier(1)
x, y = selectControl.GetMousePos()
local tbl = {}
for key, value in pairs(tblin) do
if check(key, value) then
goto CONTINUE
end
local pos = selectControl.VecToScreen(getpos(key, value))
local friendly = getfriendly(key, value)
if checkVisible(pos) then
table.insert(tbl, {pos = pos, friendly = friendly, dist = pace.util.FastDistance2D(pos.x, pos.y, x, y), key = key, value = value})
else
local hit = false
if selected then
for i, val in ipairs(selected) do
if val.key == key and val.value == value then
hit = true
break
end
end
end
if not hit then
pace.DrawSelection(pos)
end
end
::CONTINUE::
end
if tbl[1] then
table.sort(tbl, function(a, b) return a.dist < b.dist end)
if not selected or not holding then
selected = {}
local first = tbl[1]
for i, v in ipairs(tbl) do
if math.Round(v.dist / 200) == math.Round(first.dist / 200) then
table.insert(selected, v)
else
break
end
end
if #selected < 3 and first.dist < area / 4 then
selected = {first}
end
end
elseif not holding then
selected = nil
end
if selected then
if #selected == 1 then
local v = selected[1]
pace.DrawSelectionSelected(v.pos)
pace.DrawHUDText(v.pos.x, v.pos.y, L(v.friendly), 0, -30, v.pos.x, v.pos.y)
data = v
if selectCallback then selectCallback(v.key, v.value) end
else
table.sort(selected, function(a,b) return L(a.friendly) > L(b.friendly) end)
local found
local rad = math.min(#selected * 30, 400)
for k, v in ipairs(selected) do
local sx = math.sin((k / #selected) * math.pi * 2) * rad
local sy = math.cos((k / #selected) * math.pi * 2) * rad
v.pos = selectControl.VecToScreen(getpos(v.key, v.value))
if holding and pace.util.FastDistance2D(v.pos.x + sx, v.pos.y + sy, x, y) < area then
pace.DrawSelectionSelected(v.pos)
pace.DrawHUDText(v.pos.x, v.pos.y, L(v.friendly), sx, sy, v.pos.x, v.pos.y, true)
found = v
if selectCallback then selectCallback(v.key, v.value) end
else
pace.DrawSelectionHovered(v.pos)
pace.DrawHUDText(v.pos.x, v.pos.y, L(v.friendly), sx, sy, v.pos.x, v.pos.y, false, Color(255, 255, 255, 128))
end
end
data = found
end
end
end
pace.IsSelecting = true
selectControl.HUDPaint = HUDPaint
selectControl.GUIMousePressed = GUIMousePressed
selectControl.GUIMouseReleased = GUIMouseReleased
pac.AddHook("GUIMousePressed", "draw_select", selectControl.GUIMousePressed)
pac.AddHook("GUIMouseReleased", "draw_select", selectControl.GUIMouseReleased)
pac.AddHook("HUDPaint", "draw_select", selectControl.HUDPaint)
end
function pace.SelectBone(ent, callback, only_movable)
if not ent or not ent:IsValid() then return end
local tbl = table.Copy(pac.GetModelBones(ent))
if only_movable then
local models = ent:GetModel() and util.GetModelMeshes(ent:GetModel())
if models then
for k, v in pairs(tbl) do
if not v.bone then
tbl[k] = nil
end
end
end
for k, v in pairs(tbl) do
if v.is_special or not RENDER_ATTACHMENTS:GetBool() and v.is_attachment then
tbl[k] = nil
end
end
end
select_something(
tbl,
function() end,
function(k, v)
return pac.GetBonePosAng(ent, k)
end,
function(k, v)
return k
end,
callback,
function (key, val)
if val.is_special or val.is_attachment then return end
ent.pac_bones_select_target = val.i
end,
function() return ent:IsValid() end
)
end
function pace.SelectPart(parts, callback)
select_something(
parts,
function(_, part)
return part:IsHidden() and part:GetShowInEditor()
end,
function(_, part)
if part.GetDrawPosition then
return part:GetDrawPosition()
end
local owner = part:GetOwner()
if owner:IsValid() then
return owner:GetPos()
end
owner = part:GetPlayerOwner()
if owner:IsValid() then
return owner:GetPos()
end
end,
function(_, part)
return part:GetName()
end,
function(data) return callback(data.value) end
)
end
function pace.SelectEntity(callback)
select_something(
ents.GetAll(),
function(_, ent)
return
not ent:IsValid() or
ent:EntIndex() == -1
end,
function(_, ent)
return ent:EyePos()
end,
function(_, ent)
return get_friendly_name(ent)
end,
function(data) return callback(data.value) end
)
end