#1459: Pose Studio dials turn from the bone's current pose, and the ring finger moves on its own #1479

Open
TheSlowly wants to merge 2 commits from TheSlowly/Slipstream:pose-dials-1459 into main
Collaborator

Fixes #1459.

  • Ring finger: mHandRing1Left/Right in bone_axes.xml were copies of the foot entries with followers that wrote Ring1's full rotation into Ring2/Ring3, so the whole finger curled ~3x and Ring2/3 edits were overwritten. Removed; the ring finger uses the default model like the other fingers. Saved and shared poses store quaternions, so nothing stored changes.
  • First drag on an animated bone no longer replaces the pose with (v, 0, 0): the press decodes the live frame and the drag turns from it. Values past a dial's range aren't clamped (only turning further outward stops).
  • No 180-degree flip at Y = 90 on arm/leg bones (tiny nudge off the pole in the math; shown values unchanged).
  • Dial input: drags are relative to the press, no pinning below the centre line, Shift = fine, reset only on the centre dot and only when the value changes; capture loss commits the drag.

Tests: slposedialmath_test.cpp (standalone g++), pose_dials_1459_checks.py in indra/newview/tests.

Fixes #1459. - Ring finger: mHandRing1Left/Right in bone_axes.xml were copies of the foot entries with followers that wrote Ring1's full rotation into Ring2/Ring3, so the whole finger curled ~3x and Ring2/3 edits were overwritten. Removed; the ring finger uses the default model like the other fingers. Saved and shared poses store quaternions, so nothing stored changes. - First drag on an animated bone no longer replaces the pose with (v, 0, 0): the press decodes the live frame and the drag turns from it. Values past a dial's range aren't clamped (only turning further outward stops). - No 180-degree flip at Y = 90 on arm/leg bones (tiny nudge off the pole in the math; shown values unchanged). - Dial input: drags are relative to the press, no pinning below the centre line, Shift = fine, reset only on the centre dot and only when the value changes; capture loss commits the drag. Tests: `slposedialmath_test.cpp` (standalone g++), `pose_dials_1459_checks.py` in indra/newview/tests.
Ring finger: bone_axes.xml gave mHandRing1Left/Right the foot's dial model with Ring2 and
Ring3 as followers, and setBoneAngles wrote Ring1's whole rotation into both on every turn.
The finger curled three times the dialled angle and any edit to Ring2/Ring3 was overwritten.
Both entries are gone; the ring finger uses the default model like the other fingers. Saved
and shared poses store rotations, not dial values, so nothing stored changes meaning.

First turn on an animated bone: an unedited bone showed dial zero and the first turn applied
(value, 0, 0), snapping the bone from the animation's frame about an axis unrelated to the
dial. SLPoseStudio::getShownBoneAngles decodes an unedited bone's current rotation (the frame
Freeze holds, or the playing animation's) into dial values; the dials show them and applyAxis
starts from them, so only the turned axis moves.

180-degree flip at Y = +90: on leg-model bones (arms, legs, collars, wrists) an applied y of
exactly 180 degrees took the generator's "y >= 180" pre-rotation without the sphere remap
that goes with it, turning the bone 180 degrees about its own length. That is the elbow's end
stop, and any 5/10/15/45 snap on a shoulder, hip or collar. The generator math moved
unchanged into the dependency-free slposedialmath.h; dialToQuat moves that one value 1e-6
rad off the pole. Every other value is bit-identical to before.

Dial input: a press jumped the value to the clicked point, the area below the centre line
pinned it to an end, and a hub 30% of the ring wide (or a click on the knob) reset it. The
dial now turns relative to the press (a click alone changes nothing and commits nothing,
the turn carries on below the line), Shift turns it at a tenth of the speed, and only a click
on the small centre dot resets. Tool tips updated.

Test-Plan:
    g++ -std=c++17 -Wall -Wextra -Werror slposedialmath_test.cpp -o dial_test && ./dial_test
    (in indra/newview/tests; before the pole fix: "elbow Y 89.99 -> 90: 179.990 deg" and an
    assertion failure; the drag checks failed to build before SLPoseDial existed; ok after)
    python3 indra/newview/tests/pose_dials_1459_checks.py --source-root .
    (failed on each of ring entries, getShownBoneAngles, click sets value, tool tips; ok after)
    clang-cl /Zs on slposemath, slposestudio, slposedialctrl, slfloaterposestudio: clean
    In world, Pose Studio, Hands view: turn Ring 1 Left alone; Ring 2 and Ring 3 do not move
    with it, and an earlier edit to Ring 2 stays.
    With an animation playing (Freeze on, then off), pick an unedited arm bone and drag one
    dial a little: the bone turns from where it was, no jump; the other dials show its pose.
    Elbow Left: drag Y to its end (90); the forearm does not flip over. Snap 5, shoulder Y 90:
    no flip.
    Click a dial ring without dragging: the value and the bone do not change. Drag below the
    centre line: the value keeps turning, no jump to an end. Shift+drag turns slowly.
    Click the centre dot: that axis resets to 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the animation playing, a dial's value came from the last refresh while applyAxis took
the other axes from a fresh decode, so the first turn still jumped. Refresh is held off
while dials apply, so the next axis jumped the same way. The dial now has a press signal.
On a press the floater decodes the live frame once and puts that decode on all three dials
and spinners. The drag starts from that value, and applyAxis applies the turn on top of the
same decode. After every apply the dials and spinners show the values actually applied.

A decoded value past a dial's end was clamped when the dial took it, so the first turn snapped
the bone to the end stop and the spinner disagreed with the dial. The dial now keeps the value
and draws the pointer at the end stop. A drag's limits are the range widened to its start
value (SLPoseDial::dragLimits), so only turning further outward is stopped. The scroll wheel
follows the same rule.

Smaller fixes:
- Clicking the centre dot at zero no longer commits. It used to mark an unedited bone edited,
  add an undo step and send a sync, and a double-click did all that twice. The scroll wheel
  no longer commits twice.
- Losing the mouse capture mid-drag ends the drag and commits it.
- The reset dot sits higher and its hit area stays above the value label.

Test-Plan:
    g++ -std=c++17 -Wall -Wextra -Werror slposedialmath_test.cpp -o dial_test && ./dial_test
    (in indra/newview/tests; failed to build before dragLimits / shownValue / the limited
    dragValue existed; ok after)
    python3 indra/newview/tests/pose_dials_1459_checks.py --source-root .
    (failed in turn on: no press signal, set value clamped, reset at zero commits, capture
    loss unhandled, hub over the label; ok after)
    clang-cl /Zs on slposemath, slposestudio, slposedialctrl, slfloaterposestudio: clean
    In world, Freeze off, an animation playing: pick an unedited arm bone, drag X a little,
    then Y. Neither drag jumps, and the other dials match the bone after each.
    A bone whose pose decodes past a dial's end: the dial shows the real number at its end
    stop, matching the spinner. Dragging inward moves from there; outward does not move.
    Click the centre dot on an axis already at 0, and double-click it: the bone stays
    unedited (grey dot), no undo step.
    Start a drag and alt-tab away mid-drag: the turn is kept and committed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u pose-dials-1459:TheSlowly-pose-dials-1459
git switch TheSlowly-pose-dials-1459
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sky_line/Slipstream!1479
No description provided.