From 35b4a08ff0485bd6498dc929a99c9fd67da0e089 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Mon, 24 Jan 2011 17:50:12 -0800 Subject: Added new notifications for ER-393 and ER-394 --- indra/newview/skins/default/xui/en/notifications.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 6f21938bdb..09e35994ad 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -4829,6 +4829,20 @@ You don't have permission to view this notecard. Insufficient permissions to rez object. + +Unable to send IM across parent estates. + + + +Unable to transfer inventory across parent estates. + + Date: Mon, 24 Jan 2011 18:15:03 -0800 Subject: Exposing estate_id in new instant message for viewer use. Part of ER-393 --- indra/newview/llimview.cpp | 1 + indra/newview/llimview.h | 1 + indra/newview/llviewermessage.cpp | 8 ++++++++ 3 files changed, 10 insertions(+) (limited to 'indra') diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index afd565bb26..00000bffc9 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -3231,6 +3231,7 @@ public: std::string((char*)&bin_bucket[0]), IM_SESSION_INVITE, message_params["parent_estate_id"].asInteger(), + message_params["estate_id"].asInteger(), message_params["region_id"].asUUID(), ll_vector3_from_sd(message_params["position"]), true); diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index a15776c207..486e8c2d5d 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -335,6 +335,7 @@ public: const std::string& session_name = LLStringUtil::null, EInstantMessage dialog = IM_NOTHING_SPECIAL, U32 parent_estate_id = 0, + U32 estate_id = 0, const LLUUID& region_id = LLUUID::null, const LLVector3& position = LLVector3::zero, bool link_name = false); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 7dc5d96689..858e558e6c 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2202,6 +2202,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) std::string name; std::string message; U32 parent_estate_id = 0; + U32 estate_id = 0; LLUUID region_id; LLVector3 position; U8 binary_bucket[MTUBYTES]; @@ -2221,6 +2222,10 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, name); msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, message); msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id); + if (msg->getNumberOfBlocks(_PREHASH_EstateBlock) > 0) + { + msg->getU32Fast(_PREHASH_EstateBlock, _PREHASH_EstateID, estate_id); + } msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_RegionID, region_id); msg->getVector3Fast(_PREHASH_MessageBlock, _PREHASH_Position, position); msg->getBinaryDataFast( _PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES); @@ -2321,6 +2326,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLStringUtil::null, dialog, parent_estate_id, + estate_id, region_id, position, true); @@ -2366,6 +2372,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLStringUtil::null, dialog, parent_estate_id, + estate_id, region_id, position, true); @@ -2683,6 +2690,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) ll_safe_string((char*)binary_bucket), IM_SESSION_INVITE, parent_estate_id, + estate_id, region_id, position, true); -- cgit v1.2.3 From 4a083db6c52d2cc5c1cd1f908270f5952ace6505 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Tue, 25 Jan 2011 08:16:29 -0800 Subject: Backed out changeset b3a24f496b23 --- indra/newview/llimview.cpp | 1 - indra/newview/llimview.h | 1 - indra/newview/llviewermessage.cpp | 8 -------- 3 files changed, 10 deletions(-) (limited to 'indra') diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 00000bffc9..afd565bb26 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -3231,7 +3231,6 @@ public: std::string((char*)&bin_bucket[0]), IM_SESSION_INVITE, message_params["parent_estate_id"].asInteger(), - message_params["estate_id"].asInteger(), message_params["region_id"].asUUID(), ll_vector3_from_sd(message_params["position"]), true); diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 486e8c2d5d..a15776c207 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -335,7 +335,6 @@ public: const std::string& session_name = LLStringUtil::null, EInstantMessage dialog = IM_NOTHING_SPECIAL, U32 parent_estate_id = 0, - U32 estate_id = 0, const LLUUID& region_id = LLUUID::null, const LLVector3& position = LLVector3::zero, bool link_name = false); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 858e558e6c..7dc5d96689 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2202,7 +2202,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) std::string name; std::string message; U32 parent_estate_id = 0; - U32 estate_id = 0; LLUUID region_id; LLVector3 position; U8 binary_bucket[MTUBYTES]; @@ -2222,10 +2221,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, name); msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, message); msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id); - if (msg->getNumberOfBlocks(_PREHASH_EstateBlock) > 0) - { - msg->getU32Fast(_PREHASH_EstateBlock, _PREHASH_EstateID, estate_id); - } msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_RegionID, region_id); msg->getVector3Fast(_PREHASH_MessageBlock, _PREHASH_Position, position); msg->getBinaryDataFast( _PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES); @@ -2326,7 +2321,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLStringUtil::null, dialog, parent_estate_id, - estate_id, region_id, position, true); @@ -2372,7 +2366,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLStringUtil::null, dialog, parent_estate_id, - estate_id, region_id, position, true); @@ -2690,7 +2683,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) ll_safe_string((char*)binary_bucket), IM_SESSION_INVITE, parent_estate_id, - estate_id, region_id, position, true); -- cgit v1.2.3 From 9a9f813c2f1292942c8cc8fcde9c48ed2ca31f42 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Mon, 7 Mar 2011 17:16:16 -0800 Subject: Added some error checking, because s*** happens. --- indra/newview/llappviewerwin32.cpp | 41 +++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) (limited to 'indra') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index d328567a0e..2fbec6e49e 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -301,23 +301,44 @@ void create_console() // redirect unbuffered STDOUT to the console l_std_handle = (long)GetStdHandle(STD_OUTPUT_HANDLE); h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); - fp = _fdopen( h_con_handle, "w" ); - *stdout = *fp; - setvbuf( stdout, NULL, _IONBF, 0 ); + if (h_con_handle == -1) + { + llwarns << "create_console() failed to open stdout handle" << llendl; + } + else + { + fp = _fdopen( h_con_handle, "w" ); + *stdout = *fp; + setvbuf( stdout, NULL, _IONBF, 0 ); + } // redirect unbuffered STDIN to the console l_std_handle = (long)GetStdHandle(STD_INPUT_HANDLE); h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); - fp = _fdopen( h_con_handle, "r" ); - *stdin = *fp; - setvbuf( stdin, NULL, _IONBF, 0 ); + if (h_con_handle == -1) + { + llwarns << "create_console() failed to open stdin handle" << llendl; + } + else + { + fp = _fdopen( h_con_handle, "r" ); + *stdin = *fp; + setvbuf( stdin, NULL, _IONBF, 0 ); + } // redirect unbuffered STDERR to the console l_std_handle = (long)GetStdHandle(STD_ERROR_HANDLE); h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); - fp = _fdopen( h_con_handle, "w" ); - *stderr = *fp; - setvbuf( stderr, NULL, _IONBF, 0 ); + if (h_con_handle == -1) + { + llwarns << "create_console() failed to open stderr handle" << llendl; + } + else + { + fp = _fdopen( h_con_handle, "w" ); + *stderr = *fp; + setvbuf( stderr, NULL, _IONBF, 0 ); + } } LLAppViewerWin32::LLAppViewerWin32(const char* cmd_line) : @@ -363,8 +384,10 @@ bool LLAppViewerWin32::initLogging() void LLAppViewerWin32::initConsole() { + llinfos << "Test before create_console" << llendl; // pop up debug console create_console(); + llinfos << "Test after create_console" << llendl; return LLAppViewer::initConsole(); } -- cgit v1.2.3 From 07e3f01389c6f86a370e6b591bf8e7d1ccff2729 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Tue, 8 Mar 2011 09:46:56 -0800 Subject: Removed two log messages commited in error earlier. --- indra/newview/llappviewerwin32.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 2fbec6e49e..b9d546de59 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -384,10 +384,8 @@ bool LLAppViewerWin32::initLogging() void LLAppViewerWin32::initConsole() { - llinfos << "Test before create_console" << llendl; // pop up debug console create_console(); - llinfos << "Test after create_console" << llendl; return LLAppViewer::initConsole(); } -- cgit v1.2.3 From 58b393bb1eb2ef15597803741fded4942f3dc647 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Wed, 9 Mar 2011 03:31:48 +0000 Subject: Fix to LLWindow listener keyUp event. Fix to headless client scanKeyboard, allowing input from eventhost --- indra/llwindow/llkeyboardheadless.cpp | 25 ++++++++++++++++++++++++- indra/llwindow/llwindowlistener.cpp | 2 +- indra/newview/llappviewer.cpp | 4 ++-- 3 files changed, 27 insertions(+), 4 deletions(-) (limited to 'indra') diff --git a/indra/llwindow/llkeyboardheadless.cpp b/indra/llwindow/llkeyboardheadless.cpp index 4dfaaed4e1..c87617c9ff 100644 --- a/indra/llwindow/llkeyboardheadless.cpp +++ b/indra/llwindow/llkeyboardheadless.cpp @@ -46,5 +46,28 @@ MASK LLKeyboardHeadless::currentMask(BOOL for_mouse_event) { return MASK_NONE; } void LLKeyboardHeadless::scanKeyboard() -{ } +{ + for (S32 key = 0; key < KEY_COUNT; key++) + { + // Generate callback if any event has occurred on this key this frame. + // Can't just test mKeyLevel, because this could be a slow frame and + // key might have gone down then up. JC + if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) + { + mCurScanKey = key; + mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); + } + } + + // Reset edges for next frame + for (S32 key = 0; key < KEY_COUNT; key++) + { + mKeyUp[key] = FALSE; + mKeyDown[key] = FALSE; + if (mKeyLevel[key]) + { + mKeyLevelFrameCount[key]++; + } + } +} diff --git a/indra/llwindow/llwindowlistener.cpp b/indra/llwindow/llwindowlistener.cpp index 22cc12acee..59f4c89e34 100644 --- a/indra/llwindow/llwindowlistener.cpp +++ b/indra/llwindow/llwindowlistener.cpp @@ -100,7 +100,7 @@ void LLWindowListener::keyUp(LLSD const & evt) } // *TODO - figure out how to handle the mask - mKeyboard->handleTranslatedKeyDown(keycode, 0); + mKeyboard->handleTranslatedKeyUp(keycode, 0); } void LLWindowListener::mouseDown(LLSD const & evt) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f7ec83bea9..d0e1a454fa 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1119,11 +1119,11 @@ bool LLAppViewer::mainLoop() // Scan keyboard for movement keys. Command keys and typing // are handled by windows callbacks. Don't do this until we're // done initializing. JC - if (gViewerWindow->mWindow->getVisible() + if ((gHeadlessClient || gViewerWindow->mWindow->getVisible()) && gViewerWindow->getActive() && !gViewerWindow->mWindow->getMinimized() && LLStartUp::getStartupState() == STATE_STARTED - && !gViewerWindow->getShowProgress() + && (gHeadlessClient || !gViewerWindow->getShowProgress()) && !gFocusMgr.focusLocked()) { LLMemType mjk(LLMemType::MTYPE_JOY_KEY); -- cgit v1.2.3 From bdd994d186369afdfd263d4c40689b165b75bee6 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Wed, 9 Mar 2011 14:32:22 -0800 Subject: Get rid of un-used LLUUID. Reviewed by Kelly --- indra/newview/llstartup.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 49d4983294..7ced909dd3 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1965,7 +1965,6 @@ bool idle_startup() // Start automatic replay if the flag is set. if (gSavedSettings.getBOOL("StatsAutoRun") || LLAgentPilot::sReplaySession) { - LLUUID id; LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL; gAgentPilot.startPlayback(); } -- cgit v1.2.3 From 1558cb30d2e6009fa43a4838b746259298279ef0 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Fri, 11 Mar 2011 14:45:15 -0800 Subject: Added 'getPosition' function to LLAgent control in llEventHost. Reviewed by Kelly. --- indra/newview/llagentlistener.cpp | 27 +++++++++++++++++++++++++++ indra/newview/llagentlistener.h | 1 + 2 files changed, 28 insertions(+) (limited to 'indra') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index c453fe91f4..ef39fed587 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -59,11 +59,20 @@ LLAgentListener::LLAgentListener(LLAgent &agent) "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" + "[\"global\"]: array of global {x, y, z} position\n" + "[\"euler\"]: map of {roll, pitch, yaw}\n" + "[\"quat\"]: array of [x, y, z, w] quaternion values", + &LLAgentListener::getPosition, + LLSDMap("reply", LLSD())); } void LLAgentListener::requestTeleport(LLSD const & event_data) const @@ -140,3 +149,21 @@ void LLAgentListener::getAxes(const LLSD& event) const ("euler", LLSDMap("roll", roll)("pitch", pitch)("yaw", yaw)), event); } + + +void LLAgentListener::getPosition(const LLSD& event) const +{ + LLVector3 region_pos(mAgent.getPositionAgent()); + LLVector3 global_pos(mAgent.getPositionGlobal()); + 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... + sendReply(LLSDMap + ("region", llsd_copy_array(boost::begin(region_pos.mV), boost::end(region_pos.mV))) + ("global", llsd_copy_array(boost::begin(global_pos.mV), boost::end(global_pos.mV))) + ("quat", llsd_copy_array(boost::begin(quat.mQ), boost::end(quat.mQ))) + ("euler", LLSDMap("roll", roll)("pitch", pitch)("yaw", yaw)), + event); +} diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index 0aa58d0b16..6f087fc3da 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -46,6 +46,7 @@ private: void requestStand(LLSD const & event_data) const; void resetAxes(const LLSD& event) const; void getAxes(const LLSD& event) const; + void getPosition(const LLSD& event) const; private: LLAgent & mAgent; -- cgit v1.2.3 From 797a405b3704ec7c7f1aa871a0274c97def7e55e Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Mon, 14 Mar 2011 17:24:20 -0700 Subject: ER-611: Fix viewer so it can support multiple instances if a SLURL is passed in. Added "SLURLPassToOtherInstance" to settings.xml and check before pushing a slurl to another viewer instance. Reviewed by Kelly --- indra/newview/app_settings/settings.xml | 11 +++++++++++ indra/newview/llappviewer.cpp | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index a94ff89a8e..b09fb9b5ff 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12157,6 +12157,17 @@ Value 1 + SLURLPassToOtherInstance + + Comment + Pass execution to prevoius viewer instances if there is a given slurl + Persist + 1 + Type + Boolean + Value + 1 + soundsbeacon Comment diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index d0e1a454fa..2c79749894 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2372,7 +2372,8 @@ bool LLAppViewer::initConfiguration() // it relies on checking a marker file which will not work when running // out of different directories - if (LLStartUp::getStartSLURL().isValid()) + if (LLStartUp::getStartSLURL().isValid() && + !(gSavedSettings.getBOOL("SLURLPassToOtherInstance"))) { if (sendURLToOtherInstance(LLStartUp::getStartSLURL().getSLURLString())) { -- cgit v1.2.3 From 18ae6c639e58c4c996d4c3b2a4b34ef41deab970 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Mon, 14 Mar 2011 17:33:33 -0700 Subject: Added warning if llEventHost LLAgent requestSit() can't find the sit target --- indra/newview/llagentlistener.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'indra') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index ef39fed587..da5bf59e74 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -117,6 +117,11 @@ void LLAgentListener::requestSit(LLSD const & event_data) const object->getRegion()->sendReliableMessage(); } + else + { + llwarns << "LLAgent requestSit could not find the sit target " + << event_data["obj_uuid"].asUUID() << llendl; + } } void LLAgentListener::requestStand(LLSD const & event_data) const -- cgit v1.2.3 From bc0833d5db9e887f72ea6e7a630781203ad6ad77 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Tue, 15 Mar 2011 04:19:16 +0000 Subject: ER-612: Add LLEventAPI access to LLAgent auto pilot --- indra/newview/llagent.cpp | 51 +++++++---- indra/newview/llagent.h | 10 ++- indra/newview/llagentlistener.cpp | 183 ++++++++++++++++++++++++++++---------- indra/newview/llagentlistener.h | 21 +++-- 4 files changed, 191 insertions(+), 74 deletions(-) (limited to 'indra') diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 7d491a7774..9025982310 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -1214,6 +1214,12 @@ void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::s return; } + // Are there any pending callbacks from previous auto pilot requests? + if (mAutoPilotFinishedCallback) + { + mAutoPilotFinishedCallback(dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal) < mAutoPilotStopDistance, mAutoPilotCallbackData); + } + mAutoPilotFinishedCallback = finish_callback; mAutoPilotCallbackData = callback_data; mAutoPilotRotationThreshold = rot_threshold; @@ -1262,22 +1268,8 @@ void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::s } mAutoPilot = TRUE; - mAutoPilotTargetGlobal = target_global; - - // trace ray down to find height of destination from ground - LLVector3d traceEndPt = target_global; - traceEndPt.mdV[VZ] -= 20.f; - - LLVector3d targetOnGround; - LLVector3 groundNorm; - LLViewerObject *obj; + setAutoPilotTargetGlobal(target_global); - LLWorld::getInstance()->resolveStepHeightGlobal(NULL, target_global, traceEndPt, targetOnGround, groundNorm, &obj); - F64 target_height = llmax((F64)gAgentAvatarp->getPelvisToFoot(), target_global.mdV[VZ] - targetOnGround.mdV[VZ]); - - // clamp z value of target to minimum height above ground - mAutoPilotTargetGlobal.mdV[VZ] = targetOnGround.mdV[VZ] + target_height; - mAutoPilotTargetDist = (F32)dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal); if (target_rotation) { mAutoPilotUseRotation = TRUE; @@ -1294,13 +1286,37 @@ void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::s } +//----------------------------------------------------------------------------- +// setAutoPilotTargetGlobal +//----------------------------------------------------------------------------- +void LLAgent::setAutoPilotTargetGlobal(const LLVector3d &target_global) +{ + if (mAutoPilot) + { + mAutoPilotTargetGlobal = target_global; + + // trace ray down to find height of destination from ground + LLVector3d traceEndPt = target_global; + traceEndPt.mdV[VZ] -= 20.f; + + LLVector3d targetOnGround; + LLVector3 groundNorm; + LLViewerObject *obj; + + LLWorld::getInstance()->resolveStepHeightGlobal(NULL, target_global, traceEndPt, targetOnGround, groundNorm, &obj); + F64 target_height = llmax((F64)gAgentAvatarp->getPelvisToFoot(), target_global.mdV[VZ] - targetOnGround.mdV[VZ]); + + // clamp z value of target to minimum height above ground + mAutoPilotTargetGlobal.mdV[VZ] = targetOnGround.mdV[VZ] + target_height; + mAutoPilotTargetDist = (F32)dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal); + } +} + //----------------------------------------------------------------------------- // startFollowPilot() //----------------------------------------------------------------------------- void LLAgent::startFollowPilot(const LLUUID &leader_id) { - if (!mAutoPilot) return; - mLeaderID = leader_id; if ( mLeaderID.isNull() ) return; @@ -1338,6 +1354,7 @@ void LLAgent::stopAutoPilot(BOOL user_cancel) if (mAutoPilotFinishedCallback) { mAutoPilotFinishedCallback(!user_cancel && dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal) < mAutoPilotStopDistance, mAutoPilotCallbackData); + mAutoPilotFinishedCallback = NULL; } mLeaderID = LLUUID::null; diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 896408c0dd..0fc77bd3a1 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -467,6 +467,14 @@ public: public: BOOL getAutoPilot() const { return mAutoPilot; } LLVector3d getAutoPilotTargetGlobal() const { return mAutoPilotTargetGlobal; } + LLUUID getAutoPilotLeaderID() const { return mLeaderID; } + F32 getAutoPilotStopDistance() const { return mAutoPilotStopDistance; } + F32 getAutoPilotTargetDist() const { return mAutoPilotTargetDist; } + BOOL getAutoPilotUseRotation() const { return mAutoPilotUseRotation; } + LLVector3 getAutoPilotTargetFacing() const { return mAutoPilotTargetFacing; } + F32 getAutoPilotRotationThreshold() const { return mAutoPilotRotationThreshold; } + std::string getAutoPilotBehaviorName() const { return mAutoPilotBehaviorName; } + void startAutoPilotGlobal(const LLVector3d &pos_global, const std::string& behavior_name = std::string(), const LLQuaternion *target_rotation = NULL, @@ -474,7 +482,7 @@ public: F32 stop_distance = 0.f, F32 rotation_threshold = 0.03f); void startFollowPilot(const LLUUID &leader_id); void stopAutoPilot(BOOL user_cancel = FALSE); - void setAutoPilotGlobal(const LLVector3d &pos_global); + void setAutoPilotTargetGlobal(const LLVector3d &target_global); void autoPilot(F32 *delta_yaw); // Autopilot walking action, angles in radians void renderAutoPilotTarget(); private: diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index ef39fed587..8377a66286 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -45,14 +45,14 @@ LLAgentListener::LLAgentListener(LLAgent &agent) "LLAgent listener to (e.g.) teleport, sit, stand, etc."), mAgent(agent) { - add("requestTeleport", + add("requestTeleport", "Teleport: [\"regionname\"], [\"x\"], [\"y\"], [\"z\"]\n" "If [\"skip_confirmation\"] is true, use LLURLDispatcher rather than LLCommandDispatcher.", &LLAgentListener::requestTeleport); - add("requestSit", + add("requestSit", "Ask to sit on the object specified in [\"obj_uuid\"]", &LLAgentListener::requestSit); - add("requestStand", + add("requestStand", "Ask to stand up", &LLAgentListener::requestStand); add("resetAxes", @@ -73,55 +73,90 @@ LLAgentListener::LLAgentListener(LLAgent &agent) "[\"quat\"]: array of [x, y, z, w] quaternion values", &LLAgentListener::getPosition, LLSDMap("reply", LLSD())); + add("startAutoPilot", + "Start the autopilot system using the following parameters:\n" + "[\"target_global\"]: array of target global {x, y, z} position\n" + "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]\n" + "[\"target_rotation\"]: array of [x, y, z, w] quaternion values [default: no target]\n" + "[\"rotation_threshold\"]: target maximum angle from target facing rotation [default: 0.03 radians]\n" + "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]", + //"[\"callback_pump\"]: pump to send success/failure and callback data to [default: none]\n" + //"[\"callback_data\"]: data to send back during a callback [default: none]", + &LLAgentListener::startAutoPilot); + add("getAutoPilot", + "Send information about current state of the autopilot system to [\"reply\"]:\n" + "[\"enabled\"]: boolean indicating whether or not autopilot is enabled\n" + "[\"target_global\"]: array of target global {x, y, z} position\n" + "[\"leader_id\"]: uuid of target autopilot is following\n" + "[\"stop_distance\"]: target maximum distance from target\n" + "[\"target_distance\"]: last known distance from target\n" + "[\"use_rotation\"]: boolean indicating if autopilot has a target facing rotation\n" + "[\"target_facing\"]: array of {x, y} target direction to face\n" + "[\"rotation_threshold\"]: target maximum angle from target facing rotation\n" + "[\"behavior_name\"]: name of the autopilot behavior", + &LLAgentListener::getAutoPilot, + LLSDMap("reply", LLSD())); + add("startFollowPilot", + "Follow [\"leader_id\"] using the autopilot system.", + &LLAgentListener::startFollowPilot); + add("setAutoPilotTarget", + "Update target for currently running autopilot:\n" + "[\"target_global\"]: array of target global {x, y, z} position", + &LLAgentListener::setAutoPilotTarget); + add("stopAutoPilot", + "Stop the autopilot system:\n" + "[\"user_cancel\"] indicates whether or not to act as though user canceled autopilot [default: false]", + &LLAgentListener::stopAutoPilot); + } void LLAgentListener::requestTeleport(LLSD const & event_data) const { - if(event_data["skip_confirmation"].asBoolean()) - { - LLSD params(LLSD::emptyArray()); - params.append(event_data["regionname"]); - params.append(event_data["x"]); - params.append(event_data["y"]); - params.append(event_data["z"]); - LLCommandDispatcher::dispatch("teleport", params, LLSD(), NULL, true); - // *TODO - lookup other LLCommandHandlers for "agent", "classified", "event", "group", "floater", "parcel", "login", login_refresh", "balance", "chat" - // should we just compose LLCommandHandler and LLDispatchListener? - } - else - { - std::string url = LLSLURL(event_data["regionname"], - LLVector3(event_data["x"].asReal(), - event_data["y"].asReal(), - event_data["z"].asReal())).getSLURLString(); - LLURLDispatcher::dispatch(url, NULL, false); - } + if(event_data["skip_confirmation"].asBoolean()) + { + LLSD params(LLSD::emptyArray()); + params.append(event_data["regionname"]); + params.append(event_data["x"]); + params.append(event_data["y"]); + params.append(event_data["z"]); + LLCommandDispatcher::dispatch("teleport", params, LLSD(), NULL, true); + // *TODO - lookup other LLCommandHandlers for "agent", "classified", "event", "group", "floater", "parcel", "login", login_refresh", "balance", "chat" + // should we just compose LLCommandHandler and LLDispatchListener? + } + else + { + std::string url = LLSLURL(event_data["regionname"], + LLVector3(event_data["x"].asReal(), + event_data["y"].asReal(), + event_data["z"].asReal())).getSLURLString(); + LLURLDispatcher::dispatch(url, NULL, false); + } } void LLAgentListener::requestSit(LLSD const & event_data) const { - //mAgent.getAvatarObject()->sitOnObject(); - // shamelessly ripped from llviewermenu.cpp:handle_sit_or_stand() - // *TODO - find a permanent place to share this code properly. - LLViewerObject *object = gObjectList.findObject(event_data["obj_uuid"]); - - if (object && object->getPCode() == LL_PCODE_VOLUME) - { - gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, mAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, mAgent.getSessionID()); - gMessageSystem->nextBlockFast(_PREHASH_TargetObject); - gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID); - gMessageSystem->addVector3Fast(_PREHASH_Offset, LLVector3(0,0,0)); - - object->getRegion()->sendReliableMessage(); - } + //mAgent.getAvatarObject()->sitOnObject(); + // shamelessly ripped from llviewermenu.cpp:handle_sit_or_stand() + // *TODO - find a permanent place to share this code properly. + LLViewerObject *object = gObjectList.findObject(event_data["obj_uuid"]); + + if (object && object->getPCode() == LL_PCODE_VOLUME) + { + gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, mAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, mAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_TargetObject); + gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID); + gMessageSystem->addVector3Fast(_PREHASH_Offset, LLVector3(0,0,0)); + + object->getRegion()->sendReliableMessage(); + } } void LLAgentListener::requestStand(LLSD const & event_data) const { - mAgent.setControlFlags(AGENT_CONTROL_STAND_UP); + mAgent.setControlFlags(AGENT_CONTROL_STAND_UP); } void LLAgentListener::resetAxes(const LLSD& event) const @@ -153,17 +188,69 @@ void LLAgentListener::getAxes(const LLSD& event) const void LLAgentListener::getPosition(const LLSD& event) const { - LLVector3 region_pos(mAgent.getPositionAgent()); - LLVector3 global_pos(mAgent.getPositionGlobal()); - LLQuaternion quat(mAgent.getQuat()); F32 roll, pitch, yaw; + LLQuaternion quat(mAgent.getQuat()); quat.getEulerAngles(&roll, &pitch, &yaw); - // The official query API for LLQuaternion's [x, y, z, w] values is its - // public member mQ... sendReply(LLSDMap - ("region", llsd_copy_array(boost::begin(region_pos.mV), boost::end(region_pos.mV))) - ("global", llsd_copy_array(boost::begin(global_pos.mV), boost::end(global_pos.mV))) - ("quat", llsd_copy_array(boost::begin(quat.mQ), boost::end(quat.mQ))) + ("region", ll_sd_from_vector3(mAgent.getPositionAgent())) + ("global", ll_sd_from_vector3d(mAgent.getPositionGlobal())) + ("quat", ll_sd_from_quaternion(quat)) ("euler", LLSDMap("roll", roll)("pitch", pitch)("yaw", yaw)), event); } + + +void LLAgentListener::startAutoPilot(LLSD const & event) const +{ + LLQuaternion target_rotation_value; + LLQuaternion* target_rotation = NULL; + if (event.has("target_rotation")) + { + target_rotation_value = ll_quaternion_from_sd(event["target_rotation"]); + target_rotation = &target_rotation_value; + } + // *TODO: Use callback_pump and callback_data + F32 rotation_threshold = 0.03f; + if (event.has("rotation_threshold")) + { + rotation_threshold = event["rotation_threshold"].asReal(); + } + mAgent.startAutoPilotGlobal(ll_vector3d_from_sd(event["target_global"]), + event["behavior_name"], + target_rotation, + NULL, NULL, + event["stop_distance"].asReal(), + rotation_threshold); +} + +void LLAgentListener::getAutoPilot(const LLSD& event) const +{ + sendReply(LLSDMap + ("enabled", (LLSD::Boolean) mAgent.getAutoPilot()) + ("target_global", ll_sd_from_vector3d(mAgent.getAutoPilotTargetGlobal())) + ("leader_id", mAgent.getAutoPilotLeaderID()) + ("stop_distance", mAgent.getAutoPilotStopDistance()) + ("target_distance", mAgent.getAutoPilotTargetDist()) + ("use_rotation", (LLSD::Boolean) mAgent.getAutoPilotUseRotation()) + ("target_facing", ll_sd_from_vector3(mAgent.getAutoPilotTargetFacing())) + ("rotation_threshold", mAgent.getAutoPilotRotationThreshold()) + ("behavior_name", mAgent.getAutoPilotBehaviorName()), + event); +} + +void LLAgentListener::startFollowPilot(LLSD const & event) const +{ + mAgent.startFollowPilot(event["leader_id"]); +} + +void LLAgentListener::setAutoPilotTarget(LLSD const & event) const +{ + LLVector3d target_global(ll_vector3d_from_sd(event["target_global"])); + mAgent.setAutoPilotTargetGlobal(target_global); +} + +void LLAgentListener::stopAutoPilot(LLSD const & event) const +{ + mAgent.stopAutoPilot(event["user_cancel"]); +} + diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index 6f087fc3da..40225c9c63 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -38,18 +38,23 @@ class LLSD; class LLAgentListener : public LLEventAPI { public: - LLAgentListener(LLAgent &agent); + LLAgentListener(LLAgent &agent); private: - void requestTeleport(LLSD const & event_data) const; - void requestSit(LLSD const & event_data) const; - void requestStand(LLSD const & event_data) const; - void resetAxes(const LLSD& event) const; - void getAxes(const LLSD& event) const; - void getPosition(const LLSD& event) const; + void requestTeleport(LLSD const & event_data) const; + void requestSit(LLSD const & event_data) const; + void requestStand(LLSD const & event_data) const; + void resetAxes(const LLSD& event) const; + void getAxes(const LLSD& event) const; + void getPosition(const LLSD& event) const; + void startAutoPilot(const LLSD& event) const; + void getAutoPilot(const LLSD& event) const; + void startFollowPilot(const LLSD& event) const; + void setAutoPilotTarget(const LLSD& event) const; + void stopAutoPilot(const LLSD& event) const; private: - LLAgent & mAgent; + LLAgent & mAgent; }; #endif // LL_LLAGENTLISTENER_H -- cgit v1.2.3 From b91ac7ae99c4034b31a07a8074f2e14d64790976 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Tue, 15 Mar 2011 16:06:38 -0700 Subject: ER-614 : Add lleventhost API to send chat messages. Reviewed by Kelly --- indra/newview/CMakeLists.txt | 2 + indra/newview/llbottomtray.cpp | 3 ++ indra/newview/llbottomtray.h | 4 ++ indra/newview/llnearbychatbarlistener.cpp | 87 +++++++++++++++++++++++++++++++ indra/newview/llnearbychatbarlistener.h | 50 ++++++++++++++++++ 5 files changed, 146 insertions(+) create mode 100644 indra/newview/llnearbychatbarlistener.cpp create mode 100644 indra/newview/llnearbychatbarlistener.h (limited to 'indra') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 11bebf04ef..c835891cbc 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -307,6 +307,7 @@ set(viewer_SOURCE_FILES llnearbychat.cpp llnearbychatbar.cpp llnearbychathandler.cpp + llnearbychatbarlistener.cpp llnetmap.cpp llnotificationalerthandler.cpp llnotificationgrouphandler.cpp @@ -848,6 +849,7 @@ set(viewer_HEADER_FILES llnearbychat.h llnearbychatbar.h llnearbychathandler.h + llnearbychatbarlistener.h llnetmap.h llnotificationhandler.h llnotificationmanager.h diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index d8ec4b605c..c55c72e2a4 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -44,6 +44,7 @@ #include "llhints.h" #include "llimfloater.h" // for LLIMFloater #include "llnearbychatbar.h" +#include "llnearbychatbarlistener.h" #include "llspeakbutton.h" #include "llsplitbutton.h" #include "llsyswellwindow.h" @@ -551,6 +552,8 @@ BOOL LLBottomTray::postBuild() mNearbyChatBar = findChild("chat_bar"); LLHints::registerHintTarget("chat_bar", mNearbyChatBar->LLView::getHandle()); + mListener.reset(new LLNearbyChatBarListener(*mNearbyChatBar)); + mChatBarContainer = getChild("chat_bar_layout_panel"); mNearbyCharResizeHandlePanel = getChild("chat_bar_resize_handle_panel"); diff --git a/indra/newview/llbottomtray.h b/indra/newview/llbottomtray.h index 04e5f5e9e0..83a33845bf 100644 --- a/indra/newview/llbottomtray.h +++ b/indra/newview/llbottomtray.h @@ -39,6 +39,7 @@ class LLIMChiclet; class LLBottomTrayLite; class LLLayoutPanel; class LLMenuGL; +class LLNearbyChatBarListener; // Build time optimization, generate once in .cpp file #ifndef LLBOTTOMTRAY_CPP @@ -508,6 +509,9 @@ protected: * Image used to show position where dragged button will be dropped. */ LLUIImage* mImageDragIndication; + + // We want only one LLNearbyChatBarListener object, so it's tied to this singleton + boost::shared_ptr mListener; }; #endif // LL_LLBOTTOMPANEL_H diff --git a/indra/newview/llnearbychatbarlistener.cpp b/indra/newview/llnearbychatbarlistener.cpp new file mode 100644 index 0000000000..c30e89c35e --- /dev/null +++ b/indra/newview/llnearbychatbarlistener.cpp @@ -0,0 +1,87 @@ +/** + * @file llnearbychatbarlistener.cpp + * @author Dave Simmons + * @date 2011-03-15 + * @brief Implementation for LLNearbyChatBarListener. + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llnearbychatbarlistener.h" + +#include "llagent.h" +#include "llchat.h" + + +// Ugly glue for llnearbychatbar.cpp utility function. Avoids pulling in a bunch of UI +// definitions. Also needs to get cleaned up from llchatbar.cpp +extern void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); + + +LLNearbyChatBarListener::LLNearbyChatBarListener(LLNearbyChatBar & chatbar) + : LLEventAPI("LLChatBar", + "LLChatBar listener to (e.g.) sendChat, etc."), + mChatbar(chatbar) +{ + add("sendChat", + "Send chat to the simulator:\n" + "[\"message\"] chat message text [required]\n" + "[\"channel\"] chat channel number [default = 0]\n" + "[\"type\"] chat type \"whisper\", \"normal\", \"shout\" [default = \"normal\"]", + &LLNearbyChatBarListener::sendChat); +} + + +// "sendChat" command +void LLNearbyChatBarListener::sendChat(LLSD const & chat_data) const +{ + // Extract the data + std::string chat_text = chat_data["message"].asString(); + + S32 channel = 0; + if (chat_data.has("channel")) + { + channel = chat_data["channel"].asInteger(); + if (channel < 0 || channel >= 2147483647) + { // Use 0 up to (but not including) DEBUG_CHANNEL (wtf isn't that defined??) + channel = 0; + } + } + + EChatType type_o_chat = CHAT_TYPE_NORMAL; + if (chat_data.has("type")) + { + std::string type_string = chat_data["type"].asString(); + if (type_string == "whisper") + { + type_o_chat = CHAT_TYPE_WHISPER; + } + else if (type_string == "shout") + { + type_o_chat = CHAT_TYPE_SHOUT; + } + } + send_chat_from_viewer(chat_text, type_o_chat, channel); +} + diff --git a/indra/newview/llnearbychatbarlistener.h b/indra/newview/llnearbychatbarlistener.h new file mode 100644 index 0000000000..13e4e5990c --- /dev/null +++ b/indra/newview/llnearbychatbarlistener.h @@ -0,0 +1,50 @@ +/** + * @file llnearbychatbarlistener.h + * @author Dave Simmons + * @date 2011-03-15 + * @brief Class definition for LLNearbyChatBarListener. + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#ifndef LL_LLNEARBYCHATBARLISTENER_H +#define LL_LLNEARBYCHATBARLISTENER_H + +#include "lleventapi.h" + +class LLSD; +class LLNearbyChatBar; + +class LLNearbyChatBarListener : public LLEventAPI +{ +public: + LLNearbyChatBarListener(LLNearbyChatBar & chatbar); + +private: + void sendChat(LLSD const & chat_data) const; + + LLNearbyChatBar & mChatbar; +}; + +#endif // LL_LLNEARBYCHATBARLISTENER_H + -- cgit v1.2.3 From acb763878543f2a25131b40646559feb7405c4fa Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Wed, 16 Mar 2011 13:20:18 -0700 Subject: ER-614: Add lleventhost API to send chat messages. Cleanup code a bit, now invoking proper routine to make viewer do chat animations. Commented out some un-used chat related code in llchatbar.cpp and llnotificationmanager.h. Also re-named a singleton class in llnearbychatbar.cpp so we don't have multiple LLChatHandler classes. Reviewed by Kelly --- indra/newview/llchatbar.cpp | 4 ++++ indra/newview/llnearbychatbar.cpp | 6 +++--- indra/newview/llnearbychatbarlistener.cpp | 23 ++++++++++++++++++----- indra/newview/llnotificationmanager.h | 2 +- 4 files changed, 26 insertions(+), 9 deletions(-) (limited to 'indra') diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index 6e58be8174..4a58dc558a 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -671,6 +671,9 @@ void LLChatBar::onCommitGesture(LLUICtrl* ctrl) } } + +/* Cruft - global gChatHandler declared below has been commented out, + so this class is never used. See similar code in llnearbychatbar.cpp class LLChatHandler : public LLCommandHandler { public: @@ -710,3 +713,4 @@ public: // Creating the object registers with the dispatcher. //LLChatHandler gChatHandler; +cruft */ diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp index 836ae9a0cf..7ed949cd10 100644 --- a/indra/newview/llnearbychatbar.cpp +++ b/indra/newview/llnearbychatbar.cpp @@ -864,11 +864,11 @@ void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CHAT_COUNT); } -class LLChatHandler : public LLCommandHandler +class LLChatCommandHandler : public LLCommandHandler { public: // not allowed from outside the app - LLChatHandler() : LLCommandHandler("chat", UNTRUSTED_BLOCK) { } + LLChatCommandHandler() : LLCommandHandler("chat", UNTRUSTED_BLOCK) { } // Your code here bool handle(const LLSD& tokens, const LLSD& query_map, @@ -902,6 +902,6 @@ public: }; // Creating the object registers with the dispatcher. -LLChatHandler gChatHandler; +LLChatCommandHandler gChatHandler; diff --git a/indra/newview/llnearbychatbarlistener.cpp b/indra/newview/llnearbychatbarlistener.cpp index c30e89c35e..99286d972b 100644 --- a/indra/newview/llnearbychatbarlistener.cpp +++ b/indra/newview/llnearbychatbarlistener.cpp @@ -29,15 +29,12 @@ #include "llviewerprecompiledheaders.h" #include "llnearbychatbarlistener.h" +#include "llnearbychatbar.h" #include "llagent.h" #include "llchat.h" -// Ugly glue for llnearbychatbar.cpp utility function. Avoids pulling in a bunch of UI -// definitions. Also needs to get cleaned up from llchatbar.cpp -extern void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); - LLNearbyChatBarListener::LLNearbyChatBarListener(LLNearbyChatBar & chatbar) : LLEventAPI("LLChatBar", @@ -82,6 +79,22 @@ void LLNearbyChatBarListener::sendChat(LLSD const & chat_data) const type_o_chat = CHAT_TYPE_SHOUT; } } - send_chat_from_viewer(chat_text, type_o_chat, channel); + + // Have to prepend /42 style channel numbers + std::string chat_to_send; + if (channel == 0) + { + chat_to_send = chat_text; + } + else + { + chat_to_send += "/"; + chat_to_send += chat_data["channel"].asString(); + chat_to_send += " "; + chat_to_send += chat_text; + } + + // Send it as if it was typed in + mChatbar.sendChatFromViewer(chat_to_send, type_o_chat, (BOOL)(channel == 0)); } diff --git a/indra/newview/llnotificationmanager.h b/indra/newview/llnotificationmanager.h index 72fa394621..16e82e4cce 100644 --- a/indra/newview/llnotificationmanager.h +++ b/indra/newview/llnotificationmanager.h @@ -69,7 +69,7 @@ public: private: //TODO (*) std::map > mNotifyHandlers; - std::map mChatHandlers; + // cruft std::map mChatHandlers; }; } -- cgit v1.2.3 From 034cf7273fab18a7c6ad1fda1b0d2dd600f31825 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Thu, 17 Mar 2011 11:37:20 -0700 Subject: Added optional 'fly' property to LLEventHost "LLAgent" setAutoPilot and getAutoPilot functions. Reviewed by Kelly. --- indra/newview/llagentlistener.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'indra') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index d0361bf768..8476c4847a 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -220,6 +220,11 @@ void LLAgentListener::startAutoPilot(LLSD const & event) const { rotation_threshold = event["rotation_threshold"].asReal(); } + if (event.has("fly")) + { + mAgent.setFlying(event["fly"].asBoolean()); + } + mAgent.startAutoPilotGlobal(ll_vector3d_from_sd(event["target_global"]), event["behavior_name"], target_rotation, @@ -240,6 +245,7 @@ void LLAgentListener::getAutoPilot(const LLSD& event) const ("target_facing", ll_sd_from_vector3(mAgent.getAutoPilotTargetFacing())) ("rotation_threshold", mAgent.getAutoPilotRotationThreshold()) ("behavior_name", mAgent.getAutoPilotBehaviorName()), + ("fly", (LLSD::Boolean) mAgent.getFlying()), event); } -- cgit v1.2.3 From 62214c96d465650f814194215b6b8f39ae38873a Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Thu, 17 Mar 2011 11:38:43 -0700 Subject: ER-616 : Create LLEventHost API to receive incoming chat messages. Added "LLChat" LLEventStream and pass incoming chat to it. Reviewed by Kelly. --- indra/newview/llnearbychathandler.cpp | 31 +++++++++++++++++-------------- indra/newview/llnearbychathandler.h | 4 ++++ 2 files changed, 21 insertions(+), 14 deletions(-) (limited to 'indra') diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp index de5439e4e0..7e0f066b1d 100644 --- a/indra/newview/llnearbychathandler.cpp +++ b/indra/newview/llnearbychathandler.cpp @@ -441,6 +441,8 @@ void LLNearbyChatScreenChannel::reshape (S32 width, S32 height, BOOL called_fr //----------------------------------------------------------------------------------------------- //LLNearbyChatHandler //----------------------------------------------------------------------------------------------- +boost::scoped_ptr LLNearbyChatHandler::sChatWatcher(new LLEventStream("LLChat")); + LLNearbyChatHandler::LLNearbyChatHandler(e_notification_type type, const LLSD& id) { mType = type; @@ -525,6 +527,19 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args) LLFirstUse::otherAvatarChatFirst(); } + // Build data and send event on to LLEventStream + LLSD notification; + notification["message"] = chat_msg.mText; + notification["from"] = chat_msg.mFromName; + notification["from_id"] = chat_msg.mFromID; + notification["time"] = chat_msg.mTime; + notification["source"] = (S32)chat_msg.mSourceType; + notification["chat_type"] = (S32)chat_msg.mChatType; + notification["chat_style"] = (S32)chat_msg.mChatStyle; + + sChatWatcher->post(notification); + + if( nearby_chat->getVisible() || ( chat_msg.mSourceType == CHAT_SOURCE_AGENT && gSavedSettings.getBOOL("UseChatBubbles") ) @@ -558,24 +573,13 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args) } */ - LLUUID id; - id.generate(); - LLNearbyChatScreenChannel* channel = dynamic_cast(mChannel); - if(channel) { - LLSD notification; + LLUUID id; + id.generate(); notification["id"] = id; - notification["message"] = chat_msg.mText; - notification["from"] = chat_msg.mFromName; - notification["from_id"] = chat_msg.mFromID; - notification["time"] = chat_msg.mTime; - notification["source"] = (S32)chat_msg.mSourceType; - notification["chat_type"] = (S32)chat_msg.mChatType; - notification["chat_style"] = (S32)chat_msg.mChatStyle; - std::string r_color_name = "White"; F32 r_color_alpha = 1.0f; LLViewerChat::getChatColor( chat_msg, r_color_name, r_color_alpha); @@ -585,7 +589,6 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args) notification["font_size"] = (S32)LLViewerChat::getChatFontSize() ; channel->addNotification(notification); } - } void LLNearbyChatHandler::onDeleteToast(LLToast* toast) diff --git a/indra/newview/llnearbychathandler.h b/indra/newview/llnearbychathandler.h index ec1f29cdfc..b0e4f62d51 100644 --- a/indra/newview/llnearbychathandler.h +++ b/indra/newview/llnearbychathandler.h @@ -29,6 +29,8 @@ #include "llnotificationhandler.h" +class LLEventPump; + //add LLNearbyChatHandler to LLNotificationsUI namespace namespace LLNotificationsUI{ @@ -44,6 +46,8 @@ public: protected: virtual void onDeleteToast(LLToast* toast); virtual void initChannel(); + + static boost::scoped_ptr sChatWatcher; }; } -- cgit v1.2.3 From 1c34f5caff0f074e983a8ef4d89fd08f1210f526 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Thu, 17 Mar 2011 16:22:54 -0700 Subject: ER-612: Add LLEventAPI access to LLAgent auto pilot. Follow-on work to allow blocking of flying during autopilot. Reviewed by Kelly. --- indra/newview/llagent.cpp | 21 ++++++++++--- indra/newview/llagent.h | 4 ++- indra/newview/llagentlistener.cpp | 66 ++++++++++++++++++++++++--------------- 3 files changed, 60 insertions(+), 31 deletions(-) (limited to 'indra') diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 9025982310..75acd1a0be 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -198,6 +198,7 @@ LLAgent::LLAgent() : mAutoPilot(FALSE), mAutoPilotFlyOnStop(FALSE), + mAutoPilotAllowFlying(TRUE), mAutoPilotTargetGlobal(), mAutoPilotStopDistance(1.f), mAutoPilotUseRotation(FALSE), @@ -1207,7 +1208,7 @@ BOOL LLAgent::getBusy() const //----------------------------------------------------------------------------- // startAutoPilotGlobal() //----------------------------------------------------------------------------- -void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::string& behavior_name, const LLQuaternion *target_rotation, void (*finish_callback)(BOOL, void *), void *callback_data, F32 stop_distance, F32 rot_threshold) +void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::string& behavior_name, const LLQuaternion *target_rotation, void (*finish_callback)(BOOL, void *), void *callback_data, F32 stop_distance, F32 rot_threshold, BOOL allow_flying) { if (!isAgentAvatarValid()) { @@ -1224,6 +1225,7 @@ void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::s mAutoPilotCallbackData = callback_data; mAutoPilotRotationThreshold = rot_threshold; mAutoPilotBehaviorName = behavior_name; + mAutoPilotAllowFlying = allow_flying; LLVector3d delta_pos( target_global ); delta_pos -= getPositionGlobal(); @@ -1251,14 +1253,23 @@ void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::s } } - mAutoPilotFlyOnStop = getFlying(); + if (mAutoPilotAllowFlying) + { + mAutoPilotFlyOnStop = getFlying(); + } + else + { + mAutoPilotFlyOnStop = FALSE; + } - if (distance > 30.0) + if (distance > 30.0 && mAutoPilotAllowFlying) { setFlying(TRUE); } - if ( distance > 1.f && heightDelta > (sqrtf(mAutoPilotStopDistance) + 1.f)) + if ( distance > 1.f && + mAutoPilotAllowFlying && + heightDelta > (sqrtf(mAutoPilotStopDistance) + 1.f)) { setFlying(TRUE); // Do not force flying for "Sit" behavior to prevent flying after pressing "Stand" @@ -1394,7 +1405,7 @@ void LLAgent::autoPilot(F32 *delta_yaw) if (!isAgentAvatarValid()) return; - if (gAgentAvatarp->mInAir) + if (gAgentAvatarp->mInAir && mAutoPilotAllowFlying) { setFlying(TRUE); } diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 0fc77bd3a1..a45f55f27a 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -479,7 +479,8 @@ public: const std::string& behavior_name = std::string(), const LLQuaternion *target_rotation = NULL, void (*finish_callback)(BOOL, void *) = NULL, void *callback_data = NULL, - F32 stop_distance = 0.f, F32 rotation_threshold = 0.03f); + F32 stop_distance = 0.f, F32 rotation_threshold = 0.03f, + BOOL allow_flying = TRUE); void startFollowPilot(const LLUUID &leader_id); void stopAutoPilot(BOOL user_cancel = FALSE); void setAutoPilotTargetGlobal(const LLVector3d &target_global); @@ -488,6 +489,7 @@ public: private: BOOL mAutoPilot; BOOL mAutoPilotFlyOnStop; + BOOL mAutoPilotAllowFlying; LLVector3d mAutoPilotTargetGlobal; F32 mAutoPilotStopDistance; BOOL mAutoPilotUseRotation; diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 8476c4847a..6b12853547 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -184,10 +184,13 @@ void LLAgentListener::getAxes(const LLSD& event) const quat.getEulerAngles(&roll, &pitch, &yaw); // The official query API for LLQuaternion's [x, y, z, w] values is its // public member mQ... - sendReply(LLSDMap - ("quat", llsd_copy_array(boost::begin(quat.mQ), boost::end(quat.mQ))) - ("euler", LLSDMap("roll", roll)("pitch", pitch)("yaw", yaw)), - event); + 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); } @@ -196,12 +199,17 @@ void LLAgentListener::getPosition(const LLSD& event) const F32 roll, pitch, yaw; LLQuaternion quat(mAgent.getQuat()); quat.getEulerAngles(&roll, &pitch, &yaw); - sendReply(LLSDMap - ("region", ll_sd_from_vector3(mAgent.getPositionAgent())) - ("global", ll_sd_from_vector3d(mAgent.getPositionGlobal())) - ("quat", ll_sd_from_quaternion(quat)) - ("euler", LLSDMap("roll", roll)("pitch", pitch)("yaw", yaw)), - event); + + 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; + reply["region"] = ll_sd_from_vector3(mAgent.getPositionAgent()); + reply["global"] = ll_sd_from_vector3d(mAgent.getPositionGlobal()); + + sendReply(reply, event); } @@ -220,9 +228,15 @@ void LLAgentListener::startAutoPilot(LLSD const & event) const { rotation_threshold = event["rotation_threshold"].asReal(); } - if (event.has("fly")) + + BOOL allow_flying = TRUE; + if (event.has("allow_flying")) { - mAgent.setFlying(event["fly"].asBoolean()); + allow_flying = (BOOL) event["allow_flying"].asBoolean(); + if (!allow_flying) + { + mAgent.setFlying(FALSE); + } } mAgent.startAutoPilotGlobal(ll_vector3d_from_sd(event["target_global"]), @@ -230,23 +244,25 @@ void LLAgentListener::startAutoPilot(LLSD const & event) const target_rotation, NULL, NULL, event["stop_distance"].asReal(), - rotation_threshold); + rotation_threshold, + allow_flying); } void LLAgentListener::getAutoPilot(const LLSD& event) const { - sendReply(LLSDMap - ("enabled", (LLSD::Boolean) mAgent.getAutoPilot()) - ("target_global", ll_sd_from_vector3d(mAgent.getAutoPilotTargetGlobal())) - ("leader_id", mAgent.getAutoPilotLeaderID()) - ("stop_distance", mAgent.getAutoPilotStopDistance()) - ("target_distance", mAgent.getAutoPilotTargetDist()) - ("use_rotation", (LLSD::Boolean) mAgent.getAutoPilotUseRotation()) - ("target_facing", ll_sd_from_vector3(mAgent.getAutoPilotTargetFacing())) - ("rotation_threshold", mAgent.getAutoPilotRotationThreshold()) - ("behavior_name", mAgent.getAutoPilotBehaviorName()), - ("fly", (LLSD::Boolean) mAgent.getFlying()), - event); + LLSD reply = LLSD::emptyMap(); + reply["enabled"] = (LLSD::Boolean) mAgent.getAutoPilot(); + reply["target_global"] = ll_sd_from_vector3d(mAgent.getAutoPilotTargetGlobal()); + reply["leader_id"] = mAgent.getAutoPilotLeaderID(); + reply["stop_distance"] = mAgent.getAutoPilotStopDistance(); + reply["target_distance"] = mAgent.getAutoPilotTargetDist(); + reply["use_rotation"] = (LLSD::Boolean) mAgent.getAutoPilotUseRotation(); + reply["target_facing"] = ll_sd_from_vector3(mAgent.getAutoPilotTargetFacing()); + reply["rotation_threshold"] = mAgent.getAutoPilotRotationThreshold(); + reply["behavior_name"] = mAgent.getAutoPilotBehaviorName(); + reply["fly"] = (LLSD::Boolean) mAgent.getFlying(); + + sendReply(reply, event); } void LLAgentListener::startFollowPilot(LLSD const & event) const -- cgit v1.2.3 From becc9d09970755f9cc0d95c46b9f2d81d5b856b5 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Tue, 22 Mar 2011 15:44:02 -0700 Subject: Improve LLEventHost API for autopilot and following avatars. Reviewed by Kelly. --- indra/newview/llagent.cpp | 11 +++- indra/newview/llagent.h | 2 +- indra/newview/llagentlistener.cpp | 109 ++++++++++++++++++++++++++++++++++---- indra/newview/llagentlistener.h | 7 +-- 4 files changed, 113 insertions(+), 16 deletions(-) (limited to 'indra') diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 75acd1a0be..fd5cee2772 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -1326,7 +1326,7 @@ void LLAgent::setAutoPilotTargetGlobal(const LLVector3d &target_global) //----------------------------------------------------------------------------- // startFollowPilot() //----------------------------------------------------------------------------- -void LLAgent::startFollowPilot(const LLUUID &leader_id) +void LLAgent::startFollowPilot(const LLUUID &leader_id, BOOL allow_flying, F32 stop_distance) { mLeaderID = leader_id; if ( mLeaderID.isNull() ) return; @@ -1338,7 +1338,14 @@ void LLAgent::startFollowPilot(const LLUUID &leader_id) return; } - startAutoPilotGlobal(object->getPositionGlobal()); + startAutoPilotGlobal(object->getPositionGlobal(), + std::string(), // behavior_name + NULL, // target_rotation + NULL, // finish_callback + NULL, // callback_data + stop_distance, + 0.03f, // rotation_threshold + allow_flying); } diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index a45f55f27a..33c05816e2 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -481,7 +481,7 @@ public: void (*finish_callback)(BOOL, void *) = NULL, void *callback_data = NULL, F32 stop_distance = 0.f, F32 rotation_threshold = 0.03f, BOOL allow_flying = TRUE); - void startFollowPilot(const LLUUID &leader_id); + void startFollowPilot(const LLUUID &leader_id, BOOL allow_flying = TRUE, F32 stop_distance = 0.5f); void stopAutoPilot(BOOL user_cancel = FALSE); void setAutoPilotTargetGlobal(const LLVector3d &target_global); void autoPilot(F32 *delta_yaw); // Autopilot walking action, angles in radians diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 6b12853547..0d30b95074 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -31,6 +31,7 @@ #include "llagentlistener.h" #include "llagent.h" +#include "llvoavatar.h" #include "llcommandhandler.h" #include "llslurl.h" #include "llurldispatcher.h" @@ -79,7 +80,8 @@ LLAgentListener::LLAgentListener(LLAgent &agent) "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]\n" "[\"target_rotation\"]: array of [x, y, z, w] quaternion values [default: no target]\n" "[\"rotation_threshold\"]: target maximum angle from target facing rotation [default: 0.03 radians]\n" - "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]", + "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]" + "[\"allow_flying\"]: allow flying during autopilot [default: True]", //"[\"callback_pump\"]: pump to send success/failure and callback data to [default: none]\n" //"[\"callback_data\"]: data to send back during a callback [default: none]", &LLAgentListener::startAutoPilot); @@ -97,7 +99,10 @@ LLAgentListener::LLAgentListener(LLAgent &agent) &LLAgentListener::getAutoPilot, LLSDMap("reply", LLSD())); add("startFollowPilot", - "Follow [\"leader_id\"] using the autopilot system.", + "[\"leader_id\"]: uuid of target to follow using the autopilot system (optional with avatar_name)\n" + "[\"avatar_name\"]: avatar name to follow using the autopilot system (optional with leader_id)\n" + "[\"allow_flying\"]: allow flying during autopilot [default: True]\n" + "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]", &LLAgentListener::startFollowPilot); add("setAutoPilotTarget", "Update target for currently running autopilot:\n" @@ -213,7 +218,7 @@ void LLAgentListener::getPosition(const LLSD& event) const } -void LLAgentListener::startAutoPilot(LLSD const & event) const +void LLAgentListener::startAutoPilot(LLSD const & event) { LLQuaternion target_rotation_value; LLQuaternion* target_rotation = NULL; @@ -239,11 +244,20 @@ void LLAgentListener::startAutoPilot(LLSD const & event) const } } + F32 stop_distance = 0.f; + if (event.has("stop_distance")) + { + stop_distance = event["stop_distance"].asReal(); + } + + // Clear follow target, this is doing a path + mFollowTarget.setNull(); + mAgent.startAutoPilotGlobal(ll_vector3d_from_sd(event["target_global"]), event["behavior_name"], target_rotation, NULL, NULL, - event["stop_distance"].asReal(), + stop_distance, rotation_threshold, allow_flying); } @@ -251,11 +265,29 @@ void LLAgentListener::startAutoPilot(LLSD const & event) const void LLAgentListener::getAutoPilot(const LLSD& event) const { LLSD reply = LLSD::emptyMap(); - reply["enabled"] = (LLSD::Boolean) mAgent.getAutoPilot(); + + LLSD::Boolean enabled = mAgent.getAutoPilot(); + reply["enabled"] = enabled; + reply["target_global"] = ll_sd_from_vector3d(mAgent.getAutoPilotTargetGlobal()); + reply["leader_id"] = mAgent.getAutoPilotLeaderID(); + reply["stop_distance"] = mAgent.getAutoPilotStopDistance(); + reply["target_distance"] = mAgent.getAutoPilotTargetDist(); + if (!enabled && + mFollowTarget.notNull()) + { // Get an actual distance from the target object we were following + LLViewerObject * target = gObjectList.findObject(mFollowTarget); + if (target) + { // Found the target AV, return the actual distance to them as well as their ID + LLVector3 difference = target->getPositionRegion() - mAgent.getPositionAgent(); + reply["target_distance"] = difference.length(); + reply["leader_id"] = mFollowTarget; + } + } + reply["use_rotation"] = (LLSD::Boolean) mAgent.getAutoPilotUseRotation(); reply["target_facing"] = ll_sd_from_vector3(mAgent.getAutoPilotTargetFacing()); reply["rotation_threshold"] = mAgent.getAutoPilotRotationThreshold(); @@ -265,19 +297,76 @@ void LLAgentListener::getAutoPilot(const LLSD& event) const sendReply(reply, event); } -void LLAgentListener::startFollowPilot(LLSD const & event) const +void LLAgentListener::startFollowPilot(LLSD const & event) { - mAgent.startFollowPilot(event["leader_id"]); + LLUUID target_id; + + BOOL allow_flying = TRUE; + if (event.has("allow_flying")) + { + allow_flying = (BOOL) event["allow_flying"].asBoolean(); + } + + if (event.has("leader_id")) + { + target_id = event["leader_id"]; + } + else if (event.has("avatar_name")) + { // Find the avatar with matching name + std::string target_name = event["avatar_name"].asString(); + + if (target_name.length() > 0) + { + S32 num_objects = gObjectList.getNumObjects(); + S32 cur_index = 0; + while (cur_index < num_objects) + { + LLViewerObject * cur_object = gObjectList.getObject(cur_index++); + if (cur_object && + cur_object->asAvatar() && + cur_object->asAvatar()->getFullname() == target_name) + { // Found avatar with matching name, extract id and break out of loop + target_id = cur_object->getID(); + break; + } + } + } + } + + F32 stop_distance = 0.f; + if (event.has("stop_distance")) + { + stop_distance = event["stop_distance"].asReal(); + } + + if (target_id.notNull()) + { + if (!allow_flying) + { + mAgent.setFlying(FALSE); + } + mFollowTarget = target_id; // Save follow target so we can report distance later + + mAgent.startFollowPilot(target_id, allow_flying, stop_distance); + } } void LLAgentListener::setAutoPilotTarget(LLSD const & event) const { - LLVector3d target_global(ll_vector3d_from_sd(event["target_global"])); - mAgent.setAutoPilotTargetGlobal(target_global); + if (event.has("target_global")) + { + LLVector3d target_global(ll_vector3d_from_sd(event["target_global"])); + mAgent.setAutoPilotTargetGlobal(target_global); + } } void LLAgentListener::stopAutoPilot(LLSD const & event) const { - mAgent.stopAutoPilot(event["user_cancel"]); + BOOL user_cancel = FALSE; + if (event.has("user_cancel")) + { + user_cancel = event["user_cancel"].asBoolean(); + } + mAgent.stopAutoPilot(user_cancel); } diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index 40225c9c63..aadb87db12 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -47,14 +47,15 @@ private: void resetAxes(const LLSD& event) const; void getAxes(const LLSD& event) const; void getPosition(const LLSD& event) const; - void startAutoPilot(const LLSD& event) const; + void startAutoPilot(const LLSD& event); void getAutoPilot(const LLSD& event) const; - void startFollowPilot(const LLSD& event) const; + void startFollowPilot(const LLSD& event); void setAutoPilotTarget(const LLSD& event) const; void stopAutoPilot(const LLSD& event) const; private: - LLAgent & mAgent; + LLAgent & mAgent; + LLUUID mFollowTarget; }; #endif // LL_LLAGENTLISTENER_H -- cgit v1.2.3 From 7517f25c4322c858cc7a60d62532dfb654a805dc Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Thu, 24 Mar 2011 10:39:22 -0700 Subject: ER-650: touch events. Added 'requestTouch' API for LLAgent operations via llEventHost. Re-factored some message sending code for grabs. Reviewed by Kelly --- indra/newview/llagentlistener.cpp | 75 +++++++++++++++++++++++++++++ indra/newview/llagentlistener.h | 1 + indra/newview/lltoolgrab.cpp | 99 +++++++++++++++++++++++++-------------- indra/newview/lltoolgrab.h | 7 +++ indra/newview/llviewermenu.cpp | 50 +++++--------------- 5 files changed, 160 insertions(+), 72 deletions(-) (limited to 'indra') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 0d30b95074..0a13644911 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -40,6 +40,7 @@ #include "llviewerregion.h" #include "llsdutil.h" #include "llsdutil_math.h" +#include "lltoolgrab.h" LLAgentListener::LLAgentListener(LLAgent &agent) : LLEventAPI("LLAgent", @@ -56,6 +57,11 @@ LLAgentListener::LLAgentListener(LLAgent &agent) add("requestStand", "Ask to stand up", &LLAgentListener::requestStand); + add("requestTouch", + "[\"obj_uuid\"]: id of object to touch, use this or [\"position\"] to indicate the object to touch" + "[\"position\"]: region position {x, y, z} where to find closest object to touch" + "[\"face\"]: optional object face number to touch[Default: 0]", + &LLAgentListener::requestTouch); add("resetAxes", "Set the agent to a fixed orientation (optionally specify [\"lookat\"] = array of [x, y, z])", &LLAgentListener::resetAxes); @@ -169,6 +175,75 @@ void LLAgentListener::requestStand(LLSD const & event_data) const mAgent.setControlFlags(AGENT_CONTROL_STAND_UP); } +void LLAgentListener::requestTouch(LLSD const & event_data) const +{ + LLViewerObject *object = NULL; + + if (event_data.has("obj_uuid")) + { + object = gObjectList.findObject(event_data["obj_uuid"]); + } + else if (event_data.has("position")) + { + LLVector3 target_position = ll_vector3_from_sd(event_data["position"]); + + // Find the object closest to that position + F32 min_distance = 10000.0f; // Start big + S32 num_objects = gObjectList.getNumObjects(); + S32 cur_index = 0; + while (cur_index < num_objects) + { + LLViewerObject * cur_object = gObjectList.getObject(cur_index++); + if (cur_object) + { // Calculate distance from the target position + LLVector3 target_diff = cur_object->getPositionRegion() - target_position; + F32 distance_to_target = target_diff.length(); + if (distance_to_target < min_distance) + { // Found an object closer + min_distance = distance_to_target; + object = cur_object; + } + } + } + } + + S32 face = 0; + if (event_data.has("face")) + { + face = event_data["face"].asInteger(); + } + + if (object && object->getPCode() == LL_PCODE_VOLUME) + { + // Fake enough pick info to get it to (hopefully) work + LLPickInfo pick; + pick.mObjectFace = face; + + /* + These values are sent to the simulator, but face seems to be easiest to use + + pick.mUVCoords "UVCoord" + pick.mSTCoords "STCoord" + pick.mObjectFace "FaceIndex" + pick.mIntersection "Position" + pick.mNormal "Normal" + pick.mBinormal "Binormal" + */ + + // A touch is a sketchy message sequence ... send a grab, immediately + // followed by un-grabbing, crossing fingers and hoping packets arrive in + // the correct order + send_ObjectGrab_message(object, pick, LLVector3::zero); + send_ObjectDeGrab_message(object, pick); + } + else + { + llwarns << "LLAgent requestTouch could not find the touch target " + << event_data["obj_uuid"].asUUID() << llendl; + } +} + + void LLAgentListener::resetAxes(const LLSD& event) const { if (event.has("lookat")) diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index aadb87db12..6aeda5f8db 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -44,6 +44,7 @@ private: void requestTeleport(LLSD const & event_data) const; void requestSit(LLSD const & event_data) const; void requestStand(LLSD const & event_data) const; + void requestTouch(LLSD const & event_data) const; void resetAxes(const LLSD& event) const; void getAxes(const LLSD& event) const; void getPosition(const LLSD& event) const; diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp index b6c0f662e5..319e2508e0 100644 --- a/indra/newview/lltoolgrab.cpp +++ b/indra/newview/lltoolgrab.cpp @@ -54,7 +54,6 @@ #include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" -#include "llviewerwindow.h" #include "llvoavatarself.h" #include "llworld.h" @@ -387,22 +386,7 @@ void LLToolGrab::startGrab() mDragStartPointGlobal = grab_start_global; mDragStartFromCamera = grab_start_global - gAgentCamera.getCameraPositionGlobal(); - LLMessageSystem *msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ObjectGrab); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU32Fast(_PREHASH_LocalID, objectp->mLocalID); - msg->addVector3Fast(_PREHASH_GrabOffset, grab_offset ); - msg->nextBlock("SurfaceInfo"); - msg->addVector3("UVCoord", LLVector3(mGrabPick.mUVCoords)); - msg->addVector3("STCoord", LLVector3(mGrabPick.mSTCoords)); - msg->addS32Fast(_PREHASH_FaceIndex, mGrabPick.mObjectFace); - msg->addVector3("Position", mGrabPick.mIntersection); - msg->addVector3("Normal", mGrabPick.mNormal); - msg->addVector3("Binormal", mGrabPick.mBinormal); - msg->sendMessage( objectp->getRegion()->getHost()); + send_ObjectGrab_message(objectp, mGrabPick, grab_offset); mGrabOffsetFromCenterInitial = grab_offset; mGrabHiddenOffsetFromCamera = mDragStartFromCamera; @@ -1036,28 +1020,12 @@ void LLToolGrab::stopGrab() } // Next, send messages to simulator - LLMessageSystem *msg = gMessageSystem; switch(mMode) { case GRAB_ACTIVE_CENTER: case GRAB_NONPHYSICAL: case GRAB_LOCKED: - msg->newMessageFast(_PREHASH_ObjectDeGrab); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU32Fast(_PREHASH_LocalID, objectp->mLocalID); - msg->nextBlock("SurfaceInfo"); - msg->addVector3("UVCoord", LLVector3(pick.mUVCoords)); - msg->addVector3("STCoord", LLVector3(pick.mSTCoords)); - msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace); - msg->addVector3("Position", pick.mIntersection); - msg->addVector3("Normal", pick.mNormal); - msg->addVector3("Binormal", pick.mBinormal); - - msg->sendMessage(objectp->getRegion()->getHost()); - + send_ObjectDeGrab_message(objectp, pick); mVerticalDragging = FALSE; break; @@ -1109,3 +1077,66 @@ LLVector3d LLToolGrab::getGrabPointGlobal() return gAgent.getPositionGlobal(); } } + + +void send_ObjectGrab_message(LLViewerObject* object, const LLPickInfo & pick, const LLVector3 &grab_offset) +{ + if (!object) return; + + LLMessageSystem *msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_ObjectGrab); + msg->nextBlockFast( _PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast( _PREHASH_ObjectData); + msg->addU32Fast( _PREHASH_LocalID, object->mLocalID); + msg->addVector3Fast(_PREHASH_GrabOffset, grab_offset); + msg->nextBlock("SurfaceInfo"); + msg->addVector3("UVCoord", LLVector3(pick.mUVCoords)); + msg->addVector3("STCoord", LLVector3(pick.mSTCoords)); + msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace); + msg->addVector3("Position", pick.mIntersection); + msg->addVector3("Normal", pick.mNormal); + msg->addVector3("Binormal", pick.mBinormal); + msg->sendMessage( object->getRegion()->getHost()); + + /* Diagnostic code + llinfos << "mUVCoords: " << pick.mUVCoords + << ", mSTCoords: " << pick.mSTCoords + << ", mObjectFace: " << pick.mObjectFace + << ", mIntersection: " << pick.mIntersection + << ", mNormal: " << pick.mNormal + << ", mBinormal: " << pick.mBinormal + << llendl; + + llinfos << "Avatar pos: " << gAgent.getPositionAgent() << llendl; + llinfos << "Object pos: " << object->getPosition() << llendl; + */ +} + + +void send_ObjectDeGrab_message(LLViewerObject* object, const LLPickInfo & pick) +{ + if (!object) return; + + LLMessageSystem *msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_ObjectDeGrab); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_LocalID, object->mLocalID); + msg->nextBlock("SurfaceInfo"); + msg->addVector3("UVCoord", LLVector3(pick.mUVCoords)); + msg->addVector3("STCoord", LLVector3(pick.mSTCoords)); + msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace); + msg->addVector3("Position", pick.mIntersection); + msg->addVector3("Normal", pick.mNormal); + msg->addVector3("Binormal", pick.mBinormal); + msg->sendMessage(object->getRegion()->getHost()); +} + + + diff --git a/indra/newview/lltoolgrab.h b/indra/newview/lltoolgrab.h index 61e3fcb8b2..06a3b662c8 100644 --- a/indra/newview/lltoolgrab.h +++ b/indra/newview/lltoolgrab.h @@ -39,6 +39,13 @@ class LLTextBox; class LLViewerObject; class LLPickInfo; + +// Message utilities +void send_ObjectGrab_message(LLViewerObject* object, const LLPickInfo & pick, const LLVector3 &grab_offset); +void send_ObjectDeGrab_message(LLViewerObject* object, const LLPickInfo & pick); + + + class LLToolGrab : public LLTool, public LLSingleton { public: diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index ec72df79d1..81a4188cd4 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -104,6 +104,7 @@ #include "llappearancemgr.h" #include "lltrans.h" #include "lleconomy.h" +#include "lltoolgrab.h" #include "boost/unordered_map.hpp" using namespace LLVOAvatarDefines; @@ -2392,50 +2393,23 @@ class LLObjectEnableReportAbuse : public view_listener_t } }; + void handle_object_touch() { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return; - - LLPickInfo pick = LLToolPie::getInstance()->getPick(); + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) return; - LLMessageSystem *msg = gMessageSystem; + LLPickInfo pick = LLToolPie::getInstance()->getPick(); - msg->newMessageFast(_PREHASH_ObjectGrab); - msg->nextBlockFast( _PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast( _PREHASH_ObjectData); - msg->addU32Fast( _PREHASH_LocalID, object->mLocalID); - msg->addVector3Fast(_PREHASH_GrabOffset, LLVector3::zero ); - msg->nextBlock("SurfaceInfo"); - msg->addVector3("UVCoord", LLVector3(pick.mUVCoords)); - msg->addVector3("STCoord", LLVector3(pick.mSTCoords)); - msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace); - msg->addVector3("Position", pick.mIntersection); - msg->addVector3("Normal", pick.mNormal); - msg->addVector3("Binormal", pick.mBinormal); - msg->sendMessage( object->getRegion()->getHost()); - - // *NOTE: Hope the packets arrive safely and in order or else - // there will be some problems. - // *TODO: Just fix this bad assumption. - msg->newMessageFast(_PREHASH_ObjectDeGrab); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU32Fast(_PREHASH_LocalID, object->mLocalID); - msg->nextBlock("SurfaceInfo"); - msg->addVector3("UVCoord", LLVector3(pick.mUVCoords)); - msg->addVector3("STCoord", LLVector3(pick.mSTCoords)); - msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace); - msg->addVector3("Position", pick.mIntersection); - msg->addVector3("Normal", pick.mNormal); - msg->addVector3("Binormal", pick.mBinormal); - msg->sendMessage(object->getRegion()->getHost()); + // *NOTE: Hope the packets arrive safely and in order or else + // there will be some problems. + // *TODO: Just fix this bad assumption. + send_ObjectGrab_message(object, pick, LLVector3::zero); + send_ObjectDeGrab_message(object, pick); } + + static void init_default_item_label(const std::string& item_name) { boost::unordered_map::iterator it = sDefaultItemLabels.find(item_name); -- cgit v1.2.3 From 3c8f6f44dc7b0ec6c8632fc75df6effad3e7ef98 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Mon, 28 Mar 2011 10:22:01 -0700 Subject: Fix usage of flag SLURLPassToOtherInstance during login. --- indra/newview/llappviewer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b670a40cd0..0bf8fc2205 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2459,7 +2459,7 @@ bool LLAppViewer::initConfiguration() // out of different directories if (LLStartUp::getStartSLURL().isValid() && - !(gSavedSettings.getBOOL("SLURLPassToOtherInstance"))) + (gSavedSettings.getBOOL("SLURLPassToOtherInstance"))) { if (sendURLToOtherInstance(LLStartUp::getStartSLURL().getSLURLString())) { -- cgit v1.2.3 From 0642000a12785bc4e17b334751f386bd1ec6c702 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Mon, 28 Mar 2011 10:27:52 -0700 Subject: Added optional 'position' property to 'requestSit' LLEventHost function, re-factored code into new findObjectClosestTo() function. Reviewed by Kelly --- indra/newview/llagentlistener.cpp | 67 +++++++++++++++++++++++++-------------- indra/newview/llagentlistener.h | 4 +++ 2 files changed, 48 insertions(+), 23 deletions(-) (limited to 'indra') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 0a13644911..c1edcef4c0 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -52,7 +52,8 @@ LLAgentListener::LLAgentListener(LLAgent &agent) "If [\"skip_confirmation\"] is true, use LLURLDispatcher rather than LLCommandDispatcher.", &LLAgentListener::requestTeleport); add("requestSit", - "Ask to sit on the object specified in [\"obj_uuid\"]", + "[\"obj_uuid\"]: id of object to sit on, use this or [\"position\"] to indicate the sit target" + "[\"position\"]: region position {x, y, z} where to find closest object to sit on", &LLAgentListener::requestSit); add("requestStand", "Ask to stand up", @@ -149,7 +150,17 @@ void LLAgentListener::requestSit(LLSD const & event_data) const //mAgent.getAvatarObject()->sitOnObject(); // shamelessly ripped from llviewermenu.cpp:handle_sit_or_stand() // *TODO - find a permanent place to share this code properly. - LLViewerObject *object = gObjectList.findObject(event_data["obj_uuid"]); + + LLViewerObject *object = NULL; + if (event_data.has("obj_uuid")) + { + object = gObjectList.findObject(event_data["obj_uuid"]); + } + else if (event_data.has("position")) + { + LLVector3 target_position = ll_vector3_from_sd(event_data["position"]); + object = findObjectClosestTo(target_position); + } if (object && object->getPCode() == LL_PCODE_VOLUME) { @@ -165,8 +176,8 @@ void LLAgentListener::requestSit(LLSD const & event_data) const } else { - llwarns << "LLAgent requestSit could not find the sit target " - << event_data["obj_uuid"].asUUID() << llendl; + llwarns << "LLAgent requestSit could not find the sit target: " + << event_data << llendl; } } @@ -175,6 +186,34 @@ void LLAgentListener::requestStand(LLSD const & event_data) const mAgent.setControlFlags(AGENT_CONTROL_STAND_UP); } + +LLViewerObject * LLAgentListener::findObjectClosestTo( const LLVector3 & position ) const +{ + LLViewerObject *object = NULL; + + // Find the object closest to that position + F32 min_distance = 10000.0f; // Start big + S32 num_objects = gObjectList.getNumObjects(); + S32 cur_index = 0; + while (cur_index < num_objects) + { + LLViewerObject * cur_object = gObjectList.getObject(cur_index++); + if (cur_object) + { // Calculate distance from the target position + LLVector3 target_diff = cur_object->getPositionRegion() - position; + F32 distance_to_target = target_diff.length(); + if (distance_to_target < min_distance) + { // Found an object closer + min_distance = distance_to_target; + object = cur_object; + } + } + } + + return object; +} + + void LLAgentListener::requestTouch(LLSD const & event_data) const { LLViewerObject *object = NULL; @@ -186,25 +225,7 @@ void LLAgentListener::requestTouch(LLSD const & event_data) const else if (event_data.has("position")) { LLVector3 target_position = ll_vector3_from_sd(event_data["position"]); - - // Find the object closest to that position - F32 min_distance = 10000.0f; // Start big - S32 num_objects = gObjectList.getNumObjects(); - S32 cur_index = 0; - while (cur_index < num_objects) - { - LLViewerObject * cur_object = gObjectList.getObject(cur_index++); - if (cur_object) - { // Calculate distance from the target position - LLVector3 target_diff = cur_object->getPositionRegion() - target_position; - F32 distance_to_target = target_diff.length(); - if (distance_to_target < min_distance) - { // Found an object closer - min_distance = distance_to_target; - object = cur_object; - } - } - } + object = findObjectClosestTo(target_position); } S32 face = 0; diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index 6aeda5f8db..c917151b71 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -34,6 +34,8 @@ class LLAgent; class LLSD; +class LLViewerObject; +class LLVector3d; class LLAgentListener : public LLEventAPI { @@ -54,6 +56,8 @@ private: void setAutoPilotTarget(const LLSD& event) const; void stopAutoPilot(const LLSD& event) const; + LLViewerObject * findObjectClosestTo( const LLVector3 & position ) const; + private: LLAgent & mAgent; LLUUID mFollowTarget; -- cgit v1.2.3 From f2bb81d17660054697ed984afc0e3f8d90f77eda Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Mon, 28 Mar 2011 16:54:40 -0700 Subject: Added LLEventHost API for gestures. Have new llgesturelistener.cpp and .h files, wired up to LLGestureMgr class. Reviewed by Kelly --- indra/newview/CMakeLists.txt | 2 + indra/newview/llgesturelistener.cpp | 159 ++++++++++++++++++++++++++++++++++++ indra/newview/llgesturelistener.h | 52 ++++++++++++ indra/newview/llgesturemgr.cpp | 2 + indra/newview/llgesturemgr.h | 4 + 5 files changed, 219 insertions(+) create mode 100644 indra/newview/llgesturelistener.cpp create mode 100644 indra/newview/llgesturelistener.h (limited to 'indra') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index d6a144f1dc..ef48fcdf2f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -232,6 +232,7 @@ set(viewer_SOURCE_FILES llfolderviewitem.cpp llfollowcam.cpp llfriendcard.cpp + llgesturelistener.cpp llgesturemgr.cpp llgiveinventory.cpp llglsandbox.cpp @@ -776,6 +777,7 @@ set(viewer_HEADER_FILES llfolderviewitem.h llfollowcam.h llfriendcard.h + llgesturelistener.h llgesturemgr.h llgiveinventory.h llgroupactions.h diff --git a/indra/newview/llgesturelistener.cpp b/indra/newview/llgesturelistener.cpp new file mode 100644 index 0000000000..f682700746 --- /dev/null +++ b/indra/newview/llgesturelistener.cpp @@ -0,0 +1,159 @@ +/** + * @file llgesturelistener.cpp + * @author Dave Simmons + * @date 2011-03-28 + * @brief Implementation for LLGestureListener. + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llgesturelistener.h" +#include "llgesturemgr.h" +#include "llmultigesture.h" + + +LLGestureListener::LLGestureListener() + : LLEventAPI("LLGesture", + "LLGesture listener interface to control gestures") +{ + add("getActiveGestures", + "Return information about the agent's available gestures [\"reply\"]:\n" + "[\"gestures\"]: list of gestures. This is a dictionary with UUID strings as keys\n" + " and the following values:\n" + " [\"name\"]: name of the gesture, may be empty\n" + " [\"trigger\"]: trigger string used to invoke via user chat, may be empty\n" + " [\"playing\"]: true or false indicating the playing state", + &LLGestureListener::getActiveGestures, + LLSDMap("reply", LLSD())); + add("isGesturePlaying", + "[\"id\"]: UUID of the gesture to query. Returns True or False in [\"playing\"] value of the result", + &LLGestureListener::isGesturePlaying); + add("startGesture", + "[\"id\"]: UUID of the gesture to start play", + &LLGestureListener::startGesture); + add("stopGesture", + "[\"id\"]: UUID of the gesture to stop", + &LLGestureListener::stopGesture); +} + + +// "getActiveGestures" command +void LLGestureListener::getActiveGestures(const LLSD& event_data) const +{ + LLSD reply = LLSD::emptyMap(); + LLSD gesture_map = LLSD::emptyMap(); + + const LLGestureMgr::item_map_t& active_gestures = LLGestureMgr::instance().getActiveGestures(); + + // Scan active gesture map and get all the names + LLGestureMgr::item_map_t::const_iterator it; + for (it = active_gestures.begin(); it != active_gestures.end(); ++it) + { + LLMultiGesture* gesture = (*it).second; + if (gesture) + { // Add an entry to the result map with the LLUUID as key with a map containing data + LLSD info = LLSD::emptyMap(); + info["name"] = (LLSD::String) gesture->mName; + info["trigger"] = (LLSD::String) gesture->mTrigger; + info["playing"] = (LLSD::Boolean) gesture->mPlaying; + + gesture_map[(*it).first.asString()] = info; + } + } + + reply["gestures"] = gesture_map; + sendReply(reply, event_data); +} + + + +// "isGesturePlaying" command +void LLGestureListener::isGesturePlaying(const LLSD& event_data) const +{ + bool is_playing = false; + if (event_data.has("id")) + { + LLUUID gesture_id = event_data["id"].asUUID(); + if (gesture_id.notNull()) + { + is_playing = LLGestureMgr::instance().isGesturePlaying(gesture_id); + } + else + { + llwarns << "isGesturePlaying did not find a gesture object for " << gesture_id << llendl; + } + } + else + { + llwarns << "isGesturePlaying didn't have 'id' value passed in" << llendl; + } + + LLSD reply = LLSD::emptyMap(); + reply["playing"] = (LLSD::Boolean) is_playing; + sendReply(reply, event_data); +} + + +// "startGesture" command +void LLGestureListener::startGesture(LLSD const & event_data) const +{ + startOrStopGesture(event_data, true); +} + + +// "stopGesture" command +void LLGestureListener::stopGesture(LLSD const & event_data) const +{ + startOrStopGesture(event_data, false); +} + + +// Real code for "startGesture" or "stopGesture" +void LLGestureListener::startOrStopGesture(LLSD const & event_data, bool start) const +{ + if (event_data.has("id")) + { + LLUUID gesture_id = event_data["id"].asUUID(); + if (gesture_id.notNull()) + { + if (start) + { + LLGestureMgr::instance().playGesture(gesture_id); + } + else + { + LLGestureMgr::instance().stopGesture(gesture_id); + } + } + else + { + llwarns << "startOrStopGesture did not find a gesture object for " << gesture_id << llendl; + } + } + else + { + llwarns << "startOrStopGesture didn't have 'id' value passed in" << llendl; + } +} + diff --git a/indra/newview/llgesturelistener.h b/indra/newview/llgesturelistener.h new file mode 100644 index 0000000000..326881ac2b --- /dev/null +++ b/indra/newview/llgesturelistener.h @@ -0,0 +1,52 @@ +/** + * @file llgesturelistener.h + * @author Dave Simmons + * @date 2011-03-15 + * @brief Class definition for LLGestureListener. + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#ifndef LL_LLGESTURELISTENER_H +#define LL_LLGESTURELISTENER_H + +#include "lleventapi.h" + +class LLSD; + +class LLGestureListener : public LLEventAPI +{ +public: + LLGestureListener(); + +private: + void getActiveGestures(LLSD const & gesture_data) const; + void isGesturePlaying(LLSD const & gesture_data) const; + void startGesture(LLSD const & gesture_data) const; + void stopGesture(LLSD const & gesture_data) const; + + void startOrStopGesture(LLSD const & event_data, bool start) const; +}; + +#endif // LL_LLGESTURELISTENER_H + diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index f658287fb1..c5b821c360 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -51,6 +51,7 @@ #include "llviewerstats.h" #include "llnearbychatbar.h" #include "llappearancemgr.h" +#include "llgesturelistener.h" // Longest time, in seconds, to wait for all animations to stop playing const F32 MAX_WAIT_ANIM_SECS = 30.f; @@ -68,6 +69,7 @@ LLGestureMgr::LLGestureMgr() mLoadingCount(0) { gInventory.addObserver(this); + mListener.reset(new LLGestureListener()); } diff --git a/indra/newview/llgesturemgr.h b/indra/newview/llgesturemgr.h index b9935efeb3..e305895797 100644 --- a/indra/newview/llgesturemgr.h +++ b/indra/newview/llgesturemgr.h @@ -37,6 +37,7 @@ #include "llviewerinventory.h" class LLMultiGesture; +class LLGestureListener; class LLGestureStep; class LLUUID; class LLVFS; @@ -172,6 +173,9 @@ private: callback_map_t mCallbackMap; std::vector mPlaying; BOOL mValid; + + // LLEventHost interface + boost::shared_ptr mListener; }; #endif -- cgit v1.2.3 From 65d28f8aeac84b4f80a15069b4212956d08aba66 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Fri, 1 Apr 2011 16:42:53 -0700 Subject: Added LSL script functions llGetEnv(), which was missing, and llRegionSayTo(), which is new --- indra/lscript/lscript_library/lscript_library.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra') diff --git a/indra/lscript/lscript_library/lscript_library.cpp b/indra/lscript/lscript_library/lscript_library.cpp index 967c69fea9..7ffe53a307 100644 --- a/indra/lscript/lscript_library/lscript_library.cpp +++ b/indra/lscript/lscript_library/lscript_library.cpp @@ -461,6 +461,9 @@ void LLScriptLibrary::init() addFunction(10.f, 0.f, dummy_func, "llGetDisplayName", "s", "k"); addFunction(10.f, 0.f, dummy_func, "llRequestDisplayName", "k", "k"); + addFunction(10.f, 0.f, dummy_func, "llGetEnv", "s", "s"); + addFunction(10.f, 0.f, dummy_func, "llRegionSayTo", NULL, "kis"); + // energy, sleep, dummy_func, name, return type, parameters, help text, gods-only // IF YOU ADD NEW SCRIPT CALLS, YOU MUST PUT THEM AT THE END OF THIS LIST. -- cgit v1.2.3 From 3ce04bdcc7dedb1ce0b2c9db75fe22439cd24132 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Fri, 1 Apr 2011 18:04:39 -0700 Subject: Comment and line ending repair --- indra/newview/llgesturelistener.cpp | 52 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'indra') diff --git a/indra/newview/llgesturelistener.cpp b/indra/newview/llgesturelistener.cpp index f682700746..22b7d233c5 100644 --- a/indra/newview/llgesturelistener.cpp +++ b/indra/newview/llgesturelistener.cpp @@ -39,8 +39,8 @@ LLGestureListener::LLGestureListener() { add("getActiveGestures", "Return information about the agent's available gestures [\"reply\"]:\n" - "[\"gestures\"]: list of gestures. This is a dictionary with UUID strings as keys\n" - " and the following values:\n" + "[\"gestures\"]: a dictionary with UUID strings as keys\n" + " and the following dict values for each entry:\n" " [\"name\"]: name of the gesture, may be empty\n" " [\"trigger\"]: trigger string used to invoke via user chat, may be empty\n" " [\"playing\"]: true or false indicating the playing state", @@ -50,7 +50,7 @@ LLGestureListener::LLGestureListener() "[\"id\"]: UUID of the gesture to query. Returns True or False in [\"playing\"] value of the result", &LLGestureListener::isGesturePlaying); add("startGesture", - "[\"id\"]: UUID of the gesture to start play", + "[\"id\"]: UUID of the gesture to start playing", &LLGestureListener::startGesture); add("stopGesture", "[\"id\"]: UUID of the gesture to stop", @@ -64,23 +64,23 @@ void LLGestureListener::getActiveGestures(const LLSD& event_data) const LLSD reply = LLSD::emptyMap(); LLSD gesture_map = LLSD::emptyMap(); - const LLGestureMgr::item_map_t& active_gestures = LLGestureMgr::instance().getActiveGestures(); - - // Scan active gesture map and get all the names - LLGestureMgr::item_map_t::const_iterator it; - for (it = active_gestures.begin(); it != active_gestures.end(); ++it) - { - LLMultiGesture* gesture = (*it).second; - if (gesture) - { // Add an entry to the result map with the LLUUID as key with a map containing data - LLSD info = LLSD::emptyMap(); - info["name"] = (LLSD::String) gesture->mName; - info["trigger"] = (LLSD::String) gesture->mTrigger; - info["playing"] = (LLSD::Boolean) gesture->mPlaying; - - gesture_map[(*it).first.asString()] = info; - } - } + const LLGestureMgr::item_map_t& active_gestures = LLGestureMgr::instance().getActiveGestures(); + + // Scan active gesture map and get all the names + LLGestureMgr::item_map_t::const_iterator it; + for (it = active_gestures.begin(); it != active_gestures.end(); ++it) + { + LLMultiGesture* gesture = (*it).second; + if (gesture) + { // Add an entry to the result map with the LLUUID as key with a map containing data + LLSD info = LLSD::emptyMap(); + info["name"] = (LLSD::String) gesture->mName; + info["trigger"] = (LLSD::String) gesture->mTrigger; + info["playing"] = (LLSD::Boolean) gesture->mPlaying; + + gesture_map[(*it).first.asString()] = info; + } + } reply["gestures"] = gesture_map; sendReply(reply, event_data); @@ -139,12 +139,12 @@ void LLGestureListener::startOrStopGesture(LLSD const & event_data, bool start) { if (start) { - LLGestureMgr::instance().playGesture(gesture_id); - } - else - { - LLGestureMgr::instance().stopGesture(gesture_id); - } + LLGestureMgr::instance().playGesture(gesture_id); + } + else + { + LLGestureMgr::instance().stopGesture(gesture_id); + } } else { -- cgit v1.2.3 From e74e0c8da5ecdb107f89bd33de81397ac41f5a5b Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Tue, 5 Apr 2011 09:07:11 -0700 Subject: ER-671 : Add LLRegionSayTo() LSL function. Added new chat type for direct messages to match server code, use light orange for text. Reviewed by Kelly. --- indra/llcommon/llchat.h | 3 ++- indra/newview/llnearbychatbarlistener.cpp | 4 ++-- indra/newview/llviewerchat.cpp | 8 ++++++++ indra/newview/skins/default/colors.xml | 3 +++ 4 files changed, 15 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llchat.h b/indra/llcommon/llchat.h index 87c2d6775b..f5b242fdfc 100644 --- a/indra/llcommon/llchat.h +++ b/indra/llcommon/llchat.h @@ -49,7 +49,8 @@ typedef enum e_chat_type CHAT_TYPE_STOP = 5, CHAT_TYPE_DEBUG_MSG = 6, CHAT_TYPE_REGION = 7, - CHAT_TYPE_OWNER = 8 + CHAT_TYPE_OWNER = 8, + CHAT_TYPE_DIRECT = 9 // From llRegionSayTo() } EChatType; typedef enum e_chat_audible_level diff --git a/indra/newview/llnearbychatbarlistener.cpp b/indra/newview/llnearbychatbarlistener.cpp index 99286d972b..0d64eaed47 100644 --- a/indra/newview/llnearbychatbarlistener.cpp +++ b/indra/newview/llnearbychatbarlistener.cpp @@ -60,8 +60,8 @@ void LLNearbyChatBarListener::sendChat(LLSD const & chat_data) const if (chat_data.has("channel")) { channel = chat_data["channel"].asInteger(); - if (channel < 0 || channel >= 2147483647) - { // Use 0 up to (but not including) DEBUG_CHANNEL (wtf isn't that defined??) + if (channel < 0 || channel >= CHAT_CHANNEL_DEBUG) + { // Use 0 up to (but not including) CHAT_CHANNEL_DEBUG channel = 0; } } diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp index 0af850a46b..2f449978dc 100644 --- a/indra/newview/llviewerchat.cpp +++ b/indra/newview/llviewerchat.cpp @@ -75,6 +75,10 @@ void LLViewerChat::getChatColor(const LLChat& chat, LLColor4& r_color) { r_color = LLUIColorTable::instance().getColor("llOwnerSayChatColor"); } + else if ( chat.mChatType == CHAT_TYPE_DIRECT ) + { + r_color = LLUIColorTable::instance().getColor("DirectChatColor"); + } else { r_color = LLUIColorTable::instance().getColor("ObjectChatColor"); @@ -140,6 +144,10 @@ void LLViewerChat::getChatColor(const LLChat& chat, std::string& r_color_name, F { r_color_name = "llOwnerSayChatColor"; } + else if ( chat.mChatType == CHAT_TYPE_DIRECT ) + { + r_color_name = "DirectChatColor"; + } else { r_color_name = "ObjectChatColor"; diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index 75aec21f93..d197ab2fdf 100644 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -763,4 +763,7 @@ + -- cgit v1.2.3 From 18f5bbfdd3b08e33bc27b787cb4cc1293e2586c8 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Tue, 5 Apr 2011 10:33:01 -0700 Subject: ER-671: Add LLRegionSayTo() LSL function. Added viewer preferences color picker under 'Colors' panel for messages sent directly to viewer via llRegionSayTo(). Reviewed by Kelly. --- .../default/xui/en/panel_preferences_colors.xml | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/panel_preferences_colors.xml b/indra/newview/skins/default/xui/en/panel_preferences_colors.xml index 8a37822413..c6d1e38ee7 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_colors.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_colors.xml @@ -206,6 +206,37 @@ width="95"> Errors + + + + + + Direct + Date: Tue, 5 Apr 2011 10:34:24 -0700 Subject: Cleanup: use CHAT_CHANNEL_DEBUG instead of 2147483647 --- indra/newview/llchatbar.cpp | 2 +- indra/newview/llnearbychatbar.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index 4a58dc558a..cf0374075a 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -694,7 +694,7 @@ public: { S32 channel = tokens[0].asInteger(); // VWR-19499 Restrict function to chat channels greater than 0. - if ((channel > 0) && (channel < 2147483647)) + if ((channel > 0) && (channel < CHAT_CHANNEL_DEBUG)) { retval = true; // Say mesg on channel diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp index 947efdbb19..cf828306d8 100644 --- a/indra/newview/llnearbychatbar.cpp +++ b/indra/newview/llnearbychatbar.cpp @@ -895,7 +895,7 @@ public: { S32 channel = tokens[0].asInteger(); // VWR-19499 Restrict function to chat channels greater than 0. - if ((channel > 0) && (channel < 2147483647)) + if ((channel > 0) && (channel < CHAT_CHANNEL_DEBUG)) { retval = true; // Send unescaped message, see EXT-6353. -- cgit v1.2.3 From b84ac95c2fa3f020b656737244c38222351b8d36 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Thu, 7 Apr 2011 17:03:42 -0700 Subject: ER-671: add llRegionSayTo(). Cleaned up some chat code, implemented '@' special case. Reviewed by Kelly --- indra/newview/llnearbychathandler.cpp | 35 ++++++++++++++++++++++------------- indra/newview/llviewermessage.cpp | 12 ++++-------- 2 files changed, 26 insertions(+), 21 deletions(-) (limited to 'indra') diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp index 2566bf1095..11dc496311 100644 --- a/indra/newview/llnearbychathandler.cpp +++ b/indra/newview/llnearbychathandler.cpp @@ -489,6 +489,27 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args) // tmp_chat.mFromName = tmp_chat.mFromID.asString(); } + // Build notification data + LLSD notification; + notification["message"] = chat_msg.mText; + notification["from"] = chat_msg.mFromName; + notification["from_id"] = chat_msg.mFromID; + notification["time"] = chat_msg.mTime; + notification["source"] = (S32)chat_msg.mSourceType; + notification["chat_type"] = (S32)chat_msg.mChatType; + notification["chat_style"] = (S32)chat_msg.mChatStyle; + // Pass sender info so that it can be rendered properly (STORM-1021). + notification["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args); + + if (chat_msg.mChatType == CHAT_TYPE_DIRECT && + chat_msg.mText.length() > 0 && + chat_msg.mText[0] == '@') + { + // Send event on to LLEventStream and exit + sChatWatcher->post(notification); + return; + } + // don't show toast and add message to chat history on receive debug message // with disabled setting showing script errors or enabled setting to show script // errors in separate window. @@ -531,19 +552,7 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args) } - // Build data and send event on to LLEventStream - LLSD notification; - notification["message"] = chat_msg.mText; - notification["from"] = chat_msg.mFromName; - notification["from_id"] = chat_msg.mFromID; - notification["time"] = chat_msg.mTime; - notification["source"] = (S32)chat_msg.mSourceType; - notification["chat_type"] = (S32)chat_msg.mChatType; - notification["chat_style"] = (S32)chat_msg.mChatStyle; - // Pass sender info so that it can be rendered properly (STORM-1021). - notification["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args); - - + // Send event on to LLEventStream sChatWatcher->post(notification); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 9641a0901c..5792bf2c03 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3202,7 +3202,6 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) if (is_audible) { BOOL visible_in_chat_bubble = FALSE; - std::string verb; color.setVec(1.f,1.f,1.f,1.f); msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); @@ -3251,18 +3250,19 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } else { + chat.mText = ""; switch(chat.mChatType) { case CHAT_TYPE_WHISPER: - verb = LLTrans::getString("whisper") + " "; + chat.mText = LLTrans::getString("whisper") + " "; break; case CHAT_TYPE_DEBUG_MSG: case CHAT_TYPE_OWNER: case CHAT_TYPE_NORMAL: - verb = ""; + case CHAT_TYPE_DIRECT: break; case CHAT_TYPE_SHOUT: - verb = LLTrans::getString("shout") + " "; + chat.mText = LLTrans::getString("shout") + " "; break; case CHAT_TYPE_START: case CHAT_TYPE_STOP: @@ -3270,13 +3270,9 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) break; default: LL_WARNS("Messaging") << "Unknown type " << chat.mChatType << " in chat!" << LL_ENDL; - verb = ""; break; } - - chat.mText = ""; - chat.mText += verb; chat.mText += mesg; } -- cgit v1.2.3 From 2bf967149626672584b17b53fb5d2e6186f3d896 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Fri, 8 Apr 2011 15:54:32 -0700 Subject: Fixed a NULL pointer crash found while using viewer. See https://osiris.lindenlab.com/viewer_crash_browser/index.php?filter_id=24941. Reviewed by Kelly --- indra/newview/llwearabletype.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra') diff --git a/indra/newview/llwearabletype.cpp b/indra/newview/llwearabletype.cpp index f933be4d8f..5b4b820903 100644 --- a/indra/newview/llwearabletype.cpp +++ b/indra/newview/llwearabletype.cpp @@ -144,6 +144,7 @@ BOOL LLWearableType::getDisableCameraSwitch(LLWearableType::EType type) { const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); const WearableEntry *entry = dict->lookup(type); + if (!entry) return FALSE; return entry->mDisableCameraSwitch; } @@ -152,6 +153,7 @@ BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type) { const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); const WearableEntry *entry = dict->lookup(type); + if (!entry) return FALSE; return entry->mAllowMultiwear; } -- cgit v1.2.3 From 411a1bfcb6e6f7c0bc6e8afcf8aed447426df340 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Fri, 15 Apr 2011 20:08:06 +0000 Subject: Set run_build_test.py to be executable --- indra/cmake/run_build_test.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 indra/cmake/run_build_test.py (limited to 'indra') diff --git a/indra/cmake/run_build_test.py b/indra/cmake/run_build_test.py old mode 100644 new mode 100755 -- cgit v1.2.3 From ebe0c8204df30a85b8228e81acbcf7945c15220c Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Fri, 15 Apr 2011 15:52:52 -0700 Subject: ER-710: Viewer effects. Added 'lookAt' command for LLAgent event host API. Also changed a bunch of parameters named 'event' to 'event_host' since VS highlights them as keywords. Reviewed by Kelly. --- indra/newview/llagentlistener.cpp | 102 ++++++++++++++++++++++++-------------- indra/newview/llagentlistener.h | 17 ++++--- 2 files changed, 75 insertions(+), 44 deletions(-) (limited to 'indra') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index c1edcef4c0..2dc6764f51 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -41,6 +41,8 @@ #include "llsdutil.h" #include "llsdutil_math.h" #include "lltoolgrab.h" +#include "llhudeffectlookat.h" +#include "llagentcamera.h" LLAgentListener::LLAgentListener(LLAgent &agent) : LLEventAPI("LLAgent", @@ -119,7 +121,11 @@ LLAgentListener::LLAgentListener(LLAgent &agent) "Stop the autopilot system:\n" "[\"user_cancel\"] indicates whether or not to act as though user canceled autopilot [default: false]", &LLAgentListener::stopAutoPilot); - + add("lookAt", + "[\"type\"]: number to indicate the lookAt type, 0 to clear\n" + "[\"obj_uuid\"]: id of object to look at, use this or [\"position\"] to indicate the target\n" + "[\"position\"]: region position {x, y, z} where to find closest object or avatar to look at", + &LLAgentListener::lookAt); } void LLAgentListener::requestTeleport(LLSD const & event_data) const @@ -265,11 +271,11 @@ void LLAgentListener::requestTouch(LLSD const & event_data) const } -void LLAgentListener::resetAxes(const LLSD& event) const +void LLAgentListener::resetAxes(const LLSD& event_data) const { - if (event.has("lookat")) + if (event_data.has("lookat")) { - mAgent.resetAxes(ll_vector3_from_sd(event["lookat"])); + mAgent.resetAxes(ll_vector3_from_sd(event_data["lookat"])); } else { @@ -278,7 +284,7 @@ void LLAgentListener::resetAxes(const LLSD& event) const } } -void LLAgentListener::getAxes(const LLSD& event) const +void LLAgentListener::getAxes(const LLSD& event_data) const { LLQuaternion quat(mAgent.getQuat()); F32 roll, pitch, yaw; @@ -291,11 +297,11 @@ void LLAgentListener::getAxes(const LLSD& event) const reply["euler"]["roll"] = roll; reply["euler"]["pitch"] = pitch; reply["euler"]["yaw"] = yaw; - sendReply(reply, event); + sendReply(reply, event_data); } -void LLAgentListener::getPosition(const LLSD& event) const +void LLAgentListener::getPosition(const LLSD& event_data) const { F32 roll, pitch, yaw; LLQuaternion quat(mAgent.getQuat()); @@ -310,30 +316,30 @@ void LLAgentListener::getPosition(const LLSD& event) const reply["region"] = ll_sd_from_vector3(mAgent.getPositionAgent()); reply["global"] = ll_sd_from_vector3d(mAgent.getPositionGlobal()); - sendReply(reply, event); + sendReply(reply, event_data); } -void LLAgentListener::startAutoPilot(LLSD const & event) +void LLAgentListener::startAutoPilot(LLSD const & event_data) { LLQuaternion target_rotation_value; LLQuaternion* target_rotation = NULL; - if (event.has("target_rotation")) + if (event_data.has("target_rotation")) { - target_rotation_value = ll_quaternion_from_sd(event["target_rotation"]); + target_rotation_value = ll_quaternion_from_sd(event_data["target_rotation"]); target_rotation = &target_rotation_value; } // *TODO: Use callback_pump and callback_data F32 rotation_threshold = 0.03f; - if (event.has("rotation_threshold")) + if (event_data.has("rotation_threshold")) { - rotation_threshold = event["rotation_threshold"].asReal(); + rotation_threshold = event_data["rotation_threshold"].asReal(); } BOOL allow_flying = TRUE; - if (event.has("allow_flying")) + if (event_data.has("allow_flying")) { - allow_flying = (BOOL) event["allow_flying"].asBoolean(); + allow_flying = (BOOL) event_data["allow_flying"].asBoolean(); if (!allow_flying) { mAgent.setFlying(FALSE); @@ -341,16 +347,16 @@ void LLAgentListener::startAutoPilot(LLSD const & event) } F32 stop_distance = 0.f; - if (event.has("stop_distance")) + if (event_data.has("stop_distance")) { - stop_distance = event["stop_distance"].asReal(); + stop_distance = event_data["stop_distance"].asReal(); } // Clear follow target, this is doing a path mFollowTarget.setNull(); - mAgent.startAutoPilotGlobal(ll_vector3d_from_sd(event["target_global"]), - event["behavior_name"], + mAgent.startAutoPilotGlobal(ll_vector3d_from_sd(event_data["target_global"]), + event_data["behavior_name"], target_rotation, NULL, NULL, stop_distance, @@ -358,7 +364,7 @@ void LLAgentListener::startAutoPilot(LLSD const & event) allow_flying); } -void LLAgentListener::getAutoPilot(const LLSD& event) const +void LLAgentListener::getAutoPilot(const LLSD& event_data) const { LLSD reply = LLSD::emptyMap(); @@ -390,26 +396,26 @@ void LLAgentListener::getAutoPilot(const LLSD& event) const reply["behavior_name"] = mAgent.getAutoPilotBehaviorName(); reply["fly"] = (LLSD::Boolean) mAgent.getFlying(); - sendReply(reply, event); + sendReply(reply, event_data); } -void LLAgentListener::startFollowPilot(LLSD const & event) +void LLAgentListener::startFollowPilot(LLSD const & event_data) { LLUUID target_id; BOOL allow_flying = TRUE; - if (event.has("allow_flying")) + if (event_data.has("allow_flying")) { - allow_flying = (BOOL) event["allow_flying"].asBoolean(); + allow_flying = (BOOL) event_data["allow_flying"].asBoolean(); } - if (event.has("leader_id")) + if (event_data.has("leader_id")) { - target_id = event["leader_id"]; + target_id = event_data["leader_id"]; } - else if (event.has("avatar_name")) + else if (event_data.has("avatar_name")) { // Find the avatar with matching name - std::string target_name = event["avatar_name"].asString(); + std::string target_name = event_data["avatar_name"].asString(); if (target_name.length() > 0) { @@ -430,9 +436,9 @@ void LLAgentListener::startFollowPilot(LLSD const & event) } F32 stop_distance = 0.f; - if (event.has("stop_distance")) + if (event_data.has("stop_distance")) { - stop_distance = event["stop_distance"].asReal(); + stop_distance = event_data["stop_distance"].asReal(); } if (target_id.notNull()) @@ -447,22 +453,46 @@ void LLAgentListener::startFollowPilot(LLSD const & event) } } -void LLAgentListener::setAutoPilotTarget(LLSD const & event) const +void LLAgentListener::setAutoPilotTarget(LLSD const & event_data) const { - if (event.has("target_global")) + if (event_data.has("target_global")) { - LLVector3d target_global(ll_vector3d_from_sd(event["target_global"])); + LLVector3d target_global(ll_vector3d_from_sd(event_data["target_global"])); mAgent.setAutoPilotTargetGlobal(target_global); } } -void LLAgentListener::stopAutoPilot(LLSD const & event) const +void LLAgentListener::stopAutoPilot(LLSD const & event_data) const { BOOL user_cancel = FALSE; - if (event.has("user_cancel")) + if (event_data.has("user_cancel")) { - user_cancel = event["user_cancel"].asBoolean(); + user_cancel = event_data["user_cancel"].asBoolean(); } mAgent.stopAutoPilot(user_cancel); } +void LLAgentListener::lookAt(LLSD const & event_data) const +{ + LLViewerObject *object = NULL; + if (event_data.has("obj_uuid")) + { + object = gObjectList.findObject(event_data["obj_uuid"]); + } + else if (event_data.has("position")) + { + LLVector3 target_position = ll_vector3_from_sd(event_data["position"]); + object = findObjectClosestTo(target_position); + } + + S32 look_at_type = (S32) LOOKAT_TARGET_NONE; + if (event_data.has("type")) + { + look_at_type = event_data["type"].asInteger(); + } + if (look_at_type >= (S32) LOOKAT_TARGET_NONE && + look_at_type < (S32) LOOKAT_NUM_TARGETS) + { + gAgentCamera.setLookAt((ELookAtType) look_at_type, object); + } +} diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index c917151b71..ab2b10abcb 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -47,14 +47,15 @@ private: void requestSit(LLSD const & event_data) const; void requestStand(LLSD const & event_data) const; void requestTouch(LLSD const & event_data) const; - void resetAxes(const LLSD& event) const; - void getAxes(const LLSD& event) const; - void getPosition(const LLSD& event) const; - void startAutoPilot(const LLSD& event); - void getAutoPilot(const LLSD& event) const; - void startFollowPilot(const LLSD& event); - void setAutoPilotTarget(const LLSD& event) const; - void stopAutoPilot(const LLSD& event) const; + void resetAxes(const LLSD& event_data) const; + void getAxes(const LLSD& event_data) const; + void getPosition(const LLSD& event_data) const; + void startAutoPilot(const LLSD& event_data); + void getAutoPilot(const LLSD& event_data) const; + void startFollowPilot(const LLSD& event_data); + void setAutoPilotTarget(const LLSD& event_data) const; + void stopAutoPilot(const LLSD& event_data) const; + void lookAt(LLSD const & event_data) const; LLViewerObject * findObjectClosestTo( const LLVector3 & position ) const; -- cgit v1.2.3 From 7e998f5eccdbcff35a4807b92d6b8a9cb4735f14 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Tue, 19 Apr 2011 21:49:11 +0000 Subject: Fix for problems executing test build script --- indra/cmake/LLTestCommand.cmake | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra') diff --git a/indra/cmake/LLTestCommand.cmake b/indra/cmake/LLTestCommand.cmake index 554559edbd..7e9854dc4c 100644 --- a/indra/cmake/LLTestCommand.cmake +++ b/indra/cmake/LLTestCommand.cmake @@ -1,3 +1,5 @@ +include(Python) + MACRO(LL_TEST_COMMAND OUTVAR LD_LIBRARY_PATH) # nat wonders how Kitware can use the term 'function' for a construct that # cannot return a value. And yet, variables you set inside a FUNCTION are -- cgit v1.2.3 From 970b3a7f28c2f1a611410cb8738d17800949b1bd Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Thu, 21 Apr 2011 11:43:43 -0700 Subject: ER-785: Missing LSL tooltip strings for llRegionSayTo and llGetEnv. Tooltips are no longer missing. Reviewed by Kelly. --- indra/newview/skins/default/xui/en/strings.xml | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 27295150c5..8ac65cee91 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -1830,6 +1830,15 @@ Requests single-word username of an avatar. When data is available the dataserv key llRequestDisplayName(key id) Requests name of an avatar. When data is available the dataserver event will be raised. + +llRegionSayTo(key target, integer channel, string msg) +Sends msg on channel (not DEBUG_CHANNEL) directly to prim or avatar target anywhere within the region + + +llGetEnv(string name) +Returns a string with the requested data about the region + + Not Away -- cgit v1.2.3 From 5c7a906b44aa950ec3c8b786fec6516b51f9d66c Mon Sep 17 00:00:00 2001 From: Logan Dethrow Date: Fri, 6 May 2011 15:15:17 -0400 Subject: Increased the viewer cache size limit to 10GB. Increased the default to 1GB. * Changed the hard coded cache limit in llappviewer.cpp to 10GB as well as the slider maximum in the preferences menu. * The VFS cache is capped at 1GB due to file system limitations. The former 80/20 split between texture/vfs is maintained up to 5GB. Above this limit the texture cache is given all the additional cache space up to 10GB. * Fixed a log message in lltexturecache.cpp that was not showing the correct texture size. ER-883 * Fixed a bug in llfloaterpreference.cpp that caused new cache value to be written to the old cache setting. This resulted in the the cache not being cleared when the location was set back to the default. ER-882 * Disabled the "The cache will be cleared on reboot" message that is triggered by the reset button in the cache preferences in the case where the cache is already located in the default location. The cache is only cleared when its location is changed. This is intended to address resident confusion regarding the purpose of the reset button, as demonstrated in VWR-19562. --- indra/newview/llappviewer.cpp | 54 +++++++++++++--------- indra/newview/llfloaterpreference.cpp | 11 +++-- indra/newview/lltexturecache.cpp | 4 +- .../default/xui/en/panel_preferences_setup.xml | 4 +- 4 files changed, 42 insertions(+), 31 deletions(-) (limited to 'indra') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 061ef7268e..f99762d768 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3548,7 +3548,7 @@ bool LLAppViewer::initCache() gSavedSettings.getBOOL("PurgeCacheOnNextStartup")) { gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false); - mPurgeCache = true; + mPurgeCache = true; } // We have moved the location of the cache directory over time. @@ -3583,11 +3583,23 @@ bool LLAppViewer::initCache() // Init the texture cache // Allocate 80% of the cache size for textures - const S32 MB = 1024*1024; + const S32 MB = 1024 * 1024; S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB; - const S64 MAX_CACHE_SIZE = 1024*MB; + const S64 MAX_CACHE_SIZE = 10 * 1024ll * MB; + const S64 MAX_VFS_SIZE = 1024 * MB; // 1 GB cache_size = llmin(cache_size, MAX_CACHE_SIZE); - S64 texture_cache_size = ((cache_size * 8)/10); + + S64 texture_cache_size = ((cache_size * 8) / 10); + S64 vfs_size = cache_size - texture_cache_size; + + if (vfs_size > MAX_VFS_SIZE) + { + // Give the texture cache more space, since the VFS can't be bigger than 1GB. + // This happens when the user's CacheSize setting is greater than 5GB. + vfs_size = MAX_VFS_SIZE; + texture_cache_size = cache_size - MAX_VFS_SIZE; + } + S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch); texture_cache_size -= extra; @@ -3596,21 +3608,19 @@ bool LLAppViewer::initCache() LLSplashScreen::update(LLTrans::getString("StartupInitializingVFS")); // Init the VFS - S64 vfs_size = cache_size - texture_cache_size; - const S64 MAX_VFS_SIZE = 1024 * MB; // 1 GB - vfs_size = llmin(vfs_size, MAX_VFS_SIZE); + vfs_size = llmin(vfs_size + extra, MAX_VFS_SIZE); vfs_size = (vfs_size / MB) * MB; // make sure it is MB aligned U32 vfs_size_u32 = (U32)vfs_size; U32 old_vfs_size = gSavedSettings.getU32("VFSOldSize") * MB; bool resize_vfs = (vfs_size_u32 != old_vfs_size); if (resize_vfs) { - gSavedSettings.setU32("VFSOldSize", vfs_size_u32/MB); + gSavedSettings.setU32("VFSOldSize", vfs_size_u32 / MB); } - LL_INFOS("AppCache") << "VFS CACHE SIZE: " << vfs_size/(1024*1024) << " MB" << LL_ENDL; + LL_INFOS("AppCache") << "VFS CACHE SIZE: " << vfs_size / (1024*1024) << " MB" << LL_ENDL; // This has to happen BEFORE starting the vfs - //time_t ltime; + // time_t ltime; srand(time(NULL)); // Flawfinder: ignore U32 old_salt = gSavedSettings.getU32("VFSSalt"); U32 new_salt; @@ -3631,10 +3641,10 @@ bool LLAppViewer::initCache() do { new_salt = rand(); - } while( new_salt == old_salt ); + } while(new_salt == old_salt); } - old_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE) + llformat("%u",old_salt); + old_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_DATA_FILE_BASE) + llformat("%u", old_salt); // make sure this file exists llstat s; @@ -3648,7 +3658,7 @@ bool LLAppViewer::initCache() mask += "*"; std::string dir; - dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""); + dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); std::string found_file; if (gDirUtilp->getNextFileInDir(dir, mask, found_file)) @@ -3664,7 +3674,7 @@ bool LLAppViewer::initCache() } } - old_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_INDEX_FILE_BASE) + llformat("%u",old_salt); + old_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_INDEX_FILE_BASE) + llformat("%u", old_salt); stat_result = LLFile::stat(old_vfs_index_file, &s); if (stat_result) @@ -3677,7 +3687,7 @@ bool LLAppViewer::initCache() // Just in case, nuke any other old cache files in the directory. std::string dir; - dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""); + dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); std::string mask; mask = gDirUtilp->getDirDelimiter(); @@ -3693,11 +3703,11 @@ bool LLAppViewer::initCache() gDirUtilp->deleteFilesInDir(dir, mask); } - new_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE) + llformat("%u",new_salt); - new_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_INDEX_FILE_BASE) + llformat("%u",new_salt); + new_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_DATA_FILE_BASE) + llformat("%u", new_salt); + new_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_INDEX_FILE_BASE) + llformat("%u", new_salt); - static_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_data.db2"); - static_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_index.db2"); + static_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "static_data.db2"); + static_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "static_index.db2"); if (resize_vfs) { @@ -3720,19 +3730,19 @@ bool LLAppViewer::initCache() // Don't remove VFS after viewer crashes. If user has corrupt data, they can reinstall. JC gVFS = LLVFS::createLLVFS(new_vfs_index_file, new_vfs_data_file, false, vfs_size_u32, false); - if( !gVFS ) + if (!gVFS) { return false; } gStaticVFS = LLVFS::createLLVFS(static_vfs_index_file, static_vfs_data_file, true, 0, false); - if( !gStaticVFS ) + if (!gStaticVFS) { return false; } BOOL success = gVFS->isValid() && gStaticVFS->isValid(); - if( !success ) + if (!success) { return false; } diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 1a9d0af9af..8d4dd0228a 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -897,14 +897,15 @@ void LLFloaterPreference::onClickSetCache() void LLFloaterPreference::onClickResetCache() { - if (!gSavedSettings.getString("CacheLocation").empty()) + if (gDirUtilp->getCacheDir(false) == gDirUtilp->getCacheDir(true)) { - gSavedSettings.setString("NewCacheLocation", ""); - gSavedSettings.setString("NewCacheLocationTopFolder", ""); + // The cache location was already the default. + return; } - + gSavedSettings.setString("NewCacheLocation", ""); + gSavedSettings.setString("NewCacheLocationTopFolder", ""); LLNotificationsUtil::add("CacheWillBeMoved"); - std::string cache_location = gDirUtilp->getCacheDir(true); + std::string cache_location = gDirUtilp->getCacheDir(false); gSavedSettings.setString("CacheLocation", cache_location); std::string top_folder(gDirUtilp->getBaseFileName(cache_location)); gSavedSettings.setString("CacheLocationTopFolder", top_folder); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 7fb52c1939..5a68e0e37e 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -949,7 +949,7 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL texture_cache max_size -= sCacheMaxTexturesSize; LL_INFOS("TextureCache") << "Headers: " << sCacheMaxEntries - << " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << LL_ENDL; + << " Textures size: " << sCacheMaxTexturesSize / (1024 * 1024) << " MB" << LL_ENDL; setDirNames(location); @@ -1655,7 +1655,7 @@ void LLTextureCache::purgeTextures(bool validate) LL_INFOS("TextureCache") << "TEXTURE CACHE:" << " PURGED: " << purge_count << " ENTRIES: " << num_entries - << " CACHE SIZE: " << mTexturesSizeTotal / 1024*1024 << " MB" + << " CACHE SIZE: " << mTexturesSizeTotal / (1024 * 1024) << " MB" << llendl; } diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 901a1257e0..bdc21960cd 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -113,10 +113,10 @@ follows="left|top" height="15" increment="16" - initial_value="512" + initial_value="1024" layout="topleft" left_delta="150" - max_val="1024" + max_val="10240" min_val="32" name="cache_size" top_delta="-2" -- cgit v1.2.3 From 781af27e9cd500f6d62bc2d4658180f154af8816 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Mon, 9 May 2011 13:49:20 -0400 Subject: SH-1419 Sim complains about changing physical materials when Physics, Temporary, or Phantom is changed. --- indra/newview/llselectmgr.cpp | 10 +++++----- indra/newview/llviewerobject.cpp | 17 ++++++++++------- indra/newview/llviewerobject.h | 2 +- 3 files changed, 16 insertions(+), 13 deletions(-) (limited to 'indra') diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 9b264b81c7..8fa4065fa6 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1997,7 +1997,7 @@ void LLSelectMgr::selectionSetPhysicsType(U8 type) if (object->permModify()) { object->setPhysicsShapeType(mType); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } @@ -2016,7 +2016,7 @@ void LLSelectMgr::selectionSetFriction(F32 friction) if (object->permModify()) { object->setPhysicsFriction(mFriction); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } @@ -2035,7 +2035,7 @@ void LLSelectMgr::selectionSetGravity(F32 gravity ) if (object->permModify()) { object->setPhysicsGravity(mGravity); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } @@ -2054,7 +2054,7 @@ void LLSelectMgr::selectionSetDensity(F32 density ) if (object->permModify()) { object->setPhysicsDensity(mDensity); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } @@ -2073,7 +2073,7 @@ void LLSelectMgr::selectionSetRestitution(F32 restitution) if (object->permModify()) { object->setPhysicsRestitution(mRestitution); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 6d493bfcd5..f5fee662e6 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -5282,7 +5282,7 @@ bool LLViewerObject::specialHoverCursor() const || (mClickAction != 0); } -void LLViewerObject::updateFlags() +void LLViewerObject::updateFlags(BOOL physics_changed) { LLViewerRegion* regionp = getRegion(); if(!regionp) return; @@ -5295,12 +5295,15 @@ void LLViewerObject::updateFlags() gMessageSystem->addBOOL("IsTemporary", flagTemporaryOnRez() ); gMessageSystem->addBOOL("IsPhantom", flagPhantom() ); gMessageSystem->addBOOL("CastsShadows", flagCastShadows() ); - gMessageSystem->nextBlock("ExtraPhysics"); - gMessageSystem->addU8("PhysicsShapeType", getPhysicsShapeType() ); - gMessageSystem->addF32("Density", getPhysicsDensity() ); - gMessageSystem->addF32("Friction", getPhysicsFriction() ); - gMessageSystem->addF32("Restitution", getPhysicsRestitution() ); - gMessageSystem->addF32("GravityMultiplier", getPhysicsGravity() ); + if (physics_changed) + { + gMessageSystem->nextBlock("ExtraPhysics"); + gMessageSystem->addU8("PhysicsShapeType", getPhysicsShapeType() ); + gMessageSystem->addF32("Density", getPhysicsDensity() ); + gMessageSystem->addF32("Friction", getPhysicsFriction() ); + gMessageSystem->addF32("Restitution", getPhysicsRestitution() ); + gMessageSystem->addF32("GravityMultiplier", getPhysicsGravity() ); + } gMessageSystem->sendReliable( regionp->getHost() ); } diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index e417343bec..21198f7dd1 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -488,7 +488,7 @@ public: void setRegion(LLViewerRegion *regionp); virtual void updateRegion(LLViewerRegion *regionp); - void updateFlags(); + void updateFlags(BOOL physics_changed = FALSE); BOOL setFlags(U32 flag, BOOL state); void setPhysicsShapeType(U8 type); void setPhysicsGravity(F32 gravity); -- cgit v1.2.3 From 155d96000fdb319ee9ce03fd2e2d94c08f0c0a21 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Mon, 9 May 2011 13:50:07 -0400 Subject: SH-1444 "Allow mesh objects" setting is visible on a non-mesh region. --- indra/newview/llfloaterregioninfo.cpp | 5 +++++ indra/newview/skins/default/xui/en/panel_region_general.xml | 1 + 2 files changed, 6 insertions(+) (limited to 'indra') diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 34fda49375..fc6976755f 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -590,6 +590,11 @@ bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region) getChildView("im_btn")->setEnabled(allow_modify); getChildView("manage_telehub_btn")->setEnabled(allow_modify); + const bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && + gAgent.getRegion() && + !gAgent.getRegion()->getCapability("GetMesh").empty(); + getChildView("mesh_rez_enabled_check")->setVisible(enable_mesh); + getChildView("mesh_rez_enabled_check")->setEnabled(getChildView("mesh_rez_enabled_check")->getEnabled() && enable_mesh); // Data gets filled in by processRegionInfo return LLPanelRegionInfo::refreshFromRegion(region); diff --git a/indra/newview/skins/default/xui/en/panel_region_general.xml b/indra/newview/skins/default/xui/en/panel_region_general.xml index e0d9f3f714..3f9195d092 100644 --- a/indra/newview/skins/default/xui/en/panel_region_general.xml +++ b/indra/newview/skins/default/xui/en/panel_region_general.xml @@ -134,6 +134,7 @@ top="190" width="80" /> Date: Mon, 9 May 2011 18:00:10 -0400 Subject: SH-1343 Change wizard slider labels Changed "Performance" and "Accuracy" to "Higher Performance" and "Higher Accuracy" on physics page. --- indra/newview/skins/default/xui/en/floater_model_wizard.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_model_wizard.xml b/indra/newview/skins/default/xui/en/floater_model_wizard.xml index 03af348a8d..fa4c56ffec 100644 --- a/indra/newview/skins/default/xui/en/floater_model_wizard.xml +++ b/indra/newview/skins/default/xui/en/floater_model_wizard.xml @@ -571,9 +571,9 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se bg_opaque_color="DkGray2" background_visible="true" background_opaque="true"> - Performance + Higher Performance Faster rendering but less detailed; lowers Resource (prim) cost. - Accuracy + Higher Accuracy More detailed model but slower; increases Resource (prim) cost. Date: Fri, 13 May 2011 11:32:59 -0700 Subject: Updating to remove spam associated with the search for the [MacLocale] string. The change of OS version from "Darwin" to "Mac OS X" changed the name of the string the code is looking for. Reviewed by Richard. --- indra/newview/skins/default/xui/da/language_settings.xml | 1 + indra/newview/skins/default/xui/de/language_settings.xml | 1 + indra/newview/skins/default/xui/en/language_settings.xml | 1 + indra/newview/skins/default/xui/es/language_settings.xml | 1 + indra/newview/skins/default/xui/fr/language_settings.xml | 1 + indra/newview/skins/default/xui/it/language_settings.xml | 1 + indra/newview/skins/default/xui/ja/language_settings.xml | 1 + indra/newview/skins/default/xui/nl/language_settings.xml | 1 + indra/newview/skins/default/xui/pl/language_settings.xml | 1 + indra/newview/skins/default/xui/pt/language_settings.xml | 1 + 10 files changed, 10 insertions(+) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/da/language_settings.xml b/indra/newview/skins/default/xui/da/language_settings.xml index 3e46f69af1..0e3cbfd2d2 100644 --- a/indra/newview/skins/default/xui/da/language_settings.xml +++ b/indra/newview/skins/default/xui/da/language_settings.xml @@ -4,6 +4,7 @@ danish + da_DK.UTF-8 da_DK.UTF-8 da_DK.UTF-8 diff --git a/indra/newview/skins/default/xui/de/language_settings.xml b/indra/newview/skins/default/xui/de/language_settings.xml index d54f548fe1..f9346eef7d 100644 --- a/indra/newview/skins/default/xui/de/language_settings.xml +++ b/indra/newview/skins/default/xui/de/language_settings.xml @@ -4,6 +4,7 @@ german + de_DE.UTF-8 de_DE.UTF-8 de_DE.UTF-8 diff --git a/indra/newview/skins/default/xui/en/language_settings.xml b/indra/newview/skins/default/xui/en/language_settings.xml index c8a06fe401..51779e4bfd 100644 --- a/indra/newview/skins/default/xui/en/language_settings.xml +++ b/indra/newview/skins/default/xui/en/language_settings.xml @@ -4,6 +4,7 @@ english + C C C diff --git a/indra/newview/skins/default/xui/es/language_settings.xml b/indra/newview/skins/default/xui/es/language_settings.xml index f172994077..997293a741 100644 --- a/indra/newview/skins/default/xui/es/language_settings.xml +++ b/indra/newview/skins/default/xui/es/language_settings.xml @@ -4,6 +4,7 @@ spanish + es_ES.UTF-8 es_ES.UTF-8 es_ES.UTF-8 diff --git a/indra/newview/skins/default/xui/fr/language_settings.xml b/indra/newview/skins/default/xui/fr/language_settings.xml index bd272e1f28..fdac9d65a7 100644 --- a/indra/newview/skins/default/xui/fr/language_settings.xml +++ b/indra/newview/skins/default/xui/fr/language_settings.xml @@ -4,6 +4,7 @@ french + fr_FR.UTF-8 fr_FR.UTF-8 fr_FR.UTF-8 diff --git a/indra/newview/skins/default/xui/it/language_settings.xml b/indra/newview/skins/default/xui/it/language_settings.xml index 312b8e21aa..5f448fa828 100644 --- a/indra/newview/skins/default/xui/it/language_settings.xml +++ b/indra/newview/skins/default/xui/it/language_settings.xml @@ -4,6 +4,7 @@ italian + it_IT.UTF-8 it_IT.UTF-8 it_IT.UTF-8 diff --git a/indra/newview/skins/default/xui/ja/language_settings.xml b/indra/newview/skins/default/xui/ja/language_settings.xml index a6023f9b56..91e8f4be7c 100644 --- a/indra/newview/skins/default/xui/ja/language_settings.xml +++ b/indra/newview/skins/default/xui/ja/language_settings.xml @@ -4,6 +4,7 @@ japanese + ja_JP.UTF-8 ja_JP.UTF-8 ja_JP.UTF-8 diff --git a/indra/newview/skins/default/xui/nl/language_settings.xml b/indra/newview/skins/default/xui/nl/language_settings.xml index 53501d5dcb..40f4d9178a 100644 --- a/indra/newview/skins/default/xui/nl/language_settings.xml +++ b/indra/newview/skins/default/xui/nl/language_settings.xml @@ -4,6 +4,7 @@ dutch + nl_NL.UTF-8 nl_NL.UTF-8 nl_NL.UTF-8 diff --git a/indra/newview/skins/default/xui/pl/language_settings.xml b/indra/newview/skins/default/xui/pl/language_settings.xml index 681b38e9cf..93051d1317 100644 --- a/indra/newview/skins/default/xui/pl/language_settings.xml +++ b/indra/newview/skins/default/xui/pl/language_settings.xml @@ -4,6 +4,7 @@ polish + pl_PL.UTF-8 pl_PL.UTF-8 pl_PL.UTF-8 diff --git a/indra/newview/skins/default/xui/pt/language_settings.xml b/indra/newview/skins/default/xui/pt/language_settings.xml index e1de6ffea7..8799475ace 100644 --- a/indra/newview/skins/default/xui/pt/language_settings.xml +++ b/indra/newview/skins/default/xui/pt/language_settings.xml @@ -4,6 +4,7 @@ portuguese + pt_PT.UTF-8 pt_PT.UTF-8 pt_PT.UTF-8 -- cgit v1.2.3 From 3ba907e24d73541870ad57003869341a98e23153 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Fri, 13 May 2011 15:56:38 -0400 Subject: SH-769 FIXED Name field in upload model dialog allows 255 characters --- indra/newview/skins/default/xui/en/floater_model_preview.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index d08c3e7078..533e0c96f2 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -26,7 +26,7 @@ Name: - -- cgit v1.2.3 From c62ef53863bd01cb96de55e0250c8a8193b6c72b Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Fri, 13 May 2011 21:22:54 +0000 Subject: eventhost autopilot system should now set agent to flying when allow_flying= True --- indra/newview/llagentlistener.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'indra') diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 706851e7ff..591594d12c 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -339,10 +339,7 @@ void LLAgentListener::startAutoPilot(LLSD const & event_data) if (event_data.has("allow_flying")) { allow_flying = (BOOL) event_data["allow_flying"].asBoolean(); - if (!allow_flying) - { - mAgent.setFlying(FALSE); - } + mAgent.setFlying(allow_flying); } F32 stop_distance = 0.f; @@ -442,10 +439,7 @@ void LLAgentListener::startFollowPilot(LLSD const & event_data) if (target_id.notNull()) { - if (!allow_flying) - { - mAgent.setFlying(FALSE); - } + mAgent.setFlying(allow_flying); mFollowTarget = target_id; // Save follow target so we can report distance later mAgent.startFollowPilot(target_id, allow_flying, stop_distance); -- cgit v1.2.3 From e4a9704d4157151442accca1116ad70f7f63ae95 Mon Sep 17 00:00:00 2001 From: callum Date: Fri, 13 May 2011 17:08:43 -0700 Subject: EXP-676 FIX As a web developer, I want to access information about the current state of the SL client, such as avatar location --- indra/llplugin/llpluginclassmedia.cpp | 2744 ++++---- indra/llplugin/llpluginclassmedia.h | 840 +-- indra/media_plugins/webkit/media_plugin_webkit.cpp | 51 +- indra/newview/app_settings/settings.xml | 11 + indra/newview/llviewermedia.cpp | 7434 ++++++++++---------- indra/newview/llviewermedia.h | 5 +- indra/newview/skins/default/xui/en/menu_login.xml | 6 +- 7 files changed, 5643 insertions(+), 5448 deletions(-) (limited to 'indra') diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 2103216536..cc8fe53c3b 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -1,1335 +1,1409 @@ -/** - * @file llpluginclassmedia.cpp - * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class. - * - * @cond - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#include "linden_common.h" -#include "indra_constants.h" - -#include "llpluginclassmedia.h" -#include "llpluginmessageclasses.h" - -#include "llqtwebkit.h" - -static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256; - -static int nextPowerOf2( int value ) -{ - int next_power_of_2 = 1; - while ( next_power_of_2 < value ) - { - next_power_of_2 <<= 1; - } - - return next_power_of_2; -} - -LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner) -{ - mOwner = owner; - mPlugin = NULL; - reset(); - - //debug use - mDeleteOK = true ; -} - - -LLPluginClassMedia::~LLPluginClassMedia() -{ - llassert_always(mDeleteOK) ; - reset(); -} - -bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug) -{ - LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; - LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL; - LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; - - mPlugin = new LLPluginProcessParent(this); - mPlugin->setSleepTime(mSleepTime); - - // Queue up the media init message -- it will be sent after all the currently queued messages. - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init"); - message.setValue("target", mTarget); - sendMessage(message); - - mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug); - - return true; -} - - -void LLPluginClassMedia::reset() -{ - if(mPlugin != NULL) - { - delete mPlugin; - mPlugin = NULL; - } - - mTextureParamsReceived = false; - mRequestedTextureDepth = 0; - mRequestedTextureInternalFormat = 0; - mRequestedTextureFormat = 0; - mRequestedTextureType = 0; - mRequestedTextureSwapBytes = false; - mRequestedTextureCoordsOpenGL = false; - mTextureSharedMemorySize = 0; - mTextureSharedMemoryName.clear(); - mDefaultMediaWidth = 0; - mDefaultMediaHeight = 0; - mNaturalMediaWidth = 0; - mNaturalMediaHeight = 0; - mSetMediaWidth = -1; - mSetMediaHeight = -1; - mRequestedMediaWidth = 0; - mRequestedMediaHeight = 0; - mRequestedTextureWidth = 0; - mRequestedTextureHeight = 0; - mFullMediaWidth = 0; - mFullMediaHeight = 0; - mTextureWidth = 0; - mTextureHeight = 0; - mMediaWidth = 0; - mMediaHeight = 0; - mDirtyRect = LLRect::null; - mAutoScaleMedia = false; - mRequestedVolume = 1.0f; - mPriority = PRIORITY_NORMAL; - mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; - mAllowDownsample = false; - mPadding = 0; - mLastMouseX = 0; - mLastMouseY = 0; - mStatus = LLPluginClassMediaOwner::MEDIA_NONE; - mSleepTime = 1.0f / 100.0f; - mCanCut = false; - mCanCopy = false; - mCanPaste = false; - mMediaName.clear(); - mMediaDescription.clear(); - mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f); - - // media_browser class - mNavigateURI.clear(); - mNavigateResultCode = -1; - mNavigateResultString.clear(); - mHistoryBackAvailable = false; - mHistoryForwardAvailable = false; - mStatusText.clear(); - mProgressPercent = 0; - mClickURL.clear(); - mClickNavType.clear(); - mClickTarget.clear(); - mClickUUID.clear(); - mStatusCode = 0; - - // media_time class - mCurrentTime = 0.0f; - mDuration = 0.0f; - mCurrentRate = 0.0f; - mLoadedDuration = 0.0f; -} - -void LLPluginClassMedia::idle(void) -{ - if(mPlugin) - { - mPlugin->idle(); - } - - if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL)) - { - // Can't process a size change at this time - } - else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight)) - { - // Calculate the correct size for the media texture - mRequestedTextureHeight = mRequestedMediaHeight; - if(mPadding < 0) - { - // negative values indicate the plugin wants a power of 2 - mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth); - } - else - { - mRequestedTextureWidth = mRequestedMediaWidth; - - if(mPadding > 1) - { - // Pad up to a multiple of the specified number of bytes per row - int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth; - int pad = rowbytes % mPadding; - if(pad != 0) - { - rowbytes += mPadding - pad; - } - - if(rowbytes % mRequestedTextureDepth == 0) - { - mRequestedTextureWidth = rowbytes / mRequestedTextureDepth; - } - else - { - LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL; - } - } - } - - - // Size change has been requested but not initiated yet. - size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth; - - // Add an extra line for padding, just in case. - newsize += mRequestedTextureWidth * mRequestedTextureDepth; - - if(newsize != mTextureSharedMemorySize) - { - if(!mTextureSharedMemoryName.empty()) - { - // Tell the plugin to remove the old memory segment - mPlugin->removeSharedMemory(mTextureSharedMemoryName); - mTextureSharedMemoryName.clear(); - } - - mTextureSharedMemorySize = newsize; - mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize); - if(!mTextureSharedMemoryName.empty()) - { - void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); - - // clear texture memory to avoid random screen visual fuzz from uninitialized texture data - memset( addr, 0x00, newsize ); - - // We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin, - // so it may not be worthwhile. - // mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight); - } - } - - // This is our local indicator that a change is in progress. - mTextureWidth = -1; - mTextureHeight = -1; - mMediaWidth = -1; - mMediaHeight = -1; - - // This invalidates any existing dirty rect. - resetDirty(); - - // Send a size change message to the plugin - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change"); - message.setValue("name", mTextureSharedMemoryName); - message.setValueS32("width", mRequestedMediaWidth); - message.setValueS32("height", mRequestedMediaHeight); - message.setValueS32("texture_width", mRequestedTextureWidth); - message.setValueS32("texture_height", mRequestedTextureHeight); - message.setValueReal("background_r", mBackgroundColor.mV[VX]); - message.setValueReal("background_g", mBackgroundColor.mV[VY]); - message.setValueReal("background_b", mBackgroundColor.mV[VZ]); - message.setValueReal("background_a", mBackgroundColor.mV[VW]); - mPlugin->sendMessage(message); // DO NOT just use sendMessage() here -- we want this to jump ahead of the queue. - - LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL; - } - } - - if(mPlugin && mPlugin->isRunning()) - { - // Send queued messages - while(!mSendQueue.empty()) - { - LLPluginMessage message = mSendQueue.front(); - mSendQueue.pop(); - mPlugin->sendMessage(message); - } - } -} - -int LLPluginClassMedia::getTextureWidth() const -{ - return nextPowerOf2(mTextureWidth); -} - -int LLPluginClassMedia::getTextureHeight() const -{ - return nextPowerOf2(mTextureHeight); -} - -unsigned char* LLPluginClassMedia::getBitsData() -{ - unsigned char *result = NULL; - if((mPlugin != NULL) && !mTextureSharedMemoryName.empty()) - { - result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); - } - return result; -} - -void LLPluginClassMedia::setSize(int width, int height) -{ - if((width > 0) && (height > 0)) - { - mSetMediaWidth = width; - mSetMediaHeight = height; - } - else - { - mSetMediaWidth = -1; - mSetMediaHeight = -1; - } - - setSizeInternal(); -} - -void LLPluginClassMedia::setSizeInternal(void) -{ - if((mSetMediaWidth > 0) && (mSetMediaHeight > 0)) - { - mRequestedMediaWidth = mSetMediaWidth; - mRequestedMediaHeight = mSetMediaHeight; - } - else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0)) - { - mRequestedMediaWidth = mNaturalMediaWidth; - mRequestedMediaHeight = mNaturalMediaHeight; - } - else - { - mRequestedMediaWidth = mDefaultMediaWidth; - mRequestedMediaHeight = mDefaultMediaHeight; - } - - // Save these for size/interest calculations - mFullMediaWidth = mRequestedMediaWidth; - mFullMediaHeight = mRequestedMediaHeight; - - if(mAllowDownsample) - { - switch(mPriority) - { - case PRIORITY_SLIDESHOW: - case PRIORITY_LOW: - // Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit - while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) - { - mRequestedMediaWidth /= 2; - mRequestedMediaHeight /= 2; - } - break; - - default: - // Don't adjust texture size - break; - } - } - - if(mAutoScaleMedia) - { - mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth); - mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight); - } - - if(mRequestedMediaWidth > 2048) - mRequestedMediaWidth = 2048; - - if(mRequestedMediaHeight > 2048) - mRequestedMediaHeight = 2048; -} - -void LLPluginClassMedia::setAutoScale(bool auto_scale) -{ - if(auto_scale != mAutoScaleMedia) - { - mAutoScaleMedia = auto_scale; - setSizeInternal(); - } -} - -bool LLPluginClassMedia::textureValid(void) -{ - if( - !mTextureParamsReceived || - mTextureWidth <= 0 || - mTextureHeight <= 0 || - mMediaWidth <= 0 || - mMediaHeight <= 0 || - mRequestedMediaWidth != mMediaWidth || - mRequestedMediaHeight != mMediaHeight || - getBitsData() == NULL - ) - return false; - - return true; -} - -bool LLPluginClassMedia::getDirty(LLRect *dirty_rect) -{ - bool result = !mDirtyRect.isEmpty(); - - if(dirty_rect != NULL) - { - *dirty_rect = mDirtyRect; - } - - return result; -} - -void LLPluginClassMedia::resetDirty(void) -{ - mDirtyRect = LLRect::null; -} - -std::string LLPluginClassMedia::translateModifiers(MASK modifiers) -{ - std::string result; - - - if(modifiers & MASK_CONTROL) - { - result += "control|"; - } - - if(modifiers & MASK_ALT) - { - result += "alt|"; - } - - if(modifiers & MASK_SHIFT) - { - result += "shift|"; - } - - // TODO: should I deal with platform differences here or in callers? - // TODO: how do we deal with the Mac "command" key? -/* - if(modifiers & MASK_SOMETHING) - { - result += "meta|"; - } -*/ - return result; -} - -void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers) -{ - if(type == MOUSE_EVENT_MOVE) - { - if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked()) - { - // Don't queue up mouse move events that can't be delivered. - return; - } - - if((x == mLastMouseX) && (y == mLastMouseY)) - { - // Don't spam unnecessary mouse move events. - return; - } - - mLastMouseX = x; - mLastMouseY = y; - } - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event"); - std::string temp; - switch(type) - { - case MOUSE_EVENT_DOWN: temp = "down"; break; - case MOUSE_EVENT_UP: temp = "up"; break; - case MOUSE_EVENT_MOVE: temp = "move"; break; - case MOUSE_EVENT_DOUBLE_CLICK: temp = "double_click"; break; - } - message.setValue("event", temp); - - message.setValueS32("button", button); - - message.setValueS32("x", x); - - // Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it. - if(!mRequestedTextureCoordsOpenGL) - { - // TODO: Should I use mMediaHeight or mRequestedMediaHeight here? - y = mMediaHeight - y; - } - message.setValueS32("y", y); - - message.setValue("modifiers", translateModifiers(modifiers)); - - sendMessage(message); -} - -bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data) -{ - bool result = true; - - // FIXME: - // HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode. - // For now, return false for the ones the webkit plugin won't handle properly. - - switch(key_code) - { - case KEY_BACKSPACE: - case KEY_TAB: - case KEY_RETURN: - case KEY_PAD_RETURN: - case KEY_SHIFT: - case KEY_CONTROL: - case KEY_ALT: - case KEY_CAPSLOCK: - case KEY_ESCAPE: - case KEY_PAGE_UP: - case KEY_PAGE_DOWN: - case KEY_END: - case KEY_HOME: - case KEY_LEFT: - case KEY_UP: - case KEY_RIGHT: - case KEY_DOWN: - case KEY_INSERT: - case KEY_DELETE: - // These will be handled - break; - - default: - // regular ASCII characters will also be handled - if(key_code >= KEY_SPECIAL) - { - // Other "special" codes will not work properly. - result = false; - } - break; - } - -#if LL_DARWIN - if(modifiers & MASK_ALT) - { - // Option-key modified characters should be handled by the unicode input path instead of this one. - result = false; - } -#endif - - if(result) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event"); - std::string temp; - switch(type) - { - case KEY_EVENT_DOWN: temp = "down"; break; - case KEY_EVENT_UP: temp = "up"; break; - case KEY_EVENT_REPEAT: temp = "repeat"; break; - } - message.setValue("event", temp); - - message.setValueS32("key", key_code); - - message.setValue("modifiers", translateModifiers(modifiers)); - message.setValueLLSD("native_key_data", native_key_data); - - sendMessage(message); - } - - return result; -} - -void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); - - message.setValueS32("x", x); - message.setValueS32("y", y); - message.setValue("modifiers", translateModifiers(modifiers)); - - sendMessage(message); -} - -bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event"); - - message.setValue("text", text); - message.setValue("modifiers", translateModifiers(modifiers)); - message.setValueLLSD("native_key_data", native_key_data); - - sendMessage(message); - - return true; -} - -void LLPluginClassMedia::loadURI(const std::string &uri) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri"); - - message.setValue("uri", uri); - - sendMessage(message); -} - -const char* LLPluginClassMedia::priorityToString(EPriority priority) -{ - const char* result = "UNKNOWN"; - switch(priority) - { - case PRIORITY_UNLOADED: result = "unloaded"; break; - case PRIORITY_STOPPED: result = "stopped"; break; - case PRIORITY_HIDDEN: result = "hidden"; break; - case PRIORITY_SLIDESHOW: result = "slideshow"; break; - case PRIORITY_LOW: result = "low"; break; - case PRIORITY_NORMAL: result = "normal"; break; - case PRIORITY_HIGH: result = "high"; break; - } - - return result; -} - -void LLPluginClassMedia::setPriority(EPriority priority) -{ - if(mPriority != priority) - { - mPriority = priority; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); - - std::string priority_string = priorityToString(priority); - switch(priority) - { - case PRIORITY_UNLOADED: - mSleepTime = 1.0f; - break; - case PRIORITY_STOPPED: - mSleepTime = 1.0f; - break; - case PRIORITY_HIDDEN: - mSleepTime = 1.0f; - break; - case PRIORITY_SLIDESHOW: - mSleepTime = 1.0f; - break; - case PRIORITY_LOW: - mSleepTime = 1.0f / 25.0f; - break; - case PRIORITY_NORMAL: - mSleepTime = 1.0f / 50.0f; - break; - case PRIORITY_HIGH: - mSleepTime = 1.0f / 100.0f; - break; - } - - message.setValue("priority", priority_string); - - sendMessage(message); - - if(mPlugin) - { - mPlugin->setSleepTime(mSleepTime); - } - - LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; - - // This may affect the calculated size, so recalculate it here. - setSizeInternal(); - } -} - -void LLPluginClassMedia::setLowPrioritySizeLimit(int size) -{ - int power = nextPowerOf2(size); - if(mLowPrioritySizeLimit != power) - { - mLowPrioritySizeLimit = power; - - // This may affect the calculated size, so recalculate it here. - setSizeInternal(); - } -} - -F64 LLPluginClassMedia::getCPUUsage() -{ - F64 result = 0.0f; - - if(mPlugin) - { - result = mPlugin->getCPUUsage(); - } - - return result; -} - -void LLPluginClassMedia::sendPickFileResponse(const std::string &file) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response"); - message.setValue("file", file); - if(mPlugin && mPlugin->isBlocked()) - { - // If the plugin sent a blocking pick-file request, the response should unblock it. - message.setValueBoolean("blocking_response", true); - } - sendMessage(message); -} - -void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response"); - message.setValueBoolean("ok", ok); - message.setValue("username", username); - message.setValue("password", password); - if(mPlugin && mPlugin->isBlocked()) - { - // If the plugin sent a blocking pick-file request, the response should unblock it. - message.setValueBoolean("blocking_response", true); - } - sendMessage(message); -} - -void LLPluginClassMedia::cut() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); - sendMessage(message); -} - -void LLPluginClassMedia::copy() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy"); - sendMessage(message); -} - -void LLPluginClassMedia::paste() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste"); - sendMessage(message); -} - -void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path"); - message.setValue("path", user_data_path); - sendMessage(message); -} - -void LLPluginClassMedia::setLanguageCode(const std::string &language_code) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code"); - message.setValue("language", language_code); - sendMessage(message); -} - -void LLPluginClassMedia::setPluginsEnabled(const bool enabled) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled"); - message.setValueBoolean("enable", enabled); - sendMessage(message); -} - -void LLPluginClassMedia::setJavascriptEnabled(const bool enabled) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled"); - message.setValueBoolean("enable", enabled); - sendMessage(message); -} - -void LLPluginClassMedia::setTarget(const std::string &target) -{ - mTarget = target; -} - -/* virtual */ -void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) -{ - std::string message_class = message.getClass(); - - if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) - { - std::string message_name = message.getName(); - if(message_name == "texture_params") - { - mRequestedTextureDepth = message.getValueS32("depth"); - mRequestedTextureInternalFormat = message.getValueU32("internalformat"); - mRequestedTextureFormat = message.getValueU32("format"); - mRequestedTextureType = message.getValueU32("type"); - mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes"); - mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl"); - - // These two are optional, and will default to 0 if they're not specified. - mDefaultMediaWidth = message.getValueS32("default_width"); - mDefaultMediaHeight = message.getValueS32("default_height"); - - mAllowDownsample = message.getValueBoolean("allow_downsample"); - mPadding = message.getValueS32("padding"); - - setSizeInternal(); - - mTextureParamsReceived = true; - } - else if(message_name == "updated") - { - if(message.hasValue("left")) - { - LLRect newDirtyRect; - newDirtyRect.mLeft = message.getValueS32("left"); - newDirtyRect.mTop = message.getValueS32("top"); - newDirtyRect.mRight = message.getValueS32("right"); - newDirtyRect.mBottom = message.getValueS32("bottom"); - - // The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion. - // If they're backwards, swap them. - if(newDirtyRect.mTop < newDirtyRect.mBottom) - { - S32 temp = newDirtyRect.mTop; - newDirtyRect.mTop = newDirtyRect.mBottom; - newDirtyRect.mBottom = temp; - } - - if(mDirtyRect.isEmpty()) - { - mDirtyRect = newDirtyRect; - } - else - { - mDirtyRect.unionWith(newDirtyRect); - } - - LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" - << newDirtyRect.mLeft << ", " - << newDirtyRect.mTop << ", " - << newDirtyRect.mRight << ", " - << newDirtyRect.mBottom << "), new dirty rect is: (" - << mDirtyRect.mLeft << ", " - << mDirtyRect.mTop << ", " - << mDirtyRect.mRight << ", " - << mDirtyRect.mBottom << ")" - << LL_ENDL; - - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED); - } - - - bool time_duration_updated = false; - int previous_percent = mProgressPercent; - - if(message.hasValue("current_time")) - { - mCurrentTime = message.getValueReal("current_time"); - time_duration_updated = true; - } - if(message.hasValue("duration")) - { - mDuration = message.getValueReal("duration"); - time_duration_updated = true; - } - - if(message.hasValue("current_rate")) - { - mCurrentRate = message.getValueReal("current_rate"); - } - - if(message.hasValue("loaded_duration")) - { - mLoadedDuration = message.getValueReal("loaded_duration"); - time_duration_updated = true; - } - else - { - // If the message doesn't contain a loaded_duration param, assume it's equal to duration - mLoadedDuration = mDuration; - } - - // Calculate a percentage based on the loaded duration and total duration. - if(mDuration != 0.0f) // Don't divide by zero. - { - mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration); - } - - if(time_duration_updated) - { - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED); - } - - if(previous_percent != mProgressPercent) - { - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); - } - } - else if(message_name == "media_status") - { - std::string status = message.getValue("status"); - - LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL; - - if(status == "loading") - { - mStatus = LLPluginClassMediaOwner::MEDIA_LOADING; - } - else if(status == "loaded") - { - mStatus = LLPluginClassMediaOwner::MEDIA_LOADED; - } - else if(status == "error") - { - mStatus = LLPluginClassMediaOwner::MEDIA_ERROR; - } - else if(status == "playing") - { - mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING; - } - else if(status == "paused") - { - mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED; - } - else if(status == "done") - { - mStatus = LLPluginClassMediaOwner::MEDIA_DONE; - } - else - { - // empty string or any unknown string - mStatus = LLPluginClassMediaOwner::MEDIA_NONE; - } - } - else if(message_name == "size_change_request") - { - S32 width = message.getValueS32("width"); - S32 height = message.getValueS32("height"); - std::string name = message.getValue("name"); - - // TODO: check that name matches? - mNaturalMediaWidth = width; - mNaturalMediaHeight = height; - - setSizeInternal(); - } - else if(message_name == "size_change_response") - { - std::string name = message.getValue("name"); - - // TODO: check that name matches? - - mTextureWidth = message.getValueS32("texture_width"); - mTextureHeight = message.getValueS32("texture_height"); - mMediaWidth = message.getValueS32("width"); - mMediaHeight = message.getValueS32("height"); - - // This invalidates any existing dirty rect. - resetDirty(); - - // TODO: should we verify that the plugin sent back the right values? - // Two size changes in a row may cause them to not match, due to queueing, etc. - - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED); - } - else if(message_name == "cursor_changed") - { - mCursorName = message.getValue("name"); - - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED); - } - else if(message_name == "edit_state") - { - if(message.hasValue("cut")) - { - mCanCut = message.getValueBoolean("cut"); - } - if(message.hasValue("copy")) - { - mCanCopy = message.getValueBoolean("copy"); - } - if(message.hasValue("paste")) - { - mCanPaste = message.getValueBoolean("paste"); - } - } - else if(message_name == "name_text") - { - mMediaName = message.getValue("name"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED); - } - else if(message_name == "pick_file") - { - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST); - } - else if(message_name == "auth_request") - { - mAuthURL = message.getValue("url"); - mAuthRealm = message.getValue("realm"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST); - } - else - { - LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; - } - } - else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) - { - std::string message_name = message.getName(); - if(message_name == "navigate_begin") - { - mNavigateURI = message.getValue("uri"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN); - } - else if(message_name == "navigate_complete") - { - mNavigateURI = message.getValue("uri"); - mNavigateResultCode = message.getValueS32("result_code"); - mNavigateResultString = message.getValue("result_string"); - mHistoryBackAvailable = message.getValueBoolean("history_back_available"); - mHistoryForwardAvailable = message.getValueBoolean("history_forward_available"); - - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE); - } - else if(message_name == "progress") - { - mProgressPercent = message.getValueS32("percent"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); - } - else if(message_name == "status_text") - { - mStatusText = message.getValue("status"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED); - } - else if(message_name == "location_changed") - { - mLocation = message.getValue("uri"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED); - } - else if(message_name == "click_href") - { - mClickURL = message.getValue("uri"); - mClickTarget = message.getValue("target"); - mClickUUID = message.getValue("uuid"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF); - } - else if(message_name == "click_nofollow") - { - mClickURL = message.getValue("uri"); - mClickNavType = message.getValue("nav_type"); - mClickTarget.clear(); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW); - } - else if(message_name == "navigate_error_page") - { - mStatusCode = message.getValueS32("status_code"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE); - } - else if(message_name == "cookie_set") - { - if(mOwner) - { - mOwner->handleCookieSet(this, message.getValue("cookie")); - } - } - else if(message_name == "close_request") - { - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST); - } - else if(message_name == "geometry_change") - { - mClickUUID = message.getValue("uuid"); - mGeometryX = message.getValueS32("x"); - mGeometryY = message.getValueS32("y"); - mGeometryWidth = message.getValueS32("width"); - mGeometryHeight = message.getValueS32("height"); - - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE); - } - else if(message_name == "link_hovered") - { - // text is not currently used -- the tooltip hover text is taken from the "title". - mHoverLink = message.getValue("link"); - mHoverText = message.getValue("title"); - // message.getValue("text"); - - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED); - } - else - { - LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; - } - } - else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) - { - std::string message_name = message.getName(); - - // This class hasn't defined any incoming messages yet. -// if(message_name == "message_name") -// { -// } -// else - { - LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; - } - } - -} - -/* virtual */ -void LLPluginClassMedia::pluginLaunchFailed() -{ - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH); -} - -/* virtual */ -void LLPluginClassMedia::pluginDied() -{ - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED); -} - -void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event) -{ - if(mOwner) - { - mOwner->handleMediaEvent(this, event); - } -} - -void LLPluginClassMedia::sendMessage(const LLPluginMessage &message) -{ - if(mPlugin && mPlugin->isRunning()) - { - mPlugin->sendMessage(message); - } - else - { - // The plugin isn't set up yet -- queue this message to be sent after initialization. - mSendQueue.push(message); - } -} - -//////////////////////////////////////////////////////////// -// MARK: media_browser class functions -bool LLPluginClassMedia::pluginSupportsMediaBrowser(void) -{ - std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER); - return !version.empty(); -} - -void LLPluginClassMedia::focus(bool focused) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus"); - - message.setValueBoolean("focused", focused); - - sendMessage(message); -} - -void LLPluginClassMedia::clear_cache() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache"); - sendMessage(message); -} - -void LLPluginClassMedia::clear_cookies() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies"); - sendMessage(message); -} - -void LLPluginClassMedia::set_cookies(const std::string &cookies) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies"); - message.setValue("cookies", cookies); - sendMessage(message); -} - -void LLPluginClassMedia::enable_cookies(bool enable) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies"); - message.setValueBoolean("enable", enable); - sendMessage(message); -} - -void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup"); - - message.setValueBoolean("enable", enable); - message.setValue("host", host); - message.setValueS32("port", port); - - sendMessage(message); -} - -void LLPluginClassMedia::browse_stop() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop"); - sendMessage(message); -} - -void LLPluginClassMedia::browse_reload(bool ignore_cache) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload"); - - message.setValueBoolean("ignore_cache", ignore_cache); - - sendMessage(message); -} - -void LLPluginClassMedia::browse_forward() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward"); - sendMessage(message); -} - -void LLPluginClassMedia::browse_back() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back"); - sendMessage(message); -} - -void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent"); - - message.setValue("user_agent", user_agent); - - sendMessage(message); -} - -void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened"); - - message.setValue("target", target); - message.setValue("uuid", uuid); - - sendMessage(message); -} - -void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed"); - - message.setValue("uuid", uuid); - - sendMessage(message); -} - -void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors"); - message.setValueBoolean("ignore", ignore); - sendMessage(message); -} - -void LLPluginClassMedia::addCertificateFilePath(const std::string& path) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path"); - message.setValue("path", path); - sendMessage(message); -} - -void LLPluginClassMedia::crashPlugin() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); - - sendMessage(message); -} - -void LLPluginClassMedia::hangPlugin() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang"); - - sendMessage(message); -} - - -//////////////////////////////////////////////////////////// -// MARK: media_time class functions -bool LLPluginClassMedia::pluginSupportsMediaTime(void) -{ - std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME); - return !version.empty(); -} - -void LLPluginClassMedia::stop() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop"); - sendMessage(message); -} - -void LLPluginClassMedia::start(float rate) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start"); - - message.setValueReal("rate", rate); - - sendMessage(message); -} - -void LLPluginClassMedia::pause() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause"); - sendMessage(message); -} - -void LLPluginClassMedia::seek(float time) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek"); - - message.setValueReal("time", time); - - sendMessage(message); -} - -void LLPluginClassMedia::setLoop(bool loop) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop"); - - message.setValueBoolean("loop", loop); - - sendMessage(message); -} - -void LLPluginClassMedia::setVolume(float volume) -{ - if(volume != mRequestedVolume) - { - mRequestedVolume = volume; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume"); - - message.setValueReal("volume", volume); - - sendMessage(message); - } -} - -float LLPluginClassMedia::getVolume() -{ - return mRequestedVolume; -} - -void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history) -{ - // Send URL history to plugin - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history"); - message.setValueLLSD("history", url_history); - sendMessage(message); - - LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL; -} - +/** + * @file llpluginclassmedia.cpp + * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * @endcond + */ + +#include "linden_common.h" +#include "indra_constants.h" + +#include "llpluginclassmedia.h" +#include "llpluginmessageclasses.h" + +#include "llqtwebkit.h" + +static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256; + +static int nextPowerOf2( int value ) +{ + int next_power_of_2 = 1; + while ( next_power_of_2 < value ) + { + next_power_of_2 <<= 1; + } + + return next_power_of_2; +} + +LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner) +{ + mOwner = owner; + mPlugin = NULL; + reset(); + + //debug use + mDeleteOK = true ; +} + + +LLPluginClassMedia::~LLPluginClassMedia() +{ + llassert_always(mDeleteOK) ; + reset(); +} + +bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug) +{ + LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; + LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL; + LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; + + mPlugin = new LLPluginProcessParent(this); + mPlugin->setSleepTime(mSleepTime); + + // Queue up the media init message -- it will be sent after all the currently queued messages. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init"); + message.setValue("target", mTarget); + sendMessage(message); + + mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug); + + return true; +} + + +void LLPluginClassMedia::reset() +{ + if(mPlugin != NULL) + { + delete mPlugin; + mPlugin = NULL; + } + + mTextureParamsReceived = false; + mRequestedTextureDepth = 0; + mRequestedTextureInternalFormat = 0; + mRequestedTextureFormat = 0; + mRequestedTextureType = 0; + mRequestedTextureSwapBytes = false; + mRequestedTextureCoordsOpenGL = false; + mTextureSharedMemorySize = 0; + mTextureSharedMemoryName.clear(); + mDefaultMediaWidth = 0; + mDefaultMediaHeight = 0; + mNaturalMediaWidth = 0; + mNaturalMediaHeight = 0; + mSetMediaWidth = -1; + mSetMediaHeight = -1; + mRequestedMediaWidth = 0; + mRequestedMediaHeight = 0; + mRequestedTextureWidth = 0; + mRequestedTextureHeight = 0; + mFullMediaWidth = 0; + mFullMediaHeight = 0; + mTextureWidth = 0; + mTextureHeight = 0; + mMediaWidth = 0; + mMediaHeight = 0; + mDirtyRect = LLRect::null; + mAutoScaleMedia = false; + mRequestedVolume = 1.0f; + mPriority = PRIORITY_NORMAL; + mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; + mAllowDownsample = false; + mPadding = 0; + mLastMouseX = 0; + mLastMouseY = 0; + mStatus = LLPluginClassMediaOwner::MEDIA_NONE; + mSleepTime = 1.0f / 100.0f; + mCanCut = false; + mCanCopy = false; + mCanPaste = false; + mMediaName.clear(); + mMediaDescription.clear(); + mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f); + + // media_browser class + mNavigateURI.clear(); + mNavigateResultCode = -1; + mNavigateResultString.clear(); + mHistoryBackAvailable = false; + mHistoryForwardAvailable = false; + mStatusText.clear(); + mProgressPercent = 0; + mClickURL.clear(); + mClickNavType.clear(); + mClickTarget.clear(); + mClickUUID.clear(); + mStatusCode = 0; + + // media_time class + mCurrentTime = 0.0f; + mDuration = 0.0f; + mCurrentRate = 0.0f; + mLoadedDuration = 0.0f; +} + +void LLPluginClassMedia::idle(void) +{ + if(mPlugin) + { + mPlugin->idle(); + } + + if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL)) + { + // Can't process a size change at this time + } + else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight)) + { + // Calculate the correct size for the media texture + mRequestedTextureHeight = mRequestedMediaHeight; + if(mPadding < 0) + { + // negative values indicate the plugin wants a power of 2 + mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth); + } + else + { + mRequestedTextureWidth = mRequestedMediaWidth; + + if(mPadding > 1) + { + // Pad up to a multiple of the specified number of bytes per row + int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth; + int pad = rowbytes % mPadding; + if(pad != 0) + { + rowbytes += mPadding - pad; + } + + if(rowbytes % mRequestedTextureDepth == 0) + { + mRequestedTextureWidth = rowbytes / mRequestedTextureDepth; + } + else + { + LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL; + } + } + } + + + // Size change has been requested but not initiated yet. + size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth; + + // Add an extra line for padding, just in case. + newsize += mRequestedTextureWidth * mRequestedTextureDepth; + + if(newsize != mTextureSharedMemorySize) + { + if(!mTextureSharedMemoryName.empty()) + { + // Tell the plugin to remove the old memory segment + mPlugin->removeSharedMemory(mTextureSharedMemoryName); + mTextureSharedMemoryName.clear(); + } + + mTextureSharedMemorySize = newsize; + mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize); + if(!mTextureSharedMemoryName.empty()) + { + void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); + + // clear texture memory to avoid random screen visual fuzz from uninitialized texture data + memset( addr, 0x00, newsize ); + + // We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin, + // so it may not be worthwhile. + // mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight); + } + } + + // This is our local indicator that a change is in progress. + mTextureWidth = -1; + mTextureHeight = -1; + mMediaWidth = -1; + mMediaHeight = -1; + + // This invalidates any existing dirty rect. + resetDirty(); + + // Send a size change message to the plugin + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change"); + message.setValue("name", mTextureSharedMemoryName); + message.setValueS32("width", mRequestedMediaWidth); + message.setValueS32("height", mRequestedMediaHeight); + message.setValueS32("texture_width", mRequestedTextureWidth); + message.setValueS32("texture_height", mRequestedTextureHeight); + message.setValueReal("background_r", mBackgroundColor.mV[VX]); + message.setValueReal("background_g", mBackgroundColor.mV[VY]); + message.setValueReal("background_b", mBackgroundColor.mV[VZ]); + message.setValueReal("background_a", mBackgroundColor.mV[VW]); + mPlugin->sendMessage(message); // DO NOT just use sendMessage() here -- we want this to jump ahead of the queue. + + LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL; + } + } + + if(mPlugin && mPlugin->isRunning()) + { + // Send queued messages + while(!mSendQueue.empty()) + { + LLPluginMessage message = mSendQueue.front(); + mSendQueue.pop(); + mPlugin->sendMessage(message); + } + } +} + +int LLPluginClassMedia::getTextureWidth() const +{ + return nextPowerOf2(mTextureWidth); +} + +int LLPluginClassMedia::getTextureHeight() const +{ + return nextPowerOf2(mTextureHeight); +} + +unsigned char* LLPluginClassMedia::getBitsData() +{ + unsigned char *result = NULL; + if((mPlugin != NULL) && !mTextureSharedMemoryName.empty()) + { + result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); + } + return result; +} + +void LLPluginClassMedia::setSize(int width, int height) +{ + if((width > 0) && (height > 0)) + { + mSetMediaWidth = width; + mSetMediaHeight = height; + } + else + { + mSetMediaWidth = -1; + mSetMediaHeight = -1; + } + + setSizeInternal(); +} + +void LLPluginClassMedia::setSizeInternal(void) +{ + if((mSetMediaWidth > 0) && (mSetMediaHeight > 0)) + { + mRequestedMediaWidth = mSetMediaWidth; + mRequestedMediaHeight = mSetMediaHeight; + } + else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0)) + { + mRequestedMediaWidth = mNaturalMediaWidth; + mRequestedMediaHeight = mNaturalMediaHeight; + } + else + { + mRequestedMediaWidth = mDefaultMediaWidth; + mRequestedMediaHeight = mDefaultMediaHeight; + } + + // Save these for size/interest calculations + mFullMediaWidth = mRequestedMediaWidth; + mFullMediaHeight = mRequestedMediaHeight; + + if(mAllowDownsample) + { + switch(mPriority) + { + case PRIORITY_SLIDESHOW: + case PRIORITY_LOW: + // Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit + while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) + { + mRequestedMediaWidth /= 2; + mRequestedMediaHeight /= 2; + } + break; + + default: + // Don't adjust texture size + break; + } + } + + if(mAutoScaleMedia) + { + mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth); + mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight); + } + + if(mRequestedMediaWidth > 2048) + mRequestedMediaWidth = 2048; + + if(mRequestedMediaHeight > 2048) + mRequestedMediaHeight = 2048; +} + +void LLPluginClassMedia::setAutoScale(bool auto_scale) +{ + if(auto_scale != mAutoScaleMedia) + { + mAutoScaleMedia = auto_scale; + setSizeInternal(); + } +} + +bool LLPluginClassMedia::textureValid(void) +{ + if( + !mTextureParamsReceived || + mTextureWidth <= 0 || + mTextureHeight <= 0 || + mMediaWidth <= 0 || + mMediaHeight <= 0 || + mRequestedMediaWidth != mMediaWidth || + mRequestedMediaHeight != mMediaHeight || + getBitsData() == NULL + ) + return false; + + return true; +} + +bool LLPluginClassMedia::getDirty(LLRect *dirty_rect) +{ + bool result = !mDirtyRect.isEmpty(); + + if(dirty_rect != NULL) + { + *dirty_rect = mDirtyRect; + } + + return result; +} + +void LLPluginClassMedia::resetDirty(void) +{ + mDirtyRect = LLRect::null; +} + +std::string LLPluginClassMedia::translateModifiers(MASK modifiers) +{ + std::string result; + + + if(modifiers & MASK_CONTROL) + { + result += "control|"; + } + + if(modifiers & MASK_ALT) + { + result += "alt|"; + } + + if(modifiers & MASK_SHIFT) + { + result += "shift|"; + } + + // TODO: should I deal with platform differences here or in callers? + // TODO: how do we deal with the Mac "command" key? +/* + if(modifiers & MASK_SOMETHING) + { + result += "meta|"; + } +*/ + return result; +} + +void LLPluginClassMedia::jsExposeObjectEvent( bool expose ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_expose_object"); + message.setValueBoolean( "expose", expose ); + sendMessage( message ); +} + +void LLPluginClassMedia::jsValuesValidEvent( bool valid ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_values_valid"); + message.setValueBoolean( "valid", valid ); + sendMessage( message ); +} + +void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_location"); + message.setValueReal( "x", x ); + message.setValueReal( "y", y ); + message.setValueReal( "z", z ); + sendMessage( message ); +} + +void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_language"); + message.setValue( "language", language ); + sendMessage( message ); +} + +void LLPluginClassMedia::jsAgentRegionEvent( const std::string& region ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_region"); + message.setValue( "region", region ); + sendMessage( message ); +} + +void LLPluginClassMedia::jsAgentMaturityEvent( const std::string& maturity ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_maturity"); + message.setValue( "maturity", maturity ); + sendMessage( message ); +} + +void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers) +{ + if(type == MOUSE_EVENT_MOVE) + { + if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked()) + { + // Don't queue up mouse move events that can't be delivered. + return; + } + + if((x == mLastMouseX) && (y == mLastMouseY)) + { + // Don't spam unnecessary mouse move events. + return; + } + + mLastMouseX = x; + mLastMouseY = y; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event"); + std::string temp; + switch(type) + { + case MOUSE_EVENT_DOWN: temp = "down"; break; + case MOUSE_EVENT_UP: temp = "up"; break; + case MOUSE_EVENT_MOVE: temp = "move"; break; + case MOUSE_EVENT_DOUBLE_CLICK: temp = "double_click"; break; + } + message.setValue("event", temp); + + message.setValueS32("button", button); + + message.setValueS32("x", x); + + // Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it. + if(!mRequestedTextureCoordsOpenGL) + { + // TODO: Should I use mMediaHeight or mRequestedMediaHeight here? + y = mMediaHeight - y; + } + message.setValueS32("y", y); + + message.setValue("modifiers", translateModifiers(modifiers)); + + sendMessage(message); +} + +bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data) +{ + bool result = true; + + // FIXME: + // HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode. + // For now, return false for the ones the webkit plugin won't handle properly. + + switch(key_code) + { + case KEY_BACKSPACE: + case KEY_TAB: + case KEY_RETURN: + case KEY_PAD_RETURN: + case KEY_SHIFT: + case KEY_CONTROL: + case KEY_ALT: + case KEY_CAPSLOCK: + case KEY_ESCAPE: + case KEY_PAGE_UP: + case KEY_PAGE_DOWN: + case KEY_END: + case KEY_HOME: + case KEY_LEFT: + case KEY_UP: + case KEY_RIGHT: + case KEY_DOWN: + case KEY_INSERT: + case KEY_DELETE: + // These will be handled + break; + + default: + // regular ASCII characters will also be handled + if(key_code >= KEY_SPECIAL) + { + // Other "special" codes will not work properly. + result = false; + } + break; + } + +#if LL_DARWIN + if(modifiers & MASK_ALT) + { + // Option-key modified characters should be handled by the unicode input path instead of this one. + result = false; + } +#endif + + if(result) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event"); + std::string temp; + switch(type) + { + case KEY_EVENT_DOWN: temp = "down"; break; + case KEY_EVENT_UP: temp = "up"; break; + case KEY_EVENT_REPEAT: temp = "repeat"; break; + } + message.setValue("event", temp); + + message.setValueS32("key", key_code); + + message.setValue("modifiers", translateModifiers(modifiers)); + message.setValueLLSD("native_key_data", native_key_data); + + sendMessage(message); + } + + return result; +} + +void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); + + message.setValueS32("x", x); + message.setValueS32("y", y); + message.setValue("modifiers", translateModifiers(modifiers)); + + sendMessage(message); +} + +bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event"); + + message.setValue("text", text); + message.setValue("modifiers", translateModifiers(modifiers)); + message.setValueLLSD("native_key_data", native_key_data); + + sendMessage(message); + + return true; +} + +void LLPluginClassMedia::loadURI(const std::string &uri) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri"); + + message.setValue("uri", uri); + + sendMessage(message); +} + +const char* LLPluginClassMedia::priorityToString(EPriority priority) +{ + const char* result = "UNKNOWN"; + switch(priority) + { + case PRIORITY_UNLOADED: result = "unloaded"; break; + case PRIORITY_STOPPED: result = "stopped"; break; + case PRIORITY_HIDDEN: result = "hidden"; break; + case PRIORITY_SLIDESHOW: result = "slideshow"; break; + case PRIORITY_LOW: result = "low"; break; + case PRIORITY_NORMAL: result = "normal"; break; + case PRIORITY_HIGH: result = "high"; break; + } + + return result; +} + +void LLPluginClassMedia::setPriority(EPriority priority) +{ + if(mPriority != priority) + { + mPriority = priority; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); + + std::string priority_string = priorityToString(priority); + switch(priority) + { + case PRIORITY_UNLOADED: + mSleepTime = 1.0f; + break; + case PRIORITY_STOPPED: + mSleepTime = 1.0f; + break; + case PRIORITY_HIDDEN: + mSleepTime = 1.0f; + break; + case PRIORITY_SLIDESHOW: + mSleepTime = 1.0f; + break; + case PRIORITY_LOW: + mSleepTime = 1.0f / 25.0f; + break; + case PRIORITY_NORMAL: + mSleepTime = 1.0f / 50.0f; + break; + case PRIORITY_HIGH: + mSleepTime = 1.0f / 100.0f; + break; + } + + message.setValue("priority", priority_string); + + sendMessage(message); + + if(mPlugin) + { + mPlugin->setSleepTime(mSleepTime); + } + + LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; + + // This may affect the calculated size, so recalculate it here. + setSizeInternal(); + } +} + +void LLPluginClassMedia::setLowPrioritySizeLimit(int size) +{ + int power = nextPowerOf2(size); + if(mLowPrioritySizeLimit != power) + { + mLowPrioritySizeLimit = power; + + // This may affect the calculated size, so recalculate it here. + setSizeInternal(); + } +} + +F64 LLPluginClassMedia::getCPUUsage() +{ + F64 result = 0.0f; + + if(mPlugin) + { + result = mPlugin->getCPUUsage(); + } + + return result; +} + +void LLPluginClassMedia::sendPickFileResponse(const std::string &file) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response"); + message.setValue("file", file); + if(mPlugin && mPlugin->isBlocked()) + { + // If the plugin sent a blocking pick-file request, the response should unblock it. + message.setValueBoolean("blocking_response", true); + } + sendMessage(message); +} + +void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response"); + message.setValueBoolean("ok", ok); + message.setValue("username", username); + message.setValue("password", password); + if(mPlugin && mPlugin->isBlocked()) + { + // If the plugin sent a blocking pick-file request, the response should unblock it. + message.setValueBoolean("blocking_response", true); + } + sendMessage(message); +} + +void LLPluginClassMedia::cut() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); + sendMessage(message); +} + +void LLPluginClassMedia::copy() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy"); + sendMessage(message); +} + +void LLPluginClassMedia::paste() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste"); + sendMessage(message); +} + +void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path"); + message.setValue("path", user_data_path); + sendMessage(message); +} + +void LLPluginClassMedia::setLanguageCode(const std::string &language_code) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code"); + message.setValue("language", language_code); + sendMessage(message); +} + +void LLPluginClassMedia::setPluginsEnabled(const bool enabled) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled"); + message.setValueBoolean("enable", enabled); + sendMessage(message); +} + +void LLPluginClassMedia::setJavascriptEnabled(const bool enabled) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled"); + message.setValueBoolean("enable", enabled); + sendMessage(message); +} + +void LLPluginClassMedia::setTarget(const std::string &target) +{ + mTarget = target; +} + +/* virtual */ +void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) +{ + std::string message_class = message.getClass(); + + if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + std::string message_name = message.getName(); + if(message_name == "texture_params") + { + mRequestedTextureDepth = message.getValueS32("depth"); + mRequestedTextureInternalFormat = message.getValueU32("internalformat"); + mRequestedTextureFormat = message.getValueU32("format"); + mRequestedTextureType = message.getValueU32("type"); + mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes"); + mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl"); + + // These two are optional, and will default to 0 if they're not specified. + mDefaultMediaWidth = message.getValueS32("default_width"); + mDefaultMediaHeight = message.getValueS32("default_height"); + + mAllowDownsample = message.getValueBoolean("allow_downsample"); + mPadding = message.getValueS32("padding"); + + setSizeInternal(); + + mTextureParamsReceived = true; + } + else if(message_name == "updated") + { + if(message.hasValue("left")) + { + LLRect newDirtyRect; + newDirtyRect.mLeft = message.getValueS32("left"); + newDirtyRect.mTop = message.getValueS32("top"); + newDirtyRect.mRight = message.getValueS32("right"); + newDirtyRect.mBottom = message.getValueS32("bottom"); + + // The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion. + // If they're backwards, swap them. + if(newDirtyRect.mTop < newDirtyRect.mBottom) + { + S32 temp = newDirtyRect.mTop; + newDirtyRect.mTop = newDirtyRect.mBottom; + newDirtyRect.mBottom = temp; + } + + if(mDirtyRect.isEmpty()) + { + mDirtyRect = newDirtyRect; + } + else + { + mDirtyRect.unionWith(newDirtyRect); + } + + LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" + << newDirtyRect.mLeft << ", " + << newDirtyRect.mTop << ", " + << newDirtyRect.mRight << ", " + << newDirtyRect.mBottom << "), new dirty rect is: (" + << mDirtyRect.mLeft << ", " + << mDirtyRect.mTop << ", " + << mDirtyRect.mRight << ", " + << mDirtyRect.mBottom << ")" + << LL_ENDL; + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED); + } + + + bool time_duration_updated = false; + int previous_percent = mProgressPercent; + + if(message.hasValue("current_time")) + { + mCurrentTime = message.getValueReal("current_time"); + time_duration_updated = true; + } + if(message.hasValue("duration")) + { + mDuration = message.getValueReal("duration"); + time_duration_updated = true; + } + + if(message.hasValue("current_rate")) + { + mCurrentRate = message.getValueReal("current_rate"); + } + + if(message.hasValue("loaded_duration")) + { + mLoadedDuration = message.getValueReal("loaded_duration"); + time_duration_updated = true; + } + else + { + // If the message doesn't contain a loaded_duration param, assume it's equal to duration + mLoadedDuration = mDuration; + } + + // Calculate a percentage based on the loaded duration and total duration. + if(mDuration != 0.0f) // Don't divide by zero. + { + mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration); + } + + if(time_duration_updated) + { + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED); + } + + if(previous_percent != mProgressPercent) + { + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); + } + } + else if(message_name == "media_status") + { + std::string status = message.getValue("status"); + + LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL; + + if(status == "loading") + { + mStatus = LLPluginClassMediaOwner::MEDIA_LOADING; + } + else if(status == "loaded") + { + mStatus = LLPluginClassMediaOwner::MEDIA_LOADED; + } + else if(status == "error") + { + mStatus = LLPluginClassMediaOwner::MEDIA_ERROR; + } + else if(status == "playing") + { + mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING; + } + else if(status == "paused") + { + mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED; + } + else if(status == "done") + { + mStatus = LLPluginClassMediaOwner::MEDIA_DONE; + } + else + { + // empty string or any unknown string + mStatus = LLPluginClassMediaOwner::MEDIA_NONE; + } + } + else if(message_name == "size_change_request") + { + S32 width = message.getValueS32("width"); + S32 height = message.getValueS32("height"); + std::string name = message.getValue("name"); + + // TODO: check that name matches? + mNaturalMediaWidth = width; + mNaturalMediaHeight = height; + + setSizeInternal(); + } + else if(message_name == "size_change_response") + { + std::string name = message.getValue("name"); + + // TODO: check that name matches? + + mTextureWidth = message.getValueS32("texture_width"); + mTextureHeight = message.getValueS32("texture_height"); + mMediaWidth = message.getValueS32("width"); + mMediaHeight = message.getValueS32("height"); + + // This invalidates any existing dirty rect. + resetDirty(); + + // TODO: should we verify that the plugin sent back the right values? + // Two size changes in a row may cause them to not match, due to queueing, etc. + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED); + } + else if(message_name == "cursor_changed") + { + mCursorName = message.getValue("name"); + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED); + } + else if(message_name == "edit_state") + { + if(message.hasValue("cut")) + { + mCanCut = message.getValueBoolean("cut"); + } + if(message.hasValue("copy")) + { + mCanCopy = message.getValueBoolean("copy"); + } + if(message.hasValue("paste")) + { + mCanPaste = message.getValueBoolean("paste"); + } + } + else if(message_name == "name_text") + { + mMediaName = message.getValue("name"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED); + } + else if(message_name == "pick_file") + { + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST); + } + else if(message_name == "auth_request") + { + mAuthURL = message.getValue("url"); + mAuthRealm = message.getValue("realm"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST); + } + else + { + LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) + { + std::string message_name = message.getName(); + if(message_name == "navigate_begin") + { + mNavigateURI = message.getValue("uri"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN); + } + else if(message_name == "navigate_complete") + { + mNavigateURI = message.getValue("uri"); + mNavigateResultCode = message.getValueS32("result_code"); + mNavigateResultString = message.getValue("result_string"); + mHistoryBackAvailable = message.getValueBoolean("history_back_available"); + mHistoryForwardAvailable = message.getValueBoolean("history_forward_available"); + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE); + } + else if(message_name == "progress") + { + mProgressPercent = message.getValueS32("percent"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); + } + else if(message_name == "status_text") + { + mStatusText = message.getValue("status"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED); + } + else if(message_name == "location_changed") + { + mLocation = message.getValue("uri"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED); + } + else if(message_name == "click_href") + { + mClickURL = message.getValue("uri"); + mClickTarget = message.getValue("target"); + mClickUUID = message.getValue("uuid"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF); + } + else if(message_name == "click_nofollow") + { + mClickURL = message.getValue("uri"); + mClickNavType = message.getValue("nav_type"); + mClickTarget.clear(); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW); + } + else if(message_name == "navigate_error_page") + { + mStatusCode = message.getValueS32("status_code"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE); + } + else if(message_name == "cookie_set") + { + if(mOwner) + { + mOwner->handleCookieSet(this, message.getValue("cookie")); + } + } + else if(message_name == "close_request") + { + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST); + } + else if(message_name == "geometry_change") + { + mClickUUID = message.getValue("uuid"); + mGeometryX = message.getValueS32("x"); + mGeometryY = message.getValueS32("y"); + mGeometryWidth = message.getValueS32("width"); + mGeometryHeight = message.getValueS32("height"); + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE); + } + else if(message_name == "link_hovered") + { + // text is not currently used -- the tooltip hover text is taken from the "title". + mHoverLink = message.getValue("link"); + mHoverText = message.getValue("title"); + // message.getValue("text"); + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED); + } + else + { + LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + std::string message_name = message.getName(); + + // This class hasn't defined any incoming messages yet. +// if(message_name == "message_name") +// { +// } +// else + { + LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + } + } + +} + +/* virtual */ +void LLPluginClassMedia::pluginLaunchFailed() +{ + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH); +} + +/* virtual */ +void LLPluginClassMedia::pluginDied() +{ + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED); +} + +void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event) +{ + if(mOwner) + { + mOwner->handleMediaEvent(this, event); + } +} + +void LLPluginClassMedia::sendMessage(const LLPluginMessage &message) +{ + if(mPlugin && mPlugin->isRunning()) + { + mPlugin->sendMessage(message); + } + else + { + // The plugin isn't set up yet -- queue this message to be sent after initialization. + mSendQueue.push(message); + } +} + +//////////////////////////////////////////////////////////// +// MARK: media_browser class functions +bool LLPluginClassMedia::pluginSupportsMediaBrowser(void) +{ + std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER); + return !version.empty(); +} + +void LLPluginClassMedia::focus(bool focused) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus"); + + message.setValueBoolean("focused", focused); + + sendMessage(message); +} + +void LLPluginClassMedia::clear_cache() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache"); + sendMessage(message); +} + +void LLPluginClassMedia::clear_cookies() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies"); + sendMessage(message); +} + +void LLPluginClassMedia::set_cookies(const std::string &cookies) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies"); + message.setValue("cookies", cookies); + sendMessage(message); +} + +void LLPluginClassMedia::enable_cookies(bool enable) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies"); + message.setValueBoolean("enable", enable); + sendMessage(message); +} + +void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup"); + + message.setValueBoolean("enable", enable); + message.setValue("host", host); + message.setValueS32("port", port); + + sendMessage(message); +} + +void LLPluginClassMedia::browse_stop() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop"); + sendMessage(message); +} + +void LLPluginClassMedia::browse_reload(bool ignore_cache) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload"); + + message.setValueBoolean("ignore_cache", ignore_cache); + + sendMessage(message); +} + +void LLPluginClassMedia::browse_forward() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward"); + sendMessage(message); +} + +void LLPluginClassMedia::browse_back() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back"); + sendMessage(message); +} + +void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent"); + + message.setValue("user_agent", user_agent); + + sendMessage(message); +} + +void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened"); + + message.setValue("target", target); + message.setValue("uuid", uuid); + + sendMessage(message); +} + +void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed"); + + message.setValue("uuid", uuid); + + sendMessage(message); +} + +void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors"); + message.setValueBoolean("ignore", ignore); + sendMessage(message); +} + +void LLPluginClassMedia::addCertificateFilePath(const std::string& path) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path"); + message.setValue("path", path); + sendMessage(message); +} + +void LLPluginClassMedia::crashPlugin() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); + + sendMessage(message); +} + +void LLPluginClassMedia::hangPlugin() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang"); + + sendMessage(message); +} + + +//////////////////////////////////////////////////////////// +// MARK: media_time class functions +bool LLPluginClassMedia::pluginSupportsMediaTime(void) +{ + std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME); + return !version.empty(); +} + +void LLPluginClassMedia::stop() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop"); + sendMessage(message); +} + +void LLPluginClassMedia::start(float rate) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start"); + + message.setValueReal("rate", rate); + + sendMessage(message); +} + +void LLPluginClassMedia::pause() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause"); + sendMessage(message); +} + +void LLPluginClassMedia::seek(float time) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek"); + + message.setValueReal("time", time); + + sendMessage(message); +} + +void LLPluginClassMedia::setLoop(bool loop) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop"); + + message.setValueBoolean("loop", loop); + + sendMessage(message); +} + +void LLPluginClassMedia::setVolume(float volume) +{ + if(volume != mRequestedVolume) + { + mRequestedVolume = volume; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume"); + + message.setValueReal("volume", volume); + + sendMessage(message); + } +} + +float LLPluginClassMedia::getVolume() +{ + return mRequestedVolume; +} + +void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history) +{ + // Send URL history to plugin + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history"); + message.setValueLLSD("history", url_history); + sendMessage(message); + + LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL; +} + diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index cf8d8b26b9..015fb31252 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -1,416 +1,424 @@ -/** - * @file llpluginclassmedia.h - * @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class. - * - * @cond - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#ifndef LL_LLPLUGINCLASSMEDIA_H -#define LL_LLPLUGINCLASSMEDIA_H - -#include "llgltypes.h" -#include "llpluginprocessparent.h" -#include "llrect.h" -#include "llpluginclassmediaowner.h" -#include -#include "v4color.h" - -class LLPluginClassMedia : public LLPluginProcessParentOwner -{ - LOG_CLASS(LLPluginClassMedia); -public: - LLPluginClassMedia(LLPluginClassMediaOwner *owner); - virtual ~LLPluginClassMedia(); - - // local initialization, called by the media manager when creating a source - virtual bool init(const std::string &launcher_filename, - const std::string &plugin_dir, - const std::string &plugin_filename, - bool debug); - - // undoes everything init() didm called by the media manager when destroying a source - virtual void reset(); - - void idle(void); - - // All of these may return 0 or an actual valid value. - // Callers need to check the return for 0, and not use the values in that case. - int getWidth() const { return (mMediaWidth > 0) ? mMediaWidth : 0; }; - int getHeight() const { return (mMediaHeight > 0) ? mMediaHeight : 0; }; - int getNaturalWidth() const { return mNaturalMediaWidth; }; - int getNaturalHeight() const { return mNaturalMediaHeight; }; - int getSetWidth() const { return mSetMediaWidth; }; - int getSetHeight() const { return mSetMediaHeight; }; - int getBitsWidth() const { return (mTextureWidth > 0) ? mTextureWidth : 0; }; - int getBitsHeight() const { return (mTextureHeight > 0) ? mTextureHeight : 0; }; - int getTextureWidth() const; - int getTextureHeight() const; - int getFullWidth() const { return mFullMediaWidth; }; - int getFullHeight() const { return mFullMediaHeight; }; - - // This may return NULL. Callers need to check for and handle this case. - unsigned char* getBitsData(); - - // gets the format details of the texture data - // These may return 0 if they haven't been set up yet. The caller needs to detect this case. - int getTextureDepth() const { return mRequestedTextureDepth; }; - int getTextureFormatInternal() const { return mRequestedTextureInternalFormat; }; - int getTextureFormatPrimary() const { return mRequestedTextureFormat; }; - int getTextureFormatType() const { return mRequestedTextureType; }; - bool getTextureFormatSwapBytes() const { return mRequestedTextureSwapBytes; }; - bool getTextureCoordsOpenGL() const { return mRequestedTextureCoordsOpenGL; }; - - void setSize(int width, int height); - void setAutoScale(bool auto_scale); - - void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; }; - - void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; }; - - // Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent. - // This will initially be false, and will also be false for some time after setSize while the resize is processed. - // Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values - // until you call idle() again. - bool textureValid(void); - - bool getDirty(LLRect *dirty_rect = NULL); - void resetDirty(void); - - typedef enum - { - MOUSE_EVENT_DOWN, - MOUSE_EVENT_UP, - MOUSE_EVENT_MOVE, - MOUSE_EVENT_DOUBLE_CLICK - }EMouseEventType; - - void mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers); - - typedef enum - { - KEY_EVENT_DOWN, - KEY_EVENT_UP, - KEY_EVENT_REPEAT - }EKeyEventType; - - bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); - - void scrollEvent(int x, int y, MASK modifiers); - - // Text may be unicode (utf8 encoded) - bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data); - - void loadURI(const std::string &uri); - - // "Loading" means uninitialized or any state prior to fully running (processing commands) - bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; }; - - // "Running" means the steady state -- i.e. processing messages - bool isPluginRunning(void) { return mPlugin?mPlugin->isRunning():false; }; - - // "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally) - bool isPluginExited(void) { return mPlugin?mPlugin->isDone():false; }; - - std::string getPluginVersion() { return mPlugin?mPlugin->getPluginVersion():std::string(""); }; - - bool getDisableTimeout() { return mPlugin?mPlugin->getDisableTimeout():false; }; - void setDisableTimeout(bool disable) { if(mPlugin) mPlugin->setDisableTimeout(disable); }; - - // Inherited from LLPluginProcessParentOwner - /* virtual */ void receivePluginMessage(const LLPluginMessage &message); - /* virtual */ void pluginLaunchFailed(); - /* virtual */ void pluginDied(); - - - typedef enum - { - PRIORITY_UNLOADED, // media plugin isn't even loaded. - PRIORITY_STOPPED, // media is not playing, shouldn't need to update at all. - PRIORITY_HIDDEN, // media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc. - PRIORITY_SLIDESHOW, // media is in the far distance, updates very infrequently - PRIORITY_LOW, // media is in the distance, may be rendered at reduced size - PRIORITY_NORMAL, // normal (default) priority - PRIORITY_HIGH // media has user focus and/or is taking up most of the screen - }EPriority; - - static const char* priorityToString(EPriority priority); - void setPriority(EPriority priority); - void setLowPrioritySizeLimit(int size); - - F64 getCPUUsage(); - - void sendPickFileResponse(const std::string &file); - - void sendAuthResponse(bool ok, const std::string &username, const std::string &password); - - // Valid after a MEDIA_EVENT_CURSOR_CHANGED event - std::string getCursorName() const { return mCursorName; }; - - LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; } - - void cut(); - bool canCut() const { return mCanCut; }; - - void copy(); - bool canCopy() const { return mCanCopy; }; - - void paste(); - bool canPaste() const { return mCanPaste; }; - - // These can be called before init(), and they will be queued and sent before the media init message. - void setUserDataPath(const std::string &user_data_path); - void setLanguageCode(const std::string &language_code); - void setPluginsEnabled(const bool enabled); - void setJavascriptEnabled(const bool enabled); - void setTarget(const std::string &target); - - /////////////////////////////////// - // media browser class functions - bool pluginSupportsMediaBrowser(void); - - void focus(bool focused); - void clear_cache(); - void clear_cookies(); - void set_cookies(const std::string &cookies); - void enable_cookies(bool enable); - void proxy_setup(bool enable, const std::string &host = LLStringUtil::null, int port = 0); - void browse_stop(); - void browse_reload(bool ignore_cache = false); - void browse_forward(); - void browse_back(); - void setBrowserUserAgent(const std::string& user_agent); - void proxyWindowOpened(const std::string &target, const std::string &uuid); - void proxyWindowClosed(const std::string &uuid); - void ignore_ssl_cert_errors(bool ignore); - void addCertificateFilePath(const std::string& path); - - // This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE - std::string getNavigateURI() const { return mNavigateURI; }; - - // These are valid after MEDIA_EVENT_NAVIGATE_COMPLETE - S32 getNavigateResultCode() const { return mNavigateResultCode; }; - std::string getNavigateResultString() const { return mNavigateResultString; }; - bool getHistoryBackAvailable() const { return mHistoryBackAvailable; }; - bool getHistoryForwardAvailable() const { return mHistoryForwardAvailable; }; - - // This is valid after MEDIA_EVENT_PROGRESS_UPDATED - int getProgressPercent() const { return mProgressPercent; }; - - // This is valid after MEDIA_EVENT_STATUS_TEXT_CHANGED - std::string getStatusText() const { return mStatusText; }; - - // This is valid after MEDIA_EVENT_LOCATION_CHANGED - std::string getLocation() const { return mLocation; }; - - // This is valid after MEDIA_EVENT_CLICK_LINK_HREF or MEDIA_EVENT_CLICK_LINK_NOFOLLOW - std::string getClickURL() const { return mClickURL; }; - - // This is valid after MEDIA_EVENT_CLICK_LINK_NOFOLLOW - std::string getClickNavType() const { return mClickNavType; }; - - // This is valid after MEDIA_EVENT_CLICK_LINK_HREF - std::string getClickTarget() const { return mClickTarget; }; - - // This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE - std::string getClickUUID() const { return mClickUUID; }; - - // This is valid after MEDIA_EVENT_NAVIGATE_ERROR_PAGE - S32 getStatusCode() const { return mStatusCode; }; - - // These are valid during MEDIA_EVENT_GEOMETRY_CHANGE - S32 getGeometryX() const { return mGeometryX; }; - S32 getGeometryY() const { return mGeometryY; }; - S32 getGeometryWidth() const { return mGeometryWidth; }; - S32 getGeometryHeight() const { return mGeometryHeight; }; - - // These are valid during MEDIA_EVENT_AUTH_REQUEST - std::string getAuthURL() const { return mAuthURL; }; - std::string getAuthRealm() const { return mAuthRealm; }; - - // These are valid during MEDIA_EVENT_LINK_HOVERED - std::string getHoverText() const { return mHoverText; }; - std::string getHoverLink() const { return mHoverLink; }; - - std::string getMediaName() const { return mMediaName; }; - std::string getMediaDescription() const { return mMediaDescription; }; - - // Crash the plugin. If you use this outside of a testbed, you will be punished. - void crashPlugin(); - - // Hang the plugin. If you use this outside of a testbed, you will be punished. - void hangPlugin(); - - /////////////////////////////////// - // media time class functions - bool pluginSupportsMediaTime(void); - void stop(); - void start(float rate = 0.0f); - void pause(); - void seek(float time); - void setLoop(bool loop); - void setVolume(float volume); - float getVolume(); - - F64 getCurrentTime(void) const { return mCurrentTime; }; - F64 getDuration(void) const { return mDuration; }; - F64 getCurrentPlayRate(void) { return mCurrentRate; }; - F64 getLoadedDuration(void) const { return mLoadedDuration; }; - - // Initialize the URL history of the plugin by sending - // "init_history" message - void initializeUrlHistory(const LLSD& url_history); - -protected: - - LLPluginClassMediaOwner *mOwner; - - // Notify this object's owner that an event has occurred. - void mediaEvent(LLPluginClassMediaOwner::EMediaEvent event); - - void sendMessage(const LLPluginMessage &message); // Send message internally, either queueing or sending directly. - std::queue mSendQueue; // Used to queue messages while the plugin initializes. - - void setSizeInternal(void); - - bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true - S32 mRequestedTextureDepth; - LLGLenum mRequestedTextureInternalFormat; - LLGLenum mRequestedTextureFormat; - LLGLenum mRequestedTextureType; - bool mRequestedTextureSwapBytes; - bool mRequestedTextureCoordsOpenGL; - - std::string mTextureSharedMemoryName; - size_t mTextureSharedMemorySize; - - // True to scale requested media up to the full size of the texture (i.e. next power of two) - bool mAutoScaleMedia; - - // default media size for the plugin, from the texture_params message. - int mDefaultMediaWidth; - int mDefaultMediaHeight; - - // Size that has been requested by the plugin itself - int mNaturalMediaWidth; - int mNaturalMediaHeight; - - // Size that has been requested with setSize() - int mSetMediaWidth; - int mSetMediaHeight; - - // Full calculated media size (before auto-scale and downsample calculations) - int mFullMediaWidth; - int mFullMediaHeight; - - // Actual media size being set (after auto-scale) - int mRequestedMediaWidth; - int mRequestedMediaHeight; - - // Texture size calculated from actual media size - int mRequestedTextureWidth; - int mRequestedTextureHeight; - - // Size that the plugin has acknowledged - int mTextureWidth; - int mTextureHeight; - int mMediaWidth; - int mMediaHeight; - - float mRequestedVolume; - - // Priority of this media stream - EPriority mPriority; - int mLowPrioritySizeLimit; - - bool mAllowDownsample; - int mPadding; - - - LLPluginProcessParent *mPlugin; - - LLRect mDirtyRect; - - std::string translateModifiers(MASK modifiers); - - std::string mCursorName; - int mLastMouseX; - int mLastMouseY; - - LLPluginClassMediaOwner::EMediaStatus mStatus; - - F64 mSleepTime; - - bool mCanCut; - bool mCanCopy; - bool mCanPaste; - - std::string mMediaName; - std::string mMediaDescription; - - LLColor4 mBackgroundColor; - - std::string mTarget; - - ///////////////////////////////////////// - // media_browser class - std::string mNavigateURI; - S32 mNavigateResultCode; - std::string mNavigateResultString; - bool mHistoryBackAvailable; - bool mHistoryForwardAvailable; - std::string mStatusText; - int mProgressPercent; - std::string mLocation; - std::string mClickURL; - std::string mClickNavType; - std::string mClickTarget; - std::string mClickUUID; - S32 mGeometryX; - S32 mGeometryY; - S32 mGeometryWidth; - S32 mGeometryHeight; - S32 mStatusCode; - std::string mAuthURL; - std::string mAuthRealm; - std::string mHoverText; - std::string mHoverLink; - - ///////////////////////////////////////// - // media_time class - F64 mCurrentTime; - F64 mDuration; - F64 mCurrentRate; - F64 mLoadedDuration; - -//-------------------------------------- - //debug use only - // -private: - bool mDeleteOK ; -public: - void setDeleteOK(bool flag) { mDeleteOK = flag ;} -//-------------------------------------- -}; - -#endif // LL_LLPLUGINCLASSMEDIA_H +/** + * @file llpluginclassmedia.h + * @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * @endcond + */ + +#ifndef LL_LLPLUGINCLASSMEDIA_H +#define LL_LLPLUGINCLASSMEDIA_H + +#include "llgltypes.h" +#include "llpluginprocessparent.h" +#include "llrect.h" +#include "llpluginclassmediaowner.h" +#include +#include "v4color.h" + +class LLPluginClassMedia : public LLPluginProcessParentOwner +{ + LOG_CLASS(LLPluginClassMedia); +public: + LLPluginClassMedia(LLPluginClassMediaOwner *owner); + virtual ~LLPluginClassMedia(); + + // local initialization, called by the media manager when creating a source + virtual bool init(const std::string &launcher_filename, + const std::string &plugin_dir, + const std::string &plugin_filename, + bool debug); + + // undoes everything init() didm called by the media manager when destroying a source + virtual void reset(); + + void idle(void); + + // All of these may return 0 or an actual valid value. + // Callers need to check the return for 0, and not use the values in that case. + int getWidth() const { return (mMediaWidth > 0) ? mMediaWidth : 0; }; + int getHeight() const { return (mMediaHeight > 0) ? mMediaHeight : 0; }; + int getNaturalWidth() const { return mNaturalMediaWidth; }; + int getNaturalHeight() const { return mNaturalMediaHeight; }; + int getSetWidth() const { return mSetMediaWidth; }; + int getSetHeight() const { return mSetMediaHeight; }; + int getBitsWidth() const { return (mTextureWidth > 0) ? mTextureWidth : 0; }; + int getBitsHeight() const { return (mTextureHeight > 0) ? mTextureHeight : 0; }; + int getTextureWidth() const; + int getTextureHeight() const; + int getFullWidth() const { return mFullMediaWidth; }; + int getFullHeight() const { return mFullMediaHeight; }; + + // This may return NULL. Callers need to check for and handle this case. + unsigned char* getBitsData(); + + // gets the format details of the texture data + // These may return 0 if they haven't been set up yet. The caller needs to detect this case. + int getTextureDepth() const { return mRequestedTextureDepth; }; + int getTextureFormatInternal() const { return mRequestedTextureInternalFormat; }; + int getTextureFormatPrimary() const { return mRequestedTextureFormat; }; + int getTextureFormatType() const { return mRequestedTextureType; }; + bool getTextureFormatSwapBytes() const { return mRequestedTextureSwapBytes; }; + bool getTextureCoordsOpenGL() const { return mRequestedTextureCoordsOpenGL; }; + + void setSize(int width, int height); + void setAutoScale(bool auto_scale); + + void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; }; + + void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; }; + + // Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent. + // This will initially be false, and will also be false for some time after setSize while the resize is processed. + // Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values + // until you call idle() again. + bool textureValid(void); + + bool getDirty(LLRect *dirty_rect = NULL); + void resetDirty(void); + + typedef enum + { + MOUSE_EVENT_DOWN, + MOUSE_EVENT_UP, + MOUSE_EVENT_MOVE, + MOUSE_EVENT_DOUBLE_CLICK + }EMouseEventType; + + void mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers); + + typedef enum + { + KEY_EVENT_DOWN, + KEY_EVENT_UP, + KEY_EVENT_REPEAT + }EKeyEventType; + + bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); + + void scrollEvent(int x, int y, MASK modifiers); + + // Javascript <-> viewer events + void jsExposeObjectEvent( bool expose ); + void jsValuesValidEvent( bool valid ); + void jsAgentLocationEvent( double x, double y, double z ); + void jsAgentLanguageEvent( const std::string& language ); + void jsAgentRegionEvent( const std::string& region_name ); + void jsAgentMaturityEvent( const std::string& maturity ); + + // Text may be unicode (utf8 encoded) + bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data); + + void loadURI(const std::string &uri); + + // "Loading" means uninitialized or any state prior to fully running (processing commands) + bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; }; + + // "Running" means the steady state -- i.e. processing messages + bool isPluginRunning(void) { return mPlugin?mPlugin->isRunning():false; }; + + // "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally) + bool isPluginExited(void) { return mPlugin?mPlugin->isDone():false; }; + + std::string getPluginVersion() { return mPlugin?mPlugin->getPluginVersion():std::string(""); }; + + bool getDisableTimeout() { return mPlugin?mPlugin->getDisableTimeout():false; }; + void setDisableTimeout(bool disable) { if(mPlugin) mPlugin->setDisableTimeout(disable); }; + + // Inherited from LLPluginProcessParentOwner + /* virtual */ void receivePluginMessage(const LLPluginMessage &message); + /* virtual */ void pluginLaunchFailed(); + /* virtual */ void pluginDied(); + + + typedef enum + { + PRIORITY_UNLOADED, // media plugin isn't even loaded. + PRIORITY_STOPPED, // media is not playing, shouldn't need to update at all. + PRIORITY_HIDDEN, // media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc. + PRIORITY_SLIDESHOW, // media is in the far distance, updates very infrequently + PRIORITY_LOW, // media is in the distance, may be rendered at reduced size + PRIORITY_NORMAL, // normal (default) priority + PRIORITY_HIGH // media has user focus and/or is taking up most of the screen + }EPriority; + + static const char* priorityToString(EPriority priority); + void setPriority(EPriority priority); + void setLowPrioritySizeLimit(int size); + + F64 getCPUUsage(); + + void sendPickFileResponse(const std::string &file); + + void sendAuthResponse(bool ok, const std::string &username, const std::string &password); + + // Valid after a MEDIA_EVENT_CURSOR_CHANGED event + std::string getCursorName() const { return mCursorName; }; + + LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; } + + void cut(); + bool canCut() const { return mCanCut; }; + + void copy(); + bool canCopy() const { return mCanCopy; }; + + void paste(); + bool canPaste() const { return mCanPaste; }; + + // These can be called before init(), and they will be queued and sent before the media init message. + void setUserDataPath(const std::string &user_data_path); + void setLanguageCode(const std::string &language_code); + void setPluginsEnabled(const bool enabled); + void setJavascriptEnabled(const bool enabled); + void setTarget(const std::string &target); + + /////////////////////////////////// + // media browser class functions + bool pluginSupportsMediaBrowser(void); + + void focus(bool focused); + void clear_cache(); + void clear_cookies(); + void set_cookies(const std::string &cookies); + void enable_cookies(bool enable); + void proxy_setup(bool enable, const std::string &host = LLStringUtil::null, int port = 0); + void browse_stop(); + void browse_reload(bool ignore_cache = false); + void browse_forward(); + void browse_back(); + void setBrowserUserAgent(const std::string& user_agent); + void proxyWindowOpened(const std::string &target, const std::string &uuid); + void proxyWindowClosed(const std::string &uuid); + void ignore_ssl_cert_errors(bool ignore); + void addCertificateFilePath(const std::string& path); + + // This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE + std::string getNavigateURI() const { return mNavigateURI; }; + + // These are valid after MEDIA_EVENT_NAVIGATE_COMPLETE + S32 getNavigateResultCode() const { return mNavigateResultCode; }; + std::string getNavigateResultString() const { return mNavigateResultString; }; + bool getHistoryBackAvailable() const { return mHistoryBackAvailable; }; + bool getHistoryForwardAvailable() const { return mHistoryForwardAvailable; }; + + // This is valid after MEDIA_EVENT_PROGRESS_UPDATED + int getProgressPercent() const { return mProgressPercent; }; + + // This is valid after MEDIA_EVENT_STATUS_TEXT_CHANGED + std::string getStatusText() const { return mStatusText; }; + + // This is valid after MEDIA_EVENT_LOCATION_CHANGED + std::string getLocation() const { return mLocation; }; + + // This is valid after MEDIA_EVENT_CLICK_LINK_HREF or MEDIA_EVENT_CLICK_LINK_NOFOLLOW + std::string getClickURL() const { return mClickURL; }; + + // This is valid after MEDIA_EVENT_CLICK_LINK_NOFOLLOW + std::string getClickNavType() const { return mClickNavType; }; + + // This is valid after MEDIA_EVENT_CLICK_LINK_HREF + std::string getClickTarget() const { return mClickTarget; }; + + // This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE + std::string getClickUUID() const { return mClickUUID; }; + + // This is valid after MEDIA_EVENT_NAVIGATE_ERROR_PAGE + S32 getStatusCode() const { return mStatusCode; }; + + // These are valid during MEDIA_EVENT_GEOMETRY_CHANGE + S32 getGeometryX() const { return mGeometryX; }; + S32 getGeometryY() const { return mGeometryY; }; + S32 getGeometryWidth() const { return mGeometryWidth; }; + S32 getGeometryHeight() const { return mGeometryHeight; }; + + // These are valid during MEDIA_EVENT_AUTH_REQUEST + std::string getAuthURL() const { return mAuthURL; }; + std::string getAuthRealm() const { return mAuthRealm; }; + + // These are valid during MEDIA_EVENT_LINK_HOVERED + std::string getHoverText() const { return mHoverText; }; + std::string getHoverLink() const { return mHoverLink; }; + + std::string getMediaName() const { return mMediaName; }; + std::string getMediaDescription() const { return mMediaDescription; }; + + // Crash the plugin. If you use this outside of a testbed, you will be punished. + void crashPlugin(); + + // Hang the plugin. If you use this outside of a testbed, you will be punished. + void hangPlugin(); + + /////////////////////////////////// + // media time class functions + bool pluginSupportsMediaTime(void); + void stop(); + void start(float rate = 0.0f); + void pause(); + void seek(float time); + void setLoop(bool loop); + void setVolume(float volume); + float getVolume(); + + F64 getCurrentTime(void) const { return mCurrentTime; }; + F64 getDuration(void) const { return mDuration; }; + F64 getCurrentPlayRate(void) { return mCurrentRate; }; + F64 getLoadedDuration(void) const { return mLoadedDuration; }; + + // Initialize the URL history of the plugin by sending + // "init_history" message + void initializeUrlHistory(const LLSD& url_history); + +protected: + + LLPluginClassMediaOwner *mOwner; + + // Notify this object's owner that an event has occurred. + void mediaEvent(LLPluginClassMediaOwner::EMediaEvent event); + + void sendMessage(const LLPluginMessage &message); // Send message internally, either queueing or sending directly. + std::queue mSendQueue; // Used to queue messages while the plugin initializes. + + void setSizeInternal(void); + + bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true + S32 mRequestedTextureDepth; + LLGLenum mRequestedTextureInternalFormat; + LLGLenum mRequestedTextureFormat; + LLGLenum mRequestedTextureType; + bool mRequestedTextureSwapBytes; + bool mRequestedTextureCoordsOpenGL; + + std::string mTextureSharedMemoryName; + size_t mTextureSharedMemorySize; + + // True to scale requested media up to the full size of the texture (i.e. next power of two) + bool mAutoScaleMedia; + + // default media size for the plugin, from the texture_params message. + int mDefaultMediaWidth; + int mDefaultMediaHeight; + + // Size that has been requested by the plugin itself + int mNaturalMediaWidth; + int mNaturalMediaHeight; + + // Size that has been requested with setSize() + int mSetMediaWidth; + int mSetMediaHeight; + + // Full calculated media size (before auto-scale and downsample calculations) + int mFullMediaWidth; + int mFullMediaHeight; + + // Actual media size being set (after auto-scale) + int mRequestedMediaWidth; + int mRequestedMediaHeight; + + // Texture size calculated from actual media size + int mRequestedTextureWidth; + int mRequestedTextureHeight; + + // Size that the plugin has acknowledged + int mTextureWidth; + int mTextureHeight; + int mMediaWidth; + int mMediaHeight; + + float mRequestedVolume; + + // Priority of this media stream + EPriority mPriority; + int mLowPrioritySizeLimit; + + bool mAllowDownsample; + int mPadding; + + + LLPluginProcessParent *mPlugin; + + LLRect mDirtyRect; + + std::string translateModifiers(MASK modifiers); + + std::string mCursorName; + int mLastMouseX; + int mLastMouseY; + + LLPluginClassMediaOwner::EMediaStatus mStatus; + + F64 mSleepTime; + + bool mCanCut; + bool mCanCopy; + bool mCanPaste; + + std::string mMediaName; + std::string mMediaDescription; + + LLColor4 mBackgroundColor; + + std::string mTarget; + + ///////////////////////////////////////// + // media_browser class + std::string mNavigateURI; + S32 mNavigateResultCode; + std::string mNavigateResultString; + bool mHistoryBackAvailable; + bool mHistoryForwardAvailable; + std::string mStatusText; + int mProgressPercent; + std::string mLocation; + std::string mClickURL; + std::string mClickNavType; + std::string mClickTarget; + std::string mClickUUID; + S32 mGeometryX; + S32 mGeometryY; + S32 mGeometryWidth; + S32 mGeometryHeight; + S32 mStatusCode; + std::string mAuthURL; + std::string mAuthRealm; + std::string mHoverText; + std::string mHoverLink; + + ///////////////////////////////////////// + // media_time class + F64 mCurrentTime; + F64 mDuration; + F64 mCurrentRate; + F64 mLoadedDuration; + +//-------------------------------------- + //debug use only + // +private: + bool mDeleteOK ; +public: + void setDeleteOK(bool flag) { mDeleteOK = flag ;} +//-------------------------------------- +}; + +#endif // LL_LLPLUGINCLASSMEDIA_H diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index 9ba8edbb59..b22dbc6604 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -1168,6 +1168,56 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) authResponse(message_in); } else + if(message_name == "js_expose_object") + { + bool expose_object = message_in.getValueBoolean( "expose" ); +#if LLQTWEBKIT_API_VERSION >= 9 + LLQtWebKit::getInstance()->setExposeObject( expose_object ); +#endif + } + else + if(message_name == "js_values_valid") + { + bool valid = message_in.getValueBoolean( "valid" ); +#if LLQTWEBKIT_API_VERSION >= 9 + LLQtWebKit::getInstance()->setValuesValid( valid ); +#endif + } + else + if(message_name == "js_agent_location") + { + F32 x = message_in.getValueReal("x"); + F32 y = message_in.getValueReal("y"); + F32 z = message_in.getValueReal("z"); +#if LLQTWEBKIT_API_VERSION >= 9 + LLQtWebKit::getInstance()->setAgentLocation( x, y, z ); +#endif + } + else + if(message_name == "js_agent_language") + { + const std::string& language = message_in.getValue("language"); +#if LLQTWEBKIT_API_VERSION >= 9 + LLQtWebKit::getInstance()->setAgentLanguage( language ); +#endif + } + else + if(message_name == "js_agent_region") + { + const std::string& region = message_in.getValue("region"); +#if LLQTWEBKIT_API_VERSION >= 9 + LLQtWebKit::getInstance()->setAgentRegion( region ); +#endif + } + else + if(message_name == "js_agent_maturity") + { + const std::string& maturity = message_in.getValue("maturity"); +#if LLQTWEBKIT_API_VERSION >= 9 + LLQtWebKit::getInstance()->setAgentMaturity( maturity ); +#endif + } + else { // std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl; } @@ -1324,4 +1374,3 @@ int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void return 0; } - diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e6c2dc4413..8ecfccf727 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -708,6 +708,17 @@ Value 0 + BrowserEnableJSObject + + Comment + Enable or disable the viewer to Javascript bridge object. + Persist + 1 + Type + Boolean + Value + 0 + BlockAvatarAppearanceMessages Comment diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 037e22584f..62ae7ac6e2 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1,3692 +1,3742 @@ -/** - * @file llviewermedia.cpp - * @brief Client interface to the media engine - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llagent.h" -#include "llagentcamera.h" -#include "llviewermedia.h" -#include "llviewermediafocus.h" -#include "llmimetypes.h" -#include "llmediaentry.h" -#include "llversioninfo.h" -#include "llviewercontrol.h" -#include "llviewertexture.h" -#include "llviewerparcelmedia.h" -#include "llviewerparcelmgr.h" -#include "llviewertexturelist.h" -#include "llvovolume.h" -#include "llpluginclassmedia.h" -#include "llplugincookiestore.h" -#include "llviewerwindow.h" -#include "llfocusmgr.h" -#include "llcallbacklist.h" -#include "llparcel.h" -#include "llaudioengine.h" // for gAudiop -#include "llurldispatcher.h" -#include "llvoavatar.h" -#include "llvoavatarself.h" -#include "llviewerregion.h" -#include "llwebsharing.h" // For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this! -#include "llfilepicker.h" -#include "llnotifications.h" -#include "lldir.h" -#include "llevent.h" // LLSimpleListener -#include "llnotificationsutil.h" -#include "lluuid.h" -#include "llkeyboard.h" -#include "llmutelist.h" -#include "llpanelprofile.h" -#include "llappviewer.h" -//#include "llfirstuse.h" -#include "llwindow.h" - -#include "llfloatermediabrowser.h" // for handling window close requests and geometry change requests in media browser windows. -#include "llfloaterwebcontent.h" // for handling window close requests and geometry change requests in media browser windows. - -#include // for SkinFolder listener -#include - -/*static*/ const char* LLViewerMedia::AUTO_PLAY_MEDIA_SETTING = "ParcelMediaAutoPlayEnable"; -/*static*/ const char* LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING = "MediaShowOnOthers"; -/*static*/ const char* LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING = "MediaShowWithinParcel"; -/*static*/ const char* LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING = "MediaShowOutsideParcel"; - - -// Move this to its own file. - -LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter() -{ - observerListType::iterator iter = mObservers.begin(); - - while( iter != mObservers.end() ) - { - LLViewerMediaObserver *self = *iter; - iter++; - remObserver(self); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaEventEmitter::addObserver( LLViewerMediaObserver* observer ) -{ - if ( ! observer ) - return false; - - if ( std::find( mObservers.begin(), mObservers.end(), observer ) != mObservers.end() ) - return false; - - mObservers.push_back( observer ); - observer->mEmitters.push_back( this ); - - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer ) -{ - if ( ! observer ) - return false; - - mObservers.remove( observer ); - observer->mEmitters.remove(this); - - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLViewerMediaObserver::EMediaEvent event ) -{ - // Broadcast the event to any observers. - observerListType::iterator iter = mObservers.begin(); - while( iter != mObservers.end() ) - { - LLViewerMediaObserver *self = *iter; - ++iter; - self->handleMediaEvent( media, event ); - } -} - -// Move this to its own file. -LLViewerMediaObserver::~LLViewerMediaObserver() -{ - std::list::iterator iter = mEmitters.begin(); - - while( iter != mEmitters.end() ) - { - LLViewerMediaEventEmitter *self = *iter; - iter++; - self->remObserver( this ); - } -} - - -// Move this to its own file. -// helper class that tries to download a URL from a web site and calls a method -// on the Panel Land Media and to discover the MIME type -class LLMimeDiscoveryResponder : public LLHTTPClient::Responder -{ -LOG_CLASS(LLMimeDiscoveryResponder); -public: - LLMimeDiscoveryResponder( viewer_media_t media_impl) - : mMediaImpl(media_impl), - mInitialized(false) - { - if(mMediaImpl->mMimeTypeProbe != NULL) - { - llerrs << "impl already has an outstanding responder" << llendl; - } - - mMediaImpl->mMimeTypeProbe = this; - } - - ~LLMimeDiscoveryResponder() - { - disconnectOwner(); - } - - virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - std::string media_type = content["content-type"].asString(); - std::string::size_type idx1 = media_type.find_first_of(";"); - std::string mime_type = media_type.substr(0, idx1); - - lldebugs << "status is " << status << ", media type \"" << media_type << "\"" << llendl; - - // 2xx status codes indicate success. - // Most 4xx status codes are successful enough for our purposes. - // 499 is the error code for host not found, timeout, etc. - // 500 means "Internal Server error" but we decided it's okay to - // accept this and go past it in the MIME type probe - // 302 means the resource can be found temporarily in a different place - added this for join.secondlife.com - // 499 is a code specifc to join.secondlife.com (????) apparently safe to ignore -// if( ((status >= 200) && (status < 300)) || -// ((status >= 400) && (status < 499)) || -// (status == 500) || -// (status == 302) || -// (status == 499) -// ) - // We now no longer check the error code returned from the probe. - // If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting. - if(1) - { - // The probe was successful. - if(mime_type.empty()) - { - // Some sites don't return any content-type header at all. - // Treat an empty mime type as text/html. - mime_type = "text/html"; - } - - completeAny(status, mime_type); - } - else - { - llwarns << "responder failed with status " << status << ", reason " << reason << llendl; - - if(mMediaImpl) - { - mMediaImpl->mMediaSourceFailed = true; - } - } - - } - - void completeAny(U32 status, const std::string& mime_type) - { - // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl. - // Make a local copy so we can call loadURI() afterwards. - LLViewerMediaImpl *impl = mMediaImpl; - - if(impl && !mInitialized && ! mime_type.empty()) - { - if(impl->initializeMedia(mime_type)) - { - mInitialized = true; - impl->loadURI(); - disconnectOwner(); - } - } - } - - void cancelRequest() - { - disconnectOwner(); - } - -private: - void disconnectOwner() - { - if(mMediaImpl) - { - if(mMediaImpl->mMimeTypeProbe != this) - { - llerrs << "internal error: mMediaImpl->mMimeTypeProbe != this" << llendl; - } - - mMediaImpl->mMimeTypeProbe = NULL; - } - mMediaImpl = NULL; - } - - -public: - LLViewerMediaImpl *mMediaImpl; - bool mInitialized; -}; - -class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder -{ -LOG_CLASS(LLViewerMediaOpenIDResponder); -public: - LLViewerMediaOpenIDResponder( ) - { - } - - ~LLViewerMediaOpenIDResponder() - { - } - - /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; - LL_DEBUGS("MediaAuth") << content << LL_ENDL; - std::string cookie = content["set-cookie"].asString(); - - LLViewerMedia::openIDCookieResponse(cookie); - } - - /* virtual */ void completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - // This is just here to disable the default behavior (attempting to parse the response as llsd). - // We don't care about the content of the response, only the set-cookie header. - } - -}; - -class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder -{ -LOG_CLASS(LLViewerMediaWebProfileResponder); -public: - LLViewerMediaWebProfileResponder(std::string host) - { - mHost = host; - } - - ~LLViewerMediaWebProfileResponder() - { - } - - /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; - LL_WARNS("MediaAuth") << content << LL_ENDL; - - std::string cookie = content["set-cookie"].asString(); - - LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost); - } - - void completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - // This is just here to disable the default behavior (attempting to parse the response as llsd). - // We don't care about the content of the response, only the set-cookie header. - } - - std::string mHost; -}; - - -LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL; -LLURL LLViewerMedia::sOpenIDURL; -std::string LLViewerMedia::sOpenIDCookie; -LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL; -static LLViewerMedia::impl_list sViewerMediaImplList; -static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap; -static LLTimer sMediaCreateTimer; -static const F32 LLVIEWERMEDIA_CREATE_DELAY = 1.0f; -static F32 sGlobalVolume = 1.0f; -static F64 sLowestLoadableImplInterest = 0.0f; -static bool sAnyMediaShowing = false; -static boost::signals2::connection sTeleportFinishConnection; -static std::string sUpdatedCookies; -static const char *PLUGIN_COOKIE_FILE_NAME = "plugin_cookies.txt"; - -////////////////////////////////////////////////////////////////////////////////////////// -static void add_media_impl(LLViewerMediaImpl* media) -{ - sViewerMediaImplList.push_back(media); -} - -////////////////////////////////////////////////////////////////////////////////////////// -static void remove_media_impl(LLViewerMediaImpl* media) -{ - LLViewerMedia::impl_list::iterator iter = sViewerMediaImplList.begin(); - LLViewerMedia::impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end; iter++) - { - if(media == *iter) - { - sViewerMediaImplList.erase(iter); - return; - } - } -} - -class LLViewerMediaMuteListObserver : public LLMuteListObserver -{ - /* virtual */ void onChange() { LLViewerMedia::muteListChanged();} -}; - -static LLViewerMediaMuteListObserver sViewerMediaMuteListObserver; -static bool sViewerMediaMuteListObserverInitialized = false; -static bool sInWorldMediaDisabled = false; - - -////////////////////////////////////////////////////////////////////////////////////////// -// LLViewerMedia - -////////////////////////////////////////////////////////////////////////////////////////// -// static -viewer_media_t LLViewerMedia::newMediaImpl( - const LLUUID& texture_id, - S32 media_width, - S32 media_height, - U8 media_auto_scale, - U8 media_loop) -{ - LLViewerMediaImpl* media_impl = getMediaImplFromTextureID(texture_id); - if(media_impl == NULL || texture_id.isNull()) - { - // Create the media impl - media_impl = new LLViewerMediaImpl(texture_id, media_width, media_height, media_auto_scale, media_loop); - } - else - { - media_impl->unload(); - media_impl->setTextureID(texture_id); - media_impl->mMediaWidth = media_width; - media_impl->mMediaHeight = media_height; - media_impl->mMediaAutoScale = media_auto_scale; - media_impl->mMediaLoop = media_loop; - } - - return media_impl; -} - -viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self) -{ - // Try to find media with the same media ID - viewer_media_t media_impl = getMediaImplFromTextureID(media_entry->getMediaID()); - - lldebugs << "called, current URL is \"" << media_entry->getCurrentURL() - << "\", previous URL is \"" << previous_url - << "\", update_from_self is " << (update_from_self?"true":"false") - << llendl; - - bool was_loaded = false; - bool needs_navigate = false; - - if(media_impl) - { - was_loaded = media_impl->hasMedia(); - - media_impl->setHomeURL(media_entry->getHomeURL()); - - media_impl->mMediaAutoScale = media_entry->getAutoScale(); - media_impl->mMediaLoop = media_entry->getAutoLoop(); - media_impl->mMediaWidth = media_entry->getWidthPixels(); - media_impl->mMediaHeight = media_entry->getHeightPixels(); - media_impl->mMediaAutoPlay = media_entry->getAutoPlay(); - media_impl->mMediaEntryURL = media_entry->getCurrentURL(); - if (media_impl->mMediaSource) - { - media_impl->mMediaSource->setAutoScale(media_impl->mMediaAutoScale); - media_impl->mMediaSource->setLoop(media_impl->mMediaLoop); - media_impl->mMediaSource->setSize(media_entry->getWidthPixels(), media_entry->getHeightPixels()); - } - - bool url_changed = (media_impl->mMediaEntryURL != previous_url); - if(media_impl->mMediaEntryURL.empty()) - { - if(url_changed) - { - // The current media URL is now empty. Unload the media source. - media_impl->unload(); - - lldebugs << "Unloading media instance (new current URL is empty)." << llendl; - } - } - else - { - // The current media URL is not empty. - // If (the media was already loaded OR the media was set to autoplay) AND this update didn't come from this agent, - // do a navigate. - bool auto_play = media_impl->isAutoPlayable(); - if((was_loaded || auto_play) && !update_from_self) - { - needs_navigate = url_changed; - } - - lldebugs << "was_loaded is " << (was_loaded?"true":"false") - << ", auto_play is " << (auto_play?"true":"false") - << ", needs_navigate is " << (needs_navigate?"true":"false") << llendl; - } - } - else - { - media_impl = newMediaImpl( - media_entry->getMediaID(), - media_entry->getWidthPixels(), - media_entry->getHeightPixels(), - media_entry->getAutoScale(), - media_entry->getAutoLoop()); - - media_impl->setHomeURL(media_entry->getHomeURL()); - media_impl->mMediaAutoPlay = media_entry->getAutoPlay(); - media_impl->mMediaEntryURL = media_entry->getCurrentURL(); - if(media_impl->isAutoPlayable()) - { - needs_navigate = true; - } - } - - if(media_impl) - { - if(needs_navigate) - { - media_impl->navigateTo(media_impl->mMediaEntryURL, "", true, true); - lldebugs << "navigating to URL " << media_impl->mMediaEntryURL << llendl; - } - else if(!media_impl->mMediaURL.empty() && (media_impl->mMediaURL != media_impl->mMediaEntryURL)) - { - // If we already have a non-empty media URL set and we aren't doing a navigate, update the media URL to match the media entry. - media_impl->mMediaURL = media_impl->mMediaEntryURL; - - // If this causes a navigate at some point (such as after a reload), it should be considered server-driven so it isn't broadcast. - media_impl->mNavigateServerRequest = true; - - lldebugs << "updating URL in the media impl to " << media_impl->mMediaEntryURL << llendl; - } - } - - return media_impl; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& texture_id) -{ - LLViewerMediaImpl* result = NULL; - - // Look up the texture ID in the texture id->impl map. - impl_id_map::iterator iter = sViewerMediaTextureIDMap.find(texture_id); - if(iter != sViewerMediaTextureIDMap.end()) - { - result = iter->second; - } - - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -std::string LLViewerMedia::getCurrentUserAgent() -{ - // Don't use user-visible string to avoid - // punctuation and strange characters. - std::string skin_name = gSavedSettings.getString("SkinCurrent"); - - // Just in case we need to check browser differences in A/B test - // builds. - std::string channel = LLVersionInfo::getChannel(); - - // append our magic version number string to the browser user agent id - // See the HTTP 1.0 and 1.1 specifications for allowed formats: - // http://www.ietf.org/rfc/rfc1945.txt section 10.15 - // http://www.ietf.org/rfc/rfc2068.txt section 3.8 - // This was also helpful: - // http://www.mozilla.org/build/revised-user-agent-strings.html - std::ostringstream codec; - codec << "SecondLife/"; - codec << LLVersionInfo::getVersion(); - codec << " (" << channel << "; " << skin_name << " skin)"; - llinfos << codec.str() << llendl; - - return codec.str(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::updateBrowserUserAgent() -{ - std::string user_agent = getCurrentUserAgent(); - - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if(pimpl->mMediaSource && pimpl->mMediaSource->pluginSupportsMediaBrowser()) - { - pimpl->mMediaSource->setBrowserUserAgent(user_agent); - } - } - -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::handleSkinCurrentChanged(const LLSD& /*newvalue*/) -{ - // gSavedSettings is already updated when this function is called. - updateBrowserUserAgent(); - return true; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id) -{ - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if(pimpl->getMediaTextureID() == texture_id) - { - return true; - } - } - return false; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setVolume(F32 volume) -{ - if(volume != sGlobalVolume) - { - sGlobalVolume = volume; - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - pimpl->updateVolume(); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -F32 LLViewerMedia::getVolume() -{ - return sGlobalVolume; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::muteListChanged() -{ - // When the mute list changes, we need to check mute status on all impls. - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - pimpl->mNeedsMuteCheck = true; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setInWorldMediaDisabled(bool disabled) -{ - sInWorldMediaDisabled = disabled; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::getInWorldMediaDisabled() -{ - return sInWorldMediaDisabled; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::isInterestingEnough(const LLVOVolume *object, const F64 &object_interest) -{ - bool result = false; - - if (NULL == object) - { - result = false; - } - // Focused? Then it is interesting! - else if (LLViewerMediaFocus::getInstance()->getFocusedObjectID() == object->getID()) - { - result = true; - } - // Selected? Then it is interesting! - // XXX Sadly, 'contains()' doesn't take a const :( - else if (LLSelectMgr::getInstance()->getSelection()->contains(const_cast(object))) - { - result = true; - } - else - { - lldebugs << "object interest = " << object_interest << ", lowest loadable = " << sLowestLoadableImplInterest << llendl; - if(object_interest >= sLowestLoadableImplInterest) - result = true; - } - - return result; -} - -LLViewerMedia::impl_list &LLViewerMedia::getPriorityList() -{ - return sViewerMediaImplList; -} - -// This is the predicate function used to sort sViewerMediaImplList by priority. -bool LLViewerMedia::priorityComparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2) -{ - if(i1->isForcedUnloaded() && !i2->isForcedUnloaded()) - { - // Muted or failed items always go to the end of the list, period. - return false; - } - else if(i2->isForcedUnloaded() && !i1->isForcedUnloaded()) - { - // Muted or failed items always go to the end of the list, period. - return true; - } - else if(i1->hasFocus()) - { - // The item with user focus always comes to the front of the list, period. - return true; - } - else if(i2->hasFocus()) - { - // The item with user focus always comes to the front of the list, period. - return false; - } - else if(i1->isParcelMedia()) - { - // The parcel media impl sorts above all other inworld media, unless one has focus. - return true; - } - else if(i2->isParcelMedia()) - { - // The parcel media impl sorts above all other inworld media, unless one has focus. - return false; - } - else if(i1->getUsedInUI() && !i2->getUsedInUI()) - { - // i1 is a UI element, i2 is not. This makes i1 "less than" i2, so it sorts earlier in our list. - return true; - } - else if(i2->getUsedInUI() && !i1->getUsedInUI()) - { - // i2 is a UI element, i1 is not. This makes i2 "less than" i1, so it sorts earlier in our list. - return false; - } - else if(i1->isPlayable() && !i2->isPlayable()) - { - // Playable items sort above ones that wouldn't play even if they got high enough priority - return true; - } - else if(!i1->isPlayable() && i2->isPlayable()) - { - // Playable items sort above ones that wouldn't play even if they got high enough priority - return false; - } - else if(i1->getInterest() == i2->getInterest()) - { - // Generally this will mean both objects have zero interest. In this case, sort on distance. - return (i1->getProximityDistance() < i2->getProximityDistance()); - } - else - { - // The object with the larger interest value should be earlier in the list, so we reverse the sense of the comparison here. - return (i1->getInterest() > i2->getInterest()); - } -} - -static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2) -{ - if(i1->getProximityDistance() < i2->getProximityDistance()) - { - return true; - } - else if(i1->getProximityDistance() > i2->getProximityDistance()) - { - return false; - } - else - { - // Both objects have the same distance. This most likely means they're two faces of the same object. - // They may also be faces on different objects with exactly the same distance (like HUD objects). - // We don't actually care what the sort order is for this case, as long as it's stable and doesn't change when you enable/disable media. - // Comparing the impl pointers gives a completely arbitrary ordering, but it will be stable. - return (i1 < i2); - } -} - -static LLFastTimer::DeclareTimer FTM_MEDIA_UPDATE("Update Media"); - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::updateMedia(void *dummy_arg) -{ - LLFastTimer t1(FTM_MEDIA_UPDATE); - - // Enable/disable the plugin read thread - LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread")); - - // HACK: we always try to keep a spare running webkit plugin around to improve launch times. - createSpareBrowserMediaSource(); - - sAnyMediaShowing = false; - sUpdatedCookies = getCookieStore()->getChangedCookies(); - if(!sUpdatedCookies.empty()) - { - lldebugs << "updated cookies will be sent to all loaded plugins: " << llendl; - lldebugs << sUpdatedCookies << llendl; - } - - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end;) - { - LLViewerMediaImpl* pimpl = *iter++; - pimpl->update(); - pimpl->calculateInterest(); - } - - // Let the spare media source actually launch - if(sSpareBrowserMediaSource) - { - sSpareBrowserMediaSource->idle(); - } - - // Sort the static instance list using our interest criteria - sViewerMediaImplList.sort(priorityComparitor); - - // Go through the list again and adjust according to priority. - iter = sViewerMediaImplList.begin(); - end = sViewerMediaImplList.end(); - - F64 total_cpu = 0.0f; - int impl_count_total = 0; - int impl_count_interest_low = 0; - int impl_count_interest_normal = 0; - - std::vector proximity_order; - - bool inworld_media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia"); - bool inworld_audio_enabled = gSavedSettings.getBOOL("AudioStreamingMusic"); - U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal"); - U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal"); - U32 max_low = gSavedSettings.getU32("PluginInstancesLow"); - F32 max_cpu = gSavedSettings.getF32("PluginInstancesCPULimit"); - // Setting max_cpu to 0.0 disables CPU usage checking. - bool check_cpu_usage = (max_cpu != 0.0f); - - LLViewerMediaImpl* lowest_interest_loadable = NULL; - - // Notes on tweakable params: - // max_instances must be set high enough to allow the various instances used in the UI (for the help browser, search, etc.) to be loaded. - // If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow. - - for(; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - - LLPluginClassMedia::EPriority new_priority = LLPluginClassMedia::PRIORITY_NORMAL; - - if(pimpl->isForcedUnloaded() || (impl_count_total >= (int)max_instances)) - { - // Never load muted or failed impls. - // Hard limit on the number of instances that will be loaded at one time - new_priority = LLPluginClassMedia::PRIORITY_UNLOADED; - } - else if(!pimpl->getVisible()) - { - new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; - } - else if(pimpl->hasFocus()) - { - new_priority = LLPluginClassMedia::PRIORITY_HIGH; - impl_count_interest_normal++; // count this against the count of "normal" instances for priority purposes - } - else if(pimpl->getUsedInUI()) - { - new_priority = LLPluginClassMedia::PRIORITY_NORMAL; - impl_count_interest_normal++; - } - else if(pimpl->isParcelMedia()) - { - new_priority = LLPluginClassMedia::PRIORITY_NORMAL; - impl_count_interest_normal++; - } - else - { - // Look at interest and CPU usage for instances that aren't in any of the above states. - - // Heuristic -- if the media texture's approximate screen area is less than 1/4 of the native area of the texture, - // turn it down to low instead of normal. This may downsample for plugins that support it. - bool media_is_small = false; - F64 approximate_interest = pimpl->getApproximateTextureInterest(); - if(approximate_interest == 0.0f) - { - // this media has no current size, which probably means it's not loaded. - media_is_small = true; - } - else if(pimpl->getInterest() < (approximate_interest / 4)) - { - media_is_small = true; - } - - if(pimpl->getInterest() == 0.0f) - { - // This media is completely invisible, due to being outside the view frustrum or out of range. - new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; - } - else if(check_cpu_usage && (total_cpu > max_cpu)) - { - // Higher priority plugins have already used up the CPU budget. Set remaining ones to slideshow priority. - new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; - } - else if((impl_count_interest_normal < (int)max_normal) && !media_is_small) - { - // Up to max_normal inworld get normal priority - new_priority = LLPluginClassMedia::PRIORITY_NORMAL; - impl_count_interest_normal++; - } - else if (impl_count_interest_low + impl_count_interest_normal < (int)max_low + (int)max_normal) - { - // The next max_low inworld get turned down - new_priority = LLPluginClassMedia::PRIORITY_LOW; - impl_count_interest_low++; - - // Set the low priority size for downsampling to approximately the size the texture is displayed at. - { - F32 approximate_interest_dimension = fsqrtf(pimpl->getInterest()); - - pimpl->setLowPrioritySizeLimit(llround(approximate_interest_dimension)); - } - } - else - { - // Any additional impls (up to max_instances) get very infrequent time - new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; - } - } - - if(!pimpl->getUsedInUI() && (new_priority != LLPluginClassMedia::PRIORITY_UNLOADED)) - { - // This is a loadable inworld impl -- the last one in the list in this class defines the lowest loadable interest. - lowest_interest_loadable = pimpl; - - impl_count_total++; - } - - // Overrides if the window is minimized or we lost focus (taking care - // not to accidentally "raise" the priority either) - if (!gViewerWindow->getActive() /* viewer window minimized? */ - && new_priority > LLPluginClassMedia::PRIORITY_HIDDEN) - { - new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; - } - else if (!gFocusMgr.getAppHasFocus() /* viewer window lost focus? */ - && new_priority > LLPluginClassMedia::PRIORITY_LOW) - { - new_priority = LLPluginClassMedia::PRIORITY_LOW; - } - - if(!inworld_media_enabled) - { - // If inworld media is locked out, force all inworld media to stay unloaded. - if(!pimpl->getUsedInUI()) - { - new_priority = LLPluginClassMedia::PRIORITY_UNLOADED; - } - } - // update the audio stream here as well - if( !inworld_audio_enabled) - { - if(LLViewerMedia::isParcelAudioPlaying() && gAudiop && LLViewerMedia::hasParcelAudio()) - { - gAudiop->stopInternetStream(); - } - } - pimpl->setPriority(new_priority); - - if(pimpl->getUsedInUI()) - { - // Any impls used in the UI should not be in the proximity list. - pimpl->mProximity = -1; - } - else - { - proximity_order.push_back(pimpl); - } - - total_cpu += pimpl->getCPUUsage(); - - if (!pimpl->getUsedInUI() && pimpl->hasMedia()) - { - sAnyMediaShowing = true; - } - - } - - // Re-calculate this every time. - sLowestLoadableImplInterest = 0.0f; - - // Only do this calculation if we've hit the impl count limit -- up until that point we always need to load media data. - if(lowest_interest_loadable && (impl_count_total >= (int)max_instances)) - { - // Get the interest value of this impl's object for use by isInterestingEnough - LLVOVolume *object = lowest_interest_loadable->getSomeObject(); - if(object) - { - // NOTE: Don't use getMediaInterest() here. We want the pixel area, not the total media interest, - // so that we match up with the calculation done in LLMediaDataClient. - sLowestLoadableImplInterest = object->getPixelArea(); - } - } - - if(gSavedSettings.getBOOL("MediaPerformanceManagerDebug")) - { - // Give impls the same ordering as the priority list - // they're already in the right order for this. - } - else - { - // Use a distance-based sort for proximity values. - std::stable_sort(proximity_order.begin(), proximity_order.end(), proximity_comparitor); - } - - // Transfer the proximity order to the proximity fields in the objects. - for(int i = 0; i < (int)proximity_order.size(); i++) - { - proximity_order[i]->mProximity = i; - } - - LL_DEBUGS("PluginPriority") << "Total reported CPU usage is " << total_cpu << llendl; - -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::isAnyMediaShowing() -{ - return sAnyMediaShowing; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setAllMediaEnabled(bool val) -{ - // Set "tentative" autoplay first. We need to do this here or else - // re-enabling won't start up the media below. - gSavedSettings.setBOOL("MediaTentativeAutoPlay", val); - - // Then - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if (!pimpl->getUsedInUI()) - { - pimpl->setDisabled(!val); - } - } - - // Also do Parcel Media and Parcel Audio - if (val) - { - if (!LLViewerMedia::isParcelMediaPlaying() && LLViewerMedia::hasParcelMedia()) - { - LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel()); - } - - if (gSavedSettings.getBOOL("AudioStreamingMusic") && - !LLViewerMedia::isParcelAudioPlaying() && - gAudiop && - LLViewerMedia::hasParcelAudio()) - { - gAudiop->startInternetStream(LLViewerMedia::getParcelAudioURL()); - } - } - else { - // This actually unloads the impl, as opposed to "stop"ping the media - LLViewerParcelMedia::stop(); - if (gAudiop) gAudiop->stopInternetStream(); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::isParcelMediaPlaying() -{ - return (LLViewerMedia::hasParcelMedia() && LLViewerParcelMedia::getParcelMedia() && LLViewerParcelMedia::getParcelMedia()->hasMedia()); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::isParcelAudioPlaying() -{ - return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying()); -} - -void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response) -{ - LLViewerMediaImpl *impl = LLViewerMedia::getMediaImplFromTextureID(notification["payload"]["media_id"]); - if(impl) - { - LLPluginClassMedia* media = impl->getMediaPlugin(); - if(media) - { - if (response["ok"]) - { - media->sendAuthResponse(true, response["username"], response["password"]); - } - else - { - media->sendAuthResponse(false, "", ""); - } - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::clearAllCookies() -{ - // Clear all cookies for all plugins - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - for (; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if(pimpl->mMediaSource) - { - pimpl->mMediaSource->clear_cookies(); - } - } - - // Clear all cookies from the cookie store - getCookieStore()->setAllCookies(""); - - // FIXME: this may not be sufficient, since the on-disk cookie file won't get written until some browser instance exits cleanly. - // It also won't clear cookies for other accounts, or for any account if we're not logged in, and won't do anything at all if there are no webkit plugins loaded. - // Until such time as we can centralize cookie storage, the following hack should cover these cases: - - // HACK: Look for cookie files in all possible places and delete them. - // NOTE: this assumes knowledge of what happens inside the webkit plugin (it's what adds 'browser_profile' to the path and names the cookie file) - - // Places that cookie files can be: - // /browser_profile/cookies - // /first_last/browser_profile/cookies (note that there may be any number of these!) - // /first_last/plugin_cookies.txt (note that there may be any number of these!) - - std::string base_dir = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter(); - std::string target; - std::string filename; - - lldebugs << "base dir = " << base_dir << llendl; - - // The non-logged-in version is easy - target = base_dir; - target += "browser_profile"; - target += gDirUtilp->getDirDelimiter(); - target += "cookies"; - lldebugs << "target = " << target << llendl; - if(LLFile::isfile(target)) - { - LLFile::remove(target); - } - - // the hard part: iterate over all user directories and delete the cookie file from each one - while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename)) - { - target = base_dir; - target += filename; - target += gDirUtilp->getDirDelimiter(); - target += "browser_profile"; - target += gDirUtilp->getDirDelimiter(); - target += "cookies"; - lldebugs << "target = " << target << llendl; - if(LLFile::isfile(target)) - { - LLFile::remove(target); - } - - // Other accounts may have new-style cookie files too -- delete them as well - target = base_dir; - target += filename; - target += gDirUtilp->getDirDelimiter(); - target += PLUGIN_COOKIE_FILE_NAME; - lldebugs << "target = " << target << llendl; - if(LLFile::isfile(target)) - { - LLFile::remove(target); - } - } - - // If we have an OpenID cookie, re-add it to the cookie store. - setOpenIDCookie(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::clearAllCaches() -{ - // Clear all plugins' caches - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - for (; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - pimpl->clearCache(); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setCookiesEnabled(bool enabled) -{ - // Set the "cookies enabled" flag for all loaded plugins - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - for (; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if(pimpl->mMediaSource) - { - pimpl->mMediaSource->enable_cookies(enabled); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int port) -{ - // Set the proxy config for all loaded plugins - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - for (; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if(pimpl->mMediaSource) - { - pimpl->mMediaSource->proxy_setup(enable, host, port); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -///////////////////////////////////////////////////////////////////////////////////////// -// static -LLPluginCookieStore *LLViewerMedia::getCookieStore() -{ - if(sCookieStore == NULL) - { - sCookieStore = new LLPluginCookieStore; - } - - return sCookieStore; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::loadCookieFile() -{ - // build filename for each user - std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); - - if (resolved_filename.empty()) - { - llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; - return; - } - - // open the file for reading - llifstream file(resolved_filename); - if (!file.is_open()) - { - llwarns << "can't load plugin cookies from file \"" << PLUGIN_COOKIE_FILE_NAME << "\"" << llendl; - return; - } - - getCookieStore()->readAllCookies(file, true); - - file.close(); - - // send the clear_cookies message to all loaded plugins - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - for (; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if(pimpl->mMediaSource) - { - pimpl->mMediaSource->clear_cookies(); - } - } - - // If we have an OpenID cookie, re-add it to the cookie store. - setOpenIDCookie(); -} - - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::saveCookieFile() -{ - // build filename for each user - std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); - - if (resolved_filename.empty()) - { - llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; - return; - } - - // open a file for writing - llofstream file (resolved_filename); - if (!file.is_open()) - { - llwarns << "can't open plugin cookie file \"" << PLUGIN_COOKIE_FILE_NAME << "\" for writing" << llendl; - return; - } - - getCookieStore()->writePersistentCookies(file); - - file.close(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path, bool secure) -{ - std::stringstream cookie; - - cookie << name << "=" << LLPluginCookieStore::quoteString(value); - - if(expires.notNull()) - { - cookie << "; expires=" << expires.asRFC1123(); - } - - cookie << "; domain=" << domain; - - cookie << "; path=" << path; - - if(secure) - { - cookie << "; secure"; - } - - getCookieStore()->setCookies(cookie.str()); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path, bool secure) -{ - // A session cookie just has a NULL date. - addCookie(name, value, domain, LLDate(), path, secure); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::removeCookie(const std::string &name, const std::string &domain, const std::string &path ) -{ - // To remove a cookie, add one with the same name, domain, and path that expires in the past. - - addCookie(name, "", domain, LLDate(LLDate::now().secondsSinceEpoch() - 1.0), path); -} - - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setOpenIDCookie() -{ - if(!sOpenIDCookie.empty()) - { - // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port] - // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that. - // We therefore do it here. - std::string authority = sOpenIDURL.mAuthority; - std::string::size_type host_start = authority.find('@'); - if(host_start == std::string::npos) - { - // no username/password - host_start = 0; - } - else - { - // Hostname starts after the @. - // (If the hostname part is empty, this may put host_start at the end of the string. In that case, it will end up passing through an empty hostname, which is correct.) - ++host_start; - } - std::string::size_type host_end = authority.rfind(':'); - if((host_end == std::string::npos) || (host_end < host_start)) - { - // no port - host_end = authority.size(); - } - - getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start)); - - // *HACK: Doing this here is nasty, find a better way. - LLWebSharing::instance().setOpenIDCookie(sOpenIDCookie); - - // Do a web profile get so we can store the cookie - LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; - headers["Cookie"] = sOpenIDCookie; - headers["User-Agent"] = getCurrentUserAgent(); - - std::string profile_url = getProfileURL(""); - LLURL raw_profile_url( profile_url.c_str() ); - - LLHTTPClient::get(profile_url, - new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()), - headers); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token) -{ - LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL; - - // post the token to the url - // the responder will need to extract the cookie(s). - - // Save the OpenID URL for later -- we may need the host when adding the cookie. - sOpenIDURL.init(openid_url.c_str()); - - // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. - sOpenIDCookie.clear(); - - LLSD headers = LLSD::emptyMap(); - // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header - headers["Accept"] = "*/*"; - // and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" - headers["Content-Type"] = "application/x-www-form-urlencoded"; - - // postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here. - size_t size = openid_token.size(); - U8 *data = new U8[size]; - memcpy(data, openid_token.data(), size); - - LLHTTPClient::postRaw( - openid_url, - data, - size, - new LLViewerMediaOpenIDResponder(), - headers); - -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::openIDCookieResponse(const std::string &cookie) -{ - LL_DEBUGS("MediaAuth") << "Cookie received: \"" << cookie << "\"" << LL_ENDL; - - sOpenIDCookie += cookie; - - setOpenIDCookie(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::proxyWindowOpened(const std::string &target, const std::string &uuid) -{ - if(uuid.empty()) - return; - - for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++) - { - if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser()) - { - (*iter)->mMediaSource->proxyWindowOpened(target, uuid); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::proxyWindowClosed(const std::string &uuid) -{ - if(uuid.empty()) - return; - - for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++) - { - if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser()) - { - (*iter)->mMediaSource->proxyWindowClosed(uuid); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::createSpareBrowserMediaSource() -{ - // If we don't have a spare browser media source, create one. - // However, if PluginAttachDebuggerToPlugins is set then don't spawn a spare - // SLPlugin process in order to not be confused by an unrelated gdb terminal - // popping up at the moment we start a media plugin. - if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) - { - // The null owner will keep the browser plugin from fully initializing - // (specifically, it keeps LLPluginClassMedia from negotiating a size change, - // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) - sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource() -{ - LLPluginClassMedia* result = sSpareBrowserMediaSource; - sSpareBrowserMediaSource = NULL; - return result; -}; - -bool LLViewerMedia::hasInWorldMedia() -{ - if (sInWorldMediaDisabled) return false; - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - // This should be quick, because there should be very few non-in-world-media impls - for (; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if (!pimpl->getUsedInUI() && !pimpl->isParcelMedia()) - { - // Found an in-world media impl - return true; - } - } - return false; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::hasParcelMedia() -{ - return !LLViewerParcelMedia::getURL().empty(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::hasParcelAudio() -{ - return !LLViewerMedia::getParcelAudioURL().empty(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -std::string LLViewerMedia::getParcelAudioURL() -{ - return LLViewerParcelMgr::getInstance()->getAgentParcel()->getMusicURL(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::initClass() -{ - gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, NULL); - sTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> - setTeleportFinishedCallback(boost::bind(&LLViewerMedia::onTeleportFinished)); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::cleanupClass() -{ - gIdleCallbacks.deleteFunction(LLViewerMedia::updateMedia, NULL); - sTeleportFinishConnection.disconnect(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::onTeleportFinished() -{ - // On teleport, clear this setting (i.e. set it to true) - gSavedSettings.setBOOL("MediaTentativeAutoPlay", true); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// LLViewerMediaImpl -////////////////////////////////////////////////////////////////////////////////////////// -LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, - S32 media_width, - S32 media_height, - U8 media_auto_scale, - U8 media_loop) -: - mMediaSource( NULL ), - mMovieImageHasMips(false), - mMediaWidth(media_width), - mMediaHeight(media_height), - mMediaAutoScale(media_auto_scale), - mMediaLoop(media_loop), - mNeedsNewTexture(true), - mTextureUsedWidth(0), - mTextureUsedHeight(0), - mSuspendUpdates(false), - mVisible(true), - mLastSetCursor( UI_CURSOR_ARROW ), - mMediaNavState( MEDIANAVSTATE_NONE ), - mInterest(0.0f), - mUsedInUI(false), - mHasFocus(false), - mPriority(LLPluginClassMedia::PRIORITY_UNLOADED), - mNavigateRediscoverType(false), - mNavigateServerRequest(false), - mMediaSourceFailed(false), - mRequestedVolume(1.0f), - mIsMuted(false), - mNeedsMuteCheck(false), - mPreviousMediaState(MEDIA_NONE), - mPreviousMediaTime(0.0f), - mIsDisabled(false), - mIsParcelMedia(false), - mProximity(-1), - mProximityDistance(0.0f), - mMimeTypeProbe(NULL), - mMediaAutoPlay(false), - mInNearbyMediaList(false), - mClearCache(false), - mBackgroundColor(LLColor4::white), - mNavigateSuspended(false), - mNavigateSuspendedDeferred(false), - mIsUpdated(false), - mTrustedBrowser(false) -{ - - // Set up the mute list observer if it hasn't been set up already. - if(!sViewerMediaMuteListObserverInitialized) - { - LLMuteList::getInstance()->addObserver(&sViewerMediaMuteListObserver); - sViewerMediaMuteListObserverInitialized = true; - } - - add_media_impl(this); - - setTextureID(texture_id); - - // connect this media_impl to the media texture, creating it if it doesn't exist.0 - // This is necessary because we need to be able to use getMaxVirtualSize() even if the media plugin is not loaded. - LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture(mTextureId); - if(media_tex) - { - media_tex->setMediaImpl(); - } - -} - -////////////////////////////////////////////////////////////////////////////////////////// -LLViewerMediaImpl::~LLViewerMediaImpl() -{ - destroyMediaSource(); - - LLViewerMediaTexture::removeMediaImplFromTexture(mTextureId) ; - - setTextureID(); - remove_media_impl(this); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::emitEvent(LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event) -{ - // Broadcast to observers using the superclass version - LLViewerMediaEventEmitter::emitEvent(plugin, event); - - // If this media is on one or more LLVOVolume objects, tell them about the event as well. - std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; - while(iter != mObjectList.end()) - { - LLVOVolume *self = *iter; - ++iter; - self->mediaEvent(this, plugin, event); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) -{ - bool mimeTypeChanged = (mMimeType != mime_type); - bool pluginChanged = (LLMIMETypes::implType(mCurrentMimeType) != LLMIMETypes::implType(mime_type)); - - if(!mMediaSource || pluginChanged) - { - // We don't have a plugin at all, or the new mime type is handled by a different plugin than the old mime type. - (void)initializePlugin(mime_type); - } - else if(mimeTypeChanged) - { - // The same plugin should be able to handle the new media -- just update the stored mime type. - mMimeType = mime_type; - } - - return (mMediaSource != NULL); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::createMediaSource() -{ - if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) - { - // This media shouldn't be created yet. - return; - } - - if(! mMediaURL.empty()) - { - navigateInternal(); - } - else if(! mMimeType.empty()) - { - if (!initializeMedia(mMimeType)) - { - LL_WARNS("Media") << "Failed to initialize media for mime type " << mMimeType << LL_ENDL; - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::destroyMediaSource() -{ - mNeedsNewTexture = true; - - // Tell the viewer media texture it's no longer active - LLViewerMediaTexture* oldImage = LLViewerTextureManager::findMediaTexture( mTextureId ); - if (oldImage) - { - oldImage->setPlaying(FALSE) ; - } - - cancelMimeTypeProbe(); - - if(mMediaSource) - { - mMediaSource->setDeleteOK(true) ; - delete mMediaSource; - mMediaSource = NULL; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::setMediaType(const std::string& media_type) -{ - mMimeType = media_type; -} - -////////////////////////////////////////////////////////////////////////////////////////// -/*static*/ -LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target) -{ - std::string plugin_basename = LLMIMETypes::implType(media_type); - LLPluginClassMedia* media_source = NULL; - - // HACK: we always try to keep a spare running webkit plugin around to improve launch times. - // If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it. - if(plugin_basename == "media_plugin_webkit" && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) - { - media_source = LLViewerMedia::getSpareBrowserMediaSource(); - if(media_source) - { - media_source->setOwner(owner); - media_source->setTarget(target); - media_source->setSize(default_width, default_height); - - return media_source; - } - } - - if(plugin_basename.empty()) - { - LL_WARNS("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL; - } - else - { - std::string launcher_name = gDirUtilp->getLLPluginLauncher(); - std::string plugin_name = gDirUtilp->getLLPluginFilename(plugin_basename); - std::string user_data_path = gDirUtilp->getOSUserAppDir(); - user_data_path += gDirUtilp->getDirDelimiter(); - - // Fix for EXT-5960 - make browser profile specific to user (cache, cookies etc.) - // If the linden username returned is blank, that can only mean we are - // at the login page displaying login Web page or Web browser test via Develop menu. - // In this case we just use whatever gDirUtilp->getOSUserAppDir() gives us (this - // is what we always used before this change) - std::string linden_user_dir = gDirUtilp->getLindenUserDir(); - if ( ! linden_user_dir.empty() ) - { - // gDirUtilp->getLindenUserDir() is whole path, not just Linden name - user_data_path = linden_user_dir; - user_data_path += gDirUtilp->getDirDelimiter(); - }; - - // See if the plugin executable exists - llstat s; - if(LLFile::stat(launcher_name, &s)) - { - LL_WARNS("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL; - } - else if(LLFile::stat(plugin_name, &s)) - { - LL_WARNS("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; - } - else - { - media_source = new LLPluginClassMedia(owner); - media_source->setSize(default_width, default_height); - media_source->setUserDataPath(user_data_path); - media_source->setLanguageCode(LLUI::getLanguage()); - - // collect 'cookies enabled' setting from prefs and send to embedded browser - bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" ); - media_source->enable_cookies( cookies_enabled ); - - // collect 'plugins enabled' setting from prefs and send to embedded browser - bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" ); - media_source->setPluginsEnabled( plugins_enabled ); - - // collect 'javascript enabled' setting from prefs and send to embedded browser - bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" ); - media_source->setJavascriptEnabled( javascript_enabled ); - - media_source->setTarget(target); - - const std::string plugin_dir = gDirUtilp->getLLPluginDir(); - if (media_source->init(launcher_name, plugin_dir, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))) - { - return media_source; - } - else - { - LL_WARNS("Media") << "Failed to init plugin. Destroying." << LL_ENDL; - delete media_source; - } - } - } - - LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << media_type << LL_ENDL; - LLSD args; - args["MIME_TYPE"] = media_type; - LLNotificationsUtil::add("NoPlugin", args); - - return NULL; -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) -{ - if(mMediaSource) - { - // Save the previous media source's last set size before destroying it. - mMediaWidth = mMediaSource->getSetWidth(); - mMediaHeight = mMediaSource->getSetHeight(); - } - - // Always delete the old media impl first. - destroyMediaSource(); - - // and unconditionally set the mime type - mMimeType = media_type; - - if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) - { - // This impl should not be loaded at this time. - LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; - - return false; - } - - // If we got here, we want to ignore previous init failures. - mMediaSourceFailed = false; - - // Save the MIME type that really caused the plugin to load - mCurrentMimeType = mMimeType; - - LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget); - - if (media_source) - { - media_source->setDisableTimeout(gSavedSettings.getBOOL("DebugPluginDisableTimeout")); - media_source->setLoop(mMediaLoop); - media_source->setAutoScale(mMediaAutoScale); - media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent()); - media_source->focus(mHasFocus); - media_source->setBackgroundColor(mBackgroundColor); - - if(gSavedSettings.getBOOL("BrowserIgnoreSSLCertErrors")) - { - media_source->ignore_ssl_cert_errors(true); - } - - // the correct way to deal with certs it to load ours from CA.pem and append them to the ones - // Qt/WebKit loads from your system location. - // Note: This needs the new CA.pem file with the Equifax Secure Certificate Authority - // cert at the bottom: (MIIDIDCCAomgAwIBAgIENd70zzANBg) - std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "CA.pem" ); - media_source->addCertificateFilePath( ca_path ); - - media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort")); - - if(mClearCache) - { - mClearCache = false; - media_source->clear_cache(); - } - - // TODO: Only send cookies to plugins that need them - // Ideally, the plugin should tell us whether it handles cookies or not -- either via the init response or through a separate message. - // Due to the ordering of messages, it's possible we wouldn't get that information back in time to send cookies before sending a navigate message, - // which could cause odd race conditions. - std::string all_cookies = LLViewerMedia::getCookieStore()->getAllCookies(); - lldebugs << "setting cookies: " << all_cookies << llendl; - if(!all_cookies.empty()) - { - media_source->set_cookies(all_cookies); - } - - mMediaSource = media_source; - mMediaSource->setDeleteOK(false) ; - updateVolume(); - - return true; - } - - // Make sure the timer doesn't try re-initing this plugin repeatedly until something else changes. - mMediaSourceFailed = true; - - return false; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::loadURI() -{ - if(mMediaSource) - { - // trim whitespace from front and back of URL - fixes EXT-5363 - LLStringUtil::trim( mMediaURL ); - - // *HACK: we don't know if the URI coming in is properly escaped - // (the contract doesn't specify whether it is escaped or not. - // but LLQtWebKit expects it to be, so we do our best to encode - // special characters) - // The strings below were taken right from http://www.ietf.org/rfc/rfc1738.txt - // Note especially that '%' and '/' are there. - std::string uri = LLURI::escape(mMediaURL, - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789" - "$-_.+" - "!*'()," - "{}|\\^~[]`" - "<>#%" - ";/?:@&=", - false); - llinfos << "Asking media source to load URI: " << uri << llendl; - - mMediaSource->loadURI( uri ); - - // A non-zero mPreviousMediaTime means that either this media was previously unloaded by the priority code while playing/paused, - // or a seek happened before the media loaded. In either case, seek to the saved time. - if(mPreviousMediaTime != 0.0f) - { - seek(mPreviousMediaTime); - } - - if(mPreviousMediaState == MEDIA_PLAYING) - { - // This media was playing before this instance was unloaded. - start(); - } - else if(mPreviousMediaState == MEDIA_PAUSED) - { - // This media was paused before this instance was unloaded. - pause(); - } - else - { - // No relevant previous media play state -- if we're loading the URL, we want to start playing. - start(); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::setSize(int width, int height) -{ - mMediaWidth = width; - mMediaHeight = height; - if(mMediaSource) - { - mMediaSource->setSize(width, height); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::showNotification(LLNotificationPtr notify) -{ - mNotification = notify; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::hideNotification() -{ - mNotification.reset(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::play() -{ - // If the media source isn't there, try to initialize it and load an URL. - if(mMediaSource == NULL) - { - if(!initializeMedia(mMimeType)) - { - // This may be the case where the plugin's priority is PRIORITY_UNLOADED - return; - } - - // Only do this if the media source was just loaded. - loadURI(); - } - - // always start the media - start(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::stop() -{ - if(mMediaSource) - { - mMediaSource->stop(); - // destroyMediaSource(); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::pause() -{ - if(mMediaSource) - { - mMediaSource->pause(); - } - else - { - mPreviousMediaState = MEDIA_PAUSED; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::start() -{ - if(mMediaSource) - { - mMediaSource->start(); - } - else - { - mPreviousMediaState = MEDIA_PLAYING; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::seek(F32 time) -{ - if(mMediaSource) - { - mMediaSource->seek(time); - } - else - { - // Save the seek time to be set when the media is loaded. - mPreviousMediaTime = time; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::skipBack(F32 step_scale) -{ - if(mMediaSource) - { - if(mMediaSource->pluginSupportsMediaTime()) - { - F64 back_step = mMediaSource->getCurrentTime() - (mMediaSource->getDuration()*step_scale); - if(back_step < 0.0) - { - back_step = 0.0; - } - mMediaSource->seek(back_step); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::skipForward(F32 step_scale) -{ - if(mMediaSource) - { - if(mMediaSource->pluginSupportsMediaTime()) - { - F64 forward_step = mMediaSource->getCurrentTime() + (mMediaSource->getDuration()*step_scale); - if(forward_step > mMediaSource->getDuration()) - { - forward_step = mMediaSource->getDuration(); - } - mMediaSource->seek(forward_step); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::setVolume(F32 volume) -{ - mRequestedVolume = volume; - updateVolume(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::updateVolume() -{ - if(mMediaSource) - { - // always scale the volume by the global media volume - F32 volume = mRequestedVolume * LLViewerMedia::getVolume(); - - if (mProximityCamera > 0) - { - if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMax")) - { - volume = 0; - } - else if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMin")) - { - // attenuated_volume = 1 / (roll_off_rate * (d - min))^2 - // the +1 is there so that for distance 0 the volume stays the same - F64 adjusted_distance = mProximityCamera - gSavedSettings.getF32("MediaRollOffMin"); - F64 attenuation = 1.0 + (gSavedSettings.getF32("MediaRollOffRate") * adjusted_distance); - attenuation = 1.0 / (attenuation * attenuation); - // the attenuation multiplier should never be more than one since that would increase volume - volume = volume * llmin(1.0, attenuation); - } - } - - mMediaSource->setVolume(volume); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -F32 LLViewerMediaImpl::getVolume() -{ - return mRequestedVolume; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::focus(bool focus) -{ - mHasFocus = focus; - - if (mMediaSource) - { - // call focus just for the hell of it, even though this apopears to be a nop - mMediaSource->focus(focus); - if (focus) - { - // spoof a mouse click to *actually* pass focus - // Don't do this anymore -- it actually clicks through now. -// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0); -// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::hasFocus() const -{ - // FIXME: This might be able to be a bit smarter by hooking into LLViewerMediaFocus, etc. - return mHasFocus; -} - -std::string LLViewerMediaImpl::getCurrentMediaURL() -{ - if(!mCurrentMediaURL.empty()) - { - return mCurrentMediaURL; - } - - return mMediaURL; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::clearCache() -{ - if(mMediaSource) - { - mMediaSource->clear_cache(); - } - else - { - mClearCache = true; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::mouseDown(S32 x, S32 y, MASK mask, S32 button) -{ - scaleMouse(&x, &y); - mLastMouseX = x; - mLastMouseY = y; -// llinfos << "mouse down (" << x << ", " << y << ")" << llendl; - if (mMediaSource) - { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, button, x, y, mask); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::mouseUp(S32 x, S32 y, MASK mask, S32 button) -{ - scaleMouse(&x, &y); - mLastMouseX = x; - mLastMouseY = y; -// llinfos << "mouse up (" << x << ", " << y << ")" << llendl; - if (mMediaSource) - { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, button, x, y, mask); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::mouseMove(S32 x, S32 y, MASK mask) -{ - scaleMouse(&x, &y); - mLastMouseX = x; - mLastMouseY = y; -// llinfos << "mouse move (" << x << ", " << y << ")" << llendl; - if (mMediaSource) - { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, x, y, mask); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -//static -void LLViewerMediaImpl::scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y) -{ - F32 texture_x = texture_coords.mV[VX]; - F32 texture_y = texture_coords.mV[VY]; - - // Deal with repeating textures by wrapping the coordinates into the range [0, 1.0) - texture_x = fmodf(texture_x, 1.0f); - if(texture_x < 0.0f) - texture_x = 1.0 + texture_x; - - texture_y = fmodf(texture_y, 1.0f); - if(texture_y < 0.0f) - texture_y = 1.0 + texture_y; - - // scale x and y to texel units. - *x = llround(texture_x * mMediaSource->getTextureWidth()); - *y = llround((1.0f - texture_y) * mMediaSource->getTextureHeight()); - - // Adjust for the difference between the actual texture height and the amount of the texture in use. - *y -= (mMediaSource->getTextureHeight() - mMediaSource->getHeight()); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords, MASK mask, S32 button) -{ - if(mMediaSource) - { - S32 x, y; - scaleTextureCoords(texture_coords, &x, &y); - - mouseDown(x, y, mask, button); - } -} - -void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords, MASK mask, S32 button) -{ - if(mMediaSource) - { - S32 x, y; - scaleTextureCoords(texture_coords, &x, &y); - - mouseUp(x, y, mask, button); - } -} - -void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords, MASK mask) -{ - if(mMediaSource) - { - S32 x, y; - scaleTextureCoords(texture_coords, &x, &y); - - mouseMove(x, y, mask); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button) -{ - scaleMouse(&x, &y); - mLastMouseX = x; - mLastMouseY = y; - if (mMediaSource) - { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, button, x, y, mask); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, MASK mask) -{ - scaleMouse(&x, &y); - mLastMouseX = x; - mLastMouseY = y; - if (mMediaSource) - { - mMediaSource->scrollEvent(x, y, mask); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::onMouseCaptureLost() -{ - if (mMediaSource) - { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 0, mLastMouseX, mLastMouseY, 0); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask) -{ - // NOTE: this is called when the mouse is released when we have capture. - // Due to the way mouse coordinates are mapped to the object, we can't use the x and y coordinates that come in with the event. - - if(hasMouseCapture()) - { - // Release the mouse -- this will also send a mouseup to the media - gFocusMgr.setMouseCapture( FALSE ); - } - - return TRUE; -} - -////////////////////////////////////////////////////////////////////////////////////////// -std::string LLViewerMediaImpl::getName() const -{ - if (mMediaSource) - { - return mMediaSource->getMediaName(); - } - - return LLStringUtil::null; -}; - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateBack() -{ - if (mMediaSource) - { - mMediaSource->browse_back(); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateForward() -{ - if (mMediaSource) - { - mMediaSource->browse_forward(); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateReload() -{ - navigateTo(getCurrentMediaURL(), "", true, false); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateHome() -{ - bool rediscover_mimetype = mHomeMimeType.empty(); - navigateTo(mHomeURL, mHomeMimeType, rediscover_mimetype, false); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::unload() -{ - // Unload the media impl and clear its state. - destroyMediaSource(); - resetPreviousMediaState(); - mMediaURL.clear(); - mMimeType.clear(); - mCurrentMediaURL.clear(); - mCurrentMimeType.clear(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type, bool server_request) -{ - cancelMimeTypeProbe(); - - if(mMediaURL != url) - { - // Don't carry media play state across distinct URLs. - resetPreviousMediaState(); - } - - // Always set the current URL and MIME type. - mMediaURL = url; - mMimeType = mime_type; - - // Clear the current media URL, since it will no longer be correct. - mCurrentMediaURL.clear(); - - // if mime type discovery was requested, we'll need to do it when the media loads - mNavigateRediscoverType = rediscover_type; - - // and if this was a server request, the navigate on load will also need to be one. - mNavigateServerRequest = server_request; - - // An explicit navigate resets the "failed" flag. - mMediaSourceFailed = false; - - if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) - { - // Helpful to have media urls in log file. Shouldn't be spammy. - llinfos << "NOT LOADING media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl; - - // This impl should not be loaded at this time. - LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; - - return; - } - - navigateInternal(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateInternal() -{ - // Helpful to have media urls in log file. Shouldn't be spammy. - llinfos << "media id= " << mTextureId << " url=" << mMediaURL << " mime_type=" << mMimeType << llendl; - - if(mNavigateSuspended) - { - llwarns << "Deferring navigate." << llendl; - mNavigateSuspendedDeferred = true; - return; - } - - if(mMimeTypeProbe != NULL) - { - llwarns << "MIME type probe already in progress -- bailing out." << llendl; - return; - } - - if(mNavigateServerRequest) - { - setNavState(MEDIANAVSTATE_SERVER_SENT); - } - else - { - setNavState(MEDIANAVSTATE_NONE); - } - - // If the caller has specified a non-empty MIME type, look that up in our MIME types list. - // If we have a plugin for that MIME type, use that instead of attempting auto-discovery. - // This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type - // but the parcel owner has correctly set the MIME type in the parcel media settings. - - if(!mMimeType.empty() && (mMimeType != LLMIMETypes::getDefaultMimeType())) - { - std::string plugin_basename = LLMIMETypes::implType(mMimeType); - if(!plugin_basename.empty()) - { - // We have a plugin for this mime type - mNavigateRediscoverType = false; - } - } - - if(mNavigateRediscoverType) - { - - LLURI uri(mMediaURL); - std::string scheme = uri.scheme(); - - if(scheme.empty() || "http" == scheme || "https" == scheme) - { - // If we don't set an Accept header, LLHTTPClient will add one like this: - // Accept: application/llsd+xml - // which is really not what we want. - LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; - // Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com - headers["Cookie"] = ""; - LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f); - } - else if("data" == scheme || "file" == scheme || "about" == scheme) - { - // FIXME: figure out how to really discover the type for these schemes - // We use "data" internally for a text/html url for loading the login screen - if(initializeMedia("text/html")) - { - loadURI(); - } - } - else - { - // This catches 'rtsp://' urls - if(initializeMedia(scheme)) - { - loadURI(); - } - } - } - else if(initializeMedia(mMimeType)) - { - loadURI(); - } - else - { - LL_WARNS("Media") << "Couldn't navigate to: " << mMediaURL << " as there is no media type for: " << mMimeType << LL_ENDL; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateStop() -{ - if(mMediaSource) - { - mMediaSource->browse_stop(); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) -{ - bool result = false; - - if (mMediaSource) - { - // FIXME: THIS IS SO WRONG. - // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... - if( MASK_CONTROL & mask ) - { - result = true; - } - - if(!result) - { - - LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); - - result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data); - // Since the viewer internal event dispatching doesn't give us key-up events, simulate one here. - (void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data); - } - } - - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) -{ - bool result = false; - - if (mMediaSource) - { - // only accept 'printable' characters, sigh... - if (uni_char >= 32 // discard 'control' characters - && uni_char != 127) // SDL thinks this is 'delete' - yuck. - { - LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); - - mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data); - } - } - - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::canNavigateForward() -{ - BOOL result = FALSE; - if (mMediaSource) - { - result = mMediaSource->getHistoryForwardAvailable(); - } - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::canNavigateBack() -{ - BOOL result = FALSE; - if (mMediaSource) - { - result = mMediaSource->getHistoryBackAvailable(); - } - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::update() -{ - if(mMediaSource == NULL) - { - if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) - { - // This media source should not be loaded. - } - else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW) - { - // Don't load new instances that are at PRIORITY_SLIDESHOW or below. They're just kept around to preserve state. - } - else if(mMimeTypeProbe != NULL) - { - // this media source is doing a MIME type probe -- don't try loading it again. - } - else - { - // This media may need to be loaded. - if(sMediaCreateTimer.hasExpired()) - { - LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL; - createMediaSource(); - sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY); - } - else - { - LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL; - } - } - } - else - { - updateVolume(); - - // If we didn't just create the impl, it may need to get cookie updates. - if(!sUpdatedCookies.empty()) - { - // TODO: Only send cookies to plugins that need them - mMediaSource->set_cookies(sUpdatedCookies); - } - } - - - if(mMediaSource == NULL) - { - return; - } - - // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash. - setNavigateSuspended(true); - - mMediaSource->idle(); - - setNavigateSuspended(false); - - if(mMediaSource == NULL) - { - return; - } - - if(mMediaSource->isPluginExited()) - { - resetPreviousMediaState(); - destroyMediaSource(); - return; - } - - if(!mMediaSource->textureValid()) - { - return; - } - - if(mSuspendUpdates || !mVisible) - { - return; - } - - LLViewerMediaTexture* placeholder_image = updatePlaceholderImage(); - - if(placeholder_image) - { - LLRect dirty_rect; - - // Since we're updating this texture, we know it's playing. Tell the texture to do its replacement magic so it gets rendered. - placeholder_image->setPlaying(TRUE); - - if(mMediaSource->getDirty(&dirty_rect)) - { - // Constrain the dirty rect to be inside the texture - S32 x_pos = llmax(dirty_rect.mLeft, 0); - S32 y_pos = llmax(dirty_rect.mBottom, 0); - S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos; - S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos; - - if(width > 0 && height > 0) - { - - U8* data = mMediaSource->getBitsData(); - - // Offset the pixels pointer to match x_pos and y_pos - data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); - data += ( y_pos * mMediaSource->getTextureDepth() ); - - placeholder_image->setSubImage( - data, - mMediaSource->getBitsWidth(), - mMediaSource->getBitsHeight(), - x_pos, - y_pos, - width, - height); - - } - - mMediaSource->resetDirty(); - } - } -} - - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::updateImagesMediaStreams() -{ -} - - -////////////////////////////////////////////////////////////////////////////////////////// -LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() -{ - if(mTextureId.isNull()) - { - // The code that created this instance will read from the plugin's bits. - return NULL; - } - - LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId ); - - if (mNeedsNewTexture - || placeholder_image->getUseMipMaps() - || (placeholder_image->getWidth() != mMediaSource->getTextureWidth()) - || (placeholder_image->getHeight() != mMediaSource->getTextureHeight()) - || (mTextureUsedWidth != mMediaSource->getWidth()) - || (mTextureUsedHeight != mMediaSource->getHeight()) - ) - { - LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL; - LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL; - - int texture_width = mMediaSource->getTextureWidth(); - int texture_height = mMediaSource->getTextureHeight(); - int texture_depth = mMediaSource->getTextureDepth(); - - // MEDIAOPT: check to see if size actually changed before doing work - placeholder_image->destroyGLTexture(); - // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? - placeholder_image->reinit(FALSE); // probably not needed - - // MEDIAOPT: seems insane that we actually have to make an imageraw then - // immediately discard it - LLPointer raw = new LLImageRaw(texture_width, texture_height, texture_depth); - // Clear the texture to the background color, ignoring alpha. - // convert background color channels from [0.0, 1.0] to [0, 255]; - raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff); - int discard_level = 0; - - // ask media source for correct GL image format constants - placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), - mMediaSource->getTextureFormatPrimary(), - mMediaSource->getTextureFormatType(), - mMediaSource->getTextureFormatSwapBytes()); - - placeholder_image->createGLTexture(discard_level, raw); - - // MEDIAOPT: set this dynamically on play/stop - // FIXME -// placeholder_image->mIsMediaTexture = true; - mNeedsNewTexture = false; - - // If the amount of the texture being drawn by the media goes down in either width or height, - // recreate the texture to avoid leaving parts of the old image behind. - mTextureUsedWidth = mMediaSource->getWidth(); - mTextureUsedHeight = mMediaSource->getHeight(); - } - - return placeholder_image; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -LLUUID LLViewerMediaImpl::getMediaTextureID() const -{ - return mTextureId; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::setVisible(bool visible) -{ - mVisible = visible; - - if(mVisible) - { - if(mMediaSource && mMediaSource->isPluginExited()) - { - destroyMediaSource(); - } - - if(!mMediaSource) - { - createMediaSource(); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::mouseCapture() -{ - gFocusMgr.setMouseCapture(this); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y) -{ -#if 0 - S32 media_width, media_height; - S32 texture_width, texture_height; - getMediaSize( &media_width, &media_height ); - getTextureSize( &texture_width, &texture_height ); - S32 y_delta = texture_height - media_height; - - *mouse_y -= y_delta; -#endif -} - - - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::isMediaTimeBased() -{ - bool result = false; - - if(mMediaSource) - { - result = mMediaSource->pluginSupportsMediaTime(); - } - - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::isMediaPlaying() -{ - bool result = false; - - if(mMediaSource) - { - EMediaStatus status = mMediaSource->getStatus(); - if(status == MEDIA_PLAYING || status == MEDIA_LOADING) - result = true; - } - - return result; -} -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::isMediaPaused() -{ - bool result = false; - - if(mMediaSource) - { - if(mMediaSource->getStatus() == MEDIA_PAUSED) - result = true; - } - - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::hasMedia() const -{ - return mMediaSource != NULL; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -void LLViewerMediaImpl::resetPreviousMediaState() -{ - mPreviousMediaState = MEDIA_NONE; - mPreviousMediaTime = 0.0f; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// -void LLViewerMediaImpl::setDisabled(bool disabled, bool forcePlayOnEnable) -{ - if(mIsDisabled != disabled) - { - // Only do this on actual state transitions. - mIsDisabled = disabled; - - if(mIsDisabled) - { - // We just disabled this media. Clear all state. - unload(); - } - else - { - // We just (re)enabled this media. Do a navigate if auto-play is in order. - if(isAutoPlayable() || forcePlayOnEnable) - { - navigateTo(mMediaEntryURL, "", true, true); - } - } - - } -}; - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::isForcedUnloaded() const -{ - if(mIsMuted || mMediaSourceFailed || mIsDisabled) - { - return true; - } - - if(sInWorldMediaDisabled) - { - // When inworld media is disabled, all instances that aren't marked as "used in UI" will not be loaded. - if(!mUsedInUI) - { - return true; - } - } - - // If this media's class is not supposed to be shown, unload - if (!shouldShowBasedOnClass()) - { - return true; - } - - return false; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::isPlayable() const -{ - if(isForcedUnloaded()) - { - // All of the forced-unloaded criteria also imply not playable. - return false; - } - - if(hasMedia()) - { - // Anything that's already playing is, by definition, playable. - return true; - } - - if(!mMediaURL.empty()) - { - // If something has navigated the instance, it's ready to be played. - return true; - } - - return false; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent event) -{ - bool pass_through = true; - switch(event) - { - case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: - { - LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL; - std::string url = plugin->getClickURL(); - std::string nav_type = plugin->getClickNavType(); - LLURLDispatcher::dispatch(url, nav_type, NULL, mTrustedBrowser); - } - break; - case MEDIA_EVENT_CLICK_LINK_HREF: - { - LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << plugin->getClickTarget() << "\", uri is " << plugin->getClickURL() << LL_ENDL; - }; - break; - case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: - { - // The plugin failed to load properly. Make sure the timer doesn't retry. - // TODO: maybe mark this plugin as not loadable somehow? - mMediaSourceFailed = true; - - // Reset the last known state of the media to defaults. - resetPreviousMediaState(); - - // TODO: may want a different message for this case? - LLSD args; - args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType); - LLNotificationsUtil::add("MediaPluginFailed", args); - } - break; - - case MEDIA_EVENT_PLUGIN_FAILED: - { - // The plugin crashed. - mMediaSourceFailed = true; - - // Reset the last known state of the media to defaults. - resetPreviousMediaState(); - - LLSD args; - args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType); - // SJB: This is getting called every frame if the plugin fails to load, continuously respawining the alert! - //LLNotificationsUtil::add("MediaPluginFailed", args); - } - break; - - case MEDIA_EVENT_CURSOR_CHANGED: - { - LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << plugin->getCursorName() << LL_ENDL; - - std::string cursor = plugin->getCursorName(); - - if(cursor == "arrow") - mLastSetCursor = UI_CURSOR_ARROW; - else if(cursor == "ibeam") - mLastSetCursor = UI_CURSOR_IBEAM; - else if(cursor == "splith") - mLastSetCursor = UI_CURSOR_SIZEWE; - else if(cursor == "splitv") - mLastSetCursor = UI_CURSOR_SIZENS; - else if(cursor == "hand") - mLastSetCursor = UI_CURSOR_HAND; - else // for anything else, default to the arrow - mLastSetCursor = UI_CURSOR_ARROW; - } - break; - - case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN: - { - LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL; - hideNotification(); - - if(getNavState() == MEDIANAVSTATE_SERVER_SENT) - { - setNavState(MEDIANAVSTATE_SERVER_BEGUN); - } - else - { - setNavState(MEDIANAVSTATE_BEGUN); - } - } - break; - - case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE: - { - LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_COMPLETE, uri is: " << plugin->getNavigateURI() << LL_ENDL; - - std::string url = plugin->getNavigateURI(); - if(getNavState() == MEDIANAVSTATE_BEGUN) - { - if(mCurrentMediaURL == url) - { - // This is a navigate that takes us to the same url as the previous navigate. - setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS); - } - else - { - mCurrentMediaURL = url; - setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED); - } - } - else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN) - { - mCurrentMediaURL = url; - setNavState(MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED); - } - else - { - // all other cases need to leave the state alone. - } - } - break; - - case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED: - { - LL_DEBUGS("Media") << "MEDIA_EVENT_LOCATION_CHANGED, uri is: " << plugin->getLocation() << LL_ENDL; - - std::string url = plugin->getLocation(); - - if(getNavState() == MEDIANAVSTATE_BEGUN) - { - if(mCurrentMediaURL == url) - { - // This is a navigate that takes us to the same url as the previous navigate. - setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS); - } - else - { - mCurrentMediaURL = url; - setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED); - } - } - else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN) - { - mCurrentMediaURL = url; - setNavState(MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED); - } - else - { - // Don't track redirects. - setNavState(MEDIANAVSTATE_NONE); - } - } - break; - - case LLViewerMediaObserver::MEDIA_EVENT_PICK_FILE_REQUEST: - { - // Display a file picker - std::string response; - - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getOpenFile(LLFilePicker::FFLOAD_ALL)) - { - // The user didn't pick a file -- the empty response string will indicate this. - } - - response = picker.getFirstFile(); - - plugin->sendPickFileResponse(response); - } - break; - - - case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST: - { - LLNotification::Params auth_request_params; - auth_request_params.name = "AuthRequest"; - - // pass in host name and realm for site (may be zero length but will always exist) - LLSD args; - LLURL raw_url( plugin->getAuthURL().c_str() ); - args["HOST_NAME"] = raw_url.getAuthority(); - args["REALM"] = plugin->getAuthRealm(); - auth_request_params.substitutions = args; - - auth_request_params.payload = LLSD().with("media_id", mTextureId); - auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2); - LLNotifications::instance().add(auth_request_params); - }; - break; - - case LLViewerMediaObserver::MEDIA_EVENT_CLOSE_REQUEST: - { - std::string uuid = plugin->getClickUUID(); - - llinfos << "MEDIA_EVENT_CLOSE_REQUEST for uuid " << uuid << llendl; - - if(uuid.empty()) - { - // This close request is directed at this instance, let it fall through. - } - else - { - // This close request is directed at another instance - pass_through = false; - LLFloaterMediaBrowser::closeRequest(uuid); - LLFloaterWebContent::closeRequest(uuid); - } - } - break; - - case LLViewerMediaObserver::MEDIA_EVENT_GEOMETRY_CHANGE: - { - std::string uuid = plugin->getClickUUID(); - - llinfos << "MEDIA_EVENT_GEOMETRY_CHANGE for uuid " << uuid << llendl; - - if(uuid.empty()) - { - // This geometry change request is directed at this instance, let it fall through. - } - else - { - // This request is directed at another instance - pass_through = false; - LLFloaterMediaBrowser::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight()); - LLFloaterWebContent::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight()); - } - } - break; - - default: - break; - } - - if(pass_through) - { - // Just chain the event to observers. - emitEvent(plugin, event); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLViewerMediaImpl::handleCookieSet(LLPluginClassMedia* self, const std::string &cookie) -{ - LLViewerMedia::getCookieStore()->setCookies(cookie); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void -LLViewerMediaImpl::cut() -{ - if (mMediaSource) - mMediaSource->cut(); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -BOOL -LLViewerMediaImpl::canCut() const -{ - if (mMediaSource) - return mMediaSource->canCut(); - else - return FALSE; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void -LLViewerMediaImpl::copy() -{ - if (mMediaSource) - mMediaSource->copy(); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -BOOL -LLViewerMediaImpl::canCopy() const -{ - if (mMediaSource) - return mMediaSource->canCopy(); - else - return FALSE; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void -LLViewerMediaImpl::paste() -{ - if (mMediaSource) - mMediaSource->paste(); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -BOOL -LLViewerMediaImpl::canPaste() const -{ - if (mMediaSource) - return mMediaSource->canPaste(); - else - return FALSE; -} - -void LLViewerMediaImpl::setUpdated(BOOL updated) -{ - mIsUpdated = updated ; -} - -BOOL LLViewerMediaImpl::isUpdated() -{ - return mIsUpdated ; -} - -void LLViewerMediaImpl::calculateInterest() -{ - LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId ); - - if(texture != NULL) - { - mInterest = texture->getMaxVirtualSize(); - } - else - { - // This will be a relatively common case now, since it will always be true for unloaded media. - mInterest = 0.0f; - } - - // Calculate distance from the avatar, for use in the proximity calculation. - mProximityDistance = 0.0f; - mProximityCamera = 0.0f; - if(!mObjectList.empty()) - { - // Just use the first object in the list. We could go through the list and find the closest object, but this should work well enough. - std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; - LLVOVolume* objp = *iter ; - llassert_always(objp != NULL) ; - - // The distance calculation is invalid for HUD attachments -- leave both mProximityDistance and mProximityCamera at 0 for them. - if(!objp->isHUDAttachment()) - { - LLVector3d obj_global = objp->getPositionGlobal() ; - LLVector3d agent_global = gAgent.getPositionGlobal() ; - LLVector3d global_delta = agent_global - obj_global ; - mProximityDistance = global_delta.magVecSquared(); // use distance-squared because it's cheaper and sorts the same. - - LLVector3d camera_delta = gAgentCamera.getCameraPositionGlobal() - obj_global; - mProximityCamera = camera_delta.magVec(); - } - } - - if(mNeedsMuteCheck) - { - // Check all objects this instance is associated with, and those objects' owners, against the mute list - mIsMuted = false; - - std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; - for(; iter != mObjectList.end() ; ++iter) - { - LLVOVolume *obj = *iter; - llassert(obj); - if (!obj) continue; - if(LLMuteList::getInstance() && - LLMuteList::getInstance()->isMuted(obj->getID())) - { - mIsMuted = true; - } - else - { - // We won't have full permissions data for all objects. Attempt to mute objects when we can tell their owners are muted. - if (LLSelectMgr::getInstance()) - { - LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(obj); - if(obj_perm) - { - if(LLMuteList::getInstance() && - LLMuteList::getInstance()->isMuted(obj_perm->getOwner())) - mIsMuted = true; - } - } - } - } - - mNeedsMuteCheck = false; - } -} - -F64 LLViewerMediaImpl::getApproximateTextureInterest() -{ - F64 result = 0.0f; - - if(mMediaSource) - { - result = mMediaSource->getFullWidth(); - result *= mMediaSource->getFullHeight(); - } - else - { - // No media source is loaded -- all we have to go on is the texture size that has been set on the impl, if any. - result = mMediaWidth; - result *= mMediaHeight; - } - - return result; -} - -void LLViewerMediaImpl::setUsedInUI(bool used_in_ui) -{ - mUsedInUI = used_in_ui; - - // HACK: Force elements used in UI to load right away. - // This fixes some issues where UI code that uses the browser instance doesn't expect it to be unloaded. - if(mUsedInUI && (mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)) - { - if(getVisible()) - { - setPriority(LLPluginClassMedia::PRIORITY_NORMAL); - } - else - { - setPriority(LLPluginClassMedia::PRIORITY_HIDDEN); - } - - createMediaSource(); - } -}; - -void LLViewerMediaImpl::setBackgroundColor(LLColor4 color) -{ - mBackgroundColor = color; - - if(mMediaSource) - { - mMediaSource->setBackgroundColor(mBackgroundColor); - } -}; - -F64 LLViewerMediaImpl::getCPUUsage() const -{ - F64 result = 0.0f; - - if(mMediaSource) - { - result = mMediaSource->getCPUUsage(); - } - - return result; -} - -void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority) -{ - if(mPriority != priority) - { - LL_DEBUGS("PluginPriority") - << "changing priority of media id " << mTextureId - << " from " << LLPluginClassMedia::priorityToString(mPriority) - << " to " << LLPluginClassMedia::priorityToString(priority) - << LL_ENDL; - } - - mPriority = priority; - - if(priority == LLPluginClassMedia::PRIORITY_UNLOADED) - { - if(mMediaSource) - { - // Need to unload the media source - - // First, save off previous media state - mPreviousMediaState = mMediaSource->getStatus(); - mPreviousMediaTime = mMediaSource->getCurrentTime(); - - destroyMediaSource(); - } - } - - if(mMediaSource) - { - mMediaSource->setPriority(mPriority); - } - - // NOTE: loading (or reloading) media sources whose priority has risen above PRIORITY_UNLOADED is done in update(). -} - -void LLViewerMediaImpl::setLowPrioritySizeLimit(int size) -{ - if(mMediaSource) - { - mMediaSource->setLowPrioritySizeLimit(size); - } -} - -void LLViewerMediaImpl::setNavState(EMediaNavState state) -{ - mMediaNavState = state; - - switch (state) - { - case MEDIANAVSTATE_NONE: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_NONE" << llendl; break; - case MEDIANAVSTATE_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_BEGUN" << llendl; break; - case MEDIANAVSTATE_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED" << llendl; break; - case MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS" << llendl; break; - case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break; - case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS" << llendl; break; - case MEDIANAVSTATE_SERVER_SENT: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_SENT" << llendl; break; - case MEDIANAVSTATE_SERVER_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_BEGUN" << llendl; break; - case MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED" << llendl; break; - case MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break; - } -} - -void LLViewerMediaImpl::setNavigateSuspended(bool suspend) -{ - if(mNavigateSuspended != suspend) - { - mNavigateSuspended = suspend; - if(!suspend) - { - // We're coming out of suspend. If someone tried to do a navigate while suspended, do one now instead. - if(mNavigateSuspendedDeferred) - { - mNavigateSuspendedDeferred = false; - navigateInternal(); - } - } - } -} - -void LLViewerMediaImpl::cancelMimeTypeProbe() -{ - if(mMimeTypeProbe != NULL) - { - // There doesn't seem to be a way to actually cancel an outstanding request. - // Simulate it by telling the LLMimeDiscoveryResponder not to write back any results. - mMimeTypeProbe->cancelRequest(); - - // The above should already have set mMimeTypeProbe to NULL. - if(mMimeTypeProbe != NULL) - { - llerrs << "internal error: mMimeTypeProbe is not NULL after cancelling request." << llendl; - } - } -} - -void LLViewerMediaImpl::addObject(LLVOVolume* obj) -{ - std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; - for(; iter != mObjectList.end() ; ++iter) - { - if(*iter == obj) - { - return ; //already in the list. - } - } - - mObjectList.push_back(obj) ; - mNeedsMuteCheck = true; -} - -void LLViewerMediaImpl::removeObject(LLVOVolume* obj) -{ - mObjectList.remove(obj) ; - mNeedsMuteCheck = true; -} - -const std::list< LLVOVolume* >* LLViewerMediaImpl::getObjectList() const -{ - return &mObjectList ; -} - -LLVOVolume *LLViewerMediaImpl::getSomeObject() -{ - LLVOVolume *result = NULL; - - std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; - if(iter != mObjectList.end()) - { - result = *iter; - } - - return result; -} - -void LLViewerMediaImpl::setTextureID(LLUUID id) -{ - if(id != mTextureId) - { - if(mTextureId.notNull()) - { - // Remove this item's entry from the map - sViewerMediaTextureIDMap.erase(mTextureId); - } - - if(id.notNull()) - { - sViewerMediaTextureIDMap.insert(LLViewerMedia::impl_id_map::value_type(id, this)); - } - - mTextureId = id; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::isAutoPlayable() const -{ - return (mMediaAutoPlay && - gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && - gSavedSettings.getBOOL("MediaTentativeAutoPlay")); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::shouldShowBasedOnClass() const -{ - // If this is parcel media or in the UI, return true always - if (getUsedInUI() || isParcelMedia()) return true; - - bool attached_to_another_avatar = isAttachedToAnotherAvatar(); - bool inside_parcel = isInAgentParcel(); - - // llinfos << " hasFocus = " << hasFocus() << - // " others = " << (attached_to_another_avatar && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING)) << - // " within = " << (inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING)) << - // " outside = " << (!inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING)) << llendl; - - // If it has focus, we should show it - // This is incorrect, and causes EXT-6750 (disabled attachment media still plays) -// if (hasFocus()) -// return true; - - // If it is attached to an avatar and the pref is off, we shouldn't show it - if (attached_to_another_avatar) - return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING); - - if (inside_parcel) - return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING); - else - return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::isAttachedToAnotherAvatar() const -{ - bool result = false; - - std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin(); - std::list< LLVOVolume* >::const_iterator end = mObjectList.end(); - for ( ; iter != end; iter++) - { - if (isObjectAttachedToAnotherAvatar(*iter)) - { - result = true; - break; - } - } - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -//static -bool LLViewerMediaImpl::isObjectAttachedToAnotherAvatar(LLVOVolume *obj) -{ - bool result = false; - LLXform *xform = obj; - // Walk up parent chain - while (NULL != xform) - { - LLViewerObject *object = dynamic_cast (xform); - if (NULL != object) - { - LLVOAvatar *avatar = object->asAvatar(); - if ((NULL != avatar) && (avatar != gAgentAvatarp)) - { - result = true; - break; - } - } - xform = xform->getParent(); - } - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::isInAgentParcel() const -{ - bool result = false; - - std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin(); - std::list< LLVOVolume* >::const_iterator end = mObjectList.end(); - for ( ; iter != end; iter++) - { - LLVOVolume *object = *iter; - if (LLViewerMediaImpl::isObjectInAgentParcel(object)) - { - result = true; - break; - } - } - return result; -} - -LLNotificationPtr LLViewerMediaImpl::getCurrentNotification() const -{ - return mNotification; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -// static -bool LLViewerMediaImpl::isObjectInAgentParcel(LLVOVolume *obj) -{ - return (LLViewerParcelMgr::getInstance()->inAgentParcel(obj->getPositionGlobal())); -} +/** + * @file llviewermedia.cpp + * @brief Client interface to the media engine + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llagent.h" +#include "llagentcamera.h" +#include "llviewermedia.h" +#include "llviewermediafocus.h" +#include "llmimetypes.h" +#include "llmediaentry.h" +#include "llversioninfo.h" +#include "llviewercontrol.h" +#include "llviewertexture.h" +#include "llviewerparcelmedia.h" +#include "llviewerparcelmgr.h" +#include "llviewertexturelist.h" +#include "llvovolume.h" +#include "llpluginclassmedia.h" +#include "llplugincookiestore.h" +#include "llviewerwindow.h" +#include "llfocusmgr.h" +#include "llcallbacklist.h" +#include "llparcel.h" +#include "llaudioengine.h" // for gAudiop +#include "llurldispatcher.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "llviewerregion.h" +#include "llwebsharing.h" // For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this! +#include "llfilepicker.h" +#include "llnotifications.h" +#include "lldir.h" +#include "llevent.h" // LLSimpleListener +#include "llnotificationsutil.h" +#include "lluuid.h" +#include "llkeyboard.h" +#include "llmutelist.h" +#include "llpanelprofile.h" +#include "llappviewer.h" +#include "lllogininstance.h" +//#include "llfirstuse.h" +#include "llwindow.h" + +#include "llfloatermediabrowser.h" // for handling window close requests and geometry change requests in media browser windows. +#include "llfloaterwebcontent.h" // for handling window close requests and geometry change requests in media browser windows. + +#include // for SkinFolder listener +#include + +/*static*/ const char* LLViewerMedia::AUTO_PLAY_MEDIA_SETTING = "ParcelMediaAutoPlayEnable"; +/*static*/ const char* LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING = "MediaShowOnOthers"; +/*static*/ const char* LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING = "MediaShowWithinParcel"; +/*static*/ const char* LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING = "MediaShowOutsideParcel"; + + +// Move this to its own file. + +LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter() +{ + observerListType::iterator iter = mObservers.begin(); + + while( iter != mObservers.end() ) + { + LLViewerMediaObserver *self = *iter; + iter++; + remObserver(self); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaEventEmitter::addObserver( LLViewerMediaObserver* observer ) +{ + if ( ! observer ) + return false; + + if ( std::find( mObservers.begin(), mObservers.end(), observer ) != mObservers.end() ) + return false; + + mObservers.push_back( observer ); + observer->mEmitters.push_back( this ); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer ) +{ + if ( ! observer ) + return false; + + mObservers.remove( observer ); + observer->mEmitters.remove(this); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLViewerMediaObserver::EMediaEvent event ) +{ + // Broadcast the event to any observers. + observerListType::iterator iter = mObservers.begin(); + while( iter != mObservers.end() ) + { + LLViewerMediaObserver *self = *iter; + ++iter; + self->handleMediaEvent( media, event ); + } +} + +// Move this to its own file. +LLViewerMediaObserver::~LLViewerMediaObserver() +{ + std::list::iterator iter = mEmitters.begin(); + + while( iter != mEmitters.end() ) + { + LLViewerMediaEventEmitter *self = *iter; + iter++; + self->remObserver( this ); + } +} + + +// Move this to its own file. +// helper class that tries to download a URL from a web site and calls a method +// on the Panel Land Media and to discover the MIME type +class LLMimeDiscoveryResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLMimeDiscoveryResponder); +public: + LLMimeDiscoveryResponder( viewer_media_t media_impl) + : mMediaImpl(media_impl), + mInitialized(false) + { + if(mMediaImpl->mMimeTypeProbe != NULL) + { + llerrs << "impl already has an outstanding responder" << llendl; + } + + mMediaImpl->mMimeTypeProbe = this; + } + + ~LLMimeDiscoveryResponder() + { + disconnectOwner(); + } + + virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + std::string media_type = content["content-type"].asString(); + std::string::size_type idx1 = media_type.find_first_of(";"); + std::string mime_type = media_type.substr(0, idx1); + + lldebugs << "status is " << status << ", media type \"" << media_type << "\"" << llendl; + + // 2xx status codes indicate success. + // Most 4xx status codes are successful enough for our purposes. + // 499 is the error code for host not found, timeout, etc. + // 500 means "Internal Server error" but we decided it's okay to + // accept this and go past it in the MIME type probe + // 302 means the resource can be found temporarily in a different place - added this for join.secondlife.com + // 499 is a code specifc to join.secondlife.com (????) apparently safe to ignore +// if( ((status >= 200) && (status < 300)) || +// ((status >= 400) && (status < 499)) || +// (status == 500) || +// (status == 302) || +// (status == 499) +// ) + // We now no longer check the error code returned from the probe. + // If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting. + if(1) + { + // The probe was successful. + if(mime_type.empty()) + { + // Some sites don't return any content-type header at all. + // Treat an empty mime type as text/html. + mime_type = "text/html"; + } + + completeAny(status, mime_type); + } + else + { + llwarns << "responder failed with status " << status << ", reason " << reason << llendl; + + if(mMediaImpl) + { + mMediaImpl->mMediaSourceFailed = true; + } + } + + } + + void completeAny(U32 status, const std::string& mime_type) + { + // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl. + // Make a local copy so we can call loadURI() afterwards. + LLViewerMediaImpl *impl = mMediaImpl; + + if(impl && !mInitialized && ! mime_type.empty()) + { + if(impl->initializeMedia(mime_type)) + { + mInitialized = true; + impl->loadURI(); + disconnectOwner(); + } + } + } + + void cancelRequest() + { + disconnectOwner(); + } + +private: + void disconnectOwner() + { + if(mMediaImpl) + { + if(mMediaImpl->mMimeTypeProbe != this) + { + llerrs << "internal error: mMediaImpl->mMimeTypeProbe != this" << llendl; + } + + mMediaImpl->mMimeTypeProbe = NULL; + } + mMediaImpl = NULL; + } + + +public: + LLViewerMediaImpl *mMediaImpl; + bool mInitialized; +}; + +class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLViewerMediaOpenIDResponder); +public: + LLViewerMediaOpenIDResponder( ) + { + } + + ~LLViewerMediaOpenIDResponder() + { + } + + /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; + LL_DEBUGS("MediaAuth") << content << LL_ENDL; + std::string cookie = content["set-cookie"].asString(); + + LLViewerMedia::openIDCookieResponse(cookie); + } + + /* virtual */ void completedRaw( + U32 status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + // This is just here to disable the default behavior (attempting to parse the response as llsd). + // We don't care about the content of the response, only the set-cookie header. + } + +}; + +class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLViewerMediaWebProfileResponder); +public: + LLViewerMediaWebProfileResponder(std::string host) + { + mHost = host; + } + + ~LLViewerMediaWebProfileResponder() + { + } + + /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; + LL_WARNS("MediaAuth") << content << LL_ENDL; + + std::string cookie = content["set-cookie"].asString(); + + LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost); + } + + void completedRaw( + U32 status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + // This is just here to disable the default behavior (attempting to parse the response as llsd). + // We don't care about the content of the response, only the set-cookie header. + } + + std::string mHost; +}; + + +LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL; +LLURL LLViewerMedia::sOpenIDURL; +std::string LLViewerMedia::sOpenIDCookie; +LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL; +static LLViewerMedia::impl_list sViewerMediaImplList; +static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap; +static LLTimer sMediaCreateTimer; +static const F32 LLVIEWERMEDIA_CREATE_DELAY = 1.0f; +static F32 sGlobalVolume = 1.0f; +static F64 sLowestLoadableImplInterest = 0.0f; +static bool sAnyMediaShowing = false; +static boost::signals2::connection sTeleportFinishConnection; +static std::string sUpdatedCookies; +static const char *PLUGIN_COOKIE_FILE_NAME = "plugin_cookies.txt"; + +////////////////////////////////////////////////////////////////////////////////////////// +static void add_media_impl(LLViewerMediaImpl* media) +{ + sViewerMediaImplList.push_back(media); +} + +////////////////////////////////////////////////////////////////////////////////////////// +static void remove_media_impl(LLViewerMediaImpl* media) +{ + LLViewerMedia::impl_list::iterator iter = sViewerMediaImplList.begin(); + LLViewerMedia::impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + if(media == *iter) + { + sViewerMediaImplList.erase(iter); + return; + } + } +} + +class LLViewerMediaMuteListObserver : public LLMuteListObserver +{ + /* virtual */ void onChange() { LLViewerMedia::muteListChanged();} +}; + +static LLViewerMediaMuteListObserver sViewerMediaMuteListObserver; +static bool sViewerMediaMuteListObserverInitialized = false; +static bool sInWorldMediaDisabled = false; + + +////////////////////////////////////////////////////////////////////////////////////////// +// LLViewerMedia + +////////////////////////////////////////////////////////////////////////////////////////// +// static +viewer_media_t LLViewerMedia::newMediaImpl( + const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop) +{ + LLViewerMediaImpl* media_impl = getMediaImplFromTextureID(texture_id); + if(media_impl == NULL || texture_id.isNull()) + { + // Create the media impl + media_impl = new LLViewerMediaImpl(texture_id, media_width, media_height, media_auto_scale, media_loop); + } + else + { + media_impl->unload(); + media_impl->setTextureID(texture_id); + media_impl->mMediaWidth = media_width; + media_impl->mMediaHeight = media_height; + media_impl->mMediaAutoScale = media_auto_scale; + media_impl->mMediaLoop = media_loop; + } + + return media_impl; +} + +viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self) +{ + // Try to find media with the same media ID + viewer_media_t media_impl = getMediaImplFromTextureID(media_entry->getMediaID()); + + lldebugs << "called, current URL is \"" << media_entry->getCurrentURL() + << "\", previous URL is \"" << previous_url + << "\", update_from_self is " << (update_from_self?"true":"false") + << llendl; + + bool was_loaded = false; + bool needs_navigate = false; + + if(media_impl) + { + was_loaded = media_impl->hasMedia(); + + media_impl->setHomeURL(media_entry->getHomeURL()); + + media_impl->mMediaAutoScale = media_entry->getAutoScale(); + media_impl->mMediaLoop = media_entry->getAutoLoop(); + media_impl->mMediaWidth = media_entry->getWidthPixels(); + media_impl->mMediaHeight = media_entry->getHeightPixels(); + media_impl->mMediaAutoPlay = media_entry->getAutoPlay(); + media_impl->mMediaEntryURL = media_entry->getCurrentURL(); + if (media_impl->mMediaSource) + { + media_impl->mMediaSource->setAutoScale(media_impl->mMediaAutoScale); + media_impl->mMediaSource->setLoop(media_impl->mMediaLoop); + media_impl->mMediaSource->setSize(media_entry->getWidthPixels(), media_entry->getHeightPixels()); + } + + bool url_changed = (media_impl->mMediaEntryURL != previous_url); + if(media_impl->mMediaEntryURL.empty()) + { + if(url_changed) + { + // The current media URL is now empty. Unload the media source. + media_impl->unload(); + + lldebugs << "Unloading media instance (new current URL is empty)." << llendl; + } + } + else + { + // The current media URL is not empty. + // If (the media was already loaded OR the media was set to autoplay) AND this update didn't come from this agent, + // do a navigate. + bool auto_play = media_impl->isAutoPlayable(); + if((was_loaded || auto_play) && !update_from_self) + { + needs_navigate = url_changed; + } + + lldebugs << "was_loaded is " << (was_loaded?"true":"false") + << ", auto_play is " << (auto_play?"true":"false") + << ", needs_navigate is " << (needs_navigate?"true":"false") << llendl; + } + } + else + { + media_impl = newMediaImpl( + media_entry->getMediaID(), + media_entry->getWidthPixels(), + media_entry->getHeightPixels(), + media_entry->getAutoScale(), + media_entry->getAutoLoop()); + + media_impl->setHomeURL(media_entry->getHomeURL()); + media_impl->mMediaAutoPlay = media_entry->getAutoPlay(); + media_impl->mMediaEntryURL = media_entry->getCurrentURL(); + if(media_impl->isAutoPlayable()) + { + needs_navigate = true; + } + } + + if(media_impl) + { + if(needs_navigate) + { + media_impl->navigateTo(media_impl->mMediaEntryURL, "", true, true); + lldebugs << "navigating to URL " << media_impl->mMediaEntryURL << llendl; + } + else if(!media_impl->mMediaURL.empty() && (media_impl->mMediaURL != media_impl->mMediaEntryURL)) + { + // If we already have a non-empty media URL set and we aren't doing a navigate, update the media URL to match the media entry. + media_impl->mMediaURL = media_impl->mMediaEntryURL; + + // If this causes a navigate at some point (such as after a reload), it should be considered server-driven so it isn't broadcast. + media_impl->mNavigateServerRequest = true; + + lldebugs << "updating URL in the media impl to " << media_impl->mMediaEntryURL << llendl; + } + } + + return media_impl; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& texture_id) +{ + LLViewerMediaImpl* result = NULL; + + // Look up the texture ID in the texture id->impl map. + impl_id_map::iterator iter = sViewerMediaTextureIDMap.find(texture_id); + if(iter != sViewerMediaTextureIDMap.end()) + { + result = iter->second; + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +std::string LLViewerMedia::getCurrentUserAgent() +{ + // Don't use user-visible string to avoid + // punctuation and strange characters. + std::string skin_name = gSavedSettings.getString("SkinCurrent"); + + // Just in case we need to check browser differences in A/B test + // builds. + std::string channel = LLVersionInfo::getChannel(); + + // append our magic version number string to the browser user agent id + // See the HTTP 1.0 and 1.1 specifications for allowed formats: + // http://www.ietf.org/rfc/rfc1945.txt section 10.15 + // http://www.ietf.org/rfc/rfc2068.txt section 3.8 + // This was also helpful: + // http://www.mozilla.org/build/revised-user-agent-strings.html + std::ostringstream codec; + codec << "SecondLife/"; + codec << LLVersionInfo::getVersion(); + codec << " (" << channel << "; " << skin_name << " skin)"; + llinfos << codec.str() << llendl; + + return codec.str(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::updateBrowserUserAgent() +{ + std::string user_agent = getCurrentUserAgent(); + + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource && pimpl->mMediaSource->pluginSupportsMediaBrowser()) + { + pimpl->mMediaSource->setBrowserUserAgent(user_agent); + } + } + +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::handleSkinCurrentChanged(const LLSD& /*newvalue*/) +{ + // gSavedSettings is already updated when this function is called. + updateBrowserUserAgent(); + return true; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id) +{ + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->getMediaTextureID() == texture_id) + { + return true; + } + } + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setVolume(F32 volume) +{ + if(volume != sGlobalVolume) + { + sGlobalVolume = volume; + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + pimpl->updateVolume(); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +F32 LLViewerMedia::getVolume() +{ + return sGlobalVolume; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::muteListChanged() +{ + // When the mute list changes, we need to check mute status on all impls. + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + pimpl->mNeedsMuteCheck = true; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setInWorldMediaDisabled(bool disabled) +{ + sInWorldMediaDisabled = disabled; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::getInWorldMediaDisabled() +{ + return sInWorldMediaDisabled; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::isInterestingEnough(const LLVOVolume *object, const F64 &object_interest) +{ + bool result = false; + + if (NULL == object) + { + result = false; + } + // Focused? Then it is interesting! + else if (LLViewerMediaFocus::getInstance()->getFocusedObjectID() == object->getID()) + { + result = true; + } + // Selected? Then it is interesting! + // XXX Sadly, 'contains()' doesn't take a const :( + else if (LLSelectMgr::getInstance()->getSelection()->contains(const_cast(object))) + { + result = true; + } + else + { + lldebugs << "object interest = " << object_interest << ", lowest loadable = " << sLowestLoadableImplInterest << llendl; + if(object_interest >= sLowestLoadableImplInterest) + result = true; + } + + return result; +} + +LLViewerMedia::impl_list &LLViewerMedia::getPriorityList() +{ + return sViewerMediaImplList; +} + +// This is the predicate function used to sort sViewerMediaImplList by priority. +bool LLViewerMedia::priorityComparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2) +{ + if(i1->isForcedUnloaded() && !i2->isForcedUnloaded()) + { + // Muted or failed items always go to the end of the list, period. + return false; + } + else if(i2->isForcedUnloaded() && !i1->isForcedUnloaded()) + { + // Muted or failed items always go to the end of the list, period. + return true; + } + else if(i1->hasFocus()) + { + // The item with user focus always comes to the front of the list, period. + return true; + } + else if(i2->hasFocus()) + { + // The item with user focus always comes to the front of the list, period. + return false; + } + else if(i1->isParcelMedia()) + { + // The parcel media impl sorts above all other inworld media, unless one has focus. + return true; + } + else if(i2->isParcelMedia()) + { + // The parcel media impl sorts above all other inworld media, unless one has focus. + return false; + } + else if(i1->getUsedInUI() && !i2->getUsedInUI()) + { + // i1 is a UI element, i2 is not. This makes i1 "less than" i2, so it sorts earlier in our list. + return true; + } + else if(i2->getUsedInUI() && !i1->getUsedInUI()) + { + // i2 is a UI element, i1 is not. This makes i2 "less than" i1, so it sorts earlier in our list. + return false; + } + else if(i1->isPlayable() && !i2->isPlayable()) + { + // Playable items sort above ones that wouldn't play even if they got high enough priority + return true; + } + else if(!i1->isPlayable() && i2->isPlayable()) + { + // Playable items sort above ones that wouldn't play even if they got high enough priority + return false; + } + else if(i1->getInterest() == i2->getInterest()) + { + // Generally this will mean both objects have zero interest. In this case, sort on distance. + return (i1->getProximityDistance() < i2->getProximityDistance()); + } + else + { + // The object with the larger interest value should be earlier in the list, so we reverse the sense of the comparison here. + return (i1->getInterest() > i2->getInterest()); + } +} + +static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2) +{ + if(i1->getProximityDistance() < i2->getProximityDistance()) + { + return true; + } + else if(i1->getProximityDistance() > i2->getProximityDistance()) + { + return false; + } + else + { + // Both objects have the same distance. This most likely means they're two faces of the same object. + // They may also be faces on different objects with exactly the same distance (like HUD objects). + // We don't actually care what the sort order is for this case, as long as it's stable and doesn't change when you enable/disable media. + // Comparing the impl pointers gives a completely arbitrary ordering, but it will be stable. + return (i1 < i2); + } +} + +static LLFastTimer::DeclareTimer FTM_MEDIA_UPDATE("Update Media"); + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::updateMedia(void *dummy_arg) +{ + LLFastTimer t1(FTM_MEDIA_UPDATE); + + // Enable/disable the plugin read thread + LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread")); + + // HACK: we always try to keep a spare running webkit plugin around to improve launch times. + createSpareBrowserMediaSource(); + + sAnyMediaShowing = false; + sUpdatedCookies = getCookieStore()->getChangedCookies(); + if(!sUpdatedCookies.empty()) + { + lldebugs << "updated cookies will be sent to all loaded plugins: " << llendl; + lldebugs << sUpdatedCookies << llendl; + } + + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end;) + { + LLViewerMediaImpl* pimpl = *iter++; + pimpl->update(); + pimpl->calculateInterest(); + } + + // Let the spare media source actually launch + if(sSpareBrowserMediaSource) + { + sSpareBrowserMediaSource->idle(); + } + + // Sort the static instance list using our interest criteria + sViewerMediaImplList.sort(priorityComparitor); + + // Go through the list again and adjust according to priority. + iter = sViewerMediaImplList.begin(); + end = sViewerMediaImplList.end(); + + F64 total_cpu = 0.0f; + int impl_count_total = 0; + int impl_count_interest_low = 0; + int impl_count_interest_normal = 0; + + std::vector proximity_order; + + bool inworld_media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia"); + bool inworld_audio_enabled = gSavedSettings.getBOOL("AudioStreamingMusic"); + U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal"); + U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal"); + U32 max_low = gSavedSettings.getU32("PluginInstancesLow"); + F32 max_cpu = gSavedSettings.getF32("PluginInstancesCPULimit"); + // Setting max_cpu to 0.0 disables CPU usage checking. + bool check_cpu_usage = (max_cpu != 0.0f); + + LLViewerMediaImpl* lowest_interest_loadable = NULL; + + // Notes on tweakable params: + // max_instances must be set high enough to allow the various instances used in the UI (for the help browser, search, etc.) to be loaded. + // If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow. + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + + LLPluginClassMedia::EPriority new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + + if(pimpl->isForcedUnloaded() || (impl_count_total >= (int)max_instances)) + { + // Never load muted or failed impls. + // Hard limit on the number of instances that will be loaded at one time + new_priority = LLPluginClassMedia::PRIORITY_UNLOADED; + } + else if(!pimpl->getVisible()) + { + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + else if(pimpl->hasFocus()) + { + new_priority = LLPluginClassMedia::PRIORITY_HIGH; + impl_count_interest_normal++; // count this against the count of "normal" instances for priority purposes + } + else if(pimpl->getUsedInUI()) + { + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + impl_count_interest_normal++; + } + else if(pimpl->isParcelMedia()) + { + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + impl_count_interest_normal++; + } + else + { + // Look at interest and CPU usage for instances that aren't in any of the above states. + + // Heuristic -- if the media texture's approximate screen area is less than 1/4 of the native area of the texture, + // turn it down to low instead of normal. This may downsample for plugins that support it. + bool media_is_small = false; + F64 approximate_interest = pimpl->getApproximateTextureInterest(); + if(approximate_interest == 0.0f) + { + // this media has no current size, which probably means it's not loaded. + media_is_small = true; + } + else if(pimpl->getInterest() < (approximate_interest / 4)) + { + media_is_small = true; + } + + if(pimpl->getInterest() == 0.0f) + { + // This media is completely invisible, due to being outside the view frustrum or out of range. + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + else if(check_cpu_usage && (total_cpu > max_cpu)) + { + // Higher priority plugins have already used up the CPU budget. Set remaining ones to slideshow priority. + new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; + } + else if((impl_count_interest_normal < (int)max_normal) && !media_is_small) + { + // Up to max_normal inworld get normal priority + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + impl_count_interest_normal++; + } + else if (impl_count_interest_low + impl_count_interest_normal < (int)max_low + (int)max_normal) + { + // The next max_low inworld get turned down + new_priority = LLPluginClassMedia::PRIORITY_LOW; + impl_count_interest_low++; + + // Set the low priority size for downsampling to approximately the size the texture is displayed at. + { + F32 approximate_interest_dimension = fsqrtf(pimpl->getInterest()); + + pimpl->setLowPrioritySizeLimit(llround(approximate_interest_dimension)); + } + } + else + { + // Any additional impls (up to max_instances) get very infrequent time + new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; + } + } + + if(!pimpl->getUsedInUI() && (new_priority != LLPluginClassMedia::PRIORITY_UNLOADED)) + { + // This is a loadable inworld impl -- the last one in the list in this class defines the lowest loadable interest. + lowest_interest_loadable = pimpl; + + impl_count_total++; + } + + // Overrides if the window is minimized or we lost focus (taking care + // not to accidentally "raise" the priority either) + if (!gViewerWindow->getActive() /* viewer window minimized? */ + && new_priority > LLPluginClassMedia::PRIORITY_HIDDEN) + { + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + else if (!gFocusMgr.getAppHasFocus() /* viewer window lost focus? */ + && new_priority > LLPluginClassMedia::PRIORITY_LOW) + { + new_priority = LLPluginClassMedia::PRIORITY_LOW; + } + + if(!inworld_media_enabled) + { + // If inworld media is locked out, force all inworld media to stay unloaded. + if(!pimpl->getUsedInUI()) + { + new_priority = LLPluginClassMedia::PRIORITY_UNLOADED; + } + } + // update the audio stream here as well + if( !inworld_audio_enabled) + { + if(LLViewerMedia::isParcelAudioPlaying() && gAudiop && LLViewerMedia::hasParcelAudio()) + { + gAudiop->stopInternetStream(); + } + } + pimpl->setPriority(new_priority); + + if(pimpl->getUsedInUI()) + { + // Any impls used in the UI should not be in the proximity list. + pimpl->mProximity = -1; + } + else + { + proximity_order.push_back(pimpl); + } + + total_cpu += pimpl->getCPUUsage(); + + if (!pimpl->getUsedInUI() && pimpl->hasMedia()) + { + sAnyMediaShowing = true; + } + + } + + // Re-calculate this every time. + sLowestLoadableImplInterest = 0.0f; + + // Only do this calculation if we've hit the impl count limit -- up until that point we always need to load media data. + if(lowest_interest_loadable && (impl_count_total >= (int)max_instances)) + { + // Get the interest value of this impl's object for use by isInterestingEnough + LLVOVolume *object = lowest_interest_loadable->getSomeObject(); + if(object) + { + // NOTE: Don't use getMediaInterest() here. We want the pixel area, not the total media interest, + // so that we match up with the calculation done in LLMediaDataClient. + sLowestLoadableImplInterest = object->getPixelArea(); + } + } + + if(gSavedSettings.getBOOL("MediaPerformanceManagerDebug")) + { + // Give impls the same ordering as the priority list + // they're already in the right order for this. + } + else + { + // Use a distance-based sort for proximity values. + std::stable_sort(proximity_order.begin(), proximity_order.end(), proximity_comparitor); + } + + // Transfer the proximity order to the proximity fields in the objects. + for(int i = 0; i < (int)proximity_order.size(); i++) + { + proximity_order[i]->mProximity = i; + } + + LL_DEBUGS("PluginPriority") << "Total reported CPU usage is " << total_cpu << llendl; + +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::isAnyMediaShowing() +{ + return sAnyMediaShowing; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setAllMediaEnabled(bool val) +{ + // Set "tentative" autoplay first. We need to do this here or else + // re-enabling won't start up the media below. + gSavedSettings.setBOOL("MediaTentativeAutoPlay", val); + + // Then + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if (!pimpl->getUsedInUI()) + { + pimpl->setDisabled(!val); + } + } + + // Also do Parcel Media and Parcel Audio + if (val) + { + if (!LLViewerMedia::isParcelMediaPlaying() && LLViewerMedia::hasParcelMedia()) + { + LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel()); + } + + if (gSavedSettings.getBOOL("AudioStreamingMusic") && + !LLViewerMedia::isParcelAudioPlaying() && + gAudiop && + LLViewerMedia::hasParcelAudio()) + { + gAudiop->startInternetStream(LLViewerMedia::getParcelAudioURL()); + } + } + else { + // This actually unloads the impl, as opposed to "stop"ping the media + LLViewerParcelMedia::stop(); + if (gAudiop) gAudiop->stopInternetStream(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::isParcelMediaPlaying() +{ + return (LLViewerMedia::hasParcelMedia() && LLViewerParcelMedia::getParcelMedia() && LLViewerParcelMedia::getParcelMedia()->hasMedia()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::isParcelAudioPlaying() +{ + return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying()); +} + +void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response) +{ + LLViewerMediaImpl *impl = LLViewerMedia::getMediaImplFromTextureID(notification["payload"]["media_id"]); + if(impl) + { + LLPluginClassMedia* media = impl->getMediaPlugin(); + if(media) + { + if (response["ok"]) + { + media->sendAuthResponse(true, response["username"], response["password"]); + } + else + { + media->sendAuthResponse(false, "", ""); + } + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::clearAllCookies() +{ + // Clear all cookies for all plugins + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource) + { + pimpl->mMediaSource->clear_cookies(); + } + } + + // Clear all cookies from the cookie store + getCookieStore()->setAllCookies(""); + + // FIXME: this may not be sufficient, since the on-disk cookie file won't get written until some browser instance exits cleanly. + // It also won't clear cookies for other accounts, or for any account if we're not logged in, and won't do anything at all if there are no webkit plugins loaded. + // Until such time as we can centralize cookie storage, the following hack should cover these cases: + + // HACK: Look for cookie files in all possible places and delete them. + // NOTE: this assumes knowledge of what happens inside the webkit plugin (it's what adds 'browser_profile' to the path and names the cookie file) + + // Places that cookie files can be: + // /browser_profile/cookies + // /first_last/browser_profile/cookies (note that there may be any number of these!) + // /first_last/plugin_cookies.txt (note that there may be any number of these!) + + std::string base_dir = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter(); + std::string target; + std::string filename; + + lldebugs << "base dir = " << base_dir << llendl; + + // The non-logged-in version is easy + target = base_dir; + target += "browser_profile"; + target += gDirUtilp->getDirDelimiter(); + target += "cookies"; + lldebugs << "target = " << target << llendl; + if(LLFile::isfile(target)) + { + LLFile::remove(target); + } + + // the hard part: iterate over all user directories and delete the cookie file from each one + while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename)) + { + target = base_dir; + target += filename; + target += gDirUtilp->getDirDelimiter(); + target += "browser_profile"; + target += gDirUtilp->getDirDelimiter(); + target += "cookies"; + lldebugs << "target = " << target << llendl; + if(LLFile::isfile(target)) + { + LLFile::remove(target); + } + + // Other accounts may have new-style cookie files too -- delete them as well + target = base_dir; + target += filename; + target += gDirUtilp->getDirDelimiter(); + target += PLUGIN_COOKIE_FILE_NAME; + lldebugs << "target = " << target << llendl; + if(LLFile::isfile(target)) + { + LLFile::remove(target); + } + } + + // If we have an OpenID cookie, re-add it to the cookie store. + setOpenIDCookie(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::clearAllCaches() +{ + // Clear all plugins' caches + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + pimpl->clearCache(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setCookiesEnabled(bool enabled) +{ + // Set the "cookies enabled" flag for all loaded plugins + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource) + { + pimpl->mMediaSource->enable_cookies(enabled); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int port) +{ + // Set the proxy config for all loaded plugins + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource) + { + pimpl->mMediaSource->proxy_setup(enable, host, port); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +///////////////////////////////////////////////////////////////////////////////////////// +// static +LLPluginCookieStore *LLViewerMedia::getCookieStore() +{ + if(sCookieStore == NULL) + { + sCookieStore = new LLPluginCookieStore; + } + + return sCookieStore; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::loadCookieFile() +{ + // build filename for each user + std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); + + if (resolved_filename.empty()) + { + llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; + return; + } + + // open the file for reading + llifstream file(resolved_filename); + if (!file.is_open()) + { + llwarns << "can't load plugin cookies from file \"" << PLUGIN_COOKIE_FILE_NAME << "\"" << llendl; + return; + } + + getCookieStore()->readAllCookies(file, true); + + file.close(); + + // send the clear_cookies message to all loaded plugins + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource) + { + pimpl->mMediaSource->clear_cookies(); + } + } + + // If we have an OpenID cookie, re-add it to the cookie store. + setOpenIDCookie(); +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::saveCookieFile() +{ + // build filename for each user + std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); + + if (resolved_filename.empty()) + { + llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; + return; + } + + // open a file for writing + llofstream file (resolved_filename); + if (!file.is_open()) + { + llwarns << "can't open plugin cookie file \"" << PLUGIN_COOKIE_FILE_NAME << "\" for writing" << llendl; + return; + } + + getCookieStore()->writePersistentCookies(file); + + file.close(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path, bool secure) +{ + std::stringstream cookie; + + cookie << name << "=" << LLPluginCookieStore::quoteString(value); + + if(expires.notNull()) + { + cookie << "; expires=" << expires.asRFC1123(); + } + + cookie << "; domain=" << domain; + + cookie << "; path=" << path; + + if(secure) + { + cookie << "; secure"; + } + + getCookieStore()->setCookies(cookie.str()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path, bool secure) +{ + // A session cookie just has a NULL date. + addCookie(name, value, domain, LLDate(), path, secure); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::removeCookie(const std::string &name, const std::string &domain, const std::string &path ) +{ + // To remove a cookie, add one with the same name, domain, and path that expires in the past. + + addCookie(name, "", domain, LLDate(LLDate::now().secondsSinceEpoch() - 1.0), path); +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setOpenIDCookie() +{ + if(!sOpenIDCookie.empty()) + { + // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port] + // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that. + // We therefore do it here. + std::string authority = sOpenIDURL.mAuthority; + std::string::size_type host_start = authority.find('@'); + if(host_start == std::string::npos) + { + // no username/password + host_start = 0; + } + else + { + // Hostname starts after the @. + // (If the hostname part is empty, this may put host_start at the end of the string. In that case, it will end up passing through an empty hostname, which is correct.) + ++host_start; + } + std::string::size_type host_end = authority.rfind(':'); + if((host_end == std::string::npos) || (host_end < host_start)) + { + // no port + host_end = authority.size(); + } + + getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start)); + + // *HACK: Doing this here is nasty, find a better way. + LLWebSharing::instance().setOpenIDCookie(sOpenIDCookie); + + // Do a web profile get so we can store the cookie + LLSD headers = LLSD::emptyMap(); + headers["Accept"] = "*/*"; + headers["Cookie"] = sOpenIDCookie; + headers["User-Agent"] = getCurrentUserAgent(); + + std::string profile_url = getProfileURL(""); + LLURL raw_profile_url( profile_url.c_str() ); + + LLHTTPClient::get(profile_url, + new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()), + headers); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token) +{ + LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL; + + // post the token to the url + // the responder will need to extract the cookie(s). + + // Save the OpenID URL for later -- we may need the host when adding the cookie. + sOpenIDURL.init(openid_url.c_str()); + + // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. + sOpenIDCookie.clear(); + + LLSD headers = LLSD::emptyMap(); + // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header + headers["Accept"] = "*/*"; + // and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" + headers["Content-Type"] = "application/x-www-form-urlencoded"; + + // postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here. + size_t size = openid_token.size(); + U8 *data = new U8[size]; + memcpy(data, openid_token.data(), size); + + LLHTTPClient::postRaw( + openid_url, + data, + size, + new LLViewerMediaOpenIDResponder(), + headers); + +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::openIDCookieResponse(const std::string &cookie) +{ + LL_DEBUGS("MediaAuth") << "Cookie received: \"" << cookie << "\"" << LL_ENDL; + + sOpenIDCookie += cookie; + + setOpenIDCookie(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::proxyWindowOpened(const std::string &target, const std::string &uuid) +{ + if(uuid.empty()) + return; + + for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++) + { + if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser()) + { + (*iter)->mMediaSource->proxyWindowOpened(target, uuid); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::proxyWindowClosed(const std::string &uuid) +{ + if(uuid.empty()) + return; + + for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++) + { + if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser()) + { + (*iter)->mMediaSource->proxyWindowClosed(uuid); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::createSpareBrowserMediaSource() +{ + // If we don't have a spare browser media source, create one. + // However, if PluginAttachDebuggerToPlugins is set then don't spawn a spare + // SLPlugin process in order to not be confused by an unrelated gdb terminal + // popping up at the moment we start a media plugin. + if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) + { + // The null owner will keep the browser plugin from fully initializing + // (specifically, it keeps LLPluginClassMedia from negotiating a size change, + // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) + sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource() +{ + LLPluginClassMedia* result = sSpareBrowserMediaSource; + sSpareBrowserMediaSource = NULL; + return result; +}; + +bool LLViewerMedia::hasInWorldMedia() +{ + if (sInWorldMediaDisabled) return false; + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + // This should be quick, because there should be very few non-in-world-media impls + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if (!pimpl->getUsedInUI() && !pimpl->isParcelMedia()) + { + // Found an in-world media impl + return true; + } + } + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::hasParcelMedia() +{ + return !LLViewerParcelMedia::getURL().empty(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::hasParcelAudio() +{ + return !LLViewerMedia::getParcelAudioURL().empty(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +std::string LLViewerMedia::getParcelAudioURL() +{ + return LLViewerParcelMgr::getInstance()->getAgentParcel()->getMusicURL(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::initClass() +{ + gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, NULL); + sTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> + setTeleportFinishedCallback(boost::bind(&LLViewerMedia::onTeleportFinished)); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::cleanupClass() +{ + gIdleCallbacks.deleteFunction(LLViewerMedia::updateMedia, NULL); + sTeleportFinishConnection.disconnect(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::onTeleportFinished() +{ + // On teleport, clear this setting (i.e. set it to true) + gSavedSettings.setBOOL("MediaTentativeAutoPlay", true); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// LLViewerMediaImpl +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop) +: + mMediaSource( NULL ), + mMovieImageHasMips(false), + mMediaWidth(media_width), + mMediaHeight(media_height), + mMediaAutoScale(media_auto_scale), + mMediaLoop(media_loop), + mNeedsNewTexture(true), + mTextureUsedWidth(0), + mTextureUsedHeight(0), + mSuspendUpdates(false), + mVisible(true), + mLastSetCursor( UI_CURSOR_ARROW ), + mMediaNavState( MEDIANAVSTATE_NONE ), + mInterest(0.0f), + mUsedInUI(false), + mHasFocus(false), + mPriority(LLPluginClassMedia::PRIORITY_UNLOADED), + mNavigateRediscoverType(false), + mNavigateServerRequest(false), + mMediaSourceFailed(false), + mRequestedVolume(1.0f), + mIsMuted(false), + mNeedsMuteCheck(false), + mPreviousMediaState(MEDIA_NONE), + mPreviousMediaTime(0.0f), + mIsDisabled(false), + mIsParcelMedia(false), + mProximity(-1), + mProximityDistance(0.0f), + mMimeTypeProbe(NULL), + mMediaAutoPlay(false), + mInNearbyMediaList(false), + mClearCache(false), + mBackgroundColor(LLColor4::white), + mNavigateSuspended(false), + mNavigateSuspendedDeferred(false), + mIsUpdated(false), + mTrustedBrowser(false) +{ + + // Set up the mute list observer if it hasn't been set up already. + if(!sViewerMediaMuteListObserverInitialized) + { + LLMuteList::getInstance()->addObserver(&sViewerMediaMuteListObserver); + sViewerMediaMuteListObserverInitialized = true; + } + + add_media_impl(this); + + setTextureID(texture_id); + + // connect this media_impl to the media texture, creating it if it doesn't exist.0 + // This is necessary because we need to be able to use getMaxVirtualSize() even if the media plugin is not loaded. + LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture(mTextureId); + if(media_tex) + { + media_tex->setMediaImpl(); + } + +} + +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaImpl::~LLViewerMediaImpl() +{ + destroyMediaSource(); + + LLViewerMediaTexture::removeMediaImplFromTexture(mTextureId) ; + + setTextureID(); + remove_media_impl(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::emitEvent(LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event) +{ + // Broadcast to observers using the superclass version + LLViewerMediaEventEmitter::emitEvent(plugin, event); + + // If this media is on one or more LLVOVolume objects, tell them about the event as well. + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + while(iter != mObjectList.end()) + { + LLVOVolume *self = *iter; + ++iter; + self->mediaEvent(this, plugin, event); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) +{ + bool mimeTypeChanged = (mMimeType != mime_type); + bool pluginChanged = (LLMIMETypes::implType(mCurrentMimeType) != LLMIMETypes::implType(mime_type)); + + if(!mMediaSource || pluginChanged) + { + // We don't have a plugin at all, or the new mime type is handled by a different plugin than the old mime type. + (void)initializePlugin(mime_type); + } + else if(mimeTypeChanged) + { + // The same plugin should be able to handle the new media -- just update the stored mime type. + mMimeType = mime_type; + } + + return (mMediaSource != NULL); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::createMediaSource() +{ + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This media shouldn't be created yet. + return; + } + + if(! mMediaURL.empty()) + { + navigateInternal(); + } + else if(! mMimeType.empty()) + { + if (!initializeMedia(mMimeType)) + { + LL_WARNS("Media") << "Failed to initialize media for mime type " << mMimeType << LL_ENDL; + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::destroyMediaSource() +{ + mNeedsNewTexture = true; + + // Tell the viewer media texture it's no longer active + LLViewerMediaTexture* oldImage = LLViewerTextureManager::findMediaTexture( mTextureId ); + if (oldImage) + { + oldImage->setPlaying(FALSE) ; + } + + cancelMimeTypeProbe(); + + if(mMediaSource) + { + mMediaSource->setDeleteOK(true) ; + delete mMediaSource; + mMediaSource = NULL; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setMediaType(const std::string& media_type) +{ + mMimeType = media_type; +} + +////////////////////////////////////////////////////////////////////////////////////////// +/*static*/ +LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target) +{ + std::string plugin_basename = LLMIMETypes::implType(media_type); + LLPluginClassMedia* media_source = NULL; + + // HACK: we always try to keep a spare running webkit plugin around to improve launch times. + // If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it. + if(plugin_basename == "media_plugin_webkit" && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) + { + media_source = LLViewerMedia::getSpareBrowserMediaSource(); + if(media_source) + { + media_source->setOwner(owner); + media_source->setTarget(target); + media_source->setSize(default_width, default_height); + + return media_source; + } + } + + if(plugin_basename.empty()) + { + LL_WARNS("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL; + } + else + { + std::string launcher_name = gDirUtilp->getLLPluginLauncher(); + std::string plugin_name = gDirUtilp->getLLPluginFilename(plugin_basename); + std::string user_data_path = gDirUtilp->getOSUserAppDir(); + user_data_path += gDirUtilp->getDirDelimiter(); + + // Fix for EXT-5960 - make browser profile specific to user (cache, cookies etc.) + // If the linden username returned is blank, that can only mean we are + // at the login page displaying login Web page or Web browser test via Develop menu. + // In this case we just use whatever gDirUtilp->getOSUserAppDir() gives us (this + // is what we always used before this change) + std::string linden_user_dir = gDirUtilp->getLindenUserDir(); + if ( ! linden_user_dir.empty() ) + { + // gDirUtilp->getLindenUserDir() is whole path, not just Linden name + user_data_path = linden_user_dir; + user_data_path += gDirUtilp->getDirDelimiter(); + }; + + // See if the plugin executable exists + llstat s; + if(LLFile::stat(launcher_name, &s)) + { + LL_WARNS("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL; + } + else if(LLFile::stat(plugin_name, &s)) + { + LL_WARNS("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; + } + else + { + media_source = new LLPluginClassMedia(owner); + media_source->setSize(default_width, default_height); + media_source->setUserDataPath(user_data_path); + media_source->setLanguageCode(LLUI::getLanguage()); + + // collect 'cookies enabled' setting from prefs and send to embedded browser + bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" ); + media_source->enable_cookies( cookies_enabled ); + + // collect 'plugins enabled' setting from prefs and send to embedded browser + bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" ); + media_source->setPluginsEnabled( plugins_enabled ); + + // collect 'javascript enabled' setting from prefs and send to embedded browser + bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" ); + media_source->setJavascriptEnabled( javascript_enabled ); + + media_source->setTarget(target); + + const std::string plugin_dir = gDirUtilp->getLLPluginDir(); + if (media_source->init(launcher_name, plugin_dir, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))) + { + return media_source; + } + else + { + LL_WARNS("Media") << "Failed to init plugin. Destroying." << LL_ENDL; + delete media_source; + } + } + } + + LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << media_type << LL_ENDL; + LLSD args; + args["MIME_TYPE"] = media_type; + LLNotificationsUtil::add("NoPlugin", args); + + return NULL; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) +{ + if(mMediaSource) + { + // Save the previous media source's last set size before destroying it. + mMediaWidth = mMediaSource->getSetWidth(); + mMediaHeight = mMediaSource->getSetHeight(); + } + + // Always delete the old media impl first. + destroyMediaSource(); + + // and unconditionally set the mime type + mMimeType = media_type; + + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This impl should not be loaded at this time. + LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; + + return false; + } + + // If we got here, we want to ignore previous init failures. + mMediaSourceFailed = false; + + // Save the MIME type that really caused the plugin to load + mCurrentMimeType = mMimeType; + + LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget); + + if (media_source) + { + media_source->setDisableTimeout(gSavedSettings.getBOOL("DebugPluginDisableTimeout")); + media_source->setLoop(mMediaLoop); + media_source->setAutoScale(mMediaAutoScale); + media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent()); + media_source->focus(mHasFocus); + media_source->setBackgroundColor(mBackgroundColor); + + if(gSavedSettings.getBOOL("BrowserIgnoreSSLCertErrors")) + { + media_source->ignore_ssl_cert_errors(true); + } + + // the correct way to deal with certs it to load ours from CA.pem and append them to the ones + // Qt/WebKit loads from your system location. + // Note: This needs the new CA.pem file with the Equifax Secure Certificate Authority + // cert at the bottom: (MIIDIDCCAomgAwIBAgIENd70zzANBg) + std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "CA.pem" ); + media_source->addCertificateFilePath( ca_path ); + + media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort")); + + if(mClearCache) + { + mClearCache = false; + media_source->clear_cache(); + } + + // TODO: Only send cookies to plugins that need them + // Ideally, the plugin should tell us whether it handles cookies or not -- either via the init response or through a separate message. + // Due to the ordering of messages, it's possible we wouldn't get that information back in time to send cookies before sending a navigate message, + // which could cause odd race conditions. + std::string all_cookies = LLViewerMedia::getCookieStore()->getAllCookies(); + lldebugs << "setting cookies: " << all_cookies << llendl; + if(!all_cookies.empty()) + { + media_source->set_cookies(all_cookies); + } + + mMediaSource = media_source; + mMediaSource->setDeleteOK(false) ; + updateVolume(); + + return true; + } + + // Make sure the timer doesn't try re-initing this plugin repeatedly until something else changes. + mMediaSourceFailed = true; + + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::loadURI() +{ + if(mMediaSource) + { + // trim whitespace from front and back of URL - fixes EXT-5363 + LLStringUtil::trim( mMediaURL ); + + // *HACK: we don't know if the URI coming in is properly escaped + // (the contract doesn't specify whether it is escaped or not. + // but LLQtWebKit expects it to be, so we do our best to encode + // special characters) + // The strings below were taken right from http://www.ietf.org/rfc/rfc1738.txt + // Note especially that '%' and '/' are there. + std::string uri = LLURI::escape(mMediaURL, + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789" + "$-_.+" + "!*'()," + "{}|\\^~[]`" + "<>#%" + ";/?:@&=", + false); + llinfos << "Asking media source to load URI: " << uri << llendl; + + mMediaSource->loadURI( uri ); + + // A non-zero mPreviousMediaTime means that either this media was previously unloaded by the priority code while playing/paused, + // or a seek happened before the media loaded. In either case, seek to the saved time. + if(mPreviousMediaTime != 0.0f) + { + seek(mPreviousMediaTime); + } + + if(mPreviousMediaState == MEDIA_PLAYING) + { + // This media was playing before this instance was unloaded. + start(); + } + else if(mPreviousMediaState == MEDIA_PAUSED) + { + // This media was paused before this instance was unloaded. + pause(); + } + else + { + // No relevant previous media play state -- if we're loading the URL, we want to start playing. + start(); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setSize(int width, int height) +{ + mMediaWidth = width; + mMediaHeight = height; + if(mMediaSource) + { + mMediaSource->setSize(width, height); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::showNotification(LLNotificationPtr notify) +{ + mNotification = notify; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::hideNotification() +{ + mNotification.reset(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::play() +{ + // If the media source isn't there, try to initialize it and load an URL. + if(mMediaSource == NULL) + { + if(!initializeMedia(mMimeType)) + { + // This may be the case where the plugin's priority is PRIORITY_UNLOADED + return; + } + + // Only do this if the media source was just loaded. + loadURI(); + } + + // always start the media + start(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::stop() +{ + if(mMediaSource) + { + mMediaSource->stop(); + // destroyMediaSource(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::pause() +{ + if(mMediaSource) + { + mMediaSource->pause(); + } + else + { + mPreviousMediaState = MEDIA_PAUSED; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::start() +{ + if(mMediaSource) + { + mMediaSource->start(); + } + else + { + mPreviousMediaState = MEDIA_PLAYING; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::seek(F32 time) +{ + if(mMediaSource) + { + mMediaSource->seek(time); + } + else + { + // Save the seek time to be set when the media is loaded. + mPreviousMediaTime = time; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::skipBack(F32 step_scale) +{ + if(mMediaSource) + { + if(mMediaSource->pluginSupportsMediaTime()) + { + F64 back_step = mMediaSource->getCurrentTime() - (mMediaSource->getDuration()*step_scale); + if(back_step < 0.0) + { + back_step = 0.0; + } + mMediaSource->seek(back_step); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::skipForward(F32 step_scale) +{ + if(mMediaSource) + { + if(mMediaSource->pluginSupportsMediaTime()) + { + F64 forward_step = mMediaSource->getCurrentTime() + (mMediaSource->getDuration()*step_scale); + if(forward_step > mMediaSource->getDuration()) + { + forward_step = mMediaSource->getDuration(); + } + mMediaSource->seek(forward_step); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setVolume(F32 volume) +{ + mRequestedVolume = volume; + updateVolume(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::updateVolume() +{ + if(mMediaSource) + { + // always scale the volume by the global media volume + F32 volume = mRequestedVolume * LLViewerMedia::getVolume(); + + if (mProximityCamera > 0) + { + if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMax")) + { + volume = 0; + } + else if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMin")) + { + // attenuated_volume = 1 / (roll_off_rate * (d - min))^2 + // the +1 is there so that for distance 0 the volume stays the same + F64 adjusted_distance = mProximityCamera - gSavedSettings.getF32("MediaRollOffMin"); + F64 attenuation = 1.0 + (gSavedSettings.getF32("MediaRollOffRate") * adjusted_distance); + attenuation = 1.0 / (attenuation * attenuation); + // the attenuation multiplier should never be more than one since that would increase volume + volume = volume * llmin(1.0, attenuation); + } + } + + mMediaSource->setVolume(volume); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +F32 LLViewerMediaImpl::getVolume() +{ + return mRequestedVolume; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::focus(bool focus) +{ + mHasFocus = focus; + + if (mMediaSource) + { + // call focus just for the hell of it, even though this apopears to be a nop + mMediaSource->focus(focus); + if (focus) + { + // spoof a mouse click to *actually* pass focus + // Don't do this anymore -- it actually clicks through now. +// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0); +// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::hasFocus() const +{ + // FIXME: This might be able to be a bit smarter by hooking into LLViewerMediaFocus, etc. + return mHasFocus; +} + +std::string LLViewerMediaImpl::getCurrentMediaURL() +{ + if(!mCurrentMediaURL.empty()) + { + return mCurrentMediaURL; + } + + return mMediaURL; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::clearCache() +{ + if(mMediaSource) + { + mMediaSource->clear_cache(); + } + else + { + mClearCache = true; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseDown(S32 x, S32 y, MASK mask, S32 button) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; +// llinfos << "mouse down (" << x << ", " << y << ")" << llendl; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, button, x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseUp(S32 x, S32 y, MASK mask, S32 button) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; +// llinfos << "mouse up (" << x << ", " << y << ")" << llendl; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, button, x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseMove(S32 x, S32 y, MASK mask) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; +// llinfos << "mouse move (" << x << ", " << y << ")" << llendl; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +//static +void LLViewerMediaImpl::scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y) +{ + F32 texture_x = texture_coords.mV[VX]; + F32 texture_y = texture_coords.mV[VY]; + + // Deal with repeating textures by wrapping the coordinates into the range [0, 1.0) + texture_x = fmodf(texture_x, 1.0f); + if(texture_x < 0.0f) + texture_x = 1.0 + texture_x; + + texture_y = fmodf(texture_y, 1.0f); + if(texture_y < 0.0f) + texture_y = 1.0 + texture_y; + + // scale x and y to texel units. + *x = llround(texture_x * mMediaSource->getTextureWidth()); + *y = llround((1.0f - texture_y) * mMediaSource->getTextureHeight()); + + // Adjust for the difference between the actual texture height and the amount of the texture in use. + *y -= (mMediaSource->getTextureHeight() - mMediaSource->getHeight()); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords, MASK mask, S32 button) +{ + if(mMediaSource) + { + S32 x, y; + scaleTextureCoords(texture_coords, &x, &y); + + mouseDown(x, y, mask, button); + } +} + +void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords, MASK mask, S32 button) +{ + if(mMediaSource) + { + S32 x, y; + scaleTextureCoords(texture_coords, &x, &y); + + mouseUp(x, y, mask, button); + } +} + +void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords, MASK mask) +{ + if(mMediaSource) + { + S32 x, y; + scaleTextureCoords(texture_coords, &x, &y); + + mouseMove(x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, button, x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, MASK mask) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->scrollEvent(x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::onMouseCaptureLost() +{ + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 0, mLastMouseX, mLastMouseY, 0); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask) +{ + // NOTE: this is called when the mouse is released when we have capture. + // Due to the way mouse coordinates are mapped to the object, we can't use the x and y coordinates that come in with the event. + + if(hasMouseCapture()) + { + // Release the mouse -- this will also send a mouseup to the media + gFocusMgr.setMouseCapture( FALSE ); + } + + return TRUE; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::updateJavascriptObject() +{ + if ( mMediaSource ) + { + // flag to expose this information to internal browser or not. + bool expose_javascript_object = gSavedSettings.getBOOL("BrowserEnableJSObject"); + mMediaSource->jsExposeObjectEvent( expose_javascript_object ); + + // indicate if the values we have are valid (currently do this blanket-fashion for + // everything depending on whether you are logged in or not - this may require a + // more granular approach once variables are added that ARE valid before login + bool logged_in = LLLoginInstance::getInstance()->authSuccess(); + mMediaSource->jsValuesValidEvent( logged_in ); + + // current location within a region + LLVector3 agent_pos = gAgent.getPositionAgent(); + double x = agent_pos.mV[ VX ]; + double y = agent_pos.mV[ VY ]; + double z = agent_pos.mV[ VZ ]; + mMediaSource->jsAgentLocationEvent( x, y, z ); + + // current region agent is in + std::string region_name(""); + LLViewerRegion* region = gAgent.getRegion(); + if ( region ) + { + region_name = region->getName(); + }; + mMediaSource->jsAgentRegionEvent( region_name ); + + // language code the viewer is set to + mMediaSource->jsAgentLanguageEvent( LLUI::getLanguage() ); + + // maturity setting the agent has selected + if ( gAgent.prefersAdult() ) + mMediaSource->jsAgentMaturityEvent( "GMA" ); // Adult means see adult, mature and general content + else + if ( gAgent.prefersMature() ) + mMediaSource->jsAgentMaturityEvent( "GM" ); // Mature means see mature and general content + else + if ( gAgent.prefersPG() ) + mMediaSource->jsAgentMaturityEvent( "G" ); // PG means only see General content + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +std::string LLViewerMediaImpl::getName() const +{ + if (mMediaSource) + { + return mMediaSource->getMediaName(); + } + + return LLStringUtil::null; +}; + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateBack() +{ + if (mMediaSource) + { + mMediaSource->browse_back(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateForward() +{ + if (mMediaSource) + { + mMediaSource->browse_forward(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateReload() +{ + navigateTo(getCurrentMediaURL(), "", true, false); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateHome() +{ + bool rediscover_mimetype = mHomeMimeType.empty(); + navigateTo(mHomeURL, mHomeMimeType, rediscover_mimetype, false); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::unload() +{ + // Unload the media impl and clear its state. + destroyMediaSource(); + resetPreviousMediaState(); + mMediaURL.clear(); + mMimeType.clear(); + mCurrentMediaURL.clear(); + mCurrentMimeType.clear(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type, bool server_request) +{ + cancelMimeTypeProbe(); + + if(mMediaURL != url) + { + // Don't carry media play state across distinct URLs. + resetPreviousMediaState(); + } + + // Always set the current URL and MIME type. + mMediaURL = url; + mMimeType = mime_type; + + // Clear the current media URL, since it will no longer be correct. + mCurrentMediaURL.clear(); + + // if mime type discovery was requested, we'll need to do it when the media loads + mNavigateRediscoverType = rediscover_type; + + // and if this was a server request, the navigate on load will also need to be one. + mNavigateServerRequest = server_request; + + // An explicit navigate resets the "failed" flag. + mMediaSourceFailed = false; + + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // Helpful to have media urls in log file. Shouldn't be spammy. + llinfos << "NOT LOADING media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl; + + // This impl should not be loaded at this time. + LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; + + return; + } + + navigateInternal(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateInternal() +{ + // Helpful to have media urls in log file. Shouldn't be spammy. + llinfos << "media id= " << mTextureId << " url=" << mMediaURL << " mime_type=" << mMimeType << llendl; + + if(mNavigateSuspended) + { + llwarns << "Deferring navigate." << llendl; + mNavigateSuspendedDeferred = true; + return; + } + + if(mMimeTypeProbe != NULL) + { + llwarns << "MIME type probe already in progress -- bailing out." << llendl; + return; + } + + if(mNavigateServerRequest) + { + setNavState(MEDIANAVSTATE_SERVER_SENT); + } + else + { + setNavState(MEDIANAVSTATE_NONE); + } + + // If the caller has specified a non-empty MIME type, look that up in our MIME types list. + // If we have a plugin for that MIME type, use that instead of attempting auto-discovery. + // This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type + // but the parcel owner has correctly set the MIME type in the parcel media settings. + + if(!mMimeType.empty() && (mMimeType != LLMIMETypes::getDefaultMimeType())) + { + std::string plugin_basename = LLMIMETypes::implType(mMimeType); + if(!plugin_basename.empty()) + { + // We have a plugin for this mime type + mNavigateRediscoverType = false; + } + } + + if(mNavigateRediscoverType) + { + + LLURI uri(mMediaURL); + std::string scheme = uri.scheme(); + + if(scheme.empty() || "http" == scheme || "https" == scheme) + { + // If we don't set an Accept header, LLHTTPClient will add one like this: + // Accept: application/llsd+xml + // which is really not what we want. + LLSD headers = LLSD::emptyMap(); + headers["Accept"] = "*/*"; + // Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com + headers["Cookie"] = ""; + LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f); + } + else if("data" == scheme || "file" == scheme || "about" == scheme) + { + // FIXME: figure out how to really discover the type for these schemes + // We use "data" internally for a text/html url for loading the login screen + if(initializeMedia("text/html")) + { + loadURI(); + } + } + else + { + // This catches 'rtsp://' urls + if(initializeMedia(scheme)) + { + loadURI(); + } + } + } + else if(initializeMedia(mMimeType)) + { + loadURI(); + } + else + { + LL_WARNS("Media") << "Couldn't navigate to: " << mMediaURL << " as there is no media type for: " << mMimeType << LL_ENDL; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateStop() +{ + if(mMediaSource) + { + mMediaSource->browse_stop(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) +{ + bool result = false; + + if (mMediaSource) + { + // FIXME: THIS IS SO WRONG. + // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... + if( MASK_CONTROL & mask ) + { + result = true; + } + + if(!result) + { + + LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); + + result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data); + // Since the viewer internal event dispatching doesn't give us key-up events, simulate one here. + (void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data); + } + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) +{ + bool result = false; + + if (mMediaSource) + { + // only accept 'printable' characters, sigh... + if (uni_char >= 32 // discard 'control' characters + && uni_char != 127) // SDL thinks this is 'delete' - yuck. + { + LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); + + mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data); + } + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::canNavigateForward() +{ + BOOL result = FALSE; + if (mMediaSource) + { + result = mMediaSource->getHistoryForwardAvailable(); + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::canNavigateBack() +{ + BOOL result = FALSE; + if (mMediaSource) + { + result = mMediaSource->getHistoryBackAvailable(); + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::update() +{ + if(mMediaSource == NULL) + { + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This media source should not be loaded. + } + else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW) + { + // Don't load new instances that are at PRIORITY_SLIDESHOW or below. They're just kept around to preserve state. + } + else if(mMimeTypeProbe != NULL) + { + // this media source is doing a MIME type probe -- don't try loading it again. + } + else + { + // This media may need to be loaded. + if(sMediaCreateTimer.hasExpired()) + { + LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL; + createMediaSource(); + sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY); + } + else + { + LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL; + } + } + } + else + { + updateVolume(); + + // TODO: this is updated every frame - is this bad? + updateJavascriptObject(); + + // If we didn't just create the impl, it may need to get cookie updates. + if(!sUpdatedCookies.empty()) + { + // TODO: Only send cookies to plugins that need them + mMediaSource->set_cookies(sUpdatedCookies); + } + } + + + if(mMediaSource == NULL) + { + return; + } + + // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash. + setNavigateSuspended(true); + + mMediaSource->idle(); + + setNavigateSuspended(false); + + if(mMediaSource == NULL) + { + return; + } + + if(mMediaSource->isPluginExited()) + { + resetPreviousMediaState(); + destroyMediaSource(); + return; + } + + if(!mMediaSource->textureValid()) + { + return; + } + + if(mSuspendUpdates || !mVisible) + { + return; + } + + LLViewerMediaTexture* placeholder_image = updatePlaceholderImage(); + + if(placeholder_image) + { + LLRect dirty_rect; + + // Since we're updating this texture, we know it's playing. Tell the texture to do its replacement magic so it gets rendered. + placeholder_image->setPlaying(TRUE); + + if(mMediaSource->getDirty(&dirty_rect)) + { + // Constrain the dirty rect to be inside the texture + S32 x_pos = llmax(dirty_rect.mLeft, 0); + S32 y_pos = llmax(dirty_rect.mBottom, 0); + S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos; + S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos; + + if(width > 0 && height > 0) + { + + U8* data = mMediaSource->getBitsData(); + + // Offset the pixels pointer to match x_pos and y_pos + data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); + data += ( y_pos * mMediaSource->getTextureDepth() ); + + placeholder_image->setSubImage( + data, + mMediaSource->getBitsWidth(), + mMediaSource->getBitsHeight(), + x_pos, + y_pos, + width, + height); + + } + + mMediaSource->resetDirty(); + } + } +} + + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::updateImagesMediaStreams() +{ +} + + +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() +{ + if(mTextureId.isNull()) + { + // The code that created this instance will read from the plugin's bits. + return NULL; + } + + LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId ); + + if (mNeedsNewTexture + || placeholder_image->getUseMipMaps() + || (placeholder_image->getWidth() != mMediaSource->getTextureWidth()) + || (placeholder_image->getHeight() != mMediaSource->getTextureHeight()) + || (mTextureUsedWidth != mMediaSource->getWidth()) + || (mTextureUsedHeight != mMediaSource->getHeight()) + ) + { + LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL; + LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL; + + int texture_width = mMediaSource->getTextureWidth(); + int texture_height = mMediaSource->getTextureHeight(); + int texture_depth = mMediaSource->getTextureDepth(); + + // MEDIAOPT: check to see if size actually changed before doing work + placeholder_image->destroyGLTexture(); + // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? + placeholder_image->reinit(FALSE); // probably not needed + + // MEDIAOPT: seems insane that we actually have to make an imageraw then + // immediately discard it + LLPointer raw = new LLImageRaw(texture_width, texture_height, texture_depth); + // Clear the texture to the background color, ignoring alpha. + // convert background color channels from [0.0, 1.0] to [0, 255]; + raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff); + int discard_level = 0; + + // ask media source for correct GL image format constants + placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), + mMediaSource->getTextureFormatPrimary(), + mMediaSource->getTextureFormatType(), + mMediaSource->getTextureFormatSwapBytes()); + + placeholder_image->createGLTexture(discard_level, raw); + + // MEDIAOPT: set this dynamically on play/stop + // FIXME +// placeholder_image->mIsMediaTexture = true; + mNeedsNewTexture = false; + + // If the amount of the texture being drawn by the media goes down in either width or height, + // recreate the texture to avoid leaving parts of the old image behind. + mTextureUsedWidth = mMediaSource->getWidth(); + mTextureUsedHeight = mMediaSource->getHeight(); + } + + return placeholder_image; +} + + +////////////////////////////////////////////////////////////////////////////////////////// +LLUUID LLViewerMediaImpl::getMediaTextureID() const +{ + return mTextureId; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setVisible(bool visible) +{ + mVisible = visible; + + if(mVisible) + { + if(mMediaSource && mMediaSource->isPluginExited()) + { + destroyMediaSource(); + } + + if(!mMediaSource) + { + createMediaSource(); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseCapture() +{ + gFocusMgr.setMouseCapture(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y) +{ +#if 0 + S32 media_width, media_height; + S32 texture_width, texture_height; + getMediaSize( &media_width, &media_height ); + getTextureSize( &texture_width, &texture_height ); + S32 y_delta = texture_height - media_height; + + *mouse_y -= y_delta; +#endif +} + + + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::isMediaTimeBased() +{ + bool result = false; + + if(mMediaSource) + { + result = mMediaSource->pluginSupportsMediaTime(); + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::isMediaPlaying() +{ + bool result = false; + + if(mMediaSource) + { + EMediaStatus status = mMediaSource->getStatus(); + if(status == MEDIA_PLAYING || status == MEDIA_LOADING) + result = true; + } + + return result; +} +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::isMediaPaused() +{ + bool result = false; + + if(mMediaSource) + { + if(mMediaSource->getStatus() == MEDIA_PAUSED) + result = true; + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::hasMedia() const +{ + return mMediaSource != NULL; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +void LLViewerMediaImpl::resetPreviousMediaState() +{ + mPreviousMediaState = MEDIA_NONE; + mPreviousMediaTime = 0.0f; +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// +void LLViewerMediaImpl::setDisabled(bool disabled, bool forcePlayOnEnable) +{ + if(mIsDisabled != disabled) + { + // Only do this on actual state transitions. + mIsDisabled = disabled; + + if(mIsDisabled) + { + // We just disabled this media. Clear all state. + unload(); + } + else + { + // We just (re)enabled this media. Do a navigate if auto-play is in order. + if(isAutoPlayable() || forcePlayOnEnable) + { + navigateTo(mMediaEntryURL, "", true, true); + } + } + + } +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isForcedUnloaded() const +{ + if(mIsMuted || mMediaSourceFailed || mIsDisabled) + { + return true; + } + + if(sInWorldMediaDisabled) + { + // When inworld media is disabled, all instances that aren't marked as "used in UI" will not be loaded. + if(!mUsedInUI) + { + return true; + } + } + + // If this media's class is not supposed to be shown, unload + if (!shouldShowBasedOnClass()) + { + return true; + } + + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isPlayable() const +{ + if(isForcedUnloaded()) + { + // All of the forced-unloaded criteria also imply not playable. + return false; + } + + if(hasMedia()) + { + // Anything that's already playing is, by definition, playable. + return true; + } + + if(!mMediaURL.empty()) + { + // If something has navigated the instance, it's ready to be played. + return true; + } + + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent event) +{ + bool pass_through = true; + switch(event) + { + case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL; + std::string url = plugin->getClickURL(); + std::string nav_type = plugin->getClickNavType(); + LLURLDispatcher::dispatch(url, nav_type, NULL, mTrustedBrowser); + } + break; + case MEDIA_EVENT_CLICK_LINK_HREF: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << plugin->getClickTarget() << "\", uri is " << plugin->getClickURL() << LL_ENDL; + }; + break; + case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: + { + // The plugin failed to load properly. Make sure the timer doesn't retry. + // TODO: maybe mark this plugin as not loadable somehow? + mMediaSourceFailed = true; + + // Reset the last known state of the media to defaults. + resetPreviousMediaState(); + + // TODO: may want a different message for this case? + LLSD args; + args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType); + LLNotificationsUtil::add("MediaPluginFailed", args); + } + break; + + case MEDIA_EVENT_PLUGIN_FAILED: + { + // The plugin crashed. + mMediaSourceFailed = true; + + // Reset the last known state of the media to defaults. + resetPreviousMediaState(); + + LLSD args; + args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType); + // SJB: This is getting called every frame if the plugin fails to load, continuously respawining the alert! + //LLNotificationsUtil::add("MediaPluginFailed", args); + } + break; + + case MEDIA_EVENT_CURSOR_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << plugin->getCursorName() << LL_ENDL; + + std::string cursor = plugin->getCursorName(); + + if(cursor == "arrow") + mLastSetCursor = UI_CURSOR_ARROW; + else if(cursor == "ibeam") + mLastSetCursor = UI_CURSOR_IBEAM; + else if(cursor == "splith") + mLastSetCursor = UI_CURSOR_SIZEWE; + else if(cursor == "splitv") + mLastSetCursor = UI_CURSOR_SIZENS; + else if(cursor == "hand") + mLastSetCursor = UI_CURSOR_HAND; + else // for anything else, default to the arrow + mLastSetCursor = UI_CURSOR_ARROW; + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL; + hideNotification(); + + if(getNavState() == MEDIANAVSTATE_SERVER_SENT) + { + setNavState(MEDIANAVSTATE_SERVER_BEGUN); + } + else + { + setNavState(MEDIANAVSTATE_BEGUN); + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_COMPLETE, uri is: " << plugin->getNavigateURI() << LL_ENDL; + + std::string url = plugin->getNavigateURI(); + if(getNavState() == MEDIANAVSTATE_BEGUN) + { + if(mCurrentMediaURL == url) + { + // This is a navigate that takes us to the same url as the previous navigate. + setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS); + } + else + { + mCurrentMediaURL = url; + setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED); + } + } + else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN) + { + mCurrentMediaURL = url; + setNavState(MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED); + } + else + { + // all other cases need to leave the state alone. + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_LOCATION_CHANGED, uri is: " << plugin->getLocation() << LL_ENDL; + + std::string url = plugin->getLocation(); + + if(getNavState() == MEDIANAVSTATE_BEGUN) + { + if(mCurrentMediaURL == url) + { + // This is a navigate that takes us to the same url as the previous navigate. + setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS); + } + else + { + mCurrentMediaURL = url; + setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED); + } + } + else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN) + { + mCurrentMediaURL = url; + setNavState(MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED); + } + else + { + // Don't track redirects. + setNavState(MEDIANAVSTATE_NONE); + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_PICK_FILE_REQUEST: + { + // Display a file picker + std::string response; + + LLFilePicker& picker = LLFilePicker::instance(); + if (!picker.getOpenFile(LLFilePicker::FFLOAD_ALL)) + { + // The user didn't pick a file -- the empty response string will indicate this. + } + + response = picker.getFirstFile(); + + plugin->sendPickFileResponse(response); + } + break; + + + case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST: + { + LLNotification::Params auth_request_params; + auth_request_params.name = "AuthRequest"; + + // pass in host name and realm for site (may be zero length but will always exist) + LLSD args; + LLURL raw_url( plugin->getAuthURL().c_str() ); + args["HOST_NAME"] = raw_url.getAuthority(); + args["REALM"] = plugin->getAuthRealm(); + auth_request_params.substitutions = args; + + auth_request_params.payload = LLSD().with("media_id", mTextureId); + auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2); + LLNotifications::instance().add(auth_request_params); + }; + break; + + case LLViewerMediaObserver::MEDIA_EVENT_CLOSE_REQUEST: + { + std::string uuid = plugin->getClickUUID(); + + llinfos << "MEDIA_EVENT_CLOSE_REQUEST for uuid " << uuid << llendl; + + if(uuid.empty()) + { + // This close request is directed at this instance, let it fall through. + } + else + { + // This close request is directed at another instance + pass_through = false; + LLFloaterMediaBrowser::closeRequest(uuid); + LLFloaterWebContent::closeRequest(uuid); + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_GEOMETRY_CHANGE: + { + std::string uuid = plugin->getClickUUID(); + + llinfos << "MEDIA_EVENT_GEOMETRY_CHANGE for uuid " << uuid << llendl; + + if(uuid.empty()) + { + // This geometry change request is directed at this instance, let it fall through. + } + else + { + // This request is directed at another instance + pass_through = false; + LLFloaterMediaBrowser::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight()); + LLFloaterWebContent::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight()); + } + } + break; + + default: + break; + } + + if(pass_through) + { + // Just chain the event to observers. + emitEvent(plugin, event); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void LLViewerMediaImpl::handleCookieSet(LLPluginClassMedia* self, const std::string &cookie) +{ + LLViewerMedia::getCookieStore()->setCookies(cookie); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::cut() +{ + if (mMediaSource) + mMediaSource->cut(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canCut() const +{ + if (mMediaSource) + return mMediaSource->canCut(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::copy() +{ + if (mMediaSource) + mMediaSource->copy(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canCopy() const +{ + if (mMediaSource) + return mMediaSource->canCopy(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::paste() +{ + if (mMediaSource) + mMediaSource->paste(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canPaste() const +{ + if (mMediaSource) + return mMediaSource->canPaste(); + else + return FALSE; +} + +void LLViewerMediaImpl::setUpdated(BOOL updated) +{ + mIsUpdated = updated ; +} + +BOOL LLViewerMediaImpl::isUpdated() +{ + return mIsUpdated ; +} + +void LLViewerMediaImpl::calculateInterest() +{ + LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId ); + + if(texture != NULL) + { + mInterest = texture->getMaxVirtualSize(); + } + else + { + // This will be a relatively common case now, since it will always be true for unloaded media. + mInterest = 0.0f; + } + + // Calculate distance from the avatar, for use in the proximity calculation. + mProximityDistance = 0.0f; + mProximityCamera = 0.0f; + if(!mObjectList.empty()) + { + // Just use the first object in the list. We could go through the list and find the closest object, but this should work well enough. + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + LLVOVolume* objp = *iter ; + llassert_always(objp != NULL) ; + + // The distance calculation is invalid for HUD attachments -- leave both mProximityDistance and mProximityCamera at 0 for them. + if(!objp->isHUDAttachment()) + { + LLVector3d obj_global = objp->getPositionGlobal() ; + LLVector3d agent_global = gAgent.getPositionGlobal() ; + LLVector3d global_delta = agent_global - obj_global ; + mProximityDistance = global_delta.magVecSquared(); // use distance-squared because it's cheaper and sorts the same. + + LLVector3d camera_delta = gAgentCamera.getCameraPositionGlobal() - obj_global; + mProximityCamera = camera_delta.magVec(); + } + } + + if(mNeedsMuteCheck) + { + // Check all objects this instance is associated with, and those objects' owners, against the mute list + mIsMuted = false; + + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + for(; iter != mObjectList.end() ; ++iter) + { + LLVOVolume *obj = *iter; + llassert(obj); + if (!obj) continue; + if(LLMuteList::getInstance() && + LLMuteList::getInstance()->isMuted(obj->getID())) + { + mIsMuted = true; + } + else + { + // We won't have full permissions data for all objects. Attempt to mute objects when we can tell their owners are muted. + if (LLSelectMgr::getInstance()) + { + LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(obj); + if(obj_perm) + { + if(LLMuteList::getInstance() && + LLMuteList::getInstance()->isMuted(obj_perm->getOwner())) + mIsMuted = true; + } + } + } + } + + mNeedsMuteCheck = false; + } +} + +F64 LLViewerMediaImpl::getApproximateTextureInterest() +{ + F64 result = 0.0f; + + if(mMediaSource) + { + result = mMediaSource->getFullWidth(); + result *= mMediaSource->getFullHeight(); + } + else + { + // No media source is loaded -- all we have to go on is the texture size that has been set on the impl, if any. + result = mMediaWidth; + result *= mMediaHeight; + } + + return result; +} + +void LLViewerMediaImpl::setUsedInUI(bool used_in_ui) +{ + mUsedInUI = used_in_ui; + + // HACK: Force elements used in UI to load right away. + // This fixes some issues where UI code that uses the browser instance doesn't expect it to be unloaded. + if(mUsedInUI && (mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)) + { + if(getVisible()) + { + setPriority(LLPluginClassMedia::PRIORITY_NORMAL); + } + else + { + setPriority(LLPluginClassMedia::PRIORITY_HIDDEN); + } + + createMediaSource(); + } +}; + +void LLViewerMediaImpl::setBackgroundColor(LLColor4 color) +{ + mBackgroundColor = color; + + if(mMediaSource) + { + mMediaSource->setBackgroundColor(mBackgroundColor); + } +}; + +F64 LLViewerMediaImpl::getCPUUsage() const +{ + F64 result = 0.0f; + + if(mMediaSource) + { + result = mMediaSource->getCPUUsage(); + } + + return result; +} + +void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority) +{ + if(mPriority != priority) + { + LL_DEBUGS("PluginPriority") + << "changing priority of media id " << mTextureId + << " from " << LLPluginClassMedia::priorityToString(mPriority) + << " to " << LLPluginClassMedia::priorityToString(priority) + << LL_ENDL; + } + + mPriority = priority; + + if(priority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + if(mMediaSource) + { + // Need to unload the media source + + // First, save off previous media state + mPreviousMediaState = mMediaSource->getStatus(); + mPreviousMediaTime = mMediaSource->getCurrentTime(); + + destroyMediaSource(); + } + } + + if(mMediaSource) + { + mMediaSource->setPriority(mPriority); + } + + // NOTE: loading (or reloading) media sources whose priority has risen above PRIORITY_UNLOADED is done in update(). +} + +void LLViewerMediaImpl::setLowPrioritySizeLimit(int size) +{ + if(mMediaSource) + { + mMediaSource->setLowPrioritySizeLimit(size); + } +} + +void LLViewerMediaImpl::setNavState(EMediaNavState state) +{ + mMediaNavState = state; + + switch (state) + { + case MEDIANAVSTATE_NONE: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_NONE" << llendl; break; + case MEDIANAVSTATE_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_BEGUN" << llendl; break; + case MEDIANAVSTATE_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED" << llendl; break; + case MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS" << llendl; break; + case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break; + case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS" << llendl; break; + case MEDIANAVSTATE_SERVER_SENT: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_SENT" << llendl; break; + case MEDIANAVSTATE_SERVER_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_BEGUN" << llendl; break; + case MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED" << llendl; break; + case MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break; + } +} + +void LLViewerMediaImpl::setNavigateSuspended(bool suspend) +{ + if(mNavigateSuspended != suspend) + { + mNavigateSuspended = suspend; + if(!suspend) + { + // We're coming out of suspend. If someone tried to do a navigate while suspended, do one now instead. + if(mNavigateSuspendedDeferred) + { + mNavigateSuspendedDeferred = false; + navigateInternal(); + } + } + } +} + +void LLViewerMediaImpl::cancelMimeTypeProbe() +{ + if(mMimeTypeProbe != NULL) + { + // There doesn't seem to be a way to actually cancel an outstanding request. + // Simulate it by telling the LLMimeDiscoveryResponder not to write back any results. + mMimeTypeProbe->cancelRequest(); + + // The above should already have set mMimeTypeProbe to NULL. + if(mMimeTypeProbe != NULL) + { + llerrs << "internal error: mMimeTypeProbe is not NULL after cancelling request." << llendl; + } + } +} + +void LLViewerMediaImpl::addObject(LLVOVolume* obj) +{ + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + for(; iter != mObjectList.end() ; ++iter) + { + if(*iter == obj) + { + return ; //already in the list. + } + } + + mObjectList.push_back(obj) ; + mNeedsMuteCheck = true; +} + +void LLViewerMediaImpl::removeObject(LLVOVolume* obj) +{ + mObjectList.remove(obj) ; + mNeedsMuteCheck = true; +} + +const std::list< LLVOVolume* >* LLViewerMediaImpl::getObjectList() const +{ + return &mObjectList ; +} + +LLVOVolume *LLViewerMediaImpl::getSomeObject() +{ + LLVOVolume *result = NULL; + + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + if(iter != mObjectList.end()) + { + result = *iter; + } + + return result; +} + +void LLViewerMediaImpl::setTextureID(LLUUID id) +{ + if(id != mTextureId) + { + if(mTextureId.notNull()) + { + // Remove this item's entry from the map + sViewerMediaTextureIDMap.erase(mTextureId); + } + + if(id.notNull()) + { + sViewerMediaTextureIDMap.insert(LLViewerMedia::impl_id_map::value_type(id, this)); + } + + mTextureId = id; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isAutoPlayable() const +{ + return (mMediaAutoPlay && + gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && + gSavedSettings.getBOOL("MediaTentativeAutoPlay")); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::shouldShowBasedOnClass() const +{ + // If this is parcel media or in the UI, return true always + if (getUsedInUI() || isParcelMedia()) return true; + + bool attached_to_another_avatar = isAttachedToAnotherAvatar(); + bool inside_parcel = isInAgentParcel(); + + // llinfos << " hasFocus = " << hasFocus() << + // " others = " << (attached_to_another_avatar && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING)) << + // " within = " << (inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING)) << + // " outside = " << (!inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING)) << llendl; + + // If it has focus, we should show it + // This is incorrect, and causes EXT-6750 (disabled attachment media still plays) +// if (hasFocus()) +// return true; + + // If it is attached to an avatar and the pref is off, we shouldn't show it + if (attached_to_another_avatar) + return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING); + + if (inside_parcel) + return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING); + else + return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isAttachedToAnotherAvatar() const +{ + bool result = false; + + std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin(); + std::list< LLVOVolume* >::const_iterator end = mObjectList.end(); + for ( ; iter != end; iter++) + { + if (isObjectAttachedToAnotherAvatar(*iter)) + { + result = true; + break; + } + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +//static +bool LLViewerMediaImpl::isObjectAttachedToAnotherAvatar(LLVOVolume *obj) +{ + bool result = false; + LLXform *xform = obj; + // Walk up parent chain + while (NULL != xform) + { + LLViewerObject *object = dynamic_cast (xform); + if (NULL != object) + { + LLVOAvatar *avatar = object->asAvatar(); + if ((NULL != avatar) && (avatar != gAgentAvatarp)) + { + result = true; + break; + } + } + xform = xform->getParent(); + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isInAgentParcel() const +{ + bool result = false; + + std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin(); + std::list< LLVOVolume* >::const_iterator end = mObjectList.end(); + for ( ; iter != end; iter++) + { + LLVOVolume *object = *iter; + if (LLViewerMediaImpl::isObjectInAgentParcel(object)) + { + result = true; + break; + } + } + return result; +} + +LLNotificationPtr LLViewerMediaImpl::getCurrentNotification() const +{ + return mNotification; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +// static +bool LLViewerMediaImpl::isObjectInAgentParcel(LLVOVolume *obj) +{ + return (LLViewerParcelMgr::getInstance()->inAgentParcel(obj->getPositionGlobal())); +} diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index e2e342cc45..a70c6f4887 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -339,7 +339,10 @@ public: LLVOVolume *getSomeObject(); void setUpdated(BOOL updated) ; BOOL isUpdated() ; - + + // updates the javascript object in the embedded browser with viewer values + void updateJavascriptObject(); + // Updates the "interest" value in this object void calculateInterest(); F64 getInterest() const { return mInterest; }; diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index 0d4a095e14..32c1d7083a 100644 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -183,11 +183,11 @@ parameter="http://join.secondlife.com/"/> + label="Web Content Floater Debug Test" + name="Web Content Floater Debug Test"> + parameter="http://callum-linden.s3.amazonaws.com/browsertest.html"/> Date: Mon, 16 May 2011 12:34:25 -0400 Subject: SH-1506 "Upload Wizard" is missing from Inventory's add menu --- indra/newview/skins/default/xui/en/menu_inventory_add.xml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml index 484af63097..b36b82ebd8 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml @@ -42,7 +42,7 @@ - @@ -54,6 +54,18 @@ + + + + + Date: Mon, 16 May 2011 13:33:44 -0400 Subject: SH-1351 FIXED On the Edit Panel, remove the Override Material checkbox --- indra/newview/llpanelvolume.cpp | 1 - indra/newview/skins/default/xui/en/floater_tools.xml | 10 ---------- 2 files changed, 11 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index c443814c89..ff72ad0c14 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -467,7 +467,6 @@ void LLPanelVolume::refresh() getChildView("label physicsshapetype")->setVisible(enable_mesh); getChildView("Physics Shape Type Combo Ctrl")->setVisible(enable_mesh); getChildView("Physics Gravity")->setVisible(enable_mesh); - getChildView("Physics Material Override")->setVisible(enable_mesh); getChildView("Physics Friction")->setVisible(enable_mesh); getChildView("Physics Density")->setVisible(enable_mesh); getChildView("Physics Restitution")->setVisible(enable_mesh); diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 380eeae403..9178e30c8b 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -2441,16 +2441,6 @@ even though the user gets a free copy. top_pad="10" width="132" /> - - Date: Mon, 16 May 2011 15:08:16 -0400 Subject: Use trial server for new search --- indra/newview/app_settings/settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 33c5e533be..b36f43a638 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3908,7 +3908,7 @@ Type String Value - http://search.secondlife.com/viewer/[CATEGORY]/?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID]&channel=[CHANNEL]&version=[VERSION]&major=[VERSION_MAJOR]&minor=[VERSION_MINOR]&patch=[VERSION_PATCH]&build=[VERSION_BUILD] + http://beta.search.secondlife.com/viewer/[CATEGORY]/?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID]&channel=[CHANNEL]&version=[VERSION]&major=[VERSION_MAJOR]&minor=[VERSION_MINOR]&patch=[VERSION_PATCH]&build=[VERSION_BUILD] WebProfileURL -- cgit v1.2.3 From eb8221338e0276b9afe8d92738166f97782d48d6 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Mon, 16 May 2011 15:45:14 -0400 Subject: SH-1352 Move Material dropdown to Features tab, above Physics settings --- indra/newview/llpanelobject.cpp | 88 -------------------- indra/newview/llpanelobject.h | 5 -- indra/newview/llpanelvolume.cpp | 93 +++++++++++++++++++++- indra/newview/llpanelvolume.h | 6 +- .../newview/skins/default/xui/en/floater_tools.xml | 70 ++++++++-------- 5 files changed, 132 insertions(+), 130 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 64af6c2157..204c146f3c 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -33,11 +33,9 @@ #include "lleconomy.h" #include "llerror.h" #include "llfontgl.h" -#include "llmaterialtable.h" #include "llpermissionsflags.h" #include "llstring.h" #include "llvolume.h" -#include "material_codes.h" #include "m3math.h" // project includes @@ -57,7 +55,6 @@ #include "lltool.h" #include "lltoolcomp.h" #include "lltoolmgr.h" -#include "lltrans.h" #include "llui.h" #include "llviewerobject.h" #include "llviewerregion.h" @@ -101,17 +98,6 @@ BOOL LLPanelObject::postBuild() { setMouseOpaque(FALSE); - std::map material_name_map; - material_name_map["Stone"]= LLTrans::getString("Stone"); - material_name_map["Metal"]= LLTrans::getString("Metal"); - material_name_map["Glass"]= LLTrans::getString("Glass"); - material_name_map["Wood"]= LLTrans::getString("Wood"); - material_name_map["Flesh"]= LLTrans::getString("Flesh"); - material_name_map["Plastic"]= LLTrans::getString("Plastic"); - material_name_map["Rubber"]= LLTrans::getString("Rubber"); - material_name_map["Light"]= LLTrans::getString("Light"); - - LLMaterialTable::basic.initTableTransNames(material_name_map); //-------------------------------------------------------- // Top //-------------------------------------------------------- @@ -166,22 +152,6 @@ BOOL LLPanelObject::postBuild() //-------------------------------------------------------- - // material type popup - mComboMaterial = getChild("material"); - childSetCommitCallback("material",onCommitMaterial,this); - mComboMaterial->removeall(); - - for (LLMaterialTable::info_list_t::iterator iter = LLMaterialTable::basic.mMaterialInfoList.begin(); - iter != LLMaterialTable::basic.mMaterialInfoList.end(); ++iter) - { - LLMaterialInfo* minfop = *iter; - if (minfop->mMCode != LL_MCODE_LIGHT) - { - mComboMaterial->add(minfop->mName); - } - } - mComboMaterialItemCount = mComboMaterial->getItemCount(); - // Base Type mComboBaseType = getChild("comboBaseType"); childSetCommitCallback("comboBaseType",onCommitParametric,this); @@ -309,7 +279,6 @@ BOOL LLPanelObject::postBuild() LLPanelObject::LLPanelObject() : LLPanel(), - mComboMaterialItemCount(0), mIsPhysical(FALSE), mIsTemporary(FALSE), mIsPhantom(FALSE), @@ -527,43 +496,6 @@ void LLPanelObject::getState( ) mCheckCastShadows->setEnabled( roots_selected==1 && editable ); #endif - // Update material part - // slightly inefficient - materials are unique per object, not per TE - U8 material_code = 0; - struct f : public LLSelectedTEGetFunctor - { - U8 get(LLViewerObject* object, S32 te) - { - return object->getMaterial(); - } - } func; - bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_code ); - std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); - if (editable && single_volume && material_same) - { - mComboMaterial->setEnabled( TRUE ); - if (material_code == LL_MCODE_LIGHT) - { - if (mComboMaterial->getItemCount() == mComboMaterialItemCount) - { - mComboMaterial->add(LEGACY_FULLBRIGHT_DESC); - } - mComboMaterial->setSimple(LEGACY_FULLBRIGHT_DESC); - } - else - { - if (mComboMaterial->getItemCount() != mComboMaterialItemCount) - { - mComboMaterial->remove(LEGACY_FULLBRIGHT_DESC); - } - - mComboMaterial->setSimple(std::string(LLMaterialTable::basic.getName(material_code))); - } - } - else - { - mComboMaterial->setEnabled( FALSE ); - } //---------------------------------------------------------------------------- S32 selected_item = MI_BOX; @@ -1244,25 +1176,6 @@ void LLPanelObject::sendCastShadows() } } -// static -void LLPanelObject::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) -{ - //LLPanelObject* self = (LLPanelObject*) userdata; - LLComboBox* box = (LLComboBox*) ctrl; - - if (box) - { - // apply the currently selected material to the object - const std::string& material_name = box->getSimple(); - std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); - if (material_name != LEGACY_FULLBRIGHT_DESC) - { - U8 material_code = LLMaterialTable::basic.getMCode(material_name); - LLSelectMgr::getInstance()->selectionSetMaterial(material_code); - } - } -} - // static void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata ) { @@ -1937,7 +1850,6 @@ void LLPanelObject::clearCtrls() mCheckCastShadows->set(FALSE); mCheckCastShadows->setEnabled( FALSE ); #endif - mComboMaterial ->setEnabled( FALSE ); // Disable text labels mLabelPosition ->setEnabled( FALSE ); mLabelSize ->setEnabled( FALSE ); diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index e2f2a4400d..475dfdaedb 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -66,7 +66,6 @@ public: static void onCommitPhantom( LLUICtrl* ctrl, void* userdata); static void onCommitCastShadows( LLUICtrl* ctrl, void* userdata); static void onCommitPhysics( LLUICtrl* ctrl, void* userdata); - static void onCommitMaterial( LLUICtrl* ctrl, void* userdata); static void onCommitParametric(LLUICtrl* ctrl, void* userdata); @@ -94,10 +93,6 @@ protected: void getVolumeParams(LLVolumeParams& volume_params); protected: - S32 mComboMaterialItemCount; - - LLComboBox* mComboMaterial; - // Per-object options LLComboBox* mComboBaseType; diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index ff72ad0c14..ebddaa90bc 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -59,6 +59,7 @@ #include "lltool.h" #include "lltoolcomp.h" #include "lltoolmgr.h" +#include "lltrans.h" #include "llui.h" #include "llviewerobject.h" #include "llviewerregion.h" @@ -156,6 +157,34 @@ BOOL LLPanelVolume::postBuild() mSpinPhysicsRestitution = getChild("Physics Restitution"); mSpinPhysicsRestitution->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsRestitution, this, _1, mSpinPhysicsRestitution)); } + + std::map material_name_map; + material_name_map["Stone"]= LLTrans::getString("Stone"); + material_name_map["Metal"]= LLTrans::getString("Metal"); + material_name_map["Glass"]= LLTrans::getString("Glass"); + material_name_map["Wood"]= LLTrans::getString("Wood"); + material_name_map["Flesh"]= LLTrans::getString("Flesh"); + material_name_map["Plastic"]= LLTrans::getString("Plastic"); + material_name_map["Rubber"]= LLTrans::getString("Rubber"); + material_name_map["Light"]= LLTrans::getString("Light"); + + LLMaterialTable::basic.initTableTransNames(material_name_map); + + // material type popup + mComboMaterial = getChild("material"); + childSetCommitCallback("material",onCommitMaterial,this); + mComboMaterial->removeall(); + + for (LLMaterialTable::info_list_t::iterator iter = LLMaterialTable::basic.mMaterialInfoList.begin(); + iter != LLMaterialTable::basic.mMaterialInfoList.end(); ++iter) + { + LLMaterialInfo* minfop = *iter; + if (minfop->mMCode != LL_MCODE_LIGHT) + { + mComboMaterial->add(minfop->mName); + } + } + mComboMaterialItemCount = mComboMaterial->getItemCount(); // Start with everyone disabled clearCtrls(); @@ -164,7 +193,8 @@ BOOL LLPanelVolume::postBuild() } LLPanelVolume::LLPanelVolume() - : LLPanel() + : LLPanel(), + mComboMaterialItemCount(0) { setMouseOpaque(FALSE); @@ -379,6 +409,46 @@ void LLPanelVolume::getState( ) getChildView("FlexForceZ")->setEnabled(false); } + // Material properties + + // Update material part + // slightly inefficient - materials are unique per object, not per TE + U8 material_code = 0; + struct f : public LLSelectedTEGetFunctor + { + U8 get(LLViewerObject* object, S32 te) + { + return object->getMaterial(); + } + } func; + bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_code ); + std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); + if (editable && single_volume && material_same) + { + mComboMaterial->setEnabled( TRUE ); + if (material_code == LL_MCODE_LIGHT) + { + if (mComboMaterial->getItemCount() == mComboMaterialItemCount) + { + mComboMaterial->add(LEGACY_FULLBRIGHT_DESC); + } + mComboMaterial->setSimple(LEGACY_FULLBRIGHT_DESC); + } + else + { + if (mComboMaterial->getItemCount() != mComboMaterialItemCount) + { + mComboMaterial->remove(LEGACY_FULLBRIGHT_DESC); + } + + mComboMaterial->setSimple(std::string(LLMaterialTable::basic.getName(material_code))); + } + } + else + { + mComboMaterial->setEnabled( FALSE ); + } + // Physics properties mSpinPhysicsGravity->set(objectp->getPhysicsGravity()); @@ -521,6 +591,8 @@ void LLPanelVolume::clearCtrls() mSpinPhysicsFriction->setEnabled(FALSE); mSpinPhysicsDensity->setEnabled(FALSE); mSpinPhysicsRestitution->setEnabled(FALSE); + + mComboMaterial->setEnabled( FALSE ); } // @@ -672,6 +744,25 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data) } } +// static +void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) +{ + //LLPanelObject* self = (LLPanelObject*) userdata; + LLComboBox* box = (LLComboBox*) ctrl; + + if (box) + { + // apply the currently selected material to the object + const std::string& material_name = box->getSimple(); + std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); + if (material_name != LEGACY_FULLBRIGHT_DESC) + { + U8 material_code = LLMaterialTable::basic.getMCode(material_name); + LLSelectMgr::getInstance()->selectionSetMaterial(material_code); + } + } +} + // static void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata ) { diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index 776a2c1f4a..0ef47db0d9 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -63,8 +63,8 @@ public: static void onCommitLight( LLUICtrl* ctrl, void* userdata); static void onCommitIsFlexible( LLUICtrl* ctrl, void* userdata); static void onCommitFlexible( LLUICtrl* ctrl, void* userdata); - static void onCommitPhysicsParam( LLUICtrl* ctrl, void* userdata); + static void onCommitMaterial( LLUICtrl* ctrl, void* userdata); void onLightCancelColor(const LLSD& data); void onLightSelectColor(const LLSD& data); @@ -104,6 +104,10 @@ protected: LLSpinCtrl* mSpinForce[3]; */ + S32 mComboMaterialItemCount; + LLComboBox* mComboMaterial; + + LLColor4 mLightSavedColor; LLUUID mLightSavedTexture; LLPointer mObject; diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 9178e30c8b..501e93ead3 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1608,41 +1608,6 @@ even though the user gets a free copy. name="Sculpted" value="Sculpted" /> - - - - - - - - - + + + + + + + + + Date: Mon, 16 May 2011 15:17:27 -0700 Subject: EXP-819 Turning off Voice Chat setting in Basic mode reverts changes made in Sound Device selection and turning setting back on results in drop downs not being populated --- indra/newview/llfloatersounddevices.cpp | 3 +++ indra/newview/llpanelvoicedevicesettings.cpp | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llfloatersounddevices.cpp b/indra/newview/llfloatersounddevices.cpp index 9fe7c7f9dd..e692f1735a 100644 --- a/indra/newview/llfloatersounddevices.cpp +++ b/indra/newview/llfloatersounddevices.cpp @@ -68,6 +68,9 @@ BOOL LLFloaterSoundDevices::postBuild() if (panel) { panel->setUseTuningMode(false); + getChild("voice_input_device")->setCommitCallback(boost::bind(&LLPanelVoiceDeviceSettings::apply, panel)); + getChild("voice_output_device")->setCommitCallback(boost::bind(&LLPanelVoiceDeviceSettings::apply, panel)); + getChild("mic_volume_slider")->setCommitCallback(boost::bind(&LLPanelVoiceDeviceSettings::apply, panel)); } return TRUE; } diff --git a/indra/newview/llpanelvoicedevicesettings.cpp b/indra/newview/llpanelvoicedevicesettings.cpp index dc87bd0077..4a80bbbe5e 100644 --- a/indra/newview/llpanelvoicedevicesettings.cpp +++ b/indra/newview/llpanelvoicedevicesettings.cpp @@ -191,7 +191,21 @@ void LLPanelVoiceDeviceSettings::refresh() mCtrlInputDevices = getChild("voice_input_device"); mCtrlOutputDevices = getChild("voice_output_device"); - if(!LLVoiceClient::getInstance()->deviceSettingsAvailable()) + bool device_settings_available = LLVoiceClient::getInstance()->deviceSettingsAvailable(); + + if (mCtrlInputDevices) + { + mCtrlInputDevices->setEnabled(device_settings_available); + } + + if (mCtrlOutputDevices) + { + mCtrlOutputDevices->setEnabled(device_settings_available); + } + + getChild("mic_volume_slider")->setEnabled(device_settings_available); + + if(!device_settings_available) { // The combo boxes are disabled, since we can't get the device settings from the daemon just now. // Put the currently set default (ONLY) in the box, and select it. @@ -207,6 +221,7 @@ void LLPanelVoiceDeviceSettings::refresh() mCtrlOutputDevices->add( mOutputDevice, ADD_BOTTOM ); mCtrlOutputDevices->setSimple(mOutputDevice); } + mDevicesUpdated = FALSE; } else if (!mDevicesUpdated) { -- cgit v1.2.3 From 9aef66cfcc21400bbe3cc40386ec3a37a75054c4 Mon Sep 17 00:00:00 2001 From: Kazu Linden Date: Mon, 23 May 2011 12:49:19 -0700 Subject: changing URL to support SSL --- indra/newview/app_settings/settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b36f43a638..95ae6df833 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3908,7 +3908,7 @@ Type String Value - http://beta.search.secondlife.com/viewer/[CATEGORY]/?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID]&channel=[CHANNEL]&version=[VERSION]&major=[VERSION_MAJOR]&minor=[VERSION_MINOR]&patch=[VERSION_PATCH]&build=[VERSION_BUILD] + http://search-beta.secondlife.com/viewer/[CATEGORY]/?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID]&channel=[CHANNEL]&version=[VERSION]&major=[VERSION_MAJOR]&minor=[VERSION_MINOR]&patch=[VERSION_PATCH]&build=[VERSION_BUILD] WebProfileURL -- cgit v1.2.3 From 01e98f535eab4b8df6b029780d472da778ad4acb Mon Sep 17 00:00:00 2001 From: seth_productengine Date: Tue, 17 May 2011 20:22:46 +0300 Subject: STORM-1260 FIXED Replaced llerrs messages with llwarns in directory iterator code to avoid viewer halt when a cache dir is not found. --- indra/llvfs/lldiriterator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/llvfs/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp index 5536ed8f69..041436ed92 100644 --- a/indra/llvfs/lldiriterator.cpp +++ b/indra/llvfs/lldiriterator.cpp @@ -55,7 +55,7 @@ LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask) // Check if path exists. if (!fs::exists(dir_path)) { - llerrs << "Invalid path: \"" << dir_path.string() << "\"" << llendl; + llwarns << "Invalid path: \"" << dir_path.string() << "\"" << llendl; return; } @@ -100,7 +100,7 @@ bool LLDirIterator::Impl::next(std::string &fname) if (!mIsValid) { - llerrs << "The iterator is not correctly initialized." << llendl; + llwarns << "The iterator is not correctly initialized." << llendl; return false; } -- cgit v1.2.3 From e5e98a597d6bad6d2ccbe5a5a0bee45f8e66eb0b Mon Sep 17 00:00:00 2001 From: callum Date: Wed, 18 May 2011 09:56:02 -0700 Subject: Reverted Linux LLQtWebKit to older version which triggered warnings here that are treated as errors. --- indra/media_plugins/webkit/media_plugin_webkit.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index b22dbc6604..bdfbde8494 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -1170,50 +1170,50 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) else if(message_name == "js_expose_object") { - bool expose_object = message_in.getValueBoolean( "expose" ); #if LLQTWEBKIT_API_VERSION >= 9 + bool expose_object = message_in.getValueBoolean( "expose" ); LLQtWebKit::getInstance()->setExposeObject( expose_object ); #endif } else if(message_name == "js_values_valid") { - bool valid = message_in.getValueBoolean( "valid" ); #if LLQTWEBKIT_API_VERSION >= 9 + bool valid = message_in.getValueBoolean( "valid" ); LLQtWebKit::getInstance()->setValuesValid( valid ); #endif } else if(message_name == "js_agent_location") { +#if LLQTWEBKIT_API_VERSION >= 9 F32 x = message_in.getValueReal("x"); F32 y = message_in.getValueReal("y"); F32 z = message_in.getValueReal("z"); -#if LLQTWEBKIT_API_VERSION >= 9 LLQtWebKit::getInstance()->setAgentLocation( x, y, z ); #endif } else if(message_name == "js_agent_language") { - const std::string& language = message_in.getValue("language"); #if LLQTWEBKIT_API_VERSION >= 9 + const std::string& language = message_in.getValue("language"); LLQtWebKit::getInstance()->setAgentLanguage( language ); #endif } else if(message_name == "js_agent_region") { - const std::string& region = message_in.getValue("region"); #if LLQTWEBKIT_API_VERSION >= 9 + const std::string& region = message_in.getValue("region"); LLQtWebKit::getInstance()->setAgentRegion( region ); #endif } else if(message_name == "js_agent_maturity") { - const std::string& maturity = message_in.getValue("maturity"); #if LLQTWEBKIT_API_VERSION >= 9 + const std::string& maturity = message_in.getValue("maturity"); LLQtWebKit::getInstance()->setAgentMaturity( maturity ); #endif } -- cgit v1.2.3 From 4b97f03b04e7df25e5b3622122f6d124d4a5f617 Mon Sep 17 00:00:00 2001 From: Logan Dethrow Date: Fri, 20 May 2011 16:00:36 -0400 Subject: Revamped viewer cache preference controls. Implemented improved cache control user interface, changes approved by wolf. * Moved viewer cache controls from the setup preference panel to advanced * Changed cache size control slider into a spinner * Readded a clear cache button along with a cache clear confirmation dialog * Renamed the reset button to "Default Location" to clarify its function Related JIRAs: ER-815 ER-816 ER-818 ER-820 ER-821 ER-831 --- indra/newview/llappviewer.cpp | 8 +- indra/newview/llfloaterpreference.cpp | 21 +++- indra/newview/llfloaterpreference.h | 5 +- .../newview/skins/default/xui/en/notifications.xml | 12 +++ .../default/xui/en/panel_preferences_advanced.xml | 106 ++++++++++++++++++++- .../default/xui/en/panel_preferences_setup.xml | 92 ------------------ 6 files changed, 145 insertions(+), 99 deletions(-) (limited to 'indra') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 7e682fc83b..53c075450a 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3586,10 +3586,12 @@ bool LLAppViewer::initCache() // Init the texture cache // Allocate 80% of the cache size for textures const S32 MB = 1024 * 1024; - S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB; - const S64 MAX_CACHE_SIZE = 10 * 1024ll * MB; + const S64 MIN_CACHE_SIZE = 64 * MB; + const S64 MAX_CACHE_SIZE = 9984ll * MB; const S64 MAX_VFS_SIZE = 1024 * MB; // 1 GB - cache_size = llmin(cache_size, MAX_CACHE_SIZE); + + S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB; + cache_size = llclamp(cache_size, MIN_CACHE_SIZE, MAX_CACHE_SIZE); S64 texture_cache_size = ((cache_size * 8) / 10); S64 vfs_size = cache_size - texture_cache_size; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 8d13e59a79..396ea53ff3 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -187,12 +187,26 @@ void LLVoiceSetKeyDialog::onCancel(void* user_data) void handleNameTagOptionChanged(const LLSD& newvalue); void handleDisplayNamesOptionChanged(const LLSD& newvalue); bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response); +bool callback_clear_cache(const LLSD& notification, const LLSD& response); //bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater); //bool callback_reset_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater); void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator); +bool callback_clear_cache(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if ( option == 0 ) // YES + { + // flag client texture cache for clearing next time the client runs + gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); + LLNotificationsUtil::add("CacheWillClear"); + } + + return false; +} + bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -305,7 +319,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreference::onBtnCancel, this)); mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreference::onBtnOK, this)); -// mCommitCallbackRegistrar.add("Pref.ClearCache", boost::bind(&LLFloaterPreference::onClickClearCache, this)); + mCommitCallbackRegistrar.add("Pref.ClearCache", boost::bind(&LLFloaterPreference::onClickClearCache, this)); mCommitCallbackRegistrar.add("Pref.WebClearCache", boost::bind(&LLFloaterPreference::onClickBrowserClearCache, this)); mCommitCallbackRegistrar.add("Pref.SetCache", boost::bind(&LLFloaterPreference::onClickSetCache, this)); mCommitCallbackRegistrar.add("Pref.ResetCache", boost::bind(&LLFloaterPreference::onClickResetCache, this)); @@ -809,6 +823,11 @@ void LLFloaterPreference::refreshEnabledGraphics() } } +void LLFloaterPreference::onClickClearCache() +{ + LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache); +} + void LLFloaterPreference::onClickBrowserClearCache() { LLNotificationsUtil::add("ConfirmClearBrowserCache", LLSD(), LLSD(), callback_clear_browser_cache); diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 5fe509fb37..ef92575347 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -88,7 +88,8 @@ protected: void onBtnCancel(); void onBtnApply(); - void onClickBrowserClearCache(); + void onClickClearCache(); // Clear viewer texture cache, vfs, and VO cache on next startup + void onClickBrowserClearCache(); // Clear web history and caches as well as viewer caches above void onLanguageChange(); void onNameTagOpacityChange(const LLSD& newvalue); @@ -99,7 +100,7 @@ protected: void onChangeCustom(); void updateMeterText(LLUICtrl* ctrl); void onOpenHardwareSettings(); - /// callback for defaults + // callback for defaults void setHardwareDefaults(); // callback for when client turns on shaders void onVertexShaderEnable(); diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 3fb3717e68..207e55073d 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -4763,6 +4763,18 @@ Are you sure you want to delete your travel, web, and search history? notext="Cancel" yestext="OK"/> + + +Are you sure you want to clear your viewer cache? + confirm + + + Cache: + + + + MB + + + + Cache location: + + + + + UI size: diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index bdc21960cd..1c22a5c02e 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -93,98 +93,6 @@ name="connection_port" top_delta="3" width="170" /> - - Cache size - - - - MB - - - Cache location: - - - - Date: Mon, 23 May 2011 17:12:08 -0700 Subject: EXP-826 FIX Help -> About Secondlife Info is corrupted. --- indra/llkdu/llimagej2ckdu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index 39ae09650e..c156ed0cef 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -73,7 +73,7 @@ void set_default_colour_weights(kdu_params *siz); const char* engineInfoLLImageJ2CKDU() { - std::string version = llformat("KDU %s", KDU_CORE_VERSION); + static std::string version = llformat("KDU %s", KDU_CORE_VERSION); return version.c_str(); } -- cgit v1.2.3 From e9f8a5441b0d737133a833cd240709962add56a5 Mon Sep 17 00:00:00 2001 From: callum Date: Wed, 25 May 2011 08:10:04 -0700 Subject: Added support for pushing agent global location on grid and agent orientation out to LLQtWebKit --- indra/llplugin/llpluginclassmedia.cpp | 27 ++++++++++++++++++++++ indra/llplugin/llpluginclassmedia.h | 2 ++ indra/media_plugins/webkit/media_plugin_webkit.cpp | 16 ++++++++++--- indra/newview/llviewermedia.cpp | 13 +++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index cc8fe53c3b..8f161201f4 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -474,6 +474,33 @@ void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z ) sendMessage( message ); } +void LLPluginClassMedia::jsAgentGlobalLocationEvent( double x, double y, double z ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_global_location"); + message.setValueReal( "x", x ); + message.setValueReal( "y", y ); + message.setValueReal( "z", z ); + sendMessage( message ); +} + +void LLPluginClassMedia::jsAgentOrientationEvent( double angle ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_orientation"); + message.setValueReal( "angle", angle ); + + sendMessage( message ); +} + void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language ) { if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 015fb31252..c061390699 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -122,6 +122,8 @@ public: void jsExposeObjectEvent( bool expose ); void jsValuesValidEvent( bool valid ); void jsAgentLocationEvent( double x, double y, double z ); + void jsAgentGlobalLocationEvent( double x, double y, double z ); + void jsAgentOrientationEvent( double angle ); void jsAgentLanguageEvent( const std::string& language ); void jsAgentRegionEvent( const std::string& region_name ); void jsAgentMaturityEvent( const std::string& maturity ); diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index bdfbde8494..27f3c7260e 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -1194,11 +1194,21 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) #endif } else - if(message_name == "js_agent_language") + if(message_name == "js_agent_global_location") { #if LLQTWEBKIT_API_VERSION >= 9 - const std::string& language = message_in.getValue("language"); - LLQtWebKit::getInstance()->setAgentLanguage( language ); + F32 x = message_in.getValueReal("x"); + F32 y = message_in.getValueReal("y"); + F32 z = message_in.getValueReal("z"); + LLQtWebKit::getInstance()->setAgentGlobalLocation( x, y, z ); +#endif + } + else + if(message_name == "js_agent_orientation") + { +#if LLQTWEBKIT_API_VERSION >= 9 + F32 angle = message_in.getValueReal("angle"); + LLQtWebKit::getInstance()->setAgentOrientation( angle ); #endif } else diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 2b9f32f6f5..c88c07942e 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -2365,6 +2365,19 @@ void LLViewerMediaImpl::updateJavascriptObject() double z = agent_pos.mV[ VZ ]; mMediaSource->jsAgentLocationEvent( x, y, z ); + // current location within the grid + LLVector3d agent_pos_global = gAgent.getLastPositionGlobal(); + double global_x = agent_pos_global.mdV[ VX ]; + double global_y = agent_pos_global.mdV[ VY ]; + double global_z = agent_pos_global.mdV[ VZ ]; + mMediaSource->jsAgentGlobalLocationEvent( global_x, global_y, global_z ); + + // current agent orientation + double rotation = atan2( gAgent.getAtAxis().mV[VX], gAgent.getAtAxis().mV[VY] ); + double angle = rotation * RAD_TO_DEG; + if ( angle < 0.0f ) angle = 360.0f + angle; // TODO: has to be a better way to get orientation! + mMediaSource->jsAgentOrientationEvent( angle ); + // current region agent is in std::string region_name(""); LLViewerRegion* region = gAgent.getRegion(); -- cgit v1.2.3 From 57bdcd6bda363fc8df21563597419f12c87f7b15 Mon Sep 17 00:00:00 2001 From: Logan Dethrow Date: Wed, 25 May 2011 15:44:03 -0400 Subject: VWR-25862 Potential fix for caches not clearing when they are supposed to. * Removed leading delimiter from filename mask in all calls to LLDir::deleteFilesInDir() that are related to the viewer asset caches (texture, VFS, and VO). --- indra/newview/llappviewer.cpp | 12 +++++------- indra/newview/lltexturecache.cpp | 4 ++-- indra/newview/llvocache.cpp | 4 ++-- 3 files changed, 9 insertions(+), 11 deletions(-) (limited to 'indra') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 75b6c18c57..4963fdc170 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3732,14 +3732,12 @@ bool LLAppViewer::initCache() dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""); std::string mask; - mask = gDirUtilp->getDirDelimiter(); - mask += VFS_DATA_FILE_BASE; + mask = VFS_DATA_FILE_BASE; mask += "*"; gDirUtilp->deleteFilesInDir(dir, mask); - mask = gDirUtilp->getDirDelimiter(); - mask += VFS_INDEX_FILE_BASE; + mask = VFS_INDEX_FILE_BASE; mask += "*"; gDirUtilp->deleteFilesInDir(dir, mask); @@ -3805,11 +3803,11 @@ bool LLAppViewer::initCache() void LLAppViewer::purgeCache() { - LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << llendl; + LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL; LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE); LLVOCache::getInstance()->removeCache(LL_PATH_CACHE); - std::string mask = gDirUtilp->getDirDelimiter() + "*.*"; - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask); + std::string mask = "*.*"; + gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), mask); } std::string LLAppViewer::getSecondLifeTitle() const diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 7fb52c1939..faab6ac002 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -1513,12 +1513,12 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) { const char* subdirs = "0123456789abcdef"; std::string delem = gDirUtilp->getDirDelimiter(); - std::string mask = delem + "*"; + std::string mask = "*"; for (S32 i=0; i<16; i++) { std::string dirname = mTexturesDirName + delem + subdirs[i]; llinfos << "Deleting files in directory: " << dirname << llendl; - gDirUtilp->deleteFilesInDir(dirname,mask); + gDirUtilp->deleteFilesInDir(dirname, mask); if (purge_directories) { LLFile::rmdir(dirname); diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index c605ddb1c8..99035244a2 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -342,7 +342,7 @@ void LLVOCache::removeCache(ELLPath location) llinfos << "about to remove the object cache due to settings." << llendl ; std::string delem = gDirUtilp->getDirDelimiter(); - std::string mask = delem + "*"; + std::string mask = "*"; std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname); llinfos << "Removing cache at " << cache_dir << llendl; gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files @@ -364,7 +364,7 @@ void LLVOCache::removeCache() llinfos << "about to remove the object cache due to some error." << llendl ; std::string delem = gDirUtilp->getDirDelimiter(); - std::string mask = delem + "*"; + std::string mask = "*"; llinfos << "Removing cache at " << mObjectCacheDirName << llendl; gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask); -- cgit v1.2.3 From 8c97ed86ff725b9fea444ac00b4a33e76920e737 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 25 May 2011 14:38:53 -0600 Subject: fix for SH-1624: Crash during viewer startup: LLViewerTextureList::addImageToList --- indra/newview/llappviewer.cpp | 13 ++++++++++++- indra/newview/llviewertexturelist.cpp | 11 ++++++----- indra/newview/llviewertexturelist.h | 1 + 3 files changed, 19 insertions(+), 6 deletions(-) (limited to 'indra') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 75b6c18c57..a0be252ab2 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -739,6 +739,8 @@ bool LLAppViewer::init() } initThreads(); + LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ; ; + writeSystemInfo(); // Initialize updater service (now that we have an io pump) @@ -765,6 +767,10 @@ bool LLAppViewer::init() LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL; LL_INFOS("InitInfo") << "libcurl version is: " << LLCurl::getVersionString() << LL_ENDL; + //Note: --bao + //allow to start texture fetching, must be called after initThreads(); + gTextureList.start() ; + // Get the single value from the crash settings file, if it exists std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); gCrashSettings.loadFromFile(crash_settings_filename); @@ -773,6 +779,7 @@ bool LLAppViewer::init() gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ALWAYS_SEND); gCrashSettings.saveToFile(crash_settings_filename, FALSE); } + LL_INFOS("InitInfo") << "Crash settings done." << LL_ENDL ; ///////////////////////////////////////////////// // OS-specific login dialogs @@ -821,6 +828,8 @@ bool LLAppViewer::init() // Let code in llui access the viewer help floater LLUI::sHelpImpl = LLViewerHelp::getInstance(); + LL_INFOS("InitInfo") << "UI initialization is done." << LL_ENDL ; + // Load translations for tooltips LLFloater::initClass(); @@ -890,7 +899,8 @@ bool LLAppViewer::init() OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK); return 1; } - + LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ; + // Initialize the repeater service. LLMainLoopRepeater::instance().start(); @@ -899,6 +909,7 @@ bool LLAppViewer::init() // gGLActive = TRUE; initWindow(); + LL_INFOS("InitInfo") << "Window is initialized." << LL_ENDL ; // initWindow also initializes the Feature List, so now we can initialize this global. LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index cd6653b0c7..a50361add2 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -88,15 +88,16 @@ LLViewerTextureList::LLViewerTextureList() { } -void LLViewerTextureList::init() +void LLViewerTextureList::start() { sRenderThreadID = LLThread::currentID() ; - + mInitialized = TRUE ; sNumImages = 0; - mMaxResidentTexMemInMegaBytes = 0; - mMaxTotalTextureMemInMegaBytes = 0 ; - +} + +void LLViewerTextureList::init() +{ mUpdateStats = TRUE; // Update how much texture RAM we're allowed to use. diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index d02b6be6b5..772f533bbb 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -78,6 +78,7 @@ public: LLViewerTextureList(); ~LLViewerTextureList(); + void start(); void init(); void shutdown(); void dump(); -- cgit v1.2.3 From e6ecf1ee7ea73139fa134fb6bc6e0088009c9f7e Mon Sep 17 00:00:00 2001 From: callum Date: Wed, 25 May 2011 18:00:46 -0700 Subject: Replaced my test page with more generic URL for Web floater test at login page --- indra/newview/skins/default/xui/en/menu_login.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index 32c1d7083a..4c4ff3e5c4 100644 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -187,7 +187,7 @@ name="Web Content Floater Debug Test"> + parameter="http://google.com"/> Date: Wed, 25 May 2011 18:10:58 -0700 Subject: EXP-829 FIX Text Box Alignment bug EXP-755 FIX [PUBLIC] 'Search' and 'World Map' links in Sidebar are unclickable fixed issues with UI scaling and text layout as well as incorrect text editor rect transforms reviewed by Callum --- indra/llrender/llfontgl.cpp | 2 +- indra/llui/lltextbase.cpp | 119 ++++++++++++++++++++++---------------------- 2 files changed, 61 insertions(+), 60 deletions(-) (limited to 'indra') diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 13008292f6..62aa49d235 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -555,7 +555,7 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch BOOL in_word = FALSE; // avoid S32 overflow when max_pixels == S32_MAX by staying in floating point - F32 scaled_max_pixels = ceil(max_pixels * sScaleX); + F32 scaled_max_pixels = max_pixels * sScaleX; F32 width_padding = 0.f; LLFontGlyphInfo* next_glyph = NULL; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index fd7bb699f8..c4430593ad 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -280,7 +280,7 @@ bool LLTextBase::truncate() if (getLength() >= S32(mMaxTextByteLength / 4)) { // Have to check actual byte size - LLWString text(getWText()); + LLWString text(getWText()); S32 utf8_byte_size = wstring_utf8_length(text); if ( utf8_byte_size > mMaxTextByteLength ) { @@ -547,8 +547,7 @@ void LLTextBase::drawText() } LLRect text_rect(line.mRect); - text_rect.mRight = llmin(mDocumentView->getRect().getWidth(), text_rect.mRight); // clamp right edge to document extents - text_rect.translate(mVisibleTextRect.mLeft, mVisibleTextRect.mBottom); // translate into display region of text widget + text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position // draw a single line of text @@ -655,7 +654,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s } text.insert(pos, wstr); - getViewModel()->setDisplay(text); + getViewModel()->setDisplay(text); if ( truncate() ) { @@ -670,7 +669,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length) { - LLWString text(getWText()); + LLWString text(getWText()); segment_set_t::iterator seg_iter = getSegIterContaining(pos); while(seg_iter != mSegments.end()) { @@ -717,7 +716,7 @@ S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length) } text.erase(pos, length); - getViewModel()->setDisplay(text); + getViewModel()->setDisplay(text); // recreate default segment in case we erased everything createDefaultSegment(); @@ -734,9 +733,9 @@ S32 LLTextBase::overwriteCharNoUndo(S32 pos, llwchar wc) { return 0; } - LLWString text(getWText()); + LLWString text(getWText()); text[pos] = wc; - getViewModel()->setDisplay(text); + getViewModel()->setDisplay(text); onValueChange(pos, pos + 1); needsReflow(pos); @@ -857,7 +856,7 @@ BOOL LLTextBase::handleMouseUp(S32 x, S32 y, MASK mask) // Did we just click on a link? if (mURLClickSignal && cur_segment->getStyle() - && cur_segment->getStyle()->isLink()) + && cur_segment->getStyle()->isLink()) { // *TODO: send URL here? (*mURLClickSignal)(this, LLSD() ); @@ -1035,27 +1034,27 @@ void LLTextBase::draw() gl_rect_2d(text_rect, bg_color % alpha, TRUE); } - bool should_clip = mClip || mScroller != NULL; - { LLLocalClipRect clip(text_rect, should_clip); + bool should_clip = mClip || mScroller != NULL; + { LLLocalClipRect clip(text_rect, should_clip); - // draw document view - if (mScroller) + // draw document view + if (mScroller) + { + drawChild(mScroller); + } + else { - drawChild(mScroller); - } - else - { - drawChild(mDocumentView); - } + drawChild(mDocumentView); + } drawSelectionBackground(); drawText(); drawCursor(); } - mDocumentView->setVisible(FALSE); - LLUICtrl::draw(); - mDocumentView->setVisible(TRUE); + mDocumentView->setVisible(FALSE); + LLUICtrl::draw(); + mDocumentView->setVisible(TRUE); } @@ -1119,8 +1118,7 @@ void LLTextBase::updateScrollFromCursor() // scroll so that the cursor is at the top of the page LLRect scroller_doc_window = getVisibleDocumentRect(); - LLRect cursor_rect_doc = getLocalRectFromDocIndex(mCursorPos); - cursor_rect_doc.translate(scroller_doc_window.mLeft, scroller_doc_window.mBottom); + LLRect cursor_rect_doc = getDocRectFromDocIndex(mCursorPos); mScroller->scrollToShowRect(cursor_rect_doc, LLRect(0, scroller_doc_window.getHeight() - 5, scroller_doc_window.getWidth(), 5)); } @@ -1366,9 +1364,9 @@ S32 LLTextBase::getLineStart( S32 line ) const { S32 num_lines = getLineCount(); if (num_lines == 0) - { + { return 0; - } + } line = llclamp(line, 0, num_lines-1); return mLineInfoList[line].mDocIndexStart; @@ -1378,9 +1376,9 @@ S32 LLTextBase::getLineEnd( S32 line ) const { S32 num_lines = getLineCount(); if (num_lines == 0) - { + { return 0; - } + } line = llclamp(line, 0, num_lines-1); return mLineInfoList[line].mDocIndexEnd; @@ -1656,7 +1654,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para LLUrlMatch match; std::string text = new_text; while ( LLUrlRegistry::instance().findUrl(text, match, - boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3)) ) + boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3)) ) { start = match.getStart(); end = match.getEnd()+1; @@ -1950,7 +1948,7 @@ void LLTextBase::setWText(const LLWString& text) const LLWString& LLTextBase::getWText() const { - return getViewModel()->getDisplay(); + return getViewModel()->getDisplay(); } // If round is true, if the position is on the right half of a character, the cursor @@ -1961,9 +1959,12 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, { // Figure out which line we're nearest to. LLRect visible_region = getVisibleDocumentRect(); + LLRect doc_rect = mDocumentView->getRect(); + + S32 doc_y = local_y - doc_rect.mBottom; // binary search for line that starts before local_y - line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), local_y - mVisibleTextRect.mBottom + visible_region.mBottom, compare_bottom()); + line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), doc_y, compare_bottom()); if (line_iter == mLineInfoList.end()) { @@ -1971,7 +1972,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, } S32 pos = getLength(); - S32 start_x = mVisibleTextRect.mLeft + line_iter->mRect.mLeft - visible_region.mLeft; + S32 start_x = line_iter->mRect.mLeft + doc_rect.mLeft; segment_set_t::iterator line_seg_iter; S32 line_seg_offset; @@ -1993,7 +1994,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, } // if we've reached a line of text *below* the mouse cursor, doc index is first character on that line - if (hit_past_end_of_line && local_y - mVisibleTextRect.mBottom + visible_region.mBottom > line_iter->mRect.mTop) + if (hit_past_end_of_line && doc_y > line_iter->mRect.mTop) { pos = segment_line_start; break; @@ -2462,7 +2463,7 @@ LLRect LLTextBase::getVisibleDocumentRect() const LLRect doc_rect = mDocumentView->getLocalRect(); doc_rect.mLeft -= mDocumentView->getRect().mLeft; // adjust for height of text above widget baseline - doc_rect.mBottom = llmin(0, doc_rect.getHeight() - mVisibleTextRect.getHeight()); + doc_rect.mBottom = doc_rect.getHeight() - mVisibleTextRect.getHeight(); return doc_rect; } } @@ -2576,21 +2577,21 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele LLColor4 color = (mEditor.getReadOnly() ? mStyle->getReadOnlyColor() : mStyle->getColor()) % alpha; - if( selection_start > seg_start ) + if( selection_start > seg_start ) { // Draw normally S32 start = seg_start; S32 end = llmin( selection_start, seg_end ); S32 length = end - start; font->render(text, start, - rect, - color, - LLFontGL::LEFT, mEditor.mVAlign, - LLFontGL::NORMAL, - mStyle->getShadowType(), - length, - &right_x, - mEditor.getUseEllipses()); + rect, + color, + LLFontGL::LEFT, mEditor.mVAlign, + LLFontGL::NORMAL, + mStyle->getShadowType(), + length, + &right_x, + mEditor.getUseEllipses()); } rect.mLeft = (S32)ceil(right_x); @@ -2602,14 +2603,14 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele S32 length = end - start; font->render(text, start, - rect, - mStyle->getSelectedColor().get(), - LLFontGL::LEFT, mEditor.mVAlign, - LLFontGL::NORMAL, - LLFontGL::NO_SHADOW, - length, - &right_x, - mEditor.getUseEllipses()); + rect, + mStyle->getSelectedColor().get(), + LLFontGL::LEFT, mEditor.mVAlign, + LLFontGL::NORMAL, + LLFontGL::NO_SHADOW, + length, + &right_x, + mEditor.getUseEllipses()); } rect.mLeft = (S32)ceil(right_x); if( selection_end < seg_end ) @@ -2619,14 +2620,14 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele S32 end = seg_end; S32 length = end - start; font->render(text, start, - rect, - color, - LLFontGL::LEFT, mEditor.mVAlign, - LLFontGL::NORMAL, - mStyle->getShadowType(), - length, - &right_x, - mEditor.getUseEllipses()); + rect, + color, + LLFontGL::LEFT, mEditor.mVAlign, + LLFontGL::NORMAL, + mStyle->getShadowType(), + length, + &right_x, + mEditor.getUseEllipses()); } return right_x; } -- cgit v1.2.3 From cb3875fe72b120251c289302b958243e08a24e5b Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 26 May 2011 12:00:58 -0400 Subject: SH-1527 FIXED Fix for black alpha objects with lighting and shadows enabled and no lights around. --- .../shaders/class1/deferred/alphaSkinnedV.glsl | 25 +++++++++++++--------- .../shaders/class1/deferred/alphaV.glsl | 25 +++++++++++++--------- .../shaders/class1/deferred/avatarAlphaV.glsl | 25 +++++++++++++--------- .../shaders/class2/deferred/alphaSkinnedV.glsl | 25 +++++++++++++--------- .../shaders/class2/deferred/alphaV.glsl | 25 +++++++++++++--------- .../shaders/class2/deferred/avatarAlphaV.glsl | 25 +++++++++++++--------- 6 files changed, 90 insertions(+), 60 deletions(-) (limited to 'indra') diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl index 5addbbb176..65d9209983 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl @@ -35,19 +35,24 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //get distance float d = length(lv); - //normalize light vector - lv *= 1.0/d; + float da = 0.0; + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv *= 1.0/d; - //distance attenuation - float dist2 = d*d/(la*la); - float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + //distance attenuation + float dist2 = d*d/(la*la); + da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 - //angular attenuation - da *= calcDirectionalLight(n, lv); + //angular attenuation + da *= calcDirectionalLight(n, lv); + } return da; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl index 525b68c437..2691fc8ded 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl @@ -36,19 +36,24 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //get distance float d = length(lv); - //normalize light vector - lv *= 1.0/d; + float da = 0.0; + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv *= 1.0/d; - //distance attenuation - float dist2 = d*d/(la*la); - float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + //distance attenuation + float dist2 = d*d/(la*la); + da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 - //angular attenuation - da *= calcDirectionalLight(n, lv); + //angular attenuation + da *= calcDirectionalLight(n, lv); + } return da; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl index a2a7dea20d..a012cb5030 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl @@ -35,19 +35,24 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //get distance float d = length(lv); - //normalize light vector - lv *= 1.0/d; + float da = 0.0; + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv *= 1.0/d; - //distance attenuation - float dist2 = d*d/(la*la); - float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + //distance attenuation + float dist2 = d*d/(la*la); + da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 - //angular attenuation - da *= calcDirectionalLight(n, lv); + //angular attenuation + da *= calcDirectionalLight(n, lv); + } return da; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl index d227346163..dfb36980b0 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl @@ -35,19 +35,24 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //get distance float d = length(lv); - //normalize light vector - lv *= 1.0/d; + float da = 0.0; + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv *= 1.0/d; - //distance attenuation - float dist2 = d*d/(la*la); - float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + //distance attenuation + float dist2 = d*d/(la*la); + da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 - //angular attenuation - da *= calcDirectionalLight(n, lv); + //angular attenuation + da *= calcDirectionalLight(n, lv); + } return da; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl index 86f014df35..f6160815eb 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl @@ -35,19 +35,24 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //get distance float d = length(lv); - //normalize light vector - lv *= 1.0/d; + float da = 0.0; + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv *= 1.0/d; - //distance attenuation - float dist2 = d*d/(la*la); - float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + //distance attenuation + float dist2 = d*d/(la*la); + da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 - //angular attenuation - da *= calcDirectionalLight(n, lv); + //angular attenuation + da *= calcDirectionalLight(n, lv); + } return da; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl index 495e86c8db..0ae09df0c6 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl @@ -37,19 +37,24 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //get distance float d = length(lv); - //normalize light vector - lv *= 1.0/d; + float da = 0.0; + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv *= 1.0/d; - //distance attenuation - float dist2 = d*d/(la*la); - float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + //distance attenuation + float dist2 = d*d/(la*la); + da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 - //angular attenuation - da *= calcDirectionalLight(n, lv); + //angular attenuation + da *= calcDirectionalLight(n, lv); + } return da; } -- cgit v1.2.3 From 303a59e7bc8537a63aee42f738fff8a79049c2a2 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 26 May 2011 14:16:56 -0400 Subject: dos2unix fixes for newview files. --- indra/newview/llaccountingquotamanager.cpp | 528 +- indra/newview/lldrawpoolbump.cpp | 6 +- indra/newview/llfeaturemanager.cpp | 1614 ++-- indra/newview/llfloaterbuyland.cpp | 18 +- indra/newview/llpanelobject.cpp | 3998 +++++----- indra/newview/llviewermessage.cpp | 8 +- indra/newview/llviewerobject.cpp | 11424 +++++++++++++-------------- indra/newview/llviewerobject.h | 1650 ++-- indra/newview/llviewerparcelmgr.cpp | 6 +- indra/newview/llviewerprecompiledheaders.h | 4 +- indra/newview/llviewertexturelist.cpp | 4 +- 11 files changed, 9630 insertions(+), 9630 deletions(-) (limited to 'indra') diff --git a/indra/newview/llaccountingquotamanager.cpp b/indra/newview/llaccountingquotamanager.cpp index ada74ea44c..d11b86db15 100644 --- a/indra/newview/llaccountingquotamanager.cpp +++ b/indra/newview/llaccountingquotamanager.cpp @@ -1,264 +1,264 @@ -/** - * @file LLAccountingQuotaManager.cpp - * @ Handles the setting and accessing for costs associated with mesh - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2010, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llaccountingquotamanager.h" -#include "llagent.h" -#include "llviewerregion.h" -#include "llviewerobject.h" -#include "llviewerobjectlist.h" -#include "llviewerparcelmgr.h" -#include "llparcel.h" - -//=============================================================================== -LLAccountingQuotaManager::LLAccountingQuotaManager() -{ -} -//=============================================================================== -class LLAccountingQuotaResponder : public LLCurl::Responder -{ -public: - LLAccountingQuotaResponder( const LLSD& objectIDs ) - : mObjectIDs( objectIDs ) - { - } - - void clearPendingRequests ( void ) - { - for ( LLSD::array_iterator iter = mObjectIDs.beginArray(); iter != mObjectIDs.endArray(); ++iter ) - { - LLAccountingQuotaManager::getInstance()->removePendingObjectQuota( iter->asUUID() ); - } - } - - void error( U32 statusNum, const std::string& reason ) - { - llwarns << "Transport error "<asUUID(); - - LLAccountingQuotaManager::getInstance()->removePendingObjectQuota( objectID ); - - if ( containsParcel ) - { - //Typically should be one - S32 dataCount = content["parcel"].size(); - for(S32 i = 0; i < dataCount; i++) - { - //prep#todo verify that this is safe, otherwise just add a bool - S32 parcelId = 0; - S32 parcelOwner = 0; - if ( content["parcel"][i].has("parcel_id") ) - { - parcelId = content["parcel"][i]["parcel_id"].asInteger(); - } - if ( content["parcel"][i].has("parcel_owner") ) - { - parcelOwner = content["parcel"][i]["parcel_owner"].asInteger(); - } - - F32 ownerRenderCost = 0; - F32 ownerPhysicsCost = 0; - F32 ownerNetworkCost = 0; - F32 ownerSimulationCost = 0; - - F32 groupRenderCost = 0; - F32 groupPhysicsCost = 0; - F32 groupNetworkCost = 0; - F32 groupSimulationCost = 0; - - F32 otherRenderCost = 0; - F32 otherPhysicsCost = 0; - F32 otherNetworkCost = 0; - F32 otherSimulationCost = 0; - - F32 totalRenderCost = 0; - F32 totalPhysicsCost = 0; - F32 totalNetworkCost = 0; - F32 totalSimulationCost = 0; - - if ( content["parcel"][i].has("owner") ) - { - ownerRenderCost = content["parcel"][i]["owner"]["render"].asReal(); - ownerPhysicsCost = content["parcel"][i]["owner"]["physics"].asReal(); - ownerNetworkCost = content["parcel"][i]["owner"]["network"].asReal(); - ownerSimulationCost = content["parcel"][i]["owner"]["simulation"].asReal(); - - } - if ( content["parcel"][i].has("group") ) - { - groupRenderCost = content["parcel"][i]["group"]["render"].asReal(); - groupPhysicsCost = content["parcel"][i]["group"]["physics"].asReal(); - groupNetworkCost = content["parcel"][i]["group"]["network"].asReal(); - groupSimulationCost = content["parcel"][i]["group"]["simulation"].asReal(); - - } - if ( content["parcel"][i].has("other") ) - { - otherRenderCost = content["parcel"][i]["other"]["render"].asReal(); - otherPhysicsCost = content["parcel"][i]["other"]["physics"].asReal(); - otherNetworkCost = content["parcel"][i]["other"]["network"].asReal(); - otherSimulationCost = content["parcel"][i]["other"]["simulation"].asReal(); - } - - if ( content["parcel"][i].has("total") ) - { - totalRenderCost = content["parcel"][i]["total"]["render"].asReal(); - totalPhysicsCost = content["parcel"][i]["total"]["physics"].asReal(); - totalNetworkCost = content["parcel"][i]["total"]["network"].asReal(); - totalSimulationCost = content["parcel"][i]["total"]["simulation"].asReal(); - - } - - ParcelQuota parcelQuota( ownerRenderCost, ownerPhysicsCost, ownerNetworkCost, ownerSimulationCost, - groupRenderCost, groupPhysicsCost, groupNetworkCost, groupSimulationCost, - otherRenderCost, otherPhysicsCost, otherNetworkCost, otherSimulationCost, - totalRenderCost, totalPhysicsCost, totalNetworkCost, totalSimulationCost ); - //Update the Parcel - LLParcel* pParcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); - if ( pParcel ) - { - pParcel->updateQuota( objectID, parcelQuota ); - } - } - } - else - if ( containsSelection ) - { - S32 dataCount = content["selected"].size(); - for(S32 i = 0; i < dataCount; i++) - { - - F32 renderCost = 0; - F32 physicsCost = 0; - F32 networkCost = 0; - F32 simulationCost = 0; - - S32 localId = 0; - - localId = content["selected"][i]["local_id"].asInteger(); - renderCost = content["selected"][i]["render"].asReal(); - physicsCost = content["selected"][i]["physics"].asReal(); - networkCost = content["selected"][i]["network"].asReal(); - simulationCost = content["selected"][i]["simulation"].asReal(); - - SelectionQuota selectionQuota( localId, renderCost, physicsCost, networkCost, simulationCost ); - - //Update the objects - //gObjectList.updateQuota( localId, selectionQuota ); - - } - } - else - { - //Nothing in string - LLAccountingQuotaManager::getInstance()->removePendingObjectQuota( objectID ); - } - } - } - -private: - //List of posted objects - LLSD mObjectIDs; -}; -//=============================================================================== -void LLAccountingQuotaManager::fetchQuotas( const std::string& url ) -{ - // Invoking system must have already determined capability availability - if ( !url.empty() ) - { - LLSD objectList; - U32 objectIndex = 0; - IDIt IDIter = mUpdateObjectQuota.begin(); - IDIt IDIterEnd = mUpdateObjectQuota.end(); - - for ( ; IDIter != IDIterEnd; ++IDIter ) - { - // Check to see if a request for this object has already been made. - if ( mPendingObjectQuota.find( *IDIter ) == mPendingObjectQuota.end() ) - { - mPendingObjectQuota.insert( *IDIter ); - objectList[objectIndex++] = *IDIter; - } - } - - mUpdateObjectQuota.clear(); - - //Post results - if ( objectList.size() > 0 ) - { - LLSD dataToPost = LLSD::emptyMap(); - dataToPost["object_ids"] = objectList; - LLHTTPClient::post( url, dataToPost, new LLAccountingQuotaResponder( objectList )); - } - } - else - { - //url was empty - warn & continue - llwarns<<"Supplied url is empty "<removePendingObjectQuota( iter->asUUID() ); + } + } + + void error( U32 statusNum, const std::string& reason ) + { + llwarns << "Transport error "<asUUID(); + + LLAccountingQuotaManager::getInstance()->removePendingObjectQuota( objectID ); + + if ( containsParcel ) + { + //Typically should be one + S32 dataCount = content["parcel"].size(); + for(S32 i = 0; i < dataCount; i++) + { + //prep#todo verify that this is safe, otherwise just add a bool + S32 parcelId = 0; + S32 parcelOwner = 0; + if ( content["parcel"][i].has("parcel_id") ) + { + parcelId = content["parcel"][i]["parcel_id"].asInteger(); + } + if ( content["parcel"][i].has("parcel_owner") ) + { + parcelOwner = content["parcel"][i]["parcel_owner"].asInteger(); + } + + F32 ownerRenderCost = 0; + F32 ownerPhysicsCost = 0; + F32 ownerNetworkCost = 0; + F32 ownerSimulationCost = 0; + + F32 groupRenderCost = 0; + F32 groupPhysicsCost = 0; + F32 groupNetworkCost = 0; + F32 groupSimulationCost = 0; + + F32 otherRenderCost = 0; + F32 otherPhysicsCost = 0; + F32 otherNetworkCost = 0; + F32 otherSimulationCost = 0; + + F32 totalRenderCost = 0; + F32 totalPhysicsCost = 0; + F32 totalNetworkCost = 0; + F32 totalSimulationCost = 0; + + if ( content["parcel"][i].has("owner") ) + { + ownerRenderCost = content["parcel"][i]["owner"]["render"].asReal(); + ownerPhysicsCost = content["parcel"][i]["owner"]["physics"].asReal(); + ownerNetworkCost = content["parcel"][i]["owner"]["network"].asReal(); + ownerSimulationCost = content["parcel"][i]["owner"]["simulation"].asReal(); + + } + if ( content["parcel"][i].has("group") ) + { + groupRenderCost = content["parcel"][i]["group"]["render"].asReal(); + groupPhysicsCost = content["parcel"][i]["group"]["physics"].asReal(); + groupNetworkCost = content["parcel"][i]["group"]["network"].asReal(); + groupSimulationCost = content["parcel"][i]["group"]["simulation"].asReal(); + + } + if ( content["parcel"][i].has("other") ) + { + otherRenderCost = content["parcel"][i]["other"]["render"].asReal(); + otherPhysicsCost = content["parcel"][i]["other"]["physics"].asReal(); + otherNetworkCost = content["parcel"][i]["other"]["network"].asReal(); + otherSimulationCost = content["parcel"][i]["other"]["simulation"].asReal(); + } + + if ( content["parcel"][i].has("total") ) + { + totalRenderCost = content["parcel"][i]["total"]["render"].asReal(); + totalPhysicsCost = content["parcel"][i]["total"]["physics"].asReal(); + totalNetworkCost = content["parcel"][i]["total"]["network"].asReal(); + totalSimulationCost = content["parcel"][i]["total"]["simulation"].asReal(); + + } + + ParcelQuota parcelQuota( ownerRenderCost, ownerPhysicsCost, ownerNetworkCost, ownerSimulationCost, + groupRenderCost, groupPhysicsCost, groupNetworkCost, groupSimulationCost, + otherRenderCost, otherPhysicsCost, otherNetworkCost, otherSimulationCost, + totalRenderCost, totalPhysicsCost, totalNetworkCost, totalSimulationCost ); + //Update the Parcel + LLParcel* pParcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); + if ( pParcel ) + { + pParcel->updateQuota( objectID, parcelQuota ); + } + } + } + else + if ( containsSelection ) + { + S32 dataCount = content["selected"].size(); + for(S32 i = 0; i < dataCount; i++) + { + + F32 renderCost = 0; + F32 physicsCost = 0; + F32 networkCost = 0; + F32 simulationCost = 0; + + S32 localId = 0; + + localId = content["selected"][i]["local_id"].asInteger(); + renderCost = content["selected"][i]["render"].asReal(); + physicsCost = content["selected"][i]["physics"].asReal(); + networkCost = content["selected"][i]["network"].asReal(); + simulationCost = content["selected"][i]["simulation"].asReal(); + + SelectionQuota selectionQuota( localId, renderCost, physicsCost, networkCost, simulationCost ); + + //Update the objects + //gObjectList.updateQuota( localId, selectionQuota ); + + } + } + else + { + //Nothing in string + LLAccountingQuotaManager::getInstance()->removePendingObjectQuota( objectID ); + } + } + } + +private: + //List of posted objects + LLSD mObjectIDs; +}; +//=============================================================================== +void LLAccountingQuotaManager::fetchQuotas( const std::string& url ) +{ + // Invoking system must have already determined capability availability + if ( !url.empty() ) + { + LLSD objectList; + U32 objectIndex = 0; + IDIt IDIter = mUpdateObjectQuota.begin(); + IDIt IDIterEnd = mUpdateObjectQuota.end(); + + for ( ; IDIter != IDIterEnd; ++IDIter ) + { + // Check to see if a request for this object has already been made. + if ( mPendingObjectQuota.find( *IDIter ) == mPendingObjectQuota.end() ) + { + mPendingObjectQuota.insert( *IDIter ); + objectList[objectIndex++] = *IDIter; + } + } + + mUpdateObjectQuota.clear(); + + //Post results + if ( objectList.size() > 0 ) + { + LLSD dataToPost = LLSD::emptyMap(); + dataToPost["object_ids"] = objectList; + LLHTTPClient::post( url, dataToPost, new LLAccountingQuotaResponder( objectList )); + } + } + else + { + //url was empty - warn & continue + llwarns<<"Supplied url is empty "< -#include - -#include - -#include "llfeaturemanager.h" -#include "lldir.h" - -#include "llsys.h" -#include "llgl.h" -#include "llsecondlifeurls.h" - -#include "llappviewer.h" -#include "llhttpclient.h" -#include "llnotificationsutil.h" -#include "llviewercontrol.h" -#include "llworld.h" -#include "lldrawpoolterrain.h" -#include "llviewertexturelist.h" -#include "llversioninfo.h" -#include "llwindow.h" -#include "llui.h" -#include "llcontrol.h" -#include "llboost.h" -#include "llweb.h" - -#if LL_WINDOWS -#include "lldxhardware.h" -#endif - - -#if LL_DARWIN -const char FEATURE_TABLE_FILENAME[] = "featuretable_mac.txt"; -const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_mac.%s.txt"; -#elif LL_LINUX -const char FEATURE_TABLE_FILENAME[] = "featuretable_linux.txt"; -const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_linux.%s.txt"; -#elif LL_SOLARIS -const char FEATURE_TABLE_FILENAME[] = "featuretable_solaris.txt"; -const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_solaris.%s.txt"; -#else -const char FEATURE_TABLE_FILENAME[] = "featuretable%s.txt"; -const char FEATURE_TABLE_VER_FILENAME[] = "featuretable%s.%s.txt"; -#endif - -const char GPU_TABLE_FILENAME[] = "gpu_table.txt"; -const char GPU_TABLE_VER_FILENAME[] = "gpu_table.%s.txt"; - -LLFeatureInfo::LLFeatureInfo(const std::string& name, const BOOL available, const F32 level) - : mValid(TRUE), mName(name), mAvailable(available), mRecommendedLevel(level) -{ -} - -LLFeatureList::LLFeatureList(const std::string& name) - : mName(name) -{ -} - -LLFeatureList::~LLFeatureList() -{ -} - -void LLFeatureList::addFeature(const std::string& name, const BOOL available, const F32 level) -{ - if (mFeatures.count(name)) - { - LL_WARNS("RenderInit") << "LLFeatureList::Attempting to add preexisting feature " << name << LL_ENDL; - } - - LLFeatureInfo fi(name, available, level); - mFeatures[name] = fi; -} - -BOOL LLFeatureList::isFeatureAvailable(const std::string& name) -{ - if (mFeatures.count(name)) - { - return mFeatures[name].mAvailable; - } - - LL_WARNS("RenderInit") << "Feature " << name << " not on feature list!" << LL_ENDL; - - // changing this to TRUE so you have to explicitly disable - // something for it to be disabled - return TRUE; -} - -F32 LLFeatureList::getRecommendedValue(const std::string& name) -{ - if (mFeatures.count(name) && isFeatureAvailable(name)) - { - return mFeatures[name].mRecommendedLevel; - } - - LL_WARNS("RenderInit") << "Feature " << name << " not on feature list or not available!" << LL_ENDL; - return 0; -} - -BOOL LLFeatureList::maskList(LLFeatureList &mask) -{ - //llinfos << "Masking with " << mask.mName << llendl; - // - // Lookup the specified feature mask, and overlay it on top of the - // current feature mask. - // - - LLFeatureInfo mask_fi; - - feature_map_t::iterator feature_it; - for (feature_it = mask.mFeatures.begin(); feature_it != mask.mFeatures.end(); ++feature_it) - { - mask_fi = feature_it->second; - // - // Look for the corresponding feature - // - if (!mFeatures.count(mask_fi.mName)) - { - LL_WARNS("RenderInit") << "Feature " << mask_fi.mName << " in mask not in top level!" << LL_ENDL; - continue; - } - - LLFeatureInfo &cur_fi = mFeatures[mask_fi.mName]; - if (mask_fi.mAvailable && !cur_fi.mAvailable) - { - LL_WARNS("RenderInit") << "Mask attempting to reenabling disabled feature, ignoring " << cur_fi.mName << LL_ENDL; - continue; - } - cur_fi.mAvailable = mask_fi.mAvailable; - cur_fi.mRecommendedLevel = llmin(cur_fi.mRecommendedLevel, mask_fi.mRecommendedLevel); - LL_DEBUGS("RenderInit") << "Feature mask " << mask.mName - << " Feature " << mask_fi.mName - << " Mask: " << mask_fi.mRecommendedLevel - << " Now: " << cur_fi.mRecommendedLevel << LL_ENDL; - } - - LL_DEBUGS("RenderInit") << "After applying mask " << mask.mName << std::endl; - // Will conditionally call dump only if the above message will be logged, thanks - // to it being wrapped by the LL_DEBUGS and LL_ENDL macros. - dump(); - LL_CONT << LL_ENDL; - - return TRUE; -} - -void LLFeatureList::dump() -{ - LL_DEBUGS("RenderInit") << "Feature list: " << mName << LL_ENDL; - LL_DEBUGS("RenderInit") << "--------------" << LL_ENDL; - - LLFeatureInfo fi; - feature_map_t::iterator feature_it; - for (feature_it = mFeatures.begin(); feature_it != mFeatures.end(); ++feature_it) - { - fi = feature_it->second; - LL_DEBUGS("RenderInit") << fi.mName << "\t\t" << fi.mAvailable << ":" << fi.mRecommendedLevel << LL_ENDL; - } - LL_DEBUGS("RenderInit") << LL_ENDL; -} - -LLFeatureList *LLFeatureManager::findMask(const std::string& name) -{ - if (mMaskList.count(name)) - { - return mMaskList[name]; - } - - return NULL; -} - -BOOL LLFeatureManager::maskFeatures(const std::string& name) -{ - LLFeatureList *maskp = findMask(name); - if (!maskp) - { - LL_DEBUGS("RenderInit") << "Unknown feature mask " << name << LL_ENDL; - return FALSE; - } - LL_INFOS("RenderInit") << "Applying GPU Feature list: " << name << LL_ENDL; - return maskList(*maskp); -} - -BOOL LLFeatureManager::loadFeatureTables() -{ - // *TODO - if I or anyone else adds something else to the skipped list - // make this data driven. Put it in the feature table and parse it - // correctly - mSkippedFeatures.insert("RenderAnisotropic"); - mSkippedFeatures.insert("RenderGamma"); - mSkippedFeatures.insert("RenderVBOEnable"); - mSkippedFeatures.insert("RenderFogRatio"); - - // first table is install with app - std::string app_path = gDirUtilp->getAppRODataDir(); - app_path += gDirUtilp->getDirDelimiter(); - - std::string filename; - std::string http_filename; -#if LL_WINDOWS - std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); - if (os_string.find("Microsoft Windows XP") == 0) - { - filename = llformat(FEATURE_TABLE_FILENAME, "_xp"); - http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "_xp", LLVersionInfo::getVersion().c_str()); - } - else - { - filename = llformat(FEATURE_TABLE_FILENAME, ""); - http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "", LLVersionInfo::getVersion().c_str()); - } -#else - filename = FEATURE_TABLE_FILENAME; - http_filename = llformat(FEATURE_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str()); -#endif - - app_path += filename; - - - // second table is downloaded with HTTP - std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename); - - // use HTTP table if it exists - std::string path; - if (gDirUtilp->fileExists(http_path)) - { - path = http_path; - } - else - { - path = app_path; - } - - - return parseFeatureTable(path); -} - - -BOOL LLFeatureManager::parseFeatureTable(std::string filename) -{ - llinfos << "Looking for feature table in " << filename << llendl; - - llifstream file; - std::string name; - U32 version; - - file.open(filename); /*Flawfinder: ignore*/ - - if (!file) - { - LL_WARNS("RenderInit") << "Unable to open feature table " << filename << LL_ENDL; - return FALSE; - } - - // Check file version - file >> name; - file >> version; - if (name != "version") - { - LL_WARNS("RenderInit") << filename << " does not appear to be a valid feature table!" << LL_ENDL; - return FALSE; - } - - mTableVersion = version; - - LLFeatureList *flp = NULL; - while (file >> name) - { - char buffer[MAX_STRING]; /*Flawfinder: ignore*/ - - if (name.substr(0,2) == "//") - { - // This is a comment. - file.getline(buffer, MAX_STRING); - continue; - } - - if (name == "list") - { - if (flp) - { - //flp->dump(); - } - // It's a new mask, create it. - file >> name; - if (mMaskList.count(name)) - { - LL_ERRS("RenderInit") << "Overriding mask " << name << ", this is invalid!" << LL_ENDL; - } - - flp = new LLFeatureList(name); - mMaskList[name] = flp; - } - else - { - if (!flp) - { - LL_ERRS("RenderInit") << "Specified parameter before keyword!" << LL_ENDL; - return FALSE; - } - S32 available; - F32 recommended; - file >> available >> recommended; - flp->addFeature(name, available, recommended); - } - } - file.close(); - - return TRUE; -} - -void LLFeatureManager::loadGPUClass() -{ - // defaults - mGPUClass = GPU_CLASS_UNKNOWN; - mGPUString = gGLManager.getRawGLString(); - mGPUSupported = FALSE; - - // first table is in the app dir - std::string app_path = gDirUtilp->getAppRODataDir(); - app_path += gDirUtilp->getDirDelimiter(); - app_path += GPU_TABLE_FILENAME; - - // second table is downloaded with HTTP - std::string http_filename = llformat(GPU_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str()); - std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename); - - // use HTTP table if it exists - std::string path; - if (gDirUtilp->fileExists(http_path)) - { - path = http_path; - } - else - { - path = app_path; - } - - parseGPUTable(path); -} - - -void LLFeatureManager::parseGPUTable(std::string filename) -{ - llifstream file; - - file.open(filename); - - if (!file) - { - LL_WARNS("RenderInit") << "Unable to open GPU table: " << filename << "!" << LL_ENDL; - return; - } - - std::string rawRenderer = gGLManager.getRawGLString(); - std::string renderer = rawRenderer; - for (std::string::iterator i = renderer.begin(); i != renderer.end(); ++i) - { - *i = tolower(*i); - } - - bool gpuFound; - U32 lineNumber; - for (gpuFound = false, lineNumber = 0; !gpuFound && !file.eof(); lineNumber++) - { - char buffer[MAX_STRING]; /*Flawfinder: ignore*/ - buffer[0] = 0; - - file.getline(buffer, MAX_STRING); - - if (strlen(buffer) >= 2 && /*Flawfinder: ignore*/ - buffer[0] == '/' && - buffer[1] == '/') - { - // This is a comment. - continue; - } - - if (strlen(buffer) == 0) /*Flawfinder: ignore*/ - { - // This is a blank line - continue; - } - - // setup the tokenizer - std::string buf(buffer); - std::string cls, label, expr, supported; - boost_tokenizer tokens(buf, boost::char_separator("\t\n")); - boost_tokenizer::iterator token_iter = tokens.begin(); - - // grab the label, pseudo regular expression, and class - if(token_iter != tokens.end()) - { - label = *token_iter++; - } - if(token_iter != tokens.end()) - { - expr = *token_iter++; - } - if(token_iter != tokens.end()) - { - cls = *token_iter++; - } - if(token_iter != tokens.end()) - { - supported = *token_iter++; - } - - if (label.empty() || expr.empty() || cls.empty() || supported.empty()) - { - LL_WARNS("RenderInit") << "invald gpu_table.txt:" << lineNumber << ": '" << buffer << "'" << LL_ENDL; - continue; - } - - for (U32 i = 0; i < expr.length(); i++) /*Flawfinder: ignore*/ - { - expr[i] = tolower(expr[i]); - } - - // run the regular expression against the renderer - boost::regex re(expr.c_str()); - if(boost::regex_search(renderer, re)) - { - // if we found it, stop! - gpuFound = true; - mGPUString = label; - mGPUClass = (EGPUClass) strtol(cls.c_str(), NULL, 10); - mGPUSupported = (BOOL) strtol(supported.c_str(), NULL, 10); - } - } - file.close(); - - if ( gpuFound ) - { - LL_INFOS("RenderInit") << "GPU '" << rawRenderer << "' recognized as '" << mGPUString << "'" << LL_ENDL; - if (!mGPUSupported) - { - LL_INFOS("RenderInit") << "GPU '" << mGPUString << "' is not supported." << LL_ENDL; - } - } - else - { - LL_WARNS("RenderInit") << "GPU '" << rawRenderer << "' not recognized" << LL_ENDL; - } -} - -// responder saves table into file -class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder -{ -public: - - LLHTTPFeatureTableResponder(std::string filename) : - mFilename(filename) - { - } - - - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - if (isGoodStatus(status)) - { - // write to file - - llinfos << "writing feature table to " << mFilename << llendl; - - S32 file_size = buffer->countAfter(channels.in(), NULL); - if (file_size > 0) - { - // read from buffer - U8* copy_buffer = new U8[file_size]; - buffer->readAfter(channels.in(), NULL, copy_buffer, file_size); - - // write to file - LLAPRFile out(mFilename, LL_APR_WB); - out.write(copy_buffer, file_size); - out.close(); - } - } - - } - -private: - std::string mFilename; -}; - -void fetch_feature_table(std::string table) -{ - const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable"); - -#if LL_WINDOWS - std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); - std::string filename; - if (os_string.find("Microsoft Windows XP") == 0) - { - filename = llformat(table.c_str(), "_xp", LLVersionInfo::getVersion().c_str()); - } - else - { - filename = llformat(table.c_str(), "", LLVersionInfo::getVersion().c_str()); - } -#else - const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str()); -#endif - - const std::string url = base + "/" + filename; - - const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); - - llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl; - - LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path)); -} - -void fetch_gpu_table(std::string table) -{ - const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable"); - - const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str()); - - const std::string url = base + "/" + filename; - - const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); - - llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl; - - LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path)); -} - -// fetch table(s) from a website (S3) -void LLFeatureManager::fetchHTTPTables() -{ - fetch_feature_table(FEATURE_TABLE_VER_FILENAME); - fetch_gpu_table(GPU_TABLE_VER_FILENAME); -} - - -void LLFeatureManager::cleanupFeatureTables() -{ - std::for_each(mMaskList.begin(), mMaskList.end(), DeletePairedPointer()); - mMaskList.clear(); -} - -void LLFeatureManager::init() -{ - // load the tables - loadFeatureTables(); - - // get the gpu class - loadGPUClass(); - - // apply the base masks, so we know if anything is disabled - applyBaseMasks(); -} - -void LLFeatureManager::applyRecommendedSettings() -{ - // apply saved settings - // cap the level at 2 (high) - S32 level = llmax(GPU_CLASS_0, llmin(mGPUClass, GPU_CLASS_2)); - - llinfos << "Applying Recommended Features" << llendl; - - setGraphicsLevel(level, false); - gSavedSettings.setU32("RenderQualityPerformance", level); - - // now apply the tweaks to draw distance - // these are double negatives, because feature masks only work by - // downgrading values, so i needed to make a true value go to false - // for certain cards, thus the awkward name, "Disregard..." - if(!gSavedSettings.getBOOL("Disregard96DefaultDrawDistance")) - { - gSavedSettings.setF32("RenderFarClip", 96.0f); - } - else if(!gSavedSettings.getBOOL("Disregard128DefaultDrawDistance")) - { - gSavedSettings.setF32("RenderFarClip", 128.0f); - } -} - -void LLFeatureManager::applyFeatures(bool skipFeatures) -{ - // see featuretable.txt / featuretable_linux.txt / featuretable_mac.txt - -#ifndef LL_RELEASE_FOR_DOWNLOAD - dump(); -#endif - - // scroll through all of these and set their corresponding control value - for(feature_map_t::iterator mIt = mFeatures.begin(); - mIt != mFeatures.end(); - ++mIt) - { - // skip features you want to skip - // do this for when you don't want to change certain settings - if(skipFeatures) - { - if(mSkippedFeatures.find(mIt->first) != mSkippedFeatures.end()) - { - continue; - } - } - - // get the control setting - LLControlVariable* ctrl = gSavedSettings.getControl(mIt->first); - if(ctrl == NULL) - { - llwarns << "AHHH! Control setting " << mIt->first << " does not exist!" << llendl; - continue; - } - - // handle all the different types - if(ctrl->isType(TYPE_BOOLEAN)) - { - gSavedSettings.setBOOL(mIt->first, (BOOL)getRecommendedValue(mIt->first)); - } - else if (ctrl->isType(TYPE_S32)) - { - gSavedSettings.setS32(mIt->first, (S32)getRecommendedValue(mIt->first)); - } - else if (ctrl->isType(TYPE_U32)) - { - gSavedSettings.setU32(mIt->first, (U32)getRecommendedValue(mIt->first)); - } - else if (ctrl->isType(TYPE_F32)) - { - gSavedSettings.setF32(mIt->first, (F32)getRecommendedValue(mIt->first)); - } - else - { - llwarns << "AHHH! Control variable is not a numeric type!" << llendl; - } - } -} - -void LLFeatureManager::setGraphicsLevel(S32 level, bool skipFeatures) -{ - applyBaseMasks(); - - switch (level) - { - case 0: - maskFeatures("Low"); - break; - case 1: - maskFeatures("Mid"); - break; - case 2: - maskFeatures("High"); - break; - case 3: - maskFeatures("Ultra"); - break; - default: - maskFeatures("Low"); - break; - } - - applyFeatures(skipFeatures); -} - -void LLFeatureManager::applyBaseMasks() -{ - // reapply masks - mFeatures.clear(); - - LLFeatureList* maskp = findMask("all"); - if(maskp == NULL) - { - LL_WARNS("RenderInit") << "AHH! No \"all\" in feature table!" << LL_ENDL; - return; - } - - mFeatures = maskp->getFeatures(); - - // mask class - if (mGPUClass >= 0 && mGPUClass < 4) - { - const char* class_table[] = - { - "Class0", - "Class1", - "Class2", - "Class3" - }; - - LL_INFOS("RenderInit") << "Setting GPU Class to " << class_table[mGPUClass] << LL_ENDL; - maskFeatures(class_table[mGPUClass]); - } - else - { - LL_INFOS("RenderInit") << "Setting GPU Class to Unknown" << LL_ENDL; - maskFeatures("Unknown"); - } - - // now all those wacky ones - if (!gGLManager.mHasFragmentShader) - { - maskFeatures("NoPixelShaders"); - } - if (!gGLManager.mHasVertexShader) - { - maskFeatures("NoVertexShaders"); - } - if (gGLManager.mIsNVIDIA) - { - maskFeatures("NVIDIA"); - } - if (gGLManager.mIsGF2or4MX) - { - maskFeatures("GeForce2"); - } - if (gGLManager.mIsATI) - { - maskFeatures("ATI"); - } - if (gGLManager.mHasATIMemInfo && gGLManager.mVRAM < 256) - { - maskFeatures("ATIVramLT256"); - } - if (gGLManager.mATIOldDriver) - { - maskFeatures("ATIOldDriver"); - } - if (gGLManager.mIsGFFX) - { - maskFeatures("GeForceFX"); - } - if (gGLManager.mIsIntel) - { - maskFeatures("Intel"); - } - if (gGLManager.mGLVersion < 1.5f) - { - maskFeatures("OpenGLPre15"); - } - if (gGLManager.mGLVersion < 3.f) - { - maskFeatures("OpenGLPre30"); - } - if (gGLManager.mNumTextureImageUnits <= 8) - { - maskFeatures("TexUnit8orLess"); - } - - // now mask by gpu string - // Replaces ' ' with '_' in mGPUString to deal with inability for parser to handle spaces - std::string gpustr = mGPUString; - for (std::string::iterator iter = gpustr.begin(); iter != gpustr.end(); ++iter) - { - if (*iter == ' ') - { - *iter = '_'; - } - } - - //llinfos << "Masking features from gpu table match: " << gpustr << llendl; - maskFeatures(gpustr); - - // now mask cpu type ones - if (gSysMemory.getPhysicalMemoryClamped() <= 256*1024*1024) - { - maskFeatures("RAM256MB"); - } - -#if LL_SOLARIS && defined(__sparc) // even low MHz SPARCs are fast -#error The 800 is hinky. Would something like a LL_MIN_MHZ make more sense here? - if (gSysCPU.getMHz() < 800) -#else - if (gSysCPU.getMHz() < 1100) -#endif - { - maskFeatures("CPUSlow"); - } - - if (isSafe()) - { - maskFeatures("safe"); - } -} +/** + * @file llfeaturemanager.cpp + * @brief LLFeatureManager class implementation + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include +#include + +#include + +#include "llfeaturemanager.h" +#include "lldir.h" + +#include "llsys.h" +#include "llgl.h" +#include "llsecondlifeurls.h" + +#include "llappviewer.h" +#include "llhttpclient.h" +#include "llnotificationsutil.h" +#include "llviewercontrol.h" +#include "llworld.h" +#include "lldrawpoolterrain.h" +#include "llviewertexturelist.h" +#include "llversioninfo.h" +#include "llwindow.h" +#include "llui.h" +#include "llcontrol.h" +#include "llboost.h" +#include "llweb.h" + +#if LL_WINDOWS +#include "lldxhardware.h" +#endif + + +#if LL_DARWIN +const char FEATURE_TABLE_FILENAME[] = "featuretable_mac.txt"; +const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_mac.%s.txt"; +#elif LL_LINUX +const char FEATURE_TABLE_FILENAME[] = "featuretable_linux.txt"; +const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_linux.%s.txt"; +#elif LL_SOLARIS +const char FEATURE_TABLE_FILENAME[] = "featuretable_solaris.txt"; +const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_solaris.%s.txt"; +#else +const char FEATURE_TABLE_FILENAME[] = "featuretable%s.txt"; +const char FEATURE_TABLE_VER_FILENAME[] = "featuretable%s.%s.txt"; +#endif + +const char GPU_TABLE_FILENAME[] = "gpu_table.txt"; +const char GPU_TABLE_VER_FILENAME[] = "gpu_table.%s.txt"; + +LLFeatureInfo::LLFeatureInfo(const std::string& name, const BOOL available, const F32 level) + : mValid(TRUE), mName(name), mAvailable(available), mRecommendedLevel(level) +{ +} + +LLFeatureList::LLFeatureList(const std::string& name) + : mName(name) +{ +} + +LLFeatureList::~LLFeatureList() +{ +} + +void LLFeatureList::addFeature(const std::string& name, const BOOL available, const F32 level) +{ + if (mFeatures.count(name)) + { + LL_WARNS("RenderInit") << "LLFeatureList::Attempting to add preexisting feature " << name << LL_ENDL; + } + + LLFeatureInfo fi(name, available, level); + mFeatures[name] = fi; +} + +BOOL LLFeatureList::isFeatureAvailable(const std::string& name) +{ + if (mFeatures.count(name)) + { + return mFeatures[name].mAvailable; + } + + LL_WARNS("RenderInit") << "Feature " << name << " not on feature list!" << LL_ENDL; + + // changing this to TRUE so you have to explicitly disable + // something for it to be disabled + return TRUE; +} + +F32 LLFeatureList::getRecommendedValue(const std::string& name) +{ + if (mFeatures.count(name) && isFeatureAvailable(name)) + { + return mFeatures[name].mRecommendedLevel; + } + + LL_WARNS("RenderInit") << "Feature " << name << " not on feature list or not available!" << LL_ENDL; + return 0; +} + +BOOL LLFeatureList::maskList(LLFeatureList &mask) +{ + //llinfos << "Masking with " << mask.mName << llendl; + // + // Lookup the specified feature mask, and overlay it on top of the + // current feature mask. + // + + LLFeatureInfo mask_fi; + + feature_map_t::iterator feature_it; + for (feature_it = mask.mFeatures.begin(); feature_it != mask.mFeatures.end(); ++feature_it) + { + mask_fi = feature_it->second; + // + // Look for the corresponding feature + // + if (!mFeatures.count(mask_fi.mName)) + { + LL_WARNS("RenderInit") << "Feature " << mask_fi.mName << " in mask not in top level!" << LL_ENDL; + continue; + } + + LLFeatureInfo &cur_fi = mFeatures[mask_fi.mName]; + if (mask_fi.mAvailable && !cur_fi.mAvailable) + { + LL_WARNS("RenderInit") << "Mask attempting to reenabling disabled feature, ignoring " << cur_fi.mName << LL_ENDL; + continue; + } + cur_fi.mAvailable = mask_fi.mAvailable; + cur_fi.mRecommendedLevel = llmin(cur_fi.mRecommendedLevel, mask_fi.mRecommendedLevel); + LL_DEBUGS("RenderInit") << "Feature mask " << mask.mName + << " Feature " << mask_fi.mName + << " Mask: " << mask_fi.mRecommendedLevel + << " Now: " << cur_fi.mRecommendedLevel << LL_ENDL; + } + + LL_DEBUGS("RenderInit") << "After applying mask " << mask.mName << std::endl; + // Will conditionally call dump only if the above message will be logged, thanks + // to it being wrapped by the LL_DEBUGS and LL_ENDL macros. + dump(); + LL_CONT << LL_ENDL; + + return TRUE; +} + +void LLFeatureList::dump() +{ + LL_DEBUGS("RenderInit") << "Feature list: " << mName << LL_ENDL; + LL_DEBUGS("RenderInit") << "--------------" << LL_ENDL; + + LLFeatureInfo fi; + feature_map_t::iterator feature_it; + for (feature_it = mFeatures.begin(); feature_it != mFeatures.end(); ++feature_it) + { + fi = feature_it->second; + LL_DEBUGS("RenderInit") << fi.mName << "\t\t" << fi.mAvailable << ":" << fi.mRecommendedLevel << LL_ENDL; + } + LL_DEBUGS("RenderInit") << LL_ENDL; +} + +LLFeatureList *LLFeatureManager::findMask(const std::string& name) +{ + if (mMaskList.count(name)) + { + return mMaskList[name]; + } + + return NULL; +} + +BOOL LLFeatureManager::maskFeatures(const std::string& name) +{ + LLFeatureList *maskp = findMask(name); + if (!maskp) + { + LL_DEBUGS("RenderInit") << "Unknown feature mask " << name << LL_ENDL; + return FALSE; + } + LL_INFOS("RenderInit") << "Applying GPU Feature list: " << name << LL_ENDL; + return maskList(*maskp); +} + +BOOL LLFeatureManager::loadFeatureTables() +{ + // *TODO - if I or anyone else adds something else to the skipped list + // make this data driven. Put it in the feature table and parse it + // correctly + mSkippedFeatures.insert("RenderAnisotropic"); + mSkippedFeatures.insert("RenderGamma"); + mSkippedFeatures.insert("RenderVBOEnable"); + mSkippedFeatures.insert("RenderFogRatio"); + + // first table is install with app + std::string app_path = gDirUtilp->getAppRODataDir(); + app_path += gDirUtilp->getDirDelimiter(); + + std::string filename; + std::string http_filename; +#if LL_WINDOWS + std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); + if (os_string.find("Microsoft Windows XP") == 0) + { + filename = llformat(FEATURE_TABLE_FILENAME, "_xp"); + http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "_xp", LLVersionInfo::getVersion().c_str()); + } + else + { + filename = llformat(FEATURE_TABLE_FILENAME, ""); + http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "", LLVersionInfo::getVersion().c_str()); + } +#else + filename = FEATURE_TABLE_FILENAME; + http_filename = llformat(FEATURE_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str()); +#endif + + app_path += filename; + + + // second table is downloaded with HTTP + std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename); + + // use HTTP table if it exists + std::string path; + if (gDirUtilp->fileExists(http_path)) + { + path = http_path; + } + else + { + path = app_path; + } + + + return parseFeatureTable(path); +} + + +BOOL LLFeatureManager::parseFeatureTable(std::string filename) +{ + llinfos << "Looking for feature table in " << filename << llendl; + + llifstream file; + std::string name; + U32 version; + + file.open(filename); /*Flawfinder: ignore*/ + + if (!file) + { + LL_WARNS("RenderInit") << "Unable to open feature table " << filename << LL_ENDL; + return FALSE; + } + + // Check file version + file >> name; + file >> version; + if (name != "version") + { + LL_WARNS("RenderInit") << filename << " does not appear to be a valid feature table!" << LL_ENDL; + return FALSE; + } + + mTableVersion = version; + + LLFeatureList *flp = NULL; + while (file >> name) + { + char buffer[MAX_STRING]; /*Flawfinder: ignore*/ + + if (name.substr(0,2) == "//") + { + // This is a comment. + file.getline(buffer, MAX_STRING); + continue; + } + + if (name == "list") + { + if (flp) + { + //flp->dump(); + } + // It's a new mask, create it. + file >> name; + if (mMaskList.count(name)) + { + LL_ERRS("RenderInit") << "Overriding mask " << name << ", this is invalid!" << LL_ENDL; + } + + flp = new LLFeatureList(name); + mMaskList[name] = flp; + } + else + { + if (!flp) + { + LL_ERRS("RenderInit") << "Specified parameter before keyword!" << LL_ENDL; + return FALSE; + } + S32 available; + F32 recommended; + file >> available >> recommended; + flp->addFeature(name, available, recommended); + } + } + file.close(); + + return TRUE; +} + +void LLFeatureManager::loadGPUClass() +{ + // defaults + mGPUClass = GPU_CLASS_UNKNOWN; + mGPUString = gGLManager.getRawGLString(); + mGPUSupported = FALSE; + + // first table is in the app dir + std::string app_path = gDirUtilp->getAppRODataDir(); + app_path += gDirUtilp->getDirDelimiter(); + app_path += GPU_TABLE_FILENAME; + + // second table is downloaded with HTTP + std::string http_filename = llformat(GPU_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str()); + std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename); + + // use HTTP table if it exists + std::string path; + if (gDirUtilp->fileExists(http_path)) + { + path = http_path; + } + else + { + path = app_path; + } + + parseGPUTable(path); +} + + +void LLFeatureManager::parseGPUTable(std::string filename) +{ + llifstream file; + + file.open(filename); + + if (!file) + { + LL_WARNS("RenderInit") << "Unable to open GPU table: " << filename << "!" << LL_ENDL; + return; + } + + std::string rawRenderer = gGLManager.getRawGLString(); + std::string renderer = rawRenderer; + for (std::string::iterator i = renderer.begin(); i != renderer.end(); ++i) + { + *i = tolower(*i); + } + + bool gpuFound; + U32 lineNumber; + for (gpuFound = false, lineNumber = 0; !gpuFound && !file.eof(); lineNumber++) + { + char buffer[MAX_STRING]; /*Flawfinder: ignore*/ + buffer[0] = 0; + + file.getline(buffer, MAX_STRING); + + if (strlen(buffer) >= 2 && /*Flawfinder: ignore*/ + buffer[0] == '/' && + buffer[1] == '/') + { + // This is a comment. + continue; + } + + if (strlen(buffer) == 0) /*Flawfinder: ignore*/ + { + // This is a blank line + continue; + } + + // setup the tokenizer + std::string buf(buffer); + std::string cls, label, expr, supported; + boost_tokenizer tokens(buf, boost::char_separator("\t\n")); + boost_tokenizer::iterator token_iter = tokens.begin(); + + // grab the label, pseudo regular expression, and class + if(token_iter != tokens.end()) + { + label = *token_iter++; + } + if(token_iter != tokens.end()) + { + expr = *token_iter++; + } + if(token_iter != tokens.end()) + { + cls = *token_iter++; + } + if(token_iter != tokens.end()) + { + supported = *token_iter++; + } + + if (label.empty() || expr.empty() || cls.empty() || supported.empty()) + { + LL_WARNS("RenderInit") << "invald gpu_table.txt:" << lineNumber << ": '" << buffer << "'" << LL_ENDL; + continue; + } + + for (U32 i = 0; i < expr.length(); i++) /*Flawfinder: ignore*/ + { + expr[i] = tolower(expr[i]); + } + + // run the regular expression against the renderer + boost::regex re(expr.c_str()); + if(boost::regex_search(renderer, re)) + { + // if we found it, stop! + gpuFound = true; + mGPUString = label; + mGPUClass = (EGPUClass) strtol(cls.c_str(), NULL, 10); + mGPUSupported = (BOOL) strtol(supported.c_str(), NULL, 10); + } + } + file.close(); + + if ( gpuFound ) + { + LL_INFOS("RenderInit") << "GPU '" << rawRenderer << "' recognized as '" << mGPUString << "'" << LL_ENDL; + if (!mGPUSupported) + { + LL_INFOS("RenderInit") << "GPU '" << mGPUString << "' is not supported." << LL_ENDL; + } + } + else + { + LL_WARNS("RenderInit") << "GPU '" << rawRenderer << "' not recognized" << LL_ENDL; + } +} + +// responder saves table into file +class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder +{ +public: + + LLHTTPFeatureTableResponder(std::string filename) : + mFilename(filename) + { + } + + + virtual void completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + if (isGoodStatus(status)) + { + // write to file + + llinfos << "writing feature table to " << mFilename << llendl; + + S32 file_size = buffer->countAfter(channels.in(), NULL); + if (file_size > 0) + { + // read from buffer + U8* copy_buffer = new U8[file_size]; + buffer->readAfter(channels.in(), NULL, copy_buffer, file_size); + + // write to file + LLAPRFile out(mFilename, LL_APR_WB); + out.write(copy_buffer, file_size); + out.close(); + } + } + + } + +private: + std::string mFilename; +}; + +void fetch_feature_table(std::string table) +{ + const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable"); + +#if LL_WINDOWS + std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); + std::string filename; + if (os_string.find("Microsoft Windows XP") == 0) + { + filename = llformat(table.c_str(), "_xp", LLVersionInfo::getVersion().c_str()); + } + else + { + filename = llformat(table.c_str(), "", LLVersionInfo::getVersion().c_str()); + } +#else + const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str()); +#endif + + const std::string url = base + "/" + filename; + + const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); + + llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl; + + LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path)); +} + +void fetch_gpu_table(std::string table) +{ + const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable"); + + const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str()); + + const std::string url = base + "/" + filename; + + const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); + + llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl; + + LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path)); +} + +// fetch table(s) from a website (S3) +void LLFeatureManager::fetchHTTPTables() +{ + fetch_feature_table(FEATURE_TABLE_VER_FILENAME); + fetch_gpu_table(GPU_TABLE_VER_FILENAME); +} + + +void LLFeatureManager::cleanupFeatureTables() +{ + std::for_each(mMaskList.begin(), mMaskList.end(), DeletePairedPointer()); + mMaskList.clear(); +} + +void LLFeatureManager::init() +{ + // load the tables + loadFeatureTables(); + + // get the gpu class + loadGPUClass(); + + // apply the base masks, so we know if anything is disabled + applyBaseMasks(); +} + +void LLFeatureManager::applyRecommendedSettings() +{ + // apply saved settings + // cap the level at 2 (high) + S32 level = llmax(GPU_CLASS_0, llmin(mGPUClass, GPU_CLASS_2)); + + llinfos << "Applying Recommended Features" << llendl; + + setGraphicsLevel(level, false); + gSavedSettings.setU32("RenderQualityPerformance", level); + + // now apply the tweaks to draw distance + // these are double negatives, because feature masks only work by + // downgrading values, so i needed to make a true value go to false + // for certain cards, thus the awkward name, "Disregard..." + if(!gSavedSettings.getBOOL("Disregard96DefaultDrawDistance")) + { + gSavedSettings.setF32("RenderFarClip", 96.0f); + } + else if(!gSavedSettings.getBOOL("Disregard128DefaultDrawDistance")) + { + gSavedSettings.setF32("RenderFarClip", 128.0f); + } +} + +void LLFeatureManager::applyFeatures(bool skipFeatures) +{ + // see featuretable.txt / featuretable_linux.txt / featuretable_mac.txt + +#ifndef LL_RELEASE_FOR_DOWNLOAD + dump(); +#endif + + // scroll through all of these and set their corresponding control value + for(feature_map_t::iterator mIt = mFeatures.begin(); + mIt != mFeatures.end(); + ++mIt) + { + // skip features you want to skip + // do this for when you don't want to change certain settings + if(skipFeatures) + { + if(mSkippedFeatures.find(mIt->first) != mSkippedFeatures.end()) + { + continue; + } + } + + // get the control setting + LLControlVariable* ctrl = gSavedSettings.getControl(mIt->first); + if(ctrl == NULL) + { + llwarns << "AHHH! Control setting " << mIt->first << " does not exist!" << llendl; + continue; + } + + // handle all the different types + if(ctrl->isType(TYPE_BOOLEAN)) + { + gSavedSettings.setBOOL(mIt->first, (BOOL)getRecommendedValue(mIt->first)); + } + else if (ctrl->isType(TYPE_S32)) + { + gSavedSettings.setS32(mIt->first, (S32)getRecommendedValue(mIt->first)); + } + else if (ctrl->isType(TYPE_U32)) + { + gSavedSettings.setU32(mIt->first, (U32)getRecommendedValue(mIt->first)); + } + else if (ctrl->isType(TYPE_F32)) + { + gSavedSettings.setF32(mIt->first, (F32)getRecommendedValue(mIt->first)); + } + else + { + llwarns << "AHHH! Control variable is not a numeric type!" << llendl; + } + } +} + +void LLFeatureManager::setGraphicsLevel(S32 level, bool skipFeatures) +{ + applyBaseMasks(); + + switch (level) + { + case 0: + maskFeatures("Low"); + break; + case 1: + maskFeatures("Mid"); + break; + case 2: + maskFeatures("High"); + break; + case 3: + maskFeatures("Ultra"); + break; + default: + maskFeatures("Low"); + break; + } + + applyFeatures(skipFeatures); +} + +void LLFeatureManager::applyBaseMasks() +{ + // reapply masks + mFeatures.clear(); + + LLFeatureList* maskp = findMask("all"); + if(maskp == NULL) + { + LL_WARNS("RenderInit") << "AHH! No \"all\" in feature table!" << LL_ENDL; + return; + } + + mFeatures = maskp->getFeatures(); + + // mask class + if (mGPUClass >= 0 && mGPUClass < 4) + { + const char* class_table[] = + { + "Class0", + "Class1", + "Class2", + "Class3" + }; + + LL_INFOS("RenderInit") << "Setting GPU Class to " << class_table[mGPUClass] << LL_ENDL; + maskFeatures(class_table[mGPUClass]); + } + else + { + LL_INFOS("RenderInit") << "Setting GPU Class to Unknown" << LL_ENDL; + maskFeatures("Unknown"); + } + + // now all those wacky ones + if (!gGLManager.mHasFragmentShader) + { + maskFeatures("NoPixelShaders"); + } + if (!gGLManager.mHasVertexShader) + { + maskFeatures("NoVertexShaders"); + } + if (gGLManager.mIsNVIDIA) + { + maskFeatures("NVIDIA"); + } + if (gGLManager.mIsGF2or4MX) + { + maskFeatures("GeForce2"); + } + if (gGLManager.mIsATI) + { + maskFeatures("ATI"); + } + if (gGLManager.mHasATIMemInfo && gGLManager.mVRAM < 256) + { + maskFeatures("ATIVramLT256"); + } + if (gGLManager.mATIOldDriver) + { + maskFeatures("ATIOldDriver"); + } + if (gGLManager.mIsGFFX) + { + maskFeatures("GeForceFX"); + } + if (gGLManager.mIsIntel) + { + maskFeatures("Intel"); + } + if (gGLManager.mGLVersion < 1.5f) + { + maskFeatures("OpenGLPre15"); + } + if (gGLManager.mGLVersion < 3.f) + { + maskFeatures("OpenGLPre30"); + } + if (gGLManager.mNumTextureImageUnits <= 8) + { + maskFeatures("TexUnit8orLess"); + } + + // now mask by gpu string + // Replaces ' ' with '_' in mGPUString to deal with inability for parser to handle spaces + std::string gpustr = mGPUString; + for (std::string::iterator iter = gpustr.begin(); iter != gpustr.end(); ++iter) + { + if (*iter == ' ') + { + *iter = '_'; + } + } + + //llinfos << "Masking features from gpu table match: " << gpustr << llendl; + maskFeatures(gpustr); + + // now mask cpu type ones + if (gSysMemory.getPhysicalMemoryClamped() <= 256*1024*1024) + { + maskFeatures("RAM256MB"); + } + +#if LL_SOLARIS && defined(__sparc) // even low MHz SPARCs are fast +#error The 800 is hinky. Would something like a LL_MIN_MHZ make more sense here? + if (gSysCPU.getMHz() < 800) +#else + if (gSysCPU.getMHz() < 1100) +#endif + { + maskFeatures("CPUSlow"); + } + + if (isSafe()) + { + maskFeatures("safe"); + } +} diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index 50b19a4221..610142b5a9 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -461,15 +461,15 @@ void LLFloaterBuyLandUI::updateParcelInfo() if (!authorizedBuyer.isNull() && buyer != authorizedBuyer) { - // Maybe the parcel is set for sale to a group we are in. - bool authorized_group = - gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_DEED) - && gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_SET_SALE_INFO); - - if (!authorized_group) - { - mCannotBuyReason = getString("set_to_sell_to_other"); - return; + // Maybe the parcel is set for sale to a group we are in. + bool authorized_group = + gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_DEED) + && gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_SET_SALE_INFO); + + if (!authorized_group) + { + mCannotBuyReason = getString("set_to_sell_to_other"); + return; } } } diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 74f48907d2..34a92cd0ac 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1,1999 +1,1999 @@ -/** - * @file llpanelobject.cpp - * @brief Object editing (position, scale, etc.) in the tools floater - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -// file include -#include "llpanelobject.h" - -// linden library includes -#include "lleconomy.h" -#include "llerror.h" -#include "llfontgl.h" -#include "llpermissionsflags.h" -#include "llstring.h" -#include "llvolume.h" -#include "m3math.h" - -// project includes -#include "llagent.h" -#include "llbutton.h" -#include "llcheckboxctrl.h" -#include "llcolorswatch.h" -#include "llcombobox.h" -#include "llfocusmgr.h" -#include "llmanipscale.h" -#include "llpreviewscript.h" -#include "llresmgr.h" -#include "llselectmgr.h" -#include "llspinctrl.h" -#include "lltexturectrl.h" -#include "lltextbox.h" -#include "lltool.h" -#include "lltoolcomp.h" -#include "lltoolmgr.h" -#include "llui.h" -#include "llviewerobject.h" -#include "llviewerregion.h" -#include "llviewerwindow.h" -#include "llvovolume.h" -#include "llworld.h" -#include "pipeline.h" -#include "llviewercontrol.h" -#include "lluictrlfactory.h" -//#include "llfirstuse.h" - -#include "lldrawpool.h" - -// -// Constants -// -enum { - MI_BOX, - MI_CYLINDER, - MI_PRISM, - MI_SPHERE, - MI_TORUS, - MI_TUBE, - MI_RING, - MI_SCULPT, - MI_NONE, - MI_VOLUME_COUNT -}; - -enum { - MI_HOLE_SAME, - MI_HOLE_CIRCLE, - MI_HOLE_SQUARE, - MI_HOLE_TRIANGLE, - MI_HOLE_COUNT -}; - -//static const std::string LEGACY_FULLBRIGHT_DESC =LLTrans::getString("Fullbright"); - -BOOL LLPanelObject::postBuild() -{ - setMouseOpaque(FALSE); - - //-------------------------------------------------------- - // Top - //-------------------------------------------------------- - - // Lock checkbox - mCheckLock = getChild("checkbox locked"); - childSetCommitCallback("checkbox locked",onCommitLock,this); - - // Physical checkbox - mCheckPhysics = getChild("Physical Checkbox Ctrl"); - childSetCommitCallback("Physical Checkbox Ctrl",onCommitPhysics,this); - - // Temporary checkbox - mCheckTemporary = getChild("Temporary Checkbox Ctrl"); - childSetCommitCallback("Temporary Checkbox Ctrl",onCommitTemporary,this); - - // Phantom checkbox - mCheckPhantom = getChild("Phantom Checkbox Ctrl"); - childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this); - - - // Position - mLabelPosition = getChild("label position"); - mCtrlPosX = getChild("Pos X"); - childSetCommitCallback("Pos X",onCommitPosition,this); - mCtrlPosY = getChild("Pos Y"); - childSetCommitCallback("Pos Y",onCommitPosition,this); - mCtrlPosZ = getChild("Pos Z"); - childSetCommitCallback("Pos Z",onCommitPosition,this); - - // Scale - mLabelSize = getChild("label size"); - mCtrlScaleX = getChild("Scale X"); - childSetCommitCallback("Scale X",onCommitScale,this); - - // Scale Y - mCtrlScaleY = getChild("Scale Y"); - childSetCommitCallback("Scale Y",onCommitScale,this); - - // Scale Z - mCtrlScaleZ = getChild("Scale Z"); - childSetCommitCallback("Scale Z",onCommitScale,this); - - // Rotation - mLabelRotation = getChild("label rotation"); - mCtrlRotX = getChild("Rot X"); - childSetCommitCallback("Rot X",onCommitRotation,this); - mCtrlRotY = getChild("Rot Y"); - childSetCommitCallback("Rot Y",onCommitRotation,this); - mCtrlRotZ = getChild("Rot Z"); - childSetCommitCallback("Rot Z",onCommitRotation,this); - - //-------------------------------------------------------- - - // Base Type - mComboBaseType = getChild("comboBaseType"); - childSetCommitCallback("comboBaseType",onCommitParametric,this); - - // Cut - mLabelCut = getChild("text cut"); - mSpinCutBegin = getChild("cut begin"); - childSetCommitCallback("cut begin",onCommitParametric,this); - mSpinCutBegin->setValidateBeforeCommit( precommitValidate ); - mSpinCutEnd = getChild("cut end"); - childSetCommitCallback("cut end",onCommitParametric,this); - mSpinCutEnd->setValidateBeforeCommit( &precommitValidate ); - - // Hollow / Skew - mLabelHollow = getChild("text hollow"); - mLabelSkew = getChild("text skew"); - mSpinHollow = getChild("Scale 1"); - childSetCommitCallback("Scale 1",onCommitParametric,this); - mSpinHollow->setValidateBeforeCommit( &precommitValidate ); - mSpinSkew = getChild("Skew"); - childSetCommitCallback("Skew",onCommitParametric,this); - mSpinSkew->setValidateBeforeCommit( &precommitValidate ); - mLabelHoleType = getChild("Hollow Shape"); - - // Hole Type - mComboHoleType = getChild("hole"); - childSetCommitCallback("hole",onCommitParametric,this); - - // Twist - mLabelTwist = getChild("text twist"); - mSpinTwistBegin = getChild("Twist Begin"); - childSetCommitCallback("Twist Begin",onCommitParametric,this); - mSpinTwistBegin->setValidateBeforeCommit( precommitValidate ); - mSpinTwist = getChild("Twist End"); - childSetCommitCallback("Twist End",onCommitParametric,this); - mSpinTwist->setValidateBeforeCommit( &precommitValidate ); - - // Scale - mSpinScaleX = getChild("Taper Scale X"); - childSetCommitCallback("Taper Scale X",onCommitParametric,this); - mSpinScaleX->setValidateBeforeCommit( &precommitValidate ); - mSpinScaleY = getChild("Taper Scale Y"); - childSetCommitCallback("Taper Scale Y",onCommitParametric,this); - mSpinScaleY->setValidateBeforeCommit( &precommitValidate ); - - // Shear - mLabelShear = getChild("text topshear"); - mSpinShearX = getChild("Shear X"); - childSetCommitCallback("Shear X",onCommitParametric,this); - mSpinShearX->setValidateBeforeCommit( &precommitValidate ); - mSpinShearY = getChild("Shear Y"); - childSetCommitCallback("Shear Y",onCommitParametric,this); - mSpinShearY->setValidateBeforeCommit( &precommitValidate ); - - // Path / Profile - mCtrlPathBegin = getChild("Path Limit Begin"); - childSetCommitCallback("Path Limit Begin",onCommitParametric,this); - mCtrlPathBegin->setValidateBeforeCommit( &precommitValidate ); - mCtrlPathEnd = getChild("Path Limit End"); - childSetCommitCallback("Path Limit End",onCommitParametric,this); - mCtrlPathEnd->setValidateBeforeCommit( &precommitValidate ); - - // Taper - mLabelTaper = getChild("text taper2"); - mSpinTaperX = getChild("Taper X"); - childSetCommitCallback("Taper X",onCommitParametric,this); - mSpinTaperX->setValidateBeforeCommit( precommitValidate ); - mSpinTaperY = getChild("Taper Y"); - childSetCommitCallback("Taper Y",onCommitParametric,this); - mSpinTaperY->setValidateBeforeCommit( precommitValidate ); - - // Radius Offset / Revolutions - mLabelRadiusOffset = getChild("text radius delta"); - mLabelRevolutions = getChild("text revolutions"); - mSpinRadiusOffset = getChild("Radius Offset"); - childSetCommitCallback("Radius Offset",onCommitParametric,this); - mSpinRadiusOffset->setValidateBeforeCommit( &precommitValidate ); - mSpinRevolutions = getChild("Revolutions"); - childSetCommitCallback("Revolutions",onCommitParametric,this); - mSpinRevolutions->setValidateBeforeCommit( &precommitValidate ); - - // Sculpt - mCtrlSculptTexture = getChild("sculpt texture control"); - if (mCtrlSculptTexture) - { - mCtrlSculptTexture->setDefaultImageAssetID(LLUUID(SCULPT_DEFAULT_TEXTURE)); - mCtrlSculptTexture->setCommitCallback( boost::bind(&LLPanelObject::onCommitSculpt, this, _2 )); - mCtrlSculptTexture->setOnCancelCallback( boost::bind(&LLPanelObject::onCancelSculpt, this, _2 )); - mCtrlSculptTexture->setOnSelectCallback( boost::bind(&LLPanelObject::onSelectSculpt, this, _2 )); - mCtrlSculptTexture->setDropCallback( boost::bind(&LLPanelObject::onDropSculpt, this, _2 )); - // Don't allow (no copy) or (no transfer) textures to be selected during immediate mode - mCtrlSculptTexture->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); - // Allow any texture to be used during non-immediate mode. - mCtrlSculptTexture->setNonImmediateFilterPermMask(PERM_NONE); - LLAggregatePermissions texture_perms; - if (LLSelectMgr::getInstance()->selectGetAggregateTexturePermissions(texture_perms)) - { - BOOL can_copy = - texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_EMPTY || - texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_ALL; - BOOL can_transfer = - texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_EMPTY || - texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_ALL; - mCtrlSculptTexture->setCanApplyImmediately(can_copy && can_transfer); - } - else - { - mCtrlSculptTexture->setCanApplyImmediately(FALSE); - } - } - - mLabelSculptType = getChild("label sculpt type"); - mCtrlSculptType = getChild("sculpt type control"); - childSetCommitCallback("sculpt type control", onCommitSculptType, this); - mCtrlSculptMirror = getChild("sculpt mirror control"); - childSetCommitCallback("sculpt mirror control", onCommitSculptType, this); - mCtrlSculptInvert = getChild("sculpt invert control"); - childSetCommitCallback("sculpt invert control", onCommitSculptType, this); - - // Start with everyone disabled - clearCtrls(); - - return TRUE; -} - -LLPanelObject::LLPanelObject() -: LLPanel(), - mIsPhysical(FALSE), - mIsTemporary(FALSE), - mIsPhantom(FALSE), - mCastShadows(TRUE), - mSelectedType(MI_BOX), - mSculptTextureRevert(LLUUID::null), - mSculptTypeRevert(0) -{ -} - - -LLPanelObject::~LLPanelObject() -{ - // Children all cleaned up by default view destructor. -} - -void LLPanelObject::getState( ) -{ - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); - LLViewerObject* root_objectp = objectp; - if(!objectp) - { - objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); - // *FIX: shouldn't we just keep the child? - if (objectp) - { - LLViewerObject* parentp = objectp->getRootEdit(); - - if (parentp) - { - root_objectp = parentp; - } - else - { - root_objectp = objectp; - } - } - } - - LLVOVolume *volobjp = NULL; - if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) - { - volobjp = (LLVOVolume *)objectp; - } - - if( !objectp ) - { - //forfeit focus - if (gFocusMgr.childHasKeyboardFocus(this)) - { - gFocusMgr.setKeyboardFocus(NULL); - } - - // Disable all text input fields - clearCtrls(); - return; - } - - // can move or rotate only linked group with move permissions, or sub-object with move and modify perms - BOOL enable_move = objectp->permMove() && !objectp->isAttachment() && (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts")); - BOOL enable_scale = objectp->permMove() && objectp->permModify(); - BOOL enable_rotate = objectp->permMove() && ( (objectp->permModify() && !objectp->isAttachment()) || !gSavedSettings.getBOOL("EditLinkedParts")); - - S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); - BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME )) - && (selected_count == 1); - - if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 1) - { - enable_move = FALSE; - enable_scale = FALSE; - enable_rotate = FALSE; - } - - LLVector3 vec; - if (enable_move) - { - vec = objectp->getPositionEdit(); - mCtrlPosX->set( vec.mV[VX] ); - mCtrlPosY->set( vec.mV[VY] ); - mCtrlPosZ->set( vec.mV[VZ] ); - } - else - { - mCtrlPosX->clear(); - mCtrlPosY->clear(); - mCtrlPosZ->clear(); - } - - - mLabelPosition->setEnabled( enable_move ); - mCtrlPosX->setEnabled(enable_move); - mCtrlPosY->setEnabled(enable_move); - mCtrlPosZ->setEnabled(enable_move); - - if (enable_scale) - { - vec = objectp->getScale(); - mCtrlScaleX->set( vec.mV[VX] ); - mCtrlScaleY->set( vec.mV[VY] ); - mCtrlScaleZ->set( vec.mV[VZ] ); - } - else - { - mCtrlScaleX->clear(); - mCtrlScaleY->clear(); - mCtrlScaleZ->clear(); - } - - mLabelSize->setEnabled( enable_scale ); - mCtrlScaleX->setEnabled( enable_scale ); - mCtrlScaleY->setEnabled( enable_scale ); - mCtrlScaleZ->setEnabled( enable_scale ); - - LLQuaternion object_rot = objectp->getRotationEdit(); - object_rot.getEulerAngles(&(mCurEulerDegrees.mV[VX]), &(mCurEulerDegrees.mV[VY]), &(mCurEulerDegrees.mV[VZ])); - mCurEulerDegrees *= RAD_TO_DEG; - mCurEulerDegrees.mV[VX] = fmod(llround(mCurEulerDegrees.mV[VX], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); - mCurEulerDegrees.mV[VY] = fmod(llround(mCurEulerDegrees.mV[VY], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); - mCurEulerDegrees.mV[VZ] = fmod(llround(mCurEulerDegrees.mV[VZ], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); - - if (enable_rotate) - { - mCtrlRotX->set( mCurEulerDegrees.mV[VX] ); - mCtrlRotY->set( mCurEulerDegrees.mV[VY] ); - mCtrlRotZ->set( mCurEulerDegrees.mV[VZ] ); - } - else - { - mCtrlRotX->clear(); - mCtrlRotY->clear(); - mCtrlRotZ->clear(); - } - - mLabelRotation->setEnabled( enable_rotate ); - mCtrlRotX->setEnabled( enable_rotate ); - mCtrlRotY->setEnabled( enable_rotate ); - mCtrlRotZ->setEnabled( enable_rotate ); - - BOOL owners_identical; - LLUUID owner_id; - std::string owner_name; - owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); - - // BUG? Check for all objects being editable? - S32 roots_selected = LLSelectMgr::getInstance()->getSelection()->getRootObjectCount(); - BOOL editable = root_objectp->permModify(); - - // Select Single Message - getChildView("select_single")->setVisible( FALSE); - getChildView("edit_object")->setVisible( FALSE); - if (!editable || single_volume || selected_count <= 1) - { - getChildView("edit_object")->setVisible( TRUE); - getChildView("edit_object")->setEnabled(TRUE); - } - else - { - getChildView("select_single")->setVisible( TRUE); - getChildView("select_single")->setEnabled(TRUE); - } - // Lock checkbox - only modifiable if you own the object. - BOOL self_owned = (gAgent.getID() == owner_id); - mCheckLock->setEnabled( roots_selected > 0 && self_owned ); - - // More lock and debit checkbox - get the values - BOOL valid; - U32 owner_mask_on; - U32 owner_mask_off; - valid = LLSelectMgr::getInstance()->selectGetPerm(PERM_OWNER, &owner_mask_on, &owner_mask_off); - - if(valid) - { - if(owner_mask_on & PERM_MOVE) - { - // owner can move, so not locked - mCheckLock->set(FALSE); - mCheckLock->setTentative(FALSE); - } - else if(owner_mask_off & PERM_MOVE) - { - // owner can't move, so locked - mCheckLock->set(TRUE); - mCheckLock->setTentative(FALSE); - } - else - { - // some locked, some not locked - mCheckLock->set(FALSE); - mCheckLock->setTentative(TRUE); - } - } - - BOOL is_flexible = volobjp && volobjp->isFlexible(); - - // Physics checkbox - mIsPhysical = root_objectp->usePhysics(); - mCheckPhysics->set( mIsPhysical ); - mCheckPhysics->setEnabled( roots_selected>0 - && (editable || gAgent.isGodlike()) - && !is_flexible); - - mIsTemporary = root_objectp->flagTemporaryOnRez(); - mCheckTemporary->set( mIsTemporary ); - mCheckTemporary->setEnabled( roots_selected>0 && editable ); - - mIsPhantom = root_objectp->flagPhantom(); - mCheckPhantom->set( mIsPhantom ); - mCheckPhantom->setEnabled( roots_selected>0 && editable && !is_flexible ); - - -#if 0 // 1.9.2 - mCastShadows = root_objectp->flagCastShadows(); - mCheckCastShadows->set( mCastShadows ); - mCheckCastShadows->setEnabled( roots_selected==1 && editable ); -#endif - - //---------------------------------------------------------------------------- - - S32 selected_item = MI_BOX; - S32 selected_hole = MI_HOLE_SAME; - BOOL enabled = FALSE; - BOOL hole_enabled = FALSE; - F32 scale_x=1.f, scale_y=1.f; - BOOL isMesh = FALSE; - - if( !objectp || !objectp->getVolume() || !editable || !single_volume) - { - // Clear out all geometry fields. - mComboBaseType->clear(); - mSpinHollow->clear(); - mSpinCutBegin->clear(); - mSpinCutEnd->clear(); - mCtrlPathBegin->clear(); - mCtrlPathEnd->clear(); - mSpinScaleX->clear(); - mSpinScaleY->clear(); - mSpinTwist->clear(); - mSpinTwistBegin->clear(); - mComboHoleType->clear(); - mSpinShearX->clear(); - mSpinShearY->clear(); - mSpinTaperX->clear(); - mSpinTaperY->clear(); - mSpinRadiusOffset->clear(); - mSpinRevolutions->clear(); - mSpinSkew->clear(); - - mSelectedType = MI_NONE; - } - else - { - // Only allowed to change these parameters for objects - // that you have permissions on AND are not attachments. - enabled = root_objectp->permModify(); - - // Volume type - const LLVolumeParams &volume_params = objectp->getVolume()->getParams(); - U8 path = volume_params.getPathParams().getCurveType(); - U8 profile_and_hole = volume_params.getProfileParams().getCurveType(); - U8 profile = profile_and_hole & LL_PCODE_PROFILE_MASK; - U8 hole = profile_and_hole & LL_PCODE_HOLE_MASK; - - // Scale goes first so we can differentiate between a sphere and a torus, - // which have the same profile and path types. - - // Scale - scale_x = volume_params.getRatioX(); - scale_y = volume_params.getRatioY(); - - BOOL linear_path = (path == LL_PCODE_PATH_LINE) || (path == LL_PCODE_PATH_FLEXIBLE); - if ( linear_path && profile == LL_PCODE_PROFILE_CIRCLE ) - { - selected_item = MI_CYLINDER; - } - else if ( linear_path && profile == LL_PCODE_PROFILE_SQUARE ) - { - selected_item = MI_BOX; - } - else if ( linear_path && profile == LL_PCODE_PROFILE_ISOTRI ) - { - selected_item = MI_PRISM; - } - else if ( linear_path && profile == LL_PCODE_PROFILE_EQUALTRI ) - { - selected_item = MI_PRISM; - } - else if ( linear_path && profile == LL_PCODE_PROFILE_RIGHTTRI ) - { - selected_item = MI_PRISM; - } - else if (path == LL_PCODE_PATH_FLEXIBLE) // shouldn't happen - { - selected_item = MI_CYLINDER; // reasonable default - } - else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE && scale_y > 0.75f) - { - selected_item = MI_SPHERE; - } - else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE && scale_y <= 0.75f) - { - selected_item = MI_TORUS; - } - else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE_HALF) - { - selected_item = MI_SPHERE; - } - else if ( path == LL_PCODE_PATH_CIRCLE2 && profile == LL_PCODE_PROFILE_CIRCLE ) - { - // Spirals aren't supported. Make it into a sphere. JC - selected_item = MI_SPHERE; - } - else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_EQUALTRI ) - { - selected_item = MI_RING; - } - else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_SQUARE && scale_y <= 0.75f) - { - selected_item = MI_TUBE; - } - else - { - llinfos << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << llendl; - selected_item = MI_BOX; - } - - - if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) - { - selected_item = MI_SCULPT; - //LLFirstUse::useSculptedPrim(); - } - - - mComboBaseType ->setCurrentByIndex( selected_item ); - mSelectedType = selected_item; - - // Grab S path - F32 begin_s = volume_params.getBeginS(); - F32 end_s = volume_params.getEndS(); - - // Compute cut and advanced cut from S and T - F32 begin_t = volume_params.getBeginT(); - F32 end_t = volume_params.getEndT(); - - // Hollowness - F32 hollow = volume_params.getHollow(); - mSpinHollow->set( 100.f * hollow ); - - // All hollow objects allow a shape to be selected. - if (hollow > 0.f) - { - switch (hole) - { - case LL_PCODE_HOLE_CIRCLE: - selected_hole = MI_HOLE_CIRCLE; - break; - case LL_PCODE_HOLE_SQUARE: - selected_hole = MI_HOLE_SQUARE; - break; - case LL_PCODE_HOLE_TRIANGLE: - selected_hole = MI_HOLE_TRIANGLE; - break; - case LL_PCODE_HOLE_SAME: - default: - selected_hole = MI_HOLE_SAME; - break; - } - mComboHoleType->setCurrentByIndex( selected_hole ); - hole_enabled = enabled; - } - else - { - mComboHoleType->setCurrentByIndex( MI_HOLE_SAME ); - hole_enabled = FALSE; - } - - // Cut interpretation varies based on base object type - F32 cut_begin, cut_end, adv_cut_begin, adv_cut_end; - - if ( selected_item == MI_SPHERE || selected_item == MI_TORUS || - selected_item == MI_TUBE || selected_item == MI_RING ) - { - cut_begin = begin_t; - cut_end = end_t; - adv_cut_begin = begin_s; - adv_cut_end = end_s; - } - else - { - cut_begin = begin_s; - cut_end = end_s; - adv_cut_begin = begin_t; - adv_cut_end = end_t; - } - - mSpinCutBegin ->set( cut_begin ); - mSpinCutEnd ->set( cut_end ); - mCtrlPathBegin ->set( adv_cut_begin ); - mCtrlPathEnd ->set( adv_cut_end ); - - // Twist - F32 twist = volume_params.getTwist(); - F32 twist_begin = volume_params.getTwistBegin(); - // Check the path type for conversion. - if (path == LL_PCODE_PATH_LINE || path == LL_PCODE_PATH_FLEXIBLE) - { - twist *= OBJECT_TWIST_LINEAR_MAX; - twist_begin *= OBJECT_TWIST_LINEAR_MAX; - } - else - { - twist *= OBJECT_TWIST_MAX; - twist_begin *= OBJECT_TWIST_MAX; - } - - mSpinTwist ->set( twist ); - mSpinTwistBegin ->set( twist_begin ); - - // Shear - F32 shear_x = volume_params.getShearX(); - F32 shear_y = volume_params.getShearY(); - mSpinShearX->set( shear_x ); - mSpinShearY->set( shear_y ); - - // Taper - F32 taper_x = volume_params.getTaperX(); - F32 taper_y = volume_params.getTaperY(); - mSpinTaperX->set( taper_x ); - mSpinTaperY->set( taper_y ); - - // Radius offset. - F32 radius_offset = volume_params.getRadiusOffset(); - // Limit radius offset, based on taper and hole size y. - F32 radius_mag = fabs(radius_offset); - F32 hole_y_mag = fabs(scale_y); - F32 taper_y_mag = fabs(taper_y); - // Check to see if the taper effects us. - if ( (radius_offset > 0.f && taper_y < 0.f) || - (radius_offset < 0.f && taper_y > 0.f) ) - { - // The taper does not help increase the radius offset range. - taper_y_mag = 0.f; - } - F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag); - // Enforce the maximum magnitude. - if (radius_mag > max_radius_mag) - { - // Check radius offset sign. - if (radius_offset < 0.f) - { - radius_offset = -max_radius_mag; - } - else - { - radius_offset = max_radius_mag; - } - } - mSpinRadiusOffset->set( radius_offset); - - // Revolutions - F32 revolutions = volume_params.getRevolutions(); - mSpinRevolutions->set( revolutions ); - - // Skew - F32 skew = volume_params.getSkew(); - // Limit skew, based on revolutions hole size x. - F32 skew_mag= fabs(skew); - F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f); - // Discontinuity; A revolution of 1 allows skews below 0.5. - if ( fabs(revolutions - 1.0f) < 0.001) - min_skew_mag = 0.0f; - - // Clip skew. - if (skew_mag < min_skew_mag) - { - // Check skew sign. - if (skew < 0.0f) - { - skew = -min_skew_mag; - } - else - { - skew = min_skew_mag; - } - } - mSpinSkew->set( skew ); - } - - // Compute control visibility, label names, and twist range. - // Start with defaults. - BOOL cut_visible = TRUE; - BOOL hollow_visible = TRUE; - BOOL top_size_x_visible = TRUE; - BOOL top_size_y_visible = TRUE; - BOOL top_shear_x_visible = TRUE; - BOOL top_shear_y_visible = TRUE; - BOOL twist_visible = TRUE; - BOOL advanced_cut_visible = FALSE; - BOOL taper_visible = FALSE; - BOOL skew_visible = FALSE; - BOOL radius_offset_visible = FALSE; - BOOL revolutions_visible = FALSE; - BOOL sculpt_texture_visible = FALSE; - F32 twist_min = OBJECT_TWIST_LINEAR_MIN; - F32 twist_max = OBJECT_TWIST_LINEAR_MAX; - F32 twist_inc = OBJECT_TWIST_LINEAR_INC; - - BOOL advanced_is_dimple = FALSE; - BOOL advanced_is_slice = FALSE; - BOOL size_is_hole = FALSE; - - // Tune based on overall volume type - switch (selected_item) - { - case MI_SPHERE: - top_size_x_visible = FALSE; - top_size_y_visible = FALSE; - top_shear_x_visible = FALSE; - top_shear_y_visible = FALSE; - //twist_visible = FALSE; - advanced_cut_visible = TRUE; - advanced_is_dimple = TRUE; - twist_min = OBJECT_TWIST_MIN; - twist_max = OBJECT_TWIST_MAX; - twist_inc = OBJECT_TWIST_INC; - break; - - case MI_TORUS: - case MI_TUBE: - case MI_RING: - //top_size_x_visible = FALSE; - //top_size_y_visible = FALSE; - size_is_hole = TRUE; - skew_visible = TRUE; - advanced_cut_visible = TRUE; - taper_visible = TRUE; - radius_offset_visible = TRUE; - revolutions_visible = TRUE; - twist_min = OBJECT_TWIST_MIN; - twist_max = OBJECT_TWIST_MAX; - twist_inc = OBJECT_TWIST_INC; - - break; - - case MI_SCULPT: - cut_visible = FALSE; - hollow_visible = FALSE; - twist_visible = FALSE; - top_size_x_visible = FALSE; - top_size_y_visible = FALSE; - top_shear_x_visible = FALSE; - top_shear_y_visible = FALSE; - skew_visible = FALSE; - advanced_cut_visible = FALSE; - taper_visible = FALSE; - radius_offset_visible = FALSE; - revolutions_visible = FALSE; - sculpt_texture_visible = TRUE; - - break; - - case MI_BOX: - advanced_cut_visible = TRUE; - advanced_is_slice = TRUE; - break; - - case MI_CYLINDER: - advanced_cut_visible = TRUE; - advanced_is_slice = TRUE; - break; - - case MI_PRISM: - advanced_cut_visible = TRUE; - advanced_is_slice = TRUE; - break; - - default: - break; - } - - // Check if we need to change top size/hole size params. - switch (selected_item) - { - case MI_SPHERE: - case MI_TORUS: - case MI_TUBE: - case MI_RING: - mSpinScaleX->set( scale_x ); - mSpinScaleY->set( scale_y ); - mSpinScaleX->setMinValue(OBJECT_MIN_HOLE_SIZE); - mSpinScaleX->setMaxValue(OBJECT_MAX_HOLE_SIZE_X); - mSpinScaleY->setMinValue(OBJECT_MIN_HOLE_SIZE); - mSpinScaleY->setMaxValue(OBJECT_MAX_HOLE_SIZE_Y); - break; - default: - if (editable) - { - mSpinScaleX->set( 1.f - scale_x ); - mSpinScaleY->set( 1.f - scale_y ); - mSpinScaleX->setMinValue(-1.f); - mSpinScaleX->setMaxValue(1.f); - mSpinScaleY->setMinValue(-1.f); - mSpinScaleY->setMaxValue(1.f); - } - break; - } - - // Check if we need to limit the hollow based on the hole type. - if ( selected_hole == MI_HOLE_SQUARE && - ( selected_item == MI_CYLINDER || selected_item == MI_TORUS || - selected_item == MI_PRISM || selected_item == MI_RING || - selected_item == MI_SPHERE ) ) - { - mSpinHollow->setMinValue(0.f); - mSpinHollow->setMaxValue(70.f); - } - else - { - mSpinHollow->setMinValue(0.f); - mSpinHollow->setMaxValue(95.f); - } - - // Update field enablement - mComboBaseType ->setEnabled( enabled ); - - mLabelCut ->setEnabled( enabled ); - mSpinCutBegin ->setEnabled( enabled ); - mSpinCutEnd ->setEnabled( enabled ); - - mLabelHollow ->setEnabled( enabled ); - mSpinHollow ->setEnabled( enabled ); - mLabelHoleType ->setEnabled( hole_enabled ); - mComboHoleType ->setEnabled( hole_enabled ); - - mLabelTwist ->setEnabled( enabled ); - mSpinTwist ->setEnabled( enabled ); - mSpinTwistBegin ->setEnabled( enabled ); - - mLabelSkew ->setEnabled( enabled ); - mSpinSkew ->setEnabled( enabled ); - - getChildView("scale_hole")->setVisible( FALSE); - getChildView("scale_taper")->setVisible( FALSE); - if (top_size_x_visible || top_size_y_visible) - { - if (size_is_hole) - { - getChildView("scale_hole")->setVisible( TRUE); - getChildView("scale_hole")->setEnabled(enabled); - } - else - { - getChildView("scale_taper")->setVisible( TRUE); - getChildView("scale_taper")->setEnabled(enabled); - } - } - - mSpinScaleX ->setEnabled( enabled ); - mSpinScaleY ->setEnabled( enabled ); - - mLabelShear ->setEnabled( enabled ); - mSpinShearX ->setEnabled( enabled ); - mSpinShearY ->setEnabled( enabled ); - - getChildView("advanced_cut")->setVisible( FALSE); - getChildView("advanced_dimple")->setVisible( FALSE); - getChildView("advanced_slice")->setVisible( FALSE); - - if (advanced_cut_visible) - { - if (advanced_is_dimple) - { - getChildView("advanced_dimple")->setVisible( TRUE); - getChildView("advanced_dimple")->setEnabled(enabled); - } - - else if (advanced_is_slice) - { - getChildView("advanced_slice")->setVisible( TRUE); - getChildView("advanced_slice")->setEnabled(enabled); - } - else - { - getChildView("advanced_cut")->setVisible( TRUE); - getChildView("advanced_cut")->setEnabled(enabled); - } - } - - mCtrlPathBegin ->setEnabled( enabled ); - mCtrlPathEnd ->setEnabled( enabled ); - - mLabelTaper ->setEnabled( enabled ); - mSpinTaperX ->setEnabled( enabled ); - mSpinTaperY ->setEnabled( enabled ); - - mLabelRadiusOffset->setEnabled( enabled ); - mSpinRadiusOffset ->setEnabled( enabled ); - - mLabelRevolutions->setEnabled( enabled ); - mSpinRevolutions ->setEnabled( enabled ); - - // Update field visibility - mLabelCut ->setVisible( cut_visible ); - mSpinCutBegin ->setVisible( cut_visible ); - mSpinCutEnd ->setVisible( cut_visible ); - - mLabelHollow ->setVisible( hollow_visible ); - mSpinHollow ->setVisible( hollow_visible ); - mLabelHoleType ->setVisible( hollow_visible ); - mComboHoleType ->setVisible( hollow_visible ); - - mLabelTwist ->setVisible( twist_visible ); - mSpinTwist ->setVisible( twist_visible ); - mSpinTwistBegin ->setVisible( twist_visible ); - mSpinTwist ->setMinValue( twist_min ); - mSpinTwist ->setMaxValue( twist_max ); - mSpinTwist ->setIncrement( twist_inc ); - mSpinTwistBegin ->setMinValue( twist_min ); - mSpinTwistBegin ->setMaxValue( twist_max ); - mSpinTwistBegin ->setIncrement( twist_inc ); - - mSpinScaleX ->setVisible( top_size_x_visible ); - mSpinScaleY ->setVisible( top_size_y_visible ); - - mLabelSkew ->setVisible( skew_visible ); - mSpinSkew ->setVisible( skew_visible ); - - mLabelShear ->setVisible( top_shear_x_visible || top_shear_y_visible ); - mSpinShearX ->setVisible( top_shear_x_visible ); - mSpinShearY ->setVisible( top_shear_y_visible ); - - mCtrlPathBegin ->setVisible( advanced_cut_visible ); - mCtrlPathEnd ->setVisible( advanced_cut_visible ); - - mLabelTaper ->setVisible( taper_visible ); - mSpinTaperX ->setVisible( taper_visible ); - mSpinTaperY ->setVisible( taper_visible ); - - mLabelRadiusOffset->setVisible( radius_offset_visible ); - mSpinRadiusOffset ->setVisible( radius_offset_visible ); - - mLabelRevolutions->setVisible( revolutions_visible ); - mSpinRevolutions ->setVisible( revolutions_visible ); - - mCtrlSculptTexture->setVisible(sculpt_texture_visible); - mLabelSculptType->setVisible(sculpt_texture_visible); - mCtrlSculptType->setVisible(sculpt_texture_visible); - - - // sculpt texture - if (selected_item == MI_SCULPT) - { - - - LLUUID id; - LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); - - - if (sculpt_params) // if we have a legal sculpt param block for this object: - { - if (mObject != objectp) // we've just selected a new object, so save for undo - { - mSculptTextureRevert = sculpt_params->getSculptTexture(); - mSculptTypeRevert = sculpt_params->getSculptType(); - } - - U8 sculpt_type = sculpt_params->getSculptType(); - U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; - BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; - BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; - isMesh = (sculpt_stitching == LL_SCULPT_TYPE_MESH); - - LLTextureCtrl* mTextureCtrl = getChild("sculpt texture control"); - if(mTextureCtrl) - { - mTextureCtrl->setTentative(FALSE); - mTextureCtrl->setEnabled(editable && !isMesh); - if (editable) - mTextureCtrl->setImageAssetID(sculpt_params->getSculptTexture()); - else - mTextureCtrl->setImageAssetID(LLUUID::null); - } - - mComboBaseType->setEnabled(!isMesh); - - if (mCtrlSculptType) - { - mCtrlSculptType->setCurrentByIndex(sculpt_stitching); - mCtrlSculptType->setEnabled(editable && !isMesh); - } - - if (mCtrlSculptMirror) - { - mCtrlSculptMirror->set(sculpt_mirror); - mCtrlSculptMirror->setEnabled(editable && !isMesh); - } - - if (mCtrlSculptInvert) - { - mCtrlSculptInvert->set(sculpt_invert); - mCtrlSculptInvert->setEnabled(editable); - } - - if (mLabelSculptType) - { - mLabelSculptType->setEnabled(TRUE); - } - - } - } - else - { - mSculptTextureRevert = LLUUID::null; - } - - mCtrlSculptMirror->setVisible(sculpt_texture_visible && !isMesh); - mCtrlSculptInvert->setVisible(sculpt_texture_visible && !isMesh); - - //---------------------------------------------------------------------------- - - mObject = objectp; - mRootObject = root_objectp; -} - -// static -bool LLPanelObject::precommitValidate( const LLSD& data ) -{ - // TODO: Richard will fill this in later. - return TRUE; // FALSE means that validation failed and new value should not be commited. -} - -void LLPanelObject::sendIsPhysical() -{ - BOOL value = mCheckPhysics->get(); - if( mIsPhysical != value ) - { - LLSelectMgr::getInstance()->selectionUpdatePhysics(value); - mIsPhysical = value; - - llinfos << "update physics sent" << llendl; - } - else - { - llinfos << "update physics not changed" << llendl; - } -} - -void LLPanelObject::sendIsTemporary() -{ - BOOL value = mCheckTemporary->get(); - if( mIsTemporary != value ) - { - LLSelectMgr::getInstance()->selectionUpdateTemporary(value); - mIsTemporary = value; - - llinfos << "update temporary sent" << llendl; - } - else - { - llinfos << "update temporary not changed" << llendl; - } -} - - -void LLPanelObject::sendIsPhantom() -{ - BOOL value = mCheckPhantom->get(); - if( mIsPhantom != value ) - { - LLSelectMgr::getInstance()->selectionUpdatePhantom(value); - mIsPhantom = value; - - llinfos << "update phantom sent" << llendl; - } - else - { - llinfos << "update phantom not changed" << llendl; - } -} - -void LLPanelObject::sendCastShadows() -{ - BOOL value = mCheckCastShadows->get(); - if( mCastShadows != value ) - { - LLSelectMgr::getInstance()->selectionUpdateCastShadows(value); - mCastShadows = value; - - llinfos << "update cast shadows sent" << llendl; - } - else - { - llinfos << "update cast shadows not changed" << llendl; - } -} - -// static -void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelObject* self = (LLPanelObject*) userdata; - - if (self->mObject.isNull()) - { - return; - } - - if (self->mObject->getPCode() != LL_PCODE_VOLUME) - { - // Don't allow modification of non-volume objects. - return; - } - - LLVolume *volume = self->mObject->getVolume(); - if (!volume) - { - return; - } - - LLVolumeParams volume_params; - self->getVolumeParams(volume_params); - - - - // set sculpting - S32 selected_type = self->mComboBaseType->getCurrentIndex(); - - if (selected_type == MI_SCULPT) - { - self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, TRUE, TRUE); - LLSculptParams *sculpt_params = (LLSculptParams *)self->mObject->getParameterEntry(LLNetworkData::PARAMS_SCULPT); - if (sculpt_params) - volume_params.setSculptID(sculpt_params->getSculptTexture(), sculpt_params->getSculptType()); - } - else - { - LLSculptParams *sculpt_params = (LLSculptParams *)self->mObject->getParameterEntry(LLNetworkData::PARAMS_SCULPT); - if (sculpt_params) - self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE); - } - - // Update the volume, if necessary. - self->mObject->updateVolume(volume_params); - - - // This was added to make sure thate when changes are made, the UI - // adjusts to present valid options. - // *FIX: only some changes, ie, hollow or primitive type changes, - // require a refresh. - self->refresh(); - -} - -void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params) -{ - // Figure out what type of volume to make - S32 was_selected_type = mSelectedType; - S32 selected_type = mComboBaseType->getCurrentIndex(); - U8 profile; - U8 path; - switch ( selected_type ) - { - case MI_CYLINDER: - profile = LL_PCODE_PROFILE_CIRCLE; - path = LL_PCODE_PATH_LINE; - break; - - case MI_BOX: - profile = LL_PCODE_PROFILE_SQUARE; - path = LL_PCODE_PATH_LINE; - break; - - case MI_PRISM: - profile = LL_PCODE_PROFILE_EQUALTRI; - path = LL_PCODE_PATH_LINE; - break; - - case MI_SPHERE: - profile = LL_PCODE_PROFILE_CIRCLE_HALF; - path = LL_PCODE_PATH_CIRCLE; - break; - - case MI_TORUS: - profile = LL_PCODE_PROFILE_CIRCLE; - path = LL_PCODE_PATH_CIRCLE; - break; - - case MI_TUBE: - profile = LL_PCODE_PROFILE_SQUARE; - path = LL_PCODE_PATH_CIRCLE; - break; - - case MI_RING: - profile = LL_PCODE_PROFILE_EQUALTRI; - path = LL_PCODE_PATH_CIRCLE; - break; - - case MI_SCULPT: - profile = LL_PCODE_PROFILE_CIRCLE; - path = LL_PCODE_PATH_CIRCLE; - break; - - default: - llwarns << "Unknown base type " << selected_type - << " in getVolumeParams()" << llendl; - // assume a box - selected_type = MI_BOX; - profile = LL_PCODE_PROFILE_SQUARE; - path = LL_PCODE_PATH_LINE; - break; - } - - - if (path == LL_PCODE_PATH_LINE) - { - LLVOVolume *volobjp = (LLVOVolume *)(LLViewerObject*)(mObject); - if (volobjp->isFlexible()) - { - path = LL_PCODE_PATH_FLEXIBLE; - } - } - - S32 selected_hole = mComboHoleType->getCurrentIndex(); - U8 hole; - switch (selected_hole) - { - case MI_HOLE_CIRCLE: - hole = LL_PCODE_HOLE_CIRCLE; - break; - case MI_HOLE_SQUARE: - hole = LL_PCODE_HOLE_SQUARE; - break; - case MI_HOLE_TRIANGLE: - hole = LL_PCODE_HOLE_TRIANGLE; - break; - case MI_HOLE_SAME: - default: - hole = LL_PCODE_HOLE_SAME; - break; - } - - volume_params.setType(profile | hole, path); - mSelectedType = selected_type; - - // Compute cut start/end - F32 cut_begin = mSpinCutBegin->get(); - F32 cut_end = mSpinCutEnd->get(); - - // Make sure at least OBJECT_CUT_INC of the object survives - if (cut_begin > cut_end - OBJECT_MIN_CUT_INC) - { - cut_begin = cut_end - OBJECT_MIN_CUT_INC; - mSpinCutBegin->set(cut_begin); - } - - F32 adv_cut_begin = mCtrlPathBegin->get(); - F32 adv_cut_end = mCtrlPathEnd->get(); - - // Make sure at least OBJECT_CUT_INC of the object survives - if (adv_cut_begin > adv_cut_end - OBJECT_MIN_CUT_INC) - { - adv_cut_begin = adv_cut_end - OBJECT_MIN_CUT_INC; - mCtrlPathBegin->set(adv_cut_begin); - } - - F32 begin_s, end_s; - F32 begin_t, end_t; - - if (selected_type == MI_SPHERE || selected_type == MI_TORUS || - selected_type == MI_TUBE || selected_type == MI_RING) - { - begin_s = adv_cut_begin; - end_s = adv_cut_end; - - begin_t = cut_begin; - end_t = cut_end; - } - else - { - begin_s = cut_begin; - end_s = cut_end; - - begin_t = adv_cut_begin; - end_t = adv_cut_end; - } - - volume_params.setBeginAndEndS(begin_s, end_s); - volume_params.setBeginAndEndT(begin_t, end_t); - - // Hollowness - F32 hollow = mSpinHollow->get() / 100.f; - - if ( selected_hole == MI_HOLE_SQUARE && - ( selected_type == MI_CYLINDER || selected_type == MI_TORUS || - selected_type == MI_PRISM || selected_type == MI_RING || - selected_type == MI_SPHERE ) ) - { - if (hollow > 0.7f) hollow = 0.7f; - } - - volume_params.setHollow( hollow ); - - // Twist Begin,End - F32 twist_begin = mSpinTwistBegin->get(); - F32 twist = mSpinTwist->get(); - // Check the path type for twist conversion. - if (path == LL_PCODE_PATH_LINE || path == LL_PCODE_PATH_FLEXIBLE) - { - twist_begin /= OBJECT_TWIST_LINEAR_MAX; - twist /= OBJECT_TWIST_LINEAR_MAX; - } - else - { - twist_begin /= OBJECT_TWIST_MAX; - twist /= OBJECT_TWIST_MAX; - } - - volume_params.setTwistBegin(twist_begin); - volume_params.setTwist(twist); - - // Scale X,Y - F32 scale_x = mSpinScaleX->get(); - F32 scale_y = mSpinScaleY->get(); - if ( was_selected_type == MI_BOX || was_selected_type == MI_CYLINDER || was_selected_type == MI_PRISM) - { - scale_x = 1.f - scale_x; - scale_y = 1.f - scale_y; - } - - // Skew - F32 skew = mSpinSkew->get(); - - // Taper X,Y - F32 taper_x = mSpinTaperX->get(); - F32 taper_y = mSpinTaperY->get(); - - // Radius offset - F32 radius_offset = mSpinRadiusOffset->get(); - - // Revolutions - F32 revolutions = mSpinRevolutions->get(); - - if ( selected_type == MI_SPHERE ) - { - // Snap values to valid sphere parameters. - scale_x = 1.0f; - scale_y = 1.0f; - skew = 0.0f; - taper_x = 0.0f; - taper_y = 0.0f; - radius_offset = 0.0f; - revolutions = 1.0f; - } - else if ( selected_type == MI_TORUS || selected_type == MI_TUBE || - selected_type == MI_RING ) - { - scale_x = llclamp( - scale_x, - OBJECT_MIN_HOLE_SIZE, - OBJECT_MAX_HOLE_SIZE_X); - scale_y = llclamp( - scale_y, - OBJECT_MIN_HOLE_SIZE, - OBJECT_MAX_HOLE_SIZE_Y); - - // Limit radius offset, based on taper and hole size y. - F32 radius_mag = fabs(radius_offset); - F32 hole_y_mag = fabs(scale_y); - F32 taper_y_mag = fabs(taper_y); - // Check to see if the taper effects us. - if ( (radius_offset > 0.f && taper_y < 0.f) || - (radius_offset < 0.f && taper_y > 0.f) ) - { - // The taper does not help increase the radius offset range. - taper_y_mag = 0.f; - } - F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag); - // Enforce the maximum magnitude. - if (radius_mag > max_radius_mag) - { - // Check radius offset sign. - if (radius_offset < 0.f) - { - radius_offset = -max_radius_mag; - } - else - { - radius_offset = max_radius_mag; - } - } - - // Check the skew value against the revolutions. - F32 skew_mag= fabs(skew); - F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f); - // Discontinuity; A revolution of 1 allows skews below 0.5. - if ( fabs(revolutions - 1.0f) < 0.001) - min_skew_mag = 0.0f; - - // Clip skew. - if (skew_mag < min_skew_mag) - { - // Check skew sign. - if (skew < 0.0f) - { - skew = -min_skew_mag; - } - else - { - skew = min_skew_mag; - } - } - } - - volume_params.setRatio( scale_x, scale_y ); - volume_params.setSkew(skew); - volume_params.setTaper( taper_x, taper_y ); - volume_params.setRadiusOffset(radius_offset); - volume_params.setRevolutions(revolutions); - - // Shear X,Y - F32 shear_x = mSpinShearX->get(); - F32 shear_y = mSpinShearY->get(); - volume_params.setShear( shear_x, shear_y ); - - if (selected_type == MI_SCULPT) - { - volume_params.setSculptID(LLUUID::null, 0); - volume_params.setBeginAndEndT (0, 1); - volume_params.setBeginAndEndS (0, 1); - volume_params.setHollow (0); - volume_params.setTwistBegin (0); - volume_params.setTwistEnd (0); - volume_params.setRatio (1, 0.5); - volume_params.setShear (0, 0); - volume_params.setTaper (0, 0); - volume_params.setRevolutions (1); - volume_params.setRadiusOffset (0); - volume_params.setSkew (0); - } - -} - -// BUG: Make work with multiple objects -void LLPanelObject::sendRotation(BOOL btn_down) -{ - if (mObject.isNull()) return; - - LLVector3 new_rot(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get()); - new_rot.mV[VX] = llround(new_rot.mV[VX], OBJECT_ROTATION_PRECISION); - new_rot.mV[VY] = llround(new_rot.mV[VY], OBJECT_ROTATION_PRECISION); - new_rot.mV[VZ] = llround(new_rot.mV[VZ], OBJECT_ROTATION_PRECISION); - - // Note: must compare before conversion to radians - LLVector3 delta = new_rot - mCurEulerDegrees; - - if (delta.magVec() >= 0.0005f) - { - mCurEulerDegrees = new_rot; - new_rot *= DEG_TO_RAD; - - LLQuaternion rotation; - rotation.setQuat(new_rot.mV[VX], new_rot.mV[VY], new_rot.mV[VZ]); - - if (mRootObject != mObject) - { - rotation = rotation * ~mRootObject->getRotationRegion(); - } - std::vector& child_positions = mObject->mUnselectedChildrenPositions ; - std::vector child_rotations; - if (mObject->isRootEdit()) - { - mObject->saveUnselectedChildrenRotation(child_rotations) ; - mObject->saveUnselectedChildrenPosition(child_positions) ; - } - - mObject->setRotation(rotation); - LLManip::rebuild(mObject) ; - - // for individually selected roots, we need to counterrotate all the children - if (mObject->isRootEdit()) - { - mObject->resetChildrenRotationAndPosition(child_rotations, child_positions) ; - } - - if(!btn_down) - { - child_positions.clear() ; - LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_ROTATION | UPD_POSITION); - } - } -} - - -// BUG: Make work with multiple objects -void LLPanelObject::sendScale(BOOL btn_down) -{ - if (mObject.isNull()) return; - - LLVector3 newscale(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get()); - - LLVector3 delta = newscale - mObject->getScale(); - if (delta.magVec() >= 0.0005f) - { - // scale changed by more than 1/2 millimeter - - // check to see if we aren't scaling the textures - // (in which case the tex coord's need to be recomputed) - BOOL dont_stretch_textures = !LLManipScale::getStretchTextures(); - if (dont_stretch_textures) - { - LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_SCALE); - } - - mObject->setScale(newscale, TRUE); - - if(!btn_down) - { - LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_SCALE | UPD_POSITION); - } - - LLSelectMgr::getInstance()->adjustTexturesByScale(TRUE, !dont_stretch_textures); -// llinfos << "scale sent" << llendl; - } - else - { -// llinfos << "scale not changed" << llendl; - } -} - - -void LLPanelObject::sendPosition(BOOL btn_down) -{ - if (mObject.isNull()) return; - - LLVector3 newpos(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get()); - LLViewerRegion* regionp = mObject->getRegion(); - - // Clamp the Z height - const F32 height = newpos.mV[VZ]; - const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal()); - const F32 max_height = LLWorld::getInstance()->getRegionMaxHeight(); - - if (!mObject->isAttachment()) - { - if ( height < min_height) - { - newpos.mV[VZ] = min_height; - mCtrlPosZ->set( min_height ); - } - else if ( height > max_height ) - { - newpos.mV[VZ] = max_height; - mCtrlPosZ->set( max_height ); - } - - // Grass is always drawn on the ground, so clamp its position to the ground - if (mObject->getPCode() == LL_PCODE_LEGACY_GRASS) - { - mCtrlPosZ->set(LLWorld::getInstance()->resolveLandHeightAgent(newpos) + 1.f); - } - } - - // Make sure new position is in a valid region, so the object - // won't get dumped by the simulator. - LLVector3d new_pos_global = regionp->getPosGlobalFromRegion(newpos); - - if ( LLWorld::getInstance()->positionRegionValidGlobal(new_pos_global) ) - { - // send only if the position is changed, that is, the delta vector is not zero - LLVector3d old_pos_global = mObject->getPositionGlobal(); - LLVector3d delta = new_pos_global - old_pos_global; - // moved more than 1/2 millimeter - if (delta.magVec() >= 0.0005f) - { - if (mRootObject != mObject) - { - newpos = newpos - mRootObject->getPositionRegion(); - newpos = newpos * ~mRootObject->getRotationRegion(); - mObject->setPositionParent(newpos); - } - else - { - mObject->setPositionEdit(newpos); - } - - LLManip::rebuild(mObject) ; - - // for individually selected roots, we need to counter-translate all unselected children - if (mObject->isRootEdit()) - { - // only offset by parent's translation - mObject->resetChildrenPosition(LLVector3(-delta), TRUE) ; - } - - if(!btn_down) - { - LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); - } - - LLSelectMgr::getInstance()->updateSelectionCenter(); - } - } - else - { - // move failed, so we update the UI with the correct values - LLVector3 vec = mRootObject->getPositionRegion(); - mCtrlPosX->set(vec.mV[VX]); - mCtrlPosY->set(vec.mV[VY]); - mCtrlPosZ->set(vec.mV[VZ]); - } -} - -void LLPanelObject::sendSculpt() -{ - if (mObject.isNull()) - return; - - LLSculptParams sculpt_params; - - if (mCtrlSculptTexture) - sculpt_params.setSculptTexture(mCtrlSculptTexture->getImageAssetID()); - - U8 sculpt_type = 0; - - if (mCtrlSculptType) - sculpt_type |= mCtrlSculptType->getCurrentIndex(); - - bool enabled = sculpt_type != LL_SCULPT_TYPE_MESH; - - if (mCtrlSculptMirror) - { - mCtrlSculptMirror->setEnabled(enabled ? TRUE : FALSE); - } - if (mCtrlSculptInvert) - { - mCtrlSculptInvert->setEnabled(enabled ? TRUE : FALSE); - } - - if ((mCtrlSculptMirror) && (mCtrlSculptMirror->get())) - sculpt_type |= LL_SCULPT_FLAG_MIRROR; - - if ((mCtrlSculptInvert) && (mCtrlSculptInvert->get())) - sculpt_type |= LL_SCULPT_FLAG_INVERT; - - sculpt_params.setSculptType(sculpt_type); - mObject->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE); -} - -void LLPanelObject::refresh() -{ - getState(); - if (mObject.notNull() && mObject->isDead()) - { - mObject = NULL; - } - - if (mRootObject.notNull() && mRootObject->isDead()) - { - mRootObject = NULL; - } - - bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && - gAgent.getRegion() && - !gAgent.getRegion()->getCapability("GetMesh").empty(); - - F32 max_scale = get_default_max_prim_scale(LLPickInfo::isFlora(mObject)); - - getChild("Scale X")->setMaxValue(max_scale); - getChild("Scale Y")->setMaxValue(max_scale); - getChild("Scale Z")->setMaxValue(max_scale); - - BOOL found = mCtrlSculptType->itemExists("Mesh"); - if (enable_mesh && !found) - { - mCtrlSculptType->add("Mesh"); - } - else if (!enable_mesh && found) - { - mCtrlSculptType->remove("Mesh"); - } -} - - -void LLPanelObject::draw() -{ - const LLColor4 white( 1.0f, 1.0f, 1.0f, 1); - const LLColor4 red( 1.0f, 0.25f, 0.f, 1); - const LLColor4 green( 0.f, 1.0f, 0.f, 1); - const LLColor4 blue( 0.f, 0.5f, 1.0f, 1); - - // Tune the colors of the labels - LLTool* tool = LLToolMgr::getInstance()->getCurrentTool(); - - if (tool == LLToolCompTranslate::getInstance()) - { - mCtrlPosX ->setLabelColor(red); - mCtrlPosY ->setLabelColor(green); - mCtrlPosZ ->setLabelColor(blue); - - mCtrlScaleX ->setLabelColor(white); - mCtrlScaleY ->setLabelColor(white); - mCtrlScaleZ ->setLabelColor(white); - - mCtrlRotX ->setLabelColor(white); - mCtrlRotY ->setLabelColor(white); - mCtrlRotZ ->setLabelColor(white); - } - else if ( tool == LLToolCompScale::getInstance() ) - { - mCtrlPosX ->setLabelColor(white); - mCtrlPosY ->setLabelColor(white); - mCtrlPosZ ->setLabelColor(white); - - mCtrlScaleX ->setLabelColor(red); - mCtrlScaleY ->setLabelColor(green); - mCtrlScaleZ ->setLabelColor(blue); - - mCtrlRotX ->setLabelColor(white); - mCtrlRotY ->setLabelColor(white); - mCtrlRotZ ->setLabelColor(white); - } - else if ( tool == LLToolCompRotate::getInstance() ) - { - mCtrlPosX ->setLabelColor(white); - mCtrlPosY ->setLabelColor(white); - mCtrlPosZ ->setLabelColor(white); - - mCtrlScaleX ->setLabelColor(white); - mCtrlScaleY ->setLabelColor(white); - mCtrlScaleZ ->setLabelColor(white); - - mCtrlRotX ->setLabelColor(red); - mCtrlRotY ->setLabelColor(green); - mCtrlRotZ ->setLabelColor(blue); - } - else - { - mCtrlPosX ->setLabelColor(white); - mCtrlPosY ->setLabelColor(white); - mCtrlPosZ ->setLabelColor(white); - - mCtrlScaleX ->setLabelColor(white); - mCtrlScaleY ->setLabelColor(white); - mCtrlScaleZ ->setLabelColor(white); - - mCtrlRotX ->setLabelColor(white); - mCtrlRotY ->setLabelColor(white); - mCtrlRotZ ->setLabelColor(white); - } - - LLPanel::draw(); -} - -// virtual -void LLPanelObject::clearCtrls() -{ - LLPanel::clearCtrls(); - - mCheckLock ->set(FALSE); - mCheckLock ->setEnabled( FALSE ); - mCheckPhysics ->set(FALSE); - mCheckPhysics ->setEnabled( FALSE ); - mCheckTemporary ->set(FALSE); - mCheckTemporary ->setEnabled( FALSE ); - mCheckPhantom ->set(FALSE); - mCheckPhantom ->setEnabled( FALSE ); - -#if 0 // 1.9.2 - mCheckCastShadows->set(FALSE); - mCheckCastShadows->setEnabled( FALSE ); -#endif - // Disable text labels - mLabelPosition ->setEnabled( FALSE ); - mLabelSize ->setEnabled( FALSE ); - mLabelRotation ->setEnabled( FALSE ); - mLabelCut ->setEnabled( FALSE ); - mLabelHollow ->setEnabled( FALSE ); - mLabelHoleType ->setEnabled( FALSE ); - mLabelTwist ->setEnabled( FALSE ); - mLabelSkew ->setEnabled( FALSE ); - mLabelShear ->setEnabled( FALSE ); - mLabelTaper ->setEnabled( FALSE ); - mLabelRadiusOffset->setEnabled( FALSE ); - mLabelRevolutions->setEnabled( FALSE ); - - getChildView("select_single")->setVisible( FALSE); - getChildView("edit_object")->setVisible( TRUE); - getChildView("edit_object")->setEnabled(FALSE); - - getChildView("scale_hole")->setEnabled(FALSE); - getChildView("scale_taper")->setEnabled(FALSE); - getChildView("advanced_cut")->setEnabled(FALSE); - getChildView("advanced_dimple")->setEnabled(FALSE); - getChildView("advanced_slice")->setVisible( FALSE); -} - -// -// Static functions -// - -// static -void LLPanelObject::onCommitLock(LLUICtrl *ctrl, void *data) -{ - // Checkbox will have toggled itself - LLPanelObject *self = (LLPanelObject *)data; - - if(self->mRootObject.isNull()) return; - - BOOL new_state = self->mCheckLock->get(); - - LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, !new_state, PERM_MOVE | PERM_MODIFY); -} - -// static -void LLPanelObject::onCommitPosition( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelObject* self = (LLPanelObject*) userdata; - BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ; - self->sendPosition(btn_down); -} - -// static -void LLPanelObject::onCommitScale( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelObject* self = (LLPanelObject*) userdata; - BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ; - self->sendScale(btn_down); -} - -// static -void LLPanelObject::onCommitRotation( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelObject* self = (LLPanelObject*) userdata; - BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ; - self->sendRotation(btn_down); -} - -// static -void LLPanelObject::onCommitPhysics( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelObject* self = (LLPanelObject*) userdata; - self->sendIsPhysical(); -} - -// static -void LLPanelObject::onCommitTemporary( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelObject* self = (LLPanelObject*) userdata; - self->sendIsTemporary(); -} - -// static -void LLPanelObject::onCommitPhantom( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelObject* self = (LLPanelObject*) userdata; - self->sendIsPhantom(); -} - -// static -void LLPanelObject::onCommitCastShadows( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelObject* self = (LLPanelObject*) userdata; - self->sendCastShadows(); -} - - -void LLPanelObject::onSelectSculpt(const LLSD& data) -{ - LLTextureCtrl* mTextureCtrl = getChild("sculpt texture control"); - - if (mTextureCtrl) - { - mSculptTextureRevert = mTextureCtrl->getImageAssetID(); - } - - sendSculpt(); -} - - -void LLPanelObject::onCommitSculpt( const LLSD& data ) -{ - sendSculpt(); -} - -BOOL LLPanelObject::onDropSculpt(LLInventoryItem* item) -{ - LLTextureCtrl* mTextureCtrl = getChild("sculpt texture control"); - - if (mTextureCtrl) - { - LLUUID asset = item->getAssetUUID(); - - mTextureCtrl->setImageAssetID(asset); - mSculptTextureRevert = asset; - } - - return TRUE; -} - - -void LLPanelObject::onCancelSculpt(const LLSD& data) -{ - LLTextureCtrl* mTextureCtrl = getChild("sculpt texture control"); - if(!mTextureCtrl) - return; - - mTextureCtrl->setImageAssetID(mSculptTextureRevert); - - sendSculpt(); -} - -// static -void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata) -{ - LLPanelObject* self = (LLPanelObject*) userdata; - - self->sendSculpt(); -} +/** + * @file llpanelobject.cpp + * @brief Object editing (position, scale, etc.) in the tools floater + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +// file include +#include "llpanelobject.h" + +// linden library includes +#include "lleconomy.h" +#include "llerror.h" +#include "llfontgl.h" +#include "llpermissionsflags.h" +#include "llstring.h" +#include "llvolume.h" +#include "m3math.h" + +// project includes +#include "llagent.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llcolorswatch.h" +#include "llcombobox.h" +#include "llfocusmgr.h" +#include "llmanipscale.h" +#include "llpreviewscript.h" +#include "llresmgr.h" +#include "llselectmgr.h" +#include "llspinctrl.h" +#include "lltexturectrl.h" +#include "lltextbox.h" +#include "lltool.h" +#include "lltoolcomp.h" +#include "lltoolmgr.h" +#include "llui.h" +#include "llviewerobject.h" +#include "llviewerregion.h" +#include "llviewerwindow.h" +#include "llvovolume.h" +#include "llworld.h" +#include "pipeline.h" +#include "llviewercontrol.h" +#include "lluictrlfactory.h" +//#include "llfirstuse.h" + +#include "lldrawpool.h" + +// +// Constants +// +enum { + MI_BOX, + MI_CYLINDER, + MI_PRISM, + MI_SPHERE, + MI_TORUS, + MI_TUBE, + MI_RING, + MI_SCULPT, + MI_NONE, + MI_VOLUME_COUNT +}; + +enum { + MI_HOLE_SAME, + MI_HOLE_CIRCLE, + MI_HOLE_SQUARE, + MI_HOLE_TRIANGLE, + MI_HOLE_COUNT +}; + +//static const std::string LEGACY_FULLBRIGHT_DESC =LLTrans::getString("Fullbright"); + +BOOL LLPanelObject::postBuild() +{ + setMouseOpaque(FALSE); + + //-------------------------------------------------------- + // Top + //-------------------------------------------------------- + + // Lock checkbox + mCheckLock = getChild("checkbox locked"); + childSetCommitCallback("checkbox locked",onCommitLock,this); + + // Physical checkbox + mCheckPhysics = getChild("Physical Checkbox Ctrl"); + childSetCommitCallback("Physical Checkbox Ctrl",onCommitPhysics,this); + + // Temporary checkbox + mCheckTemporary = getChild("Temporary Checkbox Ctrl"); + childSetCommitCallback("Temporary Checkbox Ctrl",onCommitTemporary,this); + + // Phantom checkbox + mCheckPhantom = getChild("Phantom Checkbox Ctrl"); + childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this); + + + // Position + mLabelPosition = getChild("label position"); + mCtrlPosX = getChild("Pos X"); + childSetCommitCallback("Pos X",onCommitPosition,this); + mCtrlPosY = getChild("Pos Y"); + childSetCommitCallback("Pos Y",onCommitPosition,this); + mCtrlPosZ = getChild("Pos Z"); + childSetCommitCallback("Pos Z",onCommitPosition,this); + + // Scale + mLabelSize = getChild("label size"); + mCtrlScaleX = getChild("Scale X"); + childSetCommitCallback("Scale X",onCommitScale,this); + + // Scale Y + mCtrlScaleY = getChild("Scale Y"); + childSetCommitCallback("Scale Y",onCommitScale,this); + + // Scale Z + mCtrlScaleZ = getChild("Scale Z"); + childSetCommitCallback("Scale Z",onCommitScale,this); + + // Rotation + mLabelRotation = getChild("label rotation"); + mCtrlRotX = getChild("Rot X"); + childSetCommitCallback("Rot X",onCommitRotation,this); + mCtrlRotY = getChild("Rot Y"); + childSetCommitCallback("Rot Y",onCommitRotation,this); + mCtrlRotZ = getChild("Rot Z"); + childSetCommitCallback("Rot Z",onCommitRotation,this); + + //-------------------------------------------------------- + + // Base Type + mComboBaseType = getChild("comboBaseType"); + childSetCommitCallback("comboBaseType",onCommitParametric,this); + + // Cut + mLabelCut = getChild("text cut"); + mSpinCutBegin = getChild("cut begin"); + childSetCommitCallback("cut begin",onCommitParametric,this); + mSpinCutBegin->setValidateBeforeCommit( precommitValidate ); + mSpinCutEnd = getChild("cut end"); + childSetCommitCallback("cut end",onCommitParametric,this); + mSpinCutEnd->setValidateBeforeCommit( &precommitValidate ); + + // Hollow / Skew + mLabelHollow = getChild("text hollow"); + mLabelSkew = getChild("text skew"); + mSpinHollow = getChild("Scale 1"); + childSetCommitCallback("Scale 1",onCommitParametric,this); + mSpinHollow->setValidateBeforeCommit( &precommitValidate ); + mSpinSkew = getChild("Skew"); + childSetCommitCallback("Skew",onCommitParametric,this); + mSpinSkew->setValidateBeforeCommit( &precommitValidate ); + mLabelHoleType = getChild("Hollow Shape"); + + // Hole Type + mComboHoleType = getChild("hole"); + childSetCommitCallback("hole",onCommitParametric,this); + + // Twist + mLabelTwist = getChild("text twist"); + mSpinTwistBegin = getChild("Twist Begin"); + childSetCommitCallback("Twist Begin",onCommitParametric,this); + mSpinTwistBegin->setValidateBeforeCommit( precommitValidate ); + mSpinTwist = getChild("Twist End"); + childSetCommitCallback("Twist End",onCommitParametric,this); + mSpinTwist->setValidateBeforeCommit( &precommitValidate ); + + // Scale + mSpinScaleX = getChild("Taper Scale X"); + childSetCommitCallback("Taper Scale X",onCommitParametric,this); + mSpinScaleX->setValidateBeforeCommit( &precommitValidate ); + mSpinScaleY = getChild("Taper Scale Y"); + childSetCommitCallback("Taper Scale Y",onCommitParametric,this); + mSpinScaleY->setValidateBeforeCommit( &precommitValidate ); + + // Shear + mLabelShear = getChild("text topshear"); + mSpinShearX = getChild("Shear X"); + childSetCommitCallback("Shear X",onCommitParametric,this); + mSpinShearX->setValidateBeforeCommit( &precommitValidate ); + mSpinShearY = getChild("Shear Y"); + childSetCommitCallback("Shear Y",onCommitParametric,this); + mSpinShearY->setValidateBeforeCommit( &precommitValidate ); + + // Path / Profile + mCtrlPathBegin = getChild("Path Limit Begin"); + childSetCommitCallback("Path Limit Begin",onCommitParametric,this); + mCtrlPathBegin->setValidateBeforeCommit( &precommitValidate ); + mCtrlPathEnd = getChild("Path Limit End"); + childSetCommitCallback("Path Limit End",onCommitParametric,this); + mCtrlPathEnd->setValidateBeforeCommit( &precommitValidate ); + + // Taper + mLabelTaper = getChild("text taper2"); + mSpinTaperX = getChild("Taper X"); + childSetCommitCallback("Taper X",onCommitParametric,this); + mSpinTaperX->setValidateBeforeCommit( precommitValidate ); + mSpinTaperY = getChild("Taper Y"); + childSetCommitCallback("Taper Y",onCommitParametric,this); + mSpinTaperY->setValidateBeforeCommit( precommitValidate ); + + // Radius Offset / Revolutions + mLabelRadiusOffset = getChild("text radius delta"); + mLabelRevolutions = getChild("text revolutions"); + mSpinRadiusOffset = getChild("Radius Offset"); + childSetCommitCallback("Radius Offset",onCommitParametric,this); + mSpinRadiusOffset->setValidateBeforeCommit( &precommitValidate ); + mSpinRevolutions = getChild("Revolutions"); + childSetCommitCallback("Revolutions",onCommitParametric,this); + mSpinRevolutions->setValidateBeforeCommit( &precommitValidate ); + + // Sculpt + mCtrlSculptTexture = getChild("sculpt texture control"); + if (mCtrlSculptTexture) + { + mCtrlSculptTexture->setDefaultImageAssetID(LLUUID(SCULPT_DEFAULT_TEXTURE)); + mCtrlSculptTexture->setCommitCallback( boost::bind(&LLPanelObject::onCommitSculpt, this, _2 )); + mCtrlSculptTexture->setOnCancelCallback( boost::bind(&LLPanelObject::onCancelSculpt, this, _2 )); + mCtrlSculptTexture->setOnSelectCallback( boost::bind(&LLPanelObject::onSelectSculpt, this, _2 )); + mCtrlSculptTexture->setDropCallback( boost::bind(&LLPanelObject::onDropSculpt, this, _2 )); + // Don't allow (no copy) or (no transfer) textures to be selected during immediate mode + mCtrlSculptTexture->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); + // Allow any texture to be used during non-immediate mode. + mCtrlSculptTexture->setNonImmediateFilterPermMask(PERM_NONE); + LLAggregatePermissions texture_perms; + if (LLSelectMgr::getInstance()->selectGetAggregateTexturePermissions(texture_perms)) + { + BOOL can_copy = + texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_EMPTY || + texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_ALL; + BOOL can_transfer = + texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_EMPTY || + texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_ALL; + mCtrlSculptTexture->setCanApplyImmediately(can_copy && can_transfer); + } + else + { + mCtrlSculptTexture->setCanApplyImmediately(FALSE); + } + } + + mLabelSculptType = getChild("label sculpt type"); + mCtrlSculptType = getChild("sculpt type control"); + childSetCommitCallback("sculpt type control", onCommitSculptType, this); + mCtrlSculptMirror = getChild("sculpt mirror control"); + childSetCommitCallback("sculpt mirror control", onCommitSculptType, this); + mCtrlSculptInvert = getChild("sculpt invert control"); + childSetCommitCallback("sculpt invert control", onCommitSculptType, this); + + // Start with everyone disabled + clearCtrls(); + + return TRUE; +} + +LLPanelObject::LLPanelObject() +: LLPanel(), + mIsPhysical(FALSE), + mIsTemporary(FALSE), + mIsPhantom(FALSE), + mCastShadows(TRUE), + mSelectedType(MI_BOX), + mSculptTextureRevert(LLUUID::null), + mSculptTypeRevert(0) +{ +} + + +LLPanelObject::~LLPanelObject() +{ + // Children all cleaned up by default view destructor. +} + +void LLPanelObject::getState( ) +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); + LLViewerObject* root_objectp = objectp; + if(!objectp) + { + objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + // *FIX: shouldn't we just keep the child? + if (objectp) + { + LLViewerObject* parentp = objectp->getRootEdit(); + + if (parentp) + { + root_objectp = parentp; + } + else + { + root_objectp = objectp; + } + } + } + + LLVOVolume *volobjp = NULL; + if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) + { + volobjp = (LLVOVolume *)objectp; + } + + if( !objectp ) + { + //forfeit focus + if (gFocusMgr.childHasKeyboardFocus(this)) + { + gFocusMgr.setKeyboardFocus(NULL); + } + + // Disable all text input fields + clearCtrls(); + return; + } + + // can move or rotate only linked group with move permissions, or sub-object with move and modify perms + BOOL enable_move = objectp->permMove() && !objectp->isAttachment() && (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts")); + BOOL enable_scale = objectp->permMove() && objectp->permModify(); + BOOL enable_rotate = objectp->permMove() && ( (objectp->permModify() && !objectp->isAttachment()) || !gSavedSettings.getBOOL("EditLinkedParts")); + + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME )) + && (selected_count == 1); + + if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 1) + { + enable_move = FALSE; + enable_scale = FALSE; + enable_rotate = FALSE; + } + + LLVector3 vec; + if (enable_move) + { + vec = objectp->getPositionEdit(); + mCtrlPosX->set( vec.mV[VX] ); + mCtrlPosY->set( vec.mV[VY] ); + mCtrlPosZ->set( vec.mV[VZ] ); + } + else + { + mCtrlPosX->clear(); + mCtrlPosY->clear(); + mCtrlPosZ->clear(); + } + + + mLabelPosition->setEnabled( enable_move ); + mCtrlPosX->setEnabled(enable_move); + mCtrlPosY->setEnabled(enable_move); + mCtrlPosZ->setEnabled(enable_move); + + if (enable_scale) + { + vec = objectp->getScale(); + mCtrlScaleX->set( vec.mV[VX] ); + mCtrlScaleY->set( vec.mV[VY] ); + mCtrlScaleZ->set( vec.mV[VZ] ); + } + else + { + mCtrlScaleX->clear(); + mCtrlScaleY->clear(); + mCtrlScaleZ->clear(); + } + + mLabelSize->setEnabled( enable_scale ); + mCtrlScaleX->setEnabled( enable_scale ); + mCtrlScaleY->setEnabled( enable_scale ); + mCtrlScaleZ->setEnabled( enable_scale ); + + LLQuaternion object_rot = objectp->getRotationEdit(); + object_rot.getEulerAngles(&(mCurEulerDegrees.mV[VX]), &(mCurEulerDegrees.mV[VY]), &(mCurEulerDegrees.mV[VZ])); + mCurEulerDegrees *= RAD_TO_DEG; + mCurEulerDegrees.mV[VX] = fmod(llround(mCurEulerDegrees.mV[VX], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); + mCurEulerDegrees.mV[VY] = fmod(llround(mCurEulerDegrees.mV[VY], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); + mCurEulerDegrees.mV[VZ] = fmod(llround(mCurEulerDegrees.mV[VZ], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); + + if (enable_rotate) + { + mCtrlRotX->set( mCurEulerDegrees.mV[VX] ); + mCtrlRotY->set( mCurEulerDegrees.mV[VY] ); + mCtrlRotZ->set( mCurEulerDegrees.mV[VZ] ); + } + else + { + mCtrlRotX->clear(); + mCtrlRotY->clear(); + mCtrlRotZ->clear(); + } + + mLabelRotation->setEnabled( enable_rotate ); + mCtrlRotX->setEnabled( enable_rotate ); + mCtrlRotY->setEnabled( enable_rotate ); + mCtrlRotZ->setEnabled( enable_rotate ); + + BOOL owners_identical; + LLUUID owner_id; + std::string owner_name; + owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); + + // BUG? Check for all objects being editable? + S32 roots_selected = LLSelectMgr::getInstance()->getSelection()->getRootObjectCount(); + BOOL editable = root_objectp->permModify(); + + // Select Single Message + getChildView("select_single")->setVisible( FALSE); + getChildView("edit_object")->setVisible( FALSE); + if (!editable || single_volume || selected_count <= 1) + { + getChildView("edit_object")->setVisible( TRUE); + getChildView("edit_object")->setEnabled(TRUE); + } + else + { + getChildView("select_single")->setVisible( TRUE); + getChildView("select_single")->setEnabled(TRUE); + } + // Lock checkbox - only modifiable if you own the object. + BOOL self_owned = (gAgent.getID() == owner_id); + mCheckLock->setEnabled( roots_selected > 0 && self_owned ); + + // More lock and debit checkbox - get the values + BOOL valid; + U32 owner_mask_on; + U32 owner_mask_off; + valid = LLSelectMgr::getInstance()->selectGetPerm(PERM_OWNER, &owner_mask_on, &owner_mask_off); + + if(valid) + { + if(owner_mask_on & PERM_MOVE) + { + // owner can move, so not locked + mCheckLock->set(FALSE); + mCheckLock->setTentative(FALSE); + } + else if(owner_mask_off & PERM_MOVE) + { + // owner can't move, so locked + mCheckLock->set(TRUE); + mCheckLock->setTentative(FALSE); + } + else + { + // some locked, some not locked + mCheckLock->set(FALSE); + mCheckLock->setTentative(TRUE); + } + } + + BOOL is_flexible = volobjp && volobjp->isFlexible(); + + // Physics checkbox + mIsPhysical = root_objectp->usePhysics(); + mCheckPhysics->set( mIsPhysical ); + mCheckPhysics->setEnabled( roots_selected>0 + && (editable || gAgent.isGodlike()) + && !is_flexible); + + mIsTemporary = root_objectp->flagTemporaryOnRez(); + mCheckTemporary->set( mIsTemporary ); + mCheckTemporary->setEnabled( roots_selected>0 && editable ); + + mIsPhantom = root_objectp->flagPhantom(); + mCheckPhantom->set( mIsPhantom ); + mCheckPhantom->setEnabled( roots_selected>0 && editable && !is_flexible ); + + +#if 0 // 1.9.2 + mCastShadows = root_objectp->flagCastShadows(); + mCheckCastShadows->set( mCastShadows ); + mCheckCastShadows->setEnabled( roots_selected==1 && editable ); +#endif + + //---------------------------------------------------------------------------- + + S32 selected_item = MI_BOX; + S32 selected_hole = MI_HOLE_SAME; + BOOL enabled = FALSE; + BOOL hole_enabled = FALSE; + F32 scale_x=1.f, scale_y=1.f; + BOOL isMesh = FALSE; + + if( !objectp || !objectp->getVolume() || !editable || !single_volume) + { + // Clear out all geometry fields. + mComboBaseType->clear(); + mSpinHollow->clear(); + mSpinCutBegin->clear(); + mSpinCutEnd->clear(); + mCtrlPathBegin->clear(); + mCtrlPathEnd->clear(); + mSpinScaleX->clear(); + mSpinScaleY->clear(); + mSpinTwist->clear(); + mSpinTwistBegin->clear(); + mComboHoleType->clear(); + mSpinShearX->clear(); + mSpinShearY->clear(); + mSpinTaperX->clear(); + mSpinTaperY->clear(); + mSpinRadiusOffset->clear(); + mSpinRevolutions->clear(); + mSpinSkew->clear(); + + mSelectedType = MI_NONE; + } + else + { + // Only allowed to change these parameters for objects + // that you have permissions on AND are not attachments. + enabled = root_objectp->permModify(); + + // Volume type + const LLVolumeParams &volume_params = objectp->getVolume()->getParams(); + U8 path = volume_params.getPathParams().getCurveType(); + U8 profile_and_hole = volume_params.getProfileParams().getCurveType(); + U8 profile = profile_and_hole & LL_PCODE_PROFILE_MASK; + U8 hole = profile_and_hole & LL_PCODE_HOLE_MASK; + + // Scale goes first so we can differentiate between a sphere and a torus, + // which have the same profile and path types. + + // Scale + scale_x = volume_params.getRatioX(); + scale_y = volume_params.getRatioY(); + + BOOL linear_path = (path == LL_PCODE_PATH_LINE) || (path == LL_PCODE_PATH_FLEXIBLE); + if ( linear_path && profile == LL_PCODE_PROFILE_CIRCLE ) + { + selected_item = MI_CYLINDER; + } + else if ( linear_path && profile == LL_PCODE_PROFILE_SQUARE ) + { + selected_item = MI_BOX; + } + else if ( linear_path && profile == LL_PCODE_PROFILE_ISOTRI ) + { + selected_item = MI_PRISM; + } + else if ( linear_path && profile == LL_PCODE_PROFILE_EQUALTRI ) + { + selected_item = MI_PRISM; + } + else if ( linear_path && profile == LL_PCODE_PROFILE_RIGHTTRI ) + { + selected_item = MI_PRISM; + } + else if (path == LL_PCODE_PATH_FLEXIBLE) // shouldn't happen + { + selected_item = MI_CYLINDER; // reasonable default + } + else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE && scale_y > 0.75f) + { + selected_item = MI_SPHERE; + } + else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE && scale_y <= 0.75f) + { + selected_item = MI_TORUS; + } + else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE_HALF) + { + selected_item = MI_SPHERE; + } + else if ( path == LL_PCODE_PATH_CIRCLE2 && profile == LL_PCODE_PROFILE_CIRCLE ) + { + // Spirals aren't supported. Make it into a sphere. JC + selected_item = MI_SPHERE; + } + else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_EQUALTRI ) + { + selected_item = MI_RING; + } + else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_SQUARE && scale_y <= 0.75f) + { + selected_item = MI_TUBE; + } + else + { + llinfos << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << llendl; + selected_item = MI_BOX; + } + + + if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) + { + selected_item = MI_SCULPT; + //LLFirstUse::useSculptedPrim(); + } + + + mComboBaseType ->setCurrentByIndex( selected_item ); + mSelectedType = selected_item; + + // Grab S path + F32 begin_s = volume_params.getBeginS(); + F32 end_s = volume_params.getEndS(); + + // Compute cut and advanced cut from S and T + F32 begin_t = volume_params.getBeginT(); + F32 end_t = volume_params.getEndT(); + + // Hollowness + F32 hollow = volume_params.getHollow(); + mSpinHollow->set( 100.f * hollow ); + + // All hollow objects allow a shape to be selected. + if (hollow > 0.f) + { + switch (hole) + { + case LL_PCODE_HOLE_CIRCLE: + selected_hole = MI_HOLE_CIRCLE; + break; + case LL_PCODE_HOLE_SQUARE: + selected_hole = MI_HOLE_SQUARE; + break; + case LL_PCODE_HOLE_TRIANGLE: + selected_hole = MI_HOLE_TRIANGLE; + break; + case LL_PCODE_HOLE_SAME: + default: + selected_hole = MI_HOLE_SAME; + break; + } + mComboHoleType->setCurrentByIndex( selected_hole ); + hole_enabled = enabled; + } + else + { + mComboHoleType->setCurrentByIndex( MI_HOLE_SAME ); + hole_enabled = FALSE; + } + + // Cut interpretation varies based on base object type + F32 cut_begin, cut_end, adv_cut_begin, adv_cut_end; + + if ( selected_item == MI_SPHERE || selected_item == MI_TORUS || + selected_item == MI_TUBE || selected_item == MI_RING ) + { + cut_begin = begin_t; + cut_end = end_t; + adv_cut_begin = begin_s; + adv_cut_end = end_s; + } + else + { + cut_begin = begin_s; + cut_end = end_s; + adv_cut_begin = begin_t; + adv_cut_end = end_t; + } + + mSpinCutBegin ->set( cut_begin ); + mSpinCutEnd ->set( cut_end ); + mCtrlPathBegin ->set( adv_cut_begin ); + mCtrlPathEnd ->set( adv_cut_end ); + + // Twist + F32 twist = volume_params.getTwist(); + F32 twist_begin = volume_params.getTwistBegin(); + // Check the path type for conversion. + if (path == LL_PCODE_PATH_LINE || path == LL_PCODE_PATH_FLEXIBLE) + { + twist *= OBJECT_TWIST_LINEAR_MAX; + twist_begin *= OBJECT_TWIST_LINEAR_MAX; + } + else + { + twist *= OBJECT_TWIST_MAX; + twist_begin *= OBJECT_TWIST_MAX; + } + + mSpinTwist ->set( twist ); + mSpinTwistBegin ->set( twist_begin ); + + // Shear + F32 shear_x = volume_params.getShearX(); + F32 shear_y = volume_params.getShearY(); + mSpinShearX->set( shear_x ); + mSpinShearY->set( shear_y ); + + // Taper + F32 taper_x = volume_params.getTaperX(); + F32 taper_y = volume_params.getTaperY(); + mSpinTaperX->set( taper_x ); + mSpinTaperY->set( taper_y ); + + // Radius offset. + F32 radius_offset = volume_params.getRadiusOffset(); + // Limit radius offset, based on taper and hole size y. + F32 radius_mag = fabs(radius_offset); + F32 hole_y_mag = fabs(scale_y); + F32 taper_y_mag = fabs(taper_y); + // Check to see if the taper effects us. + if ( (radius_offset > 0.f && taper_y < 0.f) || + (radius_offset < 0.f && taper_y > 0.f) ) + { + // The taper does not help increase the radius offset range. + taper_y_mag = 0.f; + } + F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag); + // Enforce the maximum magnitude. + if (radius_mag > max_radius_mag) + { + // Check radius offset sign. + if (radius_offset < 0.f) + { + radius_offset = -max_radius_mag; + } + else + { + radius_offset = max_radius_mag; + } + } + mSpinRadiusOffset->set( radius_offset); + + // Revolutions + F32 revolutions = volume_params.getRevolutions(); + mSpinRevolutions->set( revolutions ); + + // Skew + F32 skew = volume_params.getSkew(); + // Limit skew, based on revolutions hole size x. + F32 skew_mag= fabs(skew); + F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f); + // Discontinuity; A revolution of 1 allows skews below 0.5. + if ( fabs(revolutions - 1.0f) < 0.001) + min_skew_mag = 0.0f; + + // Clip skew. + if (skew_mag < min_skew_mag) + { + // Check skew sign. + if (skew < 0.0f) + { + skew = -min_skew_mag; + } + else + { + skew = min_skew_mag; + } + } + mSpinSkew->set( skew ); + } + + // Compute control visibility, label names, and twist range. + // Start with defaults. + BOOL cut_visible = TRUE; + BOOL hollow_visible = TRUE; + BOOL top_size_x_visible = TRUE; + BOOL top_size_y_visible = TRUE; + BOOL top_shear_x_visible = TRUE; + BOOL top_shear_y_visible = TRUE; + BOOL twist_visible = TRUE; + BOOL advanced_cut_visible = FALSE; + BOOL taper_visible = FALSE; + BOOL skew_visible = FALSE; + BOOL radius_offset_visible = FALSE; + BOOL revolutions_visible = FALSE; + BOOL sculpt_texture_visible = FALSE; + F32 twist_min = OBJECT_TWIST_LINEAR_MIN; + F32 twist_max = OBJECT_TWIST_LINEAR_MAX; + F32 twist_inc = OBJECT_TWIST_LINEAR_INC; + + BOOL advanced_is_dimple = FALSE; + BOOL advanced_is_slice = FALSE; + BOOL size_is_hole = FALSE; + + // Tune based on overall volume type + switch (selected_item) + { + case MI_SPHERE: + top_size_x_visible = FALSE; + top_size_y_visible = FALSE; + top_shear_x_visible = FALSE; + top_shear_y_visible = FALSE; + //twist_visible = FALSE; + advanced_cut_visible = TRUE; + advanced_is_dimple = TRUE; + twist_min = OBJECT_TWIST_MIN; + twist_max = OBJECT_TWIST_MAX; + twist_inc = OBJECT_TWIST_INC; + break; + + case MI_TORUS: + case MI_TUBE: + case MI_RING: + //top_size_x_visible = FALSE; + //top_size_y_visible = FALSE; + size_is_hole = TRUE; + skew_visible = TRUE; + advanced_cut_visible = TRUE; + taper_visible = TRUE; + radius_offset_visible = TRUE; + revolutions_visible = TRUE; + twist_min = OBJECT_TWIST_MIN; + twist_max = OBJECT_TWIST_MAX; + twist_inc = OBJECT_TWIST_INC; + + break; + + case MI_SCULPT: + cut_visible = FALSE; + hollow_visible = FALSE; + twist_visible = FALSE; + top_size_x_visible = FALSE; + top_size_y_visible = FALSE; + top_shear_x_visible = FALSE; + top_shear_y_visible = FALSE; + skew_visible = FALSE; + advanced_cut_visible = FALSE; + taper_visible = FALSE; + radius_offset_visible = FALSE; + revolutions_visible = FALSE; + sculpt_texture_visible = TRUE; + + break; + + case MI_BOX: + advanced_cut_visible = TRUE; + advanced_is_slice = TRUE; + break; + + case MI_CYLINDER: + advanced_cut_visible = TRUE; + advanced_is_slice = TRUE; + break; + + case MI_PRISM: + advanced_cut_visible = TRUE; + advanced_is_slice = TRUE; + break; + + default: + break; + } + + // Check if we need to change top size/hole size params. + switch (selected_item) + { + case MI_SPHERE: + case MI_TORUS: + case MI_TUBE: + case MI_RING: + mSpinScaleX->set( scale_x ); + mSpinScaleY->set( scale_y ); + mSpinScaleX->setMinValue(OBJECT_MIN_HOLE_SIZE); + mSpinScaleX->setMaxValue(OBJECT_MAX_HOLE_SIZE_X); + mSpinScaleY->setMinValue(OBJECT_MIN_HOLE_SIZE); + mSpinScaleY->setMaxValue(OBJECT_MAX_HOLE_SIZE_Y); + break; + default: + if (editable) + { + mSpinScaleX->set( 1.f - scale_x ); + mSpinScaleY->set( 1.f - scale_y ); + mSpinScaleX->setMinValue(-1.f); + mSpinScaleX->setMaxValue(1.f); + mSpinScaleY->setMinValue(-1.f); + mSpinScaleY->setMaxValue(1.f); + } + break; + } + + // Check if we need to limit the hollow based on the hole type. + if ( selected_hole == MI_HOLE_SQUARE && + ( selected_item == MI_CYLINDER || selected_item == MI_TORUS || + selected_item == MI_PRISM || selected_item == MI_RING || + selected_item == MI_SPHERE ) ) + { + mSpinHollow->setMinValue(0.f); + mSpinHollow->setMaxValue(70.f); + } + else + { + mSpinHollow->setMinValue(0.f); + mSpinHollow->setMaxValue(95.f); + } + + // Update field enablement + mComboBaseType ->setEnabled( enabled ); + + mLabelCut ->setEnabled( enabled ); + mSpinCutBegin ->setEnabled( enabled ); + mSpinCutEnd ->setEnabled( enabled ); + + mLabelHollow ->setEnabled( enabled ); + mSpinHollow ->setEnabled( enabled ); + mLabelHoleType ->setEnabled( hole_enabled ); + mComboHoleType ->setEnabled( hole_enabled ); + + mLabelTwist ->setEnabled( enabled ); + mSpinTwist ->setEnabled( enabled ); + mSpinTwistBegin ->setEnabled( enabled ); + + mLabelSkew ->setEnabled( enabled ); + mSpinSkew ->setEnabled( enabled ); + + getChildView("scale_hole")->setVisible( FALSE); + getChildView("scale_taper")->setVisible( FALSE); + if (top_size_x_visible || top_size_y_visible) + { + if (size_is_hole) + { + getChildView("scale_hole")->setVisible( TRUE); + getChildView("scale_hole")->setEnabled(enabled); + } + else + { + getChildView("scale_taper")->setVisible( TRUE); + getChildView("scale_taper")->setEnabled(enabled); + } + } + + mSpinScaleX ->setEnabled( enabled ); + mSpinScaleY ->setEnabled( enabled ); + + mLabelShear ->setEnabled( enabled ); + mSpinShearX ->setEnabled( enabled ); + mSpinShearY ->setEnabled( enabled ); + + getChildView("advanced_cut")->setVisible( FALSE); + getChildView("advanced_dimple")->setVisible( FALSE); + getChildView("advanced_slice")->setVisible( FALSE); + + if (advanced_cut_visible) + { + if (advanced_is_dimple) + { + getChildView("advanced_dimple")->setVisible( TRUE); + getChildView("advanced_dimple")->setEnabled(enabled); + } + + else if (advanced_is_slice) + { + getChildView("advanced_slice")->setVisible( TRUE); + getChildView("advanced_slice")->setEnabled(enabled); + } + else + { + getChildView("advanced_cut")->setVisible( TRUE); + getChildView("advanced_cut")->setEnabled(enabled); + } + } + + mCtrlPathBegin ->setEnabled( enabled ); + mCtrlPathEnd ->setEnabled( enabled ); + + mLabelTaper ->setEnabled( enabled ); + mSpinTaperX ->setEnabled( enabled ); + mSpinTaperY ->setEnabled( enabled ); + + mLabelRadiusOffset->setEnabled( enabled ); + mSpinRadiusOffset ->setEnabled( enabled ); + + mLabelRevolutions->setEnabled( enabled ); + mSpinRevolutions ->setEnabled( enabled ); + + // Update field visibility + mLabelCut ->setVisible( cut_visible ); + mSpinCutBegin ->setVisible( cut_visible ); + mSpinCutEnd ->setVisible( cut_visible ); + + mLabelHollow ->setVisible( hollow_visible ); + mSpinHollow ->setVisible( hollow_visible ); + mLabelHoleType ->setVisible( hollow_visible ); + mComboHoleType ->setVisible( hollow_visible ); + + mLabelTwist ->setVisible( twist_visible ); + mSpinTwist ->setVisible( twist_visible ); + mSpinTwistBegin ->setVisible( twist_visible ); + mSpinTwist ->setMinValue( twist_min ); + mSpinTwist ->setMaxValue( twist_max ); + mSpinTwist ->setIncrement( twist_inc ); + mSpinTwistBegin ->setMinValue( twist_min ); + mSpinTwistBegin ->setMaxValue( twist_max ); + mSpinTwistBegin ->setIncrement( twist_inc ); + + mSpinScaleX ->setVisible( top_size_x_visible ); + mSpinScaleY ->setVisible( top_size_y_visible ); + + mLabelSkew ->setVisible( skew_visible ); + mSpinSkew ->setVisible( skew_visible ); + + mLabelShear ->setVisible( top_shear_x_visible || top_shear_y_visible ); + mSpinShearX ->setVisible( top_shear_x_visible ); + mSpinShearY ->setVisible( top_shear_y_visible ); + + mCtrlPathBegin ->setVisible( advanced_cut_visible ); + mCtrlPathEnd ->setVisible( advanced_cut_visible ); + + mLabelTaper ->setVisible( taper_visible ); + mSpinTaperX ->setVisible( taper_visible ); + mSpinTaperY ->setVisible( taper_visible ); + + mLabelRadiusOffset->setVisible( radius_offset_visible ); + mSpinRadiusOffset ->setVisible( radius_offset_visible ); + + mLabelRevolutions->setVisible( revolutions_visible ); + mSpinRevolutions ->setVisible( revolutions_visible ); + + mCtrlSculptTexture->setVisible(sculpt_texture_visible); + mLabelSculptType->setVisible(sculpt_texture_visible); + mCtrlSculptType->setVisible(sculpt_texture_visible); + + + // sculpt texture + if (selected_item == MI_SCULPT) + { + + + LLUUID id; + LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + + + if (sculpt_params) // if we have a legal sculpt param block for this object: + { + if (mObject != objectp) // we've just selected a new object, so save for undo + { + mSculptTextureRevert = sculpt_params->getSculptTexture(); + mSculptTypeRevert = sculpt_params->getSculptType(); + } + + U8 sculpt_type = sculpt_params->getSculptType(); + U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; + BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; + BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; + isMesh = (sculpt_stitching == LL_SCULPT_TYPE_MESH); + + LLTextureCtrl* mTextureCtrl = getChild("sculpt texture control"); + if(mTextureCtrl) + { + mTextureCtrl->setTentative(FALSE); + mTextureCtrl->setEnabled(editable && !isMesh); + if (editable) + mTextureCtrl->setImageAssetID(sculpt_params->getSculptTexture()); + else + mTextureCtrl->setImageAssetID(LLUUID::null); + } + + mComboBaseType->setEnabled(!isMesh); + + if (mCtrlSculptType) + { + mCtrlSculptType->setCurrentByIndex(sculpt_stitching); + mCtrlSculptType->setEnabled(editable && !isMesh); + } + + if (mCtrlSculptMirror) + { + mCtrlSculptMirror->set(sculpt_mirror); + mCtrlSculptMirror->setEnabled(editable && !isMesh); + } + + if (mCtrlSculptInvert) + { + mCtrlSculptInvert->set(sculpt_invert); + mCtrlSculptInvert->setEnabled(editable); + } + + if (mLabelSculptType) + { + mLabelSculptType->setEnabled(TRUE); + } + + } + } + else + { + mSculptTextureRevert = LLUUID::null; + } + + mCtrlSculptMirror->setVisible(sculpt_texture_visible && !isMesh); + mCtrlSculptInvert->setVisible(sculpt_texture_visible && !isMesh); + + //---------------------------------------------------------------------------- + + mObject = objectp; + mRootObject = root_objectp; +} + +// static +bool LLPanelObject::precommitValidate( const LLSD& data ) +{ + // TODO: Richard will fill this in later. + return TRUE; // FALSE means that validation failed and new value should not be commited. +} + +void LLPanelObject::sendIsPhysical() +{ + BOOL value = mCheckPhysics->get(); + if( mIsPhysical != value ) + { + LLSelectMgr::getInstance()->selectionUpdatePhysics(value); + mIsPhysical = value; + + llinfos << "update physics sent" << llendl; + } + else + { + llinfos << "update physics not changed" << llendl; + } +} + +void LLPanelObject::sendIsTemporary() +{ + BOOL value = mCheckTemporary->get(); + if( mIsTemporary != value ) + { + LLSelectMgr::getInstance()->selectionUpdateTemporary(value); + mIsTemporary = value; + + llinfos << "update temporary sent" << llendl; + } + else + { + llinfos << "update temporary not changed" << llendl; + } +} + + +void LLPanelObject::sendIsPhantom() +{ + BOOL value = mCheckPhantom->get(); + if( mIsPhantom != value ) + { + LLSelectMgr::getInstance()->selectionUpdatePhantom(value); + mIsPhantom = value; + + llinfos << "update phantom sent" << llendl; + } + else + { + llinfos << "update phantom not changed" << llendl; + } +} + +void LLPanelObject::sendCastShadows() +{ + BOOL value = mCheckCastShadows->get(); + if( mCastShadows != value ) + { + LLSelectMgr::getInstance()->selectionUpdateCastShadows(value); + mCastShadows = value; + + llinfos << "update cast shadows sent" << llendl; + } + else + { + llinfos << "update cast shadows not changed" << llendl; + } +} + +// static +void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + + if (self->mObject.isNull()) + { + return; + } + + if (self->mObject->getPCode() != LL_PCODE_VOLUME) + { + // Don't allow modification of non-volume objects. + return; + } + + LLVolume *volume = self->mObject->getVolume(); + if (!volume) + { + return; + } + + LLVolumeParams volume_params; + self->getVolumeParams(volume_params); + + + + // set sculpting + S32 selected_type = self->mComboBaseType->getCurrentIndex(); + + if (selected_type == MI_SCULPT) + { + self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, TRUE, TRUE); + LLSculptParams *sculpt_params = (LLSculptParams *)self->mObject->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + if (sculpt_params) + volume_params.setSculptID(sculpt_params->getSculptTexture(), sculpt_params->getSculptType()); + } + else + { + LLSculptParams *sculpt_params = (LLSculptParams *)self->mObject->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + if (sculpt_params) + self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE); + } + + // Update the volume, if necessary. + self->mObject->updateVolume(volume_params); + + + // This was added to make sure thate when changes are made, the UI + // adjusts to present valid options. + // *FIX: only some changes, ie, hollow or primitive type changes, + // require a refresh. + self->refresh(); + +} + +void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params) +{ + // Figure out what type of volume to make + S32 was_selected_type = mSelectedType; + S32 selected_type = mComboBaseType->getCurrentIndex(); + U8 profile; + U8 path; + switch ( selected_type ) + { + case MI_CYLINDER: + profile = LL_PCODE_PROFILE_CIRCLE; + path = LL_PCODE_PATH_LINE; + break; + + case MI_BOX: + profile = LL_PCODE_PROFILE_SQUARE; + path = LL_PCODE_PATH_LINE; + break; + + case MI_PRISM: + profile = LL_PCODE_PROFILE_EQUALTRI; + path = LL_PCODE_PATH_LINE; + break; + + case MI_SPHERE: + profile = LL_PCODE_PROFILE_CIRCLE_HALF; + path = LL_PCODE_PATH_CIRCLE; + break; + + case MI_TORUS: + profile = LL_PCODE_PROFILE_CIRCLE; + path = LL_PCODE_PATH_CIRCLE; + break; + + case MI_TUBE: + profile = LL_PCODE_PROFILE_SQUARE; + path = LL_PCODE_PATH_CIRCLE; + break; + + case MI_RING: + profile = LL_PCODE_PROFILE_EQUALTRI; + path = LL_PCODE_PATH_CIRCLE; + break; + + case MI_SCULPT: + profile = LL_PCODE_PROFILE_CIRCLE; + path = LL_PCODE_PATH_CIRCLE; + break; + + default: + llwarns << "Unknown base type " << selected_type + << " in getVolumeParams()" << llendl; + // assume a box + selected_type = MI_BOX; + profile = LL_PCODE_PROFILE_SQUARE; + path = LL_PCODE_PATH_LINE; + break; + } + + + if (path == LL_PCODE_PATH_LINE) + { + LLVOVolume *volobjp = (LLVOVolume *)(LLViewerObject*)(mObject); + if (volobjp->isFlexible()) + { + path = LL_PCODE_PATH_FLEXIBLE; + } + } + + S32 selected_hole = mComboHoleType->getCurrentIndex(); + U8 hole; + switch (selected_hole) + { + case MI_HOLE_CIRCLE: + hole = LL_PCODE_HOLE_CIRCLE; + break; + case MI_HOLE_SQUARE: + hole = LL_PCODE_HOLE_SQUARE; + break; + case MI_HOLE_TRIANGLE: + hole = LL_PCODE_HOLE_TRIANGLE; + break; + case MI_HOLE_SAME: + default: + hole = LL_PCODE_HOLE_SAME; + break; + } + + volume_params.setType(profile | hole, path); + mSelectedType = selected_type; + + // Compute cut start/end + F32 cut_begin = mSpinCutBegin->get(); + F32 cut_end = mSpinCutEnd->get(); + + // Make sure at least OBJECT_CUT_INC of the object survives + if (cut_begin > cut_end - OBJECT_MIN_CUT_INC) + { + cut_begin = cut_end - OBJECT_MIN_CUT_INC; + mSpinCutBegin->set(cut_begin); + } + + F32 adv_cut_begin = mCtrlPathBegin->get(); + F32 adv_cut_end = mCtrlPathEnd->get(); + + // Make sure at least OBJECT_CUT_INC of the object survives + if (adv_cut_begin > adv_cut_end - OBJECT_MIN_CUT_INC) + { + adv_cut_begin = adv_cut_end - OBJECT_MIN_CUT_INC; + mCtrlPathBegin->set(adv_cut_begin); + } + + F32 begin_s, end_s; + F32 begin_t, end_t; + + if (selected_type == MI_SPHERE || selected_type == MI_TORUS || + selected_type == MI_TUBE || selected_type == MI_RING) + { + begin_s = adv_cut_begin; + end_s = adv_cut_end; + + begin_t = cut_begin; + end_t = cut_end; + } + else + { + begin_s = cut_begin; + end_s = cut_end; + + begin_t = adv_cut_begin; + end_t = adv_cut_end; + } + + volume_params.setBeginAndEndS(begin_s, end_s); + volume_params.setBeginAndEndT(begin_t, end_t); + + // Hollowness + F32 hollow = mSpinHollow->get() / 100.f; + + if ( selected_hole == MI_HOLE_SQUARE && + ( selected_type == MI_CYLINDER || selected_type == MI_TORUS || + selected_type == MI_PRISM || selected_type == MI_RING || + selected_type == MI_SPHERE ) ) + { + if (hollow > 0.7f) hollow = 0.7f; + } + + volume_params.setHollow( hollow ); + + // Twist Begin,End + F32 twist_begin = mSpinTwistBegin->get(); + F32 twist = mSpinTwist->get(); + // Check the path type for twist conversion. + if (path == LL_PCODE_PATH_LINE || path == LL_PCODE_PATH_FLEXIBLE) + { + twist_begin /= OBJECT_TWIST_LINEAR_MAX; + twist /= OBJECT_TWIST_LINEAR_MAX; + } + else + { + twist_begin /= OBJECT_TWIST_MAX; + twist /= OBJECT_TWIST_MAX; + } + + volume_params.setTwistBegin(twist_begin); + volume_params.setTwist(twist); + + // Scale X,Y + F32 scale_x = mSpinScaleX->get(); + F32 scale_y = mSpinScaleY->get(); + if ( was_selected_type == MI_BOX || was_selected_type == MI_CYLINDER || was_selected_type == MI_PRISM) + { + scale_x = 1.f - scale_x; + scale_y = 1.f - scale_y; + } + + // Skew + F32 skew = mSpinSkew->get(); + + // Taper X,Y + F32 taper_x = mSpinTaperX->get(); + F32 taper_y = mSpinTaperY->get(); + + // Radius offset + F32 radius_offset = mSpinRadiusOffset->get(); + + // Revolutions + F32 revolutions = mSpinRevolutions->get(); + + if ( selected_type == MI_SPHERE ) + { + // Snap values to valid sphere parameters. + scale_x = 1.0f; + scale_y = 1.0f; + skew = 0.0f; + taper_x = 0.0f; + taper_y = 0.0f; + radius_offset = 0.0f; + revolutions = 1.0f; + } + else if ( selected_type == MI_TORUS || selected_type == MI_TUBE || + selected_type == MI_RING ) + { + scale_x = llclamp( + scale_x, + OBJECT_MIN_HOLE_SIZE, + OBJECT_MAX_HOLE_SIZE_X); + scale_y = llclamp( + scale_y, + OBJECT_MIN_HOLE_SIZE, + OBJECT_MAX_HOLE_SIZE_Y); + + // Limit radius offset, based on taper and hole size y. + F32 radius_mag = fabs(radius_offset); + F32 hole_y_mag = fabs(scale_y); + F32 taper_y_mag = fabs(taper_y); + // Check to see if the taper effects us. + if ( (radius_offset > 0.f && taper_y < 0.f) || + (radius_offset < 0.f && taper_y > 0.f) ) + { + // The taper does not help increase the radius offset range. + taper_y_mag = 0.f; + } + F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag); + // Enforce the maximum magnitude. + if (radius_mag > max_radius_mag) + { + // Check radius offset sign. + if (radius_offset < 0.f) + { + radius_offset = -max_radius_mag; + } + else + { + radius_offset = max_radius_mag; + } + } + + // Check the skew value against the revolutions. + F32 skew_mag= fabs(skew); + F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f); + // Discontinuity; A revolution of 1 allows skews below 0.5. + if ( fabs(revolutions - 1.0f) < 0.001) + min_skew_mag = 0.0f; + + // Clip skew. + if (skew_mag < min_skew_mag) + { + // Check skew sign. + if (skew < 0.0f) + { + skew = -min_skew_mag; + } + else + { + skew = min_skew_mag; + } + } + } + + volume_params.setRatio( scale_x, scale_y ); + volume_params.setSkew(skew); + volume_params.setTaper( taper_x, taper_y ); + volume_params.setRadiusOffset(radius_offset); + volume_params.setRevolutions(revolutions); + + // Shear X,Y + F32 shear_x = mSpinShearX->get(); + F32 shear_y = mSpinShearY->get(); + volume_params.setShear( shear_x, shear_y ); + + if (selected_type == MI_SCULPT) + { + volume_params.setSculptID(LLUUID::null, 0); + volume_params.setBeginAndEndT (0, 1); + volume_params.setBeginAndEndS (0, 1); + volume_params.setHollow (0); + volume_params.setTwistBegin (0); + volume_params.setTwistEnd (0); + volume_params.setRatio (1, 0.5); + volume_params.setShear (0, 0); + volume_params.setTaper (0, 0); + volume_params.setRevolutions (1); + volume_params.setRadiusOffset (0); + volume_params.setSkew (0); + } + +} + +// BUG: Make work with multiple objects +void LLPanelObject::sendRotation(BOOL btn_down) +{ + if (mObject.isNull()) return; + + LLVector3 new_rot(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get()); + new_rot.mV[VX] = llround(new_rot.mV[VX], OBJECT_ROTATION_PRECISION); + new_rot.mV[VY] = llround(new_rot.mV[VY], OBJECT_ROTATION_PRECISION); + new_rot.mV[VZ] = llround(new_rot.mV[VZ], OBJECT_ROTATION_PRECISION); + + // Note: must compare before conversion to radians + LLVector3 delta = new_rot - mCurEulerDegrees; + + if (delta.magVec() >= 0.0005f) + { + mCurEulerDegrees = new_rot; + new_rot *= DEG_TO_RAD; + + LLQuaternion rotation; + rotation.setQuat(new_rot.mV[VX], new_rot.mV[VY], new_rot.mV[VZ]); + + if (mRootObject != mObject) + { + rotation = rotation * ~mRootObject->getRotationRegion(); + } + std::vector& child_positions = mObject->mUnselectedChildrenPositions ; + std::vector child_rotations; + if (mObject->isRootEdit()) + { + mObject->saveUnselectedChildrenRotation(child_rotations) ; + mObject->saveUnselectedChildrenPosition(child_positions) ; + } + + mObject->setRotation(rotation); + LLManip::rebuild(mObject) ; + + // for individually selected roots, we need to counterrotate all the children + if (mObject->isRootEdit()) + { + mObject->resetChildrenRotationAndPosition(child_rotations, child_positions) ; + } + + if(!btn_down) + { + child_positions.clear() ; + LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_ROTATION | UPD_POSITION); + } + } +} + + +// BUG: Make work with multiple objects +void LLPanelObject::sendScale(BOOL btn_down) +{ + if (mObject.isNull()) return; + + LLVector3 newscale(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get()); + + LLVector3 delta = newscale - mObject->getScale(); + if (delta.magVec() >= 0.0005f) + { + // scale changed by more than 1/2 millimeter + + // check to see if we aren't scaling the textures + // (in which case the tex coord's need to be recomputed) + BOOL dont_stretch_textures = !LLManipScale::getStretchTextures(); + if (dont_stretch_textures) + { + LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_SCALE); + } + + mObject->setScale(newscale, TRUE); + + if(!btn_down) + { + LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_SCALE | UPD_POSITION); + } + + LLSelectMgr::getInstance()->adjustTexturesByScale(TRUE, !dont_stretch_textures); +// llinfos << "scale sent" << llendl; + } + else + { +// llinfos << "scale not changed" << llendl; + } +} + + +void LLPanelObject::sendPosition(BOOL btn_down) +{ + if (mObject.isNull()) return; + + LLVector3 newpos(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get()); + LLViewerRegion* regionp = mObject->getRegion(); + + // Clamp the Z height + const F32 height = newpos.mV[VZ]; + const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal()); + const F32 max_height = LLWorld::getInstance()->getRegionMaxHeight(); + + if (!mObject->isAttachment()) + { + if ( height < min_height) + { + newpos.mV[VZ] = min_height; + mCtrlPosZ->set( min_height ); + } + else if ( height > max_height ) + { + newpos.mV[VZ] = max_height; + mCtrlPosZ->set( max_height ); + } + + // Grass is always drawn on the ground, so clamp its position to the ground + if (mObject->getPCode() == LL_PCODE_LEGACY_GRASS) + { + mCtrlPosZ->set(LLWorld::getInstance()->resolveLandHeightAgent(newpos) + 1.f); + } + } + + // Make sure new position is in a valid region, so the object + // won't get dumped by the simulator. + LLVector3d new_pos_global = regionp->getPosGlobalFromRegion(newpos); + + if ( LLWorld::getInstance()->positionRegionValidGlobal(new_pos_global) ) + { + // send only if the position is changed, that is, the delta vector is not zero + LLVector3d old_pos_global = mObject->getPositionGlobal(); + LLVector3d delta = new_pos_global - old_pos_global; + // moved more than 1/2 millimeter + if (delta.magVec() >= 0.0005f) + { + if (mRootObject != mObject) + { + newpos = newpos - mRootObject->getPositionRegion(); + newpos = newpos * ~mRootObject->getRotationRegion(); + mObject->setPositionParent(newpos); + } + else + { + mObject->setPositionEdit(newpos); + } + + LLManip::rebuild(mObject) ; + + // for individually selected roots, we need to counter-translate all unselected children + if (mObject->isRootEdit()) + { + // only offset by parent's translation + mObject->resetChildrenPosition(LLVector3(-delta), TRUE) ; + } + + if(!btn_down) + { + LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); + } + + LLSelectMgr::getInstance()->updateSelectionCenter(); + } + } + else + { + // move failed, so we update the UI with the correct values + LLVector3 vec = mRootObject->getPositionRegion(); + mCtrlPosX->set(vec.mV[VX]); + mCtrlPosY->set(vec.mV[VY]); + mCtrlPosZ->set(vec.mV[VZ]); + } +} + +void LLPanelObject::sendSculpt() +{ + if (mObject.isNull()) + return; + + LLSculptParams sculpt_params; + + if (mCtrlSculptTexture) + sculpt_params.setSculptTexture(mCtrlSculptTexture->getImageAssetID()); + + U8 sculpt_type = 0; + + if (mCtrlSculptType) + sculpt_type |= mCtrlSculptType->getCurrentIndex(); + + bool enabled = sculpt_type != LL_SCULPT_TYPE_MESH; + + if (mCtrlSculptMirror) + { + mCtrlSculptMirror->setEnabled(enabled ? TRUE : FALSE); + } + if (mCtrlSculptInvert) + { + mCtrlSculptInvert->setEnabled(enabled ? TRUE : FALSE); + } + + if ((mCtrlSculptMirror) && (mCtrlSculptMirror->get())) + sculpt_type |= LL_SCULPT_FLAG_MIRROR; + + if ((mCtrlSculptInvert) && (mCtrlSculptInvert->get())) + sculpt_type |= LL_SCULPT_FLAG_INVERT; + + sculpt_params.setSculptType(sculpt_type); + mObject->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE); +} + +void LLPanelObject::refresh() +{ + getState(); + if (mObject.notNull() && mObject->isDead()) + { + mObject = NULL; + } + + if (mRootObject.notNull() && mRootObject->isDead()) + { + mRootObject = NULL; + } + + bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && + gAgent.getRegion() && + !gAgent.getRegion()->getCapability("GetMesh").empty(); + + F32 max_scale = get_default_max_prim_scale(LLPickInfo::isFlora(mObject)); + + getChild("Scale X")->setMaxValue(max_scale); + getChild("Scale Y")->setMaxValue(max_scale); + getChild("Scale Z")->setMaxValue(max_scale); + + BOOL found = mCtrlSculptType->itemExists("Mesh"); + if (enable_mesh && !found) + { + mCtrlSculptType->add("Mesh"); + } + else if (!enable_mesh && found) + { + mCtrlSculptType->remove("Mesh"); + } +} + + +void LLPanelObject::draw() +{ + const LLColor4 white( 1.0f, 1.0f, 1.0f, 1); + const LLColor4 red( 1.0f, 0.25f, 0.f, 1); + const LLColor4 green( 0.f, 1.0f, 0.f, 1); + const LLColor4 blue( 0.f, 0.5f, 1.0f, 1); + + // Tune the colors of the labels + LLTool* tool = LLToolMgr::getInstance()->getCurrentTool(); + + if (tool == LLToolCompTranslate::getInstance()) + { + mCtrlPosX ->setLabelColor(red); + mCtrlPosY ->setLabelColor(green); + mCtrlPosZ ->setLabelColor(blue); + + mCtrlScaleX ->setLabelColor(white); + mCtrlScaleY ->setLabelColor(white); + mCtrlScaleZ ->setLabelColor(white); + + mCtrlRotX ->setLabelColor(white); + mCtrlRotY ->setLabelColor(white); + mCtrlRotZ ->setLabelColor(white); + } + else if ( tool == LLToolCompScale::getInstance() ) + { + mCtrlPosX ->setLabelColor(white); + mCtrlPosY ->setLabelColor(white); + mCtrlPosZ ->setLabelColor(white); + + mCtrlScaleX ->setLabelColor(red); + mCtrlScaleY ->setLabelColor(green); + mCtrlScaleZ ->setLabelColor(blue); + + mCtrlRotX ->setLabelColor(white); + mCtrlRotY ->setLabelColor(white); + mCtrlRotZ ->setLabelColor(white); + } + else if ( tool == LLToolCompRotate::getInstance() ) + { + mCtrlPosX ->setLabelColor(white); + mCtrlPosY ->setLabelColor(white); + mCtrlPosZ ->setLabelColor(white); + + mCtrlScaleX ->setLabelColor(white); + mCtrlScaleY ->setLabelColor(white); + mCtrlScaleZ ->setLabelColor(white); + + mCtrlRotX ->setLabelColor(red); + mCtrlRotY ->setLabelColor(green); + mCtrlRotZ ->setLabelColor(blue); + } + else + { + mCtrlPosX ->setLabelColor(white); + mCtrlPosY ->setLabelColor(white); + mCtrlPosZ ->setLabelColor(white); + + mCtrlScaleX ->setLabelColor(white); + mCtrlScaleY ->setLabelColor(white); + mCtrlScaleZ ->setLabelColor(white); + + mCtrlRotX ->setLabelColor(white); + mCtrlRotY ->setLabelColor(white); + mCtrlRotZ ->setLabelColor(white); + } + + LLPanel::draw(); +} + +// virtual +void LLPanelObject::clearCtrls() +{ + LLPanel::clearCtrls(); + + mCheckLock ->set(FALSE); + mCheckLock ->setEnabled( FALSE ); + mCheckPhysics ->set(FALSE); + mCheckPhysics ->setEnabled( FALSE ); + mCheckTemporary ->set(FALSE); + mCheckTemporary ->setEnabled( FALSE ); + mCheckPhantom ->set(FALSE); + mCheckPhantom ->setEnabled( FALSE ); + +#if 0 // 1.9.2 + mCheckCastShadows->set(FALSE); + mCheckCastShadows->setEnabled( FALSE ); +#endif + // Disable text labels + mLabelPosition ->setEnabled( FALSE ); + mLabelSize ->setEnabled( FALSE ); + mLabelRotation ->setEnabled( FALSE ); + mLabelCut ->setEnabled( FALSE ); + mLabelHollow ->setEnabled( FALSE ); + mLabelHoleType ->setEnabled( FALSE ); + mLabelTwist ->setEnabled( FALSE ); + mLabelSkew ->setEnabled( FALSE ); + mLabelShear ->setEnabled( FALSE ); + mLabelTaper ->setEnabled( FALSE ); + mLabelRadiusOffset->setEnabled( FALSE ); + mLabelRevolutions->setEnabled( FALSE ); + + getChildView("select_single")->setVisible( FALSE); + getChildView("edit_object")->setVisible( TRUE); + getChildView("edit_object")->setEnabled(FALSE); + + getChildView("scale_hole")->setEnabled(FALSE); + getChildView("scale_taper")->setEnabled(FALSE); + getChildView("advanced_cut")->setEnabled(FALSE); + getChildView("advanced_dimple")->setEnabled(FALSE); + getChildView("advanced_slice")->setVisible( FALSE); +} + +// +// Static functions +// + +// static +void LLPanelObject::onCommitLock(LLUICtrl *ctrl, void *data) +{ + // Checkbox will have toggled itself + LLPanelObject *self = (LLPanelObject *)data; + + if(self->mRootObject.isNull()) return; + + BOOL new_state = self->mCheckLock->get(); + + LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, !new_state, PERM_MOVE | PERM_MODIFY); +} + +// static +void LLPanelObject::onCommitPosition( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ; + self->sendPosition(btn_down); +} + +// static +void LLPanelObject::onCommitScale( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ; + self->sendScale(btn_down); +} + +// static +void LLPanelObject::onCommitRotation( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ; + self->sendRotation(btn_down); +} + +// static +void LLPanelObject::onCommitPhysics( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + self->sendIsPhysical(); +} + +// static +void LLPanelObject::onCommitTemporary( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + self->sendIsTemporary(); +} + +// static +void LLPanelObject::onCommitPhantom( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + self->sendIsPhantom(); +} + +// static +void LLPanelObject::onCommitCastShadows( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + self->sendCastShadows(); +} + + +void LLPanelObject::onSelectSculpt(const LLSD& data) +{ + LLTextureCtrl* mTextureCtrl = getChild("sculpt texture control"); + + if (mTextureCtrl) + { + mSculptTextureRevert = mTextureCtrl->getImageAssetID(); + } + + sendSculpt(); +} + + +void LLPanelObject::onCommitSculpt( const LLSD& data ) +{ + sendSculpt(); +} + +BOOL LLPanelObject::onDropSculpt(LLInventoryItem* item) +{ + LLTextureCtrl* mTextureCtrl = getChild("sculpt texture control"); + + if (mTextureCtrl) + { + LLUUID asset = item->getAssetUUID(); + + mTextureCtrl->setImageAssetID(asset); + mSculptTextureRevert = asset; + } + + return TRUE; +} + + +void LLPanelObject::onCancelSculpt(const LLSD& data) +{ + LLTextureCtrl* mTextureCtrl = getChild("sculpt texture control"); + if(!mTextureCtrl) + return; + + mTextureCtrl->setImageAssetID(mSculptTextureRevert); + + sendSculpt(); +} + +// static +void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + + self->sendSculpt(); +} diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 86b56df556..fdd1199b78 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -5376,10 +5376,10 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) { // notification was specified using the new mechanism, so we can just handle it here std::string notificationID; - msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); - if (!LLNotifications::getInstance()->templateExists(notificationID)) - { - return false; + msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); + if (!LLNotifications::getInstance()->templateExists(notificationID)) + { + return false; } std::string llsdRaw; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 929f3ad188..e7878d8adf 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -1,5712 +1,5712 @@ -/** - * @file llviewerobject.cpp - * @brief Base class for viewer objects - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llviewerobject.h" - -#include "llaudioengine.h" -#include "imageids.h" -#include "indra_constants.h" -#include "llmath.h" -#include "llflexibleobject.h" -#include "llviewercontrol.h" -#include "lldatapacker.h" -#include "llfasttimer.h" -#include "llfloaterreg.h" -#include "llfontgl.h" -#include "llframetimer.h" -#include "llinventory.h" -#include "llinventorydefines.h" -#include "llmaterialtable.h" -#include "llmutelist.h" -#include "llnamevalue.h" -#include "llprimitive.h" -#include "llquantize.h" -#include "llregionhandle.h" -#include "llsdserialize.h" -#include "lltree_common.h" -#include "llxfermanager.h" -#include "message.h" -#include "object_flags.h" -#include "timing.h" - -#include "llaudiosourcevo.h" -#include "llagent.h" -#include "llagentcamera.h" -#include "llbbox.h" -#include "llbox.h" -#include "llcylinder.h" -#include "lldrawable.h" -#include "llface.h" -#include "llfloaterproperties.h" -#include "llfloatertools.h" -#include "llfollowcam.h" -#include "llhudtext.h" -#include "llselectmgr.h" -#include "llrendersphere.h" -#include "lltooldraganddrop.h" -#include "llviewercamera.h" -#include "llviewertexturelist.h" -#include "llviewerinventory.h" -#include "llviewerobjectlist.h" -#include "llviewerparceloverlay.h" -#include "llviewerpartsource.h" -#include "llviewerregion.h" -#include "llviewerstats.h" -#include "llviewertextureanim.h" -#include "llviewerwindow.h" // For getSpinAxis -#include "llvoavatar.h" -#include "llvoavatarself.h" -#include "llvoclouds.h" -#include "llvograss.h" -#include "llvoground.h" -#include "llvolume.h" -#include "llvolumemessage.h" -#include "llvopartgroup.h" -#include "llvosky.h" -#include "llvosurfacepatch.h" -#include "llvotextbubble.h" -#include "llvotree.h" -#include "llvovolume.h" -#include "llvowater.h" -#include "llworld.h" -#include "llui.h" -#include "pipeline.h" -#include "llviewernetwork.h" -#include "llvowlsky.h" -#include "llmanip.h" -#include "lltrans.h" -#include "llsdutil.h" -#include "llmediaentry.h" -#include "llaccountingquota.h" - -//#define DEBUG_UPDATE_TYPE - -BOOL LLViewerObject::sVelocityInterpolate = TRUE; -BOOL LLViewerObject::sPingInterpolate = TRUE; - -U32 LLViewerObject::sNumZombieObjects = 0; -S32 LLViewerObject::sNumObjects = 0; -BOOL LLViewerObject::sMapDebug = TRUE; -LLColor4 LLViewerObject::sEditSelectColor( 1.0f, 1.f, 0.f, 0.3f); // Edit OK -LLColor4 LLViewerObject::sNoEditSelectColor( 1.0f, 0.f, 0.f, 0.3f); // Can't edit -S32 LLViewerObject::sAxisArrowLength(50); -BOOL LLViewerObject::sPulseEnabled(FALSE); -BOOL LLViewerObject::sUseSharedDrawables(FALSE); // TRUE - -// sMaxUpdateInterpolationTime must be greater than sPhaseOutUpdateInterpolationTime -F64 LLViewerObject::sMaxUpdateInterpolationTime = 3.0; // For motion interpolation: after X seconds with no updates, don't predict object motion -F64 LLViewerObject::sPhaseOutUpdateInterpolationTime = 2.0; // For motion interpolation: after Y seconds with no updates, taper off motion prediction - - -static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object"); - -// static -LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) -{ - LLViewerObject *res = NULL; - LLFastTimer t1(FTM_CREATE_OBJECT); - - switch (pcode) - { - case LL_PCODE_VOLUME: - res = new LLVOVolume(id, pcode, regionp); break; - case LL_PCODE_LEGACY_AVATAR: - { - if (id == gAgentID) - { - if (!gAgentAvatarp) - { - gAgentAvatarp = new LLVOAvatarSelf(id, pcode, regionp); - } - else - { - gAgentAvatarp->updateRegion(regionp); - } - res = gAgentAvatarp; - } - else - { - res = new LLVOAvatar(id, pcode, regionp); - } - static_cast(res)->initInstance(); - break; - } - case LL_PCODE_LEGACY_GRASS: - res = new LLVOGrass(id, pcode, regionp); break; - case LL_PCODE_LEGACY_PART_SYS: -// llwarns << "Creating old part sys!" << llendl; -// res = new LLVOPart(id, pcode, regionp); break; - res = NULL; break; - case LL_PCODE_LEGACY_TREE: - res = new LLVOTree(id, pcode, regionp); break; - case LL_PCODE_TREE_NEW: -// llwarns << "Creating new tree!" << llendl; -// res = new LLVOTree(id, pcode, regionp); break; - res = NULL; break; - case LL_PCODE_LEGACY_TEXT_BUBBLE: - res = new LLVOTextBubble(id, pcode, regionp); break; - case LL_VO_CLOUDS: - res = new LLVOClouds(id, pcode, regionp); break; - case LL_VO_SURFACE_PATCH: - res = new LLVOSurfacePatch(id, pcode, regionp); break; - case LL_VO_SKY: - res = new LLVOSky(id, pcode, regionp); break; - case LL_VO_VOID_WATER: - res = new LLVOVoidWater(id, pcode, regionp); break; - case LL_VO_WATER: - res = new LLVOWater(id, pcode, regionp); break; - case LL_VO_GROUND: - res = new LLVOGround(id, pcode, regionp); break; - case LL_VO_PART_GROUP: - res = new LLVOPartGroup(id, pcode, regionp); break; - case LL_VO_HUD_PART_GROUP: - res = new LLVOHUDPartGroup(id, pcode, regionp); break; - case LL_VO_WL_SKY: - res = new LLVOWLSky(id, pcode, regionp); break; - default: - llwarns << "Unknown object pcode " << (S32)pcode << llendl; - res = NULL; break; - } - return res; -} - -LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global) -: LLPrimitive(), - mChildList(), - mID(id), - mLocalID(0), - mTotalCRC(0), - mTEImages(NULL), - mGLName(0), - mbCanSelect(TRUE), - mFlags(0), - mPhysicsShapeType(0), - mPhysicsGravity(0), - mPhysicsFriction(0), - mPhysicsDensity(0), - mPhysicsRestitution(0), - mDrawable(), - mCreateSelected(FALSE), - mRenderMedia(FALSE), - mBestUpdatePrecision(0), - mText(), - mLastInterpUpdateSecs(0.f), - mLastMessageUpdateSecs(0.f), - mLatestRecvPacketID(0), - mData(NULL), - mAudioSourcep(NULL), - mAudioGain(1.f), - mAppAngle(0.f), - mPixelArea(1024.f), - mInventory(NULL), - mInventorySerialNum(0), - mRegionp( regionp ), - mInventoryPending(FALSE), - mInventoryDirty(FALSE), - mDead(FALSE), - mOrphaned(FALSE), - mUserSelected(FALSE), - mOnActiveList(FALSE), - mOnMap(FALSE), - mStatic(FALSE), - mNumFaces(0), - mTimeDilation(1.f), - mRotTime(0.f), - mJointInfo(NULL), - mState(0), - mMedia(NULL), - mClickAction(0), - mObjectCost(0), - mLinksetCost(0), - mPhysicsCost(0), - mLinksetPhysicsCost(0.f), - mCostStale(true), - mPhysicsShapeUnknown(true), - mAttachmentItemID(LLUUID::null), - mLastUpdateType(OUT_UNKNOWN), - mLastUpdateCached(FALSE) -{ - if (!is_global) - { - llassert(mRegionp); - } - - LLPrimitive::init_primitive(pcode); - - // CP: added 12/2/2005 - this was being initialised to 0, not the current frame time - mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds(); - - mPositionRegion = LLVector3(0.f, 0.f, 0.f); - - if (!is_global && mRegionp) - { - mPositionAgent = mRegionp->getOriginAgent(); - } - - LLViewerObject::sNumObjects++; -} - -LLViewerObject::~LLViewerObject() -{ - deleteTEImages(); - - if(mInventory) - { - mInventory->clear(); // will deref and delete entries - delete mInventory; - mInventory = NULL; - } - - if (mJointInfo) - { - delete mJointInfo; - mJointInfo = NULL; - } - - if (mPartSourcep) - { - mPartSourcep->setDead(); - mPartSourcep = NULL; - } - - // Delete memory associated with extra parameters. - std::map::iterator iter; - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) - { - if(iter->second != NULL) - { - delete iter->second->data; - delete iter->second; - } - } - mExtraParameterList.clear(); - - for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ; - mNameValuePairs.clear(); - - delete[] mData; - mData = NULL; - - delete mMedia; - mMedia = NULL; - - sNumObjects--; - sNumZombieObjects--; - llassert(mChildList.size() == 0); - - clearInventoryListeners(); -} - -void LLViewerObject::deleteTEImages() -{ - delete[] mTEImages; - mTEImages = NULL; -} - -void LLViewerObject::markDead() -{ - if (!mDead) - { - //llinfos << "Marking self " << mLocalID << " as dead." << llendl; - - // Root object of this hierarchy unlinks itself. - if (getParent()) - { - ((LLViewerObject *)getParent())->removeChild(this); - // go ahead and delete any jointinfo's that we find - delete mJointInfo; - mJointInfo = NULL; - } - - // Mark itself as dead - mDead = TRUE; - gObjectList.cleanupReferences(this); - - LLViewerObject *childp; - while (mChildList.size() > 0) - { - childp = mChildList.back(); - if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR) - { - //llinfos << "Marking child " << childp->getLocalID() << " as dead." << llendl; - childp->setParent(NULL); // LLViewerObject::markDead 1 - childp->markDead(); - } - else - { - // make sure avatar is no longer parented, - // so we can properly set it's position - childp->setDrawableParent(NULL); - ((LLVOAvatar*)childp)->getOffObject(); - childp->setParent(NULL); // LLViewerObject::markDead 2 - } - mChildList.pop_back(); - } - - if (mDrawable.notNull()) - { - // Drawables are reference counted, mark as dead, then nuke the pointer. - mDrawable->markDead(); - mDrawable = NULL; - } - - if (mText) - { - mText->markDead(); - mText = NULL; - } - - if (mIcon) - { - mIcon->markDead(); - mIcon = NULL; - } - - if (mPartSourcep) - { - mPartSourcep->setDead(); - mPartSourcep = NULL; - } - - if (mAudioSourcep) - { - // Do some cleanup - if (gAudiop) - { - gAudiop->cleanupAudioSource(mAudioSourcep); - } - mAudioSourcep = NULL; - } - - if (flagAnimSource()) - { - if (isAgentAvatarValid()) - { - // stop motions associated with this object - gAgentAvatarp->stopMotionFromSource(mID); - } - } - - if (flagCameraSource()) - { - LLFollowCamMgr::removeFollowCamParams(mID); - } - - sNumZombieObjects++; - } -} - -void LLViewerObject::dump() const -{ - llinfos << "Type: " << pCodeToString(mPrimitiveCode) << llendl; - llinfos << "Drawable: " << (LLDrawable *)mDrawable << llendl; - llinfos << "Update Age: " << LLFrameTimer::getElapsedSeconds() - mLastMessageUpdateSecs << llendl; - - llinfos << "Parent: " << getParent() << llendl; - llinfos << "ID: " << mID << llendl; - llinfos << "LocalID: " << mLocalID << llendl; - llinfos << "PositionRegion: " << getPositionRegion() << llendl; - llinfos << "PositionAgent: " << getPositionAgent() << llendl; - llinfos << "PositionGlobal: " << getPositionGlobal() << llendl; - llinfos << "Velocity: " << getVelocity() << llendl; - if (mDrawable.notNull() && mDrawable->getNumFaces()) - { - LLFacePool *poolp = mDrawable->getFace(0)->getPool(); - if (poolp) - { - llinfos << "Pool: " << poolp << llendl; - llinfos << "Pool reference count: " << poolp->mReferences.size() << llendl; - } - } - //llinfos << "BoxTree Min: " << mDrawable->getBox()->getMin() << llendl; - //llinfos << "BoxTree Max: " << mDrawable->getBox()->getMin() << llendl; - /* - llinfos << "Velocity: " << getVelocity() << llendl; - llinfos << "AnyOwner: " << permAnyOwner() << " YouOwner: " << permYouOwner() << " Edit: " << mPermEdit << llendl; - llinfos << "UsePhysics: " << usePhysics() << " CanSelect " << mbCanSelect << " UserSelected " << mUserSelected << llendl; - llinfos << "AppAngle: " << mAppAngle << llendl; - llinfos << "PixelArea: " << mPixelArea << llendl; - - char buffer[1000]; - char *key; - for (key = mNameValuePairs.getFirstKey(); key; key = mNameValuePairs.getNextKey() ) - { - mNameValuePairs[key]->printNameValue(buffer); - llinfos << buffer << llendl; - } - for (child_list_t::iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* child = *iter; - llinfos << " child " << child->getID() << llendl; - } - */ -} - -void LLViewerObject::printNameValuePairs() const -{ - for (name_value_map_t::const_iterator iter = mNameValuePairs.begin(); - iter != mNameValuePairs.end(); iter++) - { - LLNameValue* nv = iter->second; - llinfos << nv->printNameValue() << llendl; - } -} - -void LLViewerObject::initVOClasses() -{ - // Initialized shared class stuff first. - LLVOAvatar::initClass(); - LLVOTree::initClass(); - llinfos << "Viewer Object size: " << sizeof(LLViewerObject) << llendl; - LLVOGrass::initClass(); - LLVOWater::initClass(); - LLVOVolume::initClass(); -} - -void LLViewerObject::cleanupVOClasses() -{ - LLVOGrass::cleanupClass(); - LLVOWater::cleanupClass(); - LLVOTree::cleanupClass(); - LLVOAvatar::cleanupClass(); - LLVOVolume::cleanupClass(); -} - -// Replaces all name value pairs with data from \n delimited list -// Does not update server -void LLViewerObject::setNameValueList(const std::string& name_value_list) -{ - // Clear out the old - for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ; - mNameValuePairs.clear(); - - // Bring in the new - std::string::size_type length = name_value_list.length(); - std::string::size_type start = 0; - while (start < length) - { - std::string::size_type end = name_value_list.find_first_of("\n", start); - if (end == std::string::npos) end = length; - if (end > start) - { - std::string tok = name_value_list.substr(start, end - start); - addNVPair(tok); - } - start = end+1; - } -} - - -// This method returns true if the object is over land owned by the -// agent. -bool LLViewerObject::isReturnable() -{ - if (isAttachment()) - { - return false; - } - std::vector boxes; - boxes.push_back(LLBBox(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f).getAxisAligned()); - for (child_list_t::iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* child = *iter; - boxes.push_back(LLBBox(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f).getAxisAligned()); - } - - return mRegionp - && mRegionp->objectIsReturnable(getPositionRegion(), boxes); -} - -BOOL LLViewerObject::setParent(LLViewerObject* parent) -{ - if(mParent != parent) - { - LLViewerObject* old_parent = (LLViewerObject*)mParent ; - BOOL ret = LLPrimitive::setParent(parent); - if(ret && old_parent && parent) - { - old_parent->removeChild(this) ; - } - return ret ; - } - - return FALSE ; -} - -void LLViewerObject::addChild(LLViewerObject *childp) -{ - for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) - { - if (*i == childp) - { //already has child - return; - } - } - - if (!isAvatar()) - { - // propagate selection properties - childp->mbCanSelect = mbCanSelect; - } - - if(childp->setParent(this)) - { - mChildList.push_back(childp); - } -} - -void LLViewerObject::removeChild(LLViewerObject *childp) -{ - for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) - { - if (*i == childp) - { - if (!childp->isAvatar() && mDrawable.notNull() && mDrawable->isActive() && childp->mDrawable.notNull() && !isAvatar()) - { - gPipeline.markRebuild(childp->mDrawable, LLDrawable::REBUILD_VOLUME); - } - - mChildList.erase(i); - - if(childp->getParent() == this) - { - childp->setParent(NULL); - } - break; - } - } - - if (childp->isSelected()) - { - LLSelectMgr::getInstance()->deselectObjectAndFamily(childp); - BOOL add_to_end = TRUE; - LLSelectMgr::getInstance()->selectObjectAndFamily(childp, add_to_end); - } -} - -void LLViewerObject::addThisAndAllChildren(std::vector& objects) -{ - objects.push_back(this); - for (child_list_t::iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* child = *iter; - if (!child->isAvatar()) - { - child->addThisAndAllChildren(objects); - } - } -} - -void LLViewerObject::addThisAndNonJointChildren(std::vector& objects) -{ - objects.push_back(this); - // don't add any attachments when temporarily selecting avatar - if (isAvatar()) - { - return; - } - for (child_list_t::iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* child = *iter; - if ( (!child->isAvatar()) && (!child->isJointChild())) - { - child->addThisAndNonJointChildren(objects); - } - } -} - -BOOL LLViewerObject::isChild(LLViewerObject *childp) const -{ - for (child_list_t::const_iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* testchild = *iter; - if (testchild == childp) - return TRUE; - } - return FALSE; -} - - -// returns TRUE if at least one avatar is sitting on this object -BOOL LLViewerObject::isSeat() const -{ - for (child_list_t::const_iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* child = *iter; - if (child->isAvatar()) - { - return TRUE; - } - } - return FALSE; - -} - -BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp) -{ - if (mDrawable.isNull()) - { - return FALSE; - } - - BOOL ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL); - if(!ret) - { - return FALSE ; - } - LLDrawable* old_parent = mDrawable->mParent; - mDrawable->mParent = parentp; - - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); - if( (old_parent != parentp && old_parent) - || (parentp && parentp->isActive())) - { - // *TODO we should not be relying on setDrawable parent to call markMoved - gPipeline.markMoved(mDrawable, FALSE); - } - else if (!mDrawable->isAvatar()) - { - mDrawable->updateXform(TRUE); - /*if (!mDrawable->getSpatialGroup()) - { - mDrawable->movePartition(); - }*/ - } - - return ret; -} - -// Show or hide particles, icon and HUD -void LLViewerObject::hideExtraDisplayItems( BOOL hidden ) -{ - if( mPartSourcep.notNull() ) - { - LLViewerPartSourceScript *partSourceScript = mPartSourcep.get(); - partSourceScript->setSuspended( hidden ); - } - - if( mText.notNull() ) - { - LLHUDText *hudText = mText.get(); - hudText->setHidden( hidden ); - } - - if( mIcon.notNull() ) - { - LLHUDIcon *hudIcon = mIcon.get(); - hudIcon->setHidden( hidden ); - } -} - -U32 LLViewerObject::checkMediaURL(const std::string &media_url) -{ - U32 retval = (U32)0x0; - if (!mMedia && !media_url.empty()) - { - retval |= MEDIA_URL_ADDED; - mMedia = new LLViewerObjectMedia; - mMedia->mMediaURL = media_url; - mMedia->mMediaType = LLViewerObject::MEDIA_SET; - mMedia->mPassedWhitelist = FALSE; - } - else if (mMedia) - { - if (media_url.empty()) - { - retval |= MEDIA_URL_REMOVED; - delete mMedia; - mMedia = NULL; - } - else if (mMedia->mMediaURL != media_url) // <-- This is an optimization. If they are equal don't bother with below's test. - { - /*if (! (LLTextureEntry::getAgentIDFromMediaVersionString(media_url) == gAgent.getID() && - LLTextureEntry::getVersionFromMediaVersionString(media_url) == - LLTextureEntry::getVersionFromMediaVersionString(mMedia->mMediaURL) + 1)) - */ - { - // If the media URL is different and WE were not the one who - // changed it, mark dirty. - retval |= MEDIA_URL_UPDATED; - } - mMedia->mMediaURL = media_url; - mMedia->mPassedWhitelist = FALSE; - } - } - return retval; -} - -U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, - void **user_data, - U32 block_num, - const EObjectUpdateType update_type, - LLDataPacker *dp) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - U32 retval = 0x0; - - // Coordinates of objects on simulators are region-local. - U64 region_handle; - mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); - - { - LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); - if(regionp != mRegionp && regionp && mRegionp)//region cross - { - //this is the redundant position and region update, but it is necessary in case the viewer misses the following - //position and region update messages from sim. - //this redundant update should not cause any problems. - LLVector3 delta_pos = mRegionp->getOriginAgent() - regionp->getOriginAgent(); - setPositionParent(getPosition() + delta_pos); //update to the new region position immediately. - setRegion(regionp) ; //change the region. - } - else - { - mRegionp = regionp ; - } - } - - if (!mRegionp) - { - U32 x, y; - from_region_handle(region_handle, &x, &y); - - llerrs << "Object has invalid region " << x << ":" << y << "!" << llendl; - return retval; - } - - U16 time_dilation16; - mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16); - F32 time_dilation = ((F32) time_dilation16) / 65535.f; - mTimeDilation = time_dilation; - mRegionp->setTimeDilation(time_dilation); - - // this will be used to determine if we've really changed position - // Use getPosition, not getPositionRegion, since this is what we're comparing directly against. - LLVector3 test_pos_parent = getPosition(); - - U8 data[60+16]; // This needs to match the largest size below. -#ifdef LL_BIG_ENDIAN - U16 valswizzle[4]; -#endif - U16 *val; - const F32 size = LLWorld::getInstance()->getRegionWidthInMeters(); - const F32 MAX_HEIGHT = LLWorld::getInstance()->getRegionMaxHeight(); - const F32 MIN_HEIGHT = LLWorld::getInstance()->getRegionMinHeight(); - S32 length; - S32 count; - S32 this_update_precision = 32; // in bits - - // Temporaries, because we need to compare w/ previous to set dirty flags... - LLVector3 new_pos_parent; - LLVector3 new_vel; - LLVector3 new_acc; - LLVector3 new_angv; - LLVector3 old_angv = getAngularVelocity(); - LLQuaternion new_rot; - LLVector3 new_scale = getScale(); - - U32 parent_id = 0; - U8 material = 0; - U8 click_action = 0; - U32 crc = 0; - - bool old_special_hover_cursor = specialHoverCursor(); - - LLViewerObject *cur_parentp = (LLViewerObject *)getParent(); - - if (cur_parentp) - { - parent_id = cur_parentp->mLocalID; - } - - if (!dp) - { - switch(update_type) - { - case OUT_FULL: - { -#ifdef DEBUG_UPDATE_TYPE - llinfos << "Full:" << getID() << llendl; -#endif - //clear cost and linkset cost - mCostStale = true; - if (isSelected()) - { - gFloaterTools->dirty(); - } - - LLUUID audio_uuid; - LLUUID owner_id; // only valid if audio_uuid or particle system is not null - F32 gain; - U8 sound_flags; - - mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_CRC, crc, block_num); - mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_ParentID, parent_id, block_num); - mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_Sound, audio_uuid, block_num ); - // HACK: Owner id only valid if non-null sound id or particle system - mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, block_num ); - mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Gain, gain, block_num ); - mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Flags, sound_flags, block_num ); - mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Material, material, block_num ); - mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_ClickAction, click_action, block_num); - mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_Scale, new_scale, block_num ); - length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num); - - mTotalCRC = crc; - - // Owner ID used for sound muting or particle system muting - setAttachedSound(audio_uuid, owner_id, gain, sound_flags); - - U8 old_material = getMaterial(); - if (old_material != material) - { - setMaterial(material); - if (mDrawable.notNull()) - { - gPipeline.markMoved(mDrawable, FALSE); // undamped - } - } - setClickAction(click_action); - - count = 0; - LLVector4 collision_plane; - - switch(length) - { - case (60 + 16): - // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); - ((LLVOAvatar*)this)->setFootPlane(collision_plane); - count += sizeof(LLVector4); - // fall through - case 60: - this_update_precision = 32; - // this is a terse update - // pos - htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // vel - htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // acc - htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // theta - { - LLVector3 vec; - htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - new_rot.unpackFromVector3(vec); - } - count += sizeof(LLVector3); - // omega - htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - if (new_angv.isExactlyZero()) - { - // reset rotation time - resetRot(); - } - setAngularVelocity(new_angv); -#if LL_DARWIN - if (length == 76) - { - setAngularVelocity(LLVector3::zero); - } -#endif - break; - case(32 + 16): - // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); - ((LLVOAvatar*)this)->setFootPlane(collision_plane); - count += sizeof(LLVector4); - // fall through - case 32: - this_update_precision = 16; - test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); - - // This is a terse 16 update, so treat data as an array of U16's. -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - setVelocity(LLVector3(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size))); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - setAcceleration(LLVector3(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size))); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 4); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*4; - new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f); - new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f); - new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f); - new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - new_angv.setVec(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size)); - if (new_angv.isExactlyZero()) - { - // reset rotation time - resetRot(); - } - setAngularVelocity(new_angv); - break; - - case 16: - this_update_precision = 8; - test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); - // this is a terse 8 update - new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT); - - setVelocity(U8_to_F32(data[3], -size, size), - U8_to_F32(data[4], -size, size), - U8_to_F32(data[5], -size, size) ); - - setAcceleration(U8_to_F32(data[6], -size, size), - U8_to_F32(data[7], -size, size), - U8_to_F32(data[8], -size, size) ); - - new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f); - new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f); - new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f); - new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f); - - new_angv.setVec(U8_to_F32(data[13], -size, size), - U8_to_F32(data[14], -size, size), - U8_to_F32(data[15], -size, size) ); - if (new_angv.isExactlyZero()) - { - // reset rotation time - resetRot(); - } - setAngularVelocity(new_angv); - break; - } - - //////////////////////////////////////////////////// - // - // Here we handle data specific to the full message. - // - - U32 flags; - mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); - // clear all but local flags - mFlags &= FLAGS_LOCAL; - mFlags |= flags; - - U8 state; - mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num ); - mState = state; - - // ...new objects that should come in selected need to be added to the selected list - mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); - - // Set all name value pairs - S32 nv_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_NameValue); - if (nv_size > 0) - { - std::string name_value_list; - mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_NameValue, name_value_list, block_num); - setNameValueList(name_value_list); - } - - // Clear out any existing generic data - if (mData) - { - delete [] mData; - } - - // Check for appended generic data - S32 data_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Data); - if (data_size <= 0) - { - mData = NULL; - } - else - { - // ...has generic data - mData = new U8[data_size]; - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, mData, data_size, block_num); - } - - S32 text_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Text); - if (text_size > 1) - { - // Setup object text - if (!mText) - { - mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); - mText->setFont(LLFontGL::getFontSansSerif()); - mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); - mText->setMaxLines(-1); - mText->setSourceObject(this); - mText->setOnHUDAttachment(isHUDAttachment()); - } - - std::string temp_string; - mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_Text, temp_string, block_num ); - - LLColor4U coloru; - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextColor, coloru.mV, 4, block_num); - - // alpha was flipped so that it zero encoded better - coloru.mV[3] = 255 - coloru.mV[3]; - mText->setColor(LLColor4(coloru)); - mText->setString(temp_string); - - if (mDrawable.notNull()) - { - setChanged(MOVED | SILHOUETTE); - gPipeline.markMoved(mDrawable, FALSE); // undamped - } - } - else if (mText.notNull()) - { - mText->markDead(); - mText = NULL; - } - - std::string media_url; - mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_MediaURL, media_url, block_num); - retval |= checkMediaURL(media_url); - - // - // Unpack particle system data - // - unpackParticleSource(block_num, owner_id); - - // Mark all extra parameters not used - std::map::iterator iter; - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) - { - iter->second->in_use = FALSE; - } - - // Unpack extra parameters - S32 size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ExtraParams); - if (size > 0) - { - U8 *buffer = new U8[size]; - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ExtraParams, buffer, size, block_num); - LLDataPackerBinaryBuffer dp(buffer, size); - - U8 num_parameters; - dp.unpackU8(num_parameters, "num_params"); - U8 param_block[MAX_OBJECT_PARAMS_SIZE]; - for (U8 param=0; paramsecond->in_use) - { - // Send an update message in case it was formerly in use - parameterChanged(iter->first, iter->second->data, FALSE, false); - } - } - - U8 joint_type = 0; - mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_JointType, joint_type, block_num); - if (joint_type) - { - // create new joint info - if (!mJointInfo) - { - mJointInfo = new LLVOJointInfo; - } - mJointInfo->mJointType = (EHavokJointType) joint_type; - mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_JointPivot, mJointInfo->mPivot, block_num); - mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_JointAxisOrAnchor, mJointInfo->mAxisOrAnchor, block_num); - } - else if (mJointInfo) - { - // this joint info is no longer needed - delete mJointInfo; - mJointInfo = NULL; - } - - break; - } - - case OUT_TERSE_IMPROVED: - { -#ifdef DEBUG_UPDATE_TYPE - llinfos << "TI:" << getID() << llendl; -#endif - length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num); - count = 0; - LLVector4 collision_plane; - - switch(length) - { - case(60 + 16): - // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); - ((LLVOAvatar*)this)->setFootPlane(collision_plane); - count += sizeof(LLVector4); - // fall through - case 60: - // this is a terse 32 update - // pos - this_update_precision = 32; - htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // vel - htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // acc - htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // theta - { - LLVector3 vec; - htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - new_rot.unpackFromVector3(vec); - } - count += sizeof(LLVector3); - // omega - htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - if (new_angv.isExactlyZero()) - { - // reset rotation time - resetRot(); - } - setAngularVelocity(new_angv); -#if LL_DARWIN - if (length == 76) - { - setAngularVelocity(LLVector3::zero); - } -#endif - break; - case(32 + 16): - // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); - ((LLVOAvatar*)this)->setFootPlane(collision_plane); - count += sizeof(LLVector4); - // fall through - case 32: - // this is a terse 16 update - this_update_precision = 16; - test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - setVelocity(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size)); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - setAcceleration(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size)); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*4; - new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f); - new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f); - new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f); - new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - setAngularVelocity( U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size)); - break; - - case 16: - // this is a terse 8 update - this_update_precision = 8; - test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); - new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT); - - setVelocity(U8_to_F32(data[3], -size, size), - U8_to_F32(data[4], -size, size), - U8_to_F32(data[5], -size, size) ); - - setAcceleration(U8_to_F32(data[6], -size, size), - U8_to_F32(data[7], -size, size), - U8_to_F32(data[8], -size, size) ); - - new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f); - new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f); - new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f); - new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f); - - setAngularVelocity( U8_to_F32(data[13], -size, size), - U8_to_F32(data[14], -size, size), - U8_to_F32(data[15], -size, size) ); - break; - } - - U8 state; - mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num ); - mState = state; - break; - } - - default: - break; - - } - } - else - { - // handle the compressed case - LLUUID sound_uuid; - LLUUID owner_id; - F32 gain = 0; - U8 sound_flags = 0; - F32 cutoff = 0; - - U16 val[4]; - - U8 state; - - dp->unpackU8(state, "State"); - mState = state; - - switch(update_type) - { - case OUT_TERSE_IMPROVED: - { -#ifdef DEBUG_UPDATE_TYPE - llinfos << "CompTI:" << getID() << llendl; -#endif - U8 value; - dp->unpackU8(value, "agent"); - if (value) - { - LLVector4 collision_plane; - dp->unpackVector4(collision_plane, "Plane"); - ((LLVOAvatar*)this)->setFootPlane(collision_plane); - } - test_pos_parent = getPosition(); - dp->unpackVector3(new_pos_parent, "Pos"); - dp->unpackU16(val[VX], "VelX"); - dp->unpackU16(val[VY], "VelY"); - dp->unpackU16(val[VZ], "VelZ"); - setVelocity(U16_to_F32(val[VX], -128.f, 128.f), - U16_to_F32(val[VY], -128.f, 128.f), - U16_to_F32(val[VZ], -128.f, 128.f)); - dp->unpackU16(val[VX], "AccX"); - dp->unpackU16(val[VY], "AccY"); - dp->unpackU16(val[VZ], "AccZ"); - setAcceleration(U16_to_F32(val[VX], -64.f, 64.f), - U16_to_F32(val[VY], -64.f, 64.f), - U16_to_F32(val[VZ], -64.f, 64.f)); - - dp->unpackU16(val[VX], "ThetaX"); - dp->unpackU16(val[VY], "ThetaY"); - dp->unpackU16(val[VZ], "ThetaZ"); - dp->unpackU16(val[VS], "ThetaS"); - new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f); - new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f); - new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f); - new_rot.mQ[VS] = U16_to_F32(val[VS], -1.f, 1.f); - dp->unpackU16(val[VX], "AccX"); - dp->unpackU16(val[VY], "AccY"); - dp->unpackU16(val[VZ], "AccZ"); - setAngularVelocity( U16_to_F32(val[VX], -64.f, 64.f), - U16_to_F32(val[VY], -64.f, 64.f), - U16_to_F32(val[VZ], -64.f, 64.f)); - } - break; - case OUT_FULL_COMPRESSED: - case OUT_FULL_CACHED: - { -#ifdef DEBUG_UPDATE_TYPE - llinfos << "CompFull:" << getID() << llendl; -#endif - mCostStale = true; - - if (isSelected()) - { - gFloaterTools->dirty(); - } - - dp->unpackU32(crc, "CRC"); - mTotalCRC = crc; - dp->unpackU8(material, "Material"); - U8 old_material = getMaterial(); - if (old_material != material) - { - setMaterial(material); - if (mDrawable.notNull()) - { - gPipeline.markMoved(mDrawable, FALSE); // undamped - } - } - dp->unpackU8(click_action, "ClickAction"); - setClickAction(click_action); - dp->unpackVector3(new_scale, "Scale"); - dp->unpackVector3(new_pos_parent, "Pos"); - LLVector3 vec; - dp->unpackVector3(vec, "Rot"); - new_rot.unpackFromVector3(vec); - setAcceleration(LLVector3::zero); - - U32 value; - dp->unpackU32(value, "SpecialCode"); - dp->setPassFlags(value); - dp->unpackUUID(owner_id, "Owner"); - - if (value & 0x80) - { - dp->unpackVector3(vec, "Omega"); - setAngularVelocity(vec); - } - - if (value & 0x20) - { - dp->unpackU32(parent_id, "ParentID"); - } - else - { - parent_id = 0; - } - - S32 sp_size; - U32 size; - if (value & 0x2) - { - sp_size = 1; - delete [] mData; - mData = new U8[1]; - dp->unpackU8(((U8*)mData)[0], "TreeData"); - } - else if (value & 0x1) - { - dp->unpackU32(size, "ScratchPadSize"); - delete [] mData; - mData = new U8[size]; - dp->unpackBinaryData((U8 *)mData, sp_size, "PartData"); - } - else - { - mData = NULL; - } - - // Setup object text - if (!mText && (value & 0x4)) - { - mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); - mText->setFont(LLFontGL::getFontSansSerif()); - mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); - mText->setMaxLines(-1); // Set to match current agni behavior. - mText->setSourceObject(this); - mText->setOnHUDAttachment(isHUDAttachment()); - } - - if (value & 0x4) - { - std::string temp_string; - dp->unpackString(temp_string, "Text"); - LLColor4U coloru; - dp->unpackBinaryDataFixed(coloru.mV, 4, "Color"); - coloru.mV[3] = 255 - coloru.mV[3]; - mText->setColor(LLColor4(coloru)); - mText->setString(temp_string); - - setChanged(TEXTURE); - } - else if(mText.notNull()) - { - mText->markDead(); - mText = NULL; - } - - std::string media_url; - if (value & 0x200) - { - dp->unpackString(media_url, "MediaURL"); - } - retval |= checkMediaURL(media_url); - - // - // Unpack particle system data - // - if (value & 0x8) - { - unpackParticleSource(*dp, owner_id); - } - else - { - deleteParticleSource(); - } - - // Mark all extra parameters not used - std::map::iterator iter; - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) - { - iter->second->in_use = FALSE; - } - - // Unpack extra params - U8 num_parameters; - dp->unpackU8(num_parameters, "num_params"); - U8 param_block[MAX_OBJECT_PARAMS_SIZE]; - for (U8 param=0; paramunpackU16(param_type, "param_type"); - dp->unpackBinaryData(param_block, param_size, "param_data"); - //llinfos << "Param type: " << param_type << ", Size: " << param_size << llendl; - LLDataPackerBinaryBuffer dp2(param_block, param_size); - unpackParameterEntry(param_type, &dp2); - } - - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) - { - if (!iter->second->in_use) - { - // Send an update message in case it was formerly in use - parameterChanged(iter->first, iter->second->data, FALSE, false); - } - } - - if (value & 0x10) - { - dp->unpackUUID(sound_uuid, "SoundUUID"); - dp->unpackF32(gain, "SoundGain"); - dp->unpackU8(sound_flags, "SoundFlags"); - dp->unpackF32(cutoff, "SoundRadius"); - } - - if (value & 0x100) - { - std::string name_value_list; - dp->unpackString(name_value_list, "NV"); - - setNameValueList(name_value_list); - } - - mTotalCRC = crc; - - setAttachedSound(sound_uuid, owner_id, gain, sound_flags); - - // only get these flags on updates from sim, not cached ones - // Preload these five flags for every object. - // Finer shades require the object to be selected, and the selection manager - // stores the extended permission info. - U32 flags; - mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); - // keep local flags and overwrite remote-controlled flags - mFlags = (mFlags & FLAGS_LOCAL) | flags; - - // ...new objects that should come in selected need to be added to the selected list - mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); - } - break; - - default: - break; - } - } - - // - // Fix object parenting. - // - BOOL b_changed_status = FALSE; - - if (OUT_TERSE_IMPROVED != update_type) - { - // We only need to update parenting on full updates, terse updates - // don't send parenting information. - if (!cur_parentp) - { - if (parent_id == 0) - { - // No parent now, no parent in message -> do nothing - } - else - { - // No parent now, new parent in message -> attach to that parent if possible - LLUUID parent_uuid; - LLViewerObjectList::getUUIDFromLocal(parent_uuid, - parent_id, - mesgsys->getSenderIP(), - mesgsys->getSenderPort()); - - LLViewerObject *sent_parentp = gObjectList.findObject(parent_uuid); - - // - // Check to see if we have the corresponding viewer object for the parent. - // - if (sent_parentp && sent_parentp->getParent() == this) - { - // Try to recover if we attempt to attach a parent to its child - llwarns << "Attempt to attach a parent to it's child: " << this->getID() << " to " << sent_parentp->getID() << llendl; - this->removeChild(sent_parentp); - sent_parentp->setDrawableParent(NULL); - } - - if (sent_parentp && (sent_parentp != this) && !sent_parentp->isDead()) - { - // - // We have a viewer object for the parent, and it's not dead. - // Do the actual reparenting here. - // - - // new parent is valid - b_changed_status = TRUE; - // ...no current parent, so don't try to remove child - if (mDrawable.notNull()) - { - if (mDrawable->isDead() || !mDrawable->getVObj()) - { - llwarns << "Drawable is dead or no VObj!" << llendl; - sent_parentp->addChild(this); - } - else - { - if (!setDrawableParent(sent_parentp->mDrawable)) // LLViewerObject::processUpdateMessage 1 - { - // Bad, we got a cycle somehow. - // Kill both the parent and the child, and - // set cache misses for both of them. - llwarns << "Attempting to recover from parenting cycle!" << llendl; - llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl; - llwarns << "Adding to cache miss list" << llendl; - setParent(NULL); - sent_parentp->setParent(NULL); - getRegion()->addCacheMissFull(getLocalID()); - getRegion()->addCacheMissFull(sent_parentp->getLocalID()); - gObjectList.killObject(sent_parentp); - gObjectList.killObject(this); - return retval; - } - sent_parentp->addChild(this); - // make sure this object gets a non-damped update - if (sent_parentp->mDrawable.notNull()) - { - gPipeline.markMoved(sent_parentp->mDrawable, FALSE); // undamped - } - } - } - else - { - sent_parentp->addChild(this); - } - - // Show particles, icon and HUD - hideExtraDisplayItems( FALSE ); - - setChanged(MOVED | SILHOUETTE); - } - else - { - // - // No corresponding viewer object for the parent, put the various - // pieces on the orphan list. - // - - //parent_id - U32 ip = mesgsys->getSenderIP(); - U32 port = mesgsys->getSenderPort(); - - gObjectList.orphanize(this, parent_id, ip, port); - - // Hide particles, icon and HUD - hideExtraDisplayItems( TRUE ); - } - } - } - else - { - // BUG: this is a bad assumption once border crossing is alowed - if ( (parent_id == cur_parentp->mLocalID) - &&(update_type == OUT_TERSE_IMPROVED)) - { - // Parent now, same parent in message -> do nothing - - // Debugging for suspected problems with local ids. - //LLUUID parent_uuid; - //LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, mesgsys->getSenderIP(), mesgsys->getSenderPort() ); - //if (parent_uuid != cur_parentp->getID() ) - //{ - // llerrs << "Local ID match but UUID mismatch of viewer object" << llendl; - //} - } - else - { - // Parented now, different parent in message - LLViewerObject *sent_parentp; - if (parent_id == 0) - { - // - // This object is no longer parented, we sent in a zero parent ID. - // - sent_parentp = NULL; - } - else - { - LLUUID parent_uuid; - LLViewerObjectList::getUUIDFromLocal(parent_uuid, - parent_id, - gMessageSystem->getSenderIP(), - gMessageSystem->getSenderPort()); - sent_parentp = gObjectList.findObject(parent_uuid); - - if (isAvatar()) - { - // This logic is meant to handle the case where a sitting avatar has reached a new sim - // ahead of the object she was sitting on (which is common as objects are transfered through - // a slower route than agents)... - // In this case, the local id for the object will not be valid, since the viewer has not received - // a full update for the object from that sim yet, so we assume that the agent is still sitting - // where she was originally. --RN - if (!sent_parentp) - { - sent_parentp = cur_parentp; - } - } - else if (!sent_parentp) - { - // - // Switching parents, but we don't know the new parent. - // - U32 ip = mesgsys->getSenderIP(); - U32 port = mesgsys->getSenderPort(); - - // We're an orphan, flag things appropriately. - gObjectList.orphanize(this, parent_id, ip, port); - } - } - - // Reattach if possible. - if (sent_parentp && sent_parentp != cur_parentp && sent_parentp != this) - { - // New parent is valid, detach and reattach - b_changed_status = TRUE; - if (mDrawable.notNull()) - { - if (!setDrawableParent(sent_parentp->mDrawable)) // LLViewerObject::processUpdateMessage 2 - { - // Bad, we got a cycle somehow. - // Kill both the parent and the child, and - // set cache misses for both of them. - llwarns << "Attempting to recover from parenting cycle!" << llendl; - llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl; - llwarns << "Adding to cache miss list" << llendl; - setParent(NULL); - sent_parentp->setParent(NULL); - getRegion()->addCacheMissFull(getLocalID()); - getRegion()->addCacheMissFull(sent_parentp->getLocalID()); - gObjectList.killObject(sent_parentp); - gObjectList.killObject(this); - return retval; - } - // make sure this object gets a non-damped update - } - cur_parentp->removeChild(this); - sent_parentp->addChild(this); - setChanged(MOVED | SILHOUETTE); - sent_parentp->setChanged(MOVED | SILHOUETTE); - if (sent_parentp->mDrawable.notNull()) - { - gPipeline.markMoved(sent_parentp->mDrawable, FALSE); // undamped - } - } - else if (!sent_parentp) - { - bool remove_parent = true; - // No new parent, or the parent that we sent doesn't exist on the viewer. - LLViewerObject *parentp = (LLViewerObject *)getParent(); - if (parentp) - { - if (parentp->getRegion() != getRegion()) - { - // This is probably an object flying across a region boundary, the - // object probably ISN'T being reparented, but just got an object - // update out of order (child update before parent). - //llinfos << "Don't reparent object handoffs!" << llendl; - remove_parent = false; - } - } - - if (remove_parent) - { - b_changed_status = TRUE; - if (mDrawable.notNull()) - { - // clear parent to removeChild can put the drawable on the damped list - setDrawableParent(NULL); // LLViewerObject::processUpdateMessage 3 - } - - cur_parentp->removeChild(this); - - if (mJointInfo && !parent_id) - { - // since this object is no longer parent-relative - // we make sure we delete any joint info - delete mJointInfo; - mJointInfo = NULL; - } - - setChanged(MOVED | SILHOUETTE); - - if (mDrawable.notNull()) - { - // make sure this object gets a non-damped update - gPipeline.markMoved(mDrawable, FALSE); // undamped - } - } - } - } - } - } - - new_rot.normQuat(); - - if (sPingInterpolate) - { - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mesgsys->getSender()); - if (cdp) - { - F32 ping_delay = 0.5f * mTimeDilation * ( ((F32)cdp->getPingDelay()) * 0.001f + gFrameDTClamped); - LLVector3 diff = getVelocity() * ping_delay; - new_pos_parent += diff; - } - else - { - llwarns << "findCircuit() returned NULL; skipping interpolation" << llendl; - } - } - - ////////////////////////// - // - // Set the generic change flags... - // - // - - // WTF? If we're going to skip this message, why are we - // doing all the parenting, etc above? - U32 packet_id = mesgsys->getCurrentRecvPacketID(); - if (packet_id < mLatestRecvPacketID && - mLatestRecvPacketID - packet_id < 65536) - { - //skip application of this message, it's old - return retval; - } - - mLatestRecvPacketID = packet_id; - - // Set the change flags for scale - if (new_scale != getScale()) - { - setChanged(SCALED | SILHOUETTE); - setScale(new_scale); // Must follow setting permYouOwner() - } - - // first, let's see if the new position is actually a change - - //static S32 counter = 0; - - F32 vel_mag_sq = getVelocity().magVecSquared(); - F32 accel_mag_sq = getAcceleration().magVecSquared(); - - if ( ((b_changed_status)||(test_pos_parent != new_pos_parent)) - ||( (!isSelected()) - &&( (vel_mag_sq != 0.f) - ||(accel_mag_sq != 0.f) - ||(this_update_precision > mBestUpdatePrecision)))) - { - mBestUpdatePrecision = this_update_precision; - - LLVector3 diff = new_pos_parent - test_pos_parent ; - F32 mag_sqr = diff.magVecSquared() ; - if(llfinite(mag_sqr)) - { - setPositionParent(new_pos_parent); - } - else - { - llwarns << "Can not move the object/avatar to an infinite location!" << llendl ; - - retval |= INVALID_UPDATE ; - } - - if (mParent && ((LLViewerObject*)mParent)->isAvatar()) - { - // we have changed the position of an attachment, so we need to clamp it - LLVOAvatar *avatar = (LLVOAvatar*)mParent; - - avatar->clampAttachmentPositions(); - } - - // If we're snapping the position by more than 0.5m, update LLViewerStats::mAgentPositionSnaps - if ( asAvatar() && asAvatar()->isSelf() && (mag_sqr > 0.25f) ) - { - LLViewerStats::getInstance()->mAgentPositionSnaps.push( diff.length() ); - } - } - - if (new_rot != mLastRot - || new_angv != old_angv) - { - if (new_rot != mLastRot) - { - mLastRot = new_rot; - setRotation(new_rot); - } - - setChanged(ROTATED | SILHOUETTE); - - resetRot(); - } - - - if ( gShowObjectUpdates ) - { - if (!((mPrimitiveCode == LL_PCODE_LEGACY_AVATAR) && (((LLVOAvatar *) this)->isSelf())) - && mRegionp) - { - LLViewerObject* object = gObjectList.createObjectViewer(LL_PCODE_LEGACY_TEXT_BUBBLE, mRegionp); - LLVOTextBubble* bubble = (LLVOTextBubble*) object; - - if (update_type == OUT_TERSE_IMPROVED) - { - bubble->mColor.setVec(0.f, 0.f, 1.f, 1.f); - } - else - { - bubble->mColor.setVec(1.f, 0.f, 0.f, 1.f); - } - object->setPositionGlobal(getPositionGlobal()); - gPipeline.addObject(object); - } - } - - if ((0.0f == vel_mag_sq) && - (0.0f == accel_mag_sq) && - (0.0f == getAngularVelocity().magVecSquared())) - { - mStatic = TRUE; // This object doesn't move! - } - else - { - mStatic = FALSE; - } - -// BUG: This code leads to problems during group rotate and any scale operation. -// Small discepencies between the simulator and viewer representations cause the -// selection center to creep, leading to objects moving around the wrong center. -// -// Removing this, however, means that if someone else drags an object you have -// selected, your selection center and dialog boxes will be wrong. It also means -// that higher precision information on selected objects will be ignored. -// -// I believe the group rotation problem is fixed. JNC 1.21.2002 -// - // Additionally, if any child is selected, need to update the dialogs and selection - // center. - BOOL needs_refresh = mUserSelected; - for (child_list_t::iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* child = *iter; - needs_refresh = needs_refresh || child->mUserSelected; - } - - if (needs_refresh) - { - LLSelectMgr::getInstance()->updateSelectionCenter(); - dialog_refresh_all(); - } - - - // Mark update time as approx. now, with the ping delay. - // Ping delay is off because it's not set for velocity interpolation, causing - // much jumping and hopping around... - -// U32 ping_delay = mesgsys->mCircuitInfo.getPingDelay(); - mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds(); - mLastMessageUpdateSecs = mLastInterpUpdateSecs; - if (mDrawable.notNull()) - { - // Don't clear invisibility flag on update if still orphaned! - if (mDrawable->isState(LLDrawable::FORCE_INVISIBLE) && !mOrphaned) - { -// lldebugs << "Clearing force invisible: " << mID << ":" << getPCodeString() << ":" << getPositionAgent() << llendl; - mDrawable->setState(LLDrawable::CLEAR_INVISIBLE); - } - } - - // Update special hover cursor status - bool special_hover_cursor = specialHoverCursor(); - if (old_special_hover_cursor != special_hover_cursor - && mDrawable.notNull()) - { - mDrawable->updateSpecialHoverCursor(special_hover_cursor); - } - - return retval; -} - -BOOL LLViewerObject::isActive() const -{ - return TRUE; -} - - - -BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) -{ - static LLFastTimer::DeclareTimer ftm("Viewer Object"); - LLFastTimer t(ftm); - - if (mDead) - { - // It's dead. Don't update it. - return TRUE; - } - - // CRO - don't velocity interp linked objects! - // Leviathan - but DO velocity interp joints - if (!mStatic && sVelocityInterpolate && !isSelected()) - { - // calculate dt from last update - F32 dt_raw = (F32)(time - mLastInterpUpdateSecs); - F32 dt = mTimeDilation * dt_raw; - - if (!mJointInfo) - { - applyAngularVelocity(dt); - } - - LLViewerObject *parentp = (LLViewerObject *) getParent(); - if (mJointInfo) - { - if (parentp) - { - // do parent-relative stuff - LLVector3 ang_vel = getAngularVelocity(); - F32 omega = ang_vel.magVecSquared(); - F32 angle = 0.0f; - LLQuaternion dQ; - if (omega > 0.00001f) - { - omega = sqrt(omega); - angle = omega * dt; - dQ.setQuat(angle, ang_vel); - } - LLVector3 pos = getPosition(); - - if (HJT_HINGE == mJointInfo->mJointType) - { - // hinge = uniform circular motion - LLVector3 parent_pivot = getVelocity(); - LLVector3 parent_axis = getAcceleration(); - - angle = dt * (ang_vel * mJointInfo->mAxisOrAnchor); // AxisOrAnchor = axis - dQ.setQuat(angle, mJointInfo->mAxisOrAnchor); // AxisOrAnchor = axis - LLVector3 pivot_offset = pos - mJointInfo->mPivot; // pos in pivot-frame - pivot_offset = pivot_offset * dQ; // new rotated pivot-frame pos - pos = mJointInfo->mPivot + pivot_offset; // parent-frame - LLViewerObject::setPosition(pos); - LLQuaternion Q_PC = getRotation(); - setRotation(Q_PC * dQ); - mLastInterpUpdateSecs = time; - } - else if (HJT_POINT == mJointInfo->mJointType) - // || HJT_LPOINT == mJointInfo->mJointType) - { - // point-to-point = spin about axis and uniform circular motion - // of axis about the pivot point - // - // NOTE: this interpolation scheme is not quite good enough to - // reduce the bandwidth -- needs a gravitational correction. - // Similarly for hinges with axes that deviate from vertical. - - LLQuaternion Q_PC = getRotation(); - Q_PC = Q_PC * dQ; - setRotation(Q_PC); - - LLVector3 pivot_to_child = - mJointInfo->mAxisOrAnchor; // AxisOrAnchor = anchor - pos = mJointInfo->mPivot + pivot_to_child * Q_PC; - LLViewerObject::setPosition(pos); - mLastInterpUpdateSecs = time; - } - /* else if (HJT_WHEEL == mJointInfo->mJointInfo) - { - // wheel = uniform rotation about axis, with linear - // velocity interpolation (if any) - LLVector3 parent_axis = getAcceleration(); // HACK -- accel stores the parent-axis (parent-frame) - - LLQuaternion Q_PC = getRotation(); - - angle = dt * (parent_axis * ang_vel); - dQ.setQuat(angle, parent_axis); - - Q_PC = Q_PC * dQ; - setRotation(Q_PC); - - pos = getPosition() + dt * getVelocity(); - LLViewerObject::setPosition(pos); - mLastInterpUpdateSecs = time; - }*/ - } - } - else if (isAttachment()) - { - mLastInterpUpdateSecs = time; - return TRUE; - } - else - { // Move object based on it's velocity and rotation - interpolateLinearMotion(time, dt); - } - } - - updateDrawable(FALSE); - - return TRUE; -} - - -// Move an object due to idle-time viewer side updates by iterpolating motion -void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) -{ - // linear motion - // PHYSICS_TIMESTEP is used below to correct for the fact that the velocity in object - // updates represents the average velocity of the last timestep, rather than the final velocity. - // the time dilation above should guarantee that dt is never less than PHYSICS_TIMESTEP, theoretically - // - // *TODO: should also wrap linear accel/velocity in check - // to see if object is selected, instead of explicitly - // zeroing it out - - F64 time_since_last_update = time - mLastMessageUpdateSecs; - if (time_since_last_update <= 0.0 || dt <= 0.f) - { - return; - } - - LLVector3 accel = getAcceleration(); - LLVector3 vel = getVelocity(); - - if (sMaxUpdateInterpolationTime <= 0.0) - { // Old code path ... unbounded, simple interpolation - if (!(accel.isExactlyZero() && vel.isExactlyZero())) - { - LLVector3 pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; - - // region local - setPositionRegion(pos + getPositionRegion()); - setVelocity(vel + accel*dt); - - // for objects that are spinning but not translating, make sure to flag them as having moved - setChanged(MOVED | SILHOUETTE); - } - } - else if (!accel.isExactlyZero() || !vel.isExactlyZero()) // object is moving - { // Object is moving, and hasn't been too long since we got an update from the server - - // Calculate predicted position and velocity - LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; - LLVector3 new_v = accel * dt; - - if (time_since_last_update > sPhaseOutUpdateInterpolationTime && - sPhaseOutUpdateInterpolationTime > 0.0) - { // Haven't seen a viewer update in a while, check to see if the ciruit is still active - if (mRegionp) - { // The simulator will NOT send updates if the object continues normally on the path - // predicted by the velocity and the acceleration (often gravity) sent to the viewer - // So check to see if the circuit is blocked, which means the sim is likely in a long lag - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit( mRegionp->getHost() ); - if (cdp) - { - // Find out how many seconds since last packet arrived on the circuit - F64 time_since_last_packet = LLMessageSystem::getMessageTimeSeconds() - cdp->getLastPacketInTime(); - - if (!cdp->isAlive() || // Circuit is dead or blocked - cdp->isBlocked() || // or doesn't seem to be getting any packets - (time_since_last_packet > sPhaseOutUpdateInterpolationTime)) - { - // Start to reduce motion interpolation since we haven't seen a server update in a while - F64 time_since_last_interpolation = time - mLastInterpUpdateSecs; - F64 phase_out = 1.0; - if (time_since_last_update > sMaxUpdateInterpolationTime) - { // Past the time limit, so stop the object - phase_out = 0.0; - //llinfos << "Motion phase out to zero" << llendl; - - // Kill angular motion as well. Note - not adding this due to paranoia - // about stopping rotation for llTargetOmega objects and not having it restart - // setAngularVelocity(LLVector3::zero); - } - else if (mLastInterpUpdateSecs - mLastMessageUpdateSecs > sPhaseOutUpdateInterpolationTime) - { // Last update was already phased out a bit - phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / - (sMaxUpdateInterpolationTime - time_since_last_interpolation); - //llinfos << "Continuing motion phase out of " << (F32) phase_out << llendl; - } - else - { // Phase out from full value - phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / - (sMaxUpdateInterpolationTime - sPhaseOutUpdateInterpolationTime); - //llinfos << "Starting motion phase out of " << (F32) phase_out << llendl; - } - phase_out = llclamp(phase_out, 0.0, 1.0); - - new_pos = new_pos * ((F32) phase_out); - new_v = new_v * ((F32) phase_out); - } - } - } - } - - new_pos = new_pos + getPositionRegion(); - new_v = new_v + vel; - - - // Clamp interpolated position to minimum underground and maximum region height - LLVector3d new_pos_global = mRegionp->getPosGlobalFromRegion(new_pos); - F32 min_height; - if (isAvatar()) - { // Make a better guess about AVs not going underground - min_height = LLWorld::getInstance()->resolveLandHeightGlobal(new_pos_global); - min_height += (0.5f * getScale().mV[VZ]); - } - else - { // This will put the object underground, but we can't tell if it will stop - // at ground level or not - min_height = LLWorld::getInstance()->getMinAllowedZ(this, new_pos_global); - } - - new_pos.mV[VZ] = llmax(min_height, new_pos.mV[VZ]); - new_pos.mV[VZ] = llmin(LLWorld::getInstance()->getRegionMaxHeight(), new_pos.mV[VZ]); - - // Check to see if it's going off the region - LLVector3 temp(new_pos); - if (temp.clamp(0.f, mRegionp->getWidth())) - { // Going off this region, so see if we might end up on another region - LLVector3d old_pos_global = mRegionp->getPosGlobalFromRegion(getPositionRegion()); - new_pos_global = mRegionp->getPosGlobalFromRegion(new_pos); // Re-fetch in case it got clipped above - - // Clip the positions to known regions - LLVector3d clip_pos_global = LLWorld::getInstance()->clipToVisibleRegions(old_pos_global, new_pos_global); - if (clip_pos_global != new_pos_global) - { // Was clipped, so this means we hit a edge where there is no region to enter - - //llinfos << "Hit empty region edge, clipped predicted position to " << mRegionp->getPosRegionFromGlobal(clip_pos_global) - // << " from " << new_pos << llendl; - new_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global); - - // Stop motion and get server update for bouncing on the edge - new_v.clear(); - setAcceleration(LLVector3::zero); - } - else - { // Let predicted movement cross into another region - //llinfos << "Predicting region crossing to " << new_pos << llendl; - } - } - - // Set new position and velocity - setPositionRegion(new_pos); - setVelocity(new_v); - - // for objects that are spinning but not translating, make sure to flag them as having moved - setChanged(MOVED | SILHOUETTE); - } - - // Update the last time we did anything - mLastInterpUpdateSecs = time; -} - - - -BOOL LLViewerObject::setData(const U8 *datap, const U32 data_size) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - - delete [] mData; - - if (datap) - { - mData = new U8[data_size]; - if (!mData) - { - return FALSE; - } - memcpy(mData, datap, data_size); /* Flawfinder: ignore */ - } - return TRUE; -} - -// delete an item in the inventory, but don't tell the server. This is -// used internally by remove, update, and savescript. -// This will only delete the first item with an item_id in the list -void LLViewerObject::deleteInventoryItem(const LLUUID& item_id) -{ - if(mInventory) - { - LLInventoryObject::object_list_t::iterator it = mInventory->begin(); - LLInventoryObject::object_list_t::iterator end = mInventory->end(); - for( ; it != end; ++it ) - { - if((*it)->getUUID() == item_id) - { - // This is safe only because we return immediatly. - mInventory->erase(it); // will deref and delete it - return; - } - } - doInventoryCallback(); - } -} - -void LLViewerObject::doUpdateInventory( - LLPointer& item, - U8 key, - bool is_new) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - - LLViewerInventoryItem* old_item = NULL; - if(TASK_INVENTORY_ITEM_KEY == key) - { - old_item = (LLViewerInventoryItem*)getInventoryObject(item->getUUID()); - } - else if(TASK_INVENTORY_ASSET_KEY == key) - { - old_item = getInventoryItemByAsset(item->getAssetUUID()); - } - LLUUID item_id; - LLUUID new_owner; - LLUUID new_group; - BOOL group_owned = FALSE; - if(old_item) - { - item_id = old_item->getUUID(); - new_owner = old_item->getPermissions().getOwner(); - new_group = old_item->getPermissions().getGroup(); - group_owned = old_item->getPermissions().isGroupOwned(); - old_item = NULL; - } - else - { - item_id = item->getUUID(); - } - if(!is_new && mInventory) - { - // Attempt to update the local inventory. If we can get the - // object perm, we have perfect visibility, so we want the - // serial number to match. Otherwise, take our best guess and - // make sure that the serial number does not match. - deleteInventoryItem(item_id); - LLPermissions perm(item->getPermissions()); - LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(this); - bool is_atomic = ((S32)LLAssetType::AT_OBJECT == item->getType()) ? false : true; - if(obj_perm) - { - perm.setOwnerAndGroup(LLUUID::null, obj_perm->getOwner(), obj_perm->getGroup(), is_atomic); - } - else - { - if(group_owned) - { - perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic); - } - else if(!new_owner.isNull()) - { - // The object used to be in inventory, so we can - // assume the owner and group will match what they are - // there. - perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic); - } - // *FIX: can make an even better guess by using the mPermGroup flags - else if(permYouOwner()) - { - // best guess. - perm.setOwnerAndGroup(LLUUID::null, gAgent.getID(), item->getPermissions().getGroup(), is_atomic); - --mInventorySerialNum; - } - else - { - // dummy it up. - perm.setOwnerAndGroup(LLUUID::null, LLUUID::null, LLUUID::null, is_atomic); - --mInventorySerialNum; - } - } - LLViewerInventoryItem* oldItem = item; - LLViewerInventoryItem* new_item = new LLViewerInventoryItem(oldItem); - new_item->setPermissions(perm); - mInventory->push_front(new_item); - doInventoryCallback(); - ++mInventorySerialNum; - } -} - -// save a script, which involves removing the old one, and rezzing -// in the new one. This method should be called with the asset id -// of the new and old script AFTER the bytecode has been saved. -void LLViewerObject::saveScript( - const LLViewerInventoryItem* item, - BOOL active, - bool is_new) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - - /* - * XXXPAM Investigate not making this copy. Seems unecessary, but I'm unsure about the - * interaction with doUpdateInventory() called below. - */ - lldebugs << "LLViewerObject::saveScript() " << item->getUUID() << " " << item->getAssetUUID() << llendl; - LLPointer task_item = - new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(), - item->getAssetUUID(), item->getType(), - item->getInventoryType(), - item->getName(), item->getDescription(), - item->getSaleInfo(), item->getFlags(), - item->getCreationDate()); - task_item->setTransactionID(item->getTransactionID()); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RezScript); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); - msg->nextBlockFast(_PREHASH_UpdateBlock); - msg->addU32Fast(_PREHASH_ObjectLocalID, (mLocalID)); - U8 enabled = active; - msg->addBOOLFast(_PREHASH_Enabled, enabled); - msg->nextBlockFast(_PREHASH_InventoryBlock); - task_item->packMessage(msg); - msg->sendReliable(mRegionp->getHost()); - - // do the internal logic - doUpdateInventory(task_item, TASK_INVENTORY_ITEM_KEY, is_new); -} - -void LLViewerObject::moveInventory(const LLUUID& folder_id, - const LLUUID& item_id) -{ - lldebugs << "LLViewerObject::moveInventory " << item_id << llendl; - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_MoveTaskInventory); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_FolderID, folder_id); - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addU32Fast(_PREHASH_LocalID, mLocalID); - msg->addUUIDFast(_PREHASH_ItemID, item_id); - msg->sendReliable(mRegionp->getHost()); - - LLInventoryObject* inv_obj = getInventoryObject(item_id); - if(inv_obj) - { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_obj; - if(!item->getPermissions().allowCopyBy(gAgent.getID())) - { - deleteInventoryItem(item_id); - ++mInventorySerialNum; - } - } -} - -void LLViewerObject::dirtyInventory() -{ - // If there aren't any LLVOInventoryListeners, we won't be - // able to update our mInventory when it comes back from the - // simulator, so we should not clear the inventory either. - if(mInventory && !mInventoryCallbacks.empty()) - { - mInventory->clear(); // will deref and delete entries - delete mInventory; - mInventory = NULL; - mInventoryDirty = TRUE; - } -} - -void LLViewerObject::registerInventoryListener(LLVOInventoryListener* listener, void* user_data) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - - LLInventoryCallbackInfo* info = new LLInventoryCallbackInfo; - info->mListener = listener; - info->mInventoryData = user_data; - mInventoryCallbacks.push_front(info); -} - -void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener) -{ - if (listener == NULL) - return; - for (callback_list_t::iterator iter = mInventoryCallbacks.begin(); - iter != mInventoryCallbacks.end(); ) - { - callback_list_t::iterator curiter = iter++; - LLInventoryCallbackInfo* info = *curiter; - if (info->mListener == listener) - { - delete info; - mInventoryCallbacks.erase(curiter); - break; - } - } -} - -void LLViewerObject::clearInventoryListeners() -{ - for_each(mInventoryCallbacks.begin(), mInventoryCallbacks.end(), DeletePointer()); - mInventoryCallbacks.clear(); -} - -void LLViewerObject::requestInventory() -{ - mInventoryDirty = FALSE; - if(mInventory) - { - //mInventory->clear() // will deref and delete it - //delete mInventory; - //mInventory = NULL; - doInventoryCallback(); - } - // throw away duplicate requests - else - { - fetchInventoryFromServer(); - } -} - -void LLViewerObject::fetchInventoryFromServer() -{ - if (!mInventoryPending) - { - delete mInventory; - mInventory = NULL; - mInventoryDirty = FALSE; - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RequestTaskInventory); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addU32Fast(_PREHASH_LocalID, mLocalID); - msg->sendReliable(mRegionp->getHost()); - - // this will get reset by dirtyInventory or doInventoryCallback - mInventoryPending = TRUE; - } -} - -struct LLFilenameAndTask -{ - LLUUID mTaskID; - std::string mFilename; -#ifdef _DEBUG - static S32 sCount; - LLFilenameAndTask() - { - ++sCount; - lldebugs << "Constructing LLFilenameAndTask: " << sCount << llendl; - } - ~LLFilenameAndTask() - { - --sCount; - lldebugs << "Destroying LLFilenameAndTask: " << sCount << llendl; - } -private: - LLFilenameAndTask(const LLFilenameAndTask& rhs); - const LLFilenameAndTask& operator=(const LLFilenameAndTask& rhs) const; -#endif -}; - -#ifdef _DEBUG -S32 LLFilenameAndTask::sCount = 0; -#endif - -// static -void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - - LLUUID task_id; - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id); - LLViewerObject* object = gObjectList.findObject(task_id); - if(!object) - { - llwarns << "LLViewerObject::processTaskInv object " - << task_id << " does not exist." << llendl; - return; - } - - msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum); - LLFilenameAndTask* ft = new LLFilenameAndTask; - ft->mTaskID = task_id; - - std::string unclean_filename; - msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); - ft->mFilename = LLDir::getScrubbedFileName(unclean_filename); - - if(ft->mFilename.empty()) - { - lldebugs << "Task has no inventory" << llendl; - // mock up some inventory to make a drop target. - if(object->mInventory) - { - object->mInventory->clear(); // will deref and delete it - } - else - { - object->mInventory = new LLInventoryObject::object_list_t(); - } - LLPointer obj; - obj = new LLInventoryObject(object->mID, LLUUID::null, - LLAssetType::AT_CATEGORY, - LLTrans::getString("ViewerObjectContents").c_str()); - object->mInventory->push_front(obj); - object->doInventoryCallback(); - delete ft; - return; - } - gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), - ft->mFilename, LL_PATH_CACHE, - object->mRegionp->getHost(), - TRUE, - &LLViewerObject::processTaskInvFile, - (void**)ft, - LLXferManager::HIGH_PRIORITY); -} - -void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status) -{ - LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data; - LLViewerObject* object = NULL; - if(ft && (0 == error_code) && - (object = gObjectList.findObject(ft->mTaskID))) - { - object->loadTaskInvFile(ft->mFilename); - } - else - { - // This Occurs When to requests were made, and the first one - // has already handled it. - lldebugs << "Problem loading task inventory. Return code: " - << error_code << llendl; - } - delete ft; -} - -void LLViewerObject::loadTaskInvFile(const std::string& filename) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - - std::string filename_and_local_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, filename); - llifstream ifs(filename_and_local_path); - if(ifs.good()) - { - char buffer[MAX_STRING]; /* Flawfinder: ignore */ - // *NOTE: This buffer size is hard coded into scanf() below. - char keyword[MAX_STRING]; /* Flawfinder: ignore */ - if(mInventory) - { - mInventory->clear(); // will deref and delete it - } - else - { - mInventory = new LLInventoryObject::object_list_t; - } - while(ifs.good()) - { - ifs.getline(buffer, MAX_STRING); - sscanf(buffer, " %254s", keyword); /* Flawfinder: ignore */ - if(0 == strcmp("inv_item", keyword)) - { - LLPointer inv = new LLViewerInventoryItem; - inv->importLegacyStream(ifs); - mInventory->push_front(inv); - } - else if(0 == strcmp("inv_object", keyword)) - { - LLPointer inv = new LLInventoryObject; - inv->importLegacyStream(ifs); - inv->rename(LLTrans::getString("ViewerObjectContents").c_str()); - mInventory->push_front(inv); - } - else - { - llwarns << "Unknown token in inventory file '" - << keyword << "'" << llendl; - } - } - ifs.close(); - LLFile::remove(filename_and_local_path); - } - else - { - llwarns << "unable to load task inventory: " << filename_and_local_path - << llendl; - } - doInventoryCallback(); -} - -void LLViewerObject::doInventoryCallback() -{ - for (callback_list_t::iterator iter = mInventoryCallbacks.begin(); - iter != mInventoryCallbacks.end(); ) - { - callback_list_t::iterator curiter = iter++; - LLInventoryCallbackInfo* info = *curiter; - if (info->mListener != NULL) - { - info->mListener->inventoryChanged(this, - mInventory, - mInventorySerialNum, - info->mInventoryData); - } - else - { - llinfos << "LLViewerObject::doInventoryCallback() deleting bad listener entry." << llendl; - delete info; - mInventoryCallbacks.erase(curiter); - } - } - mInventoryPending = FALSE; -} - -void LLViewerObject::removeInventory(const LLUUID& item_id) -{ - // close any associated floater properties - LLFloaterReg::hideInstance("properties", item_id); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RemoveTaskInventory); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addU32Fast(_PREHASH_LocalID, mLocalID); - msg->addUUIDFast(_PREHASH_ItemID, item_id); - msg->sendReliable(mRegionp->getHost()); - deleteInventoryItem(item_id); - ++mInventorySerialNum; -} - -void LLViewerObject::updateInventory( - LLViewerInventoryItem* item, - U8 key, - bool is_new) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - - // This slices the object into what we're concerned about on the - // viewer. The simulator will take the permissions and transfer - // ownership. - LLPointer task_item = - new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(), - item->getAssetUUID(), item->getType(), - item->getInventoryType(), - item->getName(), item->getDescription(), - item->getSaleInfo(), - item->getFlags(), - item->getCreationDate()); - task_item->setTransactionID(item->getTransactionID()); - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_UpdateTaskInventory); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_UpdateData); - msg->addU32Fast(_PREHASH_LocalID, mLocalID); - msg->addU8Fast(_PREHASH_Key, key); - msg->nextBlockFast(_PREHASH_InventoryData); - task_item->packMessage(msg); - msg->sendReliable(mRegionp->getHost()); - - // do the internal logic - doUpdateInventory(task_item, key, is_new); -} - -void LLViewerObject::updateInventoryLocal(LLInventoryItem* item, U8 key) -{ - LLPointer task_item = - new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(), - item->getAssetUUID(), item->getType(), - item->getInventoryType(), - item->getName(), item->getDescription(), - item->getSaleInfo(), item->getFlags(), - item->getCreationDate()); - - // do the internal logic - const bool is_new = false; - doUpdateInventory(task_item, key, is_new); -} - -LLInventoryObject* LLViewerObject::getInventoryObject(const LLUUID& item_id) -{ - LLInventoryObject* rv = NULL; - if(mInventory) - { - LLInventoryObject::object_list_t::iterator it = mInventory->begin(); - LLInventoryObject::object_list_t::iterator end = mInventory->end(); - for ( ; it != end; ++it) - { - if((*it)->getUUID() == item_id) - { - rv = *it; - break; - } - } - } - return rv; -} - -void LLViewerObject::getInventoryContents(LLInventoryObject::object_list_t& objects) -{ - if(mInventory) - { - LLInventoryObject::object_list_t::iterator it = mInventory->begin(); - LLInventoryObject::object_list_t::iterator end = mInventory->end(); - for( ; it != end; ++it) - { - if ((*it)->getType() != LLAssetType::AT_CATEGORY) - { - objects.push_back(*it); - } - } - } -} - -LLInventoryObject* LLViewerObject::getInventoryRoot() -{ - if (!mInventory || !mInventory->size()) - { - return NULL; - } - return mInventory->back(); -} - -LLViewerInventoryItem* LLViewerObject::getInventoryItemByAsset(const LLUUID& asset_id) -{ - if (mInventoryDirty) - llwarns << "Peforming inventory lookup for object " << mID << " that has dirty inventory!" << llendl; - - LLViewerInventoryItem* rv = NULL; - if(mInventory) - { - LLViewerInventoryItem* item = NULL; - - LLInventoryObject::object_list_t::iterator it = mInventory->begin(); - LLInventoryObject::object_list_t::iterator end = mInventory->end(); - for( ; it != end; ++it) - { - LLInventoryObject* obj = *it; - if(obj->getType() != LLAssetType::AT_CATEGORY) - { - // *FIX: gank-ass down cast! - item = (LLViewerInventoryItem*)obj; - if(item->getAssetUUID() == asset_id) - { - rv = item; - break; - } - } - } - } - return rv; -} - -void LLViewerObject::updateViewerInventoryAsset( - const LLViewerInventoryItem* item, - const LLUUID& new_asset) -{ - LLPointer task_item = - new LLViewerInventoryItem(item); - task_item->setAssetUUID(new_asset); - - // do the internal logic - doUpdateInventory(task_item, TASK_INVENTORY_ITEM_KEY, false); -} - -void LLViewerObject::setPixelAreaAndAngle(LLAgent &agent) -{ - if (getVolume()) - { //volumes calculate pixel area and angle per face - return; - } - - LLVector3 viewer_pos_agent = gAgentCamera.getCameraPositionAgent(); - LLVector3 pos_agent = getRenderPosition(); - - F32 dx = viewer_pos_agent.mV[VX] - pos_agent.mV[VX]; - F32 dy = viewer_pos_agent.mV[VY] - pos_agent.mV[VY]; - F32 dz = viewer_pos_agent.mV[VZ] - pos_agent.mV[VZ]; - - F32 max_scale = getMaxScale(); - F32 mid_scale = getMidScale(); - F32 min_scale = getMinScale(); - - // IW: estimate - when close to large objects, computing range based on distance from center is no good - // to try to get a min distance from face, subtract min_scale/2 from the range. - // This means we'll load too much detail sometimes, but that's better than not enough - // I don't think there's a better way to do this without calculating distance per-poly - F32 range = sqrt(dx*dx + dy*dy + dz*dz) - min_scale/2; - - LLViewerCamera* camera = LLViewerCamera::getInstance(); - if (range < 0.001f || isHUDAttachment()) // range == zero - { - mAppAngle = 180.f; - mPixelArea = (F32)camera->getScreenPixelArea(); - } - else - { - mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG; - - F32 pixels_per_meter = camera->getPixelMeterRatio() / range; - - mPixelArea = (pixels_per_meter * max_scale) * (pixels_per_meter * mid_scale); - if (mPixelArea > camera->getScreenPixelArea()) - { - mAppAngle = 180.f; - mPixelArea = (F32)camera->getScreenPixelArea(); - } - } -} - -BOOL LLViewerObject::updateLOD() -{ - return FALSE; -} - -BOOL LLViewerObject::updateGeometry(LLDrawable *drawable) -{ - return TRUE; -} - -void LLViewerObject::updateGL() -{ - -} - -void LLViewerObject::updateFaceSize(S32 idx) -{ - -} - -LLDrawable* LLViewerObject::createDrawable(LLPipeline *pipeline) -{ - return NULL; -} - -void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped) -{ - LLPrimitive::setScale(scale); - if (mDrawable.notNull()) - { - //encompass completely sheared objects by taking - //the most extreme point possible (<1,1,0.5>) - mDrawable->setRadius(LLVector3(1,1,0.5f).scaleVec(scale).magVec()); - updateDrawable(damped); - } - - if( (LL_PCODE_VOLUME == getPCode()) && !isDead() ) - { - if (permYouOwner() || (scale.magVecSquared() > (7.5f * 7.5f)) ) - { - if (!mOnMap) - { - llassert_always(LLWorld::getInstance()->getRegionFromHandle(getRegion()->getHandle())); - - gObjectList.addToMap(this); - mOnMap = TRUE; - } - } - else - { - if (mOnMap) - { - gObjectList.removeFromMap(this); - mOnMap = FALSE; - } - } - } -} - -void LLViewerObject::setObjectCost(F32 cost) -{ - mObjectCost = cost; - mCostStale = false; - - if (isSelected()) - { - gFloaterTools->dirty(); - } -} - -void LLViewerObject::setLinksetCost(F32 cost) -{ - mLinksetCost = cost; - mCostStale = false; - - if (isSelected()) - { - gFloaterTools->dirty(); - } -} - -void LLViewerObject::setPhysicsCost(F32 cost) -{ - mPhysicsCost = cost; - mCostStale = false; - - if (isSelected()) - { - gFloaterTools->dirty(); - } -} - -void LLViewerObject::setLinksetPhysicsCost(F32 cost) -{ - mLinksetPhysicsCost = cost; - mCostStale = false; - - if (isSelected()) - { - gFloaterTools->dirty(); - } -} - - -F32 LLViewerObject::getObjectCost() -{ - if (mCostStale) - { - gObjectList.updateObjectCost(this); - } - - return mObjectCost; -} - -F32 LLViewerObject::getLinksetCost() -{ - if (mCostStale) - { - gObjectList.updateObjectCost(this); - } - - return mLinksetCost; -} - -F32 LLViewerObject::getPhysicsCost() -{ - if (mCostStale) - { - gObjectList.updateObjectCost(this); - } - - return mPhysicsCost; -} - -F32 LLViewerObject::getLinksetPhysicsCost() -{ - if (mCostStale) - { - gObjectList.updateObjectCost(this); - } - - return mLinksetPhysicsCost; -} - -F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes) -{ - return 0.f; -} - -U32 LLViewerObject::getTriangleCount() -{ - return 0; -} - -U32 LLViewerObject::getHighLODTriangleCount() -{ - return 0; -} - -void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) -{ - LLVector4a center; - center.load3(getRenderPosition().mV); - LLVector4a size; - size.load3(getScale().mV); - newMin.setSub(center, size); - newMax.setAdd(center, size); - - mDrawable->setPositionGroup(center); -} - -F32 LLViewerObject::getBinRadius() -{ - if (mDrawable.notNull()) - { - const LLVector4a* ext = mDrawable->getSpatialExtents(); - LLVector4a diff; - diff.setSub(ext[1], ext[0]); - return diff.getLength3().getF32(); - } - - return getScale().magVec(); -} - -F32 LLViewerObject::getMaxScale() const -{ - return llmax(getScale().mV[VX],getScale().mV[VY], getScale().mV[VZ]); -} - -F32 LLViewerObject::getMinScale() const -{ - return llmin(getScale().mV[0],getScale().mV[1],getScale().mV[2]); -} - -F32 LLViewerObject::getMidScale() const -{ - if (getScale().mV[VX] < getScale().mV[VY]) - { - if (getScale().mV[VY] < getScale().mV[VZ]) - { - return getScale().mV[VY]; - } - else if (getScale().mV[VX] < getScale().mV[VZ]) - { - return getScale().mV[VZ]; - } - else - { - return getScale().mV[VX]; - } - } - else if (getScale().mV[VX] < getScale().mV[VZ]) - { - return getScale().mV[VX]; - } - else if (getScale().mV[VY] < getScale().mV[VZ]) - { - return getScale().mV[VZ]; - } - else - { - return getScale().mV[VY]; - } -} - - -void LLViewerObject::updateTextures() -{ -} - -void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */) -{ - if (isDead()) - { - return; - } - - S32 i; - S32 tex_count = getNumTEs(); - for (i = 0; i < tex_count; i++) - { - getTEImage(i)->setBoostLevel(LLViewerTexture::BOOST_SELECTED); - } - - if (isSculpted() && !isMesh()) - { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLUUID sculpt_id = sculpt_params->getSculptTexture(); - LLViewerTextureManager::getFetchedTexture(sculpt_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)->setBoostLevel(LLViewerTexture::BOOST_SELECTED); - } - - if (boost_children) - { - for (child_list_t::iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* child = *iter; - child->boostTexturePriority(); - } - } -} - - -void LLViewerObject::setLineWidthForWindowSize(S32 window_width) -{ - if (window_width < 700) - { - LLUI::setLineWidth(2.0f); - } - else if (window_width < 1100) - { - LLUI::setLineWidth(3.0f); - } - else if (window_width < 2000) - { - LLUI::setLineWidth(4.0f); - } - else - { - // _damn_, what a nice monitor! - LLUI::setLineWidth(5.0f); - } -} - -void LLViewerObject::increaseArrowLength() -{ -/* ??? - if (mAxisArrowLength == 50) - { - mAxisArrowLength = 100; - } - else - { - mAxisArrowLength = 150; - } -*/ -} - - -void LLViewerObject::decreaseArrowLength() -{ -/* ??? - if (mAxisArrowLength == 150) - { - mAxisArrowLength = 100; - } - else - { - mAxisArrowLength = 50; - } -*/ -} - -// Culled from newsim LLTask::addNVPair -void LLViewerObject::addNVPair(const std::string& data) -{ - // cout << "LLViewerObject::addNVPair() with ---" << data << "---" << endl; - LLNameValue *nv = new LLNameValue(data.c_str()); - -// char splat[MAX_STRING]; -// temp->printNameValue(splat); -// llinfos << "addNVPair " << splat << llendl; - - name_value_map_t::iterator iter = mNameValuePairs.find(nv->mName); - if (iter != mNameValuePairs.end()) - { - LLNameValue* foundnv = iter->second; - if (foundnv->mClass != NVC_READ_ONLY) - { - delete foundnv; - mNameValuePairs.erase(iter); - } - else - { - delete nv; -// llinfos << "Trying to write to Read Only NVPair " << temp->mName << " in addNVPair()" << llendl; - return; - } - } - mNameValuePairs[nv->mName] = nv; -} - -BOOL LLViewerObject::removeNVPair(const std::string& name) -{ - char* canonical_name = gNVNameTable.addString(name); - - lldebugs << "LLViewerObject::removeNVPair(): " << name << llendl; - - name_value_map_t::iterator iter = mNameValuePairs.find(canonical_name); - if (iter != mNameValuePairs.end()) - { - if( mRegionp ) - { - LLNameValue* nv = iter->second; -/* - std::string buffer = nv->printNameValue(); - gMessageSystem->newMessageFast(_PREHASH_RemoveNameValuePair); - gMessageSystem->nextBlockFast(_PREHASH_TaskData); - gMessageSystem->addUUIDFast(_PREHASH_ID, mID); - - gMessageSystem->nextBlockFast(_PREHASH_NameValueData); - gMessageSystem->addStringFast(_PREHASH_NVPair, buffer); - - gMessageSystem->sendReliable( mRegionp->getHost() ); -*/ - // Remove the NV pair from the local list. - delete nv; - mNameValuePairs.erase(iter); - return TRUE; - } - else - { - lldebugs << "removeNVPair - No region for object" << llendl; - } - } - return FALSE; -} - - -LLNameValue *LLViewerObject::getNVPair(const std::string& name) const -{ - char *canonical_name; - - canonical_name = gNVNameTable.addString(name); - - // If you access a map with a name that isn't in it, it will add the name and a null pointer. - // So first check if the data is in the map. - name_value_map_t::const_iterator iter = mNameValuePairs.find(canonical_name); - if (iter != mNameValuePairs.end()) - { - return iter->second; - } - else - { - return NULL; - } -} - -void LLViewerObject::updatePositionCaches() const -{ - if(mRegionp) - { - if (!isRoot()) - { - mPositionRegion = ((LLViewerObject *)getParent())->getPositionRegion() + getPosition() * getParent()->getRotation(); - mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); - } - else - { - mPositionRegion = getPosition(); - mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); - } - } -} - -const LLVector3d LLViewerObject::getPositionGlobal() const -{ - if(mRegionp) - { - LLVector3d position_global = mRegionp->getPosGlobalFromRegion(getPositionRegion()); - - if (isAttachment()) - { - position_global = gAgent.getPosGlobalFromAgent(getRenderPosition()); - } - return position_global; - } - else - { - LLVector3d position_global(getPosition()); - return position_global; - } -} - -const LLVector3 &LLViewerObject::getPositionAgent() const -{ - if (mRegionp) - { - if (mDrawable.notNull() && (!mDrawable->isRoot() && getParent())) - { - // Don't return cached position if you have a parent, recalc (until all dirtying is done correctly. - LLVector3 position_region; - position_region = ((LLViewerObject *)getParent())->getPositionRegion() + getPosition() * getParent()->getRotation(); - mPositionAgent = mRegionp->getPosAgentFromRegion(position_region); - } - else - { - mPositionAgent = mRegionp->getPosAgentFromRegion(getPosition()); - } - } - return mPositionAgent; -} - -const LLVector3 &LLViewerObject::getPositionRegion() const -{ - if (!isRoot()) - { - LLViewerObject *parent = (LLViewerObject *)getParent(); - mPositionRegion = parent->getPositionRegion() + (getPosition() * parent->getRotation()); - } - else - { - mPositionRegion = getPosition(); - } - - return mPositionRegion; -} - -const LLVector3 LLViewerObject::getPositionEdit() const -{ - if (isRootEdit()) - { - return getPosition(); - } - else - { - LLViewerObject *parent = (LLViewerObject *)getParent(); - LLVector3 position_edit = parent->getPositionEdit() + getPosition() * parent->getRotationEdit(); - return position_edit; - } -} - -const LLVector3 LLViewerObject::getRenderPosition() const -{ - if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED)) - { - LLVOAvatar* avatar = getAvatar(); - if (avatar) - { - return avatar->getPositionAgent(); - } - } - - if (mDrawable.isNull() || mDrawable->getGeneration() < 0) - { - return getPositionAgent(); - } - else - { - return mDrawable->getPositionAgent(); - } -} - -const LLVector3 LLViewerObject::getPivotPositionAgent() const -{ - return getRenderPosition(); -} - -const LLQuaternion LLViewerObject::getRenderRotation() const -{ - LLQuaternion ret; - if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED)) - { - return ret; - } - - if (mDrawable.isNull() || mDrawable->isStatic()) - { - ret = getRotationEdit(); - } - else - { - if (!mDrawable->isRoot()) - { - ret = getRotation() * LLQuaternion(mDrawable->getParent()->getWorldMatrix()); - } - else - { - ret = LLQuaternion(mDrawable->getWorldMatrix()); - } - } - - return ret; -} - -const LLMatrix4 LLViewerObject::getRenderMatrix() const -{ - return mDrawable->getWorldMatrix(); -} - -const LLQuaternion LLViewerObject::getRotationRegion() const -{ - LLQuaternion global_rotation = getRotation(); - if (!((LLXform *)this)->isRoot()) - { - global_rotation = global_rotation * getParent()->getRotation(); - } - return global_rotation; -} - -const LLQuaternion LLViewerObject::getRotationEdit() const -{ - LLQuaternion global_rotation = getRotation(); - if (!((LLXform *)this)->isRootEdit()) - { - global_rotation = global_rotation * getParent()->getRotation(); - } - return global_rotation; -} - -void LLViewerObject::setPositionAbsoluteGlobal( const LLVector3d &pos_global, BOOL damped ) -{ - if (isAttachment()) - { - LLVector3 new_pos = mRegionp->getPosRegionFromGlobal(pos_global); - if (isRootEdit()) - { - new_pos -= mDrawable->mXform.getParent()->getWorldPosition(); - LLQuaternion world_rotation = mDrawable->mXform.getParent()->getWorldRotation(); - new_pos = new_pos * ~world_rotation; - } - else - { - LLViewerObject* parentp = (LLViewerObject*)getParent(); - new_pos -= parentp->getPositionAgent(); - new_pos = new_pos * ~parentp->getRotationRegion(); - } - LLViewerObject::setPosition(new_pos); - - if (mParent && ((LLViewerObject*)mParent)->isAvatar()) - { - // we have changed the position of an attachment, so we need to clamp it - LLVOAvatar *avatar = (LLVOAvatar*)mParent; - - avatar->clampAttachmentPositions(); - } - } - else - { - if( isRoot() ) - { - setPositionRegion(mRegionp->getPosRegionFromGlobal(pos_global)); - } - else - { - // the relative position with the parent is not constant - LLViewerObject* parent = (LLViewerObject *)getParent(); - //RN: this assumes we are only calling this function from the edit tools - gPipeline.updateMoveNormalAsync(parent->mDrawable); - - LLVector3 pos_local = mRegionp->getPosRegionFromGlobal(pos_global) - parent->getPositionRegion(); - pos_local = pos_local * ~parent->getRotationRegion(); - LLViewerObject::setPosition( pos_local ); - } - } - //RN: assumes we always want to snap the object when calling this function - gPipeline.updateMoveNormalAsync(mDrawable); -} - -void LLViewerObject::setPosition(const LLVector3 &pos, BOOL damped) -{ - if (getPosition() != pos) - { - setChanged(TRANSLATED | SILHOUETTE); - } - - LLXform::setPosition(pos); - updateDrawable(damped); - if (isRoot()) - { - // position caches need to be up to date on root objects - updatePositionCaches(); - } -} - -void LLViewerObject::setPositionGlobal(const LLVector3d &pos_global, BOOL damped) -{ - if (isAttachment()) - { - if (isRootEdit()) - { - LLVector3 newPos = mRegionp->getPosRegionFromGlobal(pos_global); - newPos = newPos - mDrawable->mXform.getParent()->getWorldPosition(); - - LLQuaternion invWorldRotation = mDrawable->mXform.getParent()->getWorldRotation(); - invWorldRotation.transQuat(); - - newPos = newPos * invWorldRotation; - LLViewerObject::setPosition(newPos); - } - else - { - // assumes parent is root editable (root of attachment) - LLVector3 newPos = mRegionp->getPosRegionFromGlobal(pos_global); - newPos = newPos - mDrawable->mXform.getParent()->getWorldPosition(); - LLVector3 delta_pos = newPos - getPosition(); - - LLQuaternion invRotation = mDrawable->getRotation(); - invRotation.transQuat(); - - delta_pos = delta_pos * invRotation; - - // *FIX: is this right? Shouldn't we be calling the - // LLViewerObject version of setPosition? - LLVector3 old_pos = mDrawable->mXform.getParent()->getPosition(); - mDrawable->mXform.getParent()->setPosition(old_pos + delta_pos); - setChanged(TRANSLATED | SILHOUETTE); - } - if (mParent && ((LLViewerObject*)mParent)->isAvatar()) - { - // we have changed the position of an attachment, so we need to clamp it - LLVOAvatar *avatar = (LLVOAvatar*)mParent; - - avatar->clampAttachmentPositions(); - } - } - else - { - if (isRoot()) - { - setPositionRegion(mRegionp->getPosRegionFromGlobal(pos_global)); - } - else - { - // the relative position with the parent is constant, but the parent's position needs to be changed - LLVector3d position_offset; - position_offset.setVec(getPosition()*getParent()->getRotation()); - LLVector3d new_pos_global = pos_global - position_offset; - ((LLViewerObject *)getParent())->setPositionGlobal(new_pos_global); - } - } - updateDrawable(damped); -} - - -void LLViewerObject::setPositionParent(const LLVector3 &pos_parent, BOOL damped) -{ - // Set position relative to parent, if no parent, relative to region - if (!isRoot()) - { - LLViewerObject::setPosition(pos_parent, damped); - //updateDrawable(damped); - } - else - { - setPositionRegion(pos_parent, damped); - } -} - -void LLViewerObject::setPositionRegion(const LLVector3 &pos_region, BOOL damped) -{ - if (!isRootEdit()) - { - LLViewerObject* parent = (LLViewerObject*) getParent(); - LLViewerObject::setPosition((pos_region-parent->getPositionRegion())*~parent->getRotationRegion()); - } - else - { - LLViewerObject::setPosition(pos_region); - mPositionRegion = pos_region; - mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); - } -} - -void LLViewerObject::setPositionAgent(const LLVector3 &pos_agent, BOOL damped) -{ - LLVector3 pos_region = getRegion()->getPosRegionFromAgent(pos_agent); - setPositionRegion(pos_region, damped); -} - -// identical to setPositionRegion() except it checks for child-joints -// and doesn't also move the joint-parent -// TODO -- implement similar intelligence for joint-parents toward -// their joint-children -void LLViewerObject::setPositionEdit(const LLVector3 &pos_edit, BOOL damped) -{ - if (!isRootEdit()) - { - // the relative position with the parent is constant, but the parent's position needs to be changed - LLVector3 position_offset = getPosition() * getParent()->getRotation(); - - ((LLViewerObject *)getParent())->setPositionEdit(pos_edit - position_offset); - updateDrawable(damped); - } - else if (isJointChild()) - { - // compute new parent-relative position - LLViewerObject *parent = (LLViewerObject *) getParent(); - LLQuaternion inv_parent_rot = parent->getRotation(); - inv_parent_rot.transQuat(); - LLVector3 pos_parent = (pos_edit - parent->getPositionRegion()) * inv_parent_rot; - LLViewerObject::setPosition(pos_parent, damped); - } - else - { - LLViewerObject::setPosition(pos_edit, damped); - mPositionRegion = pos_edit; - mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); - } -} - - -LLViewerObject* LLViewerObject::getRootEdit() const -{ - const LLViewerObject* root = this; - while (root->mParent - && !(root->mJointInfo - || ((LLViewerObject*)root->mParent)->isAvatar()) ) - { - root = (LLViewerObject*)root->mParent; - } - return (LLViewerObject*)root; -} - - -BOOL LLViewerObject::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, - S32 face, - BOOL pick_transparent, - S32* face_hit, - LLVector3* intersection, - LLVector2* tex_coord, - LLVector3* normal, - LLVector3* bi_normal) -{ - return false; -} - -BOOL LLViewerObject::lineSegmentBoundingBox(const LLVector3& start, const LLVector3& end) -{ - if (mDrawable.isNull() || mDrawable->isDead()) - { - return FALSE; - } - - const LLVector4a* ext = mDrawable->getSpatialExtents(); - - //VECTORIZE THIS - LLVector4a center; - center.setAdd(ext[1], ext[0]); - center.mul(0.5f); - LLVector4a size; - size.setSub(ext[1], ext[0]); - size.mul(0.5f); - - LLVector4a starta, enda; - starta.load3(start.mV); - enda.load3(end.mV); - - return LLLineSegmentBoxIntersect(starta, enda, center, size); -} - -U8 LLViewerObject::getMediaType() const -{ - if (mMedia) - { - return mMedia->mMediaType; - } - else - { - return LLViewerObject::MEDIA_NONE; - } -} - -void LLViewerObject::setMediaType(U8 media_type) -{ - if (!mMedia) - { - // TODO what if we don't have a media pointer? - } - else if (mMedia->mMediaType != media_type) - { - mMedia->mMediaType = media_type; - - // TODO: update materials with new image - } -} - -std::string LLViewerObject::getMediaURL() const -{ - if (mMedia) - { - return mMedia->mMediaURL; - } - else - { - return std::string(); - } -} - -void LLViewerObject::setMediaURL(const std::string& media_url) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - - if (!mMedia) - { - mMedia = new LLViewerObjectMedia; - mMedia->mMediaURL = media_url; - mMedia->mPassedWhitelist = FALSE; - - // TODO: update materials with new image - } - else if (mMedia->mMediaURL != media_url) - { - mMedia->mMediaURL = media_url; - mMedia->mPassedWhitelist = FALSE; - - // TODO: update materials with new image - } -} - -BOOL LLViewerObject::getMediaPassedWhitelist() const -{ - if (mMedia) - { - return mMedia->mPassedWhitelist; - } - else - { - return FALSE; - } -} - -void LLViewerObject::setMediaPassedWhitelist(BOOL passed) -{ - if (mMedia) - { - mMedia->mPassedWhitelist = passed; - } -} - -BOOL LLViewerObject::setMaterial(const U8 material) -{ - BOOL res = LLPrimitive::setMaterial(material); - if (res) - { - setChanged(TEXTURE); - } - return res; -} - -void LLViewerObject::setNumTEs(const U8 num_tes) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - - U32 i; - if (num_tes != getNumTEs()) - { - if (num_tes) - { - LLPointer *new_images; - new_images = new LLPointer[num_tes]; - for (i = 0; i < num_tes; i++) - { - if (i < getNumTEs()) - { - new_images[i] = mTEImages[i]; - } - else if (getNumTEs()) - { - new_images[i] = mTEImages[getNumTEs()-1]; - } - else - { - new_images[i] = NULL; - } - } - - deleteTEImages(); - - mTEImages = new_images; - } - else - { - deleteTEImages(); - } - LLPrimitive::setNumTEs(num_tes); - setChanged(TEXTURE); - - if (mDrawable.notNull()) - { - gPipeline.markTextured(mDrawable); - } - } -} - -void LLViewerObject::sendMaterialUpdate() const -{ - LLViewerRegion* regionp = getRegion(); - if(!regionp) return; - gMessageSystem->newMessageFast(_PREHASH_ObjectMaterial); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); - gMessageSystem->addU8Fast(_PREHASH_Material, getMaterial() ); - gMessageSystem->sendReliable( regionp->getHost() ); - -} - -// formerly send_object_rotation -void LLViewerObject::sendRotationUpdate() const -{ - LLViewerRegion* regionp = getRegion(); - if(!regionp) return; - gMessageSystem->newMessageFast(_PREHASH_ObjectRotation); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID); - gMessageSystem->addQuatFast(_PREHASH_Rotation, getRotationEdit()); - //llinfos << "Sent rotation " << getRotationEdit() << llendl; - gMessageSystem->sendReliable( regionp->getHost() ); -} - -/* Obsolete, we use MultipleObjectUpdate instead -//// formerly send_object_position_global -//void LLViewerObject::sendPositionUpdate() const -//{ -// gMessageSystem->newMessageFast(_PREHASH_ObjectPosition); -// gMessageSystem->nextBlockFast(_PREHASH_AgentData); -// gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); -// gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -// gMessageSystem->nextBlockFast(_PREHASH_ObjectData); -// gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); -// gMessageSystem->addVector3Fast(_PREHASH_Position, getPositionRegion()); -// LLViewerRegion* regionp = getRegion(); -// gMessageSystem->sendReliable(regionp->getHost()); -//} -*/ - -//formerly send_object_shape(LLViewerObject *object) -void LLViewerObject::sendShapeUpdate() -{ - gMessageSystem->newMessageFast(_PREHASH_ObjectShape); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); - - LLVolumeMessage::packVolumeParams(&getVolume()->getParams(), gMessageSystem); - - LLViewerRegion *regionp = getRegion(); - gMessageSystem->sendReliable( regionp->getHost() ); -} - - -void LLViewerObject::sendTEUpdate() const -{ - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ObjectImage); - - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); - if (mMedia) - { - msg->addString("MediaURL", mMedia->mMediaURL); - } - else - { - msg->addString("MediaURL", NULL); - } - - // TODO send media type - - packTEMessage(msg); - - LLViewerRegion *regionp = getRegion(); - msg->sendReliable( regionp->getHost() ); -} - -void LLViewerObject::setTE(const U8 te, const LLTextureEntry &texture_entry) -{ - LLPrimitive::setTE(te, texture_entry); -// This doesn't work, don't get any textures. -// if (mDrawable.notNull() && mDrawable->isVisible()) -// { - const LLUUID& image_id = getTE(te)->getID(); - mTEImages[te] = LLViewerTextureManager::getFetchedTexture(image_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); -// } -} - -void LLViewerObject::setTEImage(const U8 te, LLViewerTexture *imagep) -{ - if (mTEImages[te] != imagep) - { - mTEImages[te] = imagep; - LLPrimitive::setTETexture(te, imagep->getID()); - setChanged(TEXTURE); - if (mDrawable.notNull()) - { - gPipeline.markTextured(mDrawable); - } - } -} - - -S32 LLViewerObject::setTETextureCore(const U8 te, const LLUUID& uuid, LLHost host) -{ - S32 retval = 0; - if (uuid != getTE(te)->getID() || - uuid == LLUUID::null) - { - retval = LLPrimitive::setTETexture(te, uuid); - mTEImages[te] = LLViewerTextureManager::getFetchedTexture(uuid, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); - setChanged(TEXTURE); - if (mDrawable.notNull()) - { - gPipeline.markTextured(mDrawable); - } - } - return retval; -} - - -void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image) -{ - if(index < 0 || index >= getNumTEs()) - { - return ; - } - mTEImages[index] = new_image ; -} - -S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid) -{ - // Invalid host == get from the agent's sim - return setTETextureCore(te, uuid, LLHost::invalid); -} - - -S32 LLViewerObject::setTEColor(const U8 te, const LLColor3& color) -{ - return setTEColor(te, LLColor4(color)); -} - -S32 LLViewerObject::setTEColor(const U8 te, const LLColor4& color) -{ - S32 retval = 0; - const LLTextureEntry *tep = getTE(te); - if (!tep) - { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; - } - else if (color != tep->getColor()) - { - retval = LLPrimitive::setTEColor(te, color); - if (mDrawable.notNull() && retval) - { - // These should only happen on updates which are not the initial update. - dirtyMesh(); - } - } - return retval; -} - -S32 LLViewerObject::setTEBumpmap(const U8 te, const U8 bump) -{ - S32 retval = 0; - const LLTextureEntry *tep = getTE(te); - if (!tep) - { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; - } - else if (bump != tep->getBumpmap()) - { - retval = LLPrimitive::setTEBumpmap(te, bump); - setChanged(TEXTURE); - if (mDrawable.notNull() && retval) - { - gPipeline.markTextured(mDrawable); - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); - } - } - return retval; -} - -S32 LLViewerObject::setTETexGen(const U8 te, const U8 texgen) -{ - S32 retval = 0; - const LLTextureEntry *tep = getTE(te); - if (!tep) - { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; - } - else if (texgen != tep->getTexGen()) - { - retval = LLPrimitive::setTETexGen(te, texgen); - setChanged(TEXTURE); - } - return retval; -} - -S32 LLViewerObject::setTEMediaTexGen(const U8 te, const U8 media) -{ - S32 retval = 0; - const LLTextureEntry *tep = getTE(te); - if (!tep) - { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; - } - else if (media != tep->getMediaTexGen()) - { - retval = LLPrimitive::setTEMediaTexGen(te, media); - setChanged(TEXTURE); - } - return retval; -} - -S32 LLViewerObject::setTEShiny(const U8 te, const U8 shiny) -{ - S32 retval = 0; - const LLTextureEntry *tep = getTE(te); - if (!tep) - { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; - } - else if (shiny != tep->getShiny()) - { - retval = LLPrimitive::setTEShiny(te, shiny); - setChanged(TEXTURE); - } - return retval; -} - -S32 LLViewerObject::setTEFullbright(const U8 te, const U8 fullbright) -{ - S32 retval = 0; - const LLTextureEntry *tep = getTE(te); - if (!tep) - { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; - } - else if (fullbright != tep->getFullbright()) - { - retval = LLPrimitive::setTEFullbright(te, fullbright); - setChanged(TEXTURE); - if (mDrawable.notNull() && retval) - { - gPipeline.markTextured(mDrawable); - } - } - return retval; -} - - -S32 LLViewerObject::setTEMediaFlags(const U8 te, const U8 media_flags) -{ - // this might need work for media type - S32 retval = 0; - const LLTextureEntry *tep = getTE(te); - if (!tep) - { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; - } - else if (media_flags != tep->getMediaFlags()) - { - retval = LLPrimitive::setTEMediaFlags(te, media_flags); - setChanged(TEXTURE); - if (mDrawable.notNull() && retval) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, TRUE); - gPipeline.markTextured(mDrawable); - // JC - probably only need this if changes texture coords - //gPipeline.markRebuild(mDrawable); - } - } - return retval; -} - -S32 LLViewerObject::setTEGlow(const U8 te, const F32 glow) -{ - S32 retval = 0; - const LLTextureEntry *tep = getTE(te); - if (!tep) - { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; - } - else if (glow != tep->getGlow()) - { - retval = LLPrimitive::setTEGlow(te, glow); - setChanged(TEXTURE); - if (mDrawable.notNull() && retval) - { - gPipeline.markTextured(mDrawable); - } - } - return retval; -} - - -S32 LLViewerObject::setTEScale(const U8 te, const F32 s, const F32 t) -{ - S32 retval = 0; - retval = LLPrimitive::setTEScale(te, s, t); - setChanged(TEXTURE); - if (mDrawable.notNull() && retval) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); - } - return retval; -} - -S32 LLViewerObject::setTEScaleS(const U8 te, const F32 s) -{ - S32 retval = LLPrimitive::setTEScaleS(te, s); - if (mDrawable.notNull() && retval) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); - } - - return retval; -} - -S32 LLViewerObject::setTEScaleT(const U8 te, const F32 t) -{ - S32 retval = LLPrimitive::setTEScaleT(te, t); - if (mDrawable.notNull() && retval) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); - } - - return retval; -} - -S32 LLViewerObject::setTEOffset(const U8 te, const F32 s, const F32 t) -{ - S32 retval = LLPrimitive::setTEOffset(te, s, t); - if (mDrawable.notNull() && retval) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); - } - return retval; -} - -S32 LLViewerObject::setTEOffsetS(const U8 te, const F32 s) -{ - S32 retval = LLPrimitive::setTEOffsetS(te, s); - if (mDrawable.notNull() && retval) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); - } - - return retval; -} - -S32 LLViewerObject::setTEOffsetT(const U8 te, const F32 t) -{ - S32 retval = LLPrimitive::setTEOffsetT(te, t); - if (mDrawable.notNull() && retval) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); - } - - return retval; -} - -S32 LLViewerObject::setTERotation(const U8 te, const F32 r) -{ - S32 retval = LLPrimitive::setTERotation(te, r); - if (mDrawable.notNull() && retval) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); - } - return retval; -} - - -LLViewerTexture *LLViewerObject::getTEImage(const U8 face) const -{ -// llassert(mTEImages); - - if (face < getNumTEs()) - { - LLViewerTexture* image = mTEImages[face]; - if (image) - { - return image; - } - else - { - return (LLViewerTexture*)(LLViewerFetchedTexture::sDefaultImagep); - } - } - - llerrs << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << llendl; - - return NULL; -} - - -void LLViewerObject::fitFaceTexture(const U8 face) -{ - llinfos << "fitFaceTexture not implemented" << llendl; -} - - -LLBBox LLViewerObject::getBoundingBoxAgent() const -{ - LLVector3 position_agent; - LLQuaternion rot; - LLViewerObject* avatar_parent = NULL; - LLViewerObject* root_edit = (LLViewerObject*)getRootEdit(); - if (root_edit) - { - avatar_parent = (LLViewerObject*)root_edit->getParent(); - } - - if (avatar_parent && avatar_parent->isAvatar() && - root_edit && root_edit->mDrawable.notNull() && root_edit->mDrawable->getXform()->getParent()) - { - LLXform* parent_xform = root_edit->mDrawable->getXform()->getParent(); - position_agent = (getPositionEdit() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); - rot = getRotationEdit() * parent_xform->getWorldRotation(); - } - else - { - position_agent = getPositionAgent(); - rot = getRotationRegion(); - } - - return LLBBox( position_agent, rot, getScale() * -0.5f, getScale() * 0.5f ); -} - -U32 LLViewerObject::getNumVertices() const -{ - U32 num_vertices = 0; - if (mDrawable.notNull()) - { - S32 i, num_faces; - num_faces = mDrawable->getNumFaces(); - for (i = 0; i < num_faces; i++) - { - num_vertices += mDrawable->getFace(i)->getGeomCount(); - } - } - return num_vertices; -} - -U32 LLViewerObject::getNumIndices() const -{ - U32 num_indices = 0; - if (mDrawable.notNull()) - { - S32 i, num_faces; - num_faces = mDrawable->getNumFaces(); - for (i = 0; i < num_faces; i++) - { - num_indices += mDrawable->getFace(i)->getIndicesCount(); - } - } - return num_indices; -} - -// Find the number of instances of this object's inventory that are of the given type -S32 LLViewerObject::countInventoryContents(LLAssetType::EType type) -{ - S32 count = 0; - if( mInventory ) - { - LLInventoryObject::object_list_t::const_iterator it = mInventory->begin(); - LLInventoryObject::object_list_t::const_iterator end = mInventory->end(); - for( ; it != end ; ++it ) - { - if( (*it)->getType() == type ) - { - ++count; - } - } - } - return count; -} - - -void LLViewerObject::setCanSelect(BOOL canSelect) -{ - mbCanSelect = canSelect; - for (child_list_t::iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* child = *iter; - child->mbCanSelect = canSelect; - } -} - -void LLViewerObject::setDebugText(const std::string &utf8text) -{ - if (utf8text.empty() && !mText) - { - return; - } - - if (!mText) - { - mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); - mText->setFont(LLFontGL::getFontSansSerif()); - mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); - mText->setMaxLines(-1); - mText->setSourceObject(this); - mText->setOnHUDAttachment(isHUDAttachment()); - } - mText->setColor(LLColor4::white); - mText->setString(utf8text); - mText->setZCompare(FALSE); - mText->setDoFade(FALSE); - updateText(); -} - -void LLViewerObject::setIcon(LLViewerTexture* icon_image) -{ - if (!mIcon) - { - mIcon = (LLHUDIcon *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_ICON); - mIcon->setSourceObject(this); - mIcon->setImage(icon_image); - // *TODO: make this user configurable - mIcon->setScale(0.03f); - } - else - { - mIcon->restartLifeTimer(); - } -} - -void LLViewerObject::clearIcon() -{ - if (mIcon) - { - mIcon = NULL; - } -} - -LLViewerObject* LLViewerObject::getSubParent() -{ - if (isJointChild()) - { - return this; - } - return (LLViewerObject*) getParent(); -} - -const LLViewerObject* LLViewerObject::getSubParent() const -{ - if (isJointChild()) - { - return this; - } - return (const LLViewerObject*) getParent(); -} - -BOOL LLViewerObject::isOnMap() -{ - return mOnMap; -} - - -void LLViewerObject::updateText() -{ - if (!isDead()) - { - if (mText.notNull()) - { - LLVector3 up_offset(0,0,0); - up_offset.mV[2] = getScale().mV[VZ]*0.6f; - - if (mDrawable.notNull()) - { - mText->setPositionAgent(getRenderPosition() + up_offset); - } - else - { - mText->setPositionAgent(getPositionAgent() + up_offset); - } - } - } -} - -LLVOAvatar* LLViewerObject::asAvatar() -{ - return NULL; -} - -BOOL LLViewerObject::isParticleSource() const -{ - return !mPartSourcep.isNull() && !mPartSourcep->isDead(); -} - -void LLViewerObject::setParticleSource(const LLPartSysData& particle_parameters, const LLUUID& owner_id) -{ - if (mPartSourcep) - { - deleteParticleSource(); - } - - LLPointer pss = LLViewerPartSourceScript::createPSS(this, particle_parameters); - mPartSourcep = pss; - - if (mPartSourcep) - { - mPartSourcep->setOwnerUUID(owner_id); - - if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID) - { - LLViewerTexture* image; - if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null) - { - image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.tga"); - } - else - { - image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID); - } - mPartSourcep->setImage(image); - } - } - LLViewerPartSim::getInstance()->addPartSource(pss); -} - -void LLViewerObject::unpackParticleSource(const S32 block_num, const LLUUID& owner_id) -{ - if (!mPartSourcep.isNull() && mPartSourcep->isDead()) - { - mPartSourcep = NULL; - } - if (mPartSourcep) - { - // If we've got one already, just update the existing source (or remove it) - if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep, block_num)) - { - mPartSourcep->setDead(); - mPartSourcep = NULL; - } - } - else - { - LLPointer pss = LLViewerPartSourceScript::unpackPSS(this, NULL, block_num); - //If the owner is muted, don't create the system - if(LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagParticles)) return; - - // We need to be able to deal with a particle source that hasn't changed, but still got an update! - if (pss) - { -// llinfos << "Making particle system with owner " << owner_id << llendl; - pss->setOwnerUUID(owner_id); - mPartSourcep = pss; - LLViewerPartSim::getInstance()->addPartSource(pss); - } - } - if (mPartSourcep) - { - if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID) - { - LLViewerTexture* image; - if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null) - { - image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c"); - } - else - { - image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID); - } - mPartSourcep->setImage(image); - } - } -} - -void LLViewerObject::unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_id) -{ - if (!mPartSourcep.isNull() && mPartSourcep->isDead()) - { - mPartSourcep = NULL; - } - if (mPartSourcep) - { - // If we've got one already, just update the existing source (or remove it) - if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep, dp)) - { - mPartSourcep->setDead(); - mPartSourcep = NULL; - } - } - else - { - LLPointer pss = LLViewerPartSourceScript::unpackPSS(this, NULL, dp); - //If the owner is muted, don't create the system - if(LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagParticles)) return; - // We need to be able to deal with a particle source that hasn't changed, but still got an update! - if (pss) - { -// llinfos << "Making particle system with owner " << owner_id << llendl; - pss->setOwnerUUID(owner_id); - mPartSourcep = pss; - LLViewerPartSim::getInstance()->addPartSource(pss); - } - } - if (mPartSourcep) - { - if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID) - { - LLViewerTexture* image; - if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null) - { - image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c"); - } - else - { - image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID); - } - mPartSourcep->setImage(image); - } - } -} - -void LLViewerObject::deleteParticleSource() -{ - if (mPartSourcep.notNull()) - { - mPartSourcep->setDead(); - mPartSourcep = NULL; - } -} - -// virtual -void LLViewerObject::updateDrawable(BOOL force_damped) -{ - if (mDrawable.notNull() && - !mDrawable->isState(LLDrawable::ON_MOVE_LIST) && - isChanged(MOVED)) - { - BOOL damped_motion = - !isChanged(SHIFTED) && // not shifted between regions this frame and... - ( force_damped || // ...forced into damped motion by application logic or... - ( !isSelected() && // ...not selected and... - ( mDrawable->isRoot() || // ... is root or ... - (getParent() && !((LLViewerObject*)getParent())->isSelected())// ... parent is not selected and ... - ) && - getPCode() == LL_PCODE_VOLUME && // ...is a volume object and... - getVelocity().isExactlyZero() && // ...is not moving physically and... - mDrawable->getGeneration() != -1 // ...was not created this frame. - ) - ); - gPipeline.markMoved(mDrawable, damped_motion); - } - clearChanged(SHIFTED); -} - -// virtual, overridden by LLVOVolume -F32 LLViewerObject::getVObjRadius() const -{ - return mDrawable.notNull() ? mDrawable->getRadius() : 0.f; -} - -void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const U8 flags) -{ - if (!gAudiop) - { - return; - } - - if (audio_uuid.isNull()) - { - if (!mAudioSourcep) - { - return; - } - if (mAudioSourcep->isLoop() && !mAudioSourcep->hasPendingPreloads()) - { - // We don't clear the sound if it's a loop, it'll go away on its own. - // At least, this appears to be how the scripts work. - // The attached sound ID is set to NULL to avoid it playing back when the - // object rezzes in on non-looping sounds. - //llinfos << "Clearing attached sound " << mAudioSourcep->getCurrentData()->getID() << llendl; - gAudiop->cleanupAudioSource(mAudioSourcep); - mAudioSourcep = NULL; - } - else if (flags & LL_SOUND_FLAG_STOP) - { - // Just shut off the sound - mAudioSourcep->play(LLUUID::null); - } - return; - } - if (flags & LL_SOUND_FLAG_LOOP - && mAudioSourcep && mAudioSourcep->isLoop() && mAudioSourcep->getCurrentData() - && mAudioSourcep->getCurrentData()->getID() == audio_uuid) - { - //llinfos << "Already playing this sound on a loop, ignoring" << llendl; - return; - } - - // don't clean up before previous sound is done. Solves: SL-33486 - if ( mAudioSourcep && mAudioSourcep->isDone() ) - { - gAudiop->cleanupAudioSource(mAudioSourcep); - mAudioSourcep = NULL; - } - - if (mAudioSourcep && mAudioSourcep->isMuted() && - mAudioSourcep->getCurrentData() && mAudioSourcep->getCurrentData()->getID() == audio_uuid) - { - //llinfos << "Already having this sound as muted sound, ignoring" << llendl; - return; - } - - getAudioSource(owner_id); - - if (mAudioSourcep) - { - BOOL queue = flags & LL_SOUND_FLAG_QUEUE; - mAudioGain = gain; - mAudioSourcep->setGain(gain); - mAudioSourcep->setLoop(flags & LL_SOUND_FLAG_LOOP); - mAudioSourcep->setSyncMaster(flags & LL_SOUND_FLAG_SYNC_MASTER); - mAudioSourcep->setSyncSlave(flags & LL_SOUND_FLAG_SYNC_SLAVE); - mAudioSourcep->setQueueSounds(queue); - if(!queue) // stop any current sound first to avoid "farts of doom" (SL-1541) -MG - { - mAudioSourcep->play(LLUUID::null); - } - - // Play this sound if region maturity permits - if( gAgent.canAccessMaturityAtGlobal(this->getPositionGlobal()) ) - { - //llinfos << "Playing attached sound " << audio_uuid << llendl; - mAudioSourcep->play(audio_uuid); - } - } -} - -LLAudioSource *LLViewerObject::getAudioSource(const LLUUID& owner_id) -{ - if (!mAudioSourcep) - { - // Arbitrary low gain for a sound that's not playing. - // This is used for sound preloads, for example. - LLAudioSourceVO *asvop = new LLAudioSourceVO(mID, owner_id, 0.01f, this); - - mAudioSourcep = asvop; - if(gAudiop) gAudiop->addAudioSource(asvop); - } - - return mAudioSourcep; -} - -void LLViewerObject::adjustAudioGain(const F32 gain) -{ - if (!gAudiop) - { - return; - } - if (mAudioSourcep) - { - mAudioGain = gain; - mAudioSourcep->setGain(mAudioGain); - } -} - -//---------------------------------------------------------------------------- - -bool LLViewerObject::unpackParameterEntry(U16 param_type, LLDataPacker *dp) -{ - ExtraParameter* param = getExtraParameterEntryCreate(param_type); - if (param) - { - param->data->unpack(*dp); - param->in_use = TRUE; - parameterChanged(param_type, param->data, TRUE, false); - return true; - } - else - { - return false; - } -} - -LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 param_type) -{ - LLNetworkData* new_block = NULL; - switch (param_type) - { - case LLNetworkData::PARAMS_FLEXIBLE: - { - new_block = new LLFlexibleObjectData(); - break; - } - case LLNetworkData::PARAMS_LIGHT: - { - new_block = new LLLightParams(); - break; - } - case LLNetworkData::PARAMS_SCULPT: - { - new_block = new LLSculptParams(); - break; - } - case LLNetworkData::PARAMS_LIGHT_IMAGE: - { - new_block = new LLLightImageParams(); - break; - } - default: - { - llinfos << "Unknown param type." << llendl; - break; - } - }; - - if (new_block) - { - ExtraParameter* new_entry = new ExtraParameter; - new_entry->data = new_block; - new_entry->in_use = false; // not in use yet - mExtraParameterList[param_type] = new_entry; - return new_entry; - } - return NULL; -} - -LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntry(U16 param_type) const -{ - std::map::const_iterator itor = mExtraParameterList.find(param_type); - if (itor != mExtraParameterList.end()) - { - return itor->second; - } - return NULL; -} - -LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntryCreate(U16 param_type) -{ - ExtraParameter* param = getExtraParameterEntry(param_type); - if (!param) - { - param = createNewParameterEntry(param_type); - } - return param; -} - -LLNetworkData* LLViewerObject::getParameterEntry(U16 param_type) const -{ - ExtraParameter* param = getExtraParameterEntry(param_type); - if (param) - { - return param->data; - } - else - { - return NULL; - } -} - -BOOL LLViewerObject::getParameterEntryInUse(U16 param_type) const -{ - ExtraParameter* param = getExtraParameterEntry(param_type); - if (param) - { - return param->in_use; - } - else - { - return FALSE; - } -} - -bool LLViewerObject::setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin) -{ - ExtraParameter* param = getExtraParameterEntryCreate(param_type); - if (param) - { - if (param->in_use && new_value == *(param->data)) - { - return false; - } - param->in_use = true; - param->data->copy(new_value); - parameterChanged(param_type, param->data, TRUE, local_origin); - return true; - } - else - { - return false; - } -} - -// Assumed to be called locally -// If in_use is TRUE, will crate a new extra parameter if none exists. -// Should always return true. -bool LLViewerObject::setParameterEntryInUse(U16 param_type, BOOL in_use, bool local_origin) -{ - ExtraParameter* param = getExtraParameterEntryCreate(param_type); - if (param && param->in_use != in_use) - { - param->in_use = in_use; - parameterChanged(param_type, param->data, in_use, local_origin); - return true; - } - return false; -} - -void LLViewerObject::parameterChanged(U16 param_type, bool local_origin) -{ - ExtraParameter* param = getExtraParameterEntry(param_type); - if (param) - { - parameterChanged(param_type, param->data, param->in_use, local_origin); - } -} - -void LLViewerObject::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin) -{ - if (local_origin) - { - LLViewerRegion* regionp = getRegion(); - if(!regionp) return; - - // Change happened on the viewer. Send the change up - U8 tmp[MAX_OBJECT_PARAMS_SIZE]; - LLDataPackerBinaryBuffer dpb(tmp, MAX_OBJECT_PARAMS_SIZE); - if (data->pack(dpb)) - { - U32 datasize = (U32)dpb.getCurrentSize(); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ObjectExtraParams); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); - - msg->addU16Fast(_PREHASH_ParamType, param_type); - msg->addBOOLFast(_PREHASH_ParamInUse, in_use); - - msg->addU32Fast(_PREHASH_ParamSize, datasize); - msg->addBinaryDataFast(_PREHASH_ParamData, tmp, datasize); - - msg->sendReliable( regionp->getHost() ); - } - else - { - llwarns << "Failed to send object extra parameters: " << param_type << llendl; - } - } -} - -void LLViewerObject::setDrawableState(U32 state, BOOL recursive) -{ - if (mDrawable) - { - mDrawable->setState(state); - } - if (recursive) - { - for (child_list_t::iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* child = *iter; - child->setDrawableState(state, recursive); - } - } -} - -void LLViewerObject::clearDrawableState(U32 state, BOOL recursive) -{ - if (mDrawable) - { - mDrawable->clearState(state); - } - if (recursive) - { - for (child_list_t::iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* child = *iter; - child->clearDrawableState(state, recursive); - } - } -} - -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// RN: these functions assume a 2-level hierarchy -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -// Owned by anyone? -BOOL LLViewerObject::permAnyOwner() const -{ - if (isRootEdit()) - { - return ((mFlags & FLAGS_OBJECT_ANY_OWNER) != 0); - } - else - { - return ((LLViewerObject*)getParent())->permAnyOwner(); - } -} -// Owned by this viewer? -BOOL LLViewerObject::permYouOwner() const -{ - if (isRootEdit()) - { -#ifdef HACKED_GODLIKE_VIEWER - return TRUE; -#else -# ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLGridManager::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) - { - return TRUE; - } -# endif - return ((mFlags & FLAGS_OBJECT_YOU_OWNER) != 0); -#endif - } - else - { - return ((LLViewerObject*)getParent())->permYouOwner(); - } -} - -// Owned by a group? -BOOL LLViewerObject::permGroupOwner() const -{ - if (isRootEdit()) - { - return ((mFlags & FLAGS_OBJECT_GROUP_OWNED) != 0); - } - else - { - return ((LLViewerObject*)getParent())->permGroupOwner(); - } -} - -// Can the owner edit -BOOL LLViewerObject::permOwnerModify() const -{ - if (isRootEdit()) - { -#ifdef HACKED_GODLIKE_VIEWER - return TRUE; -#else -# ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLGridManager::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) - { - return TRUE; - } -# endif - return ((mFlags & FLAGS_OBJECT_OWNER_MODIFY) != 0); -#endif - } - else - { - return ((LLViewerObject*)getParent())->permOwnerModify(); - } -} - -// Can edit -BOOL LLViewerObject::permModify() const -{ - if (isRootEdit()) - { -#ifdef HACKED_GODLIKE_VIEWER - return TRUE; -#else -# ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLGridManager::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) - { - return TRUE; - } -# endif - return ((mFlags & FLAGS_OBJECT_MODIFY) != 0); -#endif - } - else - { - return ((LLViewerObject*)getParent())->permModify(); - } -} - -// Can copy -BOOL LLViewerObject::permCopy() const -{ - if (isRootEdit()) - { -#ifdef HACKED_GODLIKE_VIEWER - return TRUE; -#else -# ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLGridManager::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) - { - return TRUE; - } -# endif - return ((mFlags & FLAGS_OBJECT_COPY) != 0); -#endif - } - else - { - return ((LLViewerObject*)getParent())->permCopy(); - } -} - -// Can move -BOOL LLViewerObject::permMove() const -{ - if (isRootEdit()) - { -#ifdef HACKED_GODLIKE_VIEWER - return TRUE; -#else -# ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLGridManager::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) - { - return TRUE; - } -# endif - return ((mFlags & FLAGS_OBJECT_MOVE) != 0); -#endif - } - else - { - return ((LLViewerObject*)getParent())->permMove(); - } -} - -// Can be transferred -BOOL LLViewerObject::permTransfer() const -{ - if (isRootEdit()) - { -#ifdef HACKED_GODLIKE_VIEWER - return TRUE; -#else -# ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLGridManager::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) - { - return TRUE; - } -# endif - return ((mFlags & FLAGS_OBJECT_TRANSFER) != 0); -#endif - } - else - { - return ((LLViewerObject*)getParent())->permTransfer(); - } -} - -// Can only open objects that you own, or that someone has -// given you modify rights to. JC -BOOL LLViewerObject::allowOpen() const -{ - return !flagInventoryEmpty() && (permYouOwner() || permModify()); -} - -LLViewerObject::LLInventoryCallbackInfo::~LLInventoryCallbackInfo() -{ - if (mListener) - { - mListener->clearVOInventoryListener(); - } -} - -void LLViewerObject::updateVolume(const LLVolumeParams& volume_params) -{ - if (setVolume(volume_params, 1)) // *FIX: magic number, ack! - { - // Transmit the update to the simulator - sendShapeUpdate(); - markForUpdate(TRUE); - } -} - -void LLViewerObject::markForUpdate(BOOL priority) -{ - if (mDrawable.notNull()) - { - gPipeline.markTextured(mDrawable); - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, priority); - } -} - -bool LLViewerObject::getIncludeInSearch() const -{ - return ((mFlags & FLAGS_INCLUDE_IN_SEARCH) != 0); -} - -void LLViewerObject::setIncludeInSearch(bool include_in_search) -{ - if (include_in_search) - { - mFlags |= FLAGS_INCLUDE_IN_SEARCH; - } - else - { - mFlags &= ~FLAGS_INCLUDE_IN_SEARCH; - } -} - -void LLViewerObject::setRegion(LLViewerRegion *regionp) -{ - if (!regionp) - { - llwarns << "viewer object set region to NULL" << llendl; - } - - mLatestRecvPacketID = 0; - mRegionp = regionp; - - for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) - { - LLViewerObject* child = *i; - child->setRegion(regionp); - } - - setChanged(MOVED | SILHOUETTE); - updateDrawable(FALSE); -} - -// virtual -void LLViewerObject::updateRegion(LLViewerRegion *regionp) -{ -// if (regionp) -// { -// F64 now = LLFrameTimer::getElapsedSeconds(); -// llinfos << "Updating to region " << regionp->getName() -// << ", ms since last update message: " << (F32)((now - mLastMessageUpdateSecs) * 1000.0) -// << ", ms since last interpolation: " << (F32)((now - mLastInterpUpdateSecs) * 1000.0) -// << llendl; -// } -} - - -bool LLViewerObject::specialHoverCursor() const -{ - return (mFlags & FLAGS_USE_PHYSICS) - || (mFlags & FLAGS_HANDLE_TOUCH) - || (mClickAction != 0); -} - -void LLViewerObject::updateFlags(BOOL physics_changed) -{ - LLViewerRegion* regionp = getRegion(); - if(!regionp) return; - gMessageSystem->newMessage("ObjectFlagUpdate"); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, getLocalID() ); - gMessageSystem->addBOOLFast(_PREHASH_UsePhysics, usePhysics() ); - gMessageSystem->addBOOL("IsTemporary", flagTemporaryOnRez() ); - gMessageSystem->addBOOL("IsPhantom", flagPhantom() ); - gMessageSystem->addBOOL("CastsShadows", flagCastShadows() ); - if (physics_changed) - { - gMessageSystem->nextBlock("ExtraPhysics"); - gMessageSystem->addU8("PhysicsShapeType", getPhysicsShapeType() ); - gMessageSystem->addF32("Density", getPhysicsDensity() ); - gMessageSystem->addF32("Friction", getPhysicsFriction() ); - gMessageSystem->addF32("Restitution", getPhysicsRestitution() ); - gMessageSystem->addF32("GravityMultiplier", getPhysicsGravity() ); - } - gMessageSystem->sendReliable( regionp->getHost() ); -} - -BOOL LLViewerObject::setFlags(U32 flags, BOOL state) -{ - BOOL setit = FALSE; - if (state) - { - if ((mFlags & flags) != flags) - { - mFlags |= flags; - setit = TRUE; - } - } - else - { - if ((mFlags & flags) != 0) - { - mFlags &= ~flags; - setit = TRUE; - } - } - - // BUG: Sometimes viewer physics and simulator physics get - // out of sync. To fix this, always send update to simulator. -// if (setit) - { - updateFlags(); - } - return setit; -} - -void LLViewerObject::setPhysicsShapeType(U8 type) -{ - mPhysicsShapeUnknown = false; - mPhysicsShapeType = type; - mCostStale = true; -} - -void LLViewerObject::setPhysicsGravity(F32 gravity) -{ - mPhysicsGravity = gravity; -} - -void LLViewerObject::setPhysicsFriction(F32 friction) -{ - mPhysicsFriction = friction; -} - -void LLViewerObject::setPhysicsDensity(F32 density) -{ - mPhysicsDensity = density; -} - -void LLViewerObject::setPhysicsRestitution(F32 restitution) -{ - mPhysicsRestitution = restitution; -} - -U8 LLViewerObject::getPhysicsShapeType() const -{ - if (mPhysicsShapeUnknown) - { - mPhysicsShapeUnknown = false; - gObjectList.updatePhysicsFlags(this); - } - - return mPhysicsShapeType; -} - -void LLViewerObject::applyAngularVelocity(F32 dt) -{ - //do target omega here - mRotTime += dt; - LLVector3 ang_vel = getAngularVelocity(); - F32 omega = ang_vel.magVecSquared(); - F32 angle = 0.0f; - LLQuaternion dQ; - if (omega > 0.00001f) - { - omega = sqrt(omega); - angle = omega * dt; - - ang_vel *= 1.f/omega; - - dQ.setQuat(angle, ang_vel); - - setRotation(getRotation()*dQ); - setChanged(MOVED | SILHOUETTE); - } -} - -void LLViewerObject::resetRot() -{ - mRotTime = 0.0f; -} - -U32 LLViewerObject::getPartitionType() const -{ - return LLViewerRegion::PARTITION_NONE; -} - -void LLViewerObject::dirtySpatialGroup(BOOL priority) const -{ - if (mDrawable) - { - LLSpatialGroup* group = mDrawable->getSpatialGroup(); - if (group) - { - group->dirtyGeom(); - gPipeline.markRebuild(group, priority); - } - } -} - -void LLViewerObject::dirtyMesh() -{ - if (mDrawable) - { - LLSpatialGroup* group = mDrawable->getSpatialGroup(); - if (group) - { - group->dirtyMesh(); - } - } -} - -F32 LLAlphaObject::getPartSize(S32 idx) -{ - return 0.f; -} - -// virtual -void LLStaticViewerObject::updateDrawable(BOOL force_damped) -{ - // Force an immediate rebuild on any update - if (mDrawable.notNull()) - { - mDrawable->updateXform(TRUE); - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); - } - clearChanged(SHIFTED); -} - -void LLViewerObject::saveUnselectedChildrenPosition(std::vector& positions) -{ - if(mChildList.empty() || !positions.empty()) - { - return ; - } - - for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* childp = *iter; - if (!childp->isSelected() && childp->mDrawable.notNull()) - { - positions.push_back(childp->getPositionEdit()); - } - } - - return ; -} - -void LLViewerObject::saveUnselectedChildrenRotation(std::vector& rotations) -{ - if(mChildList.empty()) - { - return ; - } - - for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* childp = *iter; - if (!childp->isSelected() && childp->mDrawable.notNull()) - { - rotations.push_back(childp->getRotationEdit()); - } - } - - return ; -} - -//counter-rotation -void LLViewerObject::resetChildrenRotationAndPosition(const std::vector& rotations, - const std::vector& positions) -{ - if(mChildList.empty()) - { - return ; - } - - S32 index = 0 ; - LLQuaternion inv_rotation = ~getRotationEdit() ; - LLVector3 offset = getPositionEdit() ; - for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* childp = *iter; - if (!childp->isSelected() && childp->mDrawable.notNull()) - { - if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR) - { - childp->setRotation(rotations[index] * inv_rotation); - childp->setPosition((positions[index] - offset) * inv_rotation); - LLManip::rebuild(childp); - } - else //avatar - { - LLVector3 reset_pos = (positions[index] - offset) * inv_rotation ; - LLQuaternion reset_rot = rotations[index] * inv_rotation ; - - ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); - ((LLVOAvatar*)childp)->mDrawable->mXform.setRotation(reset_rot) ; - - ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos, TRUE); - ((LLVOAvatar*)childp)->mDrawable->getVObj()->setRotation(reset_rot, TRUE) ; - - LLManip::rebuild(childp); - } - index++; - } - } - - return ; -} - -//counter-translation -void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplified) -{ - if(mChildList.empty()) - { - return ; - } - - LLVector3 child_offset; - if(simplified) //translation only, rotation matrix does not change - { - child_offset = offset * ~getRotation(); - } - else //rotation matrix might change too. - { - if (isAttachment() && mDrawable.notNull()) - { - LLXform* attachment_point_xform = mDrawable->getXform()->getParent(); - LLQuaternion parent_rotation = getRotation() * attachment_point_xform->getWorldRotation(); - child_offset = offset * ~parent_rotation; - } - else - { - child_offset = offset * ~getRenderRotation(); - } - } - - for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* childp = *iter; - if (!childp->isSelected() && childp->mDrawable.notNull()) - { - if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR) - { - childp->setPosition(childp->getPosition() + child_offset); - LLManip::rebuild(childp); - } - else //avatar - { - LLVector3 reset_pos = ((LLVOAvatar*)childp)->mDrawable->mXform.getPosition() + child_offset ; - - ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); - ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos); - - LLManip::rebuild(childp); - } - } - } - - return ; -} - -const LLUUID &LLViewerObject::getAttachmentItemID() const -{ - return mAttachmentItemID; -} - -void LLViewerObject::setAttachmentItemID(const LLUUID &id) -{ - mAttachmentItemID = id; -} - -EObjectUpdateType LLViewerObject::getLastUpdateType() const -{ - return mLastUpdateType; -} - -void LLViewerObject::setLastUpdateType(EObjectUpdateType last_update_type) -{ - mLastUpdateType = last_update_type; -} - -BOOL LLViewerObject::getLastUpdateCached() const -{ - return mLastUpdateCached; -} - -void LLViewerObject::setLastUpdateCached(BOOL last_update_cached) -{ - mLastUpdateCached = last_update_cached; -} - -const LLUUID &LLViewerObject::extractAttachmentItemID() -{ - LLUUID item_id = LLUUID::null; - LLNameValue* item_id_nv = getNVPair("AttachItemID"); - if( item_id_nv ) - { - const char* s = item_id_nv->getString(); - if( s ) - { - item_id.set(s); - } - } - setAttachmentItemID(item_id); - return getAttachmentItemID(); -} - -//virtual -LLVOAvatar* LLViewerObject::getAvatar() const -{ - if (isAttachment()) - { - LLViewerObject* vobj = (LLViewerObject*) getParent(); - - while (vobj && !vobj->asAvatar()) - { - vobj = (LLViewerObject*) vobj->getParent(); - } - - return (LLVOAvatar*) vobj; - } - - return NULL; -} - - -class ObjectPhysicsProperties : public LLHTTPNode -{ -public: - virtual void post( - ResponsePtr responder, - const LLSD& context, - const LLSD& input) const - { - LLSD object_data = input["body"]["ObjectData"]; - S32 num_entries = object_data.size(); - - for ( S32 i = 0; i < num_entries; i++ ) - { - LLSD& curr_object_data = object_data[i]; - U32 local_id = curr_object_data["LocalID"].asInteger(); - - // Iterate through nodes at end, since it can be on both the regular AND hover list - struct f : public LLSelectedNodeFunctor - { - U32 mID; - f(const U32& id) : mID(id) {} - virtual bool apply(LLSelectNode* node) - { - return (node->getObject() && node->getObject()->mLocalID == mID ); - } - } func(local_id); - - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(&func); - - if (node) - { - // The LLSD message builder doesn't know how to handle U8, so we need to send as S8 and cast - U8 type = (U8)curr_object_data["PhysicsShapeType"].asInteger(); - F32 density = (F32)curr_object_data["Density"].asReal(); - F32 friction = (F32)curr_object_data["Friction"].asReal(); - F32 restitution = (F32)curr_object_data["Restitution"].asReal(); - F32 gravity = (F32)curr_object_data["GravityMultiplier"].asReal(); - - node->getObject()->setPhysicsShapeType(type); - node->getObject()->setPhysicsGravity(gravity); - node->getObject()->setPhysicsFriction(friction); - node->getObject()->setPhysicsDensity(density); - node->getObject()->setPhysicsRestitution(restitution); - } - } - - dialog_refresh_all(); - }; -}; - -LLHTTPRegistration - gHTTPRegistrationObjectPhysicsProperties("/message/ObjectPhysicsProperties"); - - -void LLViewerObject::updateQuota( const SelectionQuota& quota ) -{ - //update quotas - mSelectionQuota = quota; -} +/** + * @file llviewerobject.cpp + * @brief Base class for viewer objects + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llviewerobject.h" + +#include "llaudioengine.h" +#include "imageids.h" +#include "indra_constants.h" +#include "llmath.h" +#include "llflexibleobject.h" +#include "llviewercontrol.h" +#include "lldatapacker.h" +#include "llfasttimer.h" +#include "llfloaterreg.h" +#include "llfontgl.h" +#include "llframetimer.h" +#include "llinventory.h" +#include "llinventorydefines.h" +#include "llmaterialtable.h" +#include "llmutelist.h" +#include "llnamevalue.h" +#include "llprimitive.h" +#include "llquantize.h" +#include "llregionhandle.h" +#include "llsdserialize.h" +#include "lltree_common.h" +#include "llxfermanager.h" +#include "message.h" +#include "object_flags.h" +#include "timing.h" + +#include "llaudiosourcevo.h" +#include "llagent.h" +#include "llagentcamera.h" +#include "llbbox.h" +#include "llbox.h" +#include "llcylinder.h" +#include "lldrawable.h" +#include "llface.h" +#include "llfloaterproperties.h" +#include "llfloatertools.h" +#include "llfollowcam.h" +#include "llhudtext.h" +#include "llselectmgr.h" +#include "llrendersphere.h" +#include "lltooldraganddrop.h" +#include "llviewercamera.h" +#include "llviewertexturelist.h" +#include "llviewerinventory.h" +#include "llviewerobjectlist.h" +#include "llviewerparceloverlay.h" +#include "llviewerpartsource.h" +#include "llviewerregion.h" +#include "llviewerstats.h" +#include "llviewertextureanim.h" +#include "llviewerwindow.h" // For getSpinAxis +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "llvoclouds.h" +#include "llvograss.h" +#include "llvoground.h" +#include "llvolume.h" +#include "llvolumemessage.h" +#include "llvopartgroup.h" +#include "llvosky.h" +#include "llvosurfacepatch.h" +#include "llvotextbubble.h" +#include "llvotree.h" +#include "llvovolume.h" +#include "llvowater.h" +#include "llworld.h" +#include "llui.h" +#include "pipeline.h" +#include "llviewernetwork.h" +#include "llvowlsky.h" +#include "llmanip.h" +#include "lltrans.h" +#include "llsdutil.h" +#include "llmediaentry.h" +#include "llaccountingquota.h" + +//#define DEBUG_UPDATE_TYPE + +BOOL LLViewerObject::sVelocityInterpolate = TRUE; +BOOL LLViewerObject::sPingInterpolate = TRUE; + +U32 LLViewerObject::sNumZombieObjects = 0; +S32 LLViewerObject::sNumObjects = 0; +BOOL LLViewerObject::sMapDebug = TRUE; +LLColor4 LLViewerObject::sEditSelectColor( 1.0f, 1.f, 0.f, 0.3f); // Edit OK +LLColor4 LLViewerObject::sNoEditSelectColor( 1.0f, 0.f, 0.f, 0.3f); // Can't edit +S32 LLViewerObject::sAxisArrowLength(50); +BOOL LLViewerObject::sPulseEnabled(FALSE); +BOOL LLViewerObject::sUseSharedDrawables(FALSE); // TRUE + +// sMaxUpdateInterpolationTime must be greater than sPhaseOutUpdateInterpolationTime +F64 LLViewerObject::sMaxUpdateInterpolationTime = 3.0; // For motion interpolation: after X seconds with no updates, don't predict object motion +F64 LLViewerObject::sPhaseOutUpdateInterpolationTime = 2.0; // For motion interpolation: after Y seconds with no updates, taper off motion prediction + + +static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object"); + +// static +LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) +{ + LLViewerObject *res = NULL; + LLFastTimer t1(FTM_CREATE_OBJECT); + + switch (pcode) + { + case LL_PCODE_VOLUME: + res = new LLVOVolume(id, pcode, regionp); break; + case LL_PCODE_LEGACY_AVATAR: + { + if (id == gAgentID) + { + if (!gAgentAvatarp) + { + gAgentAvatarp = new LLVOAvatarSelf(id, pcode, regionp); + } + else + { + gAgentAvatarp->updateRegion(regionp); + } + res = gAgentAvatarp; + } + else + { + res = new LLVOAvatar(id, pcode, regionp); + } + static_cast(res)->initInstance(); + break; + } + case LL_PCODE_LEGACY_GRASS: + res = new LLVOGrass(id, pcode, regionp); break; + case LL_PCODE_LEGACY_PART_SYS: +// llwarns << "Creating old part sys!" << llendl; +// res = new LLVOPart(id, pcode, regionp); break; + res = NULL; break; + case LL_PCODE_LEGACY_TREE: + res = new LLVOTree(id, pcode, regionp); break; + case LL_PCODE_TREE_NEW: +// llwarns << "Creating new tree!" << llendl; +// res = new LLVOTree(id, pcode, regionp); break; + res = NULL; break; + case LL_PCODE_LEGACY_TEXT_BUBBLE: + res = new LLVOTextBubble(id, pcode, regionp); break; + case LL_VO_CLOUDS: + res = new LLVOClouds(id, pcode, regionp); break; + case LL_VO_SURFACE_PATCH: + res = new LLVOSurfacePatch(id, pcode, regionp); break; + case LL_VO_SKY: + res = new LLVOSky(id, pcode, regionp); break; + case LL_VO_VOID_WATER: + res = new LLVOVoidWater(id, pcode, regionp); break; + case LL_VO_WATER: + res = new LLVOWater(id, pcode, regionp); break; + case LL_VO_GROUND: + res = new LLVOGround(id, pcode, regionp); break; + case LL_VO_PART_GROUP: + res = new LLVOPartGroup(id, pcode, regionp); break; + case LL_VO_HUD_PART_GROUP: + res = new LLVOHUDPartGroup(id, pcode, regionp); break; + case LL_VO_WL_SKY: + res = new LLVOWLSky(id, pcode, regionp); break; + default: + llwarns << "Unknown object pcode " << (S32)pcode << llendl; + res = NULL; break; + } + return res; +} + +LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global) +: LLPrimitive(), + mChildList(), + mID(id), + mLocalID(0), + mTotalCRC(0), + mTEImages(NULL), + mGLName(0), + mbCanSelect(TRUE), + mFlags(0), + mPhysicsShapeType(0), + mPhysicsGravity(0), + mPhysicsFriction(0), + mPhysicsDensity(0), + mPhysicsRestitution(0), + mDrawable(), + mCreateSelected(FALSE), + mRenderMedia(FALSE), + mBestUpdatePrecision(0), + mText(), + mLastInterpUpdateSecs(0.f), + mLastMessageUpdateSecs(0.f), + mLatestRecvPacketID(0), + mData(NULL), + mAudioSourcep(NULL), + mAudioGain(1.f), + mAppAngle(0.f), + mPixelArea(1024.f), + mInventory(NULL), + mInventorySerialNum(0), + mRegionp( regionp ), + mInventoryPending(FALSE), + mInventoryDirty(FALSE), + mDead(FALSE), + mOrphaned(FALSE), + mUserSelected(FALSE), + mOnActiveList(FALSE), + mOnMap(FALSE), + mStatic(FALSE), + mNumFaces(0), + mTimeDilation(1.f), + mRotTime(0.f), + mJointInfo(NULL), + mState(0), + mMedia(NULL), + mClickAction(0), + mObjectCost(0), + mLinksetCost(0), + mPhysicsCost(0), + mLinksetPhysicsCost(0.f), + mCostStale(true), + mPhysicsShapeUnknown(true), + mAttachmentItemID(LLUUID::null), + mLastUpdateType(OUT_UNKNOWN), + mLastUpdateCached(FALSE) +{ + if (!is_global) + { + llassert(mRegionp); + } + + LLPrimitive::init_primitive(pcode); + + // CP: added 12/2/2005 - this was being initialised to 0, not the current frame time + mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds(); + + mPositionRegion = LLVector3(0.f, 0.f, 0.f); + + if (!is_global && mRegionp) + { + mPositionAgent = mRegionp->getOriginAgent(); + } + + LLViewerObject::sNumObjects++; +} + +LLViewerObject::~LLViewerObject() +{ + deleteTEImages(); + + if(mInventory) + { + mInventory->clear(); // will deref and delete entries + delete mInventory; + mInventory = NULL; + } + + if (mJointInfo) + { + delete mJointInfo; + mJointInfo = NULL; + } + + if (mPartSourcep) + { + mPartSourcep->setDead(); + mPartSourcep = NULL; + } + + // Delete memory associated with extra parameters. + std::map::iterator iter; + for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + { + if(iter->second != NULL) + { + delete iter->second->data; + delete iter->second; + } + } + mExtraParameterList.clear(); + + for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ; + mNameValuePairs.clear(); + + delete[] mData; + mData = NULL; + + delete mMedia; + mMedia = NULL; + + sNumObjects--; + sNumZombieObjects--; + llassert(mChildList.size() == 0); + + clearInventoryListeners(); +} + +void LLViewerObject::deleteTEImages() +{ + delete[] mTEImages; + mTEImages = NULL; +} + +void LLViewerObject::markDead() +{ + if (!mDead) + { + //llinfos << "Marking self " << mLocalID << " as dead." << llendl; + + // Root object of this hierarchy unlinks itself. + if (getParent()) + { + ((LLViewerObject *)getParent())->removeChild(this); + // go ahead and delete any jointinfo's that we find + delete mJointInfo; + mJointInfo = NULL; + } + + // Mark itself as dead + mDead = TRUE; + gObjectList.cleanupReferences(this); + + LLViewerObject *childp; + while (mChildList.size() > 0) + { + childp = mChildList.back(); + if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR) + { + //llinfos << "Marking child " << childp->getLocalID() << " as dead." << llendl; + childp->setParent(NULL); // LLViewerObject::markDead 1 + childp->markDead(); + } + else + { + // make sure avatar is no longer parented, + // so we can properly set it's position + childp->setDrawableParent(NULL); + ((LLVOAvatar*)childp)->getOffObject(); + childp->setParent(NULL); // LLViewerObject::markDead 2 + } + mChildList.pop_back(); + } + + if (mDrawable.notNull()) + { + // Drawables are reference counted, mark as dead, then nuke the pointer. + mDrawable->markDead(); + mDrawable = NULL; + } + + if (mText) + { + mText->markDead(); + mText = NULL; + } + + if (mIcon) + { + mIcon->markDead(); + mIcon = NULL; + } + + if (mPartSourcep) + { + mPartSourcep->setDead(); + mPartSourcep = NULL; + } + + if (mAudioSourcep) + { + // Do some cleanup + if (gAudiop) + { + gAudiop->cleanupAudioSource(mAudioSourcep); + } + mAudioSourcep = NULL; + } + + if (flagAnimSource()) + { + if (isAgentAvatarValid()) + { + // stop motions associated with this object + gAgentAvatarp->stopMotionFromSource(mID); + } + } + + if (flagCameraSource()) + { + LLFollowCamMgr::removeFollowCamParams(mID); + } + + sNumZombieObjects++; + } +} + +void LLViewerObject::dump() const +{ + llinfos << "Type: " << pCodeToString(mPrimitiveCode) << llendl; + llinfos << "Drawable: " << (LLDrawable *)mDrawable << llendl; + llinfos << "Update Age: " << LLFrameTimer::getElapsedSeconds() - mLastMessageUpdateSecs << llendl; + + llinfos << "Parent: " << getParent() << llendl; + llinfos << "ID: " << mID << llendl; + llinfos << "LocalID: " << mLocalID << llendl; + llinfos << "PositionRegion: " << getPositionRegion() << llendl; + llinfos << "PositionAgent: " << getPositionAgent() << llendl; + llinfos << "PositionGlobal: " << getPositionGlobal() << llendl; + llinfos << "Velocity: " << getVelocity() << llendl; + if (mDrawable.notNull() && mDrawable->getNumFaces()) + { + LLFacePool *poolp = mDrawable->getFace(0)->getPool(); + if (poolp) + { + llinfos << "Pool: " << poolp << llendl; + llinfos << "Pool reference count: " << poolp->mReferences.size() << llendl; + } + } + //llinfos << "BoxTree Min: " << mDrawable->getBox()->getMin() << llendl; + //llinfos << "BoxTree Max: " << mDrawable->getBox()->getMin() << llendl; + /* + llinfos << "Velocity: " << getVelocity() << llendl; + llinfos << "AnyOwner: " << permAnyOwner() << " YouOwner: " << permYouOwner() << " Edit: " << mPermEdit << llendl; + llinfos << "UsePhysics: " << usePhysics() << " CanSelect " << mbCanSelect << " UserSelected " << mUserSelected << llendl; + llinfos << "AppAngle: " << mAppAngle << llendl; + llinfos << "PixelArea: " << mPixelArea << llendl; + + char buffer[1000]; + char *key; + for (key = mNameValuePairs.getFirstKey(); key; key = mNameValuePairs.getNextKey() ) + { + mNameValuePairs[key]->printNameValue(buffer); + llinfos << buffer << llendl; + } + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + llinfos << " child " << child->getID() << llendl; + } + */ +} + +void LLViewerObject::printNameValuePairs() const +{ + for (name_value_map_t::const_iterator iter = mNameValuePairs.begin(); + iter != mNameValuePairs.end(); iter++) + { + LLNameValue* nv = iter->second; + llinfos << nv->printNameValue() << llendl; + } +} + +void LLViewerObject::initVOClasses() +{ + // Initialized shared class stuff first. + LLVOAvatar::initClass(); + LLVOTree::initClass(); + llinfos << "Viewer Object size: " << sizeof(LLViewerObject) << llendl; + LLVOGrass::initClass(); + LLVOWater::initClass(); + LLVOVolume::initClass(); +} + +void LLViewerObject::cleanupVOClasses() +{ + LLVOGrass::cleanupClass(); + LLVOWater::cleanupClass(); + LLVOTree::cleanupClass(); + LLVOAvatar::cleanupClass(); + LLVOVolume::cleanupClass(); +} + +// Replaces all name value pairs with data from \n delimited list +// Does not update server +void LLViewerObject::setNameValueList(const std::string& name_value_list) +{ + // Clear out the old + for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ; + mNameValuePairs.clear(); + + // Bring in the new + std::string::size_type length = name_value_list.length(); + std::string::size_type start = 0; + while (start < length) + { + std::string::size_type end = name_value_list.find_first_of("\n", start); + if (end == std::string::npos) end = length; + if (end > start) + { + std::string tok = name_value_list.substr(start, end - start); + addNVPair(tok); + } + start = end+1; + } +} + + +// This method returns true if the object is over land owned by the +// agent. +bool LLViewerObject::isReturnable() +{ + if (isAttachment()) + { + return false; + } + std::vector boxes; + boxes.push_back(LLBBox(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f).getAxisAligned()); + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + boxes.push_back(LLBBox(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f).getAxisAligned()); + } + + return mRegionp + && mRegionp->objectIsReturnable(getPositionRegion(), boxes); +} + +BOOL LLViewerObject::setParent(LLViewerObject* parent) +{ + if(mParent != parent) + { + LLViewerObject* old_parent = (LLViewerObject*)mParent ; + BOOL ret = LLPrimitive::setParent(parent); + if(ret && old_parent && parent) + { + old_parent->removeChild(this) ; + } + return ret ; + } + + return FALSE ; +} + +void LLViewerObject::addChild(LLViewerObject *childp) +{ + for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) + { + if (*i == childp) + { //already has child + return; + } + } + + if (!isAvatar()) + { + // propagate selection properties + childp->mbCanSelect = mbCanSelect; + } + + if(childp->setParent(this)) + { + mChildList.push_back(childp); + } +} + +void LLViewerObject::removeChild(LLViewerObject *childp) +{ + for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) + { + if (*i == childp) + { + if (!childp->isAvatar() && mDrawable.notNull() && mDrawable->isActive() && childp->mDrawable.notNull() && !isAvatar()) + { + gPipeline.markRebuild(childp->mDrawable, LLDrawable::REBUILD_VOLUME); + } + + mChildList.erase(i); + + if(childp->getParent() == this) + { + childp->setParent(NULL); + } + break; + } + } + + if (childp->isSelected()) + { + LLSelectMgr::getInstance()->deselectObjectAndFamily(childp); + BOOL add_to_end = TRUE; + LLSelectMgr::getInstance()->selectObjectAndFamily(childp, add_to_end); + } +} + +void LLViewerObject::addThisAndAllChildren(std::vector& objects) +{ + objects.push_back(this); + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + if (!child->isAvatar()) + { + child->addThisAndAllChildren(objects); + } + } +} + +void LLViewerObject::addThisAndNonJointChildren(std::vector& objects) +{ + objects.push_back(this); + // don't add any attachments when temporarily selecting avatar + if (isAvatar()) + { + return; + } + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + if ( (!child->isAvatar()) && (!child->isJointChild())) + { + child->addThisAndNonJointChildren(objects); + } + } +} + +BOOL LLViewerObject::isChild(LLViewerObject *childp) const +{ + for (child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* testchild = *iter; + if (testchild == childp) + return TRUE; + } + return FALSE; +} + + +// returns TRUE if at least one avatar is sitting on this object +BOOL LLViewerObject::isSeat() const +{ + for (child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + if (child->isAvatar()) + { + return TRUE; + } + } + return FALSE; + +} + +BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp) +{ + if (mDrawable.isNull()) + { + return FALSE; + } + + BOOL ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL); + if(!ret) + { + return FALSE ; + } + LLDrawable* old_parent = mDrawable->mParent; + mDrawable->mParent = parentp; + + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); + if( (old_parent != parentp && old_parent) + || (parentp && parentp->isActive())) + { + // *TODO we should not be relying on setDrawable parent to call markMoved + gPipeline.markMoved(mDrawable, FALSE); + } + else if (!mDrawable->isAvatar()) + { + mDrawable->updateXform(TRUE); + /*if (!mDrawable->getSpatialGroup()) + { + mDrawable->movePartition(); + }*/ + } + + return ret; +} + +// Show or hide particles, icon and HUD +void LLViewerObject::hideExtraDisplayItems( BOOL hidden ) +{ + if( mPartSourcep.notNull() ) + { + LLViewerPartSourceScript *partSourceScript = mPartSourcep.get(); + partSourceScript->setSuspended( hidden ); + } + + if( mText.notNull() ) + { + LLHUDText *hudText = mText.get(); + hudText->setHidden( hidden ); + } + + if( mIcon.notNull() ) + { + LLHUDIcon *hudIcon = mIcon.get(); + hudIcon->setHidden( hidden ); + } +} + +U32 LLViewerObject::checkMediaURL(const std::string &media_url) +{ + U32 retval = (U32)0x0; + if (!mMedia && !media_url.empty()) + { + retval |= MEDIA_URL_ADDED; + mMedia = new LLViewerObjectMedia; + mMedia->mMediaURL = media_url; + mMedia->mMediaType = LLViewerObject::MEDIA_SET; + mMedia->mPassedWhitelist = FALSE; + } + else if (mMedia) + { + if (media_url.empty()) + { + retval |= MEDIA_URL_REMOVED; + delete mMedia; + mMedia = NULL; + } + else if (mMedia->mMediaURL != media_url) // <-- This is an optimization. If they are equal don't bother with below's test. + { + /*if (! (LLTextureEntry::getAgentIDFromMediaVersionString(media_url) == gAgent.getID() && + LLTextureEntry::getVersionFromMediaVersionString(media_url) == + LLTextureEntry::getVersionFromMediaVersionString(mMedia->mMediaURL) + 1)) + */ + { + // If the media URL is different and WE were not the one who + // changed it, mark dirty. + retval |= MEDIA_URL_UPDATED; + } + mMedia->mMediaURL = media_url; + mMedia->mPassedWhitelist = FALSE; + } + } + return retval; +} + +U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, + void **user_data, + U32 block_num, + const EObjectUpdateType update_type, + LLDataPacker *dp) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + U32 retval = 0x0; + + // Coordinates of objects on simulators are region-local. + U64 region_handle; + mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); + + { + LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); + if(regionp != mRegionp && regionp && mRegionp)//region cross + { + //this is the redundant position and region update, but it is necessary in case the viewer misses the following + //position and region update messages from sim. + //this redundant update should not cause any problems. + LLVector3 delta_pos = mRegionp->getOriginAgent() - regionp->getOriginAgent(); + setPositionParent(getPosition() + delta_pos); //update to the new region position immediately. + setRegion(regionp) ; //change the region. + } + else + { + mRegionp = regionp ; + } + } + + if (!mRegionp) + { + U32 x, y; + from_region_handle(region_handle, &x, &y); + + llerrs << "Object has invalid region " << x << ":" << y << "!" << llendl; + return retval; + } + + U16 time_dilation16; + mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16); + F32 time_dilation = ((F32) time_dilation16) / 65535.f; + mTimeDilation = time_dilation; + mRegionp->setTimeDilation(time_dilation); + + // this will be used to determine if we've really changed position + // Use getPosition, not getPositionRegion, since this is what we're comparing directly against. + LLVector3 test_pos_parent = getPosition(); + + U8 data[60+16]; // This needs to match the largest size below. +#ifdef LL_BIG_ENDIAN + U16 valswizzle[4]; +#endif + U16 *val; + const F32 size = LLWorld::getInstance()->getRegionWidthInMeters(); + const F32 MAX_HEIGHT = LLWorld::getInstance()->getRegionMaxHeight(); + const F32 MIN_HEIGHT = LLWorld::getInstance()->getRegionMinHeight(); + S32 length; + S32 count; + S32 this_update_precision = 32; // in bits + + // Temporaries, because we need to compare w/ previous to set dirty flags... + LLVector3 new_pos_parent; + LLVector3 new_vel; + LLVector3 new_acc; + LLVector3 new_angv; + LLVector3 old_angv = getAngularVelocity(); + LLQuaternion new_rot; + LLVector3 new_scale = getScale(); + + U32 parent_id = 0; + U8 material = 0; + U8 click_action = 0; + U32 crc = 0; + + bool old_special_hover_cursor = specialHoverCursor(); + + LLViewerObject *cur_parentp = (LLViewerObject *)getParent(); + + if (cur_parentp) + { + parent_id = cur_parentp->mLocalID; + } + + if (!dp) + { + switch(update_type) + { + case OUT_FULL: + { +#ifdef DEBUG_UPDATE_TYPE + llinfos << "Full:" << getID() << llendl; +#endif + //clear cost and linkset cost + mCostStale = true; + if (isSelected()) + { + gFloaterTools->dirty(); + } + + LLUUID audio_uuid; + LLUUID owner_id; // only valid if audio_uuid or particle system is not null + F32 gain; + U8 sound_flags; + + mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_CRC, crc, block_num); + mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_ParentID, parent_id, block_num); + mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_Sound, audio_uuid, block_num ); + // HACK: Owner id only valid if non-null sound id or particle system + mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, block_num ); + mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Gain, gain, block_num ); + mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Flags, sound_flags, block_num ); + mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Material, material, block_num ); + mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_ClickAction, click_action, block_num); + mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_Scale, new_scale, block_num ); + length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num); + + mTotalCRC = crc; + + // Owner ID used for sound muting or particle system muting + setAttachedSound(audio_uuid, owner_id, gain, sound_flags); + + U8 old_material = getMaterial(); + if (old_material != material) + { + setMaterial(material); + if (mDrawable.notNull()) + { + gPipeline.markMoved(mDrawable, FALSE); // undamped + } + } + setClickAction(click_action); + + count = 0; + LLVector4 collision_plane; + + switch(length) + { + case (60 + 16): + // pull out collision normal for avatar + htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + ((LLVOAvatar*)this)->setFootPlane(collision_plane); + count += sizeof(LLVector4); + // fall through + case 60: + this_update_precision = 32; + // this is a terse update + // pos + htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // vel + htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // acc + htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // theta + { + LLVector3 vec; + htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + new_rot.unpackFromVector3(vec); + } + count += sizeof(LLVector3); + // omega + htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + if (new_angv.isExactlyZero()) + { + // reset rotation time + resetRot(); + } + setAngularVelocity(new_angv); +#if LL_DARWIN + if (length == 76) + { + setAngularVelocity(LLVector3::zero); + } +#endif + break; + case(32 + 16): + // pull out collision normal for avatar + htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + ((LLVOAvatar*)this)->setFootPlane(collision_plane); + count += sizeof(LLVector4); + // fall through + case 32: + this_update_precision = 16; + test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); + + // This is a terse 16 update, so treat data as an array of U16's. +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*3; + new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*3; + setVelocity(LLVector3(U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size))); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*3; + setAcceleration(LLVector3(U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size))); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 4); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*4; + new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f); + new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f); + new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f); + new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + new_angv.setVec(U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size)); + if (new_angv.isExactlyZero()) + { + // reset rotation time + resetRot(); + } + setAngularVelocity(new_angv); + break; + + case 16: + this_update_precision = 8; + test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); + // this is a terse 8 update + new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT); + + setVelocity(U8_to_F32(data[3], -size, size), + U8_to_F32(data[4], -size, size), + U8_to_F32(data[5], -size, size) ); + + setAcceleration(U8_to_F32(data[6], -size, size), + U8_to_F32(data[7], -size, size), + U8_to_F32(data[8], -size, size) ); + + new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f); + new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f); + new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f); + new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f); + + new_angv.setVec(U8_to_F32(data[13], -size, size), + U8_to_F32(data[14], -size, size), + U8_to_F32(data[15], -size, size) ); + if (new_angv.isExactlyZero()) + { + // reset rotation time + resetRot(); + } + setAngularVelocity(new_angv); + break; + } + + //////////////////////////////////////////////////// + // + // Here we handle data specific to the full message. + // + + U32 flags; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); + // clear all but local flags + mFlags &= FLAGS_LOCAL; + mFlags |= flags; + + U8 state; + mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num ); + mState = state; + + // ...new objects that should come in selected need to be added to the selected list + mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); + + // Set all name value pairs + S32 nv_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_NameValue); + if (nv_size > 0) + { + std::string name_value_list; + mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_NameValue, name_value_list, block_num); + setNameValueList(name_value_list); + } + + // Clear out any existing generic data + if (mData) + { + delete [] mData; + } + + // Check for appended generic data + S32 data_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Data); + if (data_size <= 0) + { + mData = NULL; + } + else + { + // ...has generic data + mData = new U8[data_size]; + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, mData, data_size, block_num); + } + + S32 text_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Text); + if (text_size > 1) + { + // Setup object text + if (!mText) + { + mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); + mText->setFont(LLFontGL::getFontSansSerif()); + mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); + mText->setMaxLines(-1); + mText->setSourceObject(this); + mText->setOnHUDAttachment(isHUDAttachment()); + } + + std::string temp_string; + mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_Text, temp_string, block_num ); + + LLColor4U coloru; + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextColor, coloru.mV, 4, block_num); + + // alpha was flipped so that it zero encoded better + coloru.mV[3] = 255 - coloru.mV[3]; + mText->setColor(LLColor4(coloru)); + mText->setString(temp_string); + + if (mDrawable.notNull()) + { + setChanged(MOVED | SILHOUETTE); + gPipeline.markMoved(mDrawable, FALSE); // undamped + } + } + else if (mText.notNull()) + { + mText->markDead(); + mText = NULL; + } + + std::string media_url; + mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_MediaURL, media_url, block_num); + retval |= checkMediaURL(media_url); + + // + // Unpack particle system data + // + unpackParticleSource(block_num, owner_id); + + // Mark all extra parameters not used + std::map::iterator iter; + for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + { + iter->second->in_use = FALSE; + } + + // Unpack extra parameters + S32 size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ExtraParams); + if (size > 0) + { + U8 *buffer = new U8[size]; + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ExtraParams, buffer, size, block_num); + LLDataPackerBinaryBuffer dp(buffer, size); + + U8 num_parameters; + dp.unpackU8(num_parameters, "num_params"); + U8 param_block[MAX_OBJECT_PARAMS_SIZE]; + for (U8 param=0; paramsecond->in_use) + { + // Send an update message in case it was formerly in use + parameterChanged(iter->first, iter->second->data, FALSE, false); + } + } + + U8 joint_type = 0; + mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_JointType, joint_type, block_num); + if (joint_type) + { + // create new joint info + if (!mJointInfo) + { + mJointInfo = new LLVOJointInfo; + } + mJointInfo->mJointType = (EHavokJointType) joint_type; + mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_JointPivot, mJointInfo->mPivot, block_num); + mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_JointAxisOrAnchor, mJointInfo->mAxisOrAnchor, block_num); + } + else if (mJointInfo) + { + // this joint info is no longer needed + delete mJointInfo; + mJointInfo = NULL; + } + + break; + } + + case OUT_TERSE_IMPROVED: + { +#ifdef DEBUG_UPDATE_TYPE + llinfos << "TI:" << getID() << llendl; +#endif + length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num); + count = 0; + LLVector4 collision_plane; + + switch(length) + { + case(60 + 16): + // pull out collision normal for avatar + htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + ((LLVOAvatar*)this)->setFootPlane(collision_plane); + count += sizeof(LLVector4); + // fall through + case 60: + // this is a terse 32 update + // pos + this_update_precision = 32; + htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // vel + htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // acc + htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // theta + { + LLVector3 vec; + htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + new_rot.unpackFromVector3(vec); + } + count += sizeof(LLVector3); + // omega + htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + if (new_angv.isExactlyZero()) + { + // reset rotation time + resetRot(); + } + setAngularVelocity(new_angv); +#if LL_DARWIN + if (length == 76) + { + setAngularVelocity(LLVector3::zero); + } +#endif + break; + case(32 + 16): + // pull out collision normal for avatar + htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + ((LLVOAvatar*)this)->setFootPlane(collision_plane); + count += sizeof(LLVector4); + // fall through + case 32: + // this is a terse 16 update + this_update_precision = 16; + test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*3; + new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*3; + setVelocity(U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size)); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*3; + setAcceleration(U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size)); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*4; + new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f); + new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f); + new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f); + new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + setAngularVelocity( U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size)); + break; + + case 16: + // this is a terse 8 update + this_update_precision = 8; + test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); + new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT); + + setVelocity(U8_to_F32(data[3], -size, size), + U8_to_F32(data[4], -size, size), + U8_to_F32(data[5], -size, size) ); + + setAcceleration(U8_to_F32(data[6], -size, size), + U8_to_F32(data[7], -size, size), + U8_to_F32(data[8], -size, size) ); + + new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f); + new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f); + new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f); + new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f); + + setAngularVelocity( U8_to_F32(data[13], -size, size), + U8_to_F32(data[14], -size, size), + U8_to_F32(data[15], -size, size) ); + break; + } + + U8 state; + mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num ); + mState = state; + break; + } + + default: + break; + + } + } + else + { + // handle the compressed case + LLUUID sound_uuid; + LLUUID owner_id; + F32 gain = 0; + U8 sound_flags = 0; + F32 cutoff = 0; + + U16 val[4]; + + U8 state; + + dp->unpackU8(state, "State"); + mState = state; + + switch(update_type) + { + case OUT_TERSE_IMPROVED: + { +#ifdef DEBUG_UPDATE_TYPE + llinfos << "CompTI:" << getID() << llendl; +#endif + U8 value; + dp->unpackU8(value, "agent"); + if (value) + { + LLVector4 collision_plane; + dp->unpackVector4(collision_plane, "Plane"); + ((LLVOAvatar*)this)->setFootPlane(collision_plane); + } + test_pos_parent = getPosition(); + dp->unpackVector3(new_pos_parent, "Pos"); + dp->unpackU16(val[VX], "VelX"); + dp->unpackU16(val[VY], "VelY"); + dp->unpackU16(val[VZ], "VelZ"); + setVelocity(U16_to_F32(val[VX], -128.f, 128.f), + U16_to_F32(val[VY], -128.f, 128.f), + U16_to_F32(val[VZ], -128.f, 128.f)); + dp->unpackU16(val[VX], "AccX"); + dp->unpackU16(val[VY], "AccY"); + dp->unpackU16(val[VZ], "AccZ"); + setAcceleration(U16_to_F32(val[VX], -64.f, 64.f), + U16_to_F32(val[VY], -64.f, 64.f), + U16_to_F32(val[VZ], -64.f, 64.f)); + + dp->unpackU16(val[VX], "ThetaX"); + dp->unpackU16(val[VY], "ThetaY"); + dp->unpackU16(val[VZ], "ThetaZ"); + dp->unpackU16(val[VS], "ThetaS"); + new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f); + new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f); + new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f); + new_rot.mQ[VS] = U16_to_F32(val[VS], -1.f, 1.f); + dp->unpackU16(val[VX], "AccX"); + dp->unpackU16(val[VY], "AccY"); + dp->unpackU16(val[VZ], "AccZ"); + setAngularVelocity( U16_to_F32(val[VX], -64.f, 64.f), + U16_to_F32(val[VY], -64.f, 64.f), + U16_to_F32(val[VZ], -64.f, 64.f)); + } + break; + case OUT_FULL_COMPRESSED: + case OUT_FULL_CACHED: + { +#ifdef DEBUG_UPDATE_TYPE + llinfos << "CompFull:" << getID() << llendl; +#endif + mCostStale = true; + + if (isSelected()) + { + gFloaterTools->dirty(); + } + + dp->unpackU32(crc, "CRC"); + mTotalCRC = crc; + dp->unpackU8(material, "Material"); + U8 old_material = getMaterial(); + if (old_material != material) + { + setMaterial(material); + if (mDrawable.notNull()) + { + gPipeline.markMoved(mDrawable, FALSE); // undamped + } + } + dp->unpackU8(click_action, "ClickAction"); + setClickAction(click_action); + dp->unpackVector3(new_scale, "Scale"); + dp->unpackVector3(new_pos_parent, "Pos"); + LLVector3 vec; + dp->unpackVector3(vec, "Rot"); + new_rot.unpackFromVector3(vec); + setAcceleration(LLVector3::zero); + + U32 value; + dp->unpackU32(value, "SpecialCode"); + dp->setPassFlags(value); + dp->unpackUUID(owner_id, "Owner"); + + if (value & 0x80) + { + dp->unpackVector3(vec, "Omega"); + setAngularVelocity(vec); + } + + if (value & 0x20) + { + dp->unpackU32(parent_id, "ParentID"); + } + else + { + parent_id = 0; + } + + S32 sp_size; + U32 size; + if (value & 0x2) + { + sp_size = 1; + delete [] mData; + mData = new U8[1]; + dp->unpackU8(((U8*)mData)[0], "TreeData"); + } + else if (value & 0x1) + { + dp->unpackU32(size, "ScratchPadSize"); + delete [] mData; + mData = new U8[size]; + dp->unpackBinaryData((U8 *)mData, sp_size, "PartData"); + } + else + { + mData = NULL; + } + + // Setup object text + if (!mText && (value & 0x4)) + { + mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); + mText->setFont(LLFontGL::getFontSansSerif()); + mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); + mText->setMaxLines(-1); // Set to match current agni behavior. + mText->setSourceObject(this); + mText->setOnHUDAttachment(isHUDAttachment()); + } + + if (value & 0x4) + { + std::string temp_string; + dp->unpackString(temp_string, "Text"); + LLColor4U coloru; + dp->unpackBinaryDataFixed(coloru.mV, 4, "Color"); + coloru.mV[3] = 255 - coloru.mV[3]; + mText->setColor(LLColor4(coloru)); + mText->setString(temp_string); + + setChanged(TEXTURE); + } + else if(mText.notNull()) + { + mText->markDead(); + mText = NULL; + } + + std::string media_url; + if (value & 0x200) + { + dp->unpackString(media_url, "MediaURL"); + } + retval |= checkMediaURL(media_url); + + // + // Unpack particle system data + // + if (value & 0x8) + { + unpackParticleSource(*dp, owner_id); + } + else + { + deleteParticleSource(); + } + + // Mark all extra parameters not used + std::map::iterator iter; + for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + { + iter->second->in_use = FALSE; + } + + // Unpack extra params + U8 num_parameters; + dp->unpackU8(num_parameters, "num_params"); + U8 param_block[MAX_OBJECT_PARAMS_SIZE]; + for (U8 param=0; paramunpackU16(param_type, "param_type"); + dp->unpackBinaryData(param_block, param_size, "param_data"); + //llinfos << "Param type: " << param_type << ", Size: " << param_size << llendl; + LLDataPackerBinaryBuffer dp2(param_block, param_size); + unpackParameterEntry(param_type, &dp2); + } + + for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + { + if (!iter->second->in_use) + { + // Send an update message in case it was formerly in use + parameterChanged(iter->first, iter->second->data, FALSE, false); + } + } + + if (value & 0x10) + { + dp->unpackUUID(sound_uuid, "SoundUUID"); + dp->unpackF32(gain, "SoundGain"); + dp->unpackU8(sound_flags, "SoundFlags"); + dp->unpackF32(cutoff, "SoundRadius"); + } + + if (value & 0x100) + { + std::string name_value_list; + dp->unpackString(name_value_list, "NV"); + + setNameValueList(name_value_list); + } + + mTotalCRC = crc; + + setAttachedSound(sound_uuid, owner_id, gain, sound_flags); + + // only get these flags on updates from sim, not cached ones + // Preload these five flags for every object. + // Finer shades require the object to be selected, and the selection manager + // stores the extended permission info. + U32 flags; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); + // keep local flags and overwrite remote-controlled flags + mFlags = (mFlags & FLAGS_LOCAL) | flags; + + // ...new objects that should come in selected need to be added to the selected list + mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); + } + break; + + default: + break; + } + } + + // + // Fix object parenting. + // + BOOL b_changed_status = FALSE; + + if (OUT_TERSE_IMPROVED != update_type) + { + // We only need to update parenting on full updates, terse updates + // don't send parenting information. + if (!cur_parentp) + { + if (parent_id == 0) + { + // No parent now, no parent in message -> do nothing + } + else + { + // No parent now, new parent in message -> attach to that parent if possible + LLUUID parent_uuid; + LLViewerObjectList::getUUIDFromLocal(parent_uuid, + parent_id, + mesgsys->getSenderIP(), + mesgsys->getSenderPort()); + + LLViewerObject *sent_parentp = gObjectList.findObject(parent_uuid); + + // + // Check to see if we have the corresponding viewer object for the parent. + // + if (sent_parentp && sent_parentp->getParent() == this) + { + // Try to recover if we attempt to attach a parent to its child + llwarns << "Attempt to attach a parent to it's child: " << this->getID() << " to " << sent_parentp->getID() << llendl; + this->removeChild(sent_parentp); + sent_parentp->setDrawableParent(NULL); + } + + if (sent_parentp && (sent_parentp != this) && !sent_parentp->isDead()) + { + // + // We have a viewer object for the parent, and it's not dead. + // Do the actual reparenting here. + // + + // new parent is valid + b_changed_status = TRUE; + // ...no current parent, so don't try to remove child + if (mDrawable.notNull()) + { + if (mDrawable->isDead() || !mDrawable->getVObj()) + { + llwarns << "Drawable is dead or no VObj!" << llendl; + sent_parentp->addChild(this); + } + else + { + if (!setDrawableParent(sent_parentp->mDrawable)) // LLViewerObject::processUpdateMessage 1 + { + // Bad, we got a cycle somehow. + // Kill both the parent and the child, and + // set cache misses for both of them. + llwarns << "Attempting to recover from parenting cycle!" << llendl; + llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl; + llwarns << "Adding to cache miss list" << llendl; + setParent(NULL); + sent_parentp->setParent(NULL); + getRegion()->addCacheMissFull(getLocalID()); + getRegion()->addCacheMissFull(sent_parentp->getLocalID()); + gObjectList.killObject(sent_parentp); + gObjectList.killObject(this); + return retval; + } + sent_parentp->addChild(this); + // make sure this object gets a non-damped update + if (sent_parentp->mDrawable.notNull()) + { + gPipeline.markMoved(sent_parentp->mDrawable, FALSE); // undamped + } + } + } + else + { + sent_parentp->addChild(this); + } + + // Show particles, icon and HUD + hideExtraDisplayItems( FALSE ); + + setChanged(MOVED | SILHOUETTE); + } + else + { + // + // No corresponding viewer object for the parent, put the various + // pieces on the orphan list. + // + + //parent_id + U32 ip = mesgsys->getSenderIP(); + U32 port = mesgsys->getSenderPort(); + + gObjectList.orphanize(this, parent_id, ip, port); + + // Hide particles, icon and HUD + hideExtraDisplayItems( TRUE ); + } + } + } + else + { + // BUG: this is a bad assumption once border crossing is alowed + if ( (parent_id == cur_parentp->mLocalID) + &&(update_type == OUT_TERSE_IMPROVED)) + { + // Parent now, same parent in message -> do nothing + + // Debugging for suspected problems with local ids. + //LLUUID parent_uuid; + //LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, mesgsys->getSenderIP(), mesgsys->getSenderPort() ); + //if (parent_uuid != cur_parentp->getID() ) + //{ + // llerrs << "Local ID match but UUID mismatch of viewer object" << llendl; + //} + } + else + { + // Parented now, different parent in message + LLViewerObject *sent_parentp; + if (parent_id == 0) + { + // + // This object is no longer parented, we sent in a zero parent ID. + // + sent_parentp = NULL; + } + else + { + LLUUID parent_uuid; + LLViewerObjectList::getUUIDFromLocal(parent_uuid, + parent_id, + gMessageSystem->getSenderIP(), + gMessageSystem->getSenderPort()); + sent_parentp = gObjectList.findObject(parent_uuid); + + if (isAvatar()) + { + // This logic is meant to handle the case where a sitting avatar has reached a new sim + // ahead of the object she was sitting on (which is common as objects are transfered through + // a slower route than agents)... + // In this case, the local id for the object will not be valid, since the viewer has not received + // a full update for the object from that sim yet, so we assume that the agent is still sitting + // where she was originally. --RN + if (!sent_parentp) + { + sent_parentp = cur_parentp; + } + } + else if (!sent_parentp) + { + // + // Switching parents, but we don't know the new parent. + // + U32 ip = mesgsys->getSenderIP(); + U32 port = mesgsys->getSenderPort(); + + // We're an orphan, flag things appropriately. + gObjectList.orphanize(this, parent_id, ip, port); + } + } + + // Reattach if possible. + if (sent_parentp && sent_parentp != cur_parentp && sent_parentp != this) + { + // New parent is valid, detach and reattach + b_changed_status = TRUE; + if (mDrawable.notNull()) + { + if (!setDrawableParent(sent_parentp->mDrawable)) // LLViewerObject::processUpdateMessage 2 + { + // Bad, we got a cycle somehow. + // Kill both the parent and the child, and + // set cache misses for both of them. + llwarns << "Attempting to recover from parenting cycle!" << llendl; + llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl; + llwarns << "Adding to cache miss list" << llendl; + setParent(NULL); + sent_parentp->setParent(NULL); + getRegion()->addCacheMissFull(getLocalID()); + getRegion()->addCacheMissFull(sent_parentp->getLocalID()); + gObjectList.killObject(sent_parentp); + gObjectList.killObject(this); + return retval; + } + // make sure this object gets a non-damped update + } + cur_parentp->removeChild(this); + sent_parentp->addChild(this); + setChanged(MOVED | SILHOUETTE); + sent_parentp->setChanged(MOVED | SILHOUETTE); + if (sent_parentp->mDrawable.notNull()) + { + gPipeline.markMoved(sent_parentp->mDrawable, FALSE); // undamped + } + } + else if (!sent_parentp) + { + bool remove_parent = true; + // No new parent, or the parent that we sent doesn't exist on the viewer. + LLViewerObject *parentp = (LLViewerObject *)getParent(); + if (parentp) + { + if (parentp->getRegion() != getRegion()) + { + // This is probably an object flying across a region boundary, the + // object probably ISN'T being reparented, but just got an object + // update out of order (child update before parent). + //llinfos << "Don't reparent object handoffs!" << llendl; + remove_parent = false; + } + } + + if (remove_parent) + { + b_changed_status = TRUE; + if (mDrawable.notNull()) + { + // clear parent to removeChild can put the drawable on the damped list + setDrawableParent(NULL); // LLViewerObject::processUpdateMessage 3 + } + + cur_parentp->removeChild(this); + + if (mJointInfo && !parent_id) + { + // since this object is no longer parent-relative + // we make sure we delete any joint info + delete mJointInfo; + mJointInfo = NULL; + } + + setChanged(MOVED | SILHOUETTE); + + if (mDrawable.notNull()) + { + // make sure this object gets a non-damped update + gPipeline.markMoved(mDrawable, FALSE); // undamped + } + } + } + } + } + } + + new_rot.normQuat(); + + if (sPingInterpolate) + { + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mesgsys->getSender()); + if (cdp) + { + F32 ping_delay = 0.5f * mTimeDilation * ( ((F32)cdp->getPingDelay()) * 0.001f + gFrameDTClamped); + LLVector3 diff = getVelocity() * ping_delay; + new_pos_parent += diff; + } + else + { + llwarns << "findCircuit() returned NULL; skipping interpolation" << llendl; + } + } + + ////////////////////////// + // + // Set the generic change flags... + // + // + + // WTF? If we're going to skip this message, why are we + // doing all the parenting, etc above? + U32 packet_id = mesgsys->getCurrentRecvPacketID(); + if (packet_id < mLatestRecvPacketID && + mLatestRecvPacketID - packet_id < 65536) + { + //skip application of this message, it's old + return retval; + } + + mLatestRecvPacketID = packet_id; + + // Set the change flags for scale + if (new_scale != getScale()) + { + setChanged(SCALED | SILHOUETTE); + setScale(new_scale); // Must follow setting permYouOwner() + } + + // first, let's see if the new position is actually a change + + //static S32 counter = 0; + + F32 vel_mag_sq = getVelocity().magVecSquared(); + F32 accel_mag_sq = getAcceleration().magVecSquared(); + + if ( ((b_changed_status)||(test_pos_parent != new_pos_parent)) + ||( (!isSelected()) + &&( (vel_mag_sq != 0.f) + ||(accel_mag_sq != 0.f) + ||(this_update_precision > mBestUpdatePrecision)))) + { + mBestUpdatePrecision = this_update_precision; + + LLVector3 diff = new_pos_parent - test_pos_parent ; + F32 mag_sqr = diff.magVecSquared() ; + if(llfinite(mag_sqr)) + { + setPositionParent(new_pos_parent); + } + else + { + llwarns << "Can not move the object/avatar to an infinite location!" << llendl ; + + retval |= INVALID_UPDATE ; + } + + if (mParent && ((LLViewerObject*)mParent)->isAvatar()) + { + // we have changed the position of an attachment, so we need to clamp it + LLVOAvatar *avatar = (LLVOAvatar*)mParent; + + avatar->clampAttachmentPositions(); + } + + // If we're snapping the position by more than 0.5m, update LLViewerStats::mAgentPositionSnaps + if ( asAvatar() && asAvatar()->isSelf() && (mag_sqr > 0.25f) ) + { + LLViewerStats::getInstance()->mAgentPositionSnaps.push( diff.length() ); + } + } + + if (new_rot != mLastRot + || new_angv != old_angv) + { + if (new_rot != mLastRot) + { + mLastRot = new_rot; + setRotation(new_rot); + } + + setChanged(ROTATED | SILHOUETTE); + + resetRot(); + } + + + if ( gShowObjectUpdates ) + { + if (!((mPrimitiveCode == LL_PCODE_LEGACY_AVATAR) && (((LLVOAvatar *) this)->isSelf())) + && mRegionp) + { + LLViewerObject* object = gObjectList.createObjectViewer(LL_PCODE_LEGACY_TEXT_BUBBLE, mRegionp); + LLVOTextBubble* bubble = (LLVOTextBubble*) object; + + if (update_type == OUT_TERSE_IMPROVED) + { + bubble->mColor.setVec(0.f, 0.f, 1.f, 1.f); + } + else + { + bubble->mColor.setVec(1.f, 0.f, 0.f, 1.f); + } + object->setPositionGlobal(getPositionGlobal()); + gPipeline.addObject(object); + } + } + + if ((0.0f == vel_mag_sq) && + (0.0f == accel_mag_sq) && + (0.0f == getAngularVelocity().magVecSquared())) + { + mStatic = TRUE; // This object doesn't move! + } + else + { + mStatic = FALSE; + } + +// BUG: This code leads to problems during group rotate and any scale operation. +// Small discepencies between the simulator and viewer representations cause the +// selection center to creep, leading to objects moving around the wrong center. +// +// Removing this, however, means that if someone else drags an object you have +// selected, your selection center and dialog boxes will be wrong. It also means +// that higher precision information on selected objects will be ignored. +// +// I believe the group rotation problem is fixed. JNC 1.21.2002 +// + // Additionally, if any child is selected, need to update the dialogs and selection + // center. + BOOL needs_refresh = mUserSelected; + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + needs_refresh = needs_refresh || child->mUserSelected; + } + + if (needs_refresh) + { + LLSelectMgr::getInstance()->updateSelectionCenter(); + dialog_refresh_all(); + } + + + // Mark update time as approx. now, with the ping delay. + // Ping delay is off because it's not set for velocity interpolation, causing + // much jumping and hopping around... + +// U32 ping_delay = mesgsys->mCircuitInfo.getPingDelay(); + mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds(); + mLastMessageUpdateSecs = mLastInterpUpdateSecs; + if (mDrawable.notNull()) + { + // Don't clear invisibility flag on update if still orphaned! + if (mDrawable->isState(LLDrawable::FORCE_INVISIBLE) && !mOrphaned) + { +// lldebugs << "Clearing force invisible: " << mID << ":" << getPCodeString() << ":" << getPositionAgent() << llendl; + mDrawable->setState(LLDrawable::CLEAR_INVISIBLE); + } + } + + // Update special hover cursor status + bool special_hover_cursor = specialHoverCursor(); + if (old_special_hover_cursor != special_hover_cursor + && mDrawable.notNull()) + { + mDrawable->updateSpecialHoverCursor(special_hover_cursor); + } + + return retval; +} + +BOOL LLViewerObject::isActive() const +{ + return TRUE; +} + + + +BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) +{ + static LLFastTimer::DeclareTimer ftm("Viewer Object"); + LLFastTimer t(ftm); + + if (mDead) + { + // It's dead. Don't update it. + return TRUE; + } + + // CRO - don't velocity interp linked objects! + // Leviathan - but DO velocity interp joints + if (!mStatic && sVelocityInterpolate && !isSelected()) + { + // calculate dt from last update + F32 dt_raw = (F32)(time - mLastInterpUpdateSecs); + F32 dt = mTimeDilation * dt_raw; + + if (!mJointInfo) + { + applyAngularVelocity(dt); + } + + LLViewerObject *parentp = (LLViewerObject *) getParent(); + if (mJointInfo) + { + if (parentp) + { + // do parent-relative stuff + LLVector3 ang_vel = getAngularVelocity(); + F32 omega = ang_vel.magVecSquared(); + F32 angle = 0.0f; + LLQuaternion dQ; + if (omega > 0.00001f) + { + omega = sqrt(omega); + angle = omega * dt; + dQ.setQuat(angle, ang_vel); + } + LLVector3 pos = getPosition(); + + if (HJT_HINGE == mJointInfo->mJointType) + { + // hinge = uniform circular motion + LLVector3 parent_pivot = getVelocity(); + LLVector3 parent_axis = getAcceleration(); + + angle = dt * (ang_vel * mJointInfo->mAxisOrAnchor); // AxisOrAnchor = axis + dQ.setQuat(angle, mJointInfo->mAxisOrAnchor); // AxisOrAnchor = axis + LLVector3 pivot_offset = pos - mJointInfo->mPivot; // pos in pivot-frame + pivot_offset = pivot_offset * dQ; // new rotated pivot-frame pos + pos = mJointInfo->mPivot + pivot_offset; // parent-frame + LLViewerObject::setPosition(pos); + LLQuaternion Q_PC = getRotation(); + setRotation(Q_PC * dQ); + mLastInterpUpdateSecs = time; + } + else if (HJT_POINT == mJointInfo->mJointType) + // || HJT_LPOINT == mJointInfo->mJointType) + { + // point-to-point = spin about axis and uniform circular motion + // of axis about the pivot point + // + // NOTE: this interpolation scheme is not quite good enough to + // reduce the bandwidth -- needs a gravitational correction. + // Similarly for hinges with axes that deviate from vertical. + + LLQuaternion Q_PC = getRotation(); + Q_PC = Q_PC * dQ; + setRotation(Q_PC); + + LLVector3 pivot_to_child = - mJointInfo->mAxisOrAnchor; // AxisOrAnchor = anchor + pos = mJointInfo->mPivot + pivot_to_child * Q_PC; + LLViewerObject::setPosition(pos); + mLastInterpUpdateSecs = time; + } + /* else if (HJT_WHEEL == mJointInfo->mJointInfo) + { + // wheel = uniform rotation about axis, with linear + // velocity interpolation (if any) + LLVector3 parent_axis = getAcceleration(); // HACK -- accel stores the parent-axis (parent-frame) + + LLQuaternion Q_PC = getRotation(); + + angle = dt * (parent_axis * ang_vel); + dQ.setQuat(angle, parent_axis); + + Q_PC = Q_PC * dQ; + setRotation(Q_PC); + + pos = getPosition() + dt * getVelocity(); + LLViewerObject::setPosition(pos); + mLastInterpUpdateSecs = time; + }*/ + } + } + else if (isAttachment()) + { + mLastInterpUpdateSecs = time; + return TRUE; + } + else + { // Move object based on it's velocity and rotation + interpolateLinearMotion(time, dt); + } + } + + updateDrawable(FALSE); + + return TRUE; +} + + +// Move an object due to idle-time viewer side updates by iterpolating motion +void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) +{ + // linear motion + // PHYSICS_TIMESTEP is used below to correct for the fact that the velocity in object + // updates represents the average velocity of the last timestep, rather than the final velocity. + // the time dilation above should guarantee that dt is never less than PHYSICS_TIMESTEP, theoretically + // + // *TODO: should also wrap linear accel/velocity in check + // to see if object is selected, instead of explicitly + // zeroing it out + + F64 time_since_last_update = time - mLastMessageUpdateSecs; + if (time_since_last_update <= 0.0 || dt <= 0.f) + { + return; + } + + LLVector3 accel = getAcceleration(); + LLVector3 vel = getVelocity(); + + if (sMaxUpdateInterpolationTime <= 0.0) + { // Old code path ... unbounded, simple interpolation + if (!(accel.isExactlyZero() && vel.isExactlyZero())) + { + LLVector3 pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; + + // region local + setPositionRegion(pos + getPositionRegion()); + setVelocity(vel + accel*dt); + + // for objects that are spinning but not translating, make sure to flag them as having moved + setChanged(MOVED | SILHOUETTE); + } + } + else if (!accel.isExactlyZero() || !vel.isExactlyZero()) // object is moving + { // Object is moving, and hasn't been too long since we got an update from the server + + // Calculate predicted position and velocity + LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; + LLVector3 new_v = accel * dt; + + if (time_since_last_update > sPhaseOutUpdateInterpolationTime && + sPhaseOutUpdateInterpolationTime > 0.0) + { // Haven't seen a viewer update in a while, check to see if the ciruit is still active + if (mRegionp) + { // The simulator will NOT send updates if the object continues normally on the path + // predicted by the velocity and the acceleration (often gravity) sent to the viewer + // So check to see if the circuit is blocked, which means the sim is likely in a long lag + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit( mRegionp->getHost() ); + if (cdp) + { + // Find out how many seconds since last packet arrived on the circuit + F64 time_since_last_packet = LLMessageSystem::getMessageTimeSeconds() - cdp->getLastPacketInTime(); + + if (!cdp->isAlive() || // Circuit is dead or blocked + cdp->isBlocked() || // or doesn't seem to be getting any packets + (time_since_last_packet > sPhaseOutUpdateInterpolationTime)) + { + // Start to reduce motion interpolation since we haven't seen a server update in a while + F64 time_since_last_interpolation = time - mLastInterpUpdateSecs; + F64 phase_out = 1.0; + if (time_since_last_update > sMaxUpdateInterpolationTime) + { // Past the time limit, so stop the object + phase_out = 0.0; + //llinfos << "Motion phase out to zero" << llendl; + + // Kill angular motion as well. Note - not adding this due to paranoia + // about stopping rotation for llTargetOmega objects and not having it restart + // setAngularVelocity(LLVector3::zero); + } + else if (mLastInterpUpdateSecs - mLastMessageUpdateSecs > sPhaseOutUpdateInterpolationTime) + { // Last update was already phased out a bit + phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / + (sMaxUpdateInterpolationTime - time_since_last_interpolation); + //llinfos << "Continuing motion phase out of " << (F32) phase_out << llendl; + } + else + { // Phase out from full value + phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / + (sMaxUpdateInterpolationTime - sPhaseOutUpdateInterpolationTime); + //llinfos << "Starting motion phase out of " << (F32) phase_out << llendl; + } + phase_out = llclamp(phase_out, 0.0, 1.0); + + new_pos = new_pos * ((F32) phase_out); + new_v = new_v * ((F32) phase_out); + } + } + } + } + + new_pos = new_pos + getPositionRegion(); + new_v = new_v + vel; + + + // Clamp interpolated position to minimum underground and maximum region height + LLVector3d new_pos_global = mRegionp->getPosGlobalFromRegion(new_pos); + F32 min_height; + if (isAvatar()) + { // Make a better guess about AVs not going underground + min_height = LLWorld::getInstance()->resolveLandHeightGlobal(new_pos_global); + min_height += (0.5f * getScale().mV[VZ]); + } + else + { // This will put the object underground, but we can't tell if it will stop + // at ground level or not + min_height = LLWorld::getInstance()->getMinAllowedZ(this, new_pos_global); + } + + new_pos.mV[VZ] = llmax(min_height, new_pos.mV[VZ]); + new_pos.mV[VZ] = llmin(LLWorld::getInstance()->getRegionMaxHeight(), new_pos.mV[VZ]); + + // Check to see if it's going off the region + LLVector3 temp(new_pos); + if (temp.clamp(0.f, mRegionp->getWidth())) + { // Going off this region, so see if we might end up on another region + LLVector3d old_pos_global = mRegionp->getPosGlobalFromRegion(getPositionRegion()); + new_pos_global = mRegionp->getPosGlobalFromRegion(new_pos); // Re-fetch in case it got clipped above + + // Clip the positions to known regions + LLVector3d clip_pos_global = LLWorld::getInstance()->clipToVisibleRegions(old_pos_global, new_pos_global); + if (clip_pos_global != new_pos_global) + { // Was clipped, so this means we hit a edge where there is no region to enter + + //llinfos << "Hit empty region edge, clipped predicted position to " << mRegionp->getPosRegionFromGlobal(clip_pos_global) + // << " from " << new_pos << llendl; + new_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global); + + // Stop motion and get server update for bouncing on the edge + new_v.clear(); + setAcceleration(LLVector3::zero); + } + else + { // Let predicted movement cross into another region + //llinfos << "Predicting region crossing to " << new_pos << llendl; + } + } + + // Set new position and velocity + setPositionRegion(new_pos); + setVelocity(new_v); + + // for objects that are spinning but not translating, make sure to flag them as having moved + setChanged(MOVED | SILHOUETTE); + } + + // Update the last time we did anything + mLastInterpUpdateSecs = time; +} + + + +BOOL LLViewerObject::setData(const U8 *datap, const U32 data_size) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + delete [] mData; + + if (datap) + { + mData = new U8[data_size]; + if (!mData) + { + return FALSE; + } + memcpy(mData, datap, data_size); /* Flawfinder: ignore */ + } + return TRUE; +} + +// delete an item in the inventory, but don't tell the server. This is +// used internally by remove, update, and savescript. +// This will only delete the first item with an item_id in the list +void LLViewerObject::deleteInventoryItem(const LLUUID& item_id) +{ + if(mInventory) + { + LLInventoryObject::object_list_t::iterator it = mInventory->begin(); + LLInventoryObject::object_list_t::iterator end = mInventory->end(); + for( ; it != end; ++it ) + { + if((*it)->getUUID() == item_id) + { + // This is safe only because we return immediatly. + mInventory->erase(it); // will deref and delete it + return; + } + } + doInventoryCallback(); + } +} + +void LLViewerObject::doUpdateInventory( + LLPointer& item, + U8 key, + bool is_new) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + LLViewerInventoryItem* old_item = NULL; + if(TASK_INVENTORY_ITEM_KEY == key) + { + old_item = (LLViewerInventoryItem*)getInventoryObject(item->getUUID()); + } + else if(TASK_INVENTORY_ASSET_KEY == key) + { + old_item = getInventoryItemByAsset(item->getAssetUUID()); + } + LLUUID item_id; + LLUUID new_owner; + LLUUID new_group; + BOOL group_owned = FALSE; + if(old_item) + { + item_id = old_item->getUUID(); + new_owner = old_item->getPermissions().getOwner(); + new_group = old_item->getPermissions().getGroup(); + group_owned = old_item->getPermissions().isGroupOwned(); + old_item = NULL; + } + else + { + item_id = item->getUUID(); + } + if(!is_new && mInventory) + { + // Attempt to update the local inventory. If we can get the + // object perm, we have perfect visibility, so we want the + // serial number to match. Otherwise, take our best guess and + // make sure that the serial number does not match. + deleteInventoryItem(item_id); + LLPermissions perm(item->getPermissions()); + LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(this); + bool is_atomic = ((S32)LLAssetType::AT_OBJECT == item->getType()) ? false : true; + if(obj_perm) + { + perm.setOwnerAndGroup(LLUUID::null, obj_perm->getOwner(), obj_perm->getGroup(), is_atomic); + } + else + { + if(group_owned) + { + perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic); + } + else if(!new_owner.isNull()) + { + // The object used to be in inventory, so we can + // assume the owner and group will match what they are + // there. + perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic); + } + // *FIX: can make an even better guess by using the mPermGroup flags + else if(permYouOwner()) + { + // best guess. + perm.setOwnerAndGroup(LLUUID::null, gAgent.getID(), item->getPermissions().getGroup(), is_atomic); + --mInventorySerialNum; + } + else + { + // dummy it up. + perm.setOwnerAndGroup(LLUUID::null, LLUUID::null, LLUUID::null, is_atomic); + --mInventorySerialNum; + } + } + LLViewerInventoryItem* oldItem = item; + LLViewerInventoryItem* new_item = new LLViewerInventoryItem(oldItem); + new_item->setPermissions(perm); + mInventory->push_front(new_item); + doInventoryCallback(); + ++mInventorySerialNum; + } +} + +// save a script, which involves removing the old one, and rezzing +// in the new one. This method should be called with the asset id +// of the new and old script AFTER the bytecode has been saved. +void LLViewerObject::saveScript( + const LLViewerInventoryItem* item, + BOOL active, + bool is_new) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + /* + * XXXPAM Investigate not making this copy. Seems unecessary, but I'm unsure about the + * interaction with doUpdateInventory() called below. + */ + lldebugs << "LLViewerObject::saveScript() " << item->getUUID() << " " << item->getAssetUUID() << llendl; + LLPointer task_item = + new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(), + item->getAssetUUID(), item->getType(), + item->getInventoryType(), + item->getName(), item->getDescription(), + item->getSaleInfo(), item->getFlags(), + item->getCreationDate()); + task_item->setTransactionID(item->getTransactionID()); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RezScript); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + msg->nextBlockFast(_PREHASH_UpdateBlock); + msg->addU32Fast(_PREHASH_ObjectLocalID, (mLocalID)); + U8 enabled = active; + msg->addBOOLFast(_PREHASH_Enabled, enabled); + msg->nextBlockFast(_PREHASH_InventoryBlock); + task_item->packMessage(msg); + msg->sendReliable(mRegionp->getHost()); + + // do the internal logic + doUpdateInventory(task_item, TASK_INVENTORY_ITEM_KEY, is_new); +} + +void LLViewerObject::moveInventory(const LLUUID& folder_id, + const LLUUID& item_id) +{ + lldebugs << "LLViewerObject::moveInventory " << item_id << llendl; + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_MoveTaskInventory); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_FolderID, folder_id); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_LocalID, mLocalID); + msg->addUUIDFast(_PREHASH_ItemID, item_id); + msg->sendReliable(mRegionp->getHost()); + + LLInventoryObject* inv_obj = getInventoryObject(item_id); + if(inv_obj) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_obj; + if(!item->getPermissions().allowCopyBy(gAgent.getID())) + { + deleteInventoryItem(item_id); + ++mInventorySerialNum; + } + } +} + +void LLViewerObject::dirtyInventory() +{ + // If there aren't any LLVOInventoryListeners, we won't be + // able to update our mInventory when it comes back from the + // simulator, so we should not clear the inventory either. + if(mInventory && !mInventoryCallbacks.empty()) + { + mInventory->clear(); // will deref and delete entries + delete mInventory; + mInventory = NULL; + mInventoryDirty = TRUE; + } +} + +void LLViewerObject::registerInventoryListener(LLVOInventoryListener* listener, void* user_data) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + LLInventoryCallbackInfo* info = new LLInventoryCallbackInfo; + info->mListener = listener; + info->mInventoryData = user_data; + mInventoryCallbacks.push_front(info); +} + +void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener) +{ + if (listener == NULL) + return; + for (callback_list_t::iterator iter = mInventoryCallbacks.begin(); + iter != mInventoryCallbacks.end(); ) + { + callback_list_t::iterator curiter = iter++; + LLInventoryCallbackInfo* info = *curiter; + if (info->mListener == listener) + { + delete info; + mInventoryCallbacks.erase(curiter); + break; + } + } +} + +void LLViewerObject::clearInventoryListeners() +{ + for_each(mInventoryCallbacks.begin(), mInventoryCallbacks.end(), DeletePointer()); + mInventoryCallbacks.clear(); +} + +void LLViewerObject::requestInventory() +{ + mInventoryDirty = FALSE; + if(mInventory) + { + //mInventory->clear() // will deref and delete it + //delete mInventory; + //mInventory = NULL; + doInventoryCallback(); + } + // throw away duplicate requests + else + { + fetchInventoryFromServer(); + } +} + +void LLViewerObject::fetchInventoryFromServer() +{ + if (!mInventoryPending) + { + delete mInventory; + mInventory = NULL; + mInventoryDirty = FALSE; + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RequestTaskInventory); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_LocalID, mLocalID); + msg->sendReliable(mRegionp->getHost()); + + // this will get reset by dirtyInventory or doInventoryCallback + mInventoryPending = TRUE; + } +} + +struct LLFilenameAndTask +{ + LLUUID mTaskID; + std::string mFilename; +#ifdef _DEBUG + static S32 sCount; + LLFilenameAndTask() + { + ++sCount; + lldebugs << "Constructing LLFilenameAndTask: " << sCount << llendl; + } + ~LLFilenameAndTask() + { + --sCount; + lldebugs << "Destroying LLFilenameAndTask: " << sCount << llendl; + } +private: + LLFilenameAndTask(const LLFilenameAndTask& rhs); + const LLFilenameAndTask& operator=(const LLFilenameAndTask& rhs) const; +#endif +}; + +#ifdef _DEBUG +S32 LLFilenameAndTask::sCount = 0; +#endif + +// static +void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + LLUUID task_id; + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id); + LLViewerObject* object = gObjectList.findObject(task_id); + if(!object) + { + llwarns << "LLViewerObject::processTaskInv object " + << task_id << " does not exist." << llendl; + return; + } + + msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum); + LLFilenameAndTask* ft = new LLFilenameAndTask; + ft->mTaskID = task_id; + + std::string unclean_filename; + msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); + ft->mFilename = LLDir::getScrubbedFileName(unclean_filename); + + if(ft->mFilename.empty()) + { + lldebugs << "Task has no inventory" << llendl; + // mock up some inventory to make a drop target. + if(object->mInventory) + { + object->mInventory->clear(); // will deref and delete it + } + else + { + object->mInventory = new LLInventoryObject::object_list_t(); + } + LLPointer obj; + obj = new LLInventoryObject(object->mID, LLUUID::null, + LLAssetType::AT_CATEGORY, + LLTrans::getString("ViewerObjectContents").c_str()); + object->mInventory->push_front(obj); + object->doInventoryCallback(); + delete ft; + return; + } + gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), + ft->mFilename, LL_PATH_CACHE, + object->mRegionp->getHost(), + TRUE, + &LLViewerObject::processTaskInvFile, + (void**)ft, + LLXferManager::HIGH_PRIORITY); +} + +void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status) +{ + LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data; + LLViewerObject* object = NULL; + if(ft && (0 == error_code) && + (object = gObjectList.findObject(ft->mTaskID))) + { + object->loadTaskInvFile(ft->mFilename); + } + else + { + // This Occurs When to requests were made, and the first one + // has already handled it. + lldebugs << "Problem loading task inventory. Return code: " + << error_code << llendl; + } + delete ft; +} + +void LLViewerObject::loadTaskInvFile(const std::string& filename) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + std::string filename_and_local_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, filename); + llifstream ifs(filename_and_local_path); + if(ifs.good()) + { + char buffer[MAX_STRING]; /* Flawfinder: ignore */ + // *NOTE: This buffer size is hard coded into scanf() below. + char keyword[MAX_STRING]; /* Flawfinder: ignore */ + if(mInventory) + { + mInventory->clear(); // will deref and delete it + } + else + { + mInventory = new LLInventoryObject::object_list_t; + } + while(ifs.good()) + { + ifs.getline(buffer, MAX_STRING); + sscanf(buffer, " %254s", keyword); /* Flawfinder: ignore */ + if(0 == strcmp("inv_item", keyword)) + { + LLPointer inv = new LLViewerInventoryItem; + inv->importLegacyStream(ifs); + mInventory->push_front(inv); + } + else if(0 == strcmp("inv_object", keyword)) + { + LLPointer inv = new LLInventoryObject; + inv->importLegacyStream(ifs); + inv->rename(LLTrans::getString("ViewerObjectContents").c_str()); + mInventory->push_front(inv); + } + else + { + llwarns << "Unknown token in inventory file '" + << keyword << "'" << llendl; + } + } + ifs.close(); + LLFile::remove(filename_and_local_path); + } + else + { + llwarns << "unable to load task inventory: " << filename_and_local_path + << llendl; + } + doInventoryCallback(); +} + +void LLViewerObject::doInventoryCallback() +{ + for (callback_list_t::iterator iter = mInventoryCallbacks.begin(); + iter != mInventoryCallbacks.end(); ) + { + callback_list_t::iterator curiter = iter++; + LLInventoryCallbackInfo* info = *curiter; + if (info->mListener != NULL) + { + info->mListener->inventoryChanged(this, + mInventory, + mInventorySerialNum, + info->mInventoryData); + } + else + { + llinfos << "LLViewerObject::doInventoryCallback() deleting bad listener entry." << llendl; + delete info; + mInventoryCallbacks.erase(curiter); + } + } + mInventoryPending = FALSE; +} + +void LLViewerObject::removeInventory(const LLUUID& item_id) +{ + // close any associated floater properties + LLFloaterReg::hideInstance("properties", item_id); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RemoveTaskInventory); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_LocalID, mLocalID); + msg->addUUIDFast(_PREHASH_ItemID, item_id); + msg->sendReliable(mRegionp->getHost()); + deleteInventoryItem(item_id); + ++mInventorySerialNum; +} + +void LLViewerObject::updateInventory( + LLViewerInventoryItem* item, + U8 key, + bool is_new) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + // This slices the object into what we're concerned about on the + // viewer. The simulator will take the permissions and transfer + // ownership. + LLPointer task_item = + new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(), + item->getAssetUUID(), item->getType(), + item->getInventoryType(), + item->getName(), item->getDescription(), + item->getSaleInfo(), + item->getFlags(), + item->getCreationDate()); + task_item->setTransactionID(item->getTransactionID()); + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateTaskInventory); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_UpdateData); + msg->addU32Fast(_PREHASH_LocalID, mLocalID); + msg->addU8Fast(_PREHASH_Key, key); + msg->nextBlockFast(_PREHASH_InventoryData); + task_item->packMessage(msg); + msg->sendReliable(mRegionp->getHost()); + + // do the internal logic + doUpdateInventory(task_item, key, is_new); +} + +void LLViewerObject::updateInventoryLocal(LLInventoryItem* item, U8 key) +{ + LLPointer task_item = + new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(), + item->getAssetUUID(), item->getType(), + item->getInventoryType(), + item->getName(), item->getDescription(), + item->getSaleInfo(), item->getFlags(), + item->getCreationDate()); + + // do the internal logic + const bool is_new = false; + doUpdateInventory(task_item, key, is_new); +} + +LLInventoryObject* LLViewerObject::getInventoryObject(const LLUUID& item_id) +{ + LLInventoryObject* rv = NULL; + if(mInventory) + { + LLInventoryObject::object_list_t::iterator it = mInventory->begin(); + LLInventoryObject::object_list_t::iterator end = mInventory->end(); + for ( ; it != end; ++it) + { + if((*it)->getUUID() == item_id) + { + rv = *it; + break; + } + } + } + return rv; +} + +void LLViewerObject::getInventoryContents(LLInventoryObject::object_list_t& objects) +{ + if(mInventory) + { + LLInventoryObject::object_list_t::iterator it = mInventory->begin(); + LLInventoryObject::object_list_t::iterator end = mInventory->end(); + for( ; it != end; ++it) + { + if ((*it)->getType() != LLAssetType::AT_CATEGORY) + { + objects.push_back(*it); + } + } + } +} + +LLInventoryObject* LLViewerObject::getInventoryRoot() +{ + if (!mInventory || !mInventory->size()) + { + return NULL; + } + return mInventory->back(); +} + +LLViewerInventoryItem* LLViewerObject::getInventoryItemByAsset(const LLUUID& asset_id) +{ + if (mInventoryDirty) + llwarns << "Peforming inventory lookup for object " << mID << " that has dirty inventory!" << llendl; + + LLViewerInventoryItem* rv = NULL; + if(mInventory) + { + LLViewerInventoryItem* item = NULL; + + LLInventoryObject::object_list_t::iterator it = mInventory->begin(); + LLInventoryObject::object_list_t::iterator end = mInventory->end(); + for( ; it != end; ++it) + { + LLInventoryObject* obj = *it; + if(obj->getType() != LLAssetType::AT_CATEGORY) + { + // *FIX: gank-ass down cast! + item = (LLViewerInventoryItem*)obj; + if(item->getAssetUUID() == asset_id) + { + rv = item; + break; + } + } + } + } + return rv; +} + +void LLViewerObject::updateViewerInventoryAsset( + const LLViewerInventoryItem* item, + const LLUUID& new_asset) +{ + LLPointer task_item = + new LLViewerInventoryItem(item); + task_item->setAssetUUID(new_asset); + + // do the internal logic + doUpdateInventory(task_item, TASK_INVENTORY_ITEM_KEY, false); +} + +void LLViewerObject::setPixelAreaAndAngle(LLAgent &agent) +{ + if (getVolume()) + { //volumes calculate pixel area and angle per face + return; + } + + LLVector3 viewer_pos_agent = gAgentCamera.getCameraPositionAgent(); + LLVector3 pos_agent = getRenderPosition(); + + F32 dx = viewer_pos_agent.mV[VX] - pos_agent.mV[VX]; + F32 dy = viewer_pos_agent.mV[VY] - pos_agent.mV[VY]; + F32 dz = viewer_pos_agent.mV[VZ] - pos_agent.mV[VZ]; + + F32 max_scale = getMaxScale(); + F32 mid_scale = getMidScale(); + F32 min_scale = getMinScale(); + + // IW: estimate - when close to large objects, computing range based on distance from center is no good + // to try to get a min distance from face, subtract min_scale/2 from the range. + // This means we'll load too much detail sometimes, but that's better than not enough + // I don't think there's a better way to do this without calculating distance per-poly + F32 range = sqrt(dx*dx + dy*dy + dz*dz) - min_scale/2; + + LLViewerCamera* camera = LLViewerCamera::getInstance(); + if (range < 0.001f || isHUDAttachment()) // range == zero + { + mAppAngle = 180.f; + mPixelArea = (F32)camera->getScreenPixelArea(); + } + else + { + mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG; + + F32 pixels_per_meter = camera->getPixelMeterRatio() / range; + + mPixelArea = (pixels_per_meter * max_scale) * (pixels_per_meter * mid_scale); + if (mPixelArea > camera->getScreenPixelArea()) + { + mAppAngle = 180.f; + mPixelArea = (F32)camera->getScreenPixelArea(); + } + } +} + +BOOL LLViewerObject::updateLOD() +{ + return FALSE; +} + +BOOL LLViewerObject::updateGeometry(LLDrawable *drawable) +{ + return TRUE; +} + +void LLViewerObject::updateGL() +{ + +} + +void LLViewerObject::updateFaceSize(S32 idx) +{ + +} + +LLDrawable* LLViewerObject::createDrawable(LLPipeline *pipeline) +{ + return NULL; +} + +void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped) +{ + LLPrimitive::setScale(scale); + if (mDrawable.notNull()) + { + //encompass completely sheared objects by taking + //the most extreme point possible (<1,1,0.5>) + mDrawable->setRadius(LLVector3(1,1,0.5f).scaleVec(scale).magVec()); + updateDrawable(damped); + } + + if( (LL_PCODE_VOLUME == getPCode()) && !isDead() ) + { + if (permYouOwner() || (scale.magVecSquared() > (7.5f * 7.5f)) ) + { + if (!mOnMap) + { + llassert_always(LLWorld::getInstance()->getRegionFromHandle(getRegion()->getHandle())); + + gObjectList.addToMap(this); + mOnMap = TRUE; + } + } + else + { + if (mOnMap) + { + gObjectList.removeFromMap(this); + mOnMap = FALSE; + } + } + } +} + +void LLViewerObject::setObjectCost(F32 cost) +{ + mObjectCost = cost; + mCostStale = false; + + if (isSelected()) + { + gFloaterTools->dirty(); + } +} + +void LLViewerObject::setLinksetCost(F32 cost) +{ + mLinksetCost = cost; + mCostStale = false; + + if (isSelected()) + { + gFloaterTools->dirty(); + } +} + +void LLViewerObject::setPhysicsCost(F32 cost) +{ + mPhysicsCost = cost; + mCostStale = false; + + if (isSelected()) + { + gFloaterTools->dirty(); + } +} + +void LLViewerObject::setLinksetPhysicsCost(F32 cost) +{ + mLinksetPhysicsCost = cost; + mCostStale = false; + + if (isSelected()) + { + gFloaterTools->dirty(); + } +} + + +F32 LLViewerObject::getObjectCost() +{ + if (mCostStale) + { + gObjectList.updateObjectCost(this); + } + + return mObjectCost; +} + +F32 LLViewerObject::getLinksetCost() +{ + if (mCostStale) + { + gObjectList.updateObjectCost(this); + } + + return mLinksetCost; +} + +F32 LLViewerObject::getPhysicsCost() +{ + if (mCostStale) + { + gObjectList.updateObjectCost(this); + } + + return mPhysicsCost; +} + +F32 LLViewerObject::getLinksetPhysicsCost() +{ + if (mCostStale) + { + gObjectList.updateObjectCost(this); + } + + return mLinksetPhysicsCost; +} + +F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes) +{ + return 0.f; +} + +U32 LLViewerObject::getTriangleCount() +{ + return 0; +} + +U32 LLViewerObject::getHighLODTriangleCount() +{ + return 0; +} + +void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) +{ + LLVector4a center; + center.load3(getRenderPosition().mV); + LLVector4a size; + size.load3(getScale().mV); + newMin.setSub(center, size); + newMax.setAdd(center, size); + + mDrawable->setPositionGroup(center); +} + +F32 LLViewerObject::getBinRadius() +{ + if (mDrawable.notNull()) + { + const LLVector4a* ext = mDrawable->getSpatialExtents(); + LLVector4a diff; + diff.setSub(ext[1], ext[0]); + return diff.getLength3().getF32(); + } + + return getScale().magVec(); +} + +F32 LLViewerObject::getMaxScale() const +{ + return llmax(getScale().mV[VX],getScale().mV[VY], getScale().mV[VZ]); +} + +F32 LLViewerObject::getMinScale() const +{ + return llmin(getScale().mV[0],getScale().mV[1],getScale().mV[2]); +} + +F32 LLViewerObject::getMidScale() const +{ + if (getScale().mV[VX] < getScale().mV[VY]) + { + if (getScale().mV[VY] < getScale().mV[VZ]) + { + return getScale().mV[VY]; + } + else if (getScale().mV[VX] < getScale().mV[VZ]) + { + return getScale().mV[VZ]; + } + else + { + return getScale().mV[VX]; + } + } + else if (getScale().mV[VX] < getScale().mV[VZ]) + { + return getScale().mV[VX]; + } + else if (getScale().mV[VY] < getScale().mV[VZ]) + { + return getScale().mV[VZ]; + } + else + { + return getScale().mV[VY]; + } +} + + +void LLViewerObject::updateTextures() +{ +} + +void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */) +{ + if (isDead()) + { + return; + } + + S32 i; + S32 tex_count = getNumTEs(); + for (i = 0; i < tex_count; i++) + { + getTEImage(i)->setBoostLevel(LLViewerTexture::BOOST_SELECTED); + } + + if (isSculpted() && !isMesh()) + { + LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLUUID sculpt_id = sculpt_params->getSculptTexture(); + LLViewerTextureManager::getFetchedTexture(sculpt_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)->setBoostLevel(LLViewerTexture::BOOST_SELECTED); + } + + if (boost_children) + { + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + child->boostTexturePriority(); + } + } +} + + +void LLViewerObject::setLineWidthForWindowSize(S32 window_width) +{ + if (window_width < 700) + { + LLUI::setLineWidth(2.0f); + } + else if (window_width < 1100) + { + LLUI::setLineWidth(3.0f); + } + else if (window_width < 2000) + { + LLUI::setLineWidth(4.0f); + } + else + { + // _damn_, what a nice monitor! + LLUI::setLineWidth(5.0f); + } +} + +void LLViewerObject::increaseArrowLength() +{ +/* ??? + if (mAxisArrowLength == 50) + { + mAxisArrowLength = 100; + } + else + { + mAxisArrowLength = 150; + } +*/ +} + + +void LLViewerObject::decreaseArrowLength() +{ +/* ??? + if (mAxisArrowLength == 150) + { + mAxisArrowLength = 100; + } + else + { + mAxisArrowLength = 50; + } +*/ +} + +// Culled from newsim LLTask::addNVPair +void LLViewerObject::addNVPair(const std::string& data) +{ + // cout << "LLViewerObject::addNVPair() with ---" << data << "---" << endl; + LLNameValue *nv = new LLNameValue(data.c_str()); + +// char splat[MAX_STRING]; +// temp->printNameValue(splat); +// llinfos << "addNVPair " << splat << llendl; + + name_value_map_t::iterator iter = mNameValuePairs.find(nv->mName); + if (iter != mNameValuePairs.end()) + { + LLNameValue* foundnv = iter->second; + if (foundnv->mClass != NVC_READ_ONLY) + { + delete foundnv; + mNameValuePairs.erase(iter); + } + else + { + delete nv; +// llinfos << "Trying to write to Read Only NVPair " << temp->mName << " in addNVPair()" << llendl; + return; + } + } + mNameValuePairs[nv->mName] = nv; +} + +BOOL LLViewerObject::removeNVPair(const std::string& name) +{ + char* canonical_name = gNVNameTable.addString(name); + + lldebugs << "LLViewerObject::removeNVPair(): " << name << llendl; + + name_value_map_t::iterator iter = mNameValuePairs.find(canonical_name); + if (iter != mNameValuePairs.end()) + { + if( mRegionp ) + { + LLNameValue* nv = iter->second; +/* + std::string buffer = nv->printNameValue(); + gMessageSystem->newMessageFast(_PREHASH_RemoveNameValuePair); + gMessageSystem->nextBlockFast(_PREHASH_TaskData); + gMessageSystem->addUUIDFast(_PREHASH_ID, mID); + + gMessageSystem->nextBlockFast(_PREHASH_NameValueData); + gMessageSystem->addStringFast(_PREHASH_NVPair, buffer); + + gMessageSystem->sendReliable( mRegionp->getHost() ); +*/ + // Remove the NV pair from the local list. + delete nv; + mNameValuePairs.erase(iter); + return TRUE; + } + else + { + lldebugs << "removeNVPair - No region for object" << llendl; + } + } + return FALSE; +} + + +LLNameValue *LLViewerObject::getNVPair(const std::string& name) const +{ + char *canonical_name; + + canonical_name = gNVNameTable.addString(name); + + // If you access a map with a name that isn't in it, it will add the name and a null pointer. + // So first check if the data is in the map. + name_value_map_t::const_iterator iter = mNameValuePairs.find(canonical_name); + if (iter != mNameValuePairs.end()) + { + return iter->second; + } + else + { + return NULL; + } +} + +void LLViewerObject::updatePositionCaches() const +{ + if(mRegionp) + { + if (!isRoot()) + { + mPositionRegion = ((LLViewerObject *)getParent())->getPositionRegion() + getPosition() * getParent()->getRotation(); + mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); + } + else + { + mPositionRegion = getPosition(); + mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); + } + } +} + +const LLVector3d LLViewerObject::getPositionGlobal() const +{ + if(mRegionp) + { + LLVector3d position_global = mRegionp->getPosGlobalFromRegion(getPositionRegion()); + + if (isAttachment()) + { + position_global = gAgent.getPosGlobalFromAgent(getRenderPosition()); + } + return position_global; + } + else + { + LLVector3d position_global(getPosition()); + return position_global; + } +} + +const LLVector3 &LLViewerObject::getPositionAgent() const +{ + if (mRegionp) + { + if (mDrawable.notNull() && (!mDrawable->isRoot() && getParent())) + { + // Don't return cached position if you have a parent, recalc (until all dirtying is done correctly. + LLVector3 position_region; + position_region = ((LLViewerObject *)getParent())->getPositionRegion() + getPosition() * getParent()->getRotation(); + mPositionAgent = mRegionp->getPosAgentFromRegion(position_region); + } + else + { + mPositionAgent = mRegionp->getPosAgentFromRegion(getPosition()); + } + } + return mPositionAgent; +} + +const LLVector3 &LLViewerObject::getPositionRegion() const +{ + if (!isRoot()) + { + LLViewerObject *parent = (LLViewerObject *)getParent(); + mPositionRegion = parent->getPositionRegion() + (getPosition() * parent->getRotation()); + } + else + { + mPositionRegion = getPosition(); + } + + return mPositionRegion; +} + +const LLVector3 LLViewerObject::getPositionEdit() const +{ + if (isRootEdit()) + { + return getPosition(); + } + else + { + LLViewerObject *parent = (LLViewerObject *)getParent(); + LLVector3 position_edit = parent->getPositionEdit() + getPosition() * parent->getRotationEdit(); + return position_edit; + } +} + +const LLVector3 LLViewerObject::getRenderPosition() const +{ + if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED)) + { + LLVOAvatar* avatar = getAvatar(); + if (avatar) + { + return avatar->getPositionAgent(); + } + } + + if (mDrawable.isNull() || mDrawable->getGeneration() < 0) + { + return getPositionAgent(); + } + else + { + return mDrawable->getPositionAgent(); + } +} + +const LLVector3 LLViewerObject::getPivotPositionAgent() const +{ + return getRenderPosition(); +} + +const LLQuaternion LLViewerObject::getRenderRotation() const +{ + LLQuaternion ret; + if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED)) + { + return ret; + } + + if (mDrawable.isNull() || mDrawable->isStatic()) + { + ret = getRotationEdit(); + } + else + { + if (!mDrawable->isRoot()) + { + ret = getRotation() * LLQuaternion(mDrawable->getParent()->getWorldMatrix()); + } + else + { + ret = LLQuaternion(mDrawable->getWorldMatrix()); + } + } + + return ret; +} + +const LLMatrix4 LLViewerObject::getRenderMatrix() const +{ + return mDrawable->getWorldMatrix(); +} + +const LLQuaternion LLViewerObject::getRotationRegion() const +{ + LLQuaternion global_rotation = getRotation(); + if (!((LLXform *)this)->isRoot()) + { + global_rotation = global_rotation * getParent()->getRotation(); + } + return global_rotation; +} + +const LLQuaternion LLViewerObject::getRotationEdit() const +{ + LLQuaternion global_rotation = getRotation(); + if (!((LLXform *)this)->isRootEdit()) + { + global_rotation = global_rotation * getParent()->getRotation(); + } + return global_rotation; +} + +void LLViewerObject::setPositionAbsoluteGlobal( const LLVector3d &pos_global, BOOL damped ) +{ + if (isAttachment()) + { + LLVector3 new_pos = mRegionp->getPosRegionFromGlobal(pos_global); + if (isRootEdit()) + { + new_pos -= mDrawable->mXform.getParent()->getWorldPosition(); + LLQuaternion world_rotation = mDrawable->mXform.getParent()->getWorldRotation(); + new_pos = new_pos * ~world_rotation; + } + else + { + LLViewerObject* parentp = (LLViewerObject*)getParent(); + new_pos -= parentp->getPositionAgent(); + new_pos = new_pos * ~parentp->getRotationRegion(); + } + LLViewerObject::setPosition(new_pos); + + if (mParent && ((LLViewerObject*)mParent)->isAvatar()) + { + // we have changed the position of an attachment, so we need to clamp it + LLVOAvatar *avatar = (LLVOAvatar*)mParent; + + avatar->clampAttachmentPositions(); + } + } + else + { + if( isRoot() ) + { + setPositionRegion(mRegionp->getPosRegionFromGlobal(pos_global)); + } + else + { + // the relative position with the parent is not constant + LLViewerObject* parent = (LLViewerObject *)getParent(); + //RN: this assumes we are only calling this function from the edit tools + gPipeline.updateMoveNormalAsync(parent->mDrawable); + + LLVector3 pos_local = mRegionp->getPosRegionFromGlobal(pos_global) - parent->getPositionRegion(); + pos_local = pos_local * ~parent->getRotationRegion(); + LLViewerObject::setPosition( pos_local ); + } + } + //RN: assumes we always want to snap the object when calling this function + gPipeline.updateMoveNormalAsync(mDrawable); +} + +void LLViewerObject::setPosition(const LLVector3 &pos, BOOL damped) +{ + if (getPosition() != pos) + { + setChanged(TRANSLATED | SILHOUETTE); + } + + LLXform::setPosition(pos); + updateDrawable(damped); + if (isRoot()) + { + // position caches need to be up to date on root objects + updatePositionCaches(); + } +} + +void LLViewerObject::setPositionGlobal(const LLVector3d &pos_global, BOOL damped) +{ + if (isAttachment()) + { + if (isRootEdit()) + { + LLVector3 newPos = mRegionp->getPosRegionFromGlobal(pos_global); + newPos = newPos - mDrawable->mXform.getParent()->getWorldPosition(); + + LLQuaternion invWorldRotation = mDrawable->mXform.getParent()->getWorldRotation(); + invWorldRotation.transQuat(); + + newPos = newPos * invWorldRotation; + LLViewerObject::setPosition(newPos); + } + else + { + // assumes parent is root editable (root of attachment) + LLVector3 newPos = mRegionp->getPosRegionFromGlobal(pos_global); + newPos = newPos - mDrawable->mXform.getParent()->getWorldPosition(); + LLVector3 delta_pos = newPos - getPosition(); + + LLQuaternion invRotation = mDrawable->getRotation(); + invRotation.transQuat(); + + delta_pos = delta_pos * invRotation; + + // *FIX: is this right? Shouldn't we be calling the + // LLViewerObject version of setPosition? + LLVector3 old_pos = mDrawable->mXform.getParent()->getPosition(); + mDrawable->mXform.getParent()->setPosition(old_pos + delta_pos); + setChanged(TRANSLATED | SILHOUETTE); + } + if (mParent && ((LLViewerObject*)mParent)->isAvatar()) + { + // we have changed the position of an attachment, so we need to clamp it + LLVOAvatar *avatar = (LLVOAvatar*)mParent; + + avatar->clampAttachmentPositions(); + } + } + else + { + if (isRoot()) + { + setPositionRegion(mRegionp->getPosRegionFromGlobal(pos_global)); + } + else + { + // the relative position with the parent is constant, but the parent's position needs to be changed + LLVector3d position_offset; + position_offset.setVec(getPosition()*getParent()->getRotation()); + LLVector3d new_pos_global = pos_global - position_offset; + ((LLViewerObject *)getParent())->setPositionGlobal(new_pos_global); + } + } + updateDrawable(damped); +} + + +void LLViewerObject::setPositionParent(const LLVector3 &pos_parent, BOOL damped) +{ + // Set position relative to parent, if no parent, relative to region + if (!isRoot()) + { + LLViewerObject::setPosition(pos_parent, damped); + //updateDrawable(damped); + } + else + { + setPositionRegion(pos_parent, damped); + } +} + +void LLViewerObject::setPositionRegion(const LLVector3 &pos_region, BOOL damped) +{ + if (!isRootEdit()) + { + LLViewerObject* parent = (LLViewerObject*) getParent(); + LLViewerObject::setPosition((pos_region-parent->getPositionRegion())*~parent->getRotationRegion()); + } + else + { + LLViewerObject::setPosition(pos_region); + mPositionRegion = pos_region; + mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); + } +} + +void LLViewerObject::setPositionAgent(const LLVector3 &pos_agent, BOOL damped) +{ + LLVector3 pos_region = getRegion()->getPosRegionFromAgent(pos_agent); + setPositionRegion(pos_region, damped); +} + +// identical to setPositionRegion() except it checks for child-joints +// and doesn't also move the joint-parent +// TODO -- implement similar intelligence for joint-parents toward +// their joint-children +void LLViewerObject::setPositionEdit(const LLVector3 &pos_edit, BOOL damped) +{ + if (!isRootEdit()) + { + // the relative position with the parent is constant, but the parent's position needs to be changed + LLVector3 position_offset = getPosition() * getParent()->getRotation(); + + ((LLViewerObject *)getParent())->setPositionEdit(pos_edit - position_offset); + updateDrawable(damped); + } + else if (isJointChild()) + { + // compute new parent-relative position + LLViewerObject *parent = (LLViewerObject *) getParent(); + LLQuaternion inv_parent_rot = parent->getRotation(); + inv_parent_rot.transQuat(); + LLVector3 pos_parent = (pos_edit - parent->getPositionRegion()) * inv_parent_rot; + LLViewerObject::setPosition(pos_parent, damped); + } + else + { + LLViewerObject::setPosition(pos_edit, damped); + mPositionRegion = pos_edit; + mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); + } +} + + +LLViewerObject* LLViewerObject::getRootEdit() const +{ + const LLViewerObject* root = this; + while (root->mParent + && !(root->mJointInfo + || ((LLViewerObject*)root->mParent)->isAvatar()) ) + { + root = (LLViewerObject*)root->mParent; + } + return (LLViewerObject*)root; +} + + +BOOL LLViewerObject::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + S32 face, + BOOL pick_transparent, + S32* face_hit, + LLVector3* intersection, + LLVector2* tex_coord, + LLVector3* normal, + LLVector3* bi_normal) +{ + return false; +} + +BOOL LLViewerObject::lineSegmentBoundingBox(const LLVector3& start, const LLVector3& end) +{ + if (mDrawable.isNull() || mDrawable->isDead()) + { + return FALSE; + } + + const LLVector4a* ext = mDrawable->getSpatialExtents(); + + //VECTORIZE THIS + LLVector4a center; + center.setAdd(ext[1], ext[0]); + center.mul(0.5f); + LLVector4a size; + size.setSub(ext[1], ext[0]); + size.mul(0.5f); + + LLVector4a starta, enda; + starta.load3(start.mV); + enda.load3(end.mV); + + return LLLineSegmentBoxIntersect(starta, enda, center, size); +} + +U8 LLViewerObject::getMediaType() const +{ + if (mMedia) + { + return mMedia->mMediaType; + } + else + { + return LLViewerObject::MEDIA_NONE; + } +} + +void LLViewerObject::setMediaType(U8 media_type) +{ + if (!mMedia) + { + // TODO what if we don't have a media pointer? + } + else if (mMedia->mMediaType != media_type) + { + mMedia->mMediaType = media_type; + + // TODO: update materials with new image + } +} + +std::string LLViewerObject::getMediaURL() const +{ + if (mMedia) + { + return mMedia->mMediaURL; + } + else + { + return std::string(); + } +} + +void LLViewerObject::setMediaURL(const std::string& media_url) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + if (!mMedia) + { + mMedia = new LLViewerObjectMedia; + mMedia->mMediaURL = media_url; + mMedia->mPassedWhitelist = FALSE; + + // TODO: update materials with new image + } + else if (mMedia->mMediaURL != media_url) + { + mMedia->mMediaURL = media_url; + mMedia->mPassedWhitelist = FALSE; + + // TODO: update materials with new image + } +} + +BOOL LLViewerObject::getMediaPassedWhitelist() const +{ + if (mMedia) + { + return mMedia->mPassedWhitelist; + } + else + { + return FALSE; + } +} + +void LLViewerObject::setMediaPassedWhitelist(BOOL passed) +{ + if (mMedia) + { + mMedia->mPassedWhitelist = passed; + } +} + +BOOL LLViewerObject::setMaterial(const U8 material) +{ + BOOL res = LLPrimitive::setMaterial(material); + if (res) + { + setChanged(TEXTURE); + } + return res; +} + +void LLViewerObject::setNumTEs(const U8 num_tes) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + U32 i; + if (num_tes != getNumTEs()) + { + if (num_tes) + { + LLPointer *new_images; + new_images = new LLPointer[num_tes]; + for (i = 0; i < num_tes; i++) + { + if (i < getNumTEs()) + { + new_images[i] = mTEImages[i]; + } + else if (getNumTEs()) + { + new_images[i] = mTEImages[getNumTEs()-1]; + } + else + { + new_images[i] = NULL; + } + } + + deleteTEImages(); + + mTEImages = new_images; + } + else + { + deleteTEImages(); + } + LLPrimitive::setNumTEs(num_tes); + setChanged(TEXTURE); + + if (mDrawable.notNull()) + { + gPipeline.markTextured(mDrawable); + } + } +} + +void LLViewerObject::sendMaterialUpdate() const +{ + LLViewerRegion* regionp = getRegion(); + if(!regionp) return; + gMessageSystem->newMessageFast(_PREHASH_ObjectMaterial); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); + gMessageSystem->addU8Fast(_PREHASH_Material, getMaterial() ); + gMessageSystem->sendReliable( regionp->getHost() ); + +} + +// formerly send_object_rotation +void LLViewerObject::sendRotationUpdate() const +{ + LLViewerRegion* regionp = getRegion(); + if(!regionp) return; + gMessageSystem->newMessageFast(_PREHASH_ObjectRotation); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID); + gMessageSystem->addQuatFast(_PREHASH_Rotation, getRotationEdit()); + //llinfos << "Sent rotation " << getRotationEdit() << llendl; + gMessageSystem->sendReliable( regionp->getHost() ); +} + +/* Obsolete, we use MultipleObjectUpdate instead +//// formerly send_object_position_global +//void LLViewerObject::sendPositionUpdate() const +//{ +// gMessageSystem->newMessageFast(_PREHASH_ObjectPosition); +// gMessageSystem->nextBlockFast(_PREHASH_AgentData); +// gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); +// gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +// gMessageSystem->nextBlockFast(_PREHASH_ObjectData); +// gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); +// gMessageSystem->addVector3Fast(_PREHASH_Position, getPositionRegion()); +// LLViewerRegion* regionp = getRegion(); +// gMessageSystem->sendReliable(regionp->getHost()); +//} +*/ + +//formerly send_object_shape(LLViewerObject *object) +void LLViewerObject::sendShapeUpdate() +{ + gMessageSystem->newMessageFast(_PREHASH_ObjectShape); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); + + LLVolumeMessage::packVolumeParams(&getVolume()->getParams(), gMessageSystem); + + LLViewerRegion *regionp = getRegion(); + gMessageSystem->sendReliable( regionp->getHost() ); +} + + +void LLViewerObject::sendTEUpdate() const +{ + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ObjectImage); + + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); + if (mMedia) + { + msg->addString("MediaURL", mMedia->mMediaURL); + } + else + { + msg->addString("MediaURL", NULL); + } + + // TODO send media type + + packTEMessage(msg); + + LLViewerRegion *regionp = getRegion(); + msg->sendReliable( regionp->getHost() ); +} + +void LLViewerObject::setTE(const U8 te, const LLTextureEntry &texture_entry) +{ + LLPrimitive::setTE(te, texture_entry); +// This doesn't work, don't get any textures. +// if (mDrawable.notNull() && mDrawable->isVisible()) +// { + const LLUUID& image_id = getTE(te)->getID(); + mTEImages[te] = LLViewerTextureManager::getFetchedTexture(image_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); +// } +} + +void LLViewerObject::setTEImage(const U8 te, LLViewerTexture *imagep) +{ + if (mTEImages[te] != imagep) + { + mTEImages[te] = imagep; + LLPrimitive::setTETexture(te, imagep->getID()); + setChanged(TEXTURE); + if (mDrawable.notNull()) + { + gPipeline.markTextured(mDrawable); + } + } +} + + +S32 LLViewerObject::setTETextureCore(const U8 te, const LLUUID& uuid, LLHost host) +{ + S32 retval = 0; + if (uuid != getTE(te)->getID() || + uuid == LLUUID::null) + { + retval = LLPrimitive::setTETexture(te, uuid); + mTEImages[te] = LLViewerTextureManager::getFetchedTexture(uuid, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); + setChanged(TEXTURE); + if (mDrawable.notNull()) + { + gPipeline.markTextured(mDrawable); + } + } + return retval; +} + + +void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image) +{ + if(index < 0 || index >= getNumTEs()) + { + return ; + } + mTEImages[index] = new_image ; +} + +S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid) +{ + // Invalid host == get from the agent's sim + return setTETextureCore(te, uuid, LLHost::invalid); +} + + +S32 LLViewerObject::setTEColor(const U8 te, const LLColor3& color) +{ + return setTEColor(te, LLColor4(color)); +} + +S32 LLViewerObject::setTEColor(const U8 te, const LLColor4& color) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (color != tep->getColor()) + { + retval = LLPrimitive::setTEColor(te, color); + if (mDrawable.notNull() && retval) + { + // These should only happen on updates which are not the initial update. + dirtyMesh(); + } + } + return retval; +} + +S32 LLViewerObject::setTEBumpmap(const U8 te, const U8 bump) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (bump != tep->getBumpmap()) + { + retval = LLPrimitive::setTEBumpmap(te, bump); + setChanged(TEXTURE); + if (mDrawable.notNull() && retval) + { + gPipeline.markTextured(mDrawable); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); + } + } + return retval; +} + +S32 LLViewerObject::setTETexGen(const U8 te, const U8 texgen) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (texgen != tep->getTexGen()) + { + retval = LLPrimitive::setTETexGen(te, texgen); + setChanged(TEXTURE); + } + return retval; +} + +S32 LLViewerObject::setTEMediaTexGen(const U8 te, const U8 media) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (media != tep->getMediaTexGen()) + { + retval = LLPrimitive::setTEMediaTexGen(te, media); + setChanged(TEXTURE); + } + return retval; +} + +S32 LLViewerObject::setTEShiny(const U8 te, const U8 shiny) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (shiny != tep->getShiny()) + { + retval = LLPrimitive::setTEShiny(te, shiny); + setChanged(TEXTURE); + } + return retval; +} + +S32 LLViewerObject::setTEFullbright(const U8 te, const U8 fullbright) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (fullbright != tep->getFullbright()) + { + retval = LLPrimitive::setTEFullbright(te, fullbright); + setChanged(TEXTURE); + if (mDrawable.notNull() && retval) + { + gPipeline.markTextured(mDrawable); + } + } + return retval; +} + + +S32 LLViewerObject::setTEMediaFlags(const U8 te, const U8 media_flags) +{ + // this might need work for media type + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (media_flags != tep->getMediaFlags()) + { + retval = LLPrimitive::setTEMediaFlags(te, media_flags); + setChanged(TEXTURE); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, TRUE); + gPipeline.markTextured(mDrawable); + // JC - probably only need this if changes texture coords + //gPipeline.markRebuild(mDrawable); + } + } + return retval; +} + +S32 LLViewerObject::setTEGlow(const U8 te, const F32 glow) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (glow != tep->getGlow()) + { + retval = LLPrimitive::setTEGlow(te, glow); + setChanged(TEXTURE); + if (mDrawable.notNull() && retval) + { + gPipeline.markTextured(mDrawable); + } + } + return retval; +} + + +S32 LLViewerObject::setTEScale(const U8 te, const F32 s, const F32 t) +{ + S32 retval = 0; + retval = LLPrimitive::setTEScale(te, s, t); + setChanged(TEXTURE); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + return retval; +} + +S32 LLViewerObject::setTEScaleS(const U8 te, const F32 s) +{ + S32 retval = LLPrimitive::setTEScaleS(te, s); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + + return retval; +} + +S32 LLViewerObject::setTEScaleT(const U8 te, const F32 t) +{ + S32 retval = LLPrimitive::setTEScaleT(te, t); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + + return retval; +} + +S32 LLViewerObject::setTEOffset(const U8 te, const F32 s, const F32 t) +{ + S32 retval = LLPrimitive::setTEOffset(te, s, t); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + return retval; +} + +S32 LLViewerObject::setTEOffsetS(const U8 te, const F32 s) +{ + S32 retval = LLPrimitive::setTEOffsetS(te, s); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + + return retval; +} + +S32 LLViewerObject::setTEOffsetT(const U8 te, const F32 t) +{ + S32 retval = LLPrimitive::setTEOffsetT(te, t); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + + return retval; +} + +S32 LLViewerObject::setTERotation(const U8 te, const F32 r) +{ + S32 retval = LLPrimitive::setTERotation(te, r); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + return retval; +} + + +LLViewerTexture *LLViewerObject::getTEImage(const U8 face) const +{ +// llassert(mTEImages); + + if (face < getNumTEs()) + { + LLViewerTexture* image = mTEImages[face]; + if (image) + { + return image; + } + else + { + return (LLViewerTexture*)(LLViewerFetchedTexture::sDefaultImagep); + } + } + + llerrs << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << llendl; + + return NULL; +} + + +void LLViewerObject::fitFaceTexture(const U8 face) +{ + llinfos << "fitFaceTexture not implemented" << llendl; +} + + +LLBBox LLViewerObject::getBoundingBoxAgent() const +{ + LLVector3 position_agent; + LLQuaternion rot; + LLViewerObject* avatar_parent = NULL; + LLViewerObject* root_edit = (LLViewerObject*)getRootEdit(); + if (root_edit) + { + avatar_parent = (LLViewerObject*)root_edit->getParent(); + } + + if (avatar_parent && avatar_parent->isAvatar() && + root_edit && root_edit->mDrawable.notNull() && root_edit->mDrawable->getXform()->getParent()) + { + LLXform* parent_xform = root_edit->mDrawable->getXform()->getParent(); + position_agent = (getPositionEdit() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); + rot = getRotationEdit() * parent_xform->getWorldRotation(); + } + else + { + position_agent = getPositionAgent(); + rot = getRotationRegion(); + } + + return LLBBox( position_agent, rot, getScale() * -0.5f, getScale() * 0.5f ); +} + +U32 LLViewerObject::getNumVertices() const +{ + U32 num_vertices = 0; + if (mDrawable.notNull()) + { + S32 i, num_faces; + num_faces = mDrawable->getNumFaces(); + for (i = 0; i < num_faces; i++) + { + num_vertices += mDrawable->getFace(i)->getGeomCount(); + } + } + return num_vertices; +} + +U32 LLViewerObject::getNumIndices() const +{ + U32 num_indices = 0; + if (mDrawable.notNull()) + { + S32 i, num_faces; + num_faces = mDrawable->getNumFaces(); + for (i = 0; i < num_faces; i++) + { + num_indices += mDrawable->getFace(i)->getIndicesCount(); + } + } + return num_indices; +} + +// Find the number of instances of this object's inventory that are of the given type +S32 LLViewerObject::countInventoryContents(LLAssetType::EType type) +{ + S32 count = 0; + if( mInventory ) + { + LLInventoryObject::object_list_t::const_iterator it = mInventory->begin(); + LLInventoryObject::object_list_t::const_iterator end = mInventory->end(); + for( ; it != end ; ++it ) + { + if( (*it)->getType() == type ) + { + ++count; + } + } + } + return count; +} + + +void LLViewerObject::setCanSelect(BOOL canSelect) +{ + mbCanSelect = canSelect; + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + child->mbCanSelect = canSelect; + } +} + +void LLViewerObject::setDebugText(const std::string &utf8text) +{ + if (utf8text.empty() && !mText) + { + return; + } + + if (!mText) + { + mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); + mText->setFont(LLFontGL::getFontSansSerif()); + mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); + mText->setMaxLines(-1); + mText->setSourceObject(this); + mText->setOnHUDAttachment(isHUDAttachment()); + } + mText->setColor(LLColor4::white); + mText->setString(utf8text); + mText->setZCompare(FALSE); + mText->setDoFade(FALSE); + updateText(); +} + +void LLViewerObject::setIcon(LLViewerTexture* icon_image) +{ + if (!mIcon) + { + mIcon = (LLHUDIcon *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_ICON); + mIcon->setSourceObject(this); + mIcon->setImage(icon_image); + // *TODO: make this user configurable + mIcon->setScale(0.03f); + } + else + { + mIcon->restartLifeTimer(); + } +} + +void LLViewerObject::clearIcon() +{ + if (mIcon) + { + mIcon = NULL; + } +} + +LLViewerObject* LLViewerObject::getSubParent() +{ + if (isJointChild()) + { + return this; + } + return (LLViewerObject*) getParent(); +} + +const LLViewerObject* LLViewerObject::getSubParent() const +{ + if (isJointChild()) + { + return this; + } + return (const LLViewerObject*) getParent(); +} + +BOOL LLViewerObject::isOnMap() +{ + return mOnMap; +} + + +void LLViewerObject::updateText() +{ + if (!isDead()) + { + if (mText.notNull()) + { + LLVector3 up_offset(0,0,0); + up_offset.mV[2] = getScale().mV[VZ]*0.6f; + + if (mDrawable.notNull()) + { + mText->setPositionAgent(getRenderPosition() + up_offset); + } + else + { + mText->setPositionAgent(getPositionAgent() + up_offset); + } + } + } +} + +LLVOAvatar* LLViewerObject::asAvatar() +{ + return NULL; +} + +BOOL LLViewerObject::isParticleSource() const +{ + return !mPartSourcep.isNull() && !mPartSourcep->isDead(); +} + +void LLViewerObject::setParticleSource(const LLPartSysData& particle_parameters, const LLUUID& owner_id) +{ + if (mPartSourcep) + { + deleteParticleSource(); + } + + LLPointer pss = LLViewerPartSourceScript::createPSS(this, particle_parameters); + mPartSourcep = pss; + + if (mPartSourcep) + { + mPartSourcep->setOwnerUUID(owner_id); + + if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID) + { + LLViewerTexture* image; + if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null) + { + image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.tga"); + } + else + { + image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID); + } + mPartSourcep->setImage(image); + } + } + LLViewerPartSim::getInstance()->addPartSource(pss); +} + +void LLViewerObject::unpackParticleSource(const S32 block_num, const LLUUID& owner_id) +{ + if (!mPartSourcep.isNull() && mPartSourcep->isDead()) + { + mPartSourcep = NULL; + } + if (mPartSourcep) + { + // If we've got one already, just update the existing source (or remove it) + if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep, block_num)) + { + mPartSourcep->setDead(); + mPartSourcep = NULL; + } + } + else + { + LLPointer pss = LLViewerPartSourceScript::unpackPSS(this, NULL, block_num); + //If the owner is muted, don't create the system + if(LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagParticles)) return; + + // We need to be able to deal with a particle source that hasn't changed, but still got an update! + if (pss) + { +// llinfos << "Making particle system with owner " << owner_id << llendl; + pss->setOwnerUUID(owner_id); + mPartSourcep = pss; + LLViewerPartSim::getInstance()->addPartSource(pss); + } + } + if (mPartSourcep) + { + if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID) + { + LLViewerTexture* image; + if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null) + { + image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c"); + } + else + { + image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID); + } + mPartSourcep->setImage(image); + } + } +} + +void LLViewerObject::unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_id) +{ + if (!mPartSourcep.isNull() && mPartSourcep->isDead()) + { + mPartSourcep = NULL; + } + if (mPartSourcep) + { + // If we've got one already, just update the existing source (or remove it) + if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep, dp)) + { + mPartSourcep->setDead(); + mPartSourcep = NULL; + } + } + else + { + LLPointer pss = LLViewerPartSourceScript::unpackPSS(this, NULL, dp); + //If the owner is muted, don't create the system + if(LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagParticles)) return; + // We need to be able to deal with a particle source that hasn't changed, but still got an update! + if (pss) + { +// llinfos << "Making particle system with owner " << owner_id << llendl; + pss->setOwnerUUID(owner_id); + mPartSourcep = pss; + LLViewerPartSim::getInstance()->addPartSource(pss); + } + } + if (mPartSourcep) + { + if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID) + { + LLViewerTexture* image; + if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null) + { + image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c"); + } + else + { + image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID); + } + mPartSourcep->setImage(image); + } + } +} + +void LLViewerObject::deleteParticleSource() +{ + if (mPartSourcep.notNull()) + { + mPartSourcep->setDead(); + mPartSourcep = NULL; + } +} + +// virtual +void LLViewerObject::updateDrawable(BOOL force_damped) +{ + if (mDrawable.notNull() && + !mDrawable->isState(LLDrawable::ON_MOVE_LIST) && + isChanged(MOVED)) + { + BOOL damped_motion = + !isChanged(SHIFTED) && // not shifted between regions this frame and... + ( force_damped || // ...forced into damped motion by application logic or... + ( !isSelected() && // ...not selected and... + ( mDrawable->isRoot() || // ... is root or ... + (getParent() && !((LLViewerObject*)getParent())->isSelected())// ... parent is not selected and ... + ) && + getPCode() == LL_PCODE_VOLUME && // ...is a volume object and... + getVelocity().isExactlyZero() && // ...is not moving physically and... + mDrawable->getGeneration() != -1 // ...was not created this frame. + ) + ); + gPipeline.markMoved(mDrawable, damped_motion); + } + clearChanged(SHIFTED); +} + +// virtual, overridden by LLVOVolume +F32 LLViewerObject::getVObjRadius() const +{ + return mDrawable.notNull() ? mDrawable->getRadius() : 0.f; +} + +void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const U8 flags) +{ + if (!gAudiop) + { + return; + } + + if (audio_uuid.isNull()) + { + if (!mAudioSourcep) + { + return; + } + if (mAudioSourcep->isLoop() && !mAudioSourcep->hasPendingPreloads()) + { + // We don't clear the sound if it's a loop, it'll go away on its own. + // At least, this appears to be how the scripts work. + // The attached sound ID is set to NULL to avoid it playing back when the + // object rezzes in on non-looping sounds. + //llinfos << "Clearing attached sound " << mAudioSourcep->getCurrentData()->getID() << llendl; + gAudiop->cleanupAudioSource(mAudioSourcep); + mAudioSourcep = NULL; + } + else if (flags & LL_SOUND_FLAG_STOP) + { + // Just shut off the sound + mAudioSourcep->play(LLUUID::null); + } + return; + } + if (flags & LL_SOUND_FLAG_LOOP + && mAudioSourcep && mAudioSourcep->isLoop() && mAudioSourcep->getCurrentData() + && mAudioSourcep->getCurrentData()->getID() == audio_uuid) + { + //llinfos << "Already playing this sound on a loop, ignoring" << llendl; + return; + } + + // don't clean up before previous sound is done. Solves: SL-33486 + if ( mAudioSourcep && mAudioSourcep->isDone() ) + { + gAudiop->cleanupAudioSource(mAudioSourcep); + mAudioSourcep = NULL; + } + + if (mAudioSourcep && mAudioSourcep->isMuted() && + mAudioSourcep->getCurrentData() && mAudioSourcep->getCurrentData()->getID() == audio_uuid) + { + //llinfos << "Already having this sound as muted sound, ignoring" << llendl; + return; + } + + getAudioSource(owner_id); + + if (mAudioSourcep) + { + BOOL queue = flags & LL_SOUND_FLAG_QUEUE; + mAudioGain = gain; + mAudioSourcep->setGain(gain); + mAudioSourcep->setLoop(flags & LL_SOUND_FLAG_LOOP); + mAudioSourcep->setSyncMaster(flags & LL_SOUND_FLAG_SYNC_MASTER); + mAudioSourcep->setSyncSlave(flags & LL_SOUND_FLAG_SYNC_SLAVE); + mAudioSourcep->setQueueSounds(queue); + if(!queue) // stop any current sound first to avoid "farts of doom" (SL-1541) -MG + { + mAudioSourcep->play(LLUUID::null); + } + + // Play this sound if region maturity permits + if( gAgent.canAccessMaturityAtGlobal(this->getPositionGlobal()) ) + { + //llinfos << "Playing attached sound " << audio_uuid << llendl; + mAudioSourcep->play(audio_uuid); + } + } +} + +LLAudioSource *LLViewerObject::getAudioSource(const LLUUID& owner_id) +{ + if (!mAudioSourcep) + { + // Arbitrary low gain for a sound that's not playing. + // This is used for sound preloads, for example. + LLAudioSourceVO *asvop = new LLAudioSourceVO(mID, owner_id, 0.01f, this); + + mAudioSourcep = asvop; + if(gAudiop) gAudiop->addAudioSource(asvop); + } + + return mAudioSourcep; +} + +void LLViewerObject::adjustAudioGain(const F32 gain) +{ + if (!gAudiop) + { + return; + } + if (mAudioSourcep) + { + mAudioGain = gain; + mAudioSourcep->setGain(mAudioGain); + } +} + +//---------------------------------------------------------------------------- + +bool LLViewerObject::unpackParameterEntry(U16 param_type, LLDataPacker *dp) +{ + ExtraParameter* param = getExtraParameterEntryCreate(param_type); + if (param) + { + param->data->unpack(*dp); + param->in_use = TRUE; + parameterChanged(param_type, param->data, TRUE, false); + return true; + } + else + { + return false; + } +} + +LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 param_type) +{ + LLNetworkData* new_block = NULL; + switch (param_type) + { + case LLNetworkData::PARAMS_FLEXIBLE: + { + new_block = new LLFlexibleObjectData(); + break; + } + case LLNetworkData::PARAMS_LIGHT: + { + new_block = new LLLightParams(); + break; + } + case LLNetworkData::PARAMS_SCULPT: + { + new_block = new LLSculptParams(); + break; + } + case LLNetworkData::PARAMS_LIGHT_IMAGE: + { + new_block = new LLLightImageParams(); + break; + } + default: + { + llinfos << "Unknown param type." << llendl; + break; + } + }; + + if (new_block) + { + ExtraParameter* new_entry = new ExtraParameter; + new_entry->data = new_block; + new_entry->in_use = false; // not in use yet + mExtraParameterList[param_type] = new_entry; + return new_entry; + } + return NULL; +} + +LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntry(U16 param_type) const +{ + std::map::const_iterator itor = mExtraParameterList.find(param_type); + if (itor != mExtraParameterList.end()) + { + return itor->second; + } + return NULL; +} + +LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntryCreate(U16 param_type) +{ + ExtraParameter* param = getExtraParameterEntry(param_type); + if (!param) + { + param = createNewParameterEntry(param_type); + } + return param; +} + +LLNetworkData* LLViewerObject::getParameterEntry(U16 param_type) const +{ + ExtraParameter* param = getExtraParameterEntry(param_type); + if (param) + { + return param->data; + } + else + { + return NULL; + } +} + +BOOL LLViewerObject::getParameterEntryInUse(U16 param_type) const +{ + ExtraParameter* param = getExtraParameterEntry(param_type); + if (param) + { + return param->in_use; + } + else + { + return FALSE; + } +} + +bool LLViewerObject::setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin) +{ + ExtraParameter* param = getExtraParameterEntryCreate(param_type); + if (param) + { + if (param->in_use && new_value == *(param->data)) + { + return false; + } + param->in_use = true; + param->data->copy(new_value); + parameterChanged(param_type, param->data, TRUE, local_origin); + return true; + } + else + { + return false; + } +} + +// Assumed to be called locally +// If in_use is TRUE, will crate a new extra parameter if none exists. +// Should always return true. +bool LLViewerObject::setParameterEntryInUse(U16 param_type, BOOL in_use, bool local_origin) +{ + ExtraParameter* param = getExtraParameterEntryCreate(param_type); + if (param && param->in_use != in_use) + { + param->in_use = in_use; + parameterChanged(param_type, param->data, in_use, local_origin); + return true; + } + return false; +} + +void LLViewerObject::parameterChanged(U16 param_type, bool local_origin) +{ + ExtraParameter* param = getExtraParameterEntry(param_type); + if (param) + { + parameterChanged(param_type, param->data, param->in_use, local_origin); + } +} + +void LLViewerObject::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin) +{ + if (local_origin) + { + LLViewerRegion* regionp = getRegion(); + if(!regionp) return; + + // Change happened on the viewer. Send the change up + U8 tmp[MAX_OBJECT_PARAMS_SIZE]; + LLDataPackerBinaryBuffer dpb(tmp, MAX_OBJECT_PARAMS_SIZE); + if (data->pack(dpb)) + { + U32 datasize = (U32)dpb.getCurrentSize(); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ObjectExtraParams); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); + + msg->addU16Fast(_PREHASH_ParamType, param_type); + msg->addBOOLFast(_PREHASH_ParamInUse, in_use); + + msg->addU32Fast(_PREHASH_ParamSize, datasize); + msg->addBinaryDataFast(_PREHASH_ParamData, tmp, datasize); + + msg->sendReliable( regionp->getHost() ); + } + else + { + llwarns << "Failed to send object extra parameters: " << param_type << llendl; + } + } +} + +void LLViewerObject::setDrawableState(U32 state, BOOL recursive) +{ + if (mDrawable) + { + mDrawable->setState(state); + } + if (recursive) + { + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + child->setDrawableState(state, recursive); + } + } +} + +void LLViewerObject::clearDrawableState(U32 state, BOOL recursive) +{ + if (mDrawable) + { + mDrawable->clearState(state); + } + if (recursive) + { + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + child->clearDrawableState(state, recursive); + } + } +} + +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// RN: these functions assume a 2-level hierarchy +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +// Owned by anyone? +BOOL LLViewerObject::permAnyOwner() const +{ + if (isRootEdit()) + { + return ((mFlags & FLAGS_OBJECT_ANY_OWNER) != 0); + } + else + { + return ((LLViewerObject*)getParent())->permAnyOwner(); + } +} +// Owned by this viewer? +BOOL LLViewerObject::permYouOwner() const +{ + if (isRootEdit()) + { +#ifdef HACKED_GODLIKE_VIEWER + return TRUE; +#else +# ifdef TOGGLE_HACKED_GODLIKE_VIEWER + if (!LLGridManager::getInstance()->isInProductionGrid() + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + { + return TRUE; + } +# endif + return ((mFlags & FLAGS_OBJECT_YOU_OWNER) != 0); +#endif + } + else + { + return ((LLViewerObject*)getParent())->permYouOwner(); + } +} + +// Owned by a group? +BOOL LLViewerObject::permGroupOwner() const +{ + if (isRootEdit()) + { + return ((mFlags & FLAGS_OBJECT_GROUP_OWNED) != 0); + } + else + { + return ((LLViewerObject*)getParent())->permGroupOwner(); + } +} + +// Can the owner edit +BOOL LLViewerObject::permOwnerModify() const +{ + if (isRootEdit()) + { +#ifdef HACKED_GODLIKE_VIEWER + return TRUE; +#else +# ifdef TOGGLE_HACKED_GODLIKE_VIEWER + if (!LLGridManager::getInstance()->isInProductionGrid() + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + { + return TRUE; + } +# endif + return ((mFlags & FLAGS_OBJECT_OWNER_MODIFY) != 0); +#endif + } + else + { + return ((LLViewerObject*)getParent())->permOwnerModify(); + } +} + +// Can edit +BOOL LLViewerObject::permModify() const +{ + if (isRootEdit()) + { +#ifdef HACKED_GODLIKE_VIEWER + return TRUE; +#else +# ifdef TOGGLE_HACKED_GODLIKE_VIEWER + if (!LLGridManager::getInstance()->isInProductionGrid() + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + { + return TRUE; + } +# endif + return ((mFlags & FLAGS_OBJECT_MODIFY) != 0); +#endif + } + else + { + return ((LLViewerObject*)getParent())->permModify(); + } +} + +// Can copy +BOOL LLViewerObject::permCopy() const +{ + if (isRootEdit()) + { +#ifdef HACKED_GODLIKE_VIEWER + return TRUE; +#else +# ifdef TOGGLE_HACKED_GODLIKE_VIEWER + if (!LLGridManager::getInstance()->isInProductionGrid() + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + { + return TRUE; + } +# endif + return ((mFlags & FLAGS_OBJECT_COPY) != 0); +#endif + } + else + { + return ((LLViewerObject*)getParent())->permCopy(); + } +} + +// Can move +BOOL LLViewerObject::permMove() const +{ + if (isRootEdit()) + { +#ifdef HACKED_GODLIKE_VIEWER + return TRUE; +#else +# ifdef TOGGLE_HACKED_GODLIKE_VIEWER + if (!LLGridManager::getInstance()->isInProductionGrid() + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + { + return TRUE; + } +# endif + return ((mFlags & FLAGS_OBJECT_MOVE) != 0); +#endif + } + else + { + return ((LLViewerObject*)getParent())->permMove(); + } +} + +// Can be transferred +BOOL LLViewerObject::permTransfer() const +{ + if (isRootEdit()) + { +#ifdef HACKED_GODLIKE_VIEWER + return TRUE; +#else +# ifdef TOGGLE_HACKED_GODLIKE_VIEWER + if (!LLGridManager::getInstance()->isInProductionGrid() + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + { + return TRUE; + } +# endif + return ((mFlags & FLAGS_OBJECT_TRANSFER) != 0); +#endif + } + else + { + return ((LLViewerObject*)getParent())->permTransfer(); + } +} + +// Can only open objects that you own, or that someone has +// given you modify rights to. JC +BOOL LLViewerObject::allowOpen() const +{ + return !flagInventoryEmpty() && (permYouOwner() || permModify()); +} + +LLViewerObject::LLInventoryCallbackInfo::~LLInventoryCallbackInfo() +{ + if (mListener) + { + mListener->clearVOInventoryListener(); + } +} + +void LLViewerObject::updateVolume(const LLVolumeParams& volume_params) +{ + if (setVolume(volume_params, 1)) // *FIX: magic number, ack! + { + // Transmit the update to the simulator + sendShapeUpdate(); + markForUpdate(TRUE); + } +} + +void LLViewerObject::markForUpdate(BOOL priority) +{ + if (mDrawable.notNull()) + { + gPipeline.markTextured(mDrawable); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, priority); + } +} + +bool LLViewerObject::getIncludeInSearch() const +{ + return ((mFlags & FLAGS_INCLUDE_IN_SEARCH) != 0); +} + +void LLViewerObject::setIncludeInSearch(bool include_in_search) +{ + if (include_in_search) + { + mFlags |= FLAGS_INCLUDE_IN_SEARCH; + } + else + { + mFlags &= ~FLAGS_INCLUDE_IN_SEARCH; + } +} + +void LLViewerObject::setRegion(LLViewerRegion *regionp) +{ + if (!regionp) + { + llwarns << "viewer object set region to NULL" << llendl; + } + + mLatestRecvPacketID = 0; + mRegionp = regionp; + + for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) + { + LLViewerObject* child = *i; + child->setRegion(regionp); + } + + setChanged(MOVED | SILHOUETTE); + updateDrawable(FALSE); +} + +// virtual +void LLViewerObject::updateRegion(LLViewerRegion *regionp) +{ +// if (regionp) +// { +// F64 now = LLFrameTimer::getElapsedSeconds(); +// llinfos << "Updating to region " << regionp->getName() +// << ", ms since last update message: " << (F32)((now - mLastMessageUpdateSecs) * 1000.0) +// << ", ms since last interpolation: " << (F32)((now - mLastInterpUpdateSecs) * 1000.0) +// << llendl; +// } +} + + +bool LLViewerObject::specialHoverCursor() const +{ + return (mFlags & FLAGS_USE_PHYSICS) + || (mFlags & FLAGS_HANDLE_TOUCH) + || (mClickAction != 0); +} + +void LLViewerObject::updateFlags(BOOL physics_changed) +{ + LLViewerRegion* regionp = getRegion(); + if(!regionp) return; + gMessageSystem->newMessage("ObjectFlagUpdate"); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, getLocalID() ); + gMessageSystem->addBOOLFast(_PREHASH_UsePhysics, usePhysics() ); + gMessageSystem->addBOOL("IsTemporary", flagTemporaryOnRez() ); + gMessageSystem->addBOOL("IsPhantom", flagPhantom() ); + gMessageSystem->addBOOL("CastsShadows", flagCastShadows() ); + if (physics_changed) + { + gMessageSystem->nextBlock("ExtraPhysics"); + gMessageSystem->addU8("PhysicsShapeType", getPhysicsShapeType() ); + gMessageSystem->addF32("Density", getPhysicsDensity() ); + gMessageSystem->addF32("Friction", getPhysicsFriction() ); + gMessageSystem->addF32("Restitution", getPhysicsRestitution() ); + gMessageSystem->addF32("GravityMultiplier", getPhysicsGravity() ); + } + gMessageSystem->sendReliable( regionp->getHost() ); +} + +BOOL LLViewerObject::setFlags(U32 flags, BOOL state) +{ + BOOL setit = FALSE; + if (state) + { + if ((mFlags & flags) != flags) + { + mFlags |= flags; + setit = TRUE; + } + } + else + { + if ((mFlags & flags) != 0) + { + mFlags &= ~flags; + setit = TRUE; + } + } + + // BUG: Sometimes viewer physics and simulator physics get + // out of sync. To fix this, always send update to simulator. +// if (setit) + { + updateFlags(); + } + return setit; +} + +void LLViewerObject::setPhysicsShapeType(U8 type) +{ + mPhysicsShapeUnknown = false; + mPhysicsShapeType = type; + mCostStale = true; +} + +void LLViewerObject::setPhysicsGravity(F32 gravity) +{ + mPhysicsGravity = gravity; +} + +void LLViewerObject::setPhysicsFriction(F32 friction) +{ + mPhysicsFriction = friction; +} + +void LLViewerObject::setPhysicsDensity(F32 density) +{ + mPhysicsDensity = density; +} + +void LLViewerObject::setPhysicsRestitution(F32 restitution) +{ + mPhysicsRestitution = restitution; +} + +U8 LLViewerObject::getPhysicsShapeType() const +{ + if (mPhysicsShapeUnknown) + { + mPhysicsShapeUnknown = false; + gObjectList.updatePhysicsFlags(this); + } + + return mPhysicsShapeType; +} + +void LLViewerObject::applyAngularVelocity(F32 dt) +{ + //do target omega here + mRotTime += dt; + LLVector3 ang_vel = getAngularVelocity(); + F32 omega = ang_vel.magVecSquared(); + F32 angle = 0.0f; + LLQuaternion dQ; + if (omega > 0.00001f) + { + omega = sqrt(omega); + angle = omega * dt; + + ang_vel *= 1.f/omega; + + dQ.setQuat(angle, ang_vel); + + setRotation(getRotation()*dQ); + setChanged(MOVED | SILHOUETTE); + } +} + +void LLViewerObject::resetRot() +{ + mRotTime = 0.0f; +} + +U32 LLViewerObject::getPartitionType() const +{ + return LLViewerRegion::PARTITION_NONE; +} + +void LLViewerObject::dirtySpatialGroup(BOOL priority) const +{ + if (mDrawable) + { + LLSpatialGroup* group = mDrawable->getSpatialGroup(); + if (group) + { + group->dirtyGeom(); + gPipeline.markRebuild(group, priority); + } + } +} + +void LLViewerObject::dirtyMesh() +{ + if (mDrawable) + { + LLSpatialGroup* group = mDrawable->getSpatialGroup(); + if (group) + { + group->dirtyMesh(); + } + } +} + +F32 LLAlphaObject::getPartSize(S32 idx) +{ + return 0.f; +} + +// virtual +void LLStaticViewerObject::updateDrawable(BOOL force_damped) +{ + // Force an immediate rebuild on any update + if (mDrawable.notNull()) + { + mDrawable->updateXform(TRUE); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); + } + clearChanged(SHIFTED); +} + +void LLViewerObject::saveUnselectedChildrenPosition(std::vector& positions) +{ + if(mChildList.empty() || !positions.empty()) + { + return ; + } + + for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* childp = *iter; + if (!childp->isSelected() && childp->mDrawable.notNull()) + { + positions.push_back(childp->getPositionEdit()); + } + } + + return ; +} + +void LLViewerObject::saveUnselectedChildrenRotation(std::vector& rotations) +{ + if(mChildList.empty()) + { + return ; + } + + for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* childp = *iter; + if (!childp->isSelected() && childp->mDrawable.notNull()) + { + rotations.push_back(childp->getRotationEdit()); + } + } + + return ; +} + +//counter-rotation +void LLViewerObject::resetChildrenRotationAndPosition(const std::vector& rotations, + const std::vector& positions) +{ + if(mChildList.empty()) + { + return ; + } + + S32 index = 0 ; + LLQuaternion inv_rotation = ~getRotationEdit() ; + LLVector3 offset = getPositionEdit() ; + for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* childp = *iter; + if (!childp->isSelected() && childp->mDrawable.notNull()) + { + if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR) + { + childp->setRotation(rotations[index] * inv_rotation); + childp->setPosition((positions[index] - offset) * inv_rotation); + LLManip::rebuild(childp); + } + else //avatar + { + LLVector3 reset_pos = (positions[index] - offset) * inv_rotation ; + LLQuaternion reset_rot = rotations[index] * inv_rotation ; + + ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); + ((LLVOAvatar*)childp)->mDrawable->mXform.setRotation(reset_rot) ; + + ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos, TRUE); + ((LLVOAvatar*)childp)->mDrawable->getVObj()->setRotation(reset_rot, TRUE) ; + + LLManip::rebuild(childp); + } + index++; + } + } + + return ; +} + +//counter-translation +void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplified) +{ + if(mChildList.empty()) + { + return ; + } + + LLVector3 child_offset; + if(simplified) //translation only, rotation matrix does not change + { + child_offset = offset * ~getRotation(); + } + else //rotation matrix might change too. + { + if (isAttachment() && mDrawable.notNull()) + { + LLXform* attachment_point_xform = mDrawable->getXform()->getParent(); + LLQuaternion parent_rotation = getRotation() * attachment_point_xform->getWorldRotation(); + child_offset = offset * ~parent_rotation; + } + else + { + child_offset = offset * ~getRenderRotation(); + } + } + + for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* childp = *iter; + if (!childp->isSelected() && childp->mDrawable.notNull()) + { + if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR) + { + childp->setPosition(childp->getPosition() + child_offset); + LLManip::rebuild(childp); + } + else //avatar + { + LLVector3 reset_pos = ((LLVOAvatar*)childp)->mDrawable->mXform.getPosition() + child_offset ; + + ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); + ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos); + + LLManip::rebuild(childp); + } + } + } + + return ; +} + +const LLUUID &LLViewerObject::getAttachmentItemID() const +{ + return mAttachmentItemID; +} + +void LLViewerObject::setAttachmentItemID(const LLUUID &id) +{ + mAttachmentItemID = id; +} + +EObjectUpdateType LLViewerObject::getLastUpdateType() const +{ + return mLastUpdateType; +} + +void LLViewerObject::setLastUpdateType(EObjectUpdateType last_update_type) +{ + mLastUpdateType = last_update_type; +} + +BOOL LLViewerObject::getLastUpdateCached() const +{ + return mLastUpdateCached; +} + +void LLViewerObject::setLastUpdateCached(BOOL last_update_cached) +{ + mLastUpdateCached = last_update_cached; +} + +const LLUUID &LLViewerObject::extractAttachmentItemID() +{ + LLUUID item_id = LLUUID::null; + LLNameValue* item_id_nv = getNVPair("AttachItemID"); + if( item_id_nv ) + { + const char* s = item_id_nv->getString(); + if( s ) + { + item_id.set(s); + } + } + setAttachmentItemID(item_id); + return getAttachmentItemID(); +} + +//virtual +LLVOAvatar* LLViewerObject::getAvatar() const +{ + if (isAttachment()) + { + LLViewerObject* vobj = (LLViewerObject*) getParent(); + + while (vobj && !vobj->asAvatar()) + { + vobj = (LLViewerObject*) vobj->getParent(); + } + + return (LLVOAvatar*) vobj; + } + + return NULL; +} + + +class ObjectPhysicsProperties : public LLHTTPNode +{ +public: + virtual void post( + ResponsePtr responder, + const LLSD& context, + const LLSD& input) const + { + LLSD object_data = input["body"]["ObjectData"]; + S32 num_entries = object_data.size(); + + for ( S32 i = 0; i < num_entries; i++ ) + { + LLSD& curr_object_data = object_data[i]; + U32 local_id = curr_object_data["LocalID"].asInteger(); + + // Iterate through nodes at end, since it can be on both the regular AND hover list + struct f : public LLSelectedNodeFunctor + { + U32 mID; + f(const U32& id) : mID(id) {} + virtual bool apply(LLSelectNode* node) + { + return (node->getObject() && node->getObject()->mLocalID == mID ); + } + } func(local_id); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(&func); + + if (node) + { + // The LLSD message builder doesn't know how to handle U8, so we need to send as S8 and cast + U8 type = (U8)curr_object_data["PhysicsShapeType"].asInteger(); + F32 density = (F32)curr_object_data["Density"].asReal(); + F32 friction = (F32)curr_object_data["Friction"].asReal(); + F32 restitution = (F32)curr_object_data["Restitution"].asReal(); + F32 gravity = (F32)curr_object_data["GravityMultiplier"].asReal(); + + node->getObject()->setPhysicsShapeType(type); + node->getObject()->setPhysicsGravity(gravity); + node->getObject()->setPhysicsFriction(friction); + node->getObject()->setPhysicsDensity(density); + node->getObject()->setPhysicsRestitution(restitution); + } + } + + dialog_refresh_all(); + }; +}; + +LLHTTPRegistration + gHTTPRegistrationObjectPhysicsProperties("/message/ObjectPhysicsProperties"); + + +void LLViewerObject::updateQuota( const SelectionQuota& quota ) +{ + //update quotas + mSelectionQuota = quota; +} diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 1335c5c319..a0ad52df6b 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -1,825 +1,825 @@ -/** - * @file llviewerobject.h - * @brief Description of LLViewerObject class, which is the base class for most objects in the viewer. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLVIEWEROBJECT_H -#define LL_LLVIEWEROBJECT_H - -#include - -#include "llassetstorage.h" -#include "lldarrayptr.h" -#include "llhudicon.h" -#include "llinventory.h" -#include "llrefcount.h" -#include "llmemtype.h" -#include "llprimitive.h" -#include "lluuid.h" -#include "llvoinventorylistener.h" -#include "object_flags.h" -#include "llquaternion.h" -#include "v3dmath.h" -#include "v3math.h" -#include "llvertexbuffer.h" -#include "llaccountingquota.h" - -class LLAgent; // TODO: Get rid of this. -class LLAudioSource; -class LLAudioSourceVO; -class LLBBox; -class LLDataPacker; -class LLColor4; -class LLFrameTimer; -class LLDrawable; -class LLHost; -class LLHUDText; -class LLWorld; -class LLNameValue; -class LLNetMap; -class LLMessageSystem; -class LLPartSysData; -class LLPrimitive; -class LLPipeline; -class LLTextureEntry; -class LLViewerTexture; -class LLViewerInventoryItem; -class LLViewerObject; -class LLViewerPartSourceScript; -class LLViewerRegion; -class LLViewerObjectMedia; -class LLVOInventoryListener; -class LLVOAvatar; - -typedef enum e_object_update_type -{ - OUT_FULL, - OUT_TERSE_IMPROVED, - OUT_FULL_COMPRESSED, - OUT_FULL_CACHED, - OUT_UNKNOWN, -} EObjectUpdateType; - - -// callback typedef for inventory -typedef void (*inventory_callback)(LLViewerObject*, - LLInventoryObject::object_list_t*, - S32 serial_num, - void*); - -// a small struct for keeping track of joints -struct LLVOJointInfo -{ - EHavokJointType mJointType; - LLVector3 mPivot; // parent-frame - // whether the below an axis or anchor (and thus its frame) - // depends on the joint type: - // HINGE ==> axis=parent-frame - // P2P ==> anchor=child-frame - LLVector3 mAxisOrAnchor; -}; - -// for exporting textured materials from SL -struct LLMaterialExportInfo -{ -public: - LLMaterialExportInfo(S32 mat_index, S32 texture_index, LLColor4 color) : - mMaterialIndex(mat_index), mTextureIndex(texture_index), mColor(color) {}; - - S32 mMaterialIndex; - S32 mTextureIndex; - LLColor4 mColor; -}; - -//============================================================================ - -class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate -{ -protected: - ~LLViewerObject(); // use unref() - - // TomY: Provide for a list of extra parameter structures, mapped by structure name - struct ExtraParameter - { - BOOL in_use; - LLNetworkData *data; - }; - std::map mExtraParameterList; - -public: - typedef std::list > child_list_t; - typedef std::list > vobj_list_t; - - typedef const child_list_t const_child_list_t; - - LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global = FALSE); - MEM_TYPE_NEW(LLMemType::MTYPE_OBJECT); - - virtual void markDead(); // Mark this object as dead, and clean up its references - BOOL isDead() const {return mDead;} - BOOL isOrphaned() const { return mOrphaned; } - BOOL isParticleSource() const; - - virtual LLVOAvatar* asAvatar(); - - static void initVOClasses(); - static void cleanupVOClasses(); - - void addNVPair(const std::string& data); - BOOL removeNVPair(const std::string& name); - LLNameValue* getNVPair(const std::string& name) const; // null if no name value pair by that name - - // Object create and update functions - virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); - - // Types of media we can associate - enum { MEDIA_NONE = 0, MEDIA_SET = 1 }; - - // Return codes for processUpdateMessage - enum { - MEDIA_URL_REMOVED = 0x1, - MEDIA_URL_ADDED = 0x2, - MEDIA_URL_UPDATED = 0x4, - MEDIA_FLAGS_CHANGED = 0x8, - INVALID_UPDATE = 0x80000000 - }; - - virtual U32 processUpdateMessage(LLMessageSystem *mesgsys, - void **user_data, - U32 block_num, - const EObjectUpdateType update_type, - LLDataPacker *dp); - - - virtual BOOL isActive() const; // Whether this object needs to do an idleUpdate. - BOOL onActiveList() const {return mOnActiveList;} - void setOnActiveList(BOOL on_active) { mOnActiveList = on_active; } - - virtual BOOL isAttachment() const { return FALSE; } - virtual LLVOAvatar* getAvatar() const; //get the avatar this object is attached to, or NULL if object is not an attachment - virtual BOOL isHUDAttachment() const { return FALSE; } - virtual void updateRadius() {}; - virtual F32 getVObjRadius() const; // default implemenation is mDrawable->getRadius() - - BOOL isJointChild() const { return mJointInfo ? TRUE : FALSE; } - EHavokJointType getJointType() const { return mJointInfo ? mJointInfo->mJointType : HJT_INVALID; } - // for jointed and other parent-relative hacks - LLViewerObject* getSubParent(); - const LLViewerObject* getSubParent() const; - - // Object visiblility and GPW functions - virtual void setPixelAreaAndAngle(LLAgent &agent); // Override to generate accurate apparent angle and area - - virtual U32 getNumVertices() const; - virtual U32 getNumIndices() const; - S32 getNumFaces() const { return mNumFaces; } - - // Graphical stuff for objects - maybe broken out into render class later? - virtual void updateTextures(); - virtual void boostTexturePriority(BOOL boost_children = TRUE); // When you just want to boost priority of this object - - virtual LLDrawable* createDrawable(LLPipeline *pipeline); - virtual BOOL updateGeometry(LLDrawable *drawable); - virtual void updateGL(); - virtual void updateFaceSize(S32 idx); - virtual BOOL updateLOD(); - virtual BOOL setDrawableParent(LLDrawable* parentp); - F32 getRotTime() { return mRotTime; } - void resetRot(); - void applyAngularVelocity(F32 dt); - - void setLineWidthForWindowSize(S32 window_width); - - static void increaseArrowLength(); // makes axis arrows for selections longer - static void decreaseArrowLength(); // makes axis arrows for selections shorter - - // Accessor functions - LLViewerRegion* getRegion() const { return mRegionp; } - - BOOL isSelected() const { return mUserSelected; } - virtual void setSelected(BOOL sel) { mUserSelected = sel; mRotTime = 0.f;} - - const LLUUID &getID() const { return mID; } - U32 getLocalID() const { return mLocalID; } - U32 getCRC() const { return mTotalCRC; } - - virtual BOOL isFlexible() const { return FALSE; } - virtual BOOL isSculpted() const { return FALSE; } - virtual BOOL isMesh() const { return FALSE; } - virtual BOOL hasLightTexture() const { return FALSE; } - - // This method returns true if the object is over land owned by - // the agent, one of its groups, or it encroaches and - // anti-encroachment is enabled - bool isReturnable(); - - /* - // This method will scan through this object, and then query the - // selection manager to see if the local agent probably has the - // ability to modify the object. Since this calls into the - // selection manager, you should avoid calling this method from - // there. - BOOL isProbablyModifiable() const; - */ - - virtual BOOL setParent(LLViewerObject* parent); - virtual void addChild(LLViewerObject *childp); - virtual void removeChild(LLViewerObject *childp); - const_child_list_t& getChildren() const { return mChildList; } - S32 numChildren() const { return mChildList.size(); } - void addThisAndAllChildren(std::vector& objects); - void addThisAndNonJointChildren(std::vector& objects); - BOOL isChild(LLViewerObject *childp) const; - BOOL isSeat() const; - - - //detect if given line segment (in agent space) intersects with this viewer object. - //returns TRUE if intersection detected and returns information about intersection - virtual BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, - S32 face = -1, // which face to check, -1 = ALL_SIDES - BOOL pick_transparent = FALSE, - S32* face_hit = NULL, // which face was hit - LLVector3* intersection = NULL, // return the intersection point - LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point - ); - - virtual BOOL lineSegmentBoundingBox(const LLVector3& start, const LLVector3& end); - - virtual const LLVector3d getPositionGlobal() const; - virtual const LLVector3 &getPositionRegion() const; - virtual const LLVector3 getPositionEdit() const; - virtual const LLVector3 &getPositionAgent() const; - virtual const LLVector3 getRenderPosition() const; - - virtual const LLVector3 getPivotPositionAgent() const; // Usually = to getPositionAgent, unless like flex objects it's not - - LLViewerObject* getRootEdit() const; - - const LLQuaternion getRotationRegion() const; - const LLQuaternion getRotationEdit() const; - const LLQuaternion getRenderRotation() const; - virtual const LLMatrix4 getRenderMatrix() const; - - void setPosition(const LLVector3 &pos, BOOL damped = FALSE); - void setPositionGlobal(const LLVector3d &position, BOOL damped = FALSE); - void setPositionRegion(const LLVector3 &position, BOOL damped = FALSE); - void setPositionEdit(const LLVector3 &position, BOOL damped = FALSE); - void setPositionAgent(const LLVector3 &pos_agent, BOOL damped = FALSE); - void setPositionParent(const LLVector3 &pos_parent, BOOL damped = FALSE); - void setPositionAbsoluteGlobal( const LLVector3d &pos_global, BOOL damped = FALSE ); - - virtual const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const { return xform->getWorldMatrix(); } - - inline void setRotation(const F32 x, const F32 y, const F32 z, BOOL damped = FALSE); - inline void setRotation(const LLQuaternion& quat, BOOL damped = FALSE); - void sendRotationUpdate() const; - - /*virtual*/ void setNumTEs(const U8 num_tes); - /*virtual*/ void setTE(const U8 te, const LLTextureEntry &texture_entry); - /*virtual*/ S32 setTETexture(const U8 te, const LLUUID &uuid); - S32 setTETextureCore(const U8 te, const LLUUID& uuid, LLHost host); - /*virtual*/ S32 setTEColor(const U8 te, const LLColor3 &color); - /*virtual*/ S32 setTEColor(const U8 te, const LLColor4 &color); - /*virtual*/ S32 setTEScale(const U8 te, const F32 s, const F32 t); - /*virtual*/ S32 setTEScaleS(const U8 te, const F32 s); - /*virtual*/ S32 setTEScaleT(const U8 te, const F32 t); - /*virtual*/ S32 setTEOffset(const U8 te, const F32 s, const F32 t); - /*virtual*/ S32 setTEOffsetS(const U8 te, const F32 s); - /*virtual*/ S32 setTEOffsetT(const U8 te, const F32 t); - /*virtual*/ S32 setTERotation(const U8 te, const F32 r); - /*virtual*/ S32 setTEBumpmap(const U8 te, const U8 bump ); - /*virtual*/ S32 setTETexGen(const U8 te, const U8 texgen ); - /*virtual*/ S32 setTEMediaTexGen(const U8 te, const U8 media ); // *FIXME: this confusingly acts upon a superset of setTETexGen's flags without absorbing its semantics - /*virtual*/ S32 setTEShiny(const U8 te, const U8 shiny ); - /*virtual*/ S32 setTEFullbright(const U8 te, const U8 fullbright ); - /*virtual*/ S32 setTEMediaFlags(const U8 te, const U8 media_flags ); - /*virtual*/ S32 setTEGlow(const U8 te, const F32 glow); - /*virtual*/ BOOL setMaterial(const U8 material); - virtual void setTEImage(const U8 te, LLViewerTexture *imagep); // Not derived from LLPrimitive - void changeTEImage(S32 index, LLViewerTexture* new_image) ; - LLViewerTexture *getTEImage(const U8 te) const; - - void fitFaceTexture(const U8 face); - void sendTEUpdate() const; // Sends packed representation of all texture entry information - - virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE); - - virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL); - virtual U32 getTriangleCount(); - virtual U32 getHighLODTriangleCount(); - - void setObjectCost(F32 cost); - F32 getObjectCost(); - - void setLinksetCost(F32 cost); - F32 getLinksetCost(); - - void setPhysicsCost(F32 cost); - F32 getPhysicsCost(); - - void setLinksetPhysicsCost(F32 cost); - F32 getLinksetPhysicsCost(); - - void sendShapeUpdate(); - - U8 getState() { return mState; } - - F32 getAppAngle() const { return mAppAngle; } - F32 getPixelArea() const { return mPixelArea; } - void setPixelArea(F32 area) { mPixelArea = area; } - F32 getMaxScale() const; - F32 getMidScale() const; - F32 getMinScale() const; - - // Owner id is this object's owner - void setAttachedSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const U8 flags); - void adjustAudioGain(const F32 gain); - void clearAttachedSound() { mAudioSourcep = NULL; } - - // Create if necessary - LLAudioSource *getAudioSource(const LLUUID& owner_id); - bool isAudioSource() {return mAudioSourcep != NULL;} - - U8 getMediaType() const; - void setMediaType(U8 media_type); - - std::string getMediaURL() const; - void setMediaURL(const std::string& media_url); - - BOOL getMediaPassedWhitelist() const; - void setMediaPassedWhitelist(BOOL passed); - - void sendMaterialUpdate() const; - - void setCanSelect(BOOL canSelect); - - void setDebugText(const std::string &utf8text); - void setIcon(LLViewerTexture* icon_image); - void clearIcon(); - - void markForUpdate(BOOL priority); - void updateVolume(const LLVolumeParams& volume_params); - virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max); - virtual F32 getBinRadius(); - - LLBBox getBoundingBoxAgent() const; - - void updatePositionCaches() const; // Update the global and region position caches from the object (and parent's) xform. - void updateText(); // update text label position - virtual void updateDrawable(BOOL force_damped); // force updates on static objects - - void setDrawableState(U32 state, BOOL recursive = TRUE); - void clearDrawableState(U32 state, BOOL recursive = TRUE); - - // Called when the drawable shifts - virtual void onShift(const LLVector4a &shift_vector) { } - - ////////////////////////////////////// - // - // Inventory methods - // - - // This function is called when someone is interested in a viewer - // object's inventory. The callback is called as soon as the - // viewer object has the inventory stored locally. - void registerInventoryListener(LLVOInventoryListener* listener, void* user_data); - void removeInventoryListener(LLVOInventoryListener* listener); - BOOL isInventoryPending() { return mInventoryPending; } - void clearInventoryListeners(); - void requestInventory(); - void fetchInventoryFromServer(); - static void processTaskInv(LLMessageSystem* msg, void** user_data); - void removeInventory(const LLUUID& item_id); - - // The updateInventory() call potentially calls into the selection - // manager, so do no call updateInventory() from the selection - // manager until we have better iterators. - void updateInventory(LLViewerInventoryItem* item, U8 key, bool is_new); - void updateInventoryLocal(LLInventoryItem* item, U8 key); // Update without messaging. - LLInventoryObject* getInventoryObject(const LLUUID& item_id); - void getInventoryContents(LLInventoryObject::object_list_t& objects); - LLInventoryObject* getInventoryRoot(); - LLViewerInventoryItem* getInventoryItemByAsset(const LLUUID& asset_id); - S16 getInventorySerial() const { return mInventorySerialNum; } - - // These functions does viewer-side only object inventory modifications - void updateViewerInventoryAsset( - const LLViewerInventoryItem* item, - const LLUUID& new_asset); - - // This function will make sure that we refresh the inventory. - void dirtyInventory(); - BOOL isInventoryDirty() { return mInventoryDirty; } - - // save a script, which involves removing the old one, and rezzing - // in the new one. This method should be called with the asset id - // of the new and old script AFTER the bytecode has been saved. - void saveScript(const LLViewerInventoryItem* item, BOOL active, bool is_new); - - // move an inventory item out of the task and into agent - // inventory. This operation is based on messaging. No permissions - // checks are made on the viewer - the server will double check. - void moveInventory(const LLUUID& agent_folder, const LLUUID& item_id); - - // Find the number of instances of this object's inventory that are of the given type - S32 countInventoryContents( LLAssetType::EType type ); - - BOOL permAnyOwner() const; - BOOL permYouOwner() const; - BOOL permGroupOwner() const; - BOOL permOwnerModify() const; - BOOL permModify() const; - BOOL permCopy() const; - BOOL permMove() const; - BOOL permTransfer() const; - inline BOOL usePhysics() const { return ((mFlags & FLAGS_USE_PHYSICS) != 0); } - inline BOOL flagScripted() const { return ((mFlags & FLAGS_SCRIPTED) != 0); } - inline BOOL flagHandleTouch() const { return ((mFlags & FLAGS_HANDLE_TOUCH) != 0); } - inline BOOL flagTakesMoney() const { return ((mFlags & FLAGS_TAKES_MONEY) != 0); } - inline BOOL flagPhantom() const { return ((mFlags & FLAGS_PHANTOM) != 0); } - inline BOOL flagInventoryEmpty() const { return ((mFlags & FLAGS_INVENTORY_EMPTY) != 0); } - inline BOOL flagCastShadows() const { return ((mFlags & FLAGS_CAST_SHADOWS) != 0); } - inline BOOL flagAllowInventoryAdd() const { return ((mFlags & FLAGS_ALLOW_INVENTORY_DROP) != 0); } - inline BOOL flagTemporary() const { return ((mFlags & FLAGS_TEMPORARY) != 0); } - inline BOOL flagTemporaryOnRez() const { return ((mFlags & FLAGS_TEMPORARY_ON_REZ) != 0); } - inline BOOL flagAnimSource() const { return ((mFlags & FLAGS_ANIM_SOURCE) != 0); } - inline BOOL flagCameraSource() const { return ((mFlags & FLAGS_CAMERA_SOURCE) != 0); } - inline BOOL flagCameraDecoupled() const { return ((mFlags & FLAGS_CAMERA_DECOUPLED) != 0); } - inline BOOL flagObjectMove() const { return ((mFlags & FLAGS_OBJECT_MOVE) != 0); } - - U8 getPhysicsShapeType() const; - inline F32 getPhysicsGravity() const { return mPhysicsGravity; } - inline F32 getPhysicsFriction() const { return mPhysicsFriction; } - inline F32 getPhysicsDensity() const { return mPhysicsDensity; } - inline F32 getPhysicsRestitution() const { return mPhysicsRestitution; } - - bool getIncludeInSearch() const; - void setIncludeInSearch(bool include_in_search); - - // Does "open" object menu item apply? - BOOL allowOpen() const; - - void setClickAction(U8 action) { mClickAction = action; } - U8 getClickAction() const { return mClickAction; } - bool specialHoverCursor() const; // does it have a special hover cursor? - - void setRegion(LLViewerRegion *regionp); - virtual void updateRegion(LLViewerRegion *regionp); - - void updateFlags(BOOL physics_changed = FALSE); - BOOL setFlags(U32 flag, BOOL state); - void setPhysicsShapeType(U8 type); - void setPhysicsGravity(F32 gravity); - void setPhysicsFriction(F32 friction); - void setPhysicsDensity(F32 density); - void setPhysicsRestitution(F32 restitution); - - virtual void dump() const; - static U32 getNumZombieObjects() { return sNumZombieObjects; } - - void printNameValuePairs() const; - - virtual S32 getLOD() const { return 3; } - virtual U32 getPartitionType() const; - virtual void dirtySpatialGroup(BOOL priority = FALSE) const; - virtual void dirtyMesh(); - - virtual LLNetworkData* getParameterEntry(U16 param_type) const; - virtual bool setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin); - virtual BOOL getParameterEntryInUse(U16 param_type) const; - virtual bool setParameterEntryInUse(U16 param_type, BOOL in_use, bool local_origin); - // Called when a parameter is changed - virtual void parameterChanged(U16 param_type, bool local_origin); - virtual void parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin); - - friend class LLViewerObjectList; - friend class LLViewerMediaList; - -public: - //counter-translation - void resetChildrenPosition(const LLVector3& offset, BOOL simplified = FALSE) ; - //counter-rotation - void resetChildrenRotationAndPosition(const std::vector& rotations, - const std::vector& positions) ; - void saveUnselectedChildrenRotation(std::vector& rotations) ; - void saveUnselectedChildrenPosition(std::vector& positions) ; - std::vector mUnselectedChildrenPositions ; - -private: - ExtraParameter* createNewParameterEntry(U16 param_type); - ExtraParameter* getExtraParameterEntry(U16 param_type) const; - ExtraParameter* getExtraParameterEntryCreate(U16 param_type); - bool unpackParameterEntry(U16 param_type, LLDataPacker *dp); - - // This function checks to see if the given media URL has changed its version - // and the update wasn't due to this agent's last action. - U32 checkMediaURL(const std::string &media_url); - - // Motion prediction between updates - void interpolateLinearMotion(const F64 & time, const F32 & dt); - -public: - // - // Viewer-side only types - use the LL_PCODE_APP mask. - // - typedef enum e_vo_types - { - LL_VO_CLOUDS = LL_PCODE_APP | 0x20, - LL_VO_SURFACE_PATCH = LL_PCODE_APP | 0x30, - LL_VO_WL_SKY = LL_PCODE_APP | 0x40, - LL_VO_SQUARE_TORUS = LL_PCODE_APP | 0x50, - LL_VO_SKY = LL_PCODE_APP | 0x60, - LL_VO_VOID_WATER = LL_PCODE_APP | 0x70, - LL_VO_WATER = LL_PCODE_APP | 0x80, - LL_VO_GROUND = LL_PCODE_APP | 0x90, - LL_VO_PART_GROUP = LL_PCODE_APP | 0xa0, - LL_VO_TRIANGLE_TORUS = LL_PCODE_APP | 0xb0, - LL_VO_HUD_PART_GROUP = LL_PCODE_APP | 0xc0, - } EVOType; - - typedef enum e_physics_shape_types - { - PHYSICS_SHAPE_PRIM = 0, - PHYSICS_SHAPE_NONE, - PHYSICS_SHAPE_CONVEX_HULL, - } EPhysicsShapeType; - - LLUUID mID; - - // unique within region, not unique across regions - // Local ID = 0 is not used - U32 mLocalID; - - // Last total CRC received from sim, used for caching - U32 mTotalCRC; - - LLPointer *mTEImages; - - // Selection, picking and rendering variables - U32 mGLName; // GL "name" used by selection code - BOOL mbCanSelect; // true if user can select this object by clicking - - // Grabbed from UPDATE_FLAGS - U32 mFlags; - - // Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties - U8 mPhysicsShapeType; - F32 mPhysicsGravity; - F32 mPhysicsFriction; - F32 mPhysicsDensity; - F32 mPhysicsRestitution; - - - // Pipeline classes - LLPointer mDrawable; - - // Band-aid to select object after all creation initialization is done - BOOL mCreateSelected; - - // Replace textures with web pages on this object while drawing - BOOL mRenderMedia; - - // In bits - S32 mBestUpdatePrecision; - - // TODO: Make all this stuff private. JC - LLPointer mText; - LLPointer mIcon; - - static BOOL sUseSharedDrawables; - -protected: - // delete an item in the inventory, but don't tell the - // server. This is used internally by remove, update, and - // savescript. - void deleteInventoryItem(const LLUUID& item_id); - - // do the update/caching logic. called by saveScript and - // updateInventory. - void doUpdateInventory(LLPointer& item, U8 key, bool is_new); - - - static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp); - - BOOL setData(const U8 *datap, const U32 data_size); - - // Hide or show HUD, icon and particles - void hideExtraDisplayItems( BOOL hidden ); - - ////////////////////////// - // - // inventory functionality - // - - static void processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status); - void loadTaskInvFile(const std::string& filename); - void doInventoryCallback(); - - BOOL isOnMap(); - - void unpackParticleSource(const S32 block_num, const LLUUID& owner_id); - void unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_id); - void deleteParticleSource(); - void setParticleSource(const LLPartSysData& particle_parameters, const LLUUID& owner_id); - -public: - void updateQuota( const SelectionQuota& quota ); - const SelectionQuota& getQuota( void ) { return mSelectionQuota; } - -private: - void setNameValueList(const std::string& list); // clears nv pairs and then individually adds \n separated NV pairs from \0 terminated string - void deleteTEImages(); // correctly deletes list of images - -protected: - typedef std::map name_value_map_t; - name_value_map_t mNameValuePairs; // Any name-value pairs stored by script - - child_list_t mChildList; - - F64 mLastInterpUpdateSecs; // Last update for purposes of interpolation - F64 mLastMessageUpdateSecs; // Last update from a message from the simulator - TPACKETID mLatestRecvPacketID; // Latest time stamp on message from simulator - - // extra data sent from the sim...currently only used for tree species info - U8* mData; - - LLPointer mPartSourcep; // Particle source associated with this object. - LLAudioSourceVO* mAudioSourcep; - F32 mAudioGain; - - F32 mAppAngle; // Apparent visual arc in degrees - F32 mPixelArea; // Apparent area in pixels - - // This is the object's inventory from the viewer's perspective. - LLInventoryObject::object_list_t* mInventory; - class LLInventoryCallbackInfo - { - public: - ~LLInventoryCallbackInfo(); - LLVOInventoryListener* mListener; - void* mInventoryData; - }; - typedef std::list callback_list_t; - callback_list_t mInventoryCallbacks; - S16 mInventorySerialNum; - - LLViewerRegion *mRegionp; // Region that this object belongs to. - BOOL mInventoryPending; - BOOL mInventoryDirty; - BOOL mDead; - BOOL mOrphaned; // This is an orphaned child - BOOL mUserSelected; // Cached user select information - BOOL mOnActiveList; - BOOL mOnMap; // On the map. - BOOL mStatic; // Object doesn't move. - S32 mNumFaces; - - F32 mTimeDilation; // Time dilation sent with the object. - F32 mRotTime; // Amount (in seconds) that object has rotated according to angular velocity (llSetTargetOmega) - LLQuaternion mLastRot; // last rotation received from the simulator - - LLVOJointInfo* mJointInfo; - U8 mState; // legacy - LLViewerObjectMedia* mMedia; // NULL if no media associated - U8 mClickAction; - F32 mObjectCost; //resource cost of this object or -1 if unknown - F32 mLinksetCost; - F32 mPhysicsCost; - F32 mLinksetPhysicsCost; - - SelectionQuota mSelectionQuota; - - bool mCostStale; - mutable bool mPhysicsShapeUnknown; - - static U32 sNumZombieObjects; // Objects which are dead, but not deleted - - static BOOL sMapDebug; // Map render mode - static LLColor4 sEditSelectColor; - static LLColor4 sNoEditSelectColor; - static F32 sCurrentPulse; - static BOOL sPulseEnabled; - - static S32 sAxisArrowLength; - - // These two caches are only correct for non-parented objects right now! - mutable LLVector3 mPositionRegion; - mutable LLVector3 mPositionAgent; - - static void setPhaseOutUpdateInterpolationTime(F32 value) { sPhaseOutUpdateInterpolationTime = (F64) value; } - static void setMaxUpdateInterpolationTime(F32 value) { sMaxUpdateInterpolationTime = (F64) value; } - - static void setVelocityInterpolate(BOOL value) { sVelocityInterpolate = value; } - static void setPingInterpolate(BOOL value) { sPingInterpolate = value; } - -private: - static S32 sNumObjects; - - static F64 sPhaseOutUpdateInterpolationTime; // For motion interpolation - static F64 sMaxUpdateInterpolationTime; // For motion interpolation - - static BOOL sVelocityInterpolate; - static BOOL sPingInterpolate; - - //-------------------------------------------------------------------- - // For objects that are attachments - //-------------------------------------------------------------------- -public: - const LLUUID &getAttachmentItemID() const; - void setAttachmentItemID(const LLUUID &id); - const LLUUID &extractAttachmentItemID(); // find&set the inventory item ID of the attached object - EObjectUpdateType getLastUpdateType() const; - void setLastUpdateType(EObjectUpdateType last_update_type); - BOOL getLastUpdateCached() const; - void setLastUpdateCached(BOOL last_update_cached); - -private: - LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory. - EObjectUpdateType mLastUpdateType; - BOOL mLastUpdateCached; -}; - -/////////////////// -// -// Inlines -// -// - -inline void LLViewerObject::setRotation(const LLQuaternion& quat, BOOL damped) -{ - LLPrimitive::setRotation(quat); - setChanged(ROTATED | SILHOUETTE); - updateDrawable(damped); -} - -inline void LLViewerObject::setRotation(const F32 x, const F32 y, const F32 z, BOOL damped) -{ - LLPrimitive::setRotation(x, y, z); - setChanged(ROTATED | SILHOUETTE); - updateDrawable(damped); -} - -class LLViewerObjectMedia -{ -public: - LLViewerObjectMedia() : mMediaURL(), mPassedWhitelist(FALSE), mMediaType(0) { } - - std::string mMediaURL; // for web pages on surfaces, one per prim - BOOL mPassedWhitelist; // user has OK'd display - U8 mMediaType; // see LLTextureEntry::WEB_PAGE, etc. -}; - -// subclass of viewer object that can be added to particle partitions -class LLAlphaObject : public LLViewerObject -{ -public: - LLAlphaObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) - : LLViewerObject(id,pcode,regionp) - { mDepth = 0.f; } - - virtual F32 getPartSize(S32 idx); - virtual void getGeometry(S32 idx, - LLStrider& verticesp, - LLStrider& normalsp, - LLStrider& texcoordsp, - LLStrider& colorsp, - LLStrider& indicesp) = 0; - - F32 mDepth; -}; - -class LLStaticViewerObject : public LLViewerObject -{ -public: - LLStaticViewerObject(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp, BOOL is_global = FALSE) - : LLViewerObject(id,pcode,regionp, is_global) - { } - - virtual void updateDrawable(BOOL force_damped); -}; - - -#endif +/** + * @file llviewerobject.h + * @brief Description of LLViewerObject class, which is the base class for most objects in the viewer. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLVIEWEROBJECT_H +#define LL_LLVIEWEROBJECT_H + +#include + +#include "llassetstorage.h" +#include "lldarrayptr.h" +#include "llhudicon.h" +#include "llinventory.h" +#include "llrefcount.h" +#include "llmemtype.h" +#include "llprimitive.h" +#include "lluuid.h" +#include "llvoinventorylistener.h" +#include "object_flags.h" +#include "llquaternion.h" +#include "v3dmath.h" +#include "v3math.h" +#include "llvertexbuffer.h" +#include "llaccountingquota.h" + +class LLAgent; // TODO: Get rid of this. +class LLAudioSource; +class LLAudioSourceVO; +class LLBBox; +class LLDataPacker; +class LLColor4; +class LLFrameTimer; +class LLDrawable; +class LLHost; +class LLHUDText; +class LLWorld; +class LLNameValue; +class LLNetMap; +class LLMessageSystem; +class LLPartSysData; +class LLPrimitive; +class LLPipeline; +class LLTextureEntry; +class LLViewerTexture; +class LLViewerInventoryItem; +class LLViewerObject; +class LLViewerPartSourceScript; +class LLViewerRegion; +class LLViewerObjectMedia; +class LLVOInventoryListener; +class LLVOAvatar; + +typedef enum e_object_update_type +{ + OUT_FULL, + OUT_TERSE_IMPROVED, + OUT_FULL_COMPRESSED, + OUT_FULL_CACHED, + OUT_UNKNOWN, +} EObjectUpdateType; + + +// callback typedef for inventory +typedef void (*inventory_callback)(LLViewerObject*, + LLInventoryObject::object_list_t*, + S32 serial_num, + void*); + +// a small struct for keeping track of joints +struct LLVOJointInfo +{ + EHavokJointType mJointType; + LLVector3 mPivot; // parent-frame + // whether the below an axis or anchor (and thus its frame) + // depends on the joint type: + // HINGE ==> axis=parent-frame + // P2P ==> anchor=child-frame + LLVector3 mAxisOrAnchor; +}; + +// for exporting textured materials from SL +struct LLMaterialExportInfo +{ +public: + LLMaterialExportInfo(S32 mat_index, S32 texture_index, LLColor4 color) : + mMaterialIndex(mat_index), mTextureIndex(texture_index), mColor(color) {}; + + S32 mMaterialIndex; + S32 mTextureIndex; + LLColor4 mColor; +}; + +//============================================================================ + +class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate +{ +protected: + ~LLViewerObject(); // use unref() + + // TomY: Provide for a list of extra parameter structures, mapped by structure name + struct ExtraParameter + { + BOOL in_use; + LLNetworkData *data; + }; + std::map mExtraParameterList; + +public: + typedef std::list > child_list_t; + typedef std::list > vobj_list_t; + + typedef const child_list_t const_child_list_t; + + LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global = FALSE); + MEM_TYPE_NEW(LLMemType::MTYPE_OBJECT); + + virtual void markDead(); // Mark this object as dead, and clean up its references + BOOL isDead() const {return mDead;} + BOOL isOrphaned() const { return mOrphaned; } + BOOL isParticleSource() const; + + virtual LLVOAvatar* asAvatar(); + + static void initVOClasses(); + static void cleanupVOClasses(); + + void addNVPair(const std::string& data); + BOOL removeNVPair(const std::string& name); + LLNameValue* getNVPair(const std::string& name) const; // null if no name value pair by that name + + // Object create and update functions + virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); + + // Types of media we can associate + enum { MEDIA_NONE = 0, MEDIA_SET = 1 }; + + // Return codes for processUpdateMessage + enum { + MEDIA_URL_REMOVED = 0x1, + MEDIA_URL_ADDED = 0x2, + MEDIA_URL_UPDATED = 0x4, + MEDIA_FLAGS_CHANGED = 0x8, + INVALID_UPDATE = 0x80000000 + }; + + virtual U32 processUpdateMessage(LLMessageSystem *mesgsys, + void **user_data, + U32 block_num, + const EObjectUpdateType update_type, + LLDataPacker *dp); + + + virtual BOOL isActive() const; // Whether this object needs to do an idleUpdate. + BOOL onActiveList() const {return mOnActiveList;} + void setOnActiveList(BOOL on_active) { mOnActiveList = on_active; } + + virtual BOOL isAttachment() const { return FALSE; } + virtual LLVOAvatar* getAvatar() const; //get the avatar this object is attached to, or NULL if object is not an attachment + virtual BOOL isHUDAttachment() const { return FALSE; } + virtual void updateRadius() {}; + virtual F32 getVObjRadius() const; // default implemenation is mDrawable->getRadius() + + BOOL isJointChild() const { return mJointInfo ? TRUE : FALSE; } + EHavokJointType getJointType() const { return mJointInfo ? mJointInfo->mJointType : HJT_INVALID; } + // for jointed and other parent-relative hacks + LLViewerObject* getSubParent(); + const LLViewerObject* getSubParent() const; + + // Object visiblility and GPW functions + virtual void setPixelAreaAndAngle(LLAgent &agent); // Override to generate accurate apparent angle and area + + virtual U32 getNumVertices() const; + virtual U32 getNumIndices() const; + S32 getNumFaces() const { return mNumFaces; } + + // Graphical stuff for objects - maybe broken out into render class later? + virtual void updateTextures(); + virtual void boostTexturePriority(BOOL boost_children = TRUE); // When you just want to boost priority of this object + + virtual LLDrawable* createDrawable(LLPipeline *pipeline); + virtual BOOL updateGeometry(LLDrawable *drawable); + virtual void updateGL(); + virtual void updateFaceSize(S32 idx); + virtual BOOL updateLOD(); + virtual BOOL setDrawableParent(LLDrawable* parentp); + F32 getRotTime() { return mRotTime; } + void resetRot(); + void applyAngularVelocity(F32 dt); + + void setLineWidthForWindowSize(S32 window_width); + + static void increaseArrowLength(); // makes axis arrows for selections longer + static void decreaseArrowLength(); // makes axis arrows for selections shorter + + // Accessor functions + LLViewerRegion* getRegion() const { return mRegionp; } + + BOOL isSelected() const { return mUserSelected; } + virtual void setSelected(BOOL sel) { mUserSelected = sel; mRotTime = 0.f;} + + const LLUUID &getID() const { return mID; } + U32 getLocalID() const { return mLocalID; } + U32 getCRC() const { return mTotalCRC; } + + virtual BOOL isFlexible() const { return FALSE; } + virtual BOOL isSculpted() const { return FALSE; } + virtual BOOL isMesh() const { return FALSE; } + virtual BOOL hasLightTexture() const { return FALSE; } + + // This method returns true if the object is over land owned by + // the agent, one of its groups, or it encroaches and + // anti-encroachment is enabled + bool isReturnable(); + + /* + // This method will scan through this object, and then query the + // selection manager to see if the local agent probably has the + // ability to modify the object. Since this calls into the + // selection manager, you should avoid calling this method from + // there. + BOOL isProbablyModifiable() const; + */ + + virtual BOOL setParent(LLViewerObject* parent); + virtual void addChild(LLViewerObject *childp); + virtual void removeChild(LLViewerObject *childp); + const_child_list_t& getChildren() const { return mChildList; } + S32 numChildren() const { return mChildList.size(); } + void addThisAndAllChildren(std::vector& objects); + void addThisAndNonJointChildren(std::vector& objects); + BOOL isChild(LLViewerObject *childp) const; + BOOL isSeat() const; + + + //detect if given line segment (in agent space) intersects with this viewer object. + //returns TRUE if intersection detected and returns information about intersection + virtual BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + S32 face = -1, // which face to check, -1 = ALL_SIDES + BOOL pick_transparent = FALSE, + S32* face_hit = NULL, // which face was hit + LLVector3* intersection = NULL, // return the intersection point + LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point + LLVector3* normal = NULL, // return the surface normal at the intersection point + LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point + ); + + virtual BOOL lineSegmentBoundingBox(const LLVector3& start, const LLVector3& end); + + virtual const LLVector3d getPositionGlobal() const; + virtual const LLVector3 &getPositionRegion() const; + virtual const LLVector3 getPositionEdit() const; + virtual const LLVector3 &getPositionAgent() const; + virtual const LLVector3 getRenderPosition() const; + + virtual const LLVector3 getPivotPositionAgent() const; // Usually = to getPositionAgent, unless like flex objects it's not + + LLViewerObject* getRootEdit() const; + + const LLQuaternion getRotationRegion() const; + const LLQuaternion getRotationEdit() const; + const LLQuaternion getRenderRotation() const; + virtual const LLMatrix4 getRenderMatrix() const; + + void setPosition(const LLVector3 &pos, BOOL damped = FALSE); + void setPositionGlobal(const LLVector3d &position, BOOL damped = FALSE); + void setPositionRegion(const LLVector3 &position, BOOL damped = FALSE); + void setPositionEdit(const LLVector3 &position, BOOL damped = FALSE); + void setPositionAgent(const LLVector3 &pos_agent, BOOL damped = FALSE); + void setPositionParent(const LLVector3 &pos_parent, BOOL damped = FALSE); + void setPositionAbsoluteGlobal( const LLVector3d &pos_global, BOOL damped = FALSE ); + + virtual const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const { return xform->getWorldMatrix(); } + + inline void setRotation(const F32 x, const F32 y, const F32 z, BOOL damped = FALSE); + inline void setRotation(const LLQuaternion& quat, BOOL damped = FALSE); + void sendRotationUpdate() const; + + /*virtual*/ void setNumTEs(const U8 num_tes); + /*virtual*/ void setTE(const U8 te, const LLTextureEntry &texture_entry); + /*virtual*/ S32 setTETexture(const U8 te, const LLUUID &uuid); + S32 setTETextureCore(const U8 te, const LLUUID& uuid, LLHost host); + /*virtual*/ S32 setTEColor(const U8 te, const LLColor3 &color); + /*virtual*/ S32 setTEColor(const U8 te, const LLColor4 &color); + /*virtual*/ S32 setTEScale(const U8 te, const F32 s, const F32 t); + /*virtual*/ S32 setTEScaleS(const U8 te, const F32 s); + /*virtual*/ S32 setTEScaleT(const U8 te, const F32 t); + /*virtual*/ S32 setTEOffset(const U8 te, const F32 s, const F32 t); + /*virtual*/ S32 setTEOffsetS(const U8 te, const F32 s); + /*virtual*/ S32 setTEOffsetT(const U8 te, const F32 t); + /*virtual*/ S32 setTERotation(const U8 te, const F32 r); + /*virtual*/ S32 setTEBumpmap(const U8 te, const U8 bump ); + /*virtual*/ S32 setTETexGen(const U8 te, const U8 texgen ); + /*virtual*/ S32 setTEMediaTexGen(const U8 te, const U8 media ); // *FIXME: this confusingly acts upon a superset of setTETexGen's flags without absorbing its semantics + /*virtual*/ S32 setTEShiny(const U8 te, const U8 shiny ); + /*virtual*/ S32 setTEFullbright(const U8 te, const U8 fullbright ); + /*virtual*/ S32 setTEMediaFlags(const U8 te, const U8 media_flags ); + /*virtual*/ S32 setTEGlow(const U8 te, const F32 glow); + /*virtual*/ BOOL setMaterial(const U8 material); + virtual void setTEImage(const U8 te, LLViewerTexture *imagep); // Not derived from LLPrimitive + void changeTEImage(S32 index, LLViewerTexture* new_image) ; + LLViewerTexture *getTEImage(const U8 te) const; + + void fitFaceTexture(const U8 face); + void sendTEUpdate() const; // Sends packed representation of all texture entry information + + virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE); + + virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL); + virtual U32 getTriangleCount(); + virtual U32 getHighLODTriangleCount(); + + void setObjectCost(F32 cost); + F32 getObjectCost(); + + void setLinksetCost(F32 cost); + F32 getLinksetCost(); + + void setPhysicsCost(F32 cost); + F32 getPhysicsCost(); + + void setLinksetPhysicsCost(F32 cost); + F32 getLinksetPhysicsCost(); + + void sendShapeUpdate(); + + U8 getState() { return mState; } + + F32 getAppAngle() const { return mAppAngle; } + F32 getPixelArea() const { return mPixelArea; } + void setPixelArea(F32 area) { mPixelArea = area; } + F32 getMaxScale() const; + F32 getMidScale() const; + F32 getMinScale() const; + + // Owner id is this object's owner + void setAttachedSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const U8 flags); + void adjustAudioGain(const F32 gain); + void clearAttachedSound() { mAudioSourcep = NULL; } + + // Create if necessary + LLAudioSource *getAudioSource(const LLUUID& owner_id); + bool isAudioSource() {return mAudioSourcep != NULL;} + + U8 getMediaType() const; + void setMediaType(U8 media_type); + + std::string getMediaURL() const; + void setMediaURL(const std::string& media_url); + + BOOL getMediaPassedWhitelist() const; + void setMediaPassedWhitelist(BOOL passed); + + void sendMaterialUpdate() const; + + void setCanSelect(BOOL canSelect); + + void setDebugText(const std::string &utf8text); + void setIcon(LLViewerTexture* icon_image); + void clearIcon(); + + void markForUpdate(BOOL priority); + void updateVolume(const LLVolumeParams& volume_params); + virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max); + virtual F32 getBinRadius(); + + LLBBox getBoundingBoxAgent() const; + + void updatePositionCaches() const; // Update the global and region position caches from the object (and parent's) xform. + void updateText(); // update text label position + virtual void updateDrawable(BOOL force_damped); // force updates on static objects + + void setDrawableState(U32 state, BOOL recursive = TRUE); + void clearDrawableState(U32 state, BOOL recursive = TRUE); + + // Called when the drawable shifts + virtual void onShift(const LLVector4a &shift_vector) { } + + ////////////////////////////////////// + // + // Inventory methods + // + + // This function is called when someone is interested in a viewer + // object's inventory. The callback is called as soon as the + // viewer object has the inventory stored locally. + void registerInventoryListener(LLVOInventoryListener* listener, void* user_data); + void removeInventoryListener(LLVOInventoryListener* listener); + BOOL isInventoryPending() { return mInventoryPending; } + void clearInventoryListeners(); + void requestInventory(); + void fetchInventoryFromServer(); + static void processTaskInv(LLMessageSystem* msg, void** user_data); + void removeInventory(const LLUUID& item_id); + + // The updateInventory() call potentially calls into the selection + // manager, so do no call updateInventory() from the selection + // manager until we have better iterators. + void updateInventory(LLViewerInventoryItem* item, U8 key, bool is_new); + void updateInventoryLocal(LLInventoryItem* item, U8 key); // Update without messaging. + LLInventoryObject* getInventoryObject(const LLUUID& item_id); + void getInventoryContents(LLInventoryObject::object_list_t& objects); + LLInventoryObject* getInventoryRoot(); + LLViewerInventoryItem* getInventoryItemByAsset(const LLUUID& asset_id); + S16 getInventorySerial() const { return mInventorySerialNum; } + + // These functions does viewer-side only object inventory modifications + void updateViewerInventoryAsset( + const LLViewerInventoryItem* item, + const LLUUID& new_asset); + + // This function will make sure that we refresh the inventory. + void dirtyInventory(); + BOOL isInventoryDirty() { return mInventoryDirty; } + + // save a script, which involves removing the old one, and rezzing + // in the new one. This method should be called with the asset id + // of the new and old script AFTER the bytecode has been saved. + void saveScript(const LLViewerInventoryItem* item, BOOL active, bool is_new); + + // move an inventory item out of the task and into agent + // inventory. This operation is based on messaging. No permissions + // checks are made on the viewer - the server will double check. + void moveInventory(const LLUUID& agent_folder, const LLUUID& item_id); + + // Find the number of instances of this object's inventory that are of the given type + S32 countInventoryContents( LLAssetType::EType type ); + + BOOL permAnyOwner() const; + BOOL permYouOwner() const; + BOOL permGroupOwner() const; + BOOL permOwnerModify() const; + BOOL permModify() const; + BOOL permCopy() const; + BOOL permMove() const; + BOOL permTransfer() const; + inline BOOL usePhysics() const { return ((mFlags & FLAGS_USE_PHYSICS) != 0); } + inline BOOL flagScripted() const { return ((mFlags & FLAGS_SCRIPTED) != 0); } + inline BOOL flagHandleTouch() const { return ((mFlags & FLAGS_HANDLE_TOUCH) != 0); } + inline BOOL flagTakesMoney() const { return ((mFlags & FLAGS_TAKES_MONEY) != 0); } + inline BOOL flagPhantom() const { return ((mFlags & FLAGS_PHANTOM) != 0); } + inline BOOL flagInventoryEmpty() const { return ((mFlags & FLAGS_INVENTORY_EMPTY) != 0); } + inline BOOL flagCastShadows() const { return ((mFlags & FLAGS_CAST_SHADOWS) != 0); } + inline BOOL flagAllowInventoryAdd() const { return ((mFlags & FLAGS_ALLOW_INVENTORY_DROP) != 0); } + inline BOOL flagTemporary() const { return ((mFlags & FLAGS_TEMPORARY) != 0); } + inline BOOL flagTemporaryOnRez() const { return ((mFlags & FLAGS_TEMPORARY_ON_REZ) != 0); } + inline BOOL flagAnimSource() const { return ((mFlags & FLAGS_ANIM_SOURCE) != 0); } + inline BOOL flagCameraSource() const { return ((mFlags & FLAGS_CAMERA_SOURCE) != 0); } + inline BOOL flagCameraDecoupled() const { return ((mFlags & FLAGS_CAMERA_DECOUPLED) != 0); } + inline BOOL flagObjectMove() const { return ((mFlags & FLAGS_OBJECT_MOVE) != 0); } + + U8 getPhysicsShapeType() const; + inline F32 getPhysicsGravity() const { return mPhysicsGravity; } + inline F32 getPhysicsFriction() const { return mPhysicsFriction; } + inline F32 getPhysicsDensity() const { return mPhysicsDensity; } + inline F32 getPhysicsRestitution() const { return mPhysicsRestitution; } + + bool getIncludeInSearch() const; + void setIncludeInSearch(bool include_in_search); + + // Does "open" object menu item apply? + BOOL allowOpen() const; + + void setClickAction(U8 action) { mClickAction = action; } + U8 getClickAction() const { return mClickAction; } + bool specialHoverCursor() const; // does it have a special hover cursor? + + void setRegion(LLViewerRegion *regionp); + virtual void updateRegion(LLViewerRegion *regionp); + + void updateFlags(BOOL physics_changed = FALSE); + BOOL setFlags(U32 flag, BOOL state); + void setPhysicsShapeType(U8 type); + void setPhysicsGravity(F32 gravity); + void setPhysicsFriction(F32 friction); + void setPhysicsDensity(F32 density); + void setPhysicsRestitution(F32 restitution); + + virtual void dump() const; + static U32 getNumZombieObjects() { return sNumZombieObjects; } + + void printNameValuePairs() const; + + virtual S32 getLOD() const { return 3; } + virtual U32 getPartitionType() const; + virtual void dirtySpatialGroup(BOOL priority = FALSE) const; + virtual void dirtyMesh(); + + virtual LLNetworkData* getParameterEntry(U16 param_type) const; + virtual bool setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin); + virtual BOOL getParameterEntryInUse(U16 param_type) const; + virtual bool setParameterEntryInUse(U16 param_type, BOOL in_use, bool local_origin); + // Called when a parameter is changed + virtual void parameterChanged(U16 param_type, bool local_origin); + virtual void parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin); + + friend class LLViewerObjectList; + friend class LLViewerMediaList; + +public: + //counter-translation + void resetChildrenPosition(const LLVector3& offset, BOOL simplified = FALSE) ; + //counter-rotation + void resetChildrenRotationAndPosition(const std::vector& rotations, + const std::vector& positions) ; + void saveUnselectedChildrenRotation(std::vector& rotations) ; + void saveUnselectedChildrenPosition(std::vector& positions) ; + std::vector mUnselectedChildrenPositions ; + +private: + ExtraParameter* createNewParameterEntry(U16 param_type); + ExtraParameter* getExtraParameterEntry(U16 param_type) const; + ExtraParameter* getExtraParameterEntryCreate(U16 param_type); + bool unpackParameterEntry(U16 param_type, LLDataPacker *dp); + + // This function checks to see if the given media URL has changed its version + // and the update wasn't due to this agent's last action. + U32 checkMediaURL(const std::string &media_url); + + // Motion prediction between updates + void interpolateLinearMotion(const F64 & time, const F32 & dt); + +public: + // + // Viewer-side only types - use the LL_PCODE_APP mask. + // + typedef enum e_vo_types + { + LL_VO_CLOUDS = LL_PCODE_APP | 0x20, + LL_VO_SURFACE_PATCH = LL_PCODE_APP | 0x30, + LL_VO_WL_SKY = LL_PCODE_APP | 0x40, + LL_VO_SQUARE_TORUS = LL_PCODE_APP | 0x50, + LL_VO_SKY = LL_PCODE_APP | 0x60, + LL_VO_VOID_WATER = LL_PCODE_APP | 0x70, + LL_VO_WATER = LL_PCODE_APP | 0x80, + LL_VO_GROUND = LL_PCODE_APP | 0x90, + LL_VO_PART_GROUP = LL_PCODE_APP | 0xa0, + LL_VO_TRIANGLE_TORUS = LL_PCODE_APP | 0xb0, + LL_VO_HUD_PART_GROUP = LL_PCODE_APP | 0xc0, + } EVOType; + + typedef enum e_physics_shape_types + { + PHYSICS_SHAPE_PRIM = 0, + PHYSICS_SHAPE_NONE, + PHYSICS_SHAPE_CONVEX_HULL, + } EPhysicsShapeType; + + LLUUID mID; + + // unique within region, not unique across regions + // Local ID = 0 is not used + U32 mLocalID; + + // Last total CRC received from sim, used for caching + U32 mTotalCRC; + + LLPointer *mTEImages; + + // Selection, picking and rendering variables + U32 mGLName; // GL "name" used by selection code + BOOL mbCanSelect; // true if user can select this object by clicking + + // Grabbed from UPDATE_FLAGS + U32 mFlags; + + // Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties + U8 mPhysicsShapeType; + F32 mPhysicsGravity; + F32 mPhysicsFriction; + F32 mPhysicsDensity; + F32 mPhysicsRestitution; + + + // Pipeline classes + LLPointer mDrawable; + + // Band-aid to select object after all creation initialization is done + BOOL mCreateSelected; + + // Replace textures with web pages on this object while drawing + BOOL mRenderMedia; + + // In bits + S32 mBestUpdatePrecision; + + // TODO: Make all this stuff private. JC + LLPointer mText; + LLPointer mIcon; + + static BOOL sUseSharedDrawables; + +protected: + // delete an item in the inventory, but don't tell the + // server. This is used internally by remove, update, and + // savescript. + void deleteInventoryItem(const LLUUID& item_id); + + // do the update/caching logic. called by saveScript and + // updateInventory. + void doUpdateInventory(LLPointer& item, U8 key, bool is_new); + + + static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp); + + BOOL setData(const U8 *datap, const U32 data_size); + + // Hide or show HUD, icon and particles + void hideExtraDisplayItems( BOOL hidden ); + + ////////////////////////// + // + // inventory functionality + // + + static void processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status); + void loadTaskInvFile(const std::string& filename); + void doInventoryCallback(); + + BOOL isOnMap(); + + void unpackParticleSource(const S32 block_num, const LLUUID& owner_id); + void unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_id); + void deleteParticleSource(); + void setParticleSource(const LLPartSysData& particle_parameters, const LLUUID& owner_id); + +public: + void updateQuota( const SelectionQuota& quota ); + const SelectionQuota& getQuota( void ) { return mSelectionQuota; } + +private: + void setNameValueList(const std::string& list); // clears nv pairs and then individually adds \n separated NV pairs from \0 terminated string + void deleteTEImages(); // correctly deletes list of images + +protected: + typedef std::map name_value_map_t; + name_value_map_t mNameValuePairs; // Any name-value pairs stored by script + + child_list_t mChildList; + + F64 mLastInterpUpdateSecs; // Last update for purposes of interpolation + F64 mLastMessageUpdateSecs; // Last update from a message from the simulator + TPACKETID mLatestRecvPacketID; // Latest time stamp on message from simulator + + // extra data sent from the sim...currently only used for tree species info + U8* mData; + + LLPointer mPartSourcep; // Particle source associated with this object. + LLAudioSourceVO* mAudioSourcep; + F32 mAudioGain; + + F32 mAppAngle; // Apparent visual arc in degrees + F32 mPixelArea; // Apparent area in pixels + + // This is the object's inventory from the viewer's perspective. + LLInventoryObject::object_list_t* mInventory; + class LLInventoryCallbackInfo + { + public: + ~LLInventoryCallbackInfo(); + LLVOInventoryListener* mListener; + void* mInventoryData; + }; + typedef std::list callback_list_t; + callback_list_t mInventoryCallbacks; + S16 mInventorySerialNum; + + LLViewerRegion *mRegionp; // Region that this object belongs to. + BOOL mInventoryPending; + BOOL mInventoryDirty; + BOOL mDead; + BOOL mOrphaned; // This is an orphaned child + BOOL mUserSelected; // Cached user select information + BOOL mOnActiveList; + BOOL mOnMap; // On the map. + BOOL mStatic; // Object doesn't move. + S32 mNumFaces; + + F32 mTimeDilation; // Time dilation sent with the object. + F32 mRotTime; // Amount (in seconds) that object has rotated according to angular velocity (llSetTargetOmega) + LLQuaternion mLastRot; // last rotation received from the simulator + + LLVOJointInfo* mJointInfo; + U8 mState; // legacy + LLViewerObjectMedia* mMedia; // NULL if no media associated + U8 mClickAction; + F32 mObjectCost; //resource cost of this object or -1 if unknown + F32 mLinksetCost; + F32 mPhysicsCost; + F32 mLinksetPhysicsCost; + + SelectionQuota mSelectionQuota; + + bool mCostStale; + mutable bool mPhysicsShapeUnknown; + + static U32 sNumZombieObjects; // Objects which are dead, but not deleted + + static BOOL sMapDebug; // Map render mode + static LLColor4 sEditSelectColor; + static LLColor4 sNoEditSelectColor; + static F32 sCurrentPulse; + static BOOL sPulseEnabled; + + static S32 sAxisArrowLength; + + // These two caches are only correct for non-parented objects right now! + mutable LLVector3 mPositionRegion; + mutable LLVector3 mPositionAgent; + + static void setPhaseOutUpdateInterpolationTime(F32 value) { sPhaseOutUpdateInterpolationTime = (F64) value; } + static void setMaxUpdateInterpolationTime(F32 value) { sMaxUpdateInterpolationTime = (F64) value; } + + static void setVelocityInterpolate(BOOL value) { sVelocityInterpolate = value; } + static void setPingInterpolate(BOOL value) { sPingInterpolate = value; } + +private: + static S32 sNumObjects; + + static F64 sPhaseOutUpdateInterpolationTime; // For motion interpolation + static F64 sMaxUpdateInterpolationTime; // For motion interpolation + + static BOOL sVelocityInterpolate; + static BOOL sPingInterpolate; + + //-------------------------------------------------------------------- + // For objects that are attachments + //-------------------------------------------------------------------- +public: + const LLUUID &getAttachmentItemID() const; + void setAttachmentItemID(const LLUUID &id); + const LLUUID &extractAttachmentItemID(); // find&set the inventory item ID of the attached object + EObjectUpdateType getLastUpdateType() const; + void setLastUpdateType(EObjectUpdateType last_update_type); + BOOL getLastUpdateCached() const; + void setLastUpdateCached(BOOL last_update_cached); + +private: + LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory. + EObjectUpdateType mLastUpdateType; + BOOL mLastUpdateCached; +}; + +/////////////////// +// +// Inlines +// +// + +inline void LLViewerObject::setRotation(const LLQuaternion& quat, BOOL damped) +{ + LLPrimitive::setRotation(quat); + setChanged(ROTATED | SILHOUETTE); + updateDrawable(damped); +} + +inline void LLViewerObject::setRotation(const F32 x, const F32 y, const F32 z, BOOL damped) +{ + LLPrimitive::setRotation(x, y, z); + setChanged(ROTATED | SILHOUETTE); + updateDrawable(damped); +} + +class LLViewerObjectMedia +{ +public: + LLViewerObjectMedia() : mMediaURL(), mPassedWhitelist(FALSE), mMediaType(0) { } + + std::string mMediaURL; // for web pages on surfaces, one per prim + BOOL mPassedWhitelist; // user has OK'd display + U8 mMediaType; // see LLTextureEntry::WEB_PAGE, etc. +}; + +// subclass of viewer object that can be added to particle partitions +class LLAlphaObject : public LLViewerObject +{ +public: + LLAlphaObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) + : LLViewerObject(id,pcode,regionp) + { mDepth = 0.f; } + + virtual F32 getPartSize(S32 idx); + virtual void getGeometry(S32 idx, + LLStrider& verticesp, + LLStrider& normalsp, + LLStrider& texcoordsp, + LLStrider& colorsp, + LLStrider& indicesp) = 0; + + F32 mDepth; +}; + +class LLStaticViewerObject : public LLViewerObject +{ +public: + LLStaticViewerObject(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp, BOOL is_global = FALSE) + : LLViewerObject(id,pcode,regionp, is_global) + { } + + virtual void updateDrawable(BOOL force_damped); +}; + + +#endif diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 5ae4e872f3..8db72da1ee 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -2202,9 +2202,9 @@ bool LLViewerParcelMgr::canAgentBuyParcel(LLParcel* parcel, bool forGroup) const = parcelOwner == (forGroup ? gAgent.getGroupID() : gAgent.getID()); bool isAuthorized - = (authorizeBuyer.isNull() - || (gAgent.getID() == authorizeBuyer) - || (gAgent.hasPowerInGroup(authorizeBuyer,GP_LAND_DEED) + = (authorizeBuyer.isNull() + || (gAgent.getID() == authorizeBuyer) + || (gAgent.hasPowerInGroup(authorizeBuyer,GP_LAND_DEED) && gAgent.hasPowerInGroup(authorizeBuyer,GP_LAND_SET_SALE_INFO))); return isForSale && !isOwner && isAuthorized && isEmpowered; diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h index 45c9b3e91f..faa86d43dd 100644 --- a/indra/newview/llviewerprecompiledheaders.h +++ b/indra/newview/llviewerprecompiledheaders.h @@ -118,8 +118,8 @@ // Library includes from llvfs #include "lldir.h" - -// Library includes from llmessage project + +// Library includes from llmessage project #include "llcachename.h" #endif diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index d9ff931575..cd6653b0c7 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -110,8 +110,8 @@ void LLViewerTextureList::doPreloadImages() { LL_DEBUGS("ViewerImages") << "Preloading images..." << LL_ENDL; - llassert_always(mInitialized) ; - llassert_always(mImageList.empty()) ; + llassert_always(mInitialized) ; + llassert_always(mImageList.empty()) ; llassert_always(mUUIDMap.empty()) ; // Set the "missing asset" image -- cgit v1.2.3 From d5ae682e113d6a6f861b0d873a2fd061f8d03750 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 26 May 2011 16:04:36 -0400 Subject: SH-1444 FIXED "Allow mesh objects" setting is visible on non-mesh region. --- indra/newview/llfloaterregioninfo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index fc6976755f..232b8e9096 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -592,7 +592,8 @@ bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region) const bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && gAgent.getRegion() && - !gAgent.getRegion()->getCapability("GetMesh").empty(); + !gAgent.getRegion()->getCapability("GetMesh").empty() && + !gAgent.getRegion()->getCapability("ObjectAdd").empty(); getChildView("mesh_rez_enabled_check")->setVisible(enable_mesh); getChildView("mesh_rez_enabled_check")->setEnabled(getChildView("mesh_rez_enabled_check")->getEnabled() && enable_mesh); // Data gets filled in by processRegionInfo -- cgit v1.2.3 From 74da6623dcc53f440935ea69dde5cf140c9c5c4b Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 26 May 2011 16:48:15 -0400 Subject: SH-1668 FIXED Cubes can be scaled to 64^3 --- indra/newview/llmanipscale.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra') diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index 738d82e732..673f28e01f 100644 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -93,6 +93,7 @@ F32 get_default_max_prim_scale(bool is_flora) if (gSavedSettings.getBOOL("MeshEnabled") && gAgent.getRegion() && !gAgent.getRegion()->getCapability("GetMesh").empty() && + !gAgent.getRegion()->getCapability("ObjectAdd").empty() && !is_flora) { return DEFAULT_MAX_PRIM_SCALE; -- cgit v1.2.3 From 5a39eeb70fbc47a5a52f53e69ca5d95ed2f5e68a Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 26 May 2011 16:52:26 -0400 Subject: SH-1669 FIXED Physics properties show up on DRTSIM-52 --- indra/newview/llpanelvolume.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index ebddaa90bc..7839cdd811 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -532,7 +532,8 @@ void LLPanelVolume::refresh() bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && gAgent.getRegion() && - !gAgent.getRegion()->getCapability("GetMesh").empty(); + !gAgent.getRegion()->getCapability("GetMesh").empty() && + !gAgent.getRegion()->getCapability("ObjectAdd").empty(); getChildView("label physicsshapetype")->setVisible(enable_mesh); getChildView("Physics Shape Type Combo Ctrl")->setVisible(enable_mesh); -- cgit v1.2.3 From 7c042e1bcdde65da5629ed64a58ce1f3e23542be Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 26 May 2011 16:58:31 -0400 Subject: SH-1467 WIP Viewer checks the wrong cap for mesh-ui disable Fixes that need to go into trunk because certain Mesh UI elements are showing up on DRTSIM-52. These fixes will probably be overwritten by the actual resolution of SH-1467 but I need this workaround now. --- indra/newview/llfloatertools.cpp | 5 +++-- indra/newview/llpanelobject.cpp | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 061a42ab57..edcb96314b 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -423,7 +423,7 @@ void LLFloaterTools::refresh() // Refresh object and prim count labels LLLocale locale(LLLocale::USER_LOCALE); - if ((gAgent.getRegion() && gAgent.getRegion()->getCapability("GetMesh").empty()) || !gSavedSettings.getBOOL("MeshEnabled")) + if ((gAgent.getRegion() && (gAgent.getRegion()->getCapability("GetMesh").empty() || gAgent.getRegion()->getCapability("ObjectAdd").empty())) || !gSavedSettings.getBOOL("MeshEnabled")) { std::string obj_count_string; LLResMgr::getInstance()->getIntegerString(obj_count_string, LLSelectMgr::getInstance()->getSelection()->getRootObjectCount()); @@ -790,7 +790,8 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) bool show_mesh_cost = gAgent.getRegion() && !gAgent.getRegion()->getCapability("GetMesh").empty() && - gSavedSettings.getBOOL("MeshEnabled"); + gSavedSettings.getBOOL("MeshEnabled") && + !gAgent.getRegion()->getCapability("ObjectAdd").empty(); getChildView("obj_count")->setVisible( !land_visible && !show_mesh_cost); getChildView("prim_count")->setVisible( !land_visible && !show_mesh_cost); diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 34a92cd0ac..b4d0ada196 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1742,7 +1742,8 @@ void LLPanelObject::refresh() bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && gAgent.getRegion() && - !gAgent.getRegion()->getCapability("GetMesh").empty(); + !gAgent.getRegion()->getCapability("GetMesh").empty() && + !gAgent.getRegion()->getCapability("ObjectAdd").empty(); F32 max_scale = get_default_max_prim_scale(LLPickInfo::isFlora(mObject)); -- cgit v1.2.3 From 7a7a0f0c1bd134fa23d734d672ef44a763a9f228 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 26 May 2011 17:25:26 -0400 Subject: EXP-772: If URIs returned by SRV fail, fall back on original URI. --- indra/viewer_components/login/lllogin.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra') diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp index 651d803e0d..d480b63094 100644 --- a/indra/viewer_components/login/lllogin.cpp +++ b/indra/viewer_components/login/lllogin.cpp @@ -178,6 +178,8 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para request["uri"] = uri; request["reply"] = replyPump.getName(); rewrittenURIs = postAndWait(self, request, srv_pump_name, filter); + // EXP-772: If rewrittenURIs fail, try original URI as a fallback. + rewrittenURIs.append(uri); } // we no longer need the filter LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction")); -- cgit v1.2.3 From ecd0cc3a5a411ea050e54044bcea0dfb695b000b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 26 May 2011 17:25:26 -0400 Subject: EXP-772: If URIs returned by SRV fail, fall back on original URI. --- indra/viewer_components/login/lllogin.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra') diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp index 651d803e0d..d480b63094 100644 --- a/indra/viewer_components/login/lllogin.cpp +++ b/indra/viewer_components/login/lllogin.cpp @@ -178,6 +178,8 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para request["uri"] = uri; request["reply"] = replyPump.getName(); rewrittenURIs = postAndWait(self, request, srv_pump_name, filter); + // EXP-772: If rewrittenURIs fail, try original URI as a fallback. + rewrittenURIs.append(uri); } // we no longer need the filter LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction")); -- cgit v1.2.3 From f92b46f7a0d6824e355764b40fd6d309520413b4 Mon Sep 17 00:00:00 2001 From: eli_linden Date: Thu, 26 May 2011 15:04:14 -0700 Subject: FIX DA hardware setting UI, en_xui_change --- indra/newview/skins/default/xui/en/floater_hardware_settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_hardware_settings.xml b/indra/newview/skins/default/xui/en/floater_hardware_settings.xml index a97c697b24..05f4c52b95 100644 --- a/indra/newview/skins/default/xui/en/floater_hardware_settings.xml +++ b/indra/newview/skins/default/xui/en/floater_hardware_settings.xml @@ -80,7 +80,7 @@ left_pad="10" name="antialiasing restart" top_delta="0" - width="188"> + width="230"> (requires viewer restart) Date: Thu, 26 May 2011 18:05:29 -0400 Subject: Added newline at end of header file to fix linux build. --- indra/newview/llaccountingquotamanager.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llaccountingquotamanager.h b/indra/newview/llaccountingquotamanager.h index 4c20561bce..9551df272c 100644 --- a/indra/newview/llaccountingquotamanager.h +++ b/indra/newview/llaccountingquotamanager.h @@ -57,4 +57,5 @@ private: }; //=============================================================================== -#endif \ No newline at end of file +#endif // LLACCOUNTINGQUOTAMANAGER + -- cgit v1.2.3 From 66399cc9cc5391270bb3f9a390c34ecdd49e7241 Mon Sep 17 00:00:00 2001 From: eli_linden Date: Thu, 26 May 2011 15:47:49 -0700 Subject: FIX INTL-47 Japanese and Italian translation for set19-23, light set1-2 --- .../skins/default/xui/it/floater_about_land.xml | 4 +- .../skins/default/xui/it/floater_avatar_picker.xml | 9 +- .../skins/default/xui/it/floater_beacons.xml | 1 + .../newview/skins/default/xui/it/floater_bumps.xml | 2 +- .../skins/default/xui/it/floater_buy_object.xml | 37 +- .../skins/default/xui/it/floater_display_name.xml | 18 + .../newview/skins/default/xui/it/floater_event.xml | 45 +- .../default/xui/it/floater_hardware_settings.xml | 3 + .../skins/default/xui/it/floater_incoming_call.xml | 2 +- indra/newview/skins/default/xui/it/floater_map.xml | 3 + indra/newview/skins/default/xui/it/floater_pay.xml | 2 +- .../skins/default/xui/it/floater_preferences.xml | 4 +- .../xui/it/floater_region_debug_console.xml | 2 + .../newview/skins/default/xui/it/floater_tools.xml | 10 +- .../default/xui/it/floater_voice_controls.xml | 6 +- .../skins/default/xui/it/floater_web_content.xml | 14 + .../skins/default/xui/it/inspect_avatar.xml | 5 + .../skins/default/xui/it/menu_attachment_self.xml | 2 +- .../skins/default/xui/it/menu_avatar_self.xml | 3 +- .../skins/default/xui/it/menu_bottomtray.xml | 2 +- .../default/xui/it/menu_inspect_avatar_gear.xml | 6 +- .../default/xui/it/menu_inspect_self_gear.xml | 39 +- .../skins/default/xui/it/menu_inventory.xml | 1 + .../skins/default/xui/it/menu_inventory_add.xml | 1 + .../default/xui/it/menu_inventory_gear_default.xml | 10 +- indra/newview/skins/default/xui/it/menu_login.xml | 3 +- .../skins/default/xui/it/menu_media_ctrl.xml | 6 + .../newview/skins/default/xui/it/menu_mini_map.xml | 1 + indra/newview/skins/default/xui/it/menu_object.xml | 4 +- .../skins/default/xui/it/menu_outfit_gear.xml | 5 +- .../default/xui/it/menu_places_gear_folder.xml | 5 +- .../default/xui/it/menu_places_gear_landmark.xml | 5 +- indra/newview/skins/default/xui/it/menu_viewer.xml | 41 +- .../newview/skins/default/xui/it/notifications.xml | 279 +- .../default/xui/it/panel_avatar_list_item.xml | 2 +- .../skins/default/xui/it/panel_edit_alpha.xml | 16 +- .../skins/default/xui/it/panel_edit_gloves.xml | 2 +- .../skins/default/xui/it/panel_edit_jacket.xml | 4 +- .../skins/default/xui/it/panel_edit_pants.xml | 2 +- .../skins/default/xui/it/panel_edit_physics.xml | 14 + .../skins/default/xui/it/panel_edit_profile.xml | 10 +- .../skins/default/xui/it/panel_edit_shirt.xml | 2 +- .../skins/default/xui/it/panel_edit_shoes.xml | 2 +- .../skins/default/xui/it/panel_edit_skirt.xml | 2 +- .../skins/default/xui/it/panel_edit_socks.xml | 2 +- .../skins/default/xui/it/panel_edit_underpants.xml | 2 +- .../skins/default/xui/it/panel_edit_undershirt.xml | 2 +- .../skins/default/xui/it/panel_edit_wearable.xml | 6 + .../default/xui/it/panel_group_land_money.xml | 1 + indra/newview/skins/default/xui/it/panel_login.xml | 11 +- .../skins/default/xui/it/panel_my_profile.xml | 29 +- .../skins/default/xui/it/panel_nearby_media.xml | 2 +- .../skins/default/xui/it/panel_notify_textbox.xml | 11 + .../newview/skins/default/xui/it/panel_people.xml | 12 +- .../skins/default/xui/it/panel_place_profile.xml | 3 +- .../default/xui/it/panel_preferences_advanced.xml | 29 +- .../default/xui/it/panel_preferences_chat.xml | 49 +- .../default/xui/it/panel_preferences_colors.xml | 41 + .../default/xui/it/panel_preferences_general.xml | 18 +- .../default/xui/it/panel_preferences_graphics1.xml | 7 +- .../default/xui/it/panel_preferences_move.xml | 24 + .../default/xui/it/panel_preferences_privacy.xml | 14 +- .../default/xui/it/panel_preferences_setup.xml | 24 +- .../default/xui/it/panel_preferences_sound.xml | 12 +- .../newview/skins/default/xui/it/panel_profile.xml | 8 +- .../skins/default/xui/it/panel_profile_view.xml | 7 + .../skins/default/xui/it/panel_script_ed.xml | 14 +- .../default/xui/it/panel_scrolling_param_base.xml | 4 + .../skins/default/xui/it/panel_status_bar.xml | 2 +- .../newview/skins/default/xui/it/role_actions.xml | 87 +- indra/newview/skins/default/xui/it/strings.xml | 507 +++- .../skins/default/xui/ja/floater_about_land.xml | 4 +- .../skins/default/xui/ja/floater_avatar_picker.xml | 8 + .../skins/default/xui/ja/floater_beacons.xml | 1 + .../newview/skins/default/xui/ja/floater_bumps.xml | 10 +- .../skins/default/xui/ja/floater_buy_object.xml | 37 +- .../skins/default/xui/ja/floater_display_name.xml | 18 + .../newview/skins/default/xui/ja/floater_event.xml | 45 +- .../default/xui/ja/floater_hardware_settings.xml | 3 + .../skins/default/xui/ja/floater_incoming_call.xml | 2 +- indra/newview/skins/default/xui/ja/floater_map.xml | 27 +- indra/newview/skins/default/xui/ja/floater_pay.xml | 2 +- .../skins/default/xui/ja/floater_preferences.xml | 4 +- .../xui/ja/floater_region_debug_console.xml | 2 + .../newview/skins/default/xui/ja/floater_tools.xml | 8 + .../default/xui/ja/floater_voice_controls.xml | 2 +- .../skins/default/xui/ja/floater_web_content.xml | 14 + .../skins/default/xui/ja/inspect_avatar.xml | 4 +- .../skins/default/xui/ja/menu_attachment_self.xml | 2 +- .../skins/default/xui/ja/menu_avatar_self.xml | 3 +- .../skins/default/xui/ja/menu_bottomtray.xml | 2 +- .../default/xui/ja/menu_inspect_avatar_gear.xml | 6 +- .../default/xui/ja/menu_inspect_self_gear.xml | 39 +- .../skins/default/xui/ja/menu_inventory.xml | 1 + .../skins/default/xui/ja/menu_inventory_add.xml | 1 + .../default/xui/ja/menu_inventory_gear_default.xml | 10 +- indra/newview/skins/default/xui/ja/menu_login.xml | 3 +- .../skins/default/xui/ja/menu_media_ctrl.xml | 6 + .../newview/skins/default/xui/ja/menu_mini_map.xml | 1 + indra/newview/skins/default/xui/ja/menu_object.xml | 4 +- .../skins/default/xui/ja/menu_outfit_gear.xml | 5 +- .../default/xui/ja/menu_places_gear_folder.xml | 5 +- .../default/xui/ja/menu_places_gear_landmark.xml | 5 +- indra/newview/skins/default/xui/ja/menu_viewer.xml | 35 +- .../newview/skins/default/xui/ja/notifications.xml | 285 +- .../default/xui/ja/panel_avatar_list_item.xml | 2 +- .../skins/default/xui/ja/panel_edit_alpha.xml | 16 +- .../skins/default/xui/ja/panel_edit_gloves.xml | 2 +- .../skins/default/xui/ja/panel_edit_jacket.xml | 4 +- .../skins/default/xui/ja/panel_edit_pants.xml | 2 +- .../skins/default/xui/ja/panel_edit_physics.xml | 14 + .../skins/default/xui/ja/panel_edit_profile.xml | 10 +- .../skins/default/xui/ja/panel_edit_shirt.xml | 2 +- .../skins/default/xui/ja/panel_edit_shoes.xml | 2 +- .../skins/default/xui/ja/panel_edit_skirt.xml | 2 +- .../skins/default/xui/ja/panel_edit_socks.xml | 2 +- .../skins/default/xui/ja/panel_edit_underpants.xml | 2 +- .../skins/default/xui/ja/panel_edit_undershirt.xml | 2 +- .../skins/default/xui/ja/panel_edit_wearable.xml | 6 + .../default/xui/ja/panel_group_land_money.xml | 1 + indra/newview/skins/default/xui/ja/panel_login.xml | 11 +- .../skins/default/xui/ja/panel_my_profile.xml | 33 +- .../skins/default/xui/ja/panel_nearby_media.xml | 2 +- .../skins/default/xui/ja/panel_notify_textbox.xml | 11 + .../newview/skins/default/xui/ja/panel_people.xml | 12 +- .../skins/default/xui/ja/panel_place_profile.xml | 3 +- .../default/xui/ja/panel_preferences_advanced.xml | 29 +- .../default/xui/ja/panel_preferences_chat.xml | 49 +- .../default/xui/ja/panel_preferences_colors.xml | 41 + .../default/xui/ja/panel_preferences_general.xml | 18 +- .../default/xui/ja/panel_preferences_graphics1.xml | 7 +- .../default/xui/ja/panel_preferences_move.xml | 24 + .../default/xui/ja/panel_preferences_privacy.xml | 11 +- .../default/xui/ja/panel_preferences_setup.xml | 16 +- .../default/xui/ja/panel_preferences_sound.xml | 14 +- .../newview/skins/default/xui/ja/panel_profile.xml | 8 +- .../skins/default/xui/ja/panel_profile_view.xml | 7 + .../skins/default/xui/ja/panel_script_ed.xml | 14 +- .../default/xui/ja/panel_scrolling_param_base.xml | 4 + .../skins/default/xui/ja/panel_status_bar.xml | 2 +- .../newview/skins/default/xui/ja/role_actions.xml | 15 +- indra/newview/skins/default/xui/ja/strings.xml | 511 +++- .../skins/minimal/xui/it/floater_camera.xml | 65 + .../skins/minimal/xui/it/floater_help_browser.xml | 9 + .../skins/minimal/xui/it/floater_media_browser.xml | 31 + .../skins/minimal/xui/it/floater_nearby_chat.xml | 4 + .../skins/minimal/xui/it/floater_web_content.xml | 14 + .../skins/minimal/xui/it/inspect_avatar.xml | 26 + .../skins/minimal/xui/it/inspect_object.xml | 41 + .../minimal/xui/it/menu_add_wearable_gear.xml | 6 + .../skins/minimal/xui/it/menu_attachment_other.xml | 17 + .../skins/minimal/xui/it/menu_attachment_self.xml | 16 + .../skins/minimal/xui/it/menu_avatar_icon.xml | 7 + .../skins/minimal/xui/it/menu_avatar_other.xml | 16 + .../skins/minimal/xui/it/menu_avatar_self.xml | 32 + .../skins/minimal/xui/it/menu_bottomtray.xml | 17 + .../skins/minimal/xui/it/menu_cof_attachment.xml | 4 + .../skins/minimal/xui/it/menu_cof_body_part.xml | 5 + .../skins/minimal/xui/it/menu_cof_clothing.xml | 6 + .../newview/skins/minimal/xui/it/menu_cof_gear.xml | 5 + indra/newview/skins/minimal/xui/it/menu_edit.xml | 12 + .../skins/minimal/xui/it/menu_favorites.xml | 10 + .../skins/minimal/xui/it/menu_gesture_gear.xml | 10 + .../skins/minimal/xui/it/menu_group_plus.xml | 5 + .../skins/minimal/xui/it/menu_hide_navbar.xml | 6 + .../skins/minimal/xui/it/menu_im_well_button.xml | 4 + .../skins/minimal/xui/it/menu_imchiclet_adhoc.xml | 4 + .../skins/minimal/xui/it/menu_imchiclet_group.xml | 6 + .../skins/minimal/xui/it/menu_imchiclet_p2p.xml | 7 + .../minimal/xui/it/menu_inspect_avatar_gear.xml | 21 + .../minimal/xui/it/menu_inspect_object_gear.xml | 18 + .../minimal/xui/it/menu_inspect_self_gear.xml | 31 + .../minimal/xui/it/menu_inv_offer_chiclet.xml | 4 + .../skins/minimal/xui/it/menu_inventory.xml | 87 + .../skins/minimal/xui/it/menu_inventory_add.xml | 34 + .../minimal/xui/it/menu_inventory_gear_default.xml | 17 + indra/newview/skins/minimal/xui/it/menu_land.xml | 9 + .../newview/skins/minimal/xui/it/menu_landmark.xml | 7 + indra/newview/skins/minimal/xui/it/menu_login.xml | 24 + .../newview/skins/minimal/xui/it/menu_mini_map.xml | 11 + indra/newview/skins/minimal/xui/it/menu_navbar.xml | 11 + .../skins/minimal/xui/it/menu_nearby_chat.xml | 9 + .../xui/it/menu_notification_well_button.xml | 4 + indra/newview/skins/minimal/xui/it/menu_object.xml | 29 + .../skins/minimal/xui/it/menu_object_icon.xml | 5 + .../skins/minimal/xui/it/menu_outfit_gear.xml | 28 + .../skins/minimal/xui/it/menu_outfit_tab.xml | 9 + .../skins/minimal/xui/it/menu_participant_list.xml | 21 + .../xui/it/menu_people_friends_view_sort.xml | 8 + .../skins/minimal/xui/it/menu_people_groups.xml | 8 + .../xui/it/menu_people_groups_view_sort.xml | 5 + .../skins/minimal/xui/it/menu_people_nearby.xml | 13 + .../xui/it/menu_people_nearby_multiselect.xml | 10 + .../xui/it/menu_people_nearby_view_sort.xml | 8 + .../xui/it/menu_people_recent_view_sort.xml | 7 + indra/newview/skins/minimal/xui/it/menu_picks.xml | 8 + .../skins/minimal/xui/it/menu_picks_plus.xml | 5 + indra/newview/skins/minimal/xui/it/menu_place.xml | 7 + .../skins/minimal/xui/it/menu_place_add_button.xml | 5 + .../minimal/xui/it/menu_places_gear_folder.xml | 16 + .../minimal/xui/it/menu_places_gear_landmark.xml | 19 + .../skins/minimal/xui/it/menu_profile_overflow.xml | 12 + .../skins/minimal/xui/it/menu_save_outfit.xml | 5 + .../skins/minimal/xui/it/menu_script_chiclet.xml | 4 + indra/newview/skins/minimal/xui/it/menu_slurl.xml | 6 + .../minimal/xui/it/menu_teleport_history_gear.xml | 6 + .../minimal/xui/it/menu_teleport_history_item.xml | 6 + .../minimal/xui/it/menu_teleport_history_tab.xml | 5 + .../skins/minimal/xui/it/menu_text_editor.xml | 8 + .../skins/minimal/xui/it/menu_topinfobar.xml | 7 + .../skins/minimal/xui/it/menu_url_agent.xml | 6 + .../skins/minimal/xui/it/menu_url_group.xml | 6 + .../newview/skins/minimal/xui/it/menu_url_http.xml | 7 + .../skins/minimal/xui/it/menu_url_inventory.xml | 6 + .../newview/skins/minimal/xui/it/menu_url_map.xml | 6 + .../skins/minimal/xui/it/menu_url_objectim.xml | 8 + .../skins/minimal/xui/it/menu_url_parcel.xml | 6 + .../skins/minimal/xui/it/menu_url_slapp.xml | 5 + .../skins/minimal/xui/it/menu_url_slurl.xml | 7 + .../skins/minimal/xui/it/menu_url_teleport.xml | 6 + indra/newview/skins/minimal/xui/it/menu_viewer.xml | 14 + .../minimal/xui/it/menu_wearable_list_item.xml | 14 + .../skins/minimal/xui/it/menu_wearing_gear.xml | 5 + .../skins/minimal/xui/it/menu_wearing_tab.xml | 6 + .../newview/skins/minimal/xui/it/notifications.xml | 2951 +++++++++++++++++++ .../minimal/xui/it/panel_adhoc_control_panel.xml | 14 + .../skins/minimal/xui/it/panel_bottomtray.xml | 39 + .../minimal/xui/it/panel_group_control_panel.xml | 17 + .../minimal/xui/it/panel_im_control_panel.xml | 29 + indra/newview/skins/minimal/xui/it/panel_login.xml | 48 + .../skins/minimal/xui/it/panel_navigation_bar.xml | 18 + .../newview/skins/minimal/xui/it/panel_people.xml | 94 + .../minimal/xui/it/panel_side_tray_tab_caption.xml | 7 + .../skins/minimal/xui/it/panel_status_bar.xml | 33 + .../skins/minimal/xui/ja/floater_camera.xml | 65 + .../skins/minimal/xui/ja/floater_help_browser.xml | 9 + .../skins/minimal/xui/ja/floater_media_browser.xml | 30 + .../skins/minimal/xui/ja/floater_nearby_chat.xml | 4 + .../skins/minimal/xui/ja/floater_web_content.xml | 14 + .../skins/minimal/xui/ja/inspect_avatar.xml | 27 + .../skins/minimal/xui/ja/inspect_object.xml | 48 + .../minimal/xui/ja/menu_add_wearable_gear.xml | 6 + .../skins/minimal/xui/ja/menu_attachment_other.xml | 17 + .../skins/minimal/xui/ja/menu_attachment_self.xml | 16 + .../skins/minimal/xui/ja/menu_avatar_icon.xml | 7 + .../skins/minimal/xui/ja/menu_avatar_other.xml | 16 + .../skins/minimal/xui/ja/menu_avatar_self.xml | 32 + .../skins/minimal/xui/ja/menu_bottomtray.xml | 17 + .../skins/minimal/xui/ja/menu_cof_attachment.xml | 4 + .../skins/minimal/xui/ja/menu_cof_body_part.xml | 5 + .../skins/minimal/xui/ja/menu_cof_clothing.xml | 6 + .../newview/skins/minimal/xui/ja/menu_cof_gear.xml | 5 + indra/newview/skins/minimal/xui/ja/menu_edit.xml | 12 + .../skins/minimal/xui/ja/menu_favorites.xml | 10 + .../skins/minimal/xui/ja/menu_gesture_gear.xml | 10 + .../skins/minimal/xui/ja/menu_group_plus.xml | 5 + .../skins/minimal/xui/ja/menu_hide_navbar.xml | 6 + .../skins/minimal/xui/ja/menu_im_well_button.xml | 4 + .../skins/minimal/xui/ja/menu_imchiclet_adhoc.xml | 4 + .../skins/minimal/xui/ja/menu_imchiclet_group.xml | 6 + .../skins/minimal/xui/ja/menu_imchiclet_p2p.xml | 7 + .../minimal/xui/ja/menu_inspect_avatar_gear.xml | 21 + .../minimal/xui/ja/menu_inspect_object_gear.xml | 18 + .../minimal/xui/ja/menu_inspect_self_gear.xml | 31 + .../minimal/xui/ja/menu_inv_offer_chiclet.xml | 4 + .../skins/minimal/xui/ja/menu_inventory.xml | 87 + .../skins/minimal/xui/ja/menu_inventory_add.xml | 34 + .../minimal/xui/ja/menu_inventory_gear_default.xml | 17 + indra/newview/skins/minimal/xui/ja/menu_land.xml | 9 + .../newview/skins/minimal/xui/ja/menu_landmark.xml | 7 + indra/newview/skins/minimal/xui/ja/menu_login.xml | 25 + .../newview/skins/minimal/xui/ja/menu_mini_map.xml | 11 + indra/newview/skins/minimal/xui/ja/menu_navbar.xml | 11 + .../skins/minimal/xui/ja/menu_nearby_chat.xml | 9 + .../xui/ja/menu_notification_well_button.xml | 4 + indra/newview/skins/minimal/xui/ja/menu_object.xml | 29 + .../skins/minimal/xui/ja/menu_object_icon.xml | 5 + .../skins/minimal/xui/ja/menu_outfit_gear.xml | 28 + .../skins/minimal/xui/ja/menu_outfit_tab.xml | 9 + .../skins/minimal/xui/ja/menu_participant_list.xml | 21 + .../xui/ja/menu_people_friends_view_sort.xml | 8 + .../skins/minimal/xui/ja/menu_people_groups.xml | 8 + .../xui/ja/menu_people_groups_view_sort.xml | 5 + .../skins/minimal/xui/ja/menu_people_nearby.xml | 13 + .../xui/ja/menu_people_nearby_multiselect.xml | 10 + .../xui/ja/menu_people_nearby_view_sort.xml | 8 + .../xui/ja/menu_people_recent_view_sort.xml | 7 + indra/newview/skins/minimal/xui/ja/menu_picks.xml | 8 + .../skins/minimal/xui/ja/menu_picks_plus.xml | 5 + indra/newview/skins/minimal/xui/ja/menu_place.xml | 7 + .../skins/minimal/xui/ja/menu_place_add_button.xml | 5 + .../minimal/xui/ja/menu_places_gear_folder.xml | 16 + .../minimal/xui/ja/menu_places_gear_landmark.xml | 19 + .../skins/minimal/xui/ja/menu_profile_overflow.xml | 12 + .../skins/minimal/xui/ja/menu_save_outfit.xml | 5 + .../skins/minimal/xui/ja/menu_script_chiclet.xml | 4 + indra/newview/skins/minimal/xui/ja/menu_slurl.xml | 6 + .../minimal/xui/ja/menu_teleport_history_gear.xml | 6 + .../minimal/xui/ja/menu_teleport_history_item.xml | 6 + .../minimal/xui/ja/menu_teleport_history_tab.xml | 5 + .../skins/minimal/xui/ja/menu_text_editor.xml | 8 + .../skins/minimal/xui/ja/menu_topinfobar.xml | 7 + .../skins/minimal/xui/ja/menu_url_agent.xml | 6 + .../skins/minimal/xui/ja/menu_url_group.xml | 6 + .../newview/skins/minimal/xui/ja/menu_url_http.xml | 7 + .../skins/minimal/xui/ja/menu_url_inventory.xml | 6 + .../newview/skins/minimal/xui/ja/menu_url_map.xml | 6 + .../skins/minimal/xui/ja/menu_url_objectim.xml | 8 + .../skins/minimal/xui/ja/menu_url_parcel.xml | 6 + .../skins/minimal/xui/ja/menu_url_slapp.xml | 5 + .../skins/minimal/xui/ja/menu_url_slurl.xml | 7 + .../skins/minimal/xui/ja/menu_url_teleport.xml | 6 + indra/newview/skins/minimal/xui/ja/menu_viewer.xml | 14 + .../minimal/xui/ja/menu_wearable_list_item.xml | 14 + .../skins/minimal/xui/ja/menu_wearing_gear.xml | 5 + .../skins/minimal/xui/ja/menu_wearing_tab.xml | 6 + .../newview/skins/minimal/xui/ja/notifications.xml | 2995 ++++++++++++++++++++ .../minimal/xui/ja/panel_adhoc_control_panel.xml | 14 + .../skins/minimal/xui/ja/panel_bottomtray.xml | 39 + .../minimal/xui/ja/panel_group_control_panel.xml | 17 + .../minimal/xui/ja/panel_im_control_panel.xml | 30 + indra/newview/skins/minimal/xui/ja/panel_login.xml | 48 + .../skins/minimal/xui/ja/panel_navigation_bar.xml | 18 + .../newview/skins/minimal/xui/ja/panel_people.xml | 94 + .../minimal/xui/ja/panel_side_tray_tab_caption.xml | 7 + .../skins/minimal/xui/ja/panel_status_bar.xml | 33 + 326 files changed, 11009 insertions(+), 711 deletions(-) create mode 100644 indra/newview/skins/default/xui/it/floater_display_name.xml create mode 100644 indra/newview/skins/default/xui/it/floater_region_debug_console.xml create mode 100644 indra/newview/skins/default/xui/it/floater_web_content.xml create mode 100644 indra/newview/skins/default/xui/it/menu_media_ctrl.xml create mode 100644 indra/newview/skins/default/xui/it/panel_edit_physics.xml create mode 100644 indra/newview/skins/default/xui/it/panel_notify_textbox.xml create mode 100644 indra/newview/skins/default/xui/it/panel_preferences_colors.xml create mode 100644 indra/newview/skins/default/xui/it/panel_preferences_move.xml create mode 100644 indra/newview/skins/default/xui/it/panel_scrolling_param_base.xml create mode 100644 indra/newview/skins/default/xui/ja/floater_display_name.xml create mode 100644 indra/newview/skins/default/xui/ja/floater_region_debug_console.xml create mode 100644 indra/newview/skins/default/xui/ja/floater_web_content.xml create mode 100644 indra/newview/skins/default/xui/ja/menu_media_ctrl.xml create mode 100644 indra/newview/skins/default/xui/ja/panel_edit_physics.xml create mode 100644 indra/newview/skins/default/xui/ja/panel_notify_textbox.xml create mode 100644 indra/newview/skins/default/xui/ja/panel_preferences_colors.xml create mode 100644 indra/newview/skins/default/xui/ja/panel_preferences_move.xml create mode 100644 indra/newview/skins/default/xui/ja/panel_scrolling_param_base.xml create mode 100644 indra/newview/skins/minimal/xui/it/floater_camera.xml create mode 100644 indra/newview/skins/minimal/xui/it/floater_help_browser.xml create mode 100644 indra/newview/skins/minimal/xui/it/floater_media_browser.xml create mode 100644 indra/newview/skins/minimal/xui/it/floater_nearby_chat.xml create mode 100644 indra/newview/skins/minimal/xui/it/floater_web_content.xml create mode 100644 indra/newview/skins/minimal/xui/it/inspect_avatar.xml create mode 100644 indra/newview/skins/minimal/xui/it/inspect_object.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_add_wearable_gear.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_attachment_other.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_attachment_self.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_avatar_icon.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_avatar_other.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_avatar_self.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_bottomtray.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_cof_attachment.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_cof_body_part.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_cof_clothing.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_cof_gear.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_edit.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_favorites.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_gesture_gear.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_group_plus.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_hide_navbar.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_im_well_button.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_imchiclet_adhoc.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_imchiclet_group.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_imchiclet_p2p.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_inspect_avatar_gear.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_inspect_object_gear.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_inspect_self_gear.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_inv_offer_chiclet.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_inventory.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_inventory_add.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_inventory_gear_default.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_land.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_landmark.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_login.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_mini_map.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_navbar.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_nearby_chat.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_notification_well_button.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_object.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_object_icon.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_outfit_gear.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_outfit_tab.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_participant_list.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_people_friends_view_sort.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_people_groups.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_people_groups_view_sort.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_people_nearby.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_people_nearby_multiselect.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_people_nearby_view_sort.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_people_recent_view_sort.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_picks.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_picks_plus.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_place.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_place_add_button.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_places_gear_folder.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_places_gear_landmark.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_profile_overflow.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_save_outfit.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_script_chiclet.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_slurl.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_teleport_history_gear.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_teleport_history_item.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_teleport_history_tab.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_text_editor.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_topinfobar.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_url_agent.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_url_group.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_url_http.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_url_inventory.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_url_map.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_url_objectim.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_url_parcel.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_url_slapp.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_url_slurl.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_url_teleport.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_viewer.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_wearable_list_item.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_wearing_gear.xml create mode 100644 indra/newview/skins/minimal/xui/it/menu_wearing_tab.xml create mode 100644 indra/newview/skins/minimal/xui/it/notifications.xml create mode 100644 indra/newview/skins/minimal/xui/it/panel_adhoc_control_panel.xml create mode 100644 indra/newview/skins/minimal/xui/it/panel_bottomtray.xml create mode 100644 indra/newview/skins/minimal/xui/it/panel_group_control_panel.xml create mode 100644 indra/newview/skins/minimal/xui/it/panel_im_control_panel.xml create mode 100644 indra/newview/skins/minimal/xui/it/panel_login.xml create mode 100644 indra/newview/skins/minimal/xui/it/panel_navigation_bar.xml create mode 100644 indra/newview/skins/minimal/xui/it/panel_people.xml create mode 100644 indra/newview/skins/minimal/xui/it/panel_side_tray_tab_caption.xml create mode 100644 indra/newview/skins/minimal/xui/it/panel_status_bar.xml create mode 100644 indra/newview/skins/minimal/xui/ja/floater_camera.xml create mode 100644 indra/newview/skins/minimal/xui/ja/floater_help_browser.xml create mode 100644 indra/newview/skins/minimal/xui/ja/floater_media_browser.xml create mode 100644 indra/newview/skins/minimal/xui/ja/floater_nearby_chat.xml create mode 100644 indra/newview/skins/minimal/xui/ja/floater_web_content.xml create mode 100644 indra/newview/skins/minimal/xui/ja/inspect_avatar.xml create mode 100644 indra/newview/skins/minimal/xui/ja/inspect_object.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_add_wearable_gear.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_attachment_other.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_attachment_self.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_avatar_icon.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_avatar_other.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_avatar_self.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_bottomtray.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_cof_attachment.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_cof_body_part.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_cof_clothing.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_cof_gear.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_edit.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_favorites.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_gesture_gear.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_group_plus.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_hide_navbar.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_im_well_button.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_imchiclet_adhoc.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_imchiclet_group.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_imchiclet_p2p.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_inspect_avatar_gear.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_inspect_object_gear.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_inspect_self_gear.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_inv_offer_chiclet.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_inventory.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_inventory_add.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_inventory_gear_default.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_land.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_landmark.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_login.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_mini_map.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_navbar.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_nearby_chat.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_notification_well_button.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_object.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_object_icon.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_outfit_gear.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_outfit_tab.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_participant_list.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_people_friends_view_sort.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_people_groups.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_people_groups_view_sort.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_people_nearby.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_people_nearby_multiselect.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_people_nearby_view_sort.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_people_recent_view_sort.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_picks.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_picks_plus.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_place.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_place_add_button.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_places_gear_folder.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_places_gear_landmark.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_profile_overflow.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_save_outfit.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_script_chiclet.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_slurl.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_teleport_history_gear.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_teleport_history_item.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_teleport_history_tab.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_text_editor.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_topinfobar.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_url_agent.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_url_group.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_url_http.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_url_inventory.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_url_map.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_url_objectim.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_url_parcel.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_url_slapp.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_url_slurl.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_url_teleport.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_viewer.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_wearable_list_item.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_wearing_gear.xml create mode 100644 indra/newview/skins/minimal/xui/ja/menu_wearing_tab.xml create mode 100644 indra/newview/skins/minimal/xui/ja/notifications.xml create mode 100644 indra/newview/skins/minimal/xui/ja/panel_adhoc_control_panel.xml create mode 100644 indra/newview/skins/minimal/xui/ja/panel_bottomtray.xml create mode 100644 indra/newview/skins/minimal/xui/ja/panel_group_control_panel.xml create mode 100644 indra/newview/skins/minimal/xui/ja/panel_im_control_panel.xml create mode 100644 indra/newview/skins/minimal/xui/ja/panel_login.xml create mode 100644 indra/newview/skins/minimal/xui/ja/panel_navigation_bar.xml create mode 100644 indra/newview/skins/minimal/xui/ja/panel_people.xml create mode 100644 indra/newview/skins/minimal/xui/ja/panel_side_tray_tab_caption.xml create mode 100644 indra/newview/skins/minimal/xui/ja/panel_status_bar.xml (limited to 'indra') diff --git a/indra/newview/skins/default/xui/it/floater_about_land.xml b/indra/newview/skins/default/xui/it/floater_about_land.xml index 186ed59e36..b713bb8143 100644 --- a/indra/newview/skins/default/xui/it/floater_about_land.xml +++ b/indra/newview/skins/default/xui/it/floater_about_land.xml @@ -352,6 +352,7 @@ Solamente terreni più grandi possono essere abilitati nella ricerca. + @@ -366,6 +367,7 @@ Solamente terreni più grandi possono essere abilitati nella ricerca. + @@ -444,7 +446,7 @@ Media: (Definito dalla proprietà) - Consenti accesso pubblico ([MATURITY]) + Consenti accesso pubblico ([MATURITY]) (Nota: se si rimuove la selezione vengono create linee di espulsione) Una o più di queste impostazioni sono già impostate a livello regionale diff --git a/indra/newview/skins/default/xui/it/floater_avatar_picker.xml b/indra/newview/skins/default/xui/it/floater_avatar_picker.xml index 7c037801e9..5a542d6a27 100644 --- a/indra/newview/skins/default/xui/it/floater_avatar_picker.xml +++ b/indra/newview/skins/default/xui/it/floater_avatar_picker.xml @@ -24,6 +24,10 @@ Comincia a digitare il nome della persona: - - - - - - - - - Upload Model - - - - This wizard will help you import mesh models to Second Life. First specify a file containing the model you wish to import. Second Life supports COLLADA (.dae) files. - - - - Filename: - - - - - Model Preview: - - - - - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - - - Note: - - -Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/floater/upload_model Advanced Mesh Import Window] . - - - - - - - - - Optimize - - - - This wizard has optimized your model to improve performance. You may adjust the results of the optimization process bellow or click Next to continue. - - - Generating Level of Detail - - - Generate Level of Detail: High - - Generate Level of Detail: Medium - - Generate Level of Detail: Low - - Generate Level of Detail: Lowest - - - - Model Preview: - - - - High - - - Medium - - - Low - - - Lowest - - - - - Higher Performance - Faster rendering but less detailed; lowers Resource (prim) cost. - Higher Accuracy - More detailed model but slower; increases Resource (prim) cost. - - - ' - - - - - - Resource Cost: [COST] - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - - - - - - - - Physics - - - - The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used: - - - Performance - Faster rendering but less detailed; lowers Resource (prim) cost. - Accuracy - More detailed model but slower; increases Resource (prim) cost. - - - ' ' ' ' ' ' ' ' ' ' ' - Recommended for solid objects - Recommended for buildings - Recommended for vehicles - - - - - Resource Cost: [COST] - - - - - - - - Physics - - - - Preview the physics shape below then click Next to continue. To modify the physics shape, click the Back button. - - - - Model Preview: - - - - High - - - Medium - - - Low - - - Lowest - - - - - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - - Resource Cost: [COST] - - - - - - - Review - - - - Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload. - - - - - Model Preview: - - - - High - - - Medium - - - Low - - - Lowest - - - - - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - - - Resource Cost: [COST] - This is the cost to your Region's prim/object limit, at default scale - Physics Cost: [COST] - This is the cost to your Region's prim/object limit, at default scale - Upload Fee: - This is the amount the upload will cost. - - I confirm that I have the appropriate rights to the material contained in this model. [secondlife:///app/floater/learn_more Learn more] - - - - - - - - - Upload Complete! - - - - Congratulations! Your model has been sucessfully uploaded. You will find the model in the Objects folder in your inventory. - - - - - - - + + + + + + + + + Upload Model + + + + This wizard will help you import mesh models to Second Life. First specify a file containing the model you wish to import. Second Life supports COLLADA (.dae) files. + + + + Filename: + + + + + Model Preview: + + + + + + Dimensions (meters): + + + X: Y: Z: + + + | | + + + + + + Note: + + +Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/floater/upload_model Advanced Mesh Import Window] . + + + + + + + + + Optimize + + + + This wizard has optimized your model to improve performance. You may adjust the results of the optimization process bellow or click Next to continue. + + + Generating Level of Detail + + + Generate Level of Detail: High + + Generate Level of Detail: Medium + + Generate Level of Detail: Low + + Generate Level of Detail: Lowest + + + + Model Preview: + + + + High + + + Medium + + + Low + + + Lowest + + + + + Higher Performance + Faster rendering but less detailed; lowers Resource (prim) cost. + Higher Accuracy + More detailed model but slower; increases Resource (prim) cost. + + + ' + + + + + + Resource Cost: [COST] + + Dimensions (meters): + + + X: Y: Z: + + + | | + + + + + + + + + + + Physics + + + + The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used: + + + Higher Performance + Faster rendering but less detailed; lowers Resource (prim) cost. + Higher Accuracy + More detailed model but slower; increases Resource (prim) cost. + + + ' ' ' ' ' ' ' ' ' ' ' + Recommended for solid objects + Recommended for buildings + Recommended for vehicles + + + + + Resource Cost: [COST] + + + + + + + + Physics + + + + Preview the physics shape below then click Next to continue. To modify the physics shape, click the Back button. + + + + Model Preview: + + + + High + + + Medium + + + Low + + + Lowest + + + + + + Dimensions (meters): + + + X: Y: Z: + + + | | + + + + + Resource Cost: [COST] + + + + + + + Review + + + + Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload. + + + + + Model Preview: + + + + High + + + Medium + + + Low + + + Lowest + + + + + + Dimensions (meters): + + + X: Y: Z: + + + | | + + + + + + Resource Cost: [COST] + This is the cost to your Region's prim/object limit, at default scale + Physics Cost: [COST] + This is the cost to your Region's prim/object limit, at default scale + Upload Fee: + This is the amount the upload will cost. + + I confirm that I have the appropriate rights to the material contained in this model. [secondlife:///app/floater/learn_more Learn more] + + + + + + + + + Upload Complete! + + + + Congratulations! Your model has been sucessfully uploaded. You will find the model in the Objects folder in your inventory. + + + + + + + - - - - - - Drag to move, shift-drag to copy - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - þ: [COUNT] - - - - Stretch Both Sides - - - - - - - - - - - - - Objects: [COUNT] - - - Prims: [COUNT] - - - Linked Sets: [COUNT] - - - Cost: [COST] / [PHYSICS] - - - Objects: [COUNT] - - - Cost: [COST] / [PHYSICS] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Deed - - - Deed - - - You can modify this object - - - You can modify these objects - - - You can't modify this object - - - You can't modify these objects - - - You must select entire object to set permissions - - - Price: L$ - - - Total Price: L$ - - - Price Per: L$ - - - Mixed Price - - - Mixed Sale - - - Name: - - - - Description: - - - - Creator: - - - - TestString PleaseIgnore (please.ignore) - - - Owner: - - - - TestString PleaseIgnore (please.ignore) - - - Group: - - - - - - - - + + + + + + Drag to move, shift-drag to copy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + þ: [COUNT] + + + + Stretch Both Sides + + + + + + + + + + + + + Objects: [COUNT] + + + Prims: [COUNT] + + + Linked Sets: [COUNT] + + + Cost: [COST] / [PHYSICS] + + + Objects: [COUNT] + + + Cost: [COST] / [PHYSICS] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Deed + + + Deed + + + You can modify this object + + + You can modify these objects + + + You can't modify this object + + + You can't modify these objects + + + You must select entire object to set permissions + + + Price: L$ + + + Total Price: L$ + + + Price Per: L$ + + + Mixed Price + + + Mixed Sale + + + Name: + + + + Description: + + + + Creator: + + + + TestString PleaseIgnore (please.ignore) + + + Owner: + + + + TestString PleaseIgnore (please.ignore) + + + Group: + + + + + + + + - - - - - - - - - Upload Model - - - - This wizard will help you import mesh models to Second Life. First specify a file containing the model you wish to import. Second Life supports COLLADA (.dae) files. - - - - Filename: - - - - - Model Preview: - - - - - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - - - Note: - - -Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/floater/upload_model Advanced Mesh Import Window] . - - - - - - - - - Optimize - - - - This wizard has optimized your model to improve performance. You may adjust the results of the optimization process bellow or click Next to continue. - - - Generating Level of Detail - - - Generate Level of Detail: High - - Generate Level of Detail: Medium - - Generate Level of Detail: Low - - Generate Level of Detail: Lowest - - - - Model Preview: - - - - High - - - Medium - - - Low - - - Lowest - - - - - Higher Performance - Faster rendering but less detailed; lowers Resource (prim) cost. - Higher Accuracy - More detailed model but slower; increases Resource (prim) cost. - - - ' - - - - - - Resource Cost: [COST] - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - - - - - - - - Physics - - - - The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used: - - - Higher Performance - Faster rendering but less detailed; lowers Resource (prim) cost. - Higher Accuracy - More detailed model but slower; increases Resource (prim) cost. - - - ' ' ' ' ' ' ' ' ' ' ' - Recommended for solid objects - Recommended for buildings - Recommended for vehicles - - - - - Resource Cost: [COST] - - - - - - - - Physics - - - - Preview the physics shape below then click Next to continue. To modify the physics shape, click the Back button. - - - - Model Preview: - - - - High - - - Medium - - - Low - - - Lowest - - - - - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - - Resource Cost: [COST] - - - - - - - Review - - - - Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload. - - - - - Model Preview: - - - - High - - - Medium - - - Low - - - Lowest - - - - - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - - - Resource Cost: [COST] - This is the cost to your Region's prim/object limit, at default scale - Physics Cost: [COST] - This is the cost to your Region's prim/object limit, at default scale - Upload Fee: - This is the amount the upload will cost. - - I confirm that I have the appropriate rights to the material contained in this model. [secondlife:///app/floater/learn_more Learn more] - - - - - - - - - Upload Complete! - - - - Congratulations! Your model has been sucessfully uploaded. You will find the model in the Objects folder in your inventory. - - - - - - - + + + + + + + + + Upload Model + + + + This wizard will help you import mesh models to Second Life. First specify a file containing the model you wish to import. Second Life supports COLLADA (.dae) files. + + + + Filename: + + + + + Model Preview: + + + + + + Dimensions (meters): + + + X: Y: Z: + + + | | + + + + + + Note: + + +Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/floater/upload_model Advanced Mesh Import Window] . + + + + + + + + + Optimize + + + + This wizard has optimized your model to improve performance. You may adjust the results of the optimization process bellow or click Next to continue. + + + Generating Level of Detail + + + Generate Level of Detail: High + + Generate Level of Detail: Medium + + Generate Level of Detail: Low + + Generate Level of Detail: Lowest + + + + Model Preview: + + + + High + + + Medium + + + Low + + + Lowest + + + + + Higher Performance + Faster rendering but less detailed; lowers Resource (prim) cost. + Higher Accuracy + More detailed model but slower; increases Resource (prim) cost. + + + ' + + + + + + Resource Cost: [COST] + + Dimensions (meters): + + + X: Y: Z: + + + | | + + + + + + + + + + + Physics + + + + The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used: + + + Higher Performance + Faster rendering but less detailed; lowers Resource (prim) cost. + Higher Accuracy + More detailed model but slower; increases Resource (prim) cost. + + + ' ' ' ' ' ' ' ' ' ' ' + Recommended for solid objects + Recommended for buildings + Recommended for vehicles + + + + + Resource Cost: [COST] + + + + + + + + Physics + + + + Preview the physics shape below then click Next to continue. To modify the physics shape, click the Back button. + + + + Model Preview: + + + + High + + + Medium + + + Low + + + Lowest + + + + + + Dimensions (meters): + + + X: Y: Z: + + + | | + + + + + Resource Cost: [COST] + + + + + + + Review + + + + Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload. + + + + + Model Preview: + + + + High + + + Medium + + + Low + + + Lowest + + + + + + Dimensions (meters): + + + X: Y: Z: + + + | | + + + + + + Resource Cost: [COST] + This is the cost to your Region's prim/object limit, at default scale + Physics Cost: [COST] + This is the cost to your Region's prim/object limit, at default scale + Upload Fee: + This is the amount the upload will cost. + + I confirm that I have the appropriate rights to the material contained in this model. [secondlife:///app/floater/learn_more Learn more] + + + + + + + + + Upload Complete! + + + + Congratulations! Your model has been sucessfully uploaded. You will find the model in the Objects folder in your inventory. + + + + + + + - - - - - - Drag to move, shift-drag to copy - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - þ: [COUNT] - - - - Stretch Both Sides - - - - - - - - - - - - - Objects: [COUNT] - - - Prims: [COUNT] - - - Linked Sets: [COUNT] - - - Cost: [COST] / [PHYSICS] - - - Objects: [COUNT] - - - Cost: [COST] / [PHYSICS] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Deed - - - Deed - - - You can modify this object - - - You can modify these objects - - - You can't modify this object - - - You can't modify these objects - - - You must select entire object to set permissions - - - Price: L$ - - - Total Price: L$ - - - Price Per: L$ - - - Mixed Price - - - Mixed Sale - - - Name: - - - - Description: - - - - Creator: - - - - TestString PleaseIgnore (please.ignore) - - - Owner: - - - - TestString PleaseIgnore (please.ignore) - - - Group: - - - - - - - - + + + + + + Drag to move, shift-drag to copy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + þ: [COUNT] + + + + Stretch Both Sides + + + + + + + + + + + + + Objects: [COUNT] + + + Prims: [COUNT] + + + Linked Sets: [COUNT] + + + Cost: [COST] / [PHYSICS] + + + Objects: [COUNT] + + + Cost: [COST] / [PHYSICS] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Deed + + + Deed + + + You can modify this object + + + You can modify these objects + + + You can't modify this object + + + You can't modify these objects + + + You must select entire object to set permissions + + + Price: L$ + + + Total Price: L$ + + + Price Per: L$ + + + Mixed Price + + + Mixed Sale + + + Name: + + + + Description: + + + + Creator: + + + + TestString PleaseIgnore (please.ignore) + + + Owner: + + + + TestString PleaseIgnore (please.ignore) + + + Group: + + + + + + + +