mirror of
https://github.com/Winded/RagdollMover.git
synced 2025-03-04 03:13:36 -05:00
Add visual indicator of advanced selected bones (#15)
* Add visual indicator of advanced selected bones + Add bone scaling indicator when the user hovers over a bone using advanced bone select. Bones also scale when selecting from a set of bones, or when looking through the bone options * Rename SelectedBones -> BoneScaleGroup; revert scale amplitude * Synchronize bone scale with UI - Change `CurrentBoneScales` into a `ClientBoneState` singleton which stores scales and the selected entity. We call methods on this singleton to ensure that the visual bone scaling indicator works as intended, while also ensuring that the UI stays in sync with that state
This commit is contained in:
parent
4722de62f9
commit
6134e33504
@ -1236,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)
|
||||
@ -1256,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)
|
||||
@ -1391,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
|
||||
@ -1477,7 +1483,7 @@ function AdvBoneSelectRadialRender(ent, bones, bonenodes, isresetmode)
|
||||
|
||||
k = k + 1
|
||||
end
|
||||
|
||||
return {bone}, 1 + bone
|
||||
end
|
||||
end
|
||||
|
||||
@ -1486,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