From d0e3cee4c2e44b7bffd69e4138ecbfd04bf60601 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sun, 29 Apr 2012 10:18:00 +1000 Subject: It's April, onefang ate all the Easter eggs. Burp. --- linden/indra/newview/llgesturemgr.cpp | 241 +-------------------- .../newview/skins/default/textures/cakeisalie.png | Bin 124929 -> 0 bytes .../newview/skins/default/textures/ceilingcat.png | Bin 139515 -> 0 bytes .../newview/skins/default/textures/easteregg.png | Bin 395345 -> 0 bytes .../indra/newview/skins/default/textures/hugs.png | Bin 204219 -> 0 bytes .../newview/skins/default/textures/nomnom.png | Bin 380325 -> 0 bytes .../newview/skins/default/textures/octopus.png | Bin 442610 -> 0 bytes .../newview/skins/default/textures/zombiecat.png | Bin 334660 -> 0 bytes 8 files changed, 1 insertion(+), 240 deletions(-) delete mode 100644 linden/indra/newview/skins/default/textures/cakeisalie.png delete mode 100644 linden/indra/newview/skins/default/textures/ceilingcat.png delete mode 100644 linden/indra/newview/skins/default/textures/easteregg.png delete mode 100644 linden/indra/newview/skins/default/textures/hugs.png delete mode 100644 linden/indra/newview/skins/default/textures/nomnom.png delete mode 100644 linden/indra/newview/skins/default/textures/octopus.png delete mode 100644 linden/indra/newview/skins/default/textures/zombiecat.png diff --git a/linden/indra/newview/llgesturemgr.cpp b/linden/indra/newview/llgesturemgr.cpp index bd05cb3..f806ccc 100644 --- a/linden/indra/newview/llgesturemgr.cpp +++ b/linden/indra/newview/llgesturemgr.cpp @@ -531,7 +531,6 @@ BOOL LLGestureManager::triggerAndReviseString(const std::string &utf8str, std::s gesture = NULL; } - if (matching.size() > 0) { // choose one at random @@ -565,246 +564,8 @@ BOOL LLGestureManager::triggerAndReviseString(const std::string &utf8str, std::s found_gestures = TRUE; } } - else if (LLStringUtil::compareInsensitive("/icanhaseasteregg", cur_token) == 0 || - LLStringUtil::compareInsensitive("/icanhaseastereggs", cur_token) == 0) - { - LLViewerImage* kitteh = gImageList.getImageFromFile("easteregg.png", TRUE, TRUE); - if (kitteh) - { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewTextureRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - - LLPreviewTexture* preview; - preview = new LLPreviewTexture(rect, "Easter Egg!", kitteh); - preview->setSourceID(LLUUID::generateNewID()); - preview->setFocus(TRUE); - preview->center(); - gFloaterView->adjustToFitScreen(preview, FALSE); - } - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhascookie", cur_token) == 0 || - LLStringUtil::compareInsensitive("/icanhascookies", cur_token) == 0) - { - LLChat chat; - chat.mText = "I made you a cookie but I eated it :("; - chat.mSourceType = CHAT_SOURCE_SYSTEM; - LLFloaterChat::addChat(chat); - if (revised_string) - { - revised_string->assign(LLStringUtil::null); - } - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhasfailbook", cur_token) == 0) - { - LLWeb::loadURLInternal("http://failbook.failblog.org/"); - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhaszombie", cur_token) == 0 || - LLStringUtil::compareInsensitive("/icanhaszombies", cur_token) == 0) - { - LLViewerImage* kitteh = gImageList.getImageFromFile("zombiecat.png", TRUE, TRUE); - if (kitteh) - { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewTextureRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - - LLPreviewTexture* preview; - preview = new LLPreviewTexture(rect, "Zombiecat!", kitteh); - preview->setSourceID(LLUUID::generateNewID()); - preview->setFocus(TRUE); - preview->center(); - gFloaterView->adjustToFitScreen(preview, FALSE); - } - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhassupport", cur_token) == 0 || - LLStringUtil::compareInsensitive("/icanhashelp", cur_token) == 0 || - LLStringUtil::compareInsensitive("/icanhashalp", cur_token) == 0) - { - LLWeb::loadURLInternal("http://support.kokuaviewer.org/"); - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhasblog", cur_token) == 0) - { - LLWeb::loadURLInternal("http://kokuaviewer.org/"); - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhascodie", cur_token) == 0) - { - LLChat chat; - chat.mText = "All work and no play makes Codie a dull girl. All work and no play..."; - chat.mSourceType = CHAT_SOURCE_SYSTEM; - LLFloaterChat::addChat(chat); - if (revised_string) - { - revised_string->assign(LLStringUtil::null); - } - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhasfail", cur_token) == 0) - { - LLWeb::loadURLInternal("http://www.failblog.org/"); - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhasdownload", cur_token) == 0 || - LLStringUtil::compareInsensitive("/icanhasdownloads", cur_token) == 0 || - LLStringUtil::compareInsensitive("/icanhasupdate", cur_token) == 0 || - LLStringUtil::compareInsensitive("/icanhasupdates", cur_token) == 0 ) - { - LLWeb::loadURLInternal("http://wiki.kokuaviewer.org/wiki/Imprudence:Downloads"); - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhasfeatures", cur_token) == 0) - { - LLWeb::loadURLInternal("http://wiki.kokuaviewer.org/wiki/Imprudence:Features"); - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhaswiki", cur_token) == 0) - { - LLWeb::loadURLInternal("http://wiki.kokuaviewer.org/wiki/"); - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhasbugs", cur_token) == 0 || - LLStringUtil::compareInsensitive("/icanhasbug", cur_token) == 0 ) - { - LLWeb::loadURLInternal("http://redmine.kokuaviewer.org/"); - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhasgit", cur_token) == 0) - { - LLWeb::loadURLInternal("http://github.com/imprudence/imprudence/"); - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhasplurk", cur_token) == 0) - { - LLWeb::loadURLInternal("http://plurk.com/imprudence"); - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhastwitter", cur_token) == 0) - { - LLWeb::loadURLInternal("http://twitter.com/ImpViewer"); - return TRUE; - } - - else if (LLStringUtil::compareInsensitive("/icanhasimprudence", cur_token) == 0) - { - LLChat chat; - chat.mText = "You are using it right now, silly!..."; - chat.mSourceType = CHAT_SOURCE_SYSTEM; - LLFloaterChat::addChat(chat); - if (revised_string) - { - revised_string->assign(LLStringUtil::null); - } - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhasnoms", cur_token) == 0 || - LLStringUtil::compareInsensitive("/icanhasnom", cur_token) == 0) - { - LLViewerImage* kitteh = gImageList.getImageFromFile("nomnom.png", TRUE, TRUE); - if (kitteh) - { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewTextureRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - - LLPreviewTexture* preview; - preview = new LLPreviewTexture(rect, "Om nom nom!", kitteh); - preview->setSourceID(LLUUID::generateNewID()); - preview->setFocus(TRUE); - preview->center(); - gFloaterView->adjustToFitScreen(preview, FALSE); - } - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhasceilingcat", cur_token) == 0 || - LLStringUtil::compareInsensitive("/icanhascielingcat", cur_token) == 0) - { - LLViewerImage* kitteh = gImageList.getImageFromFile("ceilingcat.png", TRUE, TRUE); - if (kitteh) - { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewTextureRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - - LLPreviewTexture* preview; - preview = new LLPreviewTexture(rect, "Ceiling Cat is watching you!", kitteh); - preview->setSourceID(LLUUID::generateNewID()); - preview->setFocus(TRUE); - preview->center(); - gFloaterView->adjustToFitScreen(preview, FALSE); - } - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhascake", cur_token) == 0 ) - { - LLViewerImage* kitteh = gImageList.getImageFromFile("cakeisalie.png", TRUE, TRUE); - if (kitteh) - { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewTextureRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - - LLPreviewTexture* preview; - preview = new LLPreviewTexture(rect, "THE CAKE IS A LIE!", kitteh); - preview->setSourceID(LLUUID::generateNewID()); - preview->setFocus(TRUE); - preview->center(); - gFloaterView->adjustToFitScreen(preview, FALSE); - } - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhastentacles", cur_token) == 0 ) - { - LLViewerImage* kitteh = gImageList.getImageFromFile("octopus.png", TRUE, TRUE); - if (kitteh) - { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewTextureRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - - LLPreviewTexture* preview; - preview = new LLPreviewTexture(rect, "All hail the mighty octopus!", kitteh); - preview->setSourceID(LLUUID::generateNewID()); - preview->setFocus(TRUE); - preview->center(); - gFloaterView->adjustToFitScreen(preview, FALSE); - } - return TRUE; - } - else if (LLStringUtil::compareInsensitive("/icanhashugs", cur_token) == 0 || - LLStringUtil::compareInsensitive("/icanhashug", cur_token) == 0) - { - LLViewerImage* kitteh = gImageList.getImageFromFile("hugs.png", TRUE, TRUE); - if (kitteh) - { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewTextureRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - - LLPreviewTexture* preview; - preview = new LLPreviewTexture(rect, "Yes, you can has hugs!", kitteh); - preview->setSourceID(LLUUID::generateNewID()); - preview->setFocus(TRUE); - preview->center(); - gFloaterView->adjustToFitScreen(preview, FALSE); - } - return TRUE; - } - } - + if(!gesture) { // This token doesn't match a gesture. Pass it through to the output. diff --git a/linden/indra/newview/skins/default/textures/cakeisalie.png b/linden/indra/newview/skins/default/textures/cakeisalie.png deleted file mode 100644 index bc8af84..0000000 Binary files a/linden/indra/newview/skins/default/textures/cakeisalie.png and /dev/null differ diff --git a/linden/indra/newview/skins/default/textures/ceilingcat.png b/linden/indra/newview/skins/default/textures/ceilingcat.png deleted file mode 100644 index 5cf5285..0000000 Binary files a/linden/indra/newview/skins/default/textures/ceilingcat.png and /dev/null differ diff --git a/linden/indra/newview/skins/default/textures/easteregg.png b/linden/indra/newview/skins/default/textures/easteregg.png deleted file mode 100644 index 75eaef7..0000000 Binary files a/linden/indra/newview/skins/default/textures/easteregg.png and /dev/null differ diff --git a/linden/indra/newview/skins/default/textures/hugs.png b/linden/indra/newview/skins/default/textures/hugs.png deleted file mode 100644 index d612793..0000000 Binary files a/linden/indra/newview/skins/default/textures/hugs.png and /dev/null differ diff --git a/linden/indra/newview/skins/default/textures/nomnom.png b/linden/indra/newview/skins/default/textures/nomnom.png deleted file mode 100644 index ffc70ef..0000000 Binary files a/linden/indra/newview/skins/default/textures/nomnom.png and /dev/null differ diff --git a/linden/indra/newview/skins/default/textures/octopus.png b/linden/indra/newview/skins/default/textures/octopus.png deleted file mode 100644 index 91765f9..0000000 Binary files a/linden/indra/newview/skins/default/textures/octopus.png and /dev/null differ diff --git a/linden/indra/newview/skins/default/textures/zombiecat.png b/linden/indra/newview/skins/default/textures/zombiecat.png deleted file mode 100644 index 93392c0..0000000 Binary files a/linden/indra/newview/skins/default/textures/zombiecat.png and /dev/null differ -- cgit v1.1 From 5845bcd9de3b9e22952bf798d32d1b7f9cf5fa21 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sun, 29 Apr 2012 19:15:57 +1000 Subject: For Armin and his teapot. --- linden/indra/newview/llvoavatar.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linden/indra/newview/llvoavatar.cpp b/linden/indra/newview/llvoavatar.cpp index 11f4857..359ac74 100644 --- a/linden/indra/newview/llvoavatar.cpp +++ b/linden/indra/newview/llvoavatar.cpp @@ -3287,6 +3287,11 @@ void LLVOAvatar::resolveClient(LLColor4& avatar_name_color, std::string& client, avatar_name_color += colour; avatar_name_color *= 1.0/(cllsd["multiple"].asReal()+1.0f); } + else if(idx == LLUUID("7eab0700-f000-0000-0000-546561706f74")) + { + avatar_name_color = LLColor4(0.69f,0.42f,0.84f,1.0f); // Armins V3 viewer. + client = "Teapot"; + } else if(idx == LLUUID("2a9a406c-f448-68f2-4e38-878f8c46c190") || idx == LLUUID("b6820989-bf42-ff59-ddde-fd3fd3a74fe4")) { -- cgit v1.1 From 0528bbd5ef37b7d60c639db2c450cca415b6590e Mon Sep 17 00:00:00 2001 From: Robin Cornelius Date: Sat, 1 Oct 2011 22:16:53 +0100 Subject: MOAP Radar patch set --- linden/etc/message.xml | 6 + linden/indra/llmath/llsdutil_math.cpp | 14 +- linden/indra/newview/CMakeLists.txt | 4 + linden/indra/newview/app_settings/settings.xml | 128 +++++++ linden/indra/newview/llfloaterbeacons.cpp | 3 + linden/indra/newview/llstartup.cpp | 12 + linden/indra/newview/llviewermenu.cpp | 32 ++ linden/indra/newview/llviewerobject.h | 8 +- linden/indra/newview/llviewerregion.cpp | 2 + linden/indra/newview/llvovolume.cpp | 398 ++++++++++++++++++++- linden/indra/newview/llvovolume.h | 53 +++ linden/indra/newview/pipeline.cpp | 61 ++++ linden/indra/newview/pipeline.h | 5 + .../skins/default/xui/en-us/floater_beacons.xml | 5 +- .../skins/default/xui/en-us/menu_viewer.xml | 4 + 15 files changed, 720 insertions(+), 15 deletions(-) diff --git a/linden/etc/message.xml b/linden/etc/message.xml index 8d34dd8..f86ca8b 100644 --- a/linden/etc/message.xml +++ b/linden/etc/message.xml @@ -702,6 +702,12 @@ FetchLib true + + ObjectMedia + false + + ObjectMediaNavigate + false messageBans diff --git a/linden/indra/llmath/llsdutil_math.cpp b/linden/indra/llmath/llsdutil_math.cpp index 073cb2e..8ec8661 100644 --- a/linden/indra/llmath/llsdutil_math.cpp +++ b/linden/indra/llmath/llsdutil_math.cpp @@ -6,7 +6,7 @@ * * $LicenseInfo:firstyear=2006&license=viewergpl$ * - * Copyright (c) 2006-2009, Linden Research, Inc. + * Copyright (c) 2006-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -14,13 +14,13 @@ * ("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 + * online at http://secondlife.com/developers/opensource/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 + * http://secondlife.com/developers/opensource/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, @@ -30,11 +30,12 @@ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ + * */ #include "linden_common.h" -#include "llsdutil.h" +#include "llsdutil_math.h" #include "v3math.h" #include "v4math.h" @@ -165,9 +166,6 @@ LLSD ll_sd_from_color4(const LLColor4& c) LLColor4 ll_color4_from_sd(const LLSD& sd) { LLColor4 c; - c.mV[0] = (F32)sd[0].asReal(); - c.mV[1] = (F32)sd[1].asReal(); - c.mV[2] = (F32)sd[2].asReal(); - c.mV[3] = (F32)sd[3].asReal(); + c.setValue(sd); return c; } diff --git a/linden/indra/newview/CMakeLists.txt b/linden/indra/newview/CMakeLists.txt index 2a976ff..b9c41fc 100644 --- a/linden/indra/newview/CMakeLists.txt +++ b/linden/indra/newview/CMakeLists.txt @@ -274,6 +274,7 @@ set(viewer_SOURCE_FILES llmaniprotate.cpp llmanipscale.cpp llmaniptranslate.cpp + llmediadataclient.cpp llmapresponders.cpp llmediaremotectrl.cpp llmemoryview.cpp @@ -508,6 +509,7 @@ set(viewer_SOURCE_FILES wlfloaterwindlightsend.cpp wlretrievesettings.cpp wlsettingsmanager.cpp + rcmoapradar.cpp ) set(VIEWER_BINARY_NAME "imprudence-bin" CACHE STRING @@ -737,6 +739,7 @@ set(viewer_HEADER_FILES llmaniprotate.h llmanipscale.h llmaniptranslate.h + llmediadataclient.h llmapresponders.h llmediaremotectrl.h llmemoryview.h @@ -981,6 +984,7 @@ set(viewer_HEADER_FILES wlfloaterwindlightsend.h wlretrievesettings.h wlsettingsmanager.h + rcmoapradar.h ) source_group("CMake Rules" FILES ViewerInstall.cmake) diff --git a/linden/indra/newview/app_settings/settings.xml b/linden/indra/newview/app_settings/settings.xml index 2ec4832..1451aef 100644 --- a/linden/indra/newview/app_settings/settings.xml +++ b/linden/indra/newview/app_settings/settings.xml @@ -2,6 +2,123 @@ + + PrimMediaMasterEnabled + + Comment + Whether or not Media on a Prim is enabled. + Persist + 1 + Type + Boolean + Value + 1 + + PrimMediaMaxRetries + + Comment + Maximum number of retries for media queries. + Persist + 1 + Type + U32 + Value + 4 + + PrimMediaRequestQueueDelay + + Comment + Timer delay for fetching media from the queue (in seconds). + Persist + 1 + Type + F32 + Value + 1.0 + + PrimMediaRetryTimerDelay + + Comment + Timer delay for retrying on media queries (in seconds). + Persist + 1 + Type + F32 + Value + 5.0 + + PrimMediaMaxSortedQueueSize + + Comment + Maximum number of objects the viewer will load media for initially + Persist + 1 + Type + U32 + Value + 100000 + + PrimMediaMaxRoundRobinQueueSize + + Comment + Maximum number of objects the viewer will continuously update media for + Persist + 1 + Type + U32 + Value + 100000 + + ShowMOAPRadar + + Comment + Show the MOAP radar + Persist + 1 + Type + Boolean + Value + 0 + + FloaterMOAPRadarRect + + Comment + Rectangle for MOAP Radar + Persist + 1 + Type + Rect + Value + + 0 + 400 + 200 + 0 + + + MOAPRadarKeepOpen + + Comment + Keeps MOAP radar updates running in background + Persist + 1 + Type + Boolean + Value + 0 + + MOAPRadarUpdateRate + + Comment + MOAP Radar update rate (0 = high, 1 = medium, 2 = low) + Persist + 1 + Type + U32 + Value + 1 + + @@ -14645,6 +14762,17 @@ 1.0 + moapbeacon + + Comment + Beacon / Highlight MOAP sources + Persist + 1 + Type + Boolean + Value + 0 + particlesbeacon Comment diff --git a/linden/indra/newview/llfloaterbeacons.cpp b/linden/indra/newview/llfloaterbeacons.cpp index aa89780..7c40931 100644 --- a/linden/indra/newview/llfloaterbeacons.cpp +++ b/linden/indra/newview/llfloaterbeacons.cpp @@ -54,6 +54,7 @@ LLFloaterBeacons::LLFloaterBeacons(const LLSD& seed) LLPipeline::setRenderScriptedTouchBeacons(gSavedSettings.getBOOL("scripttouchbeacon")); LLPipeline::setRenderScriptedBeacons( gSavedSettings.getBOOL("scriptsbeacon")); LLPipeline::setRenderPhysicalBeacons( gSavedSettings.getBOOL("physicalbeacon")); + LLPipeline::setRenderMOAPBeacons( gSavedSettings.getBOOL("moapbeacon")); LLPipeline::setRenderSoundBeacons( gSavedSettings.getBOOL("soundsbeacon")); LLPipeline::setRenderParticleBeacons( gSavedSettings.getBOOL("particlesbeacon")); LLPipeline::setRenderHighlights( gSavedSettings.getBOOL("renderhighlights")); @@ -67,6 +68,7 @@ BOOL LLFloaterBeacons::postBuild() childSetCommitCallback("physical", onClickUICheck, this); childSetCommitCallback("sounds", onClickUICheck, this); childSetCommitCallback("particles", onClickUICheck, this); + childSetCommitCallback("moap", onClickUICheck, this); childSetCommitCallback("highlights", onClickUICheck, this); childSetCommitCallback("beacons", onClickUICheck, this); return TRUE; @@ -132,6 +134,7 @@ void LLFloaterBeacons::onClickUICheck(LLUICtrl *ctrl, void* data) else if(name == "physical") LLPipeline::setRenderPhysicalBeacons(check->get()); else if(name == "sounds") LLPipeline::setRenderSoundBeacons(check->get()); else if(name == "particles") LLPipeline::setRenderParticleBeacons(check->get()); + else if(name == "moap") LLPipeline::setRenderMOAPBeacons(check->get()); else if(name == "highlights") { LLPipeline::toggleRenderHighlights(NULL); diff --git a/linden/indra/newview/llstartup.cpp b/linden/indra/newview/llstartup.cpp index 922de18..d853dc0 100644 --- a/linden/indra/newview/llstartup.cpp +++ b/linden/indra/newview/llstartup.cpp @@ -206,6 +206,8 @@ #include "rlvhandler.h" // [/RLVa:KB] +#include "rcmoapradar.h" + #if LL_WINDOWS #include "llwindebug.h" #include "lldxhardware.h" @@ -2079,6 +2081,16 @@ bool idle_startup() LLRect window(0, gViewerWindow->getWindowHeight(), gViewerWindow->getWindowWidth(), 0); gViewerWindow->adjustControlRectanglesForFirstUse(window); + if (gSavedSettings.getBOOL("ShowRadar")) + { + LLFloaterAvatarList::showInstance(); + } + + if (gSavedSettings.getBOOL("ShowMOAPRadar")) + { + LLFloaterMOAPRadar::showInstance(); + } + if(gSavedSettings.getBOOL("ShowMiniMap")) { LLFloaterMap::showInstance(); diff --git a/linden/indra/newview/llviewermenu.cpp b/linden/indra/newview/llviewermenu.cpp index a83c11b..538adc7 100644 --- a/linden/indra/newview/llviewermenu.cpp +++ b/linden/indra/newview/llviewermenu.cpp @@ -238,6 +238,8 @@ #include "llfloaterteleporthistory.h" #include "slfloatermediafilter.h" +#include "rcmoapradar.h" + using namespace LLVOAvatarDefines; void init_client_menu(LLMenuGL* menu); void init_server_menu(LLMenuGL* menu); @@ -5216,6 +5218,34 @@ class LLViewEnableLastChatter : public view_listener_t } }; +class LLViewToggleRadar: public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + LLFloaterAvatarList::toggle(0); + bool vis = false; + if(LLFloaterAvatarList::getInstance()) + { + vis = (bool)LLFloaterAvatarList::getInstance()->getVisible(); + } + return true; + } +}; + +class LLViewToggleMOAPRadar: public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + LLFloaterMOAPRadar::toggle(0); + bool vis = false; + if(LLFloaterMOAPRadar::getInstance()) + { + vis = (bool)LLFloaterMOAPRadar::getInstance()->getVisible(); + } + return true; + } +}; + class LLEditEnableDeselect : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) @@ -11215,6 +11245,8 @@ void initialize_menus() addMenu(new LLViewEnableMouselook(), "View.EnableMouselook"); addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam"); addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter"); + addMenu(new LLViewToggleRadar(), "View.ToggleAvatarList"); + addMenu(new LLViewToggleMOAPRadar(), "View.ToggleMOAPList"); addMenu(new LLViewCheckBuildMode(), "View.CheckBuildMode"); addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam"); diff --git a/linden/indra/newview/llviewerobject.h b/linden/indra/newview/llviewerobject.h index 9b05470..98b7115 100644 --- a/linden/indra/newview/llviewerobject.h +++ b/linden/indra/newview/llviewerobject.h @@ -157,7 +157,13 @@ public: enum { MEDIA_TYPE_NONE = 0, MEDIA_TYPE_WEB_PAGE = 1 }; // Return codes for processUpdateMessage - enum { MEDIA_URL_REMOVED = 0x1, MEDIA_URL_ADDED = 0x2, MEDIA_URL_UPDATED = 0x4, INVALID_UPDATE = 0x80000000 }; + 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, diff --git a/linden/indra/newview/llviewerregion.cpp b/linden/indra/newview/llviewerregion.cpp index 2fafe30..42eb112 100644 --- a/linden/indra/newview/llviewerregion.cpp +++ b/linden/indra/newview/llviewerregion.cpp @@ -1436,6 +1436,8 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("EstateChangeInfo"); capabilityNames.append("EventQueueGet"); capabilityNames.append("FetchInventory"); + capabilityNames.append("ObjectMedia"); + capabilityNames.append("ObjectMediaNavigate"); capabilityNames.append("FetchLib"); capabilityNames.append("FetchLibDescendents"); capabilityNames.append("GetDisplayNames"); diff --git a/linden/indra/newview/llvovolume.cpp b/linden/indra/newview/llvovolume.cpp index d580d61..cb38c86 100644 --- a/linden/indra/newview/llvovolume.cpp +++ b/linden/indra/newview/llvovolume.cpp @@ -68,6 +68,9 @@ #include "rlvhandler.h" // [/RLVa:KB] +#include "llmediaentry.h" +#include "llmediadataclient.h" + const S32 MIN_QUIET_FRAMES_COALESCE = 30; const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; const F32 FORCE_CULL_AREA = 8.f; @@ -79,6 +82,93 @@ F32 LLVOVolume::sLODFactor = 1.f; F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop F32 LLVOVolume::sDistanceFactor = 1.0f; S32 LLVOVolume::sNumLODChanges = 0; +LLPointer LLVOVolume::sObjectMediaClient = NULL; +LLPointer LLVOVolume::sObjectMediaNavigateClient = NULL; + +// Implementation class of LLMediaDataClientObject. See llmediadataclient.h +class LLMediaDataClientObjectImpl : public LLMediaDataClientObject +{ +public: + LLMediaDataClientObjectImpl(LLVOVolume *obj, bool isNew) : mObject(obj), mNew(isNew) {} + LLMediaDataClientObjectImpl() { mObject = NULL; } + + virtual U8 getMediaDataCount() const + { return mObject->getNumTEs(); } + + virtual LLSD getMediaDataLLSD(U8 index) const + { + LLSD result; + LLTextureEntry *te = mObject->getTE(index); + if (NULL != te) + { + llassert((te->getMediaData() != NULL) == te->hasMedia()); + if (te->getMediaData() != NULL) + { + result = te->getMediaData()->asLLSD(); + // XXX HACK: workaround bug in asLLSD() where whitelist is not set properly + // See DEV-41949 + if (!result.has(LLMediaEntry::WHITELIST_KEY)) + { + result[LLMediaEntry::WHITELIST_KEY] = LLSD::emptyArray(); + } + } + } + return result; + } + + virtual LLUUID getID() const + { return mObject->getID(); } + + virtual void mediaNavigateBounceBack(U8 index) + { mObject->mediaNavigateBounceBack(index); } + + virtual bool hasMedia() const + { return mObject->hasMedia();} + + virtual void updateObjectMediaData(LLSD const &data, const std::string &version_string) + { mObject->updateObjectMediaData(data, version_string); } + + virtual F64 getMediaInterest() const + { + //F64 interest = mObject->getTotalMediaInterest(); + //FIXME + F64 interest = 1024; + if (interest < (F64)0.0) + { + // media interest not valid yet, try pixel area + interest = mObject->getPixelArea(); + // HACK: force recalculation of pixel area if interest is the "magic default" of 1024. + if (interest == 1024.f) + { + const_cast(static_cast(mObject))->setPixelAreaAndAngle(gAgent); + interest = mObject->getPixelArea(); + } + } + return interest; + } + + virtual bool isInterestingEnough() const + { + return true; //FUCKEDUP --> LLViewerMedia::isInterestingEnough(mObject, getMediaInterest()); + } + + virtual std::string getCapabilityUrl(const std::string &name) const + { return mObject->getRegion()->getCapability(name); } + + virtual bool isDead() const + { return mObject->isDead(); } + + virtual U32 getMediaVersion() const + { return LLTextureEntry::getVersionFromMediaVersionString(mObject->getMediaURL()); } + + virtual bool isNew() const + { return mNew; } + +private: + LLPointer mObject; + bool mNew; +}; + LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) : LLViewerObject(id, pcode, regionp), @@ -123,6 +213,18 @@ void LLVOVolume::markDead() // static void LLVOVolume::initClass() { + // gSavedSettings better be around + if (gSavedSettings.getBOOL("PrimMediaMasterEnabled")) + { + const F32 queue_timer_delay = gSavedSettings.getF32("PrimMediaRequestQueueDelay"); + const F32 retry_timer_delay = gSavedSettings.getF32("PrimMediaRetryTimerDelay"); + const U32 max_retries = gSavedSettings.getU32("PrimMediaMaxRetries"); + const U32 max_sorted_queue_size = gSavedSettings.getU32("PrimMediaMaxSortedQueueSize"); + const U32 max_round_robin_queue_size = gSavedSettings.getU32("PrimMediaMaxRoundRobinQueueSize"); + + sObjectMediaClient = new LLObjectMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries, + max_sorted_queue_size, max_round_robin_queue_size); + } } @@ -132,6 +234,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, LLDataPacker *dp) { LLColor4U color; + const S32 teDirtyBits = (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR|TEM_CHANGE_MEDIA); // Do base class updates... U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); @@ -199,10 +302,15 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, // // Unpack texture entry data // - if (unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num) & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR)) + S32 result =unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num); + if (result & teDirtyBits) { updateTEData(); } + if (result & TEM_CHANGE_MEDIA) + { + retval |= MEDIA_FLAGS_CHANGED; + } } else { @@ -235,9 +343,16 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, // llerrs << "Bogus TE data in " << getID() << ", crashing!" << llendl; llwarns << "Bogus TE data in " << getID() << llendl; } - else if (res2 & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR)) + else { - updateTEData(); + if (res2 & teDirtyBits) + { + updateTEData(); + } + if (res2 & TEM_CHANGE_MEDIA) + { + retval |= MEDIA_FLAGS_CHANGED; + } } U32 value = dp->getPassFlags(); @@ -275,13 +390,39 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, U8 tdpbuffer[1024]; LLDataPackerBinaryBuffer tdp(tdpbuffer, 1024); mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num); - if ( unpackTEMessage(tdp) & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR)) + S32 result = unpackTEMessage(tdp); + if (result & teDirtyBits) { updateTEData(); } + if (result & TEM_CHANGE_MEDIA) + { + retval |= MEDIA_FLAGS_CHANGED; + } } } } + + if (retval & (MEDIA_URL_REMOVED | MEDIA_URL_ADDED | MEDIA_URL_UPDATED | MEDIA_FLAGS_CHANGED)) + { + // If only the media URL changed, and it isn't a media version URL, + // ignore it + if ( ! ( retval & (MEDIA_URL_ADDED | MEDIA_URL_UPDATED) && + mMedia && ! mMedia->mMediaURL.empty() && + ! LLTextureEntry::isMediaVersionString(mMedia->mMediaURL) ) ) + { + // If the media changed at all, request new media data + LL_DEBUGS("MediaOnAPrim") << "Media update: " << getID() << ": retval=" << retval << " Media URL: " << + ((mMedia) ? mMedia->mMediaURL : std::string("")) << LL_ENDL; + requestMediaDataUpdate(retval & MEDIA_FLAGS_CHANGED); + } + else { + LL_INFOS("MediaOnAPrim") << "Ignoring media update for: " << getID() << " Media URL: " << + ((mMedia) ? mMedia->mMediaURL : std::string("")) << LL_ENDL; + } + } + // ...and clean up any media impls + cleanUpMediaImpls(); return retval; } @@ -2894,4 +3035,253 @@ void LLHUDPartition::shift(const LLVector3 &offset) //HUD objects don't shift with region crossing. That would be silly. } +void LLVOVolume::requestMediaDataUpdate(bool isNew) +{ + if (sObjectMediaClient) + sObjectMediaClient->fetchMedia(new LLMediaDataClientObjectImpl(this, isNew)); +} + +void LLVOVolume::cleanUpMediaImpls() +{ + // Iterate through our TEs and remove any Impls that are no longer used + const U8 numTEs = getNumTEs(); + for (U8 i = 0; i < numTEs; i++) + { + const LLTextureEntry* te = getTE(i); + if( ! te->hasMedia()) + { + // Delete the media IMPL! + removeMediaImpl(i) ; + } + } +} + +void LLVOVolume::removeMediaImpl(S32 texture_index) +{ + if(mMediaImplList.size() <= (U32)texture_index || mMediaImplList[texture_index].isNull()) + { + return ; + } + + //make the face referencing to mMediaImplList[texture_index] to point back to the old texture. + if(mDrawable) + { + LLFace* facep = mDrawable->getFace(texture_index) ; + if(facep) + { + //LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ; + //if(media_tex) + //{ + // media_tex->removeMediaFromFace(facep) ; + //} + } + } + + //check if some other face(s) of this object reference(s)to this media impl. + S32 i ; + S32 end = (S32)mMediaImplList.size() ; + for(i = 0; i < end ; i++) + { + if( i != texture_index && mMediaImplList[i] == mMediaImplList[texture_index]) + { + break ; + } + } + + if(i == end) //this object does not need this media impl. + { + //mMediaImplList[texture_index]->removeObject(this) ; + } + + mMediaImplList[texture_index] = NULL ; + return ; +} + +void LLVOVolume::addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) +{ + if((S32)mMediaImplList.size() < texture_index + 1) + { + mMediaImplList.resize(texture_index + 1) ; + } + + if(mMediaImplList[texture_index].notNull()) + { + if(mMediaImplList[texture_index] == media_impl) + { + return ; + } + + removeMediaImpl(texture_index) ; + } + + mMediaImplList[texture_index] = media_impl; + //media_impl->addObject(this) ; + + //add the face to show the media if it is in playing + if(mDrawable) + { + LLFace* facep = mDrawable->getFace(texture_index) ; + if(facep) + { + //LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ; + //if(media_tex) + //{ + // media_tex->addMediaToFace(facep) ; + //} + } + else //the face is not available now, start media on this face later. + { + //media_impl->setUpdated(TRUE) ; + } + } + return ; +} + +void LLVOVolume::sendMediaDataUpdate() +{ + if (sObjectMediaClient) + sObjectMediaClient->updateMedia(new LLMediaDataClientObjectImpl(this, false)); +} + +void LLVOVolume::updateObjectMediaData(const LLSD &media_data_array, const std::string &media_version) +{ + // media_data_array is an array of media entry maps + // media_version is the version string in the response. + U32 fetched_version = LLTextureEntry::getVersionFromMediaVersionString(media_version); + + // Only update it if it is newer! + if ( (S32)fetched_version > mLastFetchedMediaVersion) + { + mLastFetchedMediaVersion = fetched_version; + //llinfos << "updating:" << this->getID() << " " << ll_pretty_print_sd(media_data_array) << llendl; + + LLSD::array_const_iterator iter = media_data_array.beginArray(); + LLSD::array_const_iterator end = media_data_array.endArray(); + U8 texture_index = 0; + for (; iter != end; ++iter, ++texture_index) + { + syncMediaData(texture_index, *iter, false/*merge*/, false/*ignore_agent*/); + } + } +} + +bool LLVOVolume::hasMedia() const +{ + bool result = false; + const U8 numTEs = getNumTEs(); + for (U8 i = 0; i < numTEs; i++) + { + const LLTextureEntry* te = getTE(i); + if(te->hasMedia()) + { + result = true; + break; + } + } + return result; +} + +void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool merge, bool ignore_agent) +{ + if(mDead) + { + // If the object has been marked dead, don't process media updates. + return; + } + + LLTextureEntry *te = getTE(texture_index); +// LL_DEBUGS("MediaOnAPrim") << "BEFORE: texture_index = " << texture_index +// << " hasMedia = " << te->hasMedia() << " : " +// << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl; + std::string previous_url; + LLMediaEntry* mep = te->getMediaData(); + if(mep) + { + // Save the "current url" from before the update so we can tell if + // it changes. + previous_url = mep->getCurrentURL(); + } + + if (merge) + { + te->mergeIntoMediaData(media_data); + } + else { + // XXX Question: what if the media data is undefined LLSD, but the + // update we got above said that we have media flags?? Here we clobber + // that, assuming the data from the service is more up-to-date. + te->updateMediaData(media_data); + } + + mep = te->getMediaData(); + if(mep) + { + bool update_from_self = false; + if (!ignore_agent) + { + LLUUID updating_agent = LLTextureEntry::getAgentIDFromMediaVersionString(getMediaURL()); + update_from_self = (updating_agent == gAgent.getID()); + } + //viewer_media_t media_impl = LLViewerMedia::updateMediaImpl(mep, previous_url, update_from_self); + + //addMediaImpl(media_impl, texture_index) ; + } + else + { + //removeMediaImpl(texture_index); + } + +// LL_DEBUGS("MediaOnAPrim") << "AFTER: texture_index = " << texture_index +// << " hasMedia = " << te->hasMedia() << " : " +// << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl; +} + + +void LLVOVolume::mediaNavigateBounceBack(U8 texture_index) +{ + /* + // Find the media entry for this navigate + const LLMediaEntry* mep = NULL; + viewer_media_t impl = getMediaImpl(texture_index); + LLTextureEntry *te = getTE(texture_index); + if(te) + { + mep = te->getMediaData(); + } + + if (mep && impl) + { + std::string url = mep->getCurrentURL(); + // Look for a ":", if not there, assume "http://" + if (!url.empty() && std::string::npos == url.find(':')) + { + url = "http://" + url; + } + // If the url we're trying to "bounce back" to is either empty or not + // allowed by the whitelist, try the home url. If *that* doesn't work, + // set the media as failed and unload it + if (url.empty() || !mep->checkCandidateUrl(url)) + { + url = mep->getHomeURL(); + // Look for a ":", if not there, assume "http://" + if (!url.empty() && std::string::npos == url.find(':')) + { + url = "http://" + url; + } + } + if (url.empty() || !mep->checkCandidateUrl(url)) + { + // The url to navigate back to is not good, and we have nowhere else + // to go. + LL_WARNS("MediaOnAPrim") << "FAILED to bounce back URL \"" << url << "\" -- unloading impl" << LL_ENDL; + impl->setMediaFailed(true); + } + else { + // Okay, navigate now + LL_INFOS("MediaOnAPrim") << "bouncing back to URL: " << url << LL_ENDL; + impl->navigateTo(url, "", false, true); + } + } + */ +} diff --git a/linden/indra/newview/llvovolume.h b/linden/indra/newview/llvovolume.h index d09a198..39d9227 100644 --- a/linden/indra/newview/llvovolume.h +++ b/linden/indra/newview/llvovolume.h @@ -36,6 +36,8 @@ #include "llviewerobject.h" #include "llviewerimage.h" #include "llframetimer.h" +#include "llmediadataclient.h" +#include "llviewermedia.h" #include "llapr.h" #include @@ -43,6 +45,8 @@ class LLViewerTextureAnim; class LLDrawPool; class LLSelectNode; +typedef std::vector media_list_t; + enum LLVolumeInterfaceType { INTERFACE_FLEXIBLE = 1, @@ -217,6 +221,46 @@ public: // tag: vaa emerald local_asset_browser void setSculptChanged(BOOL has_changed) { mSculptChanged = has_changed; } + + + // Functions that deal with media, or media navigation + + // Update this object's media data with the given media data array + // (typically this is only called upon a response from a server request) + void updateObjectMediaData(const LLSD &media_data_array, const std::string &media_version); + + // Bounce back media at the given index to its current URL (or home URL, if current URL is empty) + void mediaNavigateBounceBack(U8 texture_index); + + // Returns whether or not this object has permission to navigate or control + // the given media entry + enum MediaPermType { + MEDIA_PERM_INTERACT, MEDIA_PERM_CONTROL + }; + bool hasMediaPermission(const LLMediaEntry* media_entry, MediaPermType perm_type); + + void mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, std::string new_location); + void mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event); + + // Sync the given media data with the impl and the given te + void syncMediaData(S32 te, const LLSD &media_data, bool merge, bool ignore_agent); + + // Send media data update to the simulator. + void sendMediaDataUpdate(); + + viewer_media_t getMediaImpl(U8 face_id) const; + S32 getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id); + F64 getTotalMediaInterest() const; + + bool hasMedia() const; + + LLVector3 getApproximateFaceNormal(U8 face_id); + + // Returns 'true' iff the media data for this object is in flight + bool isMediaDataBeingFetched() const; + + // Returns the "last fetched" media version, or -1 if not fetched yet + S32 getLastFetchedMediaVersion() const { return mLastFetchedMediaVersion; } protected: S32 computeLODDetail(F32 distance, F32 radius); @@ -224,6 +268,11 @@ protected: LLFace* addFace(S32 face_index); void updateTEData(); + void requestMediaDataUpdate(bool isNew); + void cleanUpMediaImpls(); + void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ; + void removeMediaImpl(S32 texture_index) ; + public: LLViewerTextureAnim *mTextureAnimp; U8 mTexAnimMode; @@ -242,12 +291,16 @@ private: LLVolumeInterface *mVolumeImpl; LLPointer mSculptTexture; S32 mIndexInTex; // index of this volume in the texture's volume list + media_list_t mMediaImplList; + S32 mLastFetchedMediaVersion; // as fetched from the server, starts as -1 // statics public: static F32 sLODSlopDistanceFactor;// Changing this to zero, effectively disables the LOD transition slop static F32 sLODFactor; // LOD scale factor static F32 sDistanceFactor; // LOD distance factor + static LLPointer sObjectMediaClient; + static LLPointer sObjectMediaNavigateClient; protected: static S32 sNumLODChanges; diff --git a/linden/indra/newview/pipeline.cpp b/linden/indra/newview/pipeline.cpp index cd9b3be..61ad8b7 100644 --- a/linden/indra/newview/pipeline.cpp +++ b/linden/indra/newview/pipeline.cpp @@ -232,6 +232,7 @@ BOOL LLPipeline::sPickAvatar = TRUE; BOOL LLPipeline::sDynamicLOD = TRUE; BOOL LLPipeline::sShowHUDAttachments = TRUE; BOOL LLPipeline::sRenderPhysicalBeacons = TRUE; +BOOL LLPipeline::sRenderMOAPBeacons = FALSE; BOOL LLPipeline::sRenderScriptedBeacons = FALSE; BOOL LLPipeline::sRenderScriptedTouchBeacons = TRUE; BOOL LLPipeline::sRenderParticleBeacons = FALSE; @@ -2149,6 +2150,43 @@ void renderPhysicalBeacons(LLDrawable* drawablep) } } +void renderMOAPBeacons(LLDrawable* drawablep) +{ + LLViewerObject *vobj = drawablep->getVObj(); + + if(!vobj || vobj->isAvatar()) + return; + + BOOL beacon=FALSE; + U8 tecount=vobj->getNumTEs(); + for(int x=0;xgetTE(x)->hasMedia()) + { + beacon=TRUE; + break; + } + } + if(beacon==TRUE) + { + if (gPipeline.sRenderBeacons) + { + gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth")); + } + + if (gPipeline.sRenderHighlight) + { + S32 face_id; + S32 count = drawablep->getNumFaces(); + for (face_id = 0; face_id < count; face_id++) + { + gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + } + } + } +} + + void renderParticleBeacons(LLDrawable* drawablep) { // Look for attachments, objects, etc. @@ -2329,6 +2367,11 @@ void LLPipeline::postSort(LLCamera& camera) forAllVisibleDrawables(renderPhysicalBeacons); } + if(sRenderMOAPBeacons) + { + forAllVisibleDrawables(renderMOAPBeacons); + } + if (sRenderParticleBeacons) { forAllVisibleDrawables(renderParticleBeacons); @@ -4563,6 +4606,24 @@ BOOL LLPipeline::getRenderScriptedTouchBeacons(void*) } // static +void LLPipeline::setRenderMOAPBeacons(BOOL val) +{ + sRenderMOAPBeacons = val; +} + +// static +void LLPipeline::toggleRenderMOAPBeacons(void*) +{ + sRenderMOAPBeacons = !sRenderMOAPBeacons; +} + +// static +BOOL LLPipeline::getRenderMOAPBeacons(void*) +{ + return sRenderMOAPBeacons; +} + +// static void LLPipeline::setRenderPhysicalBeacons(BOOL val) { sRenderPhysicalBeacons = val; diff --git a/linden/indra/newview/pipeline.h b/linden/indra/newview/pipeline.h index c5ab7ab..254b3c1 100644 --- a/linden/indra/newview/pipeline.h +++ b/linden/indra/newview/pipeline.h @@ -271,6 +271,10 @@ public: static void toggleRenderPhysicalBeacons(void* data); static BOOL getRenderPhysicalBeacons(void* data); + static void setRenderMOAPBeacons(BOOL val); + static void toggleRenderMOAPBeacons(void * data); + static BOOL getRenderMOAPBeacons(void * data); + static void setRenderScriptedBeacons(BOOL val); static void toggleRenderScriptedBeacons(void* data); static BOOL getRenderScriptedBeacons(void* data); @@ -572,6 +576,7 @@ protected: S32 mLightingDetail; static BOOL sRenderPhysicalBeacons; + static BOOL sRenderMOAPBeacons; static BOOL sRenderScriptedTouchBeacons; static BOOL sRenderScriptedBeacons; static BOOL sRenderParticleBeacons; diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_beacons.xml b/linden/indra/newview/skins/default/xui/en-us/floater_beacons.xml index e698878..2f9fc4d 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_beacons.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_beacons.xml @@ -1,15 +1,16 @@ - + + + + + + -- cgit v1.1 From a0dedb8a1f050465b4e447689672ea2845f0cd5b Mon Sep 17 00:00:00 2001 From: Robin Cornelius Date: Sat, 1 Oct 2011 22:32:42 +0100 Subject: And actually add the new files for MOAP radar --- linden/indra/newview/llmediadataclient.cpp | 813 +++++++++++++++++++++ linden/indra/newview/llmediadataclient.h | 341 +++++++++ linden/indra/newview/rcmoapradar.cpp | 440 +++++++++++ linden/indra/newview/rcmoapradar.h | 58 ++ .../skins/default/xui/en-us/floater_moap_radar.xml | 54 ++ 5 files changed, 1706 insertions(+) create mode 100644 linden/indra/newview/llmediadataclient.cpp create mode 100644 linden/indra/newview/llmediadataclient.h create mode 100644 linden/indra/newview/rcmoapradar.cpp create mode 100644 linden/indra/newview/rcmoapradar.h create mode 100644 linden/indra/newview/skins/default/xui/en-us/floater_moap_radar.xml diff --git a/linden/indra/newview/llmediadataclient.cpp b/linden/indra/newview/llmediadataclient.cpp new file mode 100644 index 0000000..e2fa700 --- /dev/null +++ b/linden/indra/newview/llmediadataclient.cpp @@ -0,0 +1,813 @@ +/** + * @file llmediadataclient.cpp + * @brief class for queueing up requests for media data + * + * $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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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 "llmediadataclient.h" + +#if LL_MSVC +// disable boost::lexical_cast warning +#pragma warning (disable:4702) +#endif + +#include + +#include "llhttpstatuscodes.h" +#include "llsdutil.h" +#include "llmediaentry.h" +#include "lltextureentry.h" +#include "llviewerregion.h" + +// +// When making a request +// - obtain the "overall interest score" of the object. +// This would be the sum of the impls' interest scores. +// - put the request onto a queue sorted by this score +// (highest score at the front of the queue) +// - On a timer, once a second, pull off the head of the queue and send +// the request. +// - Any request that gets a 503 still goes through the retry logic +// + +// +// Forward decls +// +const F32 LLMediaDataClient::QUEUE_TIMER_DELAY = 1.0; // seconds(s) +const F32 LLMediaDataClient::UNAVAILABLE_RETRY_TIMER_DELAY = 10.0; // secs +const U32 LLMediaDataClient::MAX_RETRIES = 10; +const U32 LLMediaDataClient::MAX_SORTED_QUEUE_SIZE = 10000; +const U32 LLMediaDataClient::MAX_ROUND_ROBIN_QUEUE_SIZE = 10000; + +// << operators +std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q); +std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &q); + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLMediaDataClient +// +////////////////////////////////////////////////////////////////////////////////////// + +LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay, + F32 retry_timer_delay, + U32 max_retries, + U32 max_sorted_queue_size, + U32 max_round_robin_queue_size) + : mQueueTimerDelay(queue_timer_delay), + mRetryTimerDelay(retry_timer_delay), + mMaxNumRetries(max_retries), + mMaxSortedQueueSize(max_sorted_queue_size), + mMaxRoundRobinQueueSize(max_round_robin_queue_size), + mQueueTimerIsRunning(false), + mCurrentQueueIsTheSortedQueue(true) +{ +} + +LLMediaDataClient::~LLMediaDataClient() +{ + stopQueueTimer(); + + // This should clear the queue, and hopefully call all the destructors. + LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClient destructor: queue: " << + (isEmpty() ? " " : " ") << LL_ENDL; + + mSortedQueue.clear(); + mRoundRobinQueue.clear(); +} + +bool LLMediaDataClient::isEmpty() const +{ + return mSortedQueue.empty() && mRoundRobinQueue.empty(); +} + +bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object) +{ + return (LLMediaDataClient::findOrRemove(mSortedQueue, object, false/*remove*/, LLMediaDataClient::Request::ANY).notNull() + || (LLMediaDataClient::findOrRemove(mRoundRobinQueue, object, false/*remove*/, LLMediaDataClient::Request::ANY).notNull())); +} + +bool LLMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object) +{ + bool removedFromSortedQueue = LLMediaDataClient::findOrRemove(mSortedQueue, object, true/*remove*/, LLMediaDataClient::Request::ANY).notNull(); + bool removedFromRoundRobinQueue = LLMediaDataClient::findOrRemove(mRoundRobinQueue, object, true/*remove*/, LLMediaDataClient::Request::ANY).notNull(); + return removedFromSortedQueue || removedFromRoundRobinQueue; +} + +//static +LLMediaDataClient::request_ptr_t LLMediaDataClient::findOrRemove(request_queue_t &queue, const LLMediaDataClientObject::ptr_t &obj, bool remove, LLMediaDataClient::Request::Type type) +{ + request_ptr_t result; + request_queue_t::iterator iter = queue.begin(); + request_queue_t::iterator end = queue.end(); + while (iter != end) + { + if (obj->getID() == (*iter)->getObject()->getID() && (type == LLMediaDataClient::Request::ANY || type == (*iter)->getType())) + { + result = *iter; + if (remove) queue.erase(iter); + break; + } + iter++; + } + return result; +} + +void LLMediaDataClient::request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload) +{ + if (object.isNull() || ! object->hasMedia()) return; + + // Push the object on the queue + enqueue(new Request(getCapabilityName(), payload, object, this)); +} + +void LLMediaDataClient::enqueue(const Request *request) +{ + if (request->isNew()) + { + // Add to sorted queue + if (LLMediaDataClient::findOrRemove(mSortedQueue, request->getObject(), true/*remove*/, request->getType()).notNull()) + { + LL_DEBUGS("LLMediaDataClient") << "REMOVING OLD request for " << *request << " ALREADY THERE!" << LL_ENDL; + } + + LL_DEBUGS("LLMediaDataClient") << "Queuing SORTED request for " << *request << LL_ENDL; + + // Sadly, we have to const-cast because items put into the queue are not const + mSortedQueue.push_back(const_cast(request)); + + LL_DEBUGS("LLMediaDataClientQueue") << "SORTED queue:" << mSortedQueue << LL_ENDL; + } + else { + if (mRoundRobinQueue.size() > mMaxRoundRobinQueueSize) + { + LL_INFOS_ONCE("LLMediaDataClient") << "RR QUEUE MAXED OUT!!!" << LL_ENDL; + LL_DEBUGS("LLMediaDataClient") << "Not queuing " << *request << LL_ENDL; + return; + } + + // ROUND ROBIN: if it is there, and it is a GET request, leave it. If not, put at front! + request_ptr_t existing_request; + if (request->getType() == Request::GET) + { + existing_request = LLMediaDataClient::findOrRemove(mRoundRobinQueue, request->getObject(), false/*remove*/, request->getType()); + } + if (existing_request.isNull()) + { + LL_DEBUGS("LLMediaDataClient") << "Queuing RR request for " << *request << LL_ENDL; + // Push the request on the pending queue + // Sadly, we have to const-cast because items put into the queue are not const + mRoundRobinQueue.push_front(const_cast(request)); + + LL_DEBUGS("LLMediaDataClientQueue") << "RR queue:" << mRoundRobinQueue << LL_ENDL; + } + else + { + LL_DEBUGS("LLMediaDataClient") << "ALREADY THERE: NOT Queuing request for " << *request << LL_ENDL; + + existing_request->markSent(false); + } + } + // Start the timer if not already running + startQueueTimer(); +} + +void LLMediaDataClient::startQueueTimer() +{ + if (! mQueueTimerIsRunning) + { + LL_DEBUGS("LLMediaDataClient") << "starting queue timer (delay=" << mQueueTimerDelay << " seconds)" << LL_ENDL; + // LLEventTimer automagically takes care of the lifetime of this object + new QueueTimer(mQueueTimerDelay, this); + } + else { + LL_DEBUGS("LLMediaDataClient") << "not starting queue timer (it's already running, right???)" << LL_ENDL; + } +} + +void LLMediaDataClient::stopQueueTimer() +{ + mQueueTimerIsRunning = false; +} + +bool LLMediaDataClient::processQueueTimer() +{ + sortQueue(); + + if(!isEmpty()) + { + LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, SORTED queue size is: " << mSortedQueue.size() + << ", RR queue size is: " << mRoundRobinQueue.size() << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() started, SORTED queue is: " << mSortedQueue << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() started, RR queue is: " << mRoundRobinQueue << LL_ENDL; + } + + serviceQueue(); + + LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, SORTED queue size is: " << mSortedQueue.size() + << ", RR queue size is: " << mRoundRobinQueue.size() << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() finished, SORTED queue is: " << mSortedQueue << LL_ENDL; + LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() finished, RR queue is: " << mRoundRobinQueue << LL_ENDL; + + return isEmpty(); +} + +void LLMediaDataClient::sortQueue() +{ + if(!mSortedQueue.empty()) + { + // Score all items first + request_queue_t::iterator iter = mSortedQueue.begin(); + request_queue_t::iterator end = mSortedQueue.end(); + while (iter != end) + { + (*iter)->updateScore(); + iter++; + } + + // Re-sort the list... + // NOTE: should this be a stable_sort? If so we need to change to using a vector. + mSortedQueue.sort(LLMediaDataClient::compareRequests); + + // ...then cull items over the max + U32 size = mSortedQueue.size(); + if (size > mMaxSortedQueueSize) + { + U32 num_to_cull = (size - mMaxSortedQueueSize); + LL_INFOS_ONCE("LLMediaDataClient") << "sorted queue MAXED OUT! Culling " + << num_to_cull << " items" << LL_ENDL; + while (num_to_cull-- > 0) + { + mSortedQueue.pop_back(); + } + } + } +} + +// static +bool LLMediaDataClient::compareRequests(const request_ptr_t &o1, const request_ptr_t &o2) +{ + if (o2.isNull()) return true; + if (o1.isNull()) return false; + return ( o1->getScore() > o2->getScore() ); +} + +void LLMediaDataClient::serviceQueue() +{ + request_queue_t *queue_p = getCurrentQueue(); + + // quick retry loop for cases where we shouldn't wait for the next timer tick + while(true) + { + if (queue_p->empty()) + { + LL_DEBUGS("LLMediaDataClient") << "queue empty: " << (*queue_p) << LL_ENDL; + break; + } + + // Peel one off of the items from the queue, and execute request + request_ptr_t request = queue_p->front(); + llassert(!request.isNull()); + const LLMediaDataClientObject *object = (request.isNull()) ? NULL : request->getObject(); + llassert(NULL != object); + + // Check for conditions that would make us just pop and rapidly loop through + // the queue. + if(request.isNull() || + request->isMarkedSent() || + NULL == object || + object->isDead() || + !object->hasMedia()) + { + if (request.isNull()) + { + LL_WARNS("LLMediaDataClient") << "Skipping NULL request" << LL_ENDL; + } + else { + LL_INFOS("LLMediaDataClient") << "Skipping : " << *request << " " + << ((request->isMarkedSent()) ? " request is marked sent" : + ((NULL == object) ? " object is NULL " : + ((object->isDead()) ? "object is dead" : + ((!object->hasMedia()) ? "object has no media!" : "BADNESS!")))) << LL_ENDL; + } + queue_p->pop_front(); + continue; // jump back to the start of the quick retry loop + } + + // Next, ask if this is "interesting enough" to fetch. If not, just stop + // and wait for the next timer go-round. Only do this for the sorted + // queue. + if (mCurrentQueueIsTheSortedQueue && !object->isInterestingEnough()) + { + LL_DEBUGS("LLMediaDataClient") << "Not fetching " << *request << ": not interesting enough" << LL_ENDL; + break; + } + + // Finally, try to send the HTTP message to the cap url + std::string url = request->getCapability(); + bool maybe_retry = false; + if (!url.empty()) + { + const LLSD &sd_payload = request->getPayload(); + LL_INFOS("LLMediaDataClient") << "Sending request for " << *request << LL_ENDL; + + // Call the subclass for creating the responder + LLHTTPClient::post(url, sd_payload, createResponder(request)); + } + else { + LL_INFOS("LLMediaDataClient") << "NOT Sending request for " << *request << ": empty cap url!" << LL_ENDL; + maybe_retry = true; + } + + bool exceeded_retries = request->getRetryCount() > mMaxNumRetries; + if (maybe_retry && ! exceeded_retries) // Try N times before giving up + { + // We got an empty cap, but in that case we will retry again next + // timer fire. + request->incRetryCount(); + } + else { + if (exceeded_retries) + { + LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " + << mMaxNumRetries << " tries...popping object id " << object->getID() << LL_ENDL; + // XXX Should we bring up a warning dialog?? + } + + queue_p->pop_front(); + + if (! mCurrentQueueIsTheSortedQueue) { + // Round robin + request->markSent(true); + mRoundRobinQueue.push_back(request); + } + } + + // end of quick loop -- any cases where we want to loop will use 'continue' to jump back to the start. + break; + } + + swapCurrentQueue(); +} + +void LLMediaDataClient::swapCurrentQueue() +{ + // Swap + mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue; + // If its empty, swap back + if (getCurrentQueue()->empty()) + { + mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue; + } +} + +LLMediaDataClient::request_queue_t *LLMediaDataClient::getCurrentQueue() +{ + return (mCurrentQueueIsTheSortedQueue) ? &mSortedQueue : &mRoundRobinQueue; +} + +// dump the queue +std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q) +{ + int i = 0; + LLMediaDataClient::request_queue_t::const_iterator iter = q.begin(); + LLMediaDataClient::request_queue_t::const_iterator end = q.end(); + while (iter != end) + { + s << "\t" << i << "]: " << (*iter)->getObject()->getID().asString() << "(" << (*iter)->getObject()->getMediaInterest() << ")"; + iter++; + i++; + } + return s; +} + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLMediaDataClient::QueueTimer +// Queue of LLMediaDataClientObject smart pointers to request media for. +// +////////////////////////////////////////////////////////////////////////////////////// + +LLMediaDataClient::QueueTimer::QueueTimer(F32 time, LLMediaDataClient *mdc) +: LLEventTimer(time), mMDC(mdc) +{ + mMDC->setIsRunning(true); +} + +LLMediaDataClient::QueueTimer::~QueueTimer() +{ + LL_DEBUGS("LLMediaDataClient") << "~QueueTimer" << LL_ENDL; + mMDC->setIsRunning(false); + mMDC = NULL; +} + +// virtual +BOOL LLMediaDataClient::QueueTimer::tick() +{ + if (mMDC.isNull()) return TRUE; + return mMDC->processQueueTimer(); +} + + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLMediaDataClient::Responder::RetryTimer +// +////////////////////////////////////////////////////////////////////////////////////// + +LLMediaDataClient::Responder::RetryTimer::RetryTimer(F32 time, Responder *mdr) +: LLEventTimer(time), mResponder(mdr) +{ +} + +// virtual +LLMediaDataClient::Responder::RetryTimer::~RetryTimer() +{ + LL_DEBUGS("LLMediaDataClient") << "~RetryTimer" << *(mResponder->getRequest()) << LL_ENDL; + + // XXX This is weird: Instead of doing the work in tick() (which re-schedules + // a timer, which might be risky), do it here, in the destructor. Yes, it is very odd. + // Instead of retrying, we just put the request back onto the queue + LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *(mResponder->getRequest()) << " retrying" << LL_ENDL; + mResponder->getRequest()->reEnqueue(); + + // Release the ref to the responder. + mResponder = NULL; +} + +// virtual +BOOL LLMediaDataClient::Responder::RetryTimer::tick() +{ + // Don't fire again + return TRUE; +} + + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLMediaDataClient::Request +// +////////////////////////////////////////////////////////////////////////////////////// +/*static*/U32 LLMediaDataClient::Request::sNum = 0; + +LLMediaDataClient::Request::Request(const char *cap_name, + const LLSD& sd_payload, + LLMediaDataClientObject *obj, + LLMediaDataClient *mdc) +: mCapName(cap_name), + mPayload(sd_payload), + mObject(obj), + mNum(++sNum), + mRetryCount(0), + mMDC(mdc), + mMarkedSent(false), + mScore((F64)0.0) +{ +} + +LLMediaDataClient::Request::~Request() +{ + LL_DEBUGS("LLMediaDataClient") << "~Request" << (*this) << LL_ENDL; + mMDC = NULL; + mObject = NULL; +} + + +std::string LLMediaDataClient::Request::getCapability() const +{ + return getObject()->getCapabilityUrl(getCapName()); +} + +// Helper function to get the "type" of request, which just pokes around to +// discover it. +LLMediaDataClient::Request::Type LLMediaDataClient::Request::getType() const +{ + if (0 == strcmp(mCapName, "ObjectMediaNavigate")) + { + return NAVIGATE; + } + else if (0 == strcmp(mCapName, "ObjectMedia")) + { + const std::string &verb = mPayload["verb"]; + if (verb == "GET") + { + return GET; + } + else if (verb == "UPDATE") + { + return UPDATE; + } + } + llassert(false); + return GET; +} + +const char *LLMediaDataClient::Request::getTypeAsString() const +{ + Type t = getType(); + switch (t) + { + case GET: + return "GET"; + break; + case UPDATE: + return "UPDATE"; + break; + case NAVIGATE: + return "NAVIGATE"; + break; + case ANY: + return "ANY"; + break; + } + return ""; +} + + +void LLMediaDataClient::Request::reEnqueue() const +{ + // I sure hope this doesn't deref a bad pointer: + mMDC->enqueue(this); +} + +F32 LLMediaDataClient::Request::getRetryTimerDelay() const +{ + return (mMDC == NULL) ? LLMediaDataClient::UNAVAILABLE_RETRY_TIMER_DELAY : + mMDC->mRetryTimerDelay; +} + +U32 LLMediaDataClient::Request::getMaxNumRetries() const +{ + return (mMDC == NULL) ? LLMediaDataClient::MAX_RETRIES : mMDC->mMaxNumRetries; +} + +void LLMediaDataClient::Request::markSent(bool flag) +{ + if (mMarkedSent != flag) + { + mMarkedSent = flag; + if (!mMarkedSent) + { + mNum = ++sNum; + } + } +} + +void LLMediaDataClient::Request::updateScore() +{ + F64 tmp = mObject->getMediaInterest(); + if (tmp != mScore) + { + LL_DEBUGS("LLMediaDataClient") << "Score for " << mObject->getID() << " changed from " << mScore << " to " << tmp << LL_ENDL; + mScore = tmp; + } +} + +std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r) +{ + s << "request: num=" << r.getNum() + << " type=" << r.getTypeAsString() + << " ID=" << r.getObject()->getID() + << " #retries=" << r.getRetryCount(); + return s; +} + + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLMediaDataClient::Responder +// +////////////////////////////////////////////////////////////////////////////////////// + +LLMediaDataClient::Responder::Responder(const request_ptr_t &request) +: mRequest(request) +{ +} + +LLMediaDataClient::Responder::~Responder() +{ + LL_DEBUGS("LLMediaDataClient") << "~Responder" << *(getRequest()) << LL_ENDL; + mRequest = NULL; +} + +/*virtual*/ +void LLMediaDataClient::Responder::error(U32 status, const std::string& reason) +{ + if (status == HTTP_SERVICE_UNAVAILABLE) + { + F32 retry_timeout = mRequest->getRetryTimerDelay(); + + mRequest->incRetryCount(); + + if (mRequest->getRetryCount() < mRequest->getMaxNumRetries()) + { + LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL; + + // Start timer (instances are automagically tracked by + // InstanceTracker<> and LLEventTimer) + new RetryTimer(F32(retry_timeout/*secs*/), this); + } + else { + LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retry count " + << mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL; + } + } + else { + std::string msg = boost::lexical_cast(status) + ": " + reason; + LL_WARNS("LLMediaDataClient") << *mRequest << " http error(" << msg << ")" << LL_ENDL; + } +} + +/*virtual*/ +void LLMediaDataClient::Responder::result(const LLSD& content) +{ + LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " result : " << ll_print_sd(content) << LL_ENDL; +} + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLObjectMediaDataClient +// Subclass of LLMediaDataClient for the ObjectMedia cap +// +////////////////////////////////////////////////////////////////////////////////////// + +LLMediaDataClient::Responder *LLObjectMediaDataClient::createResponder(const request_ptr_t &request) const +{ + return new LLObjectMediaDataClient::Responder(request); +} + +const char *LLObjectMediaDataClient::getCapabilityName() const +{ + return "ObjectMedia"; +} + +void LLObjectMediaDataClient::fetchMedia(LLMediaDataClientObject *object) +{ + LLSD sd_payload; + sd_payload["verb"] = "GET"; + sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID(); + request(object, sd_payload); +} + +void LLObjectMediaDataClient::updateMedia(LLMediaDataClientObject *object) +{ + LLSD sd_payload; + sd_payload["verb"] = "UPDATE"; + sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID(); + LLSD object_media_data; + int i = 0; + int end = object->getMediaDataCount(); + for ( ; i < end ; ++i) + { + object_media_data.append(object->getMediaDataLLSD(i)); + } + sd_payload[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data; + + LL_DEBUGS("LLMediaDataClient") << "update media data: " << object->getID() << " " << ll_print_sd(sd_payload) << LL_ENDL; + + request(object, sd_payload); +} + +/*virtual*/ +void LLObjectMediaDataClient::Responder::result(const LLSD& content) +{ + const LLMediaDataClient::Request::Type type = getRequest()->getType(); + llassert(type == LLMediaDataClient::Request::GET || type == LLMediaDataClient::Request::UPDATE) + if (type == LLMediaDataClient::Request::GET) + { + LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " GET returned: " << ll_print_sd(content) << LL_ENDL; + + // Look for an error + if (content.has("error")) + { + const LLSD &error = content["error"]; + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" << + error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; + + // XXX Warn user? + } + else { + // Check the data + const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY]; + if (object_id != getRequest()->getObject()->getID()) + { + // NOT good, wrong object id!! + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL; + return; + } + + // Otherwise, update with object media data + getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY], + content[LLTextureEntry::MEDIA_VERSION_KEY]); + } + } + else if (type == LLMediaDataClient::Request::UPDATE) + { + // just do what our superclass does + LLMediaDataClient::Responder::result(content); + } +} + +////////////////////////////////////////////////////////////////////////////////////// +// +// LLObjectMediaNavigateClient +// Subclass of LLMediaDataClient for the ObjectMediaNavigate cap +// +////////////////////////////////////////////////////////////////////////////////////// +LLMediaDataClient::Responder *LLObjectMediaNavigateClient::createResponder(const request_ptr_t &request) const +{ + return new LLObjectMediaNavigateClient::Responder(request); +} + +const char *LLObjectMediaNavigateClient::getCapabilityName() const +{ + return "ObjectMediaNavigate"; +} + +void LLObjectMediaNavigateClient::navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url) +{ + LLSD sd_payload; + sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID(); + sd_payload[LLMediaEntry::CURRENT_URL_KEY] = url; + sd_payload[LLTextureEntry::TEXTURE_INDEX_KEY] = (LLSD::Integer)texture_index; + + LL_INFOS("LLMediaDataClient") << "navigate() initiated: " << ll_print_sd(sd_payload) << LL_ENDL; + + request(object, sd_payload); +} + +/*virtual*/ +void LLObjectMediaNavigateClient::Responder::error(U32 status, const std::string& reason) +{ + // Bounce back (unless HTTP_SERVICE_UNAVAILABLE, in which case call base + // class + if (status == HTTP_SERVICE_UNAVAILABLE) + { + LLMediaDataClient::Responder::error(status, reason); + } + else { + // bounce the face back + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: http code=" << status << LL_ENDL; + const LLSD &payload = getRequest()->getPayload(); + // bounce the face back + getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); + } +} + +/*virtual*/ +void LLObjectMediaNavigateClient::Responder::result(const LLSD& content) +{ + LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << ll_print_sd(content) << LL_ENDL; + + if (content.has("error")) + { + const LLSD &error = content["error"]; + int error_code = error["code"]; + + if (ERROR_PERMISSION_DENIED_CODE == error_code) + { + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Navigation denied: bounce back" << LL_ENDL; + const LLSD &payload = getRequest()->getPayload(); + // bounce the face back + getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); + } + else { + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: code=" << + error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; + } + // XXX Warn user? + } + else { + // just do what our superclass does + LLMediaDataClient::Responder::result(content); + } +} diff --git a/linden/indra/newview/llmediadataclient.h b/linden/indra/newview/llmediadataclient.h new file mode 100644 index 0000000..0ed7c57 --- /dev/null +++ b/linden/indra/newview/llmediadataclient.h @@ -0,0 +1,341 @@ +/** + * @file llmediadataclient.h + * @brief class for queueing up requests to the media service + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + * + */ + +#ifndef LL_LLMEDIADATACLIENT_H +#define LL_LLMEDIADATACLIENT_H + +#include "llhttpclient.h" +#include +//#include "llrefcount.h" +//#include "llpointer.h" +//#include "lleventtimer.h" + + +// Link seam for LLVOVolume +class LLMediaDataClientObject : public LLRefCount +{ +public: + // Get the number of media data items + virtual U8 getMediaDataCount() const = 0; + // Get the media data at index, as an LLSD + virtual LLSD getMediaDataLLSD(U8 index) const = 0; + // Get this object's UUID + virtual LLUUID getID() const = 0; + // Navigate back to previous URL + virtual void mediaNavigateBounceBack(U8 index) = 0; + // Does this object have media? + virtual bool hasMedia() const = 0; + // Update the object's media data to the given array + virtual void updateObjectMediaData(LLSD const &media_data_array, const std::string &version_string) = 0; + // Return the total "interest" of the media (on-screen area) + virtual F64 getMediaInterest() const = 0; + // Return the given cap url + virtual std::string getCapabilityUrl(const std::string &name) const = 0; + // Return whether the object has been marked dead + virtual bool isDead() const = 0; + // Returns a media version number for the object + virtual U32 getMediaVersion() const = 0; + // Returns whether the object is "interesting enough" to fetch + virtual bool isInterestingEnough() const = 0; + // Returns whether we've seen this object yet or not + virtual bool isNew() const = 0; + + // smart pointer + typedef LLPointer ptr_t; +}; + +// This object creates a priority queue for requests. +// Abstracts the Cap URL, the request, and the responder +class LLMediaDataClient : public LLRefCount +{ +public: + LOG_CLASS(LLMediaDataClient); + + const static F32 QUEUE_TIMER_DELAY;// = 1.0; // seconds(s) + const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs + const static U32 MAX_RETRIES;// = 4; + const static U32 MAX_SORTED_QUEUE_SIZE;// = 10000; + const static U32 MAX_ROUND_ROBIN_QUEUE_SIZE;// = 10000; + + // Constructor + LLMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, + F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, + U32 max_retries = MAX_RETRIES, + U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, + U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE); + + // Make the request + void request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload); + + F32 getRetryTimerDelay() const { return mRetryTimerDelay; } + + // Returns true iff the queue is empty + bool isEmpty() const; + + // Returns true iff the given object is in the queue + bool isInQueue(const LLMediaDataClientObject::ptr_t &object); + + // Remove the given object from the queue. Returns true iff the given object is removed. + bool removeFromQueue(const LLMediaDataClientObject::ptr_t &object); + + // Called only by the Queue timer and tests (potentially) + bool processQueueTimer(); + +protected: + // Destructor + virtual ~LLMediaDataClient(); // use unref + + // Request + class Request : public LLRefCount + { + public: + enum Type { + GET, + UPDATE, + NAVIGATE, + ANY + }; + + Request(const char *cap_name, const LLSD& sd_payload, LLMediaDataClientObject *obj, LLMediaDataClient *mdc); + const char *getCapName() const { return mCapName; } + const LLSD &getPayload() const { return mPayload; } + LLMediaDataClientObject *getObject() const { return mObject; } + + U32 getNum() const { return mNum; } + + U32 getRetryCount() const { return mRetryCount; } + void incRetryCount() { mRetryCount++; } + + // Note: may return empty string! + std::string getCapability() const; + + Type getType() const; + const char *getTypeAsString() const; + + // Re-enqueue thyself + void reEnqueue() const; + + F32 getRetryTimerDelay() const; + U32 getMaxNumRetries() const; + + bool isNew() const { return mObject.notNull() ? mObject->isNew() : false; } + void markSent(bool flag); + bool isMarkedSent() const { return mMarkedSent; } + void updateScore(); + F64 getScore() const { return mScore; } + + public: + friend std::ostream& operator<<(std::ostream &s, const Request &q); + + protected: + virtual ~Request(); // use unref(); + + private: + const char *mCapName; + LLSD mPayload; + LLMediaDataClientObject::ptr_t mObject; + // Simple tracking + U32 mNum; + static U32 sNum; + U32 mRetryCount; + F64 mScore; + bool mMarkedSent; + + // Back pointer to the MDC...not a ref! + LLMediaDataClient *mMDC; + }; + typedef LLPointer request_ptr_t; + + // Responder + class Responder : public LLHTTPClient::Responder + { + public: + Responder(const request_ptr_t &request); + //If we get back an error (not found, etc...), handle it here + virtual void error(U32 status, const std::string& reason); + //If we get back a normal response, handle it here. Default just logs it. + virtual void result(const LLSD& content); + + const request_ptr_t &getRequest() const { return mRequest; } + + protected: + virtual ~Responder(); + + private: + + class RetryTimer : public LLEventTimer + { + public: + RetryTimer(F32 time, Responder *); + virtual ~RetryTimer(); + virtual BOOL tick(); + private: + // back-pointer + boost::intrusive_ptr mResponder; + }; + + request_ptr_t mRequest; + }; + +protected: + + // Subclasses must override this factory method to return a new responder + virtual Responder *createResponder(const request_ptr_t &request) const = 0; + + // Subclasses must override to return a cap name + virtual const char *getCapabilityName() const = 0; + + virtual void sortQueue(); + virtual void serviceQueue(); + +private: + typedef std::list request_queue_t; + + void enqueue(const Request*); + + // Return whether the given object is/was in the queue + static LLMediaDataClient::request_ptr_t findOrRemove(request_queue_t &queue, const LLMediaDataClientObject::ptr_t &obj, bool remove, Request::Type type); + + // Comparator for sorting + static bool compareRequests(const request_ptr_t &o1, const request_ptr_t &o2); + static F64 getObjectScore(const LLMediaDataClientObject::ptr_t &obj); + + friend std::ostream& operator<<(std::ostream &s, const Request &q); + friend std::ostream& operator<<(std::ostream &s, const request_queue_t &q); + + class QueueTimer : public LLEventTimer + { + public: + QueueTimer(F32 time, LLMediaDataClient *mdc); + virtual BOOL tick(); + protected: + virtual ~QueueTimer(); + private: + // back-pointer + LLPointer mMDC; + }; + + void startQueueTimer(); + void stopQueueTimer(); + void setIsRunning(bool val) { mQueueTimerIsRunning = val; } + + void swapCurrentQueue(); + request_queue_t *getCurrentQueue(); + + const F32 mQueueTimerDelay; + const F32 mRetryTimerDelay; + const U32 mMaxNumRetries; + const U32 mMaxSortedQueueSize; + const U32 mMaxRoundRobinQueueSize; + + bool mQueueTimerIsRunning; + + request_queue_t mSortedQueue; + request_queue_t mRoundRobinQueue; + bool mCurrentQueueIsTheSortedQueue; +}; + + +// MediaDataClient specific for the ObjectMedia cap +class LLObjectMediaDataClient : public LLMediaDataClient +{ +public: + LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, + F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, + U32 max_retries = MAX_RETRIES, + U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, + U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE) + : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries) + {} + virtual ~LLObjectMediaDataClient() {} + + void fetchMedia(LLMediaDataClientObject *object); + void updateMedia(LLMediaDataClientObject *object); + +protected: + // Subclasses must override this factory method to return a new responder + virtual Responder *createResponder(const request_ptr_t &request) const; + + // Subclasses must override to return a cap name + virtual const char *getCapabilityName() const; + + class Responder : public LLMediaDataClient::Responder + { + public: + Responder(const request_ptr_t &request) + : LLMediaDataClient::Responder(request) {} + virtual void result(const LLSD &content); + }; +}; + + +// MediaDataClient specific for the ObjectMediaNavigate cap +class LLObjectMediaNavigateClient : public LLMediaDataClient +{ +public: + // NOTE: from llmediaservice.h + static const int ERROR_PERMISSION_DENIED_CODE = 8002; + + LLObjectMediaNavigateClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY, + F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY, + U32 max_retries = MAX_RETRIES, + U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE, + U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE) + : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries) + {} + virtual ~LLObjectMediaNavigateClient() {} + + void navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url); + +protected: + // Subclasses must override this factory method to return a new responder + virtual Responder *createResponder(const request_ptr_t &request) const; + + // Subclasses must override to return a cap name + virtual const char *getCapabilityName() const; + + class Responder : public LLMediaDataClient::Responder + { + public: + Responder(const request_ptr_t &request) + : LLMediaDataClient::Responder(request) {} + virtual void error(U32 status, const std::string& reason); + virtual void result(const LLSD &content); + private: + void mediaNavigateBounceBack(); + }; + +}; + + +#endif // LL_LLMEDIADATACLIENT_H diff --git a/linden/indra/newview/rcmoapradar.cpp b/linden/indra/newview/rcmoapradar.cpp new file mode 100644 index 0000000..f0593ef --- /dev/null +++ b/linden/indra/newview/rcmoapradar.cpp @@ -0,0 +1,440 @@ +// MOAP Radar +// Robin Cornelius + + +#include "llviewerprecompiledheaders.h" + +#include "llavatarconstants.h" +#include "llfloateravatarlist.h" + +#include "lluictrlfactory.h" +#include "llviewerwindow.h" +#include "llscrolllistctrl.h" +#include "llradiogroup.h" +#include "llviewercontrol.h" +#include "llbutton.h" + +#include "llvoavatar.h" +#include "llimview.h" +#include "rcmoapradar.h" +#include "llregionflags.h" +#include "llfloaterreporter.h" +#include "llagent.h" +#include "llviewerregion.h" +#include "lltracker.h" +#include "llviewerstats.h" +#include "llerror.h" +#include "llchat.h" +#include "llfloaterchat.h" +#include "llviewermessage.h" +#include "llweb.h" +#include "llviewerobjectlist.h" +#include "llmutelist.h" +#include "llcallbacklist.h" +#include "llmediaentry.h" + +#include +#include + +#include + +#include "llworld.h" + +#include "llsdutil.h" + +LLFloaterMOAPRadar* LLFloaterMOAPRadar::sInstance = NULL; + +LLFloaterMOAPRadar::LLFloaterMOAPRadar() : LLFloater(std::string("MOAPradar")) +{ + llassert_always(sInstance == NULL); + sInstance = this; + mUpdateRate = gSavedSettings.getU32("MOAPRadarUpdateRate") * 3 + 3; + mTrackingRunning=false; +} + +LLFloaterMOAPRadar::~LLFloaterMOAPRadar() +{ + gIdleCallbacks.deleteFunction(LLFloaterMOAPRadar::callbackIdle); + sInstance = NULL; +} + +//static +void LLFloaterMOAPRadar::toggle(void*) +{ + if (sInstance) + { + if (sInstance->getVisible()) + { + sInstance->close(false); + } + else + { + sInstance->open(); + } + } + else + { + showInstance(); + } +} + +//static +void LLFloaterMOAPRadar::showInstance() +{ + if (sInstance) + { + if (!sInstance->getVisible()) + { + sInstance->open(); + } + } + else + { + sInstance = new LLFloaterMOAPRadar(); + LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_moap_radar.xml"); + } +} + +void LLFloaterMOAPRadar::draw() +{ + LLFloater::draw(); +} + +void LLFloaterMOAPRadar::onOpen() +{ + gSavedSettings.setBOOL("ShowMOAPRadar", TRUE); + sInstance->setVisible(TRUE); +} + +void LLFloaterMOAPRadar::onClose(bool app_quitting) +{ + sInstance->setVisible(FALSE); + if (!app_quitting) + { + gSavedSettings.setBOOL("ShowMOAPRadar", FALSE); + } + if (!gSavedSettings.getBOOL("MOAPRadarKeepOpen") || app_quitting) + { + destroy(); + } +} + + +BOOL LLFloaterMOAPRadar::postBuild() +{ + + mMOAPList = getChild("moap_list"); + mMOAPList->sortByColumn("distance", TRUE); + + mTrackBtn = getChild("track_btn"); + mTrackBtn->setLabel(LLStringExplicit("Track")); + + childSetAction("open_btn", onClickOpen, this); + childSetAction("track_btn", onClickTrack, this); + childSetAction("copy_btn", onClickCopy, this); + + mMOAPList->setCommitOnSelectionChange(TRUE); + childSetCommitCallback("moap_list", onSelectMOAP, this); + + gIdleCallbacks.addFunction(LLFloaterMOAPRadar::callbackIdle); + + return TRUE; +} + +//static +void LLFloaterMOAPRadar::callbackIdle(void *userdata) { + if (LLFloaterMOAPRadar::sInstance != NULL) + { + // Do not update at every frame: this would be insane ! + if (gFrameCount % LLFloaterMOAPRadar::sInstance->mUpdateRate == 0) + { + LLFloaterMOAPRadar::sInstance->updateMOAPList(); + } + } +} + + +void LLFloaterMOAPRadar::updateMOAPList() +{ + if (sInstance != this) return; + + mMOAPList->deleteAllItems(); + + S32 obj_count=gObjectList.getNumObjects(); + + int count=0; + + for(int objnum=0;objnum obj = gObjectList.getObject(objnum); + + if(obj.isNull()) + continue; + + if(obj->isDead() || obj->isOrphaned()) + continue; + + if(obj->getMediaType() == LLViewerObject::MEDIA_TYPE_NONE) + continue; + + LLSD element; + + element["id"] = obj->getID(); + + for(int face=0;facegetNumTEs();face++) + { + const LLTextureEntry * te=obj->getTE(face); + if(te==NULL) + continue; + + if(te->hasMedia()) + { + LLMediaEntry* media=te->getMediaData(); + + if(media==NULL) + continue; + + LLSD media_details; + media->asLLSD(media_details); + + element["columns"][LIST_URL]["column"] = "URL"; + element["columns"][LIST_URL]["type"] = "text"; + std::string URL=media->getCurrentURL(); + if(URL=="") + URL="(Waiting....)"; + + element["columns"][LIST_URL]["value"] = URL; + + if(mTrackingRunning && mTrackedID==obj->getID() && mTrackedFace==face) + { + element["columns"][LIST_URL]["font-style"] = "BOLD"; + } + else + { + element["columns"][LIST_URL]["font-style"] = "NORMAL"; + } + + element["columns"][LIST_FACE]["column"] = "face"; + element["columns"][LIST_FACE]["type"] = "text"; + std::stringstream face_buf; + face_buf << face; + element["columns"][LIST_FACE]["value"] = face_buf.str(); + + LLVector3d offset = gAgent.getPositionGlobal()-obj->getPositionGlobal(); + S32 dist= offset.length(); + + element["columns"][LIST_DISTANCE]["column"] = "distance"; + element["columns"][LIST_DISTANCE]["type"] = "text"; + std::stringstream dist_buf; + dist_buf << std::fixed << std::setprecision(2) << dist<<"m"; + element["columns"][LIST_DISTANCE]["value"] = dist_buf.str(); + + if(dist<25) + element["columns"][LIST_DISTANCE]["color"] = LLColor4::green.getValue(); + else if(dist<50) + element["columns"][LIST_DISTANCE]["color"] = LLColor4::blue1.getValue(); + else if(dist<100) + element["columns"][LIST_DISTANCE]["color"] = LLColor4::black.getValue(); + else if(dist<256) + element["columns"][LIST_DISTANCE]["color"] = LLColor4::yellow.getValue(); + else + element["columns"][LIST_DISTANCE]["color"] = LLColor4::red.getValue(); + + + element["columns"][LIST_POSITION]["column"] = "position"; + element["columns"][LIST_POSITION]["type"] = "text"; + element["columns"][LIST_POSITION]["value"] = ""; + + element["columns"][LIST_ALTITUDE]["column"] = "altitude"; + element["columns"][LIST_ALTITUDE]["type"] = "text"; + std::stringstream alt_buf; + alt_buf << std::fixed << std::setprecision(2) << obj->getPositionGlobal().mdV[2]<<"m"; + element["columns"][LIST_ALTITUDE]["value"] = alt_buf.str(); + + element["columns"][LIST_POSITION]["column"]="position"; + element["columns"][LIST_POSITION]["type"] = "text"; + std::stringstream pos_buf; + + S32 moap_x = (S32)offset.mdV[VX]; + S32 moap_y = (S32)offset.mdV[VY]; + if (moap_x >= -256 && moap_x <= 256 && moap_y >= -256 && moap_y <= 256) + { + pos_buf<< std::fixed << std::setprecision(2)<getPositionRegion().mV[VX]<<","<getPositionRegion().mV[VY]; + } + else + { + if (moap_y < 0) + pos_buf<<"S"; + else if (moap_y > 256) + pos_buf<<"N"; + + if (moap_x < 0) + pos_buf<<"W"; + else if (moap_x > 256) + pos_buf<<"E"; + } + + + element["columns"][LIST_POSITION]["value"] = pos_buf.str(); + + mMOAPList->addElement(element, ADD_BOTTOM); + + if(mSelectedObjID==obj->getID() && mSelectedFace==face) + { + mMOAPList->selectNthItem(count); + } + + count++; + } + } + } + + updatetrackbtn(); +} + +// static +void LLFloaterMOAPRadar::onClickOpen(void* userdata) +{ + LLFloaterMOAPRadar *self = (LLFloaterMOAPRadar*)userdata; + + LLDynamicArray ids = self->mMOAPList->getSelectedIDs(); + + if(ids.empty()) + { + return; + } + + LLUUID id=ids.front(); + + LLPointer obj = gObjectList.findObject(id); + if(obj.notNull()) + { + + const LLTextureEntry * te=obj->getTE(self->mSelectedFace); + if(te==NULL) + return; + + if(te->hasMedia()) + { + LLMediaEntry* media=te->getMediaData(); + if(media) + { + //gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(media->getCurrentURL())); + LLWeb::loadURL(media->getCurrentURL()); + } + } + } + +} + +// static +void LLFloaterMOAPRadar::onClickTrack(void* userdata) +{ + LLFloaterMOAPRadar *self = (LLFloaterMOAPRadar*)userdata; + + LLDynamicArray ids = self->mMOAPList->getSelectedIDs(); + + if(self->mTrackingRunning) + { + LLTracker::stopTracking(NULL); + self->mTrackingRunning=false; + } + + if(ids.empty()) + { + self->mTrackedID=LLUUID::null; + self->mTrackingRunning=false; + return; + } + + LLUUID id=ids.front(); + + if(id==self->mTrackedID && self->mSelectedFace==self->mTrackedFace) + { + self->mTrackedID=LLUUID::null; + self->mTrackingRunning=false; + return; + } + + self->mTrackedID=LLUUID::null; + + LLPointer obj = gObjectList.findObject(id); + if(obj.notNull()) + { + LLTracker::trackLocation(obj->getPositionGlobal(),"MOAP Tracking","",LLTracker::LOCATION_ITEM); + self->mTrackingRunning=true; + self->mTrackedID=id; + self->mTrackedFace=self->mSelectedFace; + } +} + +// static +void LLFloaterMOAPRadar::onClickCopy(void* userdata) +{ + LLFloaterMOAPRadar *self = (LLFloaterMOAPRadar*)userdata; + + LLDynamicArray ids = self->mMOAPList->getSelectedIDs(); + + if(ids.empty()) + { + LLTracker::stopTracking(NULL); + return; + } + + LLUUID id=ids.front(); + + LLPointer obj = gObjectList.findObject(id); + + if(obj.notNull()) + { + + const LLTextureEntry * te=obj->getTE(self->mSelectedFace); + if(te==NULL) + return; + + if(te->hasMedia()) + { + LLMediaEntry* media=te->getMediaData(); + if(media) + { + gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(media->getCurrentURL())); + } + } + } + +} + +//static +void LLFloaterMOAPRadar::onSelectMOAP(LLUICtrl*, void* userdata) +{ + LLFloaterMOAPRadar *self = (LLFloaterMOAPRadar*)userdata; + + LLScrollListItem *item = self->mMOAPList->getFirstSelected(); + if (item) + { + self->mSelectedObjID = item->getUUID(); + self->mSelectedFace = item->getColumn(LIST_FACE)->getValue().asInteger(); + } + + self->updatetrackbtn(); +} + +void LLFloaterMOAPRadar::updatetrackbtn() +{ + if( mTrackingRunning) + { + if( mTrackedID==mSelectedObjID && mTrackedFace==mSelectedFace) + { + mTrackBtn->setLabel(LLStringExplicit("Untrack")); + } + else + { + mTrackBtn->setLabel(LLStringExplicit("New Track")); + } + } + else + { + mTrackBtn->setLabel(LLStringExplicit("Track")); + } + +} \ No newline at end of file diff --git a/linden/indra/newview/rcmoapradar.h b/linden/indra/newview/rcmoapradar.h new file mode 100644 index 0000000..1d01546 --- /dev/null +++ b/linden/indra/newview/rcmoapradar.h @@ -0,0 +1,58 @@ + + +class LLFloaterMOAPRadar : public LLFloater +{ + +private: + LLFloaterMOAPRadar(); +public: + ~LLFloaterMOAPRadar(); + + enum AVATARS_COLUMN_ORDER + { + LIST_URL, + LIST_FACE, + LIST_DISTANCE, + LIST_POSITION, + LIST_ALTITUDE + }; + + /*virtual*/ void onClose(bool app_quitting); + /*virtual*/ void onOpen(); + /*virtual*/ BOOL postBuild(); + /*virtual*/ void draw(); + + static void toggle(void*); + + static void showInstance(); + + static void callbackIdle(void *userdata); + + void updateMOAPList(); + + static void onClickOpen(void* userdata); + static void onClickCopy(void* userdata); + static void onClickTrack(void* userdata); + static void onSelectMOAP(LLUICtrl*, void* userdata); + + +private: + static LLFloaterMOAPRadar* sInstance; + LLScrollListCtrl* mMOAPList; + LLButton * mTrackBtn; + + U32 mUpdateRate; + + LLUUID mSelectedObjID; + U8 mSelectedFace; + bool mTrackingRunning; + + LLUUID mTrackedID; + U8 mTrackedFace; + + void updatetrackbtn(); + +public: + static LLFloaterMOAPRadar* getInstance() { return sInstance; } + +}; \ No newline at end of file diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_moap_radar.xml b/linden/indra/newview/skins/default/xui/en-us/floater_moap_radar.xml new file mode 100644 index 0000000..b9e3f99 --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/floater_moap_radar.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + +