From 12299a4e01ff733aec2a4db5f9dbb43f55e6621e Mon Sep 17 00:00:00 2001
From: Rye Mutt <rye@alchemyviewer.org>
Date: Tue, 26 Dec 2023 21:58:59 -0500
Subject: [PATCH] Add black dragon camera roll keybinds

---
 indra/newview/app_settings/key_bindings.xml   | 10 ++++
 .../settings_per_account_alchemy.xml          | 11 +++++
 indra/newview/llagentcamera.cpp               | 48 ++++++++++++++++++-
 indra/newview/llagentcamera.h                 | 11 +++++
 indra/newview/llviewerinput.cpp               | 28 ++++++++++-
 .../xui/en/control_table_contents_camera.xml  | 33 +++++++++++++
 6 files changed, 139 insertions(+), 2 deletions(-)

diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml
index 24f6777410a..da0732f2d6c 100644
--- a/indra/newview/app_settings/key_bindings.xml
+++ b/indra/newview/app_settings/key_bindings.xml
@@ -89,6 +89,11 @@
     <binding key="" mask="NONE" mouse="MMB" command="voice_follow_key"/>
 
     <binding key="" mask="NONE" mouse="LMB" command="script_trigger_lbutton"/>
+
+    <binding key="Q" mask="CTL_ALT" command="roll_left"/>
+    <binding key="E" mask="CTL_ALT" command="roll_right"/>
+    <binding key="Q" mask="CTL_SHIFT" command="roll_reset"/>
+    <binding key="E" mask="CTL_SHIFT" command="roll_reset"/>
   </third_person>
   <sitting>
     <binding key="A" mask="ALT" command="spin_around_cw"/>
@@ -162,6 +167,11 @@
     <binding key="" mask="NONE" mouse="MMB" command="voice_follow_key"/>
 
     <binding key="" mask="NONE" mouse="LMB" command="script_trigger_lbutton"/>
+    
+    <binding key="Q" mask="CTL_ALT" command="roll_left"/>
+    <binding key="E" mask="CTL_ALT" command="roll_right"/>
+    <binding key="Q" mask="CTL_SHIFT" command="roll_reset"/>
+    <binding key="E" mask="CTL_SHIFT" command="roll_reset"/>
   </sitting>
   <edit_avatar>
     <!--Avatar editing camera controls-->
diff --git a/indra/newview/app_settings/settings_per_account_alchemy.xml b/indra/newview/app_settings/settings_per_account_alchemy.xml
index 5da79d17314..b9c20d99871 100644
--- a/indra/newview/app_settings/settings_per_account_alchemy.xml
+++ b/indra/newview/app_settings/settings_per_account_alchemy.xml
@@ -96,6 +96,17 @@
         <real>0.0</real>
       </array>
     </map>
+	  <key>ALStoredCameraRoll</key>
+	  <map>
+		  <key>Comment</key>
+		  <string>Stored camera roll in camera tools</string>
+		  <key>Persist</key>
+		  <integer>1</integer>
+		  <key>Type</key>
+		  <string>F32</string>
+		  <key>Value</key>
+		  <real>0.0</real>
+	  </map>
     <key>ALStoredCameraFocusObjectId</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 031b0257061..cfaf599cebd 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -187,7 +187,9 @@ LLAgentCamera::LLAgentCamera() :
 	mPanLeftKey(0.f),
 	mPanRightKey(0.f),
 	mPanInKey(0.f),
-	mPanOutKey(0.f)
+	mPanOutKey(0.f),
+	mRollLeftKey(0.f),
+	mRollRightKey(0.f)
 {
 	mFollowCam.setMaxCameraDistantFromSubject( MAX_CAMERA_DISTANCE_FROM_AGENT );
 
@@ -197,6 +199,7 @@ LLAgentCamera::LLAgentCamera() :
 
 	resetPanDiff();
 	resetOrbitDiff();
+	resetCameraRoll();
 }
 
 // Requires gSavedSettings to be initialized.
@@ -374,6 +377,7 @@ void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera)
 	}
 	resetPanDiff();
 	resetOrbitDiff();
+	resetCameraRoll();
 	mHUDTargetZoom = 1.f;
 
     if (LLSelectMgr::getInstance()->mAllowSelectAvatar)
@@ -927,6 +931,19 @@ void LLAgentCamera::cameraOrbitOver(const F32 angle)
 	}
 }
 
+//-----------------------------------------------------------------------------
+// cameraRollOver()
+//-----------------------------------------------------------------------------
+void LLAgentCamera::cameraRollOver(const F32 angle)
+{
+	mRollAngle += fmod(angle, F_TWO_PI);
+}
+
+void LLAgentCamera::resetCameraRoll()
+{
+	mRollAngle = 0.f;
+}
+
 void LLAgentCamera::resetCameraOrbit()
 {
 	LLVector3 camera_offset_unit(mCameraFocusOffsetTarget);
@@ -940,6 +957,7 @@ void LLAgentCamera::resetCameraOrbit()
 
 	cameraZoomIn(1.f);
 	resetOrbitDiff();
+	resetCameraRoll();
 }
 
 void LLAgentCamera::resetOrbitDiff()
@@ -1246,6 +1264,8 @@ void LLAgentCamera::updateCamera()
         return;
     }
 
+	//BD - Camera Rolling
+	//     Make sure we always start with a neutral camera roll.
 	// - changed camera_skyward to the new global "mCameraUpVector"
 	mCameraUpVector = LLVector3::z_axis;
 	//LLVector3	camera_skyward(0.f, 0.f, 1.f);
@@ -1312,6 +1332,7 @@ void LLAgentCamera::updateCamera()
 	const F32 ORBIT_OVER_RATE = 90.f * DEG_TO_RAD;			// radians per second
 	const F32 ORBIT_AROUND_RATE = 90.f * DEG_TO_RAD;		// radians per second
 	const F32 PAN_RATE = 5.f;								// meters per second
+	const F32 ROLL_RATE = 45.f * DEG_TO_RAD;				// radians per second
 
 	if (gAgentCamera.getOrbitUpKey() || gAgentCamera.getOrbitDownKey())
 	{
@@ -1353,6 +1374,12 @@ void LLAgentCamera::updateCamera()
 		cameraPanUp(input_rate * PAN_RATE / gFPSClamped );
 	}
 
+	if (getRollLeftKey() || getRollRightKey())
+	{
+		F32 input_rate = getRollRightKey() - getRollLeftKey();
+		cameraRollOver(input_rate * ROLL_RATE / gFPSClamped);
+	}
+
 	// Clear camera keyboard keys.
 	gAgentCamera.clearOrbitKeys();
 	gAgentCamera.clearPanKeys();
@@ -1616,6 +1643,18 @@ void LLAgentCamera::updateCamera()
 		torso_joint->setScale(torso_scale);
 		chest_joint->setScale(chest_scale);
 	}
+
+	//     We have do this at the very end to make sure it takes all previous calculations into
+	//     account and then applies our roll on top of it, besides it wouldn't even work otherwise.
+	LLQuaternion rot_quat = vwr_camera.getQuaternion();
+	LLMatrix3 rot_mat(mRollAngle, 0.f, 0.f);
+	rot_quat = LLQuaternion(rot_mat)*rot_quat;
+	
+	LLMatrix3 mat(rot_quat);
+	
+	vwr_camera.mXAxis = LLVector3(mat.mMatrix[0]);
+	vwr_camera.mYAxis = LLVector3(mat.mMatrix[1]);
+	vwr_camera.mZAxis = LLVector3(mat.mMatrix[2]);
 }
 
 void LLAgentCamera::updateLastCamera()
@@ -2694,6 +2733,7 @@ void LLAgentCamera::switchCameraPreset(ECameraPreset preset)
 
 	resetPanDiff();
 	resetOrbitDiff();
+	resetCameraRoll();
 
 	gSavedSettings.setU32("CameraPresetType", mCameraPreset);
 }
@@ -3183,6 +3223,8 @@ void LLAgentCamera::clearOrbitKeys()
 	mOrbitDownKey		= 0.f;
 	mOrbitInKey			= 0.f;
 	mOrbitOutKey		= 0.f;
+	mRollLeftKey		= 0.f;
+	mRollRightKey		= 0.f;
 }
 
 void LLAgentCamera::clearPanKeys()
@@ -3212,6 +3254,7 @@ void LLAgentCamera::storeCameraPosition()
 	// flycam  mode and not repositioned after
 	LLVector3d forward = LLVector3d(1.0, 0.0, 0.0) * LLViewerCamera::getInstance()->getQuaternion() + getCameraPositionGlobal();
 	gSavedPerAccountSettings.setVector3d("ALStoredCameraFocus", forward);
+	gSavedPerAccountSettings.setF32("ALStoredCameraRoll", mRollAngle);
 
 	LLUUID stored_camera_focus_object_id = LLUUID::null;
 	if (mFocusObject)
@@ -3225,6 +3268,7 @@ void LLAgentCamera::loadCameraPosition()
 {
 	LLVector3d stored_camera_pos = gSavedPerAccountSettings.getVector3d("ALStoredCameraPos");
 	LLVector3d stored_camera_focus = gSavedPerAccountSettings.getVector3d("ALStoredCameraFocus");
+	F32 stored_camera_roll = gSavedPerAccountSettings.getF32("ALStoredCameraRoll");
 	LLUUID stored_camera_focus_object_id = LLUUID(gSavedPerAccountSettings.getString("ALStoredCameraFocusObjectId"));
 
 	F32 renderFarClip = gSavedSettings.getF32("RenderFarClip");
@@ -3253,6 +3297,8 @@ void LLAgentCamera::loadCameraPosition()
 
 	unlockView();
 	setCameraPosAndFocusGlobal(stored_camera_pos, stored_camera_focus, stored_camera_focus_object_id);
+
+	mRollAngle = stored_camera_roll;
 }
 
 // EOF
diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h
index 0ee26a66ad8..ceff8c520f2 100644
--- a/indra/newview/llagentcamera.h
+++ b/indra/newview/llagentcamera.h
@@ -290,8 +290,10 @@ class LLAgentCamera
 	void			cameraOrbitAround(const F32 radians);	// Rotate camera CCW radians about build focus point
 	void			cameraOrbitOver(const F32 radians);		// Rotate camera forward radians over build focus point
 	void			cameraOrbitIn(const F32 meters);		// Move camera in toward build focus point
+	void			cameraRollOver(const F32 radians);		// Roll the camera
 	void			resetCameraOrbit();
 	void			resetOrbitDiff();
+	void			resetCameraRoll();
 	//--------------------------------------------------------------------
 	// Zoom
 	//--------------------------------------------------------------------
@@ -396,6 +398,8 @@ class LLAgentCamera
 	F32				getOrbitDownKey() const		{ return mOrbitDownKey; }
 	F32				getOrbitInKey() const		{ return mOrbitInKey; }
 	F32				getOrbitOutKey() const		{ return mOrbitOutKey; }
+	F32				getRollLeftKey() const		{ return mRollLeftKey; }
+	F32				getRollRightKey() const		{ return mRollRightKey; }
 
 	void			setOrbitLeftKey(F32 mag)	{ mOrbitLeftKey = mag; }
 	void			setOrbitRightKey(F32 mag)	{ mOrbitRightKey = mag; }
@@ -403,8 +407,11 @@ class LLAgentCamera
 	void			setOrbitDownKey(F32 mag)	{ mOrbitDownKey = mag; }
 	void			setOrbitInKey(F32 mag)		{ mOrbitInKey = mag; }
 	void			setOrbitOutKey(F32 mag)		{ mOrbitOutKey = mag; }
+	void			setRollLeftKey(F32 mag) { mRollLeftKey = mag; }
+	void			setRollRightKey(F32 mag) { mRollRightKey = mag; }
 
 	void			clearOrbitKeys();
+
 private:
 	F32				mOrbitLeftKey;
 	F32				mOrbitRightKey;
@@ -416,6 +423,10 @@ class LLAgentCamera
 	F32				mOrbitAroundRadians;
 	F32				mOrbitOverAngle;
 
+	F32				mRollLeftKey;
+	F32				mRollRightKey;
+	F32				mRollAngle = 0.f;
+
 	//--------------------------------------------------------------------
 	// Pan
 	//--------------------------------------------------------------------
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 25c6e42f8eb..f16f01fa452 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -481,6 +481,29 @@ bool camera_spin_under_sitting( EKeystate s )
 	return true;
 }
 
+bool camera_roll_left(EKeystate s)
+{
+    if (KEYSTATE_UP == s) return true;
+    gAgentCamera.unlockView();
+    gAgentCamera.setRollLeftKey(get_orbit_rate());
+    return true;
+}
+
+bool camera_roll_right(EKeystate s)
+{
+    if (KEYSTATE_UP == s) return true;
+    gAgentCamera.unlockView();
+    gAgentCamera.setRollRightKey(get_orbit_rate());
+    return true;
+}
+
+bool camera_roll_reset(EKeystate s)
+{
+    if (KEYSTATE_UP == s) return true;
+    gAgentCamera.mCameraRollAngle = 0.f;
+    return true;
+}
+
 bool camera_move_forward( EKeystate s )
 {
 	if( KEYSTATE_UP == s  ) return true;
@@ -1069,7 +1092,10 @@ REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to);
 REGISTER_KEYBOARD_ACTION("walk_to", walk_to);
 REGISTER_KEYBOARD_GLOBAL_ACTION("toggle_voice", toggle_voice);
 REGISTER_KEYBOARD_GLOBAL_ACTION("voice_follow_key", voice_follow_key);
-REGISTER_KEYBOARD_ACTION(script_mouse_handler_name, script_trigger_lbutton);
+REGISTER_KEYBOARD_ACTION("script_trigger_lbutton", script_trigger_lbutton);
+REGISTER_KEYBOARD_ACTION("roll_left", camera_roll_left);
+REGISTER_KEYBOARD_ACTION("roll_right", camera_roll_right);
+REGISTER_KEYBOARD_ACTION("roll_reset", camera_roll_reset);
 #undef REGISTER_KEYBOARD_ACTION
 
 LLViewerInput::LLViewerInput()
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_camera.xml b/indra/newview/skins/default/xui/en/control_table_contents_camera.xml
index 24cbb2b8850..388a69864e0 100644
--- a/indra/newview/skins/default/xui/en/control_table_contents_camera.xml
+++ b/indra/newview/skins/default/xui/en/control_table_contents_camera.xml
@@ -175,6 +175,39 @@
          tool_tip="Camera spin around clockwise"
          value="Clockwise" />
     </rows>
+	<rows
+     name="roll_left"
+     value="roll_left">
+		<columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera roll left"
+         value="Roll Left" />
+	</rows>
+	<rows
+     name="roll_right"
+     value="roll_right">
+		<columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera roll right"
+         value="Roll Right" />
+	</rows>
+	<rows
+     name="roll_reset"
+     value="roll_reset">
+		<columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Reset camera roll"
+         value="Roll Reset" />
+	</rows>
     <rows
      name="move_forward_sitting"
      value="move_forward_sitting">
-- 
GitLab