summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/llagentlistener.cpp118
-rw-r--r--indra/newview/llagentlistener.h5
-rw-r--r--indra/newview/scripts/lua/luafloater_camera_control.xml244
-rw-r--r--indra/newview/scripts/lua/require/LLAgent.lua45
-rw-r--r--indra/newview/scripts/lua/test_camera_control.lua49
5 files changed, 437 insertions, 24 deletions
diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp
index 54998f3945..80460666a5 100644
--- a/indra/newview/llagentlistener.cpp
+++ b/indra/newview/llagentlistener.cpp
@@ -31,6 +31,7 @@
#include "llagentlistener.h"
#include "llagent.h"
+#include "llagentcamera.h"
#include "llvoavatar.h"
#include "llcommandhandler.h"
#include "llslurl.h"
@@ -44,6 +45,7 @@
#include "lltoolgrab.h"
#include "llhudeffectlookat.h"
#include "llagentcamera.h"
+#include <functional>
LLAgentListener::LLAgentListener(LLAgent &agent)
: LLEventAPI("LLAgent",
@@ -69,13 +71,6 @@ LLAgentListener::LLAgentListener(LLAgent &agent)
add("resetAxes",
"Set the agent to a fixed orientation (optionally specify [\"lookat\"] = array of [x, y, z])",
&LLAgentListener::resetAxes);
- add("getAxes",
- "Obsolete - use getPosition instead\n"
- "Send information about the agent's orientation on [\"reply\"]:\n"
- "[\"euler\"]: map of {roll, pitch, yaw}\n"
- "[\"quat\"]: array of [x, y, z, w] quaternion values",
- &LLAgentListener::getAxes,
- LLSDMap("reply", LLSD()));
add("getPosition",
"Send information about the agent's position and orientation on [\"reply\"]:\n"
"[\"region\"]: array of region {x, y, z} position\n"
@@ -138,6 +133,30 @@ LLAgentListener::LLAgentListener(LLAgent &agent)
"[\"contrib\"]: user's land contribution to this group\n",
&LLAgentListener::getGroups,
LLSDMap("reply", LLSD()));
+ //camera params are similar to LSL, see https://wiki.secondlife.com/wiki/LlSetCameraParams
+ add("setCameraParams",
+ "Set Follow camera params, and then activate it:\n"
+ "[\"camera_pos\"]: vector3, camera position in region coordinates\n"
+ "[\"focus_pos\"]: vector3, what the camera is aimed at (in region coordinates)\n"
+ "[\"focus_offset\"]: vector3, adjusts the camera focus position relative to the target, default is (1, 0, 0)\n"
+ "[\"distance\"]: float (meters), distance the camera wants to be from its target, default is 3\n"
+ "[\"focus_threshold\"]: float (meters), sets the radius of a sphere around the camera's target position within which its focus is not affected by target motion, default is 1\n"
+ "[\"camera_threshold\"]: float (meters), sets the radius of a sphere around the camera's ideal position within which it is not affected by target motion, default is 1\n"
+ "[\"focus_lag\"]: float (seconds), how much the camera lags as it tries to aim towards the target, default is 0.1\n"
+ "[\"camera_lag\"]: float (seconds), how much the camera lags as it tries to move towards its 'ideal' position, default is 0.1\n"
+ "[\"camera_pitch\"]: float (degrees), adjusts the angular amount that the camera aims straight ahead vs. straight down, maintaining the same distance, default is 0\n"
+ "[\"behindness_angle\"]: float (degrees), sets the angle in degrees within which the camera is not constrained by changes in target rotation, default is 10\n"
+ "[\"behindness_lag\"]: float (seconds), sets how strongly the camera is forced to stay behind the target if outside of behindness angle, default is 0\n"
+ "[\"camera_locked\"]: bool, locks the camera position so it will not move\n"
+ "[\"focus_locked\"]: bool, locks the camera focus so it will not move",
+ &LLAgentListener::setFollowCamParams);
+ add("setFollowCamActive",
+ "Turns on or off scripted control of the camera using boolean [\"active\"]",
+ &LLAgentListener::setFollowCamActive,
+ llsd::map("active", LLSD()));
+ add("removeCameraParams",
+ "Reset Follow camera params",
+ &LLAgentListener::removeFollowCamParams);
}
void LLAgentListener::requestTeleport(LLSD const & event_data) const
@@ -296,22 +315,6 @@ void LLAgentListener::resetAxes(const LLSD& event_data) const
}
}
-void LLAgentListener::getAxes(const LLSD& event_data) const
-{
- LLQuaternion quat(mAgent.getQuat());
- F32 roll, pitch, yaw;
- quat.getEulerAngles(&roll, &pitch, &yaw);
- // The official query API for LLQuaternion's [x, y, z, w] values is its
- // public member mQ...
- LLSD reply = LLSD::emptyMap();
- reply["quat"] = llsd_copy_array(boost::begin(quat.mQ), boost::end(quat.mQ));
- reply["euler"] = LLSD::emptyMap();
- reply["euler"]["roll"] = roll;
- reply["euler"]["pitch"] = pitch;
- reply["euler"]["yaw"] = yaw;
- sendReply(reply, event_data);
-}
-
void LLAgentListener::getPosition(const LLSD& event_data) const
{
F32 roll, pitch, yaw;
@@ -519,3 +522,72 @@ void LLAgentListener::getGroups(const LLSD& event) const
}
sendReply(LLSDMap("groups", reply), event);
}
+
+/*----------------------------- camera control -----------------------------*/
+// specialize LLSDParam to support (const LLVector3&) arguments -- this
+// wouldn't even be necessary except that the relevant LLVector3 constructor
+// is explicitly explicit
+template <>
+class LLSDParam<const LLVector3&>: public LLSDParamBase
+{
+public:
+ LLSDParam(const LLSD& value): value(LLVector3(value)) {}
+
+ operator const LLVector3&() const { return value; }
+
+private:
+ LLVector3 value;
+};
+
+// accept any of a number of similar LLFollowCamMgr methods with different
+// argument types, and return a wrapper lambda that accepts LLSD and converts
+// to the target argument type
+template <typename T>
+auto wrap(void (LLFollowCamMgr::*method)(const LLUUID& source, T arg))
+{
+ return [method](LLFollowCamMgr& followcam, const LLUUID& source, const LLSD& arg)
+ { (followcam.*method)(source, LLSDParam<T>(arg)); };
+}
+
+// table of supported LLFollowCamMgr methods,
+// with the corresponding setFollowCamParams() argument keys
+static std::pair<std::string, std::function<void(LLFollowCamMgr&, const LLUUID&, const LLSD&)>>
+cam_params[] =
+{
+ { "camera_pos", wrap(&LLFollowCamMgr::setPosition) },
+ { "focus_pos", wrap(&LLFollowCamMgr::setFocus) },
+ { "focus_offset", wrap(&LLFollowCamMgr::setFocusOffset) },
+ { "camera_locked", wrap(&LLFollowCamMgr::setPositionLocked) },
+ { "focus_locked", wrap(&LLFollowCamMgr::setFocusLocked) },
+ { "distance", wrap(&LLFollowCamMgr::setDistance) },
+ { "focus_threshold", wrap(&LLFollowCamMgr::setFocusThreshold) },
+ { "camera_threshold", wrap(&LLFollowCamMgr::setPositionThreshold) },
+ { "focus_lag", wrap(&LLFollowCamMgr::setFocusLag) },
+ { "camera_lag", wrap(&LLFollowCamMgr::setPositionLag) },
+ { "camera_pitch", wrap(&LLFollowCamMgr::setPitch) },
+ { "behindness_lag", wrap(&LLFollowCamMgr::setBehindnessLag) },
+ { "behindness_angle", wrap(&LLFollowCamMgr::setBehindnessAngle) },
+};
+
+void LLAgentListener::setFollowCamParams(const LLSD& event) const
+{
+ auto& followcam{ LLFollowCamMgr::instance() };
+ for (const auto& pair : cam_params)
+ {
+ if (event.has(pair.first))
+ {
+ pair.second(followcam, gAgentID, event[pair.first]);
+ }
+ }
+ followcam.setCameraActive(gAgentID, true);
+}
+
+void LLAgentListener::setFollowCamActive(LLSD const & event) const
+{
+ LLFollowCamMgr::getInstance()->setCameraActive(gAgentID, event["active"]);
+}
+
+void LLAgentListener::removeFollowCamParams(LLSD const & event) const
+{
+ LLFollowCamMgr::getInstance()->removeFollowCamParams(gAgentID);
+}
diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h
index c544d089ce..2a24de3f52 100644
--- a/indra/newview/llagentlistener.h
+++ b/indra/newview/llagentlistener.h
@@ -48,7 +48,6 @@ private:
void requestStand(LLSD const & event_data) const;
void requestTouch(LLSD const & event_data) const;
void resetAxes(const LLSD& event_data) const;
- void getAxes(const LLSD& event_data) const;
void getGroups(const LLSD& event) const;
void getPosition(const LLSD& event_data) const;
void startAutoPilot(const LLSD& event_data);
@@ -58,6 +57,10 @@ private:
void stopAutoPilot(const LLSD& event_data) const;
void lookAt(LLSD const & event_data) const;
+ void setFollowCamParams(LLSD const & event_data) const;
+ void setFollowCamActive(LLSD const & event_data) const;
+ void removeFollowCamParams(LLSD const & event_data) const;
+
LLViewerObject * findObjectClosestTo( const LLVector3 & position ) const;
private:
diff --git a/indra/newview/scripts/lua/luafloater_camera_control.xml b/indra/newview/scripts/lua/luafloater_camera_control.xml
new file mode 100644
index 0000000000..0601a363e5
--- /dev/null
+++ b/indra/newview/scripts/lua/luafloater_camera_control.xml
@@ -0,0 +1,244 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ height="350"
+ layout="topleft"
+ name="camera_demo"
+ title="Follow camera control"
+ width="360">
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="100"
+ layout="topleft"
+ top="30"
+ left="10"
+ name="camera_lbl">
+ Camera position:
+ </text>
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="10"
+ layout="topleft"
+ top_pad="12"
+ left="10"
+ value="X"
+ name="cam_x_lbl"/>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ max_length_bytes="50"
+ name="cam_x"
+ top_delta="-2"
+ left_pad="5"
+ width="65" />
+ <button
+ follows="left|bottom"
+ height="20"
+ image_overlay="Icon_Copy"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ tool_tip="Use Agent position"
+ name="agent_cam_btn"
+ left_pad="10"
+ width="20" >
+ </button>
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="10"
+ layout="topleft"
+ top_pad="7"
+ left="10"
+ value="Y"
+ name="cam_y_lbl"/>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ max_length_bytes="50"
+ name="cam_y"
+ top_delta="-2"
+ left_pad="5"
+ width="65" />
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="10"
+ layout="topleft"
+ top_pad="7"
+ left="10"
+ value="Z"
+ name="cam_z_lbl"/>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ max_length_bytes="50"
+ name="cam_z"
+ top_delta="-2"
+ left_pad="5"
+ width="65" />
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="100"
+ layout="topleft"
+ top="30"
+ left="145"
+ name="focus_lbl">
+ Focus position:
+ </text>
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="10"
+ layout="topleft"
+ top_pad="12"
+ left="145"
+ value="X"
+ name="cam_x_lbl"/>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ max_length_bytes="50"
+ name="focus_x"
+ top_delta="-2"
+ left_pad="5"
+ width="60" />
+ <button
+ follows="left|bottom"
+ height="20"
+ image_overlay="Icon_Copy"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ tool_tip="Use Agent position"
+ name="agent_focus_btn"
+ left_pad="10"
+ width="20" >
+ </button>
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="10"
+ layout="topleft"
+ top_pad="7"
+ left="145"
+ value="Y"
+ name="cam_y_lbl"/>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ max_length_bytes="50"
+ name="focus_y"
+ top_delta="-2"
+ left_pad="5"
+ width="60" />
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="10"
+ layout="topleft"
+ top_pad="7"
+ left="145"
+ value="Z"
+ name="cam_z_lbl"/>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ max_length_bytes="50"
+ name="focus_z"
+ top_delta="-2"
+ left_pad="5"
+ width="60" />
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="100"
+ layout="topleft"
+ top="30"
+ left="270"
+ name="focus_lbl">
+ Lock:
+ </text>
+ <check_box
+ width="80"
+ height="21"
+ layout="topleft"
+ follows="top|left"
+ top_pad="12"
+ label="Camera"
+ name="lock_camera_ctrl"/>
+ <check_box
+ width="80"
+ height="21"
+ layout="topleft"
+ follows="top|left"
+ top_pad="2"
+ label="Focus"
+ name="lock_focus_ctrl"/>
+ <button
+ follows="left|bottom"
+ height="25"
+ label="Update params"
+ layout="topleft"
+ name="update_btn"
+ left="10"
+ top="140"
+ width="120" >
+ </button>
+ <button
+ follows="left|bottom"
+ height="25"
+ label="Reset"
+ layout="topleft"
+ name="reset_btn"
+ left_pad="15"
+ width="90" >
+ </button>
+ <text_editor
+ follows="top|left"
+ font="SansSerif"
+ height="160"
+ left="5"
+ enabled="false"
+ name="events_editor"
+ top_pad="15"
+ word_wrap="true"
+ max_length="65536"
+ width="350"/>
+</floater>
diff --git a/indra/newview/scripts/lua/require/LLAgent.lua b/indra/newview/scripts/lua/require/LLAgent.lua
new file mode 100644
index 0000000000..bc9a6b23a0
--- /dev/null
+++ b/indra/newview/scripts/lua/require/LLAgent.lua
@@ -0,0 +1,45 @@
+local leap = require 'leap'
+local mapargs = require 'mapargs'
+
+local LLAgent = {}
+
+function LLAgent.getRegionPosition()
+ return leap.request('LLAgent', {op = 'getPosition'}).region
+end
+
+function LLAgent.getGlobalPosition()
+ return leap.request('LLAgent', {op = 'getPosition'}).global
+end
+
+-- Use LL.leaphelp('LLAgent') and see 'setCameraParams' to get more info about params
+-- -- TYPE -- DEFAULT -- RANGE
+-- LLAgent.setCamera{ [, camera_pos] -- vector3
+-- [, focus_pos] -- vector3
+-- [, focus_offset] -- vector3 -- {1,0,0} -- {-10,-10,-10} to {10,10,10}
+-- [, distance] -- float (meters) -- 3 -- 0.5 to 50
+-- [, focus_threshold] -- float (meters) -- 1 -- 0 to 4
+-- [, camera_threshold] -- float (meters) -- 1 -- 0 to 4
+-- [, focus_lag] -- float (seconds) -- 0.1 -- 0 to 3
+-- [, camera_lag] -- float (seconds) -- 0.1 -- 0 to 3
+-- [, camera_pitch] -- float (degrees) -- 0 -- -45 to 80
+-- [, behindness_angle] -- float (degrees) -- 10 -- 0 to 180
+-- [, behindness_lag] -- float (seconds) -- 0 -- 0 to 3
+-- [, camera_locked] -- bool -- false
+-- [, focus_locked]} -- bool -- false
+function LLAgent.setCamera(...)
+ local args = mapargs('camera_pos,focus_pos,focus_offset,focus_lag,camera_lag,' ..
+ 'distance,focus_threshold,camera_threshold,camera_pitch,' ..
+ 'camera_locked,focus_locked,behindness_angle,behindness_lag', ...)
+ args.op = 'setCameraParams'
+ leap.send('LLAgent', args)
+end
+
+function LLAgent.setFollowCamActive(active)
+ leap.send('LLAgent', {op = 'setFollowCamActive', active = active})
+end
+
+function LLAgent.removeCamParams()
+ leap.send('LLAgent', {op = 'removeCameraParams'})
+end
+
+return LLAgent
diff --git a/indra/newview/scripts/lua/test_camera_control.lua b/indra/newview/scripts/lua/test_camera_control.lua
new file mode 100644
index 0000000000..9b35cdf8cd
--- /dev/null
+++ b/indra/newview/scripts/lua/test_camera_control.lua
@@ -0,0 +1,49 @@
+local Floater = require 'Floater'
+local LLAgent = require 'LLAgent'
+local startup = require 'startup'
+
+local flt = Floater('luafloater_camera_control.xml')
+
+function getValue(ctrl_name)
+ return flt:request({action="get_value", ctrl_name=ctrl_name}).value
+end
+
+function setValue(ctrl_name, value)
+ flt:post({action="set_value", ctrl_name=ctrl_name, value=value})
+end
+
+function flt:commit_update_btn(event_data)
+ lock_focus = getValue('lock_focus_ctrl')
+ lock_camera = getValue('lock_camera_ctrl')
+ local camera_pos = {getValue('cam_x'), getValue('cam_y'), getValue('cam_z')}
+ local focus_pos = {getValue('focus_x'), getValue('focus_y'), getValue('focus_z')}
+
+ LLAgent.setCamera{camera_pos=camera_pos, focus_pos=focus_pos,
+ focus_locked=lock_focus, camera_locked=lock_camera}
+
+ self:post({action="add_text", ctrl_name="events_editor",
+ value = {'Updating FollowCam params', 'camera_pos:', camera_pos, 'focus_pos:', focus_pos,
+ 'lock_focus:', lock_focus, 'lock_camera:', lock_camera}})
+end
+
+function flt:commit_agent_cam_btn(event_data)
+ agent_pos = LLAgent.getRegionPosition()
+ setValue('cam_x', math.floor(agent_pos[1]))
+ setValue('cam_y', math.floor(agent_pos[2]))
+ setValue('cam_z', math.floor(agent_pos[3]))
+end
+
+function flt:commit_agent_focus_btn(event_data)
+ agent_pos = LLAgent.getRegionPosition()
+ setValue('focus_x', math.floor(agent_pos[1]))
+ setValue('focus_y', math.floor(agent_pos[2]))
+ setValue('focus_z', math.floor(agent_pos[3]))
+end
+
+function flt:commit_reset_btn(event_data)
+ LLAgent.removeCamParams()
+ LLAgent.setFollowCamActive(false)
+end
+
+startup.wait('STATE_STARTED')
+flt:show()