diff options
| author | leviathan <leviathan@lindenlab.com> | 2026-09-24 16:04:55 -0700 |
|---|---|---|
| committer | leviathan <leviathan@lindenlab.com> | 2026-10-16 13:14:38 -0700 |
| commit | dfca45c8ae47ef1f56ef0af591a8f456fcd64784 (patch) | |
| tree | beaa98f300550e63a5f79a90d94e82cd153d10df | |
| parent | f9f14adc36f792d1f885a421f888a93a8072873f (diff) | |
add 'scroll' game-control action for changing follocam dist
| -rwxr-xr-x | indra/llwindow/llgamecontrol.cpp | 53 | ||||
| -rw-r--r-- | indra/llwindow/llgamecontrol.h | 14 | ||||
| -rw-r--r-- | indra/newview/llagent.cpp | 12 | ||||
| -rw-r--r-- | indra/newview/llagentcamera.cpp | 60 | ||||
| -rw-r--r-- | indra/newview/llagentcamera.h | 7 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/panel_preferences_game_control.xml | 9 |
6 files changed, 131 insertions, 24 deletions
diff --git a/indra/llwindow/llgamecontrol.cpp b/indra/llwindow/llgamecontrol.cpp index 7c4a45f083..644bf2adf8 100755 --- a/indra/llwindow/llgamecontrol.cpp +++ b/indra/llwindow/llgamecontrol.cpp @@ -692,6 +692,9 @@ namespace // Unbound by default: every physical axis is already claimed above (the // trigger pair covers Fly up/down), same as FlyCam's Roll axis below. avatar_axes["Zoom +/-"] = "AXIS_NONE"; + // Camera distance from the avatar (see AgentActions::mScrollAmplitude); + // client-side only, so it has no ModeAxes/ModeButtons slot. + avatar_axes["Scroll +/-"] = "AXIS_NONE"; // Buttons: action label -> button input LLSD avatar_buttons; @@ -708,6 +711,9 @@ namespace avatar_buttons["Advance back"] = "BUTTON_DPAD_DOWN"; avatar_buttons["Strafe left"] = "BUTTON_DPAD_LEFT"; avatar_buttons["Strafe right"] = "BUTTON_DPAD_RIGHT"; + // Unbound by default, same as the "Scroll +/-" axis above. + avatar_buttons["Scroll +"] = "BUTTON_NONE"; + avatar_buttons["Scroll -"] = "BUTTON_NONE"; // Default per-axis-action Invert flags LLSD avatar_axes_invert; @@ -1923,6 +1929,18 @@ namespace return bridge; } + // Avatar-mode button label -> full-deflection contribution to the same scroll + // (camera distance) accumulator as the "Scroll +/-" axis, same pattern as + // avatarZoomButtonBridge() above. + const std::map<std::string, F32>& avatarScrollButtonBridge() + { + static const std::map<std::string, F32> bridge = { + { "Scroll +", 1.f }, + { "Scroll -", -1.f }, + }; + return bridge; + } + // Cursor mode's digital (button) equivalent of "Mouse left/right"/"Mouse up/down": // a discrete alternative/addition to the analog stick for driving the on-screen // cursor, e.g. so the D-Pad can be rebound to nudge the cursor instead of moving @@ -2170,6 +2188,7 @@ LLGameControl::AgentActions LLGameControllerManager::computeAgentActions() S32 mouse_dx = 0; S32 mouse_dy = 0; S32 zoom_value = 0; + S32 scroll_value = 0; for (U8 axis = 0; axis < LLGameControl::NUM_AXES; ++axis) { const AxisActionBinding& binding = mAxisActionBindings[axis]; @@ -2217,6 +2236,23 @@ LLGameControl::AgentActions LLGameControllerManager::computeAgentActions() continue; } + // "Scroll +/-" drives the camera's distance from the avatar, captured + // separately for the same reason as "Zoom +/-" above. + if (binding.label == "Scroll +/-") + { + S32 deflection = (S32)g_innerState.mAxes[axis * 2] - (S32)g_innerState.mAxes[axis * 2 + 1]; + S32 value = binding.half == HALF_NEGATIVE ? -deflection : deflection; + if (binding.invert) + { + value = -value; + } + if (std::abs(value) > std::abs(scroll_value)) + { + scroll_value = value; + } + continue; + } + auto it = axis_bridge.find(binding.label); if (it == axis_bridge.end()) { @@ -2302,6 +2338,7 @@ LLGameControl::AgentActions LLGameControllerManager::computeAgentActions() const auto& misc_button_bridge = avatarMiscButtonBridge(); const auto& mouse_cursor_button_bridge = mouseCursorButtonBridge(); const auto& zoom_button_bridge = avatarZoomButtonBridge(); + const auto& scroll_button_bridge = avatarScrollButtonBridge(); U32 pressed_edges = g_innerState.mButtons & ~g_innerState.mPrevButtons; for (U8 btn = 0; btn < LLGameControl::NUM_BUTTONS; ++btn) { @@ -2372,6 +2409,16 @@ LLGameControl::AgentActions LLGameControllerManager::computeAgentActions() } continue; } + auto scroll_it = scroll_button_bridge.find(label); + if (scroll_it != scroll_button_bridge.end()) + { + S32 full = (S32)(scroll_it->second * 32767.f); + if (std::abs(full) > std::abs(scroll_value)) + { + scroll_value = full; + } + continue; + } auto mit = misc_button_bridge.find(label); if (mit != misc_button_bridge.end() && (pressed_edges & (1U << btn))) { @@ -2386,6 +2433,7 @@ LLGameControl::AgentActions LLGameControllerManager::computeAgentActions() result.mMouseCursorDX = std::clamp((F32)mouse_dx / 32767.f, -1.f, 1.f); result.mMouseCursorDY = std::clamp((F32)mouse_dy / 32767.f, -1.f, 1.f); result.mZoomAmplitude = std::clamp((F32)zoom_value / 32767.f, -1.f, 1.f); + result.mScrollAmplitude = std::clamp((F32)scroll_value / 32767.f, -1.f, 1.f); return result; } @@ -2520,8 +2568,9 @@ namespace || label == "Mouse left/right" || label == "Mouse up/down"; } // Avatar, Mouselook, and Captive share the avatar axis actions, - // and "Zoom +/-" (camera zoom rate; see computeAgentActions()). - return avatarAxisBridge().count(label) > 0 || label == "Zoom +/-"; + // plus "Zoom +/-" (camera FOV zoom rate) and "Scroll +/-" (camera + // distance); see computeAgentActions(). + return avatarAxisBridge().count(label) > 0 || label == "Zoom +/-" || label == "Scroll +/-"; } std::string defaultAxisActionForInput(LLGameControl::AgentControlMode mode, const std::string& input) diff --git a/indra/llwindow/llgamecontrol.h b/indra/llwindow/llgamecontrol.h index cd76987943..bbbf8c6774 100644 --- a/indra/llwindow/llgamecontrol.h +++ b/indra/llwindow/llgamecontrol.h @@ -597,10 +597,18 @@ public: // Signed magnitude ([-1, 1]) of "Zoom +/-" (Avatar/Mouselook/Captive only), // combined with the full-deflection contribution of "Zoom +"/"Zoom -" -- - // drives the camera zoom rate rather than an AGENT_CONTROL_* bit; consumed - // by LLAgent::applyExternalActions() via LLAgentCamera::setOrbitInKey/ - // setOrbitOutKey(). Positive zooms in (camera moves closer). + // drives the camera field-of-view zoom rate rather than an AGENT_CONTROL_* + // bit; consumed by LLAgent::applyExternalActions(). Positive zooms in + // (narrows the FOV). F32 mZoomAmplitude { 0.f }; + + // Signed magnitude ([-1, 1]) of "Scroll +/-" (Avatar/Captive only), + // combined with the full-deflection contribution of "Scroll +"/"Scroll -" + // -- drives the camera's distance from the avatar (unlike Zoom, which changes + // the FOV). Client-side only: not reported in GameControlData's semantic + // data. Consumed by LLAgent::applyExternalActions() via + // LLAgentCamera::scrollCamera(). Positive scrolls in (camera moves closer). + F32 mScrollAmplitude { 0.f }; }; // Keyboard presses produce action_flags which can be translated into State diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 7dd11e85bc..443b64ea99 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -5320,6 +5320,18 @@ void LLAgent::applyExternalActions(const LLGameControl::AgentActions& actions) gSavedSettings.setF32("CameraAngle", camera->getView()); } + // actions.mScrollAmplitude ([-1, 1], from "Scroll +/-"/"Scroll +"/"Scroll -") + // moves the camera toward/away from the avatar the same way the mousewheel does, + // so the third-person/follow-cam distance persists once the avatar moves (unlike + // the keyboard's camera in/out keys, which unlock the view from the avatar). + // Positive amplitude scrolls in (camera moves closer); scrollCamera()'s clicks + // are positive-out like the mousewheel's. + if (actions.mScrollAmplitude != 0.f) + { + constexpr F32 SCROLL_CLICKS_PER_SECOND = 8.f; + gAgentCamera.scrollCamera(-actions.mScrollAmplitude * SCROLL_CLICKS_PER_SECOND * g_deltaTime); + } + if (mExternalActionFlags & AGENT_CONTROL_STOP) { setControlFlags(AGENT_CONTROL_STOP); diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 1d61dcea6a..c3b2d6ad2c 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -2177,14 +2177,52 @@ void LLAgentCamera::handleScrollWheel(S32 clicks) return; } + // The Shift/Ctrl offset tweaks are wheel-only; everything else is shared with + // gamepad "Scroll" input via scrollCamera(). + if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON && !mCameraAnimating) + { + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + if (!(selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)) + { + MASK mask = gKeyboard->currentMask(true); + if (mask & MASK_SHIFT) + { + LLVector3d offset = gSavedSettings.getVector3d("FocusOffsetRearView"); + offset.mdV[VZ] += 0.1f * (F32)clicks; + gSavedSettings.setVector3d("FocusOffsetRearView", offset); + return; + } + else if (mask & MASK_CONTROL) + { + LLVector3 offset = gSavedSettings.getVector3("CameraOffsetRearView"); + offset.mV[VZ] += 0.1f * (F32)clicks; + gSavedSettings.setVector3("CameraOffsetRearView", offset); + return; + } + } + } + + scrollCamera((F32)clicks); +} + +void LLAgentCamera::scrollCamera(F32 clicks) +{ if (mCameraMode == CAMERA_MODE_FOLLOW && getFocusOnAvatar()) { if (!mFollowCam.getPositionLocked()) // not if the followCam position is locked in place { - mFollowCam.zoom(clicks); - if (mFollowCam.isZoomedToMinimumDistance()) + // LLFollowCam::zoom() only takes whole clicks (and enforces a minimum + // step per call), so accumulate fractional ones until a click is due. + mFollowCamScrollClicks += clicks; + S32 whole_clicks = (S32)mFollowCamScrollClicks; + if (whole_clicks != 0) { - changeCameraToMouselook(false); + mFollowCamScrollClicks -= (F32)whole_clicks; + mFollowCam.zoom(whole_clicks); + if (mFollowCam.isZoomedToMinimumDistance()) + { + changeCameraToMouselook(false); + } } } } @@ -2206,22 +2244,6 @@ void LLAgentCamera::handleScrollWheel(S32 clicks) } else if (mFocusOnAvatar && (mCameraMode == CAMERA_MODE_THIRD_PERSON)) { - MASK mask = gKeyboard->currentMask(true); - if (mask & MASK_SHIFT) - { - LLVector3d offset = gSavedSettings.getVector3d("FocusOffsetRearView"); - offset.mdV[VZ] += 0.1f * (F32)clicks; - gSavedSettings.setVector3d("FocusOffsetRearView", offset); - return; - } - else if (mask & MASK_CONTROL) - { - LLVector3 offset = gSavedSettings.getVector3("CameraOffsetRearView"); - offset.mV[VZ] += 0.1f * (F32)clicks; - gSavedSettings.setVector3("CameraOffsetRearView", offset); - return; - } - F32 camera_offset_initial_mag = getCameraOffsetInitial().magVec(); F32 current_zoom_fraction = mTargetCameraDistance / (camera_offset_initial_mag * gSavedSettings.getF32("CameraOffsetScale")); diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h index b44dd54755..c4db5f3e6a 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -178,6 +178,9 @@ public: void notifyFollowCamParamsCleared(); private: LLFollowCam mFollowCam; // Ventrella + // Fractional scrollCamera() clicks not yet applied to mFollowCam, whose + // zoom() only takes whole clicks. + F32 mFollowCamScrollClicks { 0.f }; //-------------------------------------------------------------------- // Flycam @@ -331,6 +334,10 @@ public: //-------------------------------------------------------------------- public: void handleScrollWheel(S32 clicks); // Mousewheel driven zoom + // Mousewheel-equivalent camera distance change, minus the wheel-only Shift/Ctrl + // offset tweaks; 'clicks' may be fractional (e.g. per-frame gamepad "Scroll" + // input). Positive moves the camera out, same sign as handleScrollWheel(). + void scrollCamera(F32 clicks); void cameraZoomIn(const F32 factor); // Zoom in by fraction of current distance F32 getCameraZoomFraction(bool get_third_person = false); // Get camera zoom as fraction of minimum and maximum zoom void setCameraZoomFraction(F32 fraction); // Set camera zoom as fraction of minimum and maximum zoom diff --git a/indra/newview/skins/default/xui/en/panel_preferences_game_control.xml b/indra/newview/skins/default/xui/en/panel_preferences_game_control.xml index 1039bfcb26..e65c016792 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_game_control.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_game_control.xml @@ -610,6 +610,9 @@ label="Zoom -/+" value="Zoom +/-"/> <combo_box.item + label="Scroll -/+" + value="Scroll +/-"/> + <combo_box.item label="None" value="None"/> </combo_box> @@ -845,6 +848,12 @@ label="Zoom -" value="Zoom -"/> <combo_box.item + label="Scroll +" + value="Scroll +"/> + <combo_box.item + label="Scroll -" + value="Scroll -"/> + <combo_box.item label="None" value="None"/> </combo_box> |
