mirror of
https://github.com/Winded/RagdollMover.git
synced 2025-03-04 03:13:36 -05:00
Merge pull request #68 from penolakushari/advsel_shapes
Advanced Select Clarity Adds different shapes for different bone types in advanced selection mode (square - physical, circle - nonphysical, triangle - procedural, rotated triangle - parented) Also bone that is being hovered over in advanced select mode will now pulse its scale so it will be easier to tell what we are about to select. (vlazed)
This commit is contained in:
commit
f4d847360d
@ -1050,16 +1050,40 @@ function DrawEntName(ent)
|
||||
draw.SimpleTextOutlined(name, "RagdollMoverFont", textpos.x, textpos.y, COLOR_RGMGREEN, TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM, OUTLINE_WIDTH, COLOR_RGMBLACK)
|
||||
end
|
||||
|
||||
local RGM_CIRCLE = {
|
||||
{ x = -3, y = -3 },
|
||||
local RGM_SHAPES = {
|
||||
{ -- Square, phys
|
||||
{ x = -5, y = -5 },
|
||||
|
||||
{ x = 0, y = -4 },
|
||||
{ x = 3, y = -3 },
|
||||
{ x = 4, y = 0 },
|
||||
{ x = 3, y = 3 },
|
||||
{ x = 0, y = 4 },
|
||||
{ x = -3, y = 3 },
|
||||
{ x = -4, y = 0 }
|
||||
{ x = 5, y = -5 },
|
||||
{ x = 5, y = 5 },
|
||||
{ x = -5, y = 5 }
|
||||
},
|
||||
|
||||
{ -- Circle, nonphys
|
||||
{ x = -3, y = -3 },
|
||||
|
||||
{ x = 0, y = -4 },
|
||||
{ x = 3, y = -3 },
|
||||
{ x = 4, y = 0 },
|
||||
{ x = 3, y = 3 },
|
||||
{ x = 0, y = 4 },
|
||||
{ x = -3, y = 3 },
|
||||
{ x = -4, y = 0 }
|
||||
},
|
||||
|
||||
{ -- Triangle, procedural
|
||||
{ x = 0, y = -5 },
|
||||
|
||||
{ x = 5, y = 5 },
|
||||
{ x = -5, y = 5 }
|
||||
},
|
||||
|
||||
{ -- 180 rotated triangle, parented
|
||||
{ x = -5, y = -5 },
|
||||
|
||||
{ x = 5, y = -5 },
|
||||
{ x = 0, y = 5 }
|
||||
}
|
||||
}
|
||||
|
||||
local LockGo = Material("icon16/lock_go.png", "alphatest")
|
||||
@ -1165,25 +1189,27 @@ function AdvBoneSelectRender(ent, bonenodes, prevbones, calc, eyePos, eyeVector,
|
||||
prevbones[i] = math.Clamp(math.ceil(fraction * NUM_GRADIENT_POINTS), 1, NUM_GRADIENT_POINTS )
|
||||
end
|
||||
|
||||
local bonetype = bonenodes[ent][i] and bonenodes[ent][i].Type or 1
|
||||
|
||||
if dist < 576 then -- 24 pixels
|
||||
surface.SetDrawColor(COLOR_BRIGHT_YELLOW:Unpack())
|
||||
table.insert(selectedBones, {name, i})
|
||||
else
|
||||
if nodesExist and bonenodes[ent][i] and bonenodes[ent][i].Type and prevbones[i] then
|
||||
surface.SetDrawColor(BONETYPE_COLORS[bonenodes[ent][i].Type][prevbones[i]]:Unpack())
|
||||
if nodesExist and bonetype and prevbones[i] then
|
||||
surface.SetDrawColor(BONETYPE_COLORS[bonetype][prevbones[i]]:Unpack())
|
||||
else
|
||||
surface.SetDrawColor(COLOR_RGMGREEN:Unpack())
|
||||
end
|
||||
end
|
||||
|
||||
local circ = table.Copy(RGM_CIRCLE)
|
||||
for k, v in ipairs(circ) do
|
||||
local shape = table.Copy(RGM_SHAPES[bonetype])
|
||||
for k, v in ipairs(shape) do
|
||||
v.x = v.x + x
|
||||
v.y = v.y + y
|
||||
end
|
||||
|
||||
draw.NoTexture()
|
||||
surface.DrawPoly(circ)
|
||||
surface.DrawPoly(shape)
|
||||
|
||||
if bonenodes[ent][i].bonelock then
|
||||
surface.SetMaterial(LockGo)
|
||||
@ -1210,6 +1236,7 @@ function AdvBoneSelectRender(ent, bonenodes, prevbones, calc, eyePos, eyeVector,
|
||||
local scrH = ScrH() - 100 -- Some padding to keep the bones centered
|
||||
local columns = 0
|
||||
|
||||
local id = #selectedBones
|
||||
-- List the selected bones. If they attempt to overflow through the screen, add the items to another column.
|
||||
for i = 0, #selectedBones - 1 do
|
||||
local yPos = my + (i % maxItemsPerColumn) * (RGMFontSize + 3)
|
||||
@ -1230,9 +1257,13 @@ function AdvBoneSelectRender(ent, bonenodes, prevbones, calc, eyePos, eyeVector,
|
||||
end
|
||||
|
||||
draw.SimpleTextOutlined(selectedBones[i + 1][1], "RagdollMoverFont", xPos, yPos, color, TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM, OUTLINE_WIDTH, COLOR_RGMBLACK)
|
||||
|
||||
-- Modify the data structure of the individual selectedBone so we don't have to worry about indexing later on
|
||||
selectedBones[i + 1] = selectedBones[i + 1][2]
|
||||
id = id + selectedBones[i + 1]
|
||||
end
|
||||
|
||||
return prevbones
|
||||
return prevbones, selectedBones, id
|
||||
end
|
||||
|
||||
function AdvBoneSelectPick(ent, bonenodes)
|
||||
@ -1315,8 +1346,12 @@ function AdvBoneSelectRadialRender(ent, bones, bonenodes, isresetmode)
|
||||
local thisrad = thisang / 180 * math.pi
|
||||
local uix, uiy = (math.sin(thisrad) * 250 * modifier), (math.cos(thisrad) * -250 * modifier)
|
||||
local color = COLOR_WHITE
|
||||
if bonenodes and bonenodes[ent] and bonenodes[ent][bone] and bonenodes[ent][bone].Type then
|
||||
color = BONETYPE_COLORS[bonenodes[ent][bone].Type][1]
|
||||
|
||||
local nodecheck = (bonenodes and bonenodes[ent] and bonenodes[ent][bone] and bonenodes[ent][bone].Type) and true or false
|
||||
local bonetype = bonenodes[ent][bone] and bonenodes[ent][bone].Type or 1
|
||||
|
||||
if nodecheck then
|
||||
color = BONETYPE_COLORS[bonetype][1]
|
||||
end
|
||||
uix, uiy = uix + midw, uiy + midh
|
||||
|
||||
@ -1328,8 +1363,8 @@ function AdvBoneSelectRadialRender(ent, bones, bonenodes, isresetmode)
|
||||
local pos = ent:GetBonePosition(bone)
|
||||
pos = pos:ToScreen()
|
||||
|
||||
local circ = table.Copy(RGM_CIRCLE)
|
||||
for k, v in ipairs(circ) do
|
||||
local shape = table.Copy(RGM_SHAPES[bonetype])
|
||||
for k, v in ipairs(shape) do
|
||||
v.x = v.x + pos.x
|
||||
v.y = v.y + pos.y
|
||||
end
|
||||
@ -1339,15 +1374,11 @@ function AdvBoneSelectRadialRender(ent, bones, bonenodes, isresetmode)
|
||||
color = COLOR_BRIGHT_YELLOW
|
||||
SelectedBone = bone
|
||||
else
|
||||
if bonenodes and bonenodes[ent] and bonenodes[ent][bone] and bonenodes[ent][bone].Type then
|
||||
surface.SetDrawColor(BONETYPE_COLORS[bonenodes[ent][bone].Type][1]:Unpack())
|
||||
else
|
||||
surface.SetDrawColor(COLOR_RGMGREEN:Unpack())
|
||||
end
|
||||
surface.SetDrawColor(BONETYPE_COLORS[bonetype][1]:Unpack())
|
||||
end
|
||||
|
||||
draw.NoTexture()
|
||||
surface.DrawPoly(circ)
|
||||
surface.DrawPoly(shape)
|
||||
|
||||
local ytextoffset = -14
|
||||
if uiy > (midh + 30) then ytextoffset = RGMFontSize + 14 end
|
||||
@ -1365,6 +1396,7 @@ function AdvBoneSelectRadialRender(ent, bones, bonenodes, isresetmode)
|
||||
draw.SimpleTextOutlined(name, "RagdollMoverFont", uix + xtextoffset, uiy + ytextoffset, color, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, OUTLINE_WIDTH, COLOR_RGMBLACK)
|
||||
end
|
||||
|
||||
return {SelectedBone}, SelectedBone and 1 + SelectedBone or 0
|
||||
else
|
||||
local bone = bones[1]
|
||||
local btype = 2
|
||||
@ -1375,8 +1407,8 @@ function AdvBoneSelectRadialRender(ent, bones, bonenodes, isresetmode)
|
||||
local pos = ent:GetBonePosition(bone)
|
||||
pos = pos:ToScreen()
|
||||
|
||||
local circ = table.Copy(RGM_CIRCLE)
|
||||
for k, v in ipairs(circ) do
|
||||
local shape = table.Copy(RGM_SHAPES[btype])
|
||||
for k, v in ipairs(shape) do
|
||||
v.x = v.x + pos.x
|
||||
v.y = v.y + pos.y
|
||||
end
|
||||
@ -1384,7 +1416,7 @@ function AdvBoneSelectRadialRender(ent, bones, bonenodes, isresetmode)
|
||||
surface.SetDrawColor(COLOR_WHITE:Unpack())
|
||||
|
||||
draw.NoTexture()
|
||||
surface.DrawPoly(circ)
|
||||
surface.DrawPoly(shape)
|
||||
|
||||
local boneoptions = btype == 1 and FeaturesPhys or FeaturesNPhys
|
||||
local count = #boneoptions
|
||||
@ -1451,7 +1483,7 @@ function AdvBoneSelectRadialRender(ent, bones, bonenodes, isresetmode)
|
||||
|
||||
k = k + 1
|
||||
end
|
||||
|
||||
return {bone}, 1 + bone
|
||||
end
|
||||
end
|
||||
|
||||
@ -1460,6 +1492,19 @@ function AdvBoneSelectRadialPick()
|
||||
return SelectedBone
|
||||
end
|
||||
|
||||
do
|
||||
local pi, sin = math.pi, math.sin
|
||||
function AdvBoneSelectPulse(ent, bones, boneScales)
|
||||
for _, bone in ipairs(bones) do
|
||||
if not bone then continue end
|
||||
|
||||
if boneScales[bone] then
|
||||
ent:ManipulateBoneScale(bone, boneScales[bone] + VECTOR_ONE * 0.05 * sin(2.666 * pi * RealTime()))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function DrawBoneConnections(ent, bone)
|
||||
local mainpos = ent:GetBonePosition(bone)
|
||||
if not mainpos then
|
||||
|
@ -2527,6 +2527,42 @@ end)
|
||||
|
||||
local GizmoWidth, SkeletonDraw
|
||||
|
||||
-- A singleton to track bone manipulate state, particularly scale. Useful if we want to use
|
||||
-- the bone manipulate state to indicate something (such as hovering over a bone in advanced bone select)
|
||||
local ClientBoneState = {
|
||||
entity = NULL,
|
||||
Scales = {},
|
||||
UpdateBoneScales = function(self)
|
||||
for i = 0, self.entity:GetBoneCount() - 1 do
|
||||
self.Scales[i] = self.entity:GetManipulateBoneScale(i)
|
||||
end
|
||||
end,
|
||||
ResetBoneScales = function(self)
|
||||
for i = 0, self.entity:GetBoneCount() - 1 do
|
||||
self.Scales[i] = VECTOR_SCALEDEF
|
||||
end
|
||||
end,
|
||||
SetBoneScales = function(self, scale)
|
||||
for i = 0, self.entity:GetBoneCount() - 1 do
|
||||
self.Scales[i] = scale
|
||||
end
|
||||
end,
|
||||
SetBoneScale = function(self, bone, scale, recursive)
|
||||
self.Scales[bone] = scale or self.entity:GetManipulateBoneScale(bone)
|
||||
|
||||
local childBones = self.entity:GetChildBones(bone)
|
||||
if recursive and #childBones > 0 then
|
||||
for _, cbone in ipairs(childBones) do
|
||||
self:SetBoneScale(cbone, scale, true)
|
||||
end
|
||||
end
|
||||
end,
|
||||
SetEntity = function(self, newEntity)
|
||||
self.entity = newEntity
|
||||
self:UpdateBoneScales()
|
||||
end
|
||||
}
|
||||
|
||||
do
|
||||
|
||||
local ConVars = {
|
||||
@ -3062,6 +3098,7 @@ end
|
||||
local function RGMResetAllBones()
|
||||
if not RAGDOLLMOVER[pl] or not RAGDOLLMOVER[pl].Entity then return end
|
||||
|
||||
ClientBoneState:ResetBoneScales()
|
||||
NetStarter.rgmResetAllBones()
|
||||
net.WriteEntity(RAGDOLLMOVER[pl].Entity)
|
||||
net.SendToServer()
|
||||
@ -3409,6 +3446,7 @@ NetStarter = {
|
||||
local NodeFunctions = {
|
||||
|
||||
function(ent, id) -- 1 nodeReset
|
||||
ClientBoneState:SetBoneScale(id, VECTOR_SCALEDEF)
|
||||
NetStarter.rgmResetAll()
|
||||
net.WriteEntity(ent)
|
||||
net.WriteUInt(id, 10)
|
||||
@ -3433,6 +3471,7 @@ local NodeFunctions = {
|
||||
end,
|
||||
|
||||
function(ent, id) -- 4 nodeResetScale
|
||||
ClientBoneState:SetBoneScale(id, VECTOR_SCALEDEF)
|
||||
NetStarter.rgmResetScale()
|
||||
net.WriteEntity(ent)
|
||||
net.WriteBool(false)
|
||||
@ -3441,6 +3480,7 @@ local NodeFunctions = {
|
||||
end,
|
||||
|
||||
function(ent, id) -- 5 nodeResetCh
|
||||
ClientBoneState:SetBoneScale(id, VECTOR_SCALEDEF, true)
|
||||
NetStarter.rgmResetAll()
|
||||
net.WriteEntity(ent)
|
||||
net.WriteUInt(id, 10)
|
||||
@ -3465,6 +3505,7 @@ local NodeFunctions = {
|
||||
end,
|
||||
|
||||
function(ent, id) -- 8 nodeResetScaleCh
|
||||
ClientBoneState:SetBoneScale(id, VECTOR_SCALEDEF, true)
|
||||
NetStarter.rgmResetScale()
|
||||
net.WriteEntity(ent)
|
||||
net.WriteBool(true)
|
||||
@ -3473,6 +3514,7 @@ local NodeFunctions = {
|
||||
end,
|
||||
|
||||
function(ent, id) -- 9 nodeScaleZero
|
||||
ClientBoneState:SetBoneScale(id, vector_origin)
|
||||
NetStarter.rgmScaleZero()
|
||||
net.WriteEntity(ent)
|
||||
net.WriteBool(false)
|
||||
@ -3481,6 +3523,7 @@ local NodeFunctions = {
|
||||
end,
|
||||
|
||||
function(ent, id) -- 10 nodeScaleZeroCh
|
||||
ClientBoneState:SetBoneScale(id, vector_origin, true)
|
||||
NetStarter.rgmScaleZero()
|
||||
net.WriteEntity(ent)
|
||||
net.WriteBool(true)
|
||||
@ -4321,7 +4364,7 @@ end
|
||||
|
||||
local function UpdateManipulationSliders(boneid, ent)
|
||||
if not IsValid(Pos1) then return end
|
||||
local pos, rot, scale = ent:GetManipulateBonePosition(boneid), ent:GetManipulateBoneAngles(boneid), ent:GetManipulateBoneScale(boneid)
|
||||
local pos, rot, scale = ent:GetManipulateBonePosition(boneid), ent:GetManipulateBoneAngles(boneid), ClientBoneState.Scales[boneid] or ent:GetManipulateBoneScale(boneid)
|
||||
rot:Normalize()
|
||||
|
||||
ManipSliderUpdating = true
|
||||
@ -4419,6 +4462,7 @@ local NETFUNC = {
|
||||
physchildren[i] = net.ReadEntity()
|
||||
end
|
||||
|
||||
ClientBoneState:SetEntity(selectedent)
|
||||
if IsValid(BonePanel) then
|
||||
RGMBuildBoneMenu(ents, selectedent, BonePanel)
|
||||
end
|
||||
@ -4468,6 +4512,7 @@ local NETFUNC = {
|
||||
physchildren[i] = net.ReadEntity()
|
||||
end
|
||||
|
||||
ClientBoneState:SetEntity(ent)
|
||||
if IsValid(BonePanel) then
|
||||
RGMBuildBoneMenu(ents, ent, BonePanel)
|
||||
end
|
||||
@ -4707,6 +4752,11 @@ function TOOL:Think()
|
||||
local nowpressed = input.IsMouseDown(MOUSE_LEFT) or input.IsMouseDown(MOUSE_RIGHT)
|
||||
local isright = input.IsMouseDown(MOUSE_RIGHT)
|
||||
|
||||
-- Track that we are moving a bone, and store its bone scale.
|
||||
if plTable.Moving then
|
||||
ClientBoneState:UpdateBoneScales()
|
||||
end
|
||||
|
||||
if nowpressed and not LastPressed and op == 2 then -- left click is a predicted function, so leftclick wouldn't work in singleplayer since i need data from client
|
||||
local ent = plTable.Entity
|
||||
|
||||
@ -4893,6 +4943,7 @@ hook.Add("KeyPress", "rgmSwitchSelectionMode", function(pl, key)
|
||||
end)
|
||||
|
||||
local BoneColors = {}
|
||||
local BoneScaleGroup, LastId, LastOp = {}, 0, 0
|
||||
local LastSelectThink, LastEnt = 0, nil
|
||||
|
||||
function TOOL:DrawHUD()
|
||||
@ -4952,16 +5003,17 @@ function TOOL:DrawHUD()
|
||||
rgm.DrawSkeleton(ent, nodes)
|
||||
end
|
||||
|
||||
local id = 0
|
||||
if self:GetOperation() == 2 and IsValid(ent) then
|
||||
local timecheck = (thinktime - LastSelectThink) > 0.1
|
||||
local calc = ( not LastEnt or LastEnt ~= ent ) or timecheck
|
||||
|
||||
if self:GetStage() == 0 then
|
||||
BoneColors = rgm.AdvBoneSelectRender(ent, nodes, BoneColors, calc, eyepos, viewvec, fov)
|
||||
BoneColors, BoneScaleGroup, id = rgm.AdvBoneSelectRender(ent, nodes, BoneColors, calc, eyepos, viewvec, fov)
|
||||
else
|
||||
rgm.AdvBoneSelectRadialRender(ent, plTable.SelectedBones, nodes, ResetMode)
|
||||
BoneScaleGroup, id = rgm.AdvBoneSelectRadialRender(ent, plTable.SelectedBones, nodes, ResetMode)
|
||||
end
|
||||
|
||||
|
||||
LastEnt = ent
|
||||
if timecheck then
|
||||
LastSelectThink = thinktime
|
||||
@ -4978,6 +5030,40 @@ function TOOL:DrawHUD()
|
||||
rgm.DrawEntName(HoveredEnt)
|
||||
end
|
||||
|
||||
-- Advanced Bone Select visual indicators
|
||||
local opsDifferent = LastOp ~= self:GetOperation()
|
||||
if IsValid(ent) then
|
||||
-- We need to track the original manipulatebonescale (scales for short) while we also use the ManipulateBoneScale function
|
||||
|
||||
if opsDifferent then
|
||||
if self:GetOperation() == 2 then
|
||||
-- If we began advanced bone select, store the original scales
|
||||
ClientBoneState:UpdateBoneScales()
|
||||
else
|
||||
-- If we just left it, restore the original scales
|
||||
for i = 0, ent:GetBoneCount() - 1 do
|
||||
ent:ManipulateBoneScale(i, ClientBoneState.Scales[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetOperation() == 2 then
|
||||
-- If we're hovering over a different bone
|
||||
if LastId ~= id then
|
||||
-- Reset the bone to the original scale. This prevents us from adding or subtracting scales from
|
||||
-- previous iterations of using advanced bone select
|
||||
for i = 0, ent:GetBoneCount() - 1 do
|
||||
ent:ManipulateBoneScale(i, ClientBoneState.Scales[i])
|
||||
end
|
||||
end
|
||||
|
||||
-- Show selected bone, regardless if any are selected
|
||||
rgm.AdvBoneSelectPulse(ent, BoneScaleGroup, ClientBoneState.Scales)
|
||||
end
|
||||
|
||||
LastId = id
|
||||
end
|
||||
LastOp = self:GetOperation()
|
||||
end
|
||||
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user